aboutsummaryrefslogtreecommitdiff
path: root/docs/getting-started.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/getting-started.md')
-rw-r--r--docs/getting-started.md107
1 files changed, 107 insertions, 0 deletions
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 0000000..6f90618
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,107 @@
+# Getting started
+
+## Build the compiler
+
+hdass builds with [Meson](https://mesonbuild.com/):
+
+```bash
+meson setup build
+meson compile -C build
+```
+
+That produces `build/hdass`. It has two options you need: `-o <file>` writes the
+output (default stdout), and `-t <target>` picks the assembler and architecture
+(`nasm` by default, `fasm`, or `arm64`). `build/hdass --help` lists the rest.
+
+hdass only *transpiles*: it emits assembly text, which you assemble and link
+yourself. The examples target Linux, so you need an x86-64 (and
+for AArch64, an aarch64) Linux toolchain. The bundled
+[Docker image](../README.md#building) has `nasm`, `fasm`, an aarch64
+cross-assembler and `qemu`; the commands below run inside it:
+
+```bash
+docker compose up -d
+docker compose exec hdass bash
+```
+
+## A first program (x86-64)
+
+Put this in `hello.hdass`:
+
+```hdass
+[entry: main]
+
+const SYS_WRITE = 1
+const SYS_EXIT = 60
+const STDOUT = 1
+
+data message = "Hello, hdass!\n"
+
+proc main
+{
+ rax = SYS_WRITE // write(STDOUT, message, message.len)
+ rdi = STDOUT
+ rsi = message
+ rdx = message.len
+ syscall
+
+ rax = SYS_EXIT // exit(0)
+ rdi = 0
+ syscall
+}
+```
+
+Transpile, assemble, link and run:
+
+```bash
+./build/hdass hello.hdass -o hello.asm
+nasm -f elf64 hello.asm -o hello.o
+ld -e main hello.o -o hello
+./hello
+```
+
+It prints `Hello, hdass!`. `[entry: main]` exports `main` and drops its `ret`, so
+the procedure ends the program itself with the exit syscall; `ld -e main` uses it
+as the start symbol. Swap `-t fasm` and `fasm hello.asm hello.o` to use fasm
+instead — the machine code is the same.
+
+## Running on AArch64
+
+The same source model runs on ARM, but the syscall ABI differs (numbers and
+argument registers), so this program is AArch64-specific. Written with the
+[`logical_registers`](targets.md#the-portable-register-model) extension so the
+registers read the same on both architectures:
+
+```hdass
+[entry: main]
+[enable: logical_registers]
+
+const SYS_EXIT = 93 // AArch64 Linux exit
+
+proc main
+{
+ r1 = 42 // x0 = exit code
+ r9 = SYS_EXIT // x8 = syscall number
+ syscall // svc #0
+}
+```
+
+Build it for AArch64 and run it under qemu:
+
+```bash
+./build/hdass -t arm64 exit.hdass -o exit.s
+aarch64-linux-gnu-as exit.s -o exit.o
+aarch64-linux-gnu-ld -e main exit.o -o exit
+qemu-aarch64 ./exit # exits 42
+```
+
+`r1` maps to `x0` and `r9` to `x8`, `syscall` becomes `svc #0`. See
+[Targets](targets.md) for the register mapping and the ABI tables.
+
+## Next
+
+- The whole language: [language reference](language.md).
+- What runs where and why programs still carry per-architecture ABI details:
+ [targets](targets.md).
+- More programs to read: [examples/](../examples/) and
+ [examples/arm64/](../examples/arm64/), each runnable with the steps above.