Skip to content
ALB Wiki

Diff — ALB FASM16 backend

Comparing rev 1 → rev 2

{{infobox
| title = ALB FASM16 backend
| target_flag = `-t fasm16`
| produces = 16-bit x86 assembly (`use16`)
| output = .COM · MZ .EXE · boot sector (`org 7C00h`)
| runs_on = Real-mode DOS, emulators, bare metal
| emitter_unit = `Emit_Native_FASM16` (emit_native_fasm16.adb)
| status = Tiny profile, growing; `--build` supported
}}
The **ALB FASM16 backend** compiles [[AdaLogic BASIC]] down to **16-bit x86 assembly** — real-mode code in 8086 mindset, where a word is 16 bits, an address is a segment:offset pair, and the operating system is interrupt `21h`. It is the backend that lets a modern typed BASIC produce programs a 1983 PC could run.
```alb One-liner
albt demo.alb -t fasm16 --build
→ fasm16_demo/demo.asm → fasm.exe → demo.exe (MZ format by default)
```
## Three output formats
The emitter's `FASM16_Output_Format` chooses what kind of 16-bit artifact comes out:
| Format | Emitted header | What it is |
| --- | --- | --- |
| **MZ .EXE** | `format MZ` · `entry main:start` · `stack 100h` | Relocatable DOS executable — the CLI default |
| **.COM** | `format binary` · `org 100h` | Flat single-segment program — `--fasm16-com` |
| **Boot** | `format binary` · `org 7C00h` | A **boot sector** — code the BIOS loads and runs |
Yes — an ALB program can, in principle, be emitted as something that boots a machine before any operating system exists. That is what "the low-level floor beneath it all" means in practice.
```note From the source itself
The emitter's own banner is honest about its station: *"FASM remains the full ALB native profile… FASM16 starts as a tiny 8086 profile."* It is a seed backend that keeps growing — features it cannot yet lower emit a `; FASM16 UNSUPPORTED: <feature>` marker in the output instead of silently producing wrong code.
```
## The DOS contract
A 16-bit program talks to DOS through software interrupts, and the emitted code does it plainly:
```text
  mov dx, ALB16_Newline
  mov ah, 09h        ; print $-terminated string
  int 21h
```
- `AH=09h` prints a `$`-terminated string — so every literal is stored with the DOS `$` delimiter
- `AH=02h` writes a single character
- `AH=0Ah` reads a buffered line into `ALB16_Input_Buffer` (`db 126, 0, 127 dup(0)` — the classic DOS input structure: max, count, payload)
- Errors are the same `$`-strings: `'ALB16 RUNTIME ERROR: divide or MOD by zero'`
Because a .COM program begins executing at offset `100h` while static storage sits before the code, binary formats emit `jmp start` first — the program leaps over its own data to reach its first instruction, exactly as hand-written .COM programs do.
## 16-bit everything
Everything gets narrower — and the compiler makes it work:
- **U16-native** — the machine word is 16 bits; `dw` is the workhorse
- **U32 by pairing** — 32-bit values live as Hi/Lo word pairs (`ALB16_U32_DividendLo/Hi`, `QuotLo/Hi`, `RemLo/Hi`) with multiword division done in software
- **Returns in DX:AX** — inline ASM expressions document the convention in the emitted comment: *"result must be returned in DX:AX (or AX for 16-bit values)"*
- **PURE shrinks** — the exact rational type packs into 4 bytes on this profile: `PURE.den equ 0 · PURE.num equ 2 · sizeof.PURE equ 4`
- **Strings pool** — a fixed 4 KiB pool (`ALB16_Str_Max equ 4096`, safe limit 3840, results capped at 255)
## The runtime that fits in a corner
Even tiny gets the same architecture — scaled:
- **Dumptruck GC** — `ALB16_GC_Grid`, 1025 nodes × 6 bytes (`Alive · Refs · Child1 · Child2`), with `CLAIM/DROP/BIND/SWEEP` — a mark-and-release memory manager in real mode
- **Prolog knowledge base** — `ALB16_KB`: 1024 fact slots × 13 bytes, hash-keyed (`HashLo/HashHi · ArgLo/ArgHi · ValLo/ValHi · Active`), so ASSERT/QUERY/RETRACT work even in 64 KiB
- **Safety traps** — divide-by-zero, bounds, and range checks print an error and halt, same contract as the 64-bit backend
- **Random** — a seeded 16/32-bit generator (`ALB16_Rnd_SeedLo/Hi`)
- **Temporal variables** — history rings survive the transition to 16 bits: `ALB_TEMP_&lt;name&gt;_history rb N` plus a head cursor
And the same `if used … end if` discipline as the [[ALB FASM backend]] wraps every routine — the assembler deletes whatever the program doesn't call, which matters enormously when a .COM file is supposed to stay small.
## Reversible blocks on 16 bits
The **reversible state forge** made the trip too: `Emit_Rev_Add/Sub/Xor/Rol/Ror/Swap/Not/Neg` all exist on this backend, operating on 16-bit registers — reversible computation is a language-level feature, not a word-size luxury.
## Under the hood
`Emit_Native_FASM16` (~6,500 lines of SPARK-annotated Ada) implements the same `Emit_*` call surface as every other backend — same front end, same AST, different floor. The two-buffer pattern (`Buffer_Global` / `Buffer_Main`) returns, and `Emit_Profile_Banner` stamps the tiny-profile banner at the top of every file.
```tip Try it
`albt demo.alb -t fasm16 --build` assembles straight to an .EXE when fasm is installed. `--fasm16-com` produces a .COM instead — run either in DOSBox or on real hardware, if you're feeling 1983.
```
## See also
- [[ALB FASM backend]] — the 64-bit sibling
- [[ALB C backend]] — the portable sibling
- [[AdaLogic BASIC]] — the language
- [[Z3]] · [[Manchester Baby]] — machines from an era this backend could nearly touch
- [[History of Programming]] · [[History of Language]]
+
## References
+
+
1. ALB Handbook — alb-lang.org/handbook — the language reference for all backends.
+
2. ALB Technology page — alb-lang.org/technology — the sixteen-backend matrix.
+
3. ALB source — github.com/rockyoliver454/AdaLogic-BASIC-ALB-Programming-Language — the emitter sources are Apache 2.0.
+
[[Category:Backends]]
[[Category:AdaLogic BASIC]]