commit 737e79b6123809afd234141474f9e06fbd964276
parent 2d96f2a454e5b12c8d2ba5fdd65dd25a7f7a3a44
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 21 Apr 2026 13:31:11 -0700
update mnemonics to lower-case, remove P1_ prefix
Diffstat:
| M | lint.sh | | | 94 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
| M | src/lisp.M1 | | | 9740 | +++++++++++++++++++++++++++++++------------------------------------------------ |
| M | src/p1_gen.py | | | 15 | ++++++++++++++- |
| M | tests/demo.M1 | | | 340 | ++++++++++++++++++++++++++++++++----------------------------------------------- |
| M | tests/hello.M1 | | | 22 | ++++++++-------------- |
5 files changed, 3992 insertions(+), 6219 deletions(-)
diff --git a/lint.sh b/lint.sh
@@ -2,15 +2,19 @@
## lint.sh — catch undefined P1 tokens before they reach M1.
##
## M1 silently passes undefined tokens through as literal text, so a
-## misspelled P1_LD_R0_R4_0 (when only P1_LD_R0_R4_8 is defined) produces
+## misspelled ld_r0,r4,0 (when only ld_r0,r4,8 is defined) produces
## a runnable-but-SIGILL-ing binary with no diagnostic. This script
-## extracts every P1_*/SYS_* token referenced in a .M1 program and
+## extracts every op-shaped token referenced in a .M1 program and
## asserts each has a matching `DEFINE` in the per-arch defs file.
##
+## After the 2026 rename, op tokens are lowercase identifiers that may
+## contain ',' for multi-operand forms (li_r0, mov_r4,r0, add_r1,r1,r2,
+## prologue_n3, sys_write). The tokenizer must skip `"…"` / `'…'`
+## quoted literals (can span lines and carry prose like "usage: lisp")
+## and `#`/`;` line comments, so the pass is written in Python.
+##
## Usage: lint.sh <p1_arch.M1> <prog.M1> [<prog.M1> ...]
## Exit: 0 on success; 1 + diagnostic on any missing token; 2 on misuse.
-##
-## POSIX sh — no bash process substitution, no GNU-only flags.
set -eu
@@ -19,24 +23,72 @@ if [ "$#" -lt 2 ]; then
exit 2
fi
-defs="$1"
-shift
+exec python3 - "$@" <<'PYEOF'
+import re
+import sys
-## Strip M1 `#`-to-EOL comments before token extraction: file-like
-## references (P1_TODO.md, etc.) live in comments and shouldn't be
-## flagged as missing DEFINEs. awk emits the pre-comment portion of
-## each line on stdout.
-used=$(awk '{ sub(/#.*/, ""); print }' "$@" | grep -oE 'P1_[A-Z0-9_]+|SYS_[A-Z0-9_]+' | sort -u)
+defs_path = sys.argv[1]
+prog_paths = sys.argv[2:]
-tmp=$(mktemp)
-trap 'rm -f "$tmp"' EXIT INT TERM
-awk '/^DEFINE[ \t]/ {print $2}' "$defs" | sort -u > "$tmp"
+def defined_names(path):
+ names = set()
+ with open(path) as f:
+ for line in f:
+ parts = line.split(None, 2)
+ if len(parts) >= 2 and parts[0] == 'DEFINE':
+ names.add(parts[1])
+ return names
-missing=$(printf '%s\n' "$used" | grep -Fxv -f "$tmp" || true)
+def tokenize_source(text):
+ """Emit op-shaped lowercase tokens from M0/M1 source, skipping
+ `"…"` / `'…'` quoted literals and `#`/`;` line comments. Quotes may
+ span newlines (strings are line-unaware in M0), comments end at LF."""
+ i, n = 0, len(text)
+ tokens = []
+ cur = []
+ def flush():
+ if cur:
+ tokens.append(''.join(cur))
+ cur.clear()
+ while i < n:
+ c = text[i]
+ if c == '"' or c == "'":
+ flush()
+ q = c
+ i += 1
+ while i < n and text[i] != q:
+ i += 1
+ i += 1 # consume closing quote (or end)
+ elif c == '#' or c == ';':
+ flush()
+ while i < n and text[i] != '\n':
+ i += 1
+ elif c.isspace():
+ flush()
+ i += 1
+ else:
+ cur.append(c)
+ i += 1
+ flush()
+ return tokens
-if [ -n "$missing" ]; then
- echo "error: P1 lint: undefined token(s) referenced in M1 source" >&2
- echo " (defs file: $defs)" >&2
- printf ' %s\n' $missing >&2
- exit 1
-fi
+TOKEN_RE = re.compile(r'^[a-z][a-z0-9_,]*$')
+
+defs = defined_names(defs_path)
+used = set()
+for p in prog_paths:
+ with open(p) as f:
+ for tok in tokenize_source(f.read()):
+ if TOKEN_RE.match(tok):
+ used.add(tok)
+
+missing = sorted(t for t in used if t not in defs)
+if missing:
+ sys.stderr.write(
+ f'error: P1 lint: undefined token(s) referenced in M1 source\n'
+ f' (defs file: {defs_path})\n'
+ )
+ for m in missing:
+ sys.stderr.write(f' {m}\n')
+ sys.exit(1)
+PYEOF
diff --git a/src/lisp.M1 b/src/lisp.M1
@@ -53,12 +53,8 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## Step-2 layout preserved: two 8-byte cells whose upper 4 bytes are
## zero (ELF_base < 4 GiB, so `&label` fits in 32 bits). Keep the high
## word as `%0`; bare `00 00 00 00` byte tokens still upset riscv64 M0.
-:heap_next
-&heap_start
-%0
-:heap_end
-&heap_tail
-%0
+:heap_next &heap_start %0
+:heap_end &heap_tail %0
## ---- _start ----------------------------------------------------------
@@ -79,206 +75,158 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## then NULL, then envp. We need argc and argv[1] before any CALL
## (no PROLOGUE on _start — CALL would bury the kernel frame under
## a pushed retaddr on amd64).
- P1_LD_R0_SP_0 ## r0 = argc
- P1_LI_R1
- %2
- P1_LI_BR
- &err_usage
- P1_BLT_R0_R1 ## argc < 2 → err_usage
- P1_LD_R2_SP_16 ## r2 = argv[1] (survives SYSCALL)
+ ld_r0,sp,0 ## r0 = argc
+ li_r1 %2
+ li_br &err_usage
+ blt_r0,r1 ## argc < 2 → err_usage
+ ld_r2,sp,16 ## r2 = argv[1] (survives SYSCALL)
## openat(AT_FDCWD=-100, argv[1], O_RDONLY=0, mode=0) → r0 = fd.
## Use openat rather than open because open is amd64-only
## (removed from the asm-generic table used by aarch64/riscv64).
## LI zero-extends; low 32 bits 0xFFFFFF9C decode as -100 in int32.
- P1_LI_R0
- SYS_OPENAT
- P1_LI_R1
- %-100
- P1_LI_R3
- %0
- P1_LI_R4
- %0
- P1_SYSCALL
-
- P1_LI_BR
- &err_open
- P1_BLTZ_R0 ## fd < 0 → err_open
+ li_r0 sys_openat
+ li_r1 %-100
+ li_r3 %0
+ li_r4 %0
+ syscall
+
+ li_br &err_open
+ bltz_r0 ## fd < 0 → err_open
## read_file_all(fd, src_buf, SRC_BUF_SIZE) → r0 = bytes_read.
## Stash fd in r4 so it survives the CALL; r4 is callee-saved.
- P1_MOV_R4_R0
- P1_MOV_R1_R0
- P1_LI_R2
- &src_buf
- P1_LI_R3
- %16384 ## 16384-byte capacity
- P1_LI_BR
- &read_file_all
- P1_CALL
+ mov_r4,r0
+ mov_r1,r0
+ li_r2 &src_buf
+ li_r3 %16384 ## 16384-byte capacity
+ li_br &read_file_all
+ call
## Filling the buffer exactly means the file was ≥ SRC_BUF_SIZE —
## bail out rather than silently truncate.
- P1_LI_R1
- %16384
- P1_LI_BR
- &err_src_too_big
- P1_BEQ_R0_R1
+ li_r1 %16384
+ li_br &err_src_too_big
+ beq_r0,r1
## Publish src_base/src_len so the reader can walk the source,
## and park (src_buf, bytes_read) in callee-saved r6/r7 so the
## tuple survives primitive registration + prelude eval down to
## the final eval_source CALL below. Capture r0 into r7 NOW —
- ## SYS_CLOSE below will overwrite r0 with its own return value.
- P1_MOV_R7_R0 ## r7 = bytes_read (captured pre-close)
- P1_LI_R6
- &src_buf ## r6 = &src_buf
- P1_LI_R1
- &src_len
- P1_ST_R7_R1_0
- P1_LI_R1
- &src_base
- P1_ST_R6_R1_0
+ ## sys_close below will overwrite r0 with its own return value.
+ mov_r7,r0 ## r7 = bytes_read (captured pre-close)
+ li_r6 &src_buf ## r6 = &src_buf
+ li_r1 &src_len
+ st_r7,r1,0
+ li_r1 &src_base
+ st_r6,r1,0
## close(fd). r4 still holds fd; SYSCALL clobbers r0 only.
- P1_LI_R0
- SYS_CLOSE
- P1_MOV_R1_R4
- P1_SYSCALL
+ li_r0 sys_close
+ mov_r1,r4
+ syscall
## Align heap_next up to 8 (pair/closure tags need 8-aligned raw
## pointers — see step 2).
- P1_LI_R4
- &heap_next
- P1_LD_R0_R4_0
- P1_ORI_R0_R0_7
- P1_ADDI_R0_R0_1
- P1_ST_R0_R4_0
+ li_r4 &heap_next
+ ld_r0,r4,0
+ ori_r0,r0,7
+ addi_r0,r0,1
+ st_r0,r4,0
## Intern the special-form symbols up front. eval_pair compares the
## car of every compound expression against these pointers, so they
## must exist before the first eval call. The intern result (r0 =
## tagged sym) is stashed at &sym_* via ST_R0_R2_0 (the target addr
## in r2); ST_R0_R1_0 isn't in the P1 op table.
- P1_LI_R1
- &str_quote
- P1_LI_R2
- %5
- P1_LI_BR
- &intern
- P1_CALL
- P1_LI_R2
- &sym_quote
- P1_ST_R0_R2_0
-
- P1_LI_R1
- &str_if
- P1_LI_R2
- %2
- P1_LI_BR
- &intern
- P1_CALL
- P1_LI_R2
- &sym_if
- P1_ST_R0_R2_0
-
- P1_LI_R1
- &str_begin
- P1_LI_R2
- %5
- P1_LI_BR
- &intern
- P1_CALL
- P1_LI_R2
- &sym_begin
- P1_ST_R0_R2_0
-
- P1_LI_R1
- &str_lambda
- P1_LI_R2
- %6
- P1_LI_BR
- &intern
- P1_CALL
- P1_LI_R2
- &sym_lambda
- P1_ST_R0_R2_0
-
- P1_LI_R1
- &str_define
- P1_LI_R2
- %6
- P1_LI_BR
- &intern
- P1_CALL
- P1_LI_R2
- &sym_define
- P1_ST_R0_R2_0
+ li_r1 &str_quote
+ li_r2 %5
+ li_br &intern
+ call
+ li_r2 &sym_quote
+ st_r0,r2,0
+
+ li_r1 &str_if
+ li_r2 %2
+ li_br &intern
+ call
+ li_r2 &sym_if
+ st_r0,r2,0
+
+ li_r1 &str_begin
+ li_r2 %5
+ li_br &intern
+ call
+ li_r2 &sym_begin
+ st_r0,r2,0
+
+ li_r1 &str_lambda
+ li_r2 %6
+ li_br &intern
+ call
+ li_r2 &sym_lambda
+ st_r0,r2,0
+
+ li_r1 &str_define
+ li_r2 %6
+ li_br &intern
+ call
+ li_r2 &sym_define
+ st_r0,r2,0
## Register primitives (LISP.md step 10b). Walk prim_table with
## r4 = cursor, r5 = saved sym across make_primitive. Entry is
## 40 bytes; zero name pointer ends the loop.
- P1_LI_R4
- &prim_table
+ li_r4 &prim_table
:_start_reg_prim_loop
- P1_LD_R1_R4_0 ## r1 = name ptr
- P1_LI_BR
- &_start_reg_prim_done
- P1_BEQZ_R1
-
- P1_LD_R2_R4_8 ## r2 = length
- P1_LI_BR
- &intern
- P1_CALL ## r0 = tagged sym
- P1_MOV_R5_R0
-
- P1_LD_R1_R4_16 ## r1 = code id
- P1_LD_R2_R4_32 ## r2 = arity
- P1_LD_R3_R4_24 ## r3 = type
- P1_LI_BR
- &make_primitive
- P1_CALL ## r0 = tagged prim
-
- P1_MOV_R2_R0
- P1_MOV_R1_R5
- P1_LI_BR
- &gset
- P1_CALL
-
- P1_ADDI_R4_R4_40
- P1_LI_BR
- &_start_reg_prim_loop
- P1_B
+ ld_r1,r4,0 ## r1 = name ptr
+ li_br &_start_reg_prim_done
+ beqz_r1
+
+ ld_r2,r4,8 ## r2 = length
+ li_br &intern
+ call ## r0 = tagged sym
+ mov_r5,r0
+
+ ld_r1,r4,16 ## r1 = code id
+ ld_r2,r4,32 ## r2 = arity
+ ld_r3,r4,24 ## r3 = type
+ li_br &make_primitive
+ call ## r0 = tagged prim
+
+ mov_r2,r0
+ mov_r1,r5
+ li_br &gset
+ call
+
+ addi_r4,r4,40
+ li_br &_start_reg_prim_loop
+ b
:_start_reg_prim_done
## Prelude eval disabled pending investigation — see LISP.md step 10h.
## Evaluate the script read from argv[1].
- P1_MOV_R1_R6
- P1_MOV_R2_R7
- P1_LI_BR
- &eval_source
- P1_CALL
- P1_MOV_R4_R0
+ mov_r1,r6
+ mov_r2,r7
+ li_br &eval_source
+ call
+ mov_r4,r0
:_start_done
## Print the final result (write form) + newline for visibility.
- P1_MOV_R1_R4
- P1_LI_BR
- &write
- P1_CALL
- P1_LI_R1
- %10
- P1_LI_BR
- &putc
- P1_CALL
+ mov_r1,r4
+ li_br &write
+ call
+ li_r1 %10
+ li_br &putc
+ call
## Exit status = decoded fixnum of last_result (bit-cast to low 8
## bits by the kernel). Non-fixnum results still exit cleanly —
## the low 8 bits of the tagged word are used.
- P1_LI_R0
- SYS_EXIT
- P1_MOV_R1_R4
- P1_SARI_R1_R1_3
- P1_SYSCALL
+ li_r0 sys_exit
+ mov_r1,r4
+ sari_r1,r1,3
+ syscall
## ---- read_file_all(r1=fd, r2=buf, r3=cap) -> r0 = total_bytes ------
@@ -286,218 +234,173 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## we can park state there across each read() call. No PROLOGUE needed:
## we only issue syscalls, never CALL.
:read_file_all
- P1_MOV_R4_R1 ## r4 = fd
- P1_MOV_R5_R2 ## r5 = cur buf ptr
- P1_MOV_R6_R3 ## r6 = remaining capacity
- P1_LI_R7
- %0 ## r7 = total_read
+ mov_r4,r1 ## r4 = fd
+ mov_r5,r2 ## r5 = cur buf ptr
+ mov_r6,r3 ## r6 = remaining capacity
+ li_r7 %0 ## r7 = total_read
:read_file_all_loop
## Capacity exhausted → stop; _start checks for the exact-full
## case and escalates to err_src_too_big.
- P1_LI_BR
- &read_file_all_done
- P1_BEQZ_R6
+ li_br &read_file_all_done
+ beqz_r6
- P1_LI_R0
- SYS_READ
- P1_MOV_R1_R4
- P1_MOV_R2_R5
- P1_MOV_R3_R6
- P1_SYSCALL ## r0 = n (0=EOF, <0=err)
+ li_r0 sys_read
+ mov_r1,r4
+ mov_r2,r5
+ mov_r3,r6
+ syscall ## r0 = n (0=EOF, <0=err)
## n <= 0 → done. Check < 0 first, then == 0.
- P1_LI_BR
- &read_file_all_done
- P1_BLTZ_R0
- P1_LI_BR
- &read_file_all_done
- P1_BEQZ_R0
-
- P1_ADD_R5_R5_R0 ## buf += n
- P1_SUB_R6_R6_R0 ## cap -= n
- P1_ADD_R7_R7_R0 ## total += n
- P1_LI_BR
- &read_file_all_loop
- P1_B
+ li_br &read_file_all_done
+ bltz_r0
+ li_br &read_file_all_done
+ beqz_r0
+
+ add_r5,r5,r0 ## buf += n
+ sub_r6,r6,r0 ## cap -= n
+ add_r7,r7,r0 ## total += n
+ li_br &read_file_all_loop
+ b
:read_file_all_done
- P1_MOV_R0_R7
- P1_RET
+ mov_r0,r7
+ ret
## ---- write_file_all(r1=fd, r2=buf, r3=len) -> r0 = total|-1 -------
## Mirror of read_file_all: write until len reaches zero or an error
## occurs. Returning -1 lets write-file raise a Lisp-facing error.
:write_file_all
- P1_MOV_R4_R1 ## r4 = fd
- P1_MOV_R5_R2 ## r5 = cursor
- P1_MOV_R6_R3 ## r6 = remaining
- P1_LI_R7
- %0 ## r7 = total_written
+ mov_r4,r1 ## r4 = fd
+ mov_r5,r2 ## r5 = cursor
+ mov_r6,r3 ## r6 = remaining
+ li_r7 %0 ## r7 = total_written
:write_file_all_loop
- P1_LI_BR
- &write_file_all_done
- P1_BEQZ_R6
-
- P1_LI_R0
- SYS_WRITE
- P1_MOV_R1_R4
- P1_MOV_R2_R5
- P1_MOV_R3_R6
- P1_SYSCALL ## r0 = n (<0 error, 0 unexpected stall)
-
- P1_LI_BR
- &write_file_all_err
- P1_BLTZ_R0
- P1_LI_BR
- &write_file_all_err
- P1_BEQZ_R0
-
- P1_ADD_R5_R5_R0
- P1_SUB_R6_R6_R0
- P1_ADD_R7_R7_R0
- P1_LI_BR
- &write_file_all_loop
- P1_B
+ li_br &write_file_all_done
+ beqz_r6
+
+ li_r0 sys_write
+ mov_r1,r4
+ mov_r2,r5
+ mov_r3,r6
+ syscall ## r0 = n (<0 error, 0 unexpected stall)
+
+ li_br &write_file_all_err
+ bltz_r0
+ li_br &write_file_all_err
+ beqz_r0
+
+ add_r5,r5,r0
+ sub_r6,r6,r0
+ add_r7,r7,r0
+ li_br &write_file_all_loop
+ b
:write_file_all_done
- P1_MOV_R0_R7
- P1_RET
+ mov_r0,r7
+ ret
:write_file_all_err
- P1_LI_R0
- %0
- P1_ADDI_R0_R0_NEG1
- P1_RET
+ li_r0 %0
+ addi_r0,r0,neg1
+ ret
## ---- eval_source(r1=base, r2=len) -> r0 = last_result --------------
## Save the current reader globals, point them at (base,len), evaluate
## every top-level form, then restore the outer reader state.
:eval_source
- P1_PROLOGUE
- P1_ST_R4_SP_8 ## save caller's r4
-
- P1_LI_R3
- &src_base
- P1_LD_R0_R3_0
- P1_LI_R4
- &saved_src_base
- P1_ST_R0_R4_0
- P1_ST_R1_R3_0
-
- P1_LI_R3
- &src_len
- P1_LD_R0_R3_0
- P1_LI_R4
- &saved_src_len
- P1_ST_R0_R4_0
- P1_ST_R2_R3_0
-
- P1_LI_R3
- &src_cursor
- P1_LD_R0_R3_0
- P1_LI_R4
- &saved_src_cursor
- P1_ST_R0_R4_0
- P1_LI_R0
- %0
- P1_ST_R0_R3_0
-
- P1_LI_R3
- &src_line
- P1_LD_R0_R3_0
- P1_LI_R4
- &saved_src_line
- P1_ST_R0_R4_0
- P1_LI_R0
- %1
- P1_ST_R0_R3_0
-
- P1_LI_R3
- &src_col
- P1_LD_R0_R3_0
- P1_LI_R4
- &saved_src_col
- P1_ST_R0_R4_0
- P1_LI_R0
- %1
- P1_ST_R0_R3_0
-
- P1_LI_R4
- %39 ## running last_result = unspec
+ prologue
+ st_r4,sp,8 ## save caller's r4
+
+ li_r3 &src_base
+ ld_r0,r3,0
+ li_r4 &saved_src_base
+ st_r0,r4,0
+ st_r1,r3,0
+
+ li_r3 &src_len
+ ld_r0,r3,0
+ li_r4 &saved_src_len
+ st_r0,r4,0
+ st_r2,r3,0
+
+ li_r3 &src_cursor
+ ld_r0,r3,0
+ li_r4 &saved_src_cursor
+ st_r0,r4,0
+ li_r0 %0
+ st_r0,r3,0
+
+ li_r3 &src_line
+ ld_r0,r3,0
+ li_r4 &saved_src_line
+ st_r0,r4,0
+ li_r0 %1
+ st_r0,r3,0
+
+ li_r3 &src_col
+ ld_r0,r3,0
+ li_r4 &saved_src_col
+ st_r0,r4,0
+ li_r0 %1
+ st_r0,r3,0
+
+ li_r4 %39 ## running last_result = unspec
:eval_source_loop
- P1_LI_BR
- &skip_ws
- P1_CALL
-
- P1_LI_BR
- &peek_char
- P1_CALL
- P1_LI_R1
- %0
- P1_ADDI_R1_R1_NEG1
- P1_LI_BR
- &eval_source_done
- P1_BEQ_R0_R1
-
- P1_LI_BR
- &read_expr
- P1_CALL
- P1_MOV_R1_R0
- P1_LI_R2
- %7
- P1_LI_BR
- &eval
- P1_CALL
- P1_MOV_R4_R0
- P1_LI_BR
- &eval_source_loop
- P1_B
+ li_br &skip_ws
+ call
+
+ li_br &peek_char
+ call
+ li_r1 %0
+ addi_r1,r1,neg1
+ li_br &eval_source_done
+ beq_r0,r1
+
+ li_br &read_expr
+ call
+ mov_r1,r0
+ li_r2 %7
+ li_br &eval
+ call
+ mov_r4,r0
+ li_br &eval_source_loop
+ b
:eval_source_done
- P1_LI_R3
- &saved_src_base
- P1_LD_R0_R3_0
- P1_LI_R1
- &src_base
- P1_ST_R0_R1_0
-
- P1_LI_R3
- &saved_src_len
- P1_LD_R0_R3_0
- P1_LI_R1
- &src_len
- P1_ST_R0_R1_0
-
- P1_LI_R3
- &saved_src_cursor
- P1_LD_R0_R3_0
- P1_LI_R1
- &src_cursor
- P1_ST_R0_R1_0
-
- P1_LI_R3
- &saved_src_line
- P1_LD_R0_R3_0
- P1_LI_R1
- &src_line
- P1_ST_R0_R1_0
-
- P1_LI_R3
- &saved_src_col
- P1_LD_R0_R3_0
- P1_LI_R1
- &src_col
- P1_ST_R0_R1_0
-
- P1_MOV_R0_R4
- P1_LD_R4_SP_8
- P1_EPILOGUE
- P1_RET
+ li_r3 &saved_src_base
+ ld_r0,r3,0
+ li_r1 &src_base
+ st_r0,r1,0
+
+ li_r3 &saved_src_len
+ ld_r0,r3,0
+ li_r1 &src_len
+ st_r0,r1,0
+
+ li_r3 &saved_src_cursor
+ ld_r0,r3,0
+ li_r1 &src_cursor
+ st_r0,r1,0
+
+ li_r3 &saved_src_line
+ ld_r0,r3,0
+ li_r1 &src_line
+ st_r0,r1,0
+
+ li_r3 &saved_src_col
+ ld_r0,r3,0
+ li_r1 &src_col
+ st_r0,r1,0
+
+ mov_r0,r4
+ ld_r4,sp,8
+ epilogue
+ ret
## ---- hash(r1=ptr, r2=len) -> r0 = u64 hash --------------------------
@@ -505,33 +408,29 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## stashing 31 in a register. Uses r6 (zero constant) across the loop;
## saves/restores it via a PROLOGUE_N1 slot.
:hash
- P1_PROLOGUE
- P1_ST_R6_SP_8
+ prologue
+ st_r6,sp,8
- P1_LI_R6
- %0 ## zero const
- P1_LI_R0
- %0 ## h = 0
+ li_r6 %0 ## zero const
+ li_r0 %0 ## h = 0
:hash_loop
- P1_LI_BR
- &hash_done
- P1_BEQ_R2_R6 ## len == 0 → done
-
- P1_SHLI_R3_R0_5 ## r3 = h << 5
- P1_SUB_R3_R3_R0 ## r3 = h*32 - h = h*31
- P1_LB_R0_R1_0 ## r0 = *ptr (zero-extended byte)
- P1_ADD_R0_R0_R3 ## r0 = h*31 + b
- P1_ADDI_R1_R1_1
- P1_ADDI_R2_R2_NEG1
- P1_LI_BR
- &hash_loop
- P1_B
+ li_br &hash_done
+ beq_r2,r6 ## len == 0 → done
+
+ shli_r3,r0,5 ## r3 = h << 5
+ sub_r3,r3,r0 ## r3 = h*32 - h = h*31
+ lb_r0,r1,0 ## r0 = *ptr (zero-extended byte)
+ add_r0,r0,r3 ## r0 = h*31 + b
+ addi_r1,r1,1
+ addi_r2,r2,neg1
+ li_br &hash_loop
+ b
:hash_done
- P1_LD_R6_SP_8
- P1_EPILOGUE
- P1_RET
+ ld_r6,sp,8
+ epilogue
+ ret
## ---- sym_name_equal(r1=tagged_sym, r2=cmp_ptr, r3=cmp_len) -> r0 ---
@@ -539,58 +438,50 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## `cmp_ptr`, else 0. Uses r6 as zero const + r7 as the cmp-byte
## scratch; both are callee-saved, so PROLOGUE_N2 stashes them.
:sym_name_equal
- P1_PROLOGUE_N2
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
+ prologue_n2
+ st_r6,sp,8
+ st_r7,sp,16
- P1_ADDI_R1_R1_NEG5 ## r1 = raw sym ptr
- P1_LD_R6_R1_0 ## r6 = header word
+ addi_r1,r1,neg5 ## r1 = raw sym ptr
+ ld_r6,r1,0 ## r6 = header word
## Mask low 32 bits: our names fit in 32 bits of the 48-bit length.
- P1_SHLI_R6_R6_32
- P1_SHRI_R6_R6_32 ## r6 = sym_len
+ shli_r6,r6,32
+ shri_r6,r6,32 ## r6 = sym_len
- P1_LI_BR
- &sym_name_equal_neq
- P1_BNE_R6_R3 ## lengths differ → not equal
+ li_br &sym_name_equal_neq
+ bne_r6,r3 ## lengths differ → not equal
- P1_ADDI_R1_R1_8 ## r1 = name bytes ptr
- P1_LI_R6
- %0 ## zero const
+ addi_r1,r1,8 ## r1 = name bytes ptr
+ li_r6 %0 ## zero const
:sym_name_equal_loop
- P1_LI_BR
- &sym_name_equal_eq
- P1_BEQ_R3_R6 ## len == 0 → match
-
- P1_LB_R0_R1_0 ## r0 = sym byte
- P1_LB_R7_R2_0 ## r7 = cmp byte
- P1_LI_BR
- &sym_name_equal_neq
- P1_BNE_R0_R7
-
- P1_ADDI_R1_R1_1
- P1_ADDI_R2_R2_1
- P1_ADDI_R3_R3_NEG1
- P1_LI_BR
- &sym_name_equal_loop
- P1_B
+ li_br &sym_name_equal_eq
+ beq_r3,r6 ## len == 0 → match
+
+ lb_r0,r1,0 ## r0 = sym byte
+ lb_r7,r2,0 ## r7 = cmp byte
+ li_br &sym_name_equal_neq
+ bne_r0,r7
+
+ addi_r1,r1,1
+ addi_r2,r2,1
+ addi_r3,r3,neg1
+ li_br &sym_name_equal_loop
+ b
:sym_name_equal_eq
- P1_LI_R0
- %1
- P1_LI_BR
- &sym_name_equal_done
- P1_B
+ li_r0 %1
+ li_br &sym_name_equal_done
+ b
:sym_name_equal_neq
- P1_LI_R0
- %0
+ li_r0 %0
:sym_name_equal_done
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N2
- P1_RET
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n2
+ ret
## ---- make_symbol(r1=src, r2=len) -> r0 = tagged symbol --------------
@@ -602,218 +493,193 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## [sp + 16] saved r7
## [sp + 24] raw_ptr across the copy loop
:make_symbol
- P1_PROLOGUE_N3
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
+ prologue_n3
+ st_r6,sp,8
+ st_r7,sp,16
- P1_MOV_R6_R1 ## r6 = src (mutated during byte copy)
- P1_MOV_R7_R2 ## r7 = len (mutated during byte copy)
+ mov_r6,r1 ## r6 = src (mutated during byte copy)
+ mov_r7,r2 ## r7 = len (mutated during byte copy)
## alloc_size = 8 + ((len + 7) >> 3 << 3)
- P1_ADDI_R1_R7_7
- P1_SHRI_R1_R1_3
- P1_SHLI_R1_R1_3
- P1_ADDI_R1_R1_8
- P1_LI_BR
- &alloc
- P1_CALL ## r0 = raw ptr
+ addi_r1,r7,7
+ shri_r1,r1,3
+ shli_r1,r1,3
+ addi_r1,r1,8
+ li_br &alloc
+ call ## r0 = raw ptr
- P1_ST_R0_SP_24 ## stash raw ptr
+ st_r0,sp,24 ## stash raw ptr
## Header: store len in low 48 bits, then stamp type=2 in byte 7.
- P1_ST_R7_R0_0
- P1_LI_R1
- %2
- P1_SB_R1_R0_7
+ st_r7,r0,0
+ li_r1 %2
+ sb_r1,r0,7
## Byte copy: dst = r3 (= raw+8), src = r6, len = r7.
- P1_ADDI_R3_R0_8
- P1_LI_R1
- %0 ## zero const for loop test
+ addi_r3,r0,8
+ li_r1 %0 ## zero const for loop test
:make_symbol_copy
- P1_LI_BR
- &make_symbol_done
- P1_BEQ_R7_R1
-
- P1_LB_R2_R6_0
- P1_SB_R2_R3_0
- P1_ADDI_R6_R6_1
- P1_ADDI_R3_R3_1
- P1_ADDI_R7_R7_NEG1
- P1_LI_BR
- &make_symbol_copy
- P1_B
+ li_br &make_symbol_done
+ beq_r7,r1
+
+ lb_r2,r6,0
+ sb_r2,r3,0
+ addi_r6,r6,1
+ addi_r3,r3,1
+ addi_r7,r7,neg1
+ li_br &make_symbol_copy
+ b
:make_symbol_done
- P1_LD_R0_SP_24
- P1_ORI_R0_R0_4 ## set bit 2 (aarch64 bitmask-imm can't do 0b101 directly)
- P1_ORI_R0_R0_1 ## set bit 0 → tag = 101 (SYMBOL)
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N3
- P1_RET
+ ld_r0,sp,24
+ ori_r0,r0,4 ## set bit 2 (aarch64 bitmask-imm can't do 0b101 directly)
+ ori_r0,r0,1 ## set bit 0 → tag = 101 (SYMBOL)
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n3
+ ret
## ---- byte_copy(r1=dst, r2=src, r3=len) -> r0 = dst_end -------------
## Raw byte copy used by string construction, path marshaling, and
## string-append. No overlap handling needed in the seed.
:byte_copy
- P1_LI_R0
- %0
+ li_r0 %0
:byte_copy_loop
- P1_LI_BR
- &byte_copy_done
- P1_BEQ_R3_R0
- P1_LB_R0_R2_0
- P1_SB_R0_R1_0
- P1_ADDI_R1_R1_1
- P1_ADDI_R2_R2_1
- P1_ADDI_R3_R3_NEG1
- P1_LI_R0
- %0
- P1_LI_BR
- &byte_copy_loop
- P1_B
+ li_br &byte_copy_done
+ beq_r3,r0
+ lb_r0,r2,0
+ sb_r0,r1,0
+ addi_r1,r1,1
+ addi_r2,r2,1
+ addi_r3,r3,neg1
+ li_r0 %0
+ li_br &byte_copy_loop
+ b
:byte_copy_done
- P1_MOV_R0_R1
- P1_RET
+ mov_r0,r1
+ ret
## ---- alloc_string(r1=len) -> r0 = tagged string ---------------------
## Allocates header + zero or more payload bytes, stamps type=1, and
## leaves the payload for the caller to fill.
:alloc_string
- P1_PROLOGUE
- P1_ST_R1_SP_8
-
- P1_ADDI_R1_R1_7
- P1_SHRI_R1_R1_3
- P1_SHLI_R1_R1_3
- P1_ADDI_R1_R1_8
- P1_LI_BR
- &alloc
- P1_CALL
-
- P1_LD_R1_SP_8
- P1_ST_R1_R0_0
- P1_LI_R1
- %1
- P1_SB_R1_R0_7
- P1_ORI_R0_R0_4 ## tag = 100 (string)
- P1_EPILOGUE
- P1_RET
+ prologue
+ st_r1,sp,8
+
+ addi_r1,r1,7
+ shri_r1,r1,3
+ shli_r1,r1,3
+ addi_r1,r1,8
+ li_br &alloc
+ call
+
+ ld_r1,sp,8
+ st_r1,r0,0
+ li_r1 %1
+ sb_r1,r0,7
+ ori_r0,r0,4 ## tag = 100 (string)
+ epilogue
+ ret
## ---- make_string(r1=src, r2=len) -> r0 = tagged string -------------
:make_string
- P1_PROLOGUE_N3
- P1_ST_R1_SP_8
- P1_ST_R2_SP_16
+ prologue_n3
+ st_r1,sp,8
+ st_r2,sp,16
- P1_MOV_R1_R2
- P1_LI_BR
- &alloc_string
- P1_CALL
- P1_ST_R0_SP_24
+ mov_r1,r2
+ li_br &alloc_string
+ call
+ st_r0,sp,24
- P1_ADDI_R1_R0_NEG4 ## raw string ptr
- P1_ADDI_R1_R1_8 ## dst payload
- P1_LD_R2_SP_8 ## src payload
- P1_LD_R3_SP_16 ## len
- P1_LI_BR
- &byte_copy
- P1_CALL
+ addi_r1,r0,neg4 ## raw string ptr
+ addi_r1,r1,8 ## dst payload
+ ld_r2,sp,8 ## src payload
+ ld_r3,sp,16 ## len
+ li_br &byte_copy
+ call
- P1_LD_R0_SP_24
- P1_EPILOGUE_N3
- P1_RET
+ ld_r0,sp,24
+ epilogue_n3
+ ret
## ---- make_vector(r1=len_raw, r2=init) -> r0 = tagged vector --------
## Allocates header + len tagged slots, stamps type=3, and fills every
## element with `init`.
:make_vector
- P1_PROLOGUE_N2
- P1_ST_R1_SP_8
- P1_ST_R2_SP_16
-
- P1_SHLI_R1_R1_3
- P1_ADDI_R1_R1_8
- P1_LI_BR
- &alloc
- P1_CALL
-
- P1_LD_R1_SP_8 ## len_raw
- P1_ST_R0_SP_8 ## overwrite slot1 = raw ptr
- P1_ST_R1_R0_0
- P1_LI_R1
- %3
- P1_SB_R1_R0_7
-
- P1_LD_R1_SP_8 ## raw ptr
- P1_LD_R2_SP_16 ## init
- P1_LD_R0_R1_0 ## header word (type|len)
- P1_SHLI_R0_R0_16 ## mask off type byte
- P1_SHRI_R0_R0_16 ## r0 = len_raw
- P1_ADDI_R1_R1_8 ## payload cursor
- P1_LI_R3
- %0
+ prologue_n2
+ st_r1,sp,8
+ st_r2,sp,16
+
+ shli_r1,r1,3
+ addi_r1,r1,8
+ li_br &alloc
+ call
+
+ ld_r1,sp,8 ## len_raw
+ st_r0,sp,8 ## overwrite slot1 = raw ptr
+ st_r1,r0,0
+ li_r1 %3
+ sb_r1,r0,7
+
+ ld_r1,sp,8 ## raw ptr
+ ld_r2,sp,16 ## init
+ ld_r0,r1,0 ## header word (type|len)
+ shli_r0,r0,16 ## mask off type byte
+ shri_r0,r0,16 ## r0 = len_raw
+ addi_r1,r1,8 ## payload cursor
+ li_r3 %0
:make_vector_loop
- P1_LI_BR
- &make_vector_done
- P1_BEQ_R0_R3
- P1_ST_R2_R1_0
- P1_ADDI_R1_R1_8
- P1_ADDI_R0_R0_NEG1
- P1_LI_BR
- &make_vector_loop
- P1_B
+ li_br &make_vector_done
+ beq_r0,r3
+ st_r2,r1,0
+ addi_r1,r1,8
+ addi_r0,r0,neg1
+ li_br &make_vector_loop
+ b
:make_vector_done
- P1_LD_R0_SP_8
- P1_ORI_R0_R0_2
- P1_ORI_R0_R0_1 ## tag = 011 (vector)
- P1_EPILOGUE_N2
- P1_RET
+ ld_r0,sp,8
+ ori_r0,r0,2
+ ori_r0,r0,1 ## tag = 011 (vector)
+ epilogue_n2
+ ret
## ---- string_to_c_path(r1=tagged_string) -> r0 = &path_buf ----------
## Copies the string bytes to a shared NUL-terminated buffer so openat
## can consume it as a kernel pathname.
:string_to_c_path
- P1_PROLOGUE_N2
- P1_ADDI_R1_R1_NEG4 ## raw string ptr
- P1_LD_R2_R1_0
- P1_SHLI_R2_R2_16
- P1_SHRI_R2_R2_16 ## r2 = len
- P1_MOV_R3_R2
- P1_LI_R0
- %256 ## PATH_BUF_SIZE = 256
- P1_LI_BR
- &string_to_c_path_ok
- P1_BLT_R3_R0
- P1_LI_BR
- &err_path_too_long
- P1_B
+ prologue_n2
+ addi_r1,r1,neg4 ## raw string ptr
+ ld_r2,r1,0
+ shli_r2,r2,16
+ shri_r2,r2,16 ## r2 = len
+ mov_r3,r2
+ li_r0 %256 ## PATH_BUF_SIZE = 256
+ li_br &string_to_c_path_ok
+ blt_r3,r0
+ li_br &err_path_too_long
+ b
:string_to_c_path_ok
- P1_MOV_R0_SP
- P1_ST_R2_R0_8
- P1_ADDI_R1_R1_8 ## payload ptr
- P1_ST_R1_R0_16
- P1_LI_R1
- &path_buf
- P1_LD_R2_R0_16
- P1_LD_R3_R0_8
- P1_LI_BR
- &byte_copy
- P1_CALL
- P1_LI_R1
- %0
- P1_SB_R1_R0_0
- P1_LI_R0
- &path_buf
- P1_EPILOGUE_N2
- P1_RET
+ mov_r0,sp
+ st_r2,r0,8
+ addi_r1,r1,8 ## payload ptr
+ st_r1,r0,16
+ li_r1 &path_buf
+ ld_r2,r0,16
+ ld_r3,r0,8
+ li_br &byte_copy
+ call
+ li_r1 %0
+ sb_r1,r0,0
+ li_r0 &path_buf
+ epilogue_n2
+ ret
## ---- intern(r1=name_ptr, r2=name_len) -> r0 = tagged sym -----------
@@ -822,317 +688,244 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## Frame layout: slot 1 = saved r6, slot 2 = saved r7, slot 3 = current
## probe index h.
:intern
- P1_PROLOGUE_N3
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
+ prologue_n3
+ st_r6,sp,8
+ st_r7,sp,16
- P1_MOV_R6_R1 ## r6 = name_ptr (callee-saved copy)
- P1_MOV_R7_R2 ## r7 = name_len
+ mov_r6,r1 ## r6 = name_ptr (callee-saved copy)
+ mov_r7,r2 ## r7 = name_len
- P1_LI_BR
- &hash
- P1_CALL ## r0 = 64-bit hash
- P1_SHLI_R0_R0_52
- P1_SHRI_R0_R0_52 ## r0 = h & 4095
+ li_br &hash
+ call ## r0 = 64-bit hash
+ shli_r0,r0,52
+ shri_r0,r0,52 ## r0 = h & 4095
- P1_MOV_R3_SP
- P1_ST_R0_SP_24 ## slot 3 = h
+ mov_r3,sp
+ st_r0,sp,24 ## slot 3 = h
:intern_probe
- P1_LD_R0_SP_24
- P1_SHLI_R0_R0_3 ## r0 = h * 8
- P1_LI_R2
- &symbol_table
- P1_ADD_R2_R2_R0 ## r2 = &symbol_table[h]
- P1_LD_R3_R2_0 ## r3 = slot value
+ ld_r0,sp,24
+ shli_r0,r0,3 ## r0 = h * 8
+ li_r2 &symbol_table
+ add_r2,r2,r0 ## r2 = &symbol_table[h]
+ ld_r3,r2,0 ## r3 = slot value
- P1_LI_BR
- &intern_empty
- P1_BEQZ_R3 ## slot == 0 → allocate
+ li_br &intern_empty
+ beqz_r3 ## slot == 0 → allocate
## Compare existing symbol to (r6, r7).
- P1_MOV_R1_R3 ## r1 = tagged sym
- P1_MOV_R2_R6 ## r2 = cmp_ptr
- P1_MOV_R3_R7 ## r3 = cmp_len
- P1_LI_BR
- &sym_name_equal
- P1_CALL ## r0 = 0 or 1
+ mov_r1,r3 ## r1 = tagged sym
+ mov_r2,r6 ## r2 = cmp_ptr
+ mov_r3,r7 ## r3 = cmp_len
+ li_br &sym_name_equal
+ call ## r0 = 0 or 1
- P1_LI_BR
- &intern_hit
- P1_BNEZ_R0
+ li_br &intern_hit
+ bnez_r0
## Advance h = (h+1) & 4095.
- P1_LD_R0_SP_24
- P1_ADDI_R0_R0_1
- P1_SHLI_R0_R0_52
- P1_SHRI_R0_R0_52
- P1_ST_R0_SP_24
- P1_LI_BR
- &intern_probe
- P1_B
+ ld_r0,sp,24
+ addi_r0,r0,1
+ shli_r0,r0,52
+ shri_r0,r0,52
+ st_r0,sp,24
+ li_br &intern_probe
+ b
:intern_empty
## Allocate a fresh symbol and plant it in the slot.
- P1_MOV_R1_R6
- P1_MOV_R2_R7
- P1_LI_BR
- &make_symbol
- P1_CALL ## r0 = tagged sym
-
- P1_LD_R1_SP_24
- P1_SHLI_R1_R1_3
- P1_LI_R2
- &symbol_table
- P1_ADD_R2_R2_R1
- P1_ST_R0_R2_0 ## write into slot
-
- P1_LI_BR
- &intern_done
- P1_B
+ mov_r1,r6
+ mov_r2,r7
+ li_br &make_symbol
+ call ## r0 = tagged sym
+
+ ld_r1,sp,24
+ shli_r1,r1,3
+ li_r2 &symbol_table
+ add_r2,r2,r1
+ st_r0,r2,0 ## write into slot
+
+ li_br &intern_done
+ b
:intern_hit
- P1_MOV_R3_SP
- P1_LD_R0_SP_24
- P1_SHLI_R0_R0_3
- P1_LI_R2
- &symbol_table
- P1_ADD_R2_R2_R0
- P1_LD_R0_R2_0 ## r0 = existing tagged sym
+ mov_r3,sp
+ ld_r0,sp,24
+ shli_r0,r0,3
+ li_r2 &symbol_table
+ add_r2,r2,r0
+ ld_r0,r2,0 ## r0 = existing tagged sym
:intern_done
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N3
- P1_RET
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n3
+ ret
## ---- cons / car / cdr (preserved from step 2) -----------------------
:cons
- P1_PROLOGUE_N2
- P1_ST_R1_SP_8
- P1_ST_R2_SP_16
- P1_LI_R1
- %16
- P1_LI_BR
- &alloc
- P1_CALL
- P1_LD_R1_SP_8
- P1_ST_R1_R0_0
- P1_LD_R2_SP_16
- P1_ST_R2_R0_8
- P1_ORI_R0_R0_2
- P1_EPILOGUE_N2
- P1_RET
+ prologue_n2
+ st_r1,sp,8
+ st_r2,sp,16
+ li_r1 %16
+ li_br &alloc
+ call
+ ld_r1,sp,8
+ st_r1,r0,0
+ ld_r2,sp,16
+ st_r2,r0,8
+ ori_r0,r0,2
+ epilogue_n2
+ ret
:car
- P1_ADDI_R1_R1_NEG2
- P1_LD_R0_R1_0
- P1_RET
+ addi_r1,r1,neg2
+ ld_r0,r1,0
+ ret
:cdr
- P1_ADDI_R1_R1_NEG2
- P1_LD_R0_R1_8
- P1_RET
+ addi_r1,r1,neg2
+ ld_r0,r1,8
+ ret
## ---- alloc(size) -> raw_ptr (preserved from step 2) -----------------
:alloc
- P1_PROLOGUE
- P1_LI_R3
- &heap_next
- P1_LD_R0_R3_0
- P1_ADD_R2_R0_R1
- P1_LI_R1
- &heap_end
- P1_LD_R1_R1_0
- P1_LI_BR
- &alloc_oom
- P1_BLT_R1_R2
- P1_ST_R2_R3_0
- P1_EPILOGUE
- P1_RET
+ prologue
+ li_r3 &heap_next
+ ld_r0,r3,0
+ add_r2,r0,r1
+ li_r1 &heap_end
+ ld_r1,r1,0
+ li_br &alloc_oom
+ blt_r1,r2
+ st_r2,r3,0
+ epilogue
+ ret
## ---- error(msg_ptr, msg_len) ----------------------------------------
:error
- P1_MOV_R6_R1
- P1_MOV_R7_R2
-
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %2
- P1_LI_R2
- &msg_error_prefix
- P1_LI_R3
- %7
- P1_SYSCALL
-
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %2
- P1_MOV_R2_R6
- P1_MOV_R3_R7
- P1_SYSCALL
-
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %2
- P1_LI_R2
- &msg_newline
- P1_LI_R3
- %1
- P1_SYSCALL
-
- P1_LI_R0
- SYS_EXIT
- P1_LI_R1
- %1
- P1_SYSCALL
+ mov_r6,r1
+ mov_r7,r2
+
+ li_r0 sys_write
+ li_r1 %2
+ li_r2 &msg_error_prefix
+ li_r3 %7
+ syscall
+
+ li_r0 sys_write
+ li_r1 %2
+ mov_r2,r6
+ mov_r3,r7
+ syscall
+
+ li_r0 sys_write
+ li_r1 %2
+ li_r2 &msg_newline
+ li_r3 %1
+ syscall
+
+ li_r0 sys_exit
+ li_r1 %1
+ syscall
## ---- Error landing pads ---------------------------------------------
:alloc_oom
- P1_LI_R1
- &msg_oom
- P1_LI_R2
- %14
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_oom
+ li_r2 %14
+ li_br &error
+ b
:err_intern_not_eq
- P1_LI_R1
- &msg_intern_not_eq
- P1_LI_R2
- %34 ## strlen == 34
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_intern_not_eq
+ li_r2 %34 ## strlen == 34
+ li_br &error
+ b
:err_intern_collision
- P1_LI_R1
- &msg_intern_collision
- P1_LI_R2
- %44 ## strlen == 44
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_intern_collision
+ li_r2 %44 ## strlen == 44
+ li_br &error
+ b
:err_usage
- P1_LI_R1
- &msg_usage
- P1_LI_R2
- %22 ## strlen("usage: lisp <file.scm>") == 22
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_usage
+ li_r2 %22 ## strlen("usage: lisp <file.scm>") == 22
+ li_br &error
+ b
:err_open
- P1_LI_R1
- &msg_open_fail
- P1_LI_R2
- %26 ## strlen("failed to open source file") == 26
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_open_fail
+ li_r2 %26 ## strlen("failed to open source file") == 26
+ li_br &error
+ b
:err_src_too_big
- P1_LI_R1
- &msg_src_too_big
- P1_LI_R2
- %21 ## strlen("source file too large") == 21
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_src_too_big
+ li_r2 %21 ## strlen("source file too large") == 21
+ li_br &error
+ b
## err_reader_bad: "error: reader: malformed input at LINE:COL\n" → stderr.
## Doesn't go through :error because we want line:col tacked on; easier to
## inline the syscalls than thread a format through error().
:err_reader_bad
## "error: "
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %2
- P1_LI_R2
- &msg_error_prefix
- P1_LI_R3
- %7
- P1_SYSCALL
+ li_r0 sys_write
+ li_r1 %2
+ li_r2 &msg_error_prefix
+ li_r3 %7
+ syscall
## "reader: malformed input"
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %2
- P1_LI_R2
- &msg_reader_bad
- P1_LI_R3
- %23 ## strlen("reader: malformed input") == 23
- P1_SYSCALL
+ li_r0 sys_write
+ li_r1 %2
+ li_r2 &msg_reader_bad
+ li_r3 %23 ## strlen("reader: malformed input") == 23
+ syscall
## " at "
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %2
- P1_LI_R2
- &msg_at
- P1_LI_R3
- %4
- P1_SYSCALL
+ li_r0 sys_write
+ li_r1 %2
+ li_r2 &msg_at
+ li_r3 %4
+ syscall
## LINE (via display_uint to stderr)
- P1_LI_R1
- &src_line
- P1_LD_R1_R1_0
- P1_LI_R2
- %2
- P1_LI_BR
- &display_uint
- P1_CALL
+ li_r1 &src_line
+ ld_r1,r1,0
+ li_r2 %2
+ li_br &display_uint
+ call
## ":"
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %2
- P1_LI_R2
- &msg_colon
- P1_LI_R3
- %1
- P1_SYSCALL
+ li_r0 sys_write
+ li_r1 %2
+ li_r2 &msg_colon
+ li_r3 %1
+ syscall
## COL
- P1_LI_R1
- &src_col
- P1_LD_R1_R1_0
- P1_LI_R2
- %2
- P1_LI_BR
- &display_uint
- P1_CALL
+ li_r1 &src_col
+ ld_r1,r1,0
+ li_r2 %2
+ li_br &display_uint
+ call
## "\n"
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %2
- P1_LI_R2
- &msg_newline
- P1_LI_R3
- %1
- P1_SYSCALL
-
- P1_LI_R0
- SYS_EXIT
- P1_LI_R1
- %1
- P1_SYSCALL
+ li_r0 sys_write
+ li_r1 %2
+ li_r2 &msg_newline
+ li_r3 %1
+ syscall
+
+ li_r0 sys_exit
+ li_r1 %1
+ syscall
## ================ Step 4: reader + minimal display ==================
@@ -1146,207 +939,153 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## ---- Reader state (globals) -----------------------------------------
## src_base/src_len are set by _start after it reads argv[1] into
## src_buf. src_cursor starts at 0; src_line/src_col start at 1.
-:src_base
-%0
-%0
-:src_len
-%0
-%0
-:src_cursor
-%0
-%0
-:src_line
-%1
-%0
-:src_col
-%1
-%0
+:src_base %0 %0
+:src_len %0 %0
+:src_cursor %0 %0
+:src_line %1 %0
+:src_col %1 %0
## ---- peek_char() -> r0 = char (0..255) or -1 on EOF ----------------
:peek_char
- P1_LI_R1
- &src_cursor
- P1_LD_R1_R1_0 ## r1 = cursor
- P1_LI_R2
- &src_len
- P1_LD_R2_R2_0 ## r2 = len
- P1_LI_BR
- &peek_char_inb
- P1_BLT_R1_R2 ## cursor < len → in-bounds
- P1_LI_R0
- %0
- P1_ADDI_R0_R0_NEG1 ## r0 = -1
- P1_RET
+ li_r1 &src_cursor
+ ld_r1,r1,0 ## r1 = cursor
+ li_r2 &src_len
+ ld_r2,r2,0 ## r2 = len
+ li_br &peek_char_inb
+ blt_r1,r2 ## cursor < len → in-bounds
+ li_r0 %0
+ addi_r0,r0,neg1 ## r0 = -1
+ ret
:peek_char_inb
- P1_LI_R2
- &src_base
- P1_LD_R2_R2_0 ## r2 = base
- P1_ADD_R2_R2_R1 ## r2 = base + cursor
- P1_LB_R0_R2_0 ## r0 = *ptr (0-ext byte)
- P1_RET
+ li_r2 &src_base
+ ld_r2,r2,0 ## r2 = base
+ add_r2,r2,r1 ## r2 = base + cursor
+ lb_r0,r2,0 ## r0 = *ptr (0-ext byte)
+ ret
## ---- advance_char() — consume current char, track line/col --------
:advance_char
- P1_PROLOGUE
- P1_LI_BR
- &peek_char
- P1_CALL ## r0 = current char (possibly -1 if EOF)
+ prologue
+ li_br &peek_char
+ call ## r0 = current char (possibly -1 if EOF)
## cursor++
- P1_LI_R1
- &src_cursor
- P1_LD_R2_R1_0
- P1_ADDI_R2_R2_1
- P1_ST_R2_R1_0
+ li_r1 &src_cursor
+ ld_r2,r1,0
+ addi_r2,r2,1
+ st_r2,r1,0
## if char == '\n', bump line and reset col; else col++.
- P1_LI_R1
- %10 ## '\n' = 10
- P1_LI_BR
- &advance_newline
- P1_BEQ_R0_R1
-
- P1_LI_R1
- &src_col
- P1_LD_R2_R1_0
- P1_ADDI_R2_R2_1
- P1_ST_R2_R1_0
- P1_EPILOGUE
- P1_RET
+ li_r1 %10 ## '\n' = 10
+ li_br &advance_newline
+ beq_r0,r1
+
+ li_r1 &src_col
+ ld_r2,r1,0
+ addi_r2,r2,1
+ st_r2,r1,0
+ epilogue
+ ret
:advance_newline
- P1_LI_R1
- &src_line
- P1_LD_R2_R1_0
- P1_ADDI_R2_R2_1
- P1_ST_R2_R1_0
- P1_LI_R1
- &src_col
- P1_LI_R2
- %1
- P1_ST_R2_R1_0
- P1_EPILOGUE
- P1_RET
+ li_r1 &src_line
+ ld_r2,r1,0
+ addi_r2,r2,1
+ st_r2,r1,0
+ li_r1 &src_col
+ li_r2 %1
+ st_r2,r1,0
+ epilogue
+ ret
## ---- skip_ws() — eat whitespace and ; line comments ----------------
:skip_ws
- P1_PROLOGUE
+ prologue
:skip_ws_loop
- P1_LI_BR
- &peek_char
- P1_CALL ## r0 = next char (or -1)
+ li_br &peek_char
+ call ## r0 = next char (or -1)
## EOF → done
- P1_LI_R1
- %0
- P1_ADDI_R1_R1_NEG1
- P1_LI_BR
- &skip_ws_done
- P1_BEQ_R0_R1
+ li_r1 %0
+ addi_r1,r1,neg1
+ li_br &skip_ws_done
+ beq_r0,r1
## ' ' (0x20)
- P1_LI_R1
- %32
- P1_LI_BR
- &skip_ws_eat
- P1_BEQ_R0_R1
+ li_r1 %32
+ li_br &skip_ws_eat
+ beq_r0,r1
## '\t' (0x09)
- P1_LI_R1
- %9
- P1_LI_BR
- &skip_ws_eat
- P1_BEQ_R0_R1
+ li_r1 %9
+ li_br &skip_ws_eat
+ beq_r0,r1
## '\n' (0x0A)
- P1_LI_R1
- %10
- P1_LI_BR
- &skip_ws_eat
- P1_BEQ_R0_R1
+ li_r1 %10
+ li_br &skip_ws_eat
+ beq_r0,r1
## '\r' (0x0D)
- P1_LI_R1
- %13
- P1_LI_BR
- &skip_ws_eat
- P1_BEQ_R0_R1
+ li_r1 %13
+ li_br &skip_ws_eat
+ beq_r0,r1
## ';' (0x3B)
- P1_LI_R1
- %59
- P1_LI_BR
- &skip_ws_comment
- P1_BEQ_R0_R1
+ li_r1 %59
+ li_br &skip_ws_comment
+ beq_r0,r1
- P1_LI_BR
- &skip_ws_done
- P1_B
+ li_br &skip_ws_done
+ b
:skip_ws_eat
- P1_LI_BR
- &advance_char
- P1_CALL
- P1_LI_BR
- &skip_ws_loop
- P1_B
+ li_br &advance_char
+ call
+ li_br &skip_ws_loop
+ b
:skip_ws_comment
- P1_LI_BR
- &advance_char
- P1_CALL ## eat ';'
+ li_br &advance_char
+ call ## eat ';'
:skip_ws_comment_loop
- P1_LI_BR
- &peek_char
- P1_CALL
+ li_br &peek_char
+ call
## EOF → outer loop (will see -1 and exit)
- P1_LI_R1
- %0
- P1_ADDI_R1_R1_NEG1
- P1_LI_BR
- &skip_ws_loop
- P1_BEQ_R0_R1
+ li_r1 %0
+ addi_r1,r1,neg1
+ li_br &skip_ws_loop
+ beq_r0,r1
## '\n' → eat and outer loop
- P1_LI_R1
- %10
- P1_LI_BR
- &skip_ws_eat
- P1_BEQ_R0_R1
+ li_r1 %10
+ li_br &skip_ws_eat
+ beq_r0,r1
## else eat and keep going
- P1_LI_BR
- &advance_char
- P1_CALL
- P1_LI_BR
- &skip_ws_comment_loop
- P1_B
+ li_br &advance_char
+ call
+ li_br &skip_ws_comment_loop
+ b
:skip_ws_done
- P1_EPILOGUE
- P1_RET
+ epilogue
+ ret
## ---- is_digit(c) -> r0 = 0 or 1 ------------------------------------
## Character already in r1.
:is_digit
- P1_LI_R2
- %48 ## '0' = 48
- P1_LI_R0
- %0 ## default: not digit
- P1_LI_BR
- &is_digit_done
- P1_BLT_R1_R2 ## c < '0' → not digit
- P1_LI_R2
- %58 ## '9' + 1 = 58 (:)
- P1_LI_BR
- &is_digit_yes
- P1_BLT_R1_R2 ## c < ':' → in range
- P1_LI_BR
- &is_digit_done
- P1_B
+ li_r2 %48 ## '0' = 48
+ li_r0 %0 ## default: not digit
+ li_br &is_digit_done
+ blt_r1,r2 ## c < '0' → not digit
+ li_r2 %58 ## '9' + 1 = 58 (:)
+ li_br &is_digit_yes
+ blt_r1,r2 ## c < ':' → in range
+ li_br &is_digit_done
+ b
:is_digit_yes
- P1_LI_R0
- %1
+ li_r0 %1
:is_digit_done
- P1_RET
+ ret
## ---- read_number() -> r0 = tagged fixnum ----------------------------
@@ -1354,318 +1093,243 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## peek_char is in [0-9]. Uses r6 = accumulator across iterations
## (saved via PROLOGUE_N1 slot 1).
:read_number
- P1_PROLOGUE
- P1_MOV_R3_SP
- P1_ST_R6_SP_8
+ prologue
+ mov_r3,sp
+ st_r6,sp,8
- P1_LI_R6
- %0 ## r6 = 0 (accumulator)
+ li_r6 %0 ## r6 = 0 (accumulator)
:read_number_loop
- P1_LI_BR
- &peek_char
- P1_CALL ## r0 = char (or -1)
+ li_br &peek_char
+ call ## r0 = char (or -1)
## If char not a digit, stop.
- P1_MOV_R1_R0
- P1_LI_BR
- &is_digit
- P1_CALL ## r0 = 0 or 1
- P1_LI_BR
- &read_number_done
- P1_BEQZ_R0
+ mov_r1,r0
+ li_br &is_digit
+ call ## r0 = 0 or 1
+ li_br &read_number_done
+ beqz_r0
## digit = peek - '0'. Re-peek (simpler than stashing).
- P1_LI_BR
- &peek_char
- P1_CALL
- P1_ADDI_R0_R0_NEG48 ## r0 = digit (0..9)
+ li_br &peek_char
+ call
+ addi_r0,r0,neg48 ## r0 = digit (0..9)
## r6 = r6 * 10 + digit. Do via (r6 << 3) + (r6 << 1).
- P1_MOV_R1_R6
- P1_SHLI_R1_R6_3 ## r1 = r6 << 3 = r6*8
- P1_MOV_R2_R6
- P1_SHLI_R2_R6_1 ## r2 = r6 << 1 = r6*2
- P1_ADD_R6_R1_R2 ## r6 = r6*10
- P1_ADD_R6_R6_R0 ## r6 = r6*10 + digit
-
- P1_LI_BR
- &advance_char
- P1_CALL
- P1_LI_BR
- &read_number_loop
- P1_B
+ mov_r1,r6
+ shli_r1,r6,3 ## r1 = r6 << 3 = r6*8
+ mov_r2,r6
+ shli_r2,r6,1 ## r2 = r6 << 1 = r6*2
+ add_r6,r1,r2 ## r6 = r6*10
+ add_r6,r6,r0 ## r6 = r6*10 + digit
+
+ li_br &advance_char
+ call
+ li_br &read_number_loop
+ b
:read_number_done
## Tag as fixnum (low 3 bits = 001 = shift-left-3 + OR 1).
- P1_SHLI_R0_R6_3
- P1_ORI_R0_R0_1
- P1_LD_R6_SP_8
- P1_EPILOGUE
- P1_RET
+ shli_r0,r6,3
+ ori_r0,r0,1
+ ld_r6,sp,8
+ epilogue
+ ret
## ---- is_delim(c) -> r0 = 0 or 1 ------------------------------------
## Returns 1 if c is a token delimiter: whitespace, '(', ')', ';', or EOF.
:is_delim
- P1_LI_R0
- %1 ## optimistic: delim
- P1_LI_R2
- %0
- P1_ADDI_R2_R2_NEG1
- P1_LI_BR
- &is_delim_done
- P1_BEQ_R1_R2 ## EOF
- P1_LI_R2
- %32
- P1_LI_BR
- &is_delim_done
- P1_BEQ_R1_R2
- P1_LI_R2
- %9
- P1_LI_BR
- &is_delim_done
- P1_BEQ_R1_R2
- P1_LI_R2
- %10
- P1_LI_BR
- &is_delim_done
- P1_BEQ_R1_R2
- P1_LI_R2
- %13
- P1_LI_BR
- &is_delim_done
- P1_BEQ_R1_R2
- P1_LI_R2
- %40 ## '('
- P1_LI_BR
- &is_delim_done
- P1_BEQ_R1_R2
- P1_LI_R2
- %41 ## ')'
- P1_LI_BR
- &is_delim_done
- P1_BEQ_R1_R2
- P1_LI_R2
- %59 ## ';'
- P1_LI_BR
- &is_delim_done
- P1_BEQ_R1_R2
- P1_LI_R0
- %0
+ li_r0 %1 ## optimistic: delim
+ li_r2 %0
+ addi_r2,r2,neg1
+ li_br &is_delim_done
+ beq_r1,r2 ## EOF
+ li_r2 %32
+ li_br &is_delim_done
+ beq_r1,r2
+ li_r2 %9
+ li_br &is_delim_done
+ beq_r1,r2
+ li_r2 %10
+ li_br &is_delim_done
+ beq_r1,r2
+ li_r2 %13
+ li_br &is_delim_done
+ beq_r1,r2
+ li_r2 %40 ## '('
+ li_br &is_delim_done
+ beq_r1,r2
+ li_r2 %41 ## ')'
+ li_br &is_delim_done
+ beq_r1,r2
+ li_r2 %59 ## ';'
+ li_br &is_delim_done
+ beq_r1,r2
+ li_r0 %0
:is_delim_done
- P1_RET
+ ret
## ---- read_symbol() -> r0 = tagged symbol --------------------------
## Reads until the next delimiter, then calls intern on the byte range.
## Uses r6 = start cursor, r7 = start pointer (both saved across loop).
:read_symbol
- P1_PROLOGUE_N2
- P1_MOV_R3_SP
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
+ prologue_n2
+ mov_r3,sp
+ st_r6,sp,8
+ st_r7,sp,16
## r7 = &src[cursor] (stored start)
- P1_LI_R1
- &src_cursor
- P1_LD_R1_R1_0
- P1_LI_R2
- &src_base
- P1_LD_R2_R2_0
- P1_ADD_R7_R1_R2 ## r7 = base + cursor
- P1_MOV_R6_R1 ## r6 = start cursor
+ li_r1 &src_cursor
+ ld_r1,r1,0
+ li_r2 &src_base
+ ld_r2,r2,0
+ add_r7,r1,r2 ## r7 = base + cursor
+ mov_r6,r1 ## r6 = start cursor
:read_symbol_loop
- P1_LI_BR
- &peek_char
- P1_CALL
- P1_MOV_R1_R0
- P1_LI_BR
- &is_delim
- P1_CALL
- P1_LI_R1
- %1
- P1_LI_BR
- &read_symbol_done
- P1_BEQ_R0_R1 ## delim → stop
-
- P1_LI_BR
- &advance_char
- P1_CALL
- P1_LI_BR
- &read_symbol_loop
- P1_B
+ li_br &peek_char
+ call
+ mov_r1,r0
+ li_br &is_delim
+ call
+ li_r1 %1
+ li_br &read_symbol_done
+ beq_r0,r1 ## delim → stop
+
+ li_br &advance_char
+ call
+ li_br &read_symbol_loop
+ b
:read_symbol_done
## Length = current cursor - r6.
- P1_LI_R1
- &src_cursor
- P1_LD_R1_R1_0
- P1_SUB_R2_R1_R6 ## r2 = cur - start = len
+ li_r1 &src_cursor
+ ld_r1,r1,0
+ sub_r2,r1,r6 ## r2 = cur - start = len
## If length 0, malformed (shouldn't happen — caller peeks before).
- P1_LI_BR
- &err_reader_bad
- P1_BEQZ_R2
+ li_br &err_reader_bad
+ beqz_r2
- P1_MOV_R1_R7 ## r1 = ptr to first byte
+ mov_r1,r7 ## r1 = ptr to first byte
## r2 = len (already set)
- P1_LI_BR
- &intern
- P1_CALL
+ li_br &intern
+ call
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N2
- P1_RET
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n2
+ ret
## ---- read_string() -> r0 = tagged string --------------------------
## Reads a double-quoted string into a scratch buffer, handling the
## four escape forms the seed needs: \n, \t, \\, and \".
:read_string
- P1_PROLOGUE_N2
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
+ prologue_n2
+ st_r6,sp,8
+ st_r7,sp,16
- P1_LI_BR
- &advance_char
- P1_CALL ## eat opening '"'
+ li_br &advance_char
+ call ## eat opening '"'
- P1_LI_R6
- &reader_string_buf
- P1_LI_R7
- %0 ## length
+ li_r6 &reader_string_buf
+ li_r7 %0 ## length
:read_string_loop
- P1_LI_BR
- &peek_char
- P1_CALL
- P1_LI_R1
- %0
- P1_ADDI_R1_R1_NEG1
- P1_LI_BR
- &err_reader_bad
- P1_BEQ_R0_R1 ## EOF in string
-
- P1_LI_R1
- %34
- P1_LI_BR
- &read_string_done
- P1_BEQ_R0_R1 ## closing '"'
-
- P1_LI_R1
- %92
- P1_LI_BR
- &read_string_escape
- P1_BEQ_R0_R1
-
- P1_LI_R1
- %512 ## READER_STRING_BUF_SIZE = 512
- P1_LI_BR
- &read_string_store
- P1_BLT_R7_R1
- P1_LI_BR
- &err_reader_bad
- P1_B
+ li_br &peek_char
+ call
+ li_r1 %0
+ addi_r1,r1,neg1
+ li_br &err_reader_bad
+ beq_r0,r1 ## EOF in string
+
+ li_r1 %34
+ li_br &read_string_done
+ beq_r0,r1 ## closing '"'
+
+ li_r1 %92
+ li_br &read_string_escape
+ beq_r0,r1
+
+ li_r1 %512 ## READER_STRING_BUF_SIZE = 512
+ li_br &read_string_store
+ blt_r7,r1
+ li_br &err_reader_bad
+ b
:read_string_store
- P1_SB_R0_R6_0
- P1_ADDI_R6_R6_1
- P1_ADDI_R7_R7_1
- P1_LI_BR
- &advance_char
- P1_CALL
- P1_LI_BR
- &read_string_loop
- P1_B
+ sb_r0,r6,0
+ addi_r6,r6,1
+ addi_r7,r7,1
+ li_br &advance_char
+ call
+ li_br &read_string_loop
+ b
:read_string_escape
- P1_LI_BR
- &advance_char
- P1_CALL ## eat '\'
- P1_LI_BR
- &peek_char
- P1_CALL
- P1_LI_R1
- %0
- P1_ADDI_R1_R1_NEG1
- P1_LI_BR
- &err_reader_bad
- P1_BEQ_R0_R1
-
- P1_LI_R1
- %110 ## 'n'
- P1_LI_BR
- &read_string_escape_nl
- P1_BEQ_R0_R1
- P1_LI_R1
- %116 ## 't'
- P1_LI_BR
- &read_string_escape_tab
- P1_BEQ_R0_R1
- P1_LI_R1
- %92 ## '\\'
- P1_LI_BR
- &read_string_store_escaped
- P1_BEQ_R0_R1
- P1_LI_R1
- %34 ## '"'
- P1_LI_BR
- &read_string_store_escaped
- P1_BEQ_R0_R1
- P1_LI_BR
- &err_reader_bad
- P1_B
+ li_br &advance_char
+ call ## eat '\'
+ li_br &peek_char
+ call
+ li_r1 %0
+ addi_r1,r1,neg1
+ li_br &err_reader_bad
+ beq_r0,r1
+
+ li_r1 %110 ## 'n'
+ li_br &read_string_escape_nl
+ beq_r0,r1
+ li_r1 %116 ## 't'
+ li_br &read_string_escape_tab
+ beq_r0,r1
+ li_r1 %92 ## '\\'
+ li_br &read_string_store_escaped
+ beq_r0,r1
+ li_r1 %34 ## '"'
+ li_br &read_string_store_escaped
+ beq_r0,r1
+ li_br &err_reader_bad
+ b
:read_string_escape_nl
- P1_LI_R0
- %10
- P1_LI_BR
- &read_string_store_escaped
- P1_B
+ li_r0 %10
+ li_br &read_string_store_escaped
+ b
:read_string_escape_tab
- P1_LI_R0
- %9
+ li_r0 %9
:read_string_store_escaped
- P1_LI_R1
- %4096
- P1_LI_BR
- &read_string_store_escaped_ok
- P1_BLT_R7_R1
- P1_LI_BR
- &err_reader_bad
- P1_B
+ li_r1 %4096
+ li_br &read_string_store_escaped_ok
+ blt_r7,r1
+ li_br &err_reader_bad
+ b
:read_string_store_escaped_ok
- P1_SB_R0_R6_0
- P1_ADDI_R6_R6_1
- P1_ADDI_R7_R7_1
- P1_LI_BR
- &advance_char
- P1_CALL ## eat escaped payload char
- P1_LI_BR
- &read_string_loop
- P1_B
+ sb_r0,r6,0
+ addi_r6,r6,1
+ addi_r7,r7,1
+ li_br &advance_char
+ call ## eat escaped payload char
+ li_br &read_string_loop
+ b
:read_string_done
- P1_LI_BR
- &advance_char
- P1_CALL ## eat closing '"'
- P1_LI_R1
- &reader_string_buf
- P1_MOV_R2_R7
- P1_LI_BR
- &make_string
- P1_CALL
-
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N2
- P1_RET
+ li_br &advance_char
+ call ## eat closing '"'
+ li_r1 &reader_string_buf
+ mov_r2,r7
+ li_br &make_string
+ call
+
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n2
+ ret
## ---- read_list() -> r0 = tagged list --------------------------------
@@ -1676,216 +1340,170 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
##
## Frame: PROLOGUE_N1 with slot 1 = saved r6 (first element tagged value).
:read_list
- P1_PROLOGUE
+ prologue
- P1_LI_BR
- &skip_ws
- P1_CALL
+ li_br &skip_ws
+ call
## If next char is ')', return nil (end of list).
- P1_LI_BR
- &peek_char
- P1_CALL
- P1_LI_R1
- %41 ## ')'
- P1_LI_BR
- &read_list_close
- P1_BEQ_R0_R1
+ li_br &peek_char
+ call
+ li_r1 %41 ## ')'
+ li_br &read_list_close
+ beq_r0,r1
## EOF mid-list → error.
- P1_LI_R1
- %0
- P1_ADDI_R1_R1_NEG1
- P1_LI_BR
- &err_reader_bad
- P1_BEQ_R0_R1
+ li_r1 %0
+ addi_r1,r1,neg1
+ li_br &err_reader_bad
+ beq_r0,r1
## Read head element, then tail, then cons them.
- P1_ST_R6_SP_8 ## save outer r6 (if any)
+ st_r6,sp,8 ## save outer r6 (if any)
- P1_LI_BR
- &read_expr
- P1_CALL ## r0 = head
+ li_br &read_expr
+ call ## r0 = head
- P1_ST_R0_SP_8 ## slot 1 = head (spill across next call)
+ st_r0,sp,8 ## slot 1 = head (spill across next call)
- P1_LI_BR
- &read_list
- P1_CALL ## r0 = tail (recursive)
+ li_br &read_list
+ call ## r0 = tail (recursive)
## cons(head, tail)
- P1_LD_R1_SP_8
- P1_MOV_R2_R0
- P1_LI_BR
- &cons
- P1_CALL
+ ld_r1,sp,8
+ mov_r2,r0
+ li_br &cons
+ call
## Restore r6 (we clobbered the slot when storing head; outer r6 is gone.
## In this test we never rely on r6 across read_list invocations, so
## leave it; slot is scratch).
- P1_EPILOGUE
- P1_RET
+ epilogue
+ ret
:read_list_close
- P1_LI_BR
- &advance_char
- P1_CALL ## eat ')'
- P1_LI_R0
- NIL ## nil = 0x07
- P1_EPILOGUE
- P1_RET
+ li_br &advance_char
+ call ## eat ')'
+ li_r0 NIL ## nil = 0x07
+ epilogue
+ ret
## ---- read_expr() -> r0 = tagged value -------------------------------
## Dispatches on the first non-whitespace char.
:read_expr
- P1_PROLOGUE
+ prologue
- P1_LI_BR
- &skip_ws
- P1_CALL
+ li_br &skip_ws
+ call
- P1_LI_BR
- &peek_char
- P1_CALL ## r0 = char
+ li_br &peek_char
+ call ## r0 = char
## EOF → error.
- P1_LI_R1
- %0
- P1_ADDI_R1_R1_NEG1
- P1_LI_BR
- &err_reader_bad
- P1_BEQ_R0_R1
+ li_r1 %0
+ addi_r1,r1,neg1
+ li_br &err_reader_bad
+ beq_r0,r1
## '(' → list.
- P1_LI_R1
- %40
- P1_LI_BR
- &read_expr_list
- P1_BEQ_R0_R1
+ li_r1 %40
+ li_br &read_expr_list
+ beq_r0,r1
## '"' → string literal.
- P1_LI_R1
- %34
- P1_LI_BR
- &read_expr_string
- P1_BEQ_R0_R1
+ li_r1 %34
+ li_br &read_expr_string
+ beq_r0,r1
## '#' → hash-prefix literal (#t, #f for now).
- P1_LI_R1
- %35
- P1_LI_BR
- &read_expr_hash
- P1_BEQ_R0_R1
+ li_r1 %35
+ li_br &read_expr_hash
+ beq_r0,r1
## digit → number.
- P1_MOV_R1_R0
- P1_LI_BR
- &is_digit
- P1_CALL
- P1_LI_R1
- %1
- P1_LI_BR
- &read_expr_number
- P1_BEQ_R0_R1
+ mov_r1,r0
+ li_br &is_digit
+ call
+ li_r1 %1
+ li_br &read_expr_number
+ beq_r0,r1
## else → symbol.
- P1_LI_BR
- &read_symbol
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ li_br &read_symbol
+ call
+ epilogue
+ ret
:read_expr_list
- P1_LI_BR
- &advance_char
- P1_CALL ## eat '('
- P1_LI_BR
- &read_list
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ li_br &advance_char
+ call ## eat '('
+ li_br &read_list
+ call
+ epilogue
+ ret
:read_expr_number
- P1_LI_BR
- &read_number
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ li_br &read_number
+ call
+ epilogue
+ ret
:read_expr_string
- P1_LI_BR
- &read_string
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ li_br &read_string
+ call
+ epilogue
+ ret
## Hash-prefix literals: `#t` → 0x0F, `#f` → 0x17. Inherits read_expr's
## PROLOGUE (no new frame). Extended syntax (#\char, #(…)) is step 11.
:read_expr_hash
- P1_LI_BR
- &advance_char
- P1_CALL ## eat '#'
- P1_LI_BR
- &peek_char
- P1_CALL ## r0 = next char
-
- P1_LI_R1
- %116 ## 't'
- P1_LI_BR
- &read_expr_hash_t
- P1_BEQ_R0_R1
- P1_LI_R1
- %102 ## 'f'
- P1_LI_BR
- &read_expr_hash_f
- P1_BEQ_R0_R1
-
- P1_LI_BR
- &err_reader_bad
- P1_B
+ li_br &advance_char
+ call ## eat '#'
+ li_br &peek_char
+ call ## r0 = next char
+
+ li_r1 %116 ## 't'
+ li_br &read_expr_hash_t
+ beq_r0,r1
+ li_r1 %102 ## 'f'
+ li_br &read_expr_hash_f
+ beq_r0,r1
+
+ li_br &err_reader_bad
+ b
:read_expr_hash_t
- P1_LI_BR
- &advance_char
- P1_CALL ## eat 't'
- P1_LI_R0
- TRUE ## #t singleton
- P1_EPILOGUE
- P1_RET
+ li_br &advance_char
+ call ## eat 't'
+ li_r0 TRUE ## #t singleton
+ epilogue
+ ret
:read_expr_hash_f
- P1_LI_BR
- &advance_char
- P1_CALL ## eat 'f'
- P1_LI_R0
- FALSE ## #f singleton
- P1_EPILOGUE
- P1_RET
+ li_br &advance_char
+ call ## eat 'f'
+ li_r0 FALSE ## #f singleton
+ epilogue
+ ret
## ---- Display --------------------------------------------------------
## ---- putc(r1=char) — write one byte to fd 1 ------------------------
-:putc_buf
-%0
-%0
+:putc_buf %0 %0
:putc
- P1_PROLOGUE
- P1_LI_R2
- &putc_buf
- P1_SB_R1_R2_0 ## *putc_buf = low byte of r1
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %1
+ prologue
+ li_r2 &putc_buf
+ sb_r1,r2,0 ## *putc_buf = low byte of r1
+ li_r0 sys_write
+ li_r1 %1
## r2 = &putc_buf already
- P1_LI_R3
- %1
- P1_SYSCALL
- P1_EPILOGUE
- P1_RET
+ li_r3 %1
+ syscall
+ epilogue
+ ret
## ---- display_uint(r1=u64, r2=fd) — decimal, no sign --------------
@@ -1894,75 +1512,63 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## fd is spilled into slot 3 because the digit loop reuses r2 as the
## divisor '10' constant — keeping fd in a reg would require saving
## another callee-saved, which costs the same.
-:digit_buf
-'000000000000000000000000000000000000000000000000'
-:digit_buf_end
-%0
+:digit_buf '000000000000000000000000000000000000000000000000'
+:digit_buf_end %0
:display_uint
- P1_PROLOGUE_N3
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
- P1_ST_R2_SP_24 ## save fd
+ prologue_n3
+ st_r6,sp,8
+ st_r7,sp,16
+ st_r2,sp,24 ## save fd
- P1_LI_R6
- &digit_buf_end ## r6 = end-of-buffer cursor (moves left)
- P1_MOV_R7_R1 ## r7 = value (mutated)
+ li_r6 &digit_buf_end ## r6 = end-of-buffer cursor (moves left)
+ mov_r7,r1 ## r7 = value (mutated)
## Special-case zero.
- P1_LI_BR
- &du_loop
- P1_BNEZ_R7 ## if value != 0, loop; else write '0'
- P1_ADDI_R6_R6_NEG1
- P1_LI_R1
- %48 ## '0'
- P1_SB_R1_R6_0
- P1_LI_BR
- &du_write
- P1_B
+ li_br &du_loop
+ bnez_r7 ## if value != 0, loop; else write '0'
+ addi_r6,r6,neg1
+ li_r1 %48 ## '0'
+ sb_r1,r6,0
+ li_br &du_write
+ b
:du_loop
- P1_LI_BR
- &du_write
- P1_BEQZ_R7 ## value == 0 → done digit gen
+ li_br &du_write
+ beqz_r7 ## value == 0 → done digit gen
## digit = value % 10.
- P1_MOV_R1_R7
- P1_LI_R2
- %10
- P1_REM_R1_R1_R2 ## r1 = value % 10
- P1_ADDI_R1_R1_48 ## r1 += '0'
- P1_ADDI_R6_R6_NEG1
- P1_SB_R1_R6_0 ## *--r6 = digit
+ mov_r1,r7
+ li_r2 %10
+ rem_r1,r1,r2 ## r1 = value % 10
+ addi_r1,r1,48 ## r1 += '0'
+ addi_r6,r6,neg1
+ sb_r1,r6,0 ## *--r6 = digit
## value = value / 10.
- P1_MOV_R1_R7
- P1_LI_R2
- %10
- P1_DIV_R1_R1_R2
- P1_MOV_R7_R1
+ mov_r1,r7
+ li_r2 %10
+ div_r1,r1,r2
+ mov_r7,r1
- P1_LI_BR
- &du_loop
- P1_B
+ li_br &du_loop
+ b
:du_write
## Stash fd into r0 first — computing len clobbers r3 (we need it
## as SP for the slot-3 load), so grab fd before that step.
- P1_LD_R0_SP_24 ## r0 = fd (temp; SYS_WRITE will overwrite r0)
- P1_LI_R1
- &digit_buf_end
- P1_SUB_R3_R1_R6 ## r3 = len = digit_buf_end - r6
- P1_MOV_R1_R0 ## r1 = fd
- P1_MOV_R2_R6 ## r2 = buf
- P1_LI_R0
- SYS_WRITE
- P1_SYSCALL
-
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N3
- P1_RET
+ ld_r0,sp,24 ## r0 = fd (temp; sys_write will overwrite r0)
+ li_r1 &digit_buf_end
+ sub_r3,r1,r6 ## r3 = len = digit_buf_end - r6
+ mov_r1,r0 ## r1 = fd
+ mov_r2,r6 ## r2 = buf
+ li_r0 sys_write
+ syscall
+
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n3
+ ret
## ---- display(r1=tagged) — dispatch on tag -------------------------
@@ -1973,225 +1579,171 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## PROLOGUE_N2 sum doesn't match display_pair's single EPILOGUE_N2, so
## recursive calls drift sp and the saved r6/r7 slots point off-frame.
:display
- P1_PROLOGUE_N2
+ prologue_n2
## nil = 0x07
- P1_LI_R2
- NIL
- P1_LI_BR
- &display_nil
- P1_BEQ_R1_R2
+ li_r2 NIL
+ li_br &display_nil
+ beq_r1,r2
## #t = 0x0F
- P1_LI_R2
- TRUE
- P1_LI_BR
- &display_true
- P1_BEQ_R1_R2
+ li_r2 TRUE
+ li_br &display_true
+ beq_r1,r2
## #f = 0x17
- P1_LI_R2
- FALSE
- P1_LI_BR
- &display_false
- P1_BEQ_R1_R2
+ li_r2 FALSE
+ li_br &display_false
+ beq_r1,r2
## Low-3-bit tag.
- P1_MOV_R2_R1
- P1_ANDI_R1_R1_7 ## r1 = tag
- P1_LI_R3
- TAG_FIXNUM
- P1_LI_BR
- &display_fixnum
- P1_BEQ_R1_R3
- P1_LI_R3
- TAG_PAIR
- P1_LI_BR
- &display_pair
- P1_BEQ_R1_R3
- P1_LI_R3
- TAG_SYMBOL
- P1_LI_BR
- &display_symbol
- P1_BEQ_R1_R3
- P1_LI_R3
- TAG_STRING
- P1_LI_BR
- &display_string
- P1_BEQ_R1_R3
+ mov_r2,r1
+ andi_r1,r1,7 ## r1 = tag
+ li_r3 TAG_FIXNUM
+ li_br &display_fixnum
+ beq_r1,r3
+ li_r3 TAG_PAIR
+ li_br &display_pair
+ beq_r1,r3
+ li_r3 TAG_SYMBOL
+ li_br &display_symbol
+ beq_r1,r3
+ li_r3 TAG_STRING
+ li_br &display_string
+ beq_r1,r3
## Unknown — treat as "?"
- P1_LI_R1
- %63 ## '?'
- P1_LI_BR
- &putc
- P1_CALL
- P1_EPILOGUE_N2
- P1_RET
+ li_r1 %63 ## '?'
+ li_br &putc
+ call
+ epilogue_n2
+ ret
:display_nil
- P1_LI_R1
- %40 ## '('
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_R1
- %41 ## ')'
- P1_LI_BR
- &putc
- P1_CALL
- P1_EPILOGUE_N2
- P1_RET
+ li_r1 %40 ## '('
+ li_br &putc
+ call
+ li_r1 %41 ## ')'
+ li_br &putc
+ call
+ epilogue_n2
+ ret
## #t and #f share display's PROLOGUE_N2 frame (reached via BEQ from
## display or write — display_fixnum/symbol pattern).
:display_true
- P1_LI_R1
- %35 ## '#'
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_R1
- %116 ## 't'
- P1_LI_BR
- &putc
- P1_CALL
- P1_EPILOGUE_N2
- P1_RET
+ li_r1 %35 ## '#'
+ li_br &putc
+ call
+ li_r1 %116 ## 't'
+ li_br &putc
+ call
+ epilogue_n2
+ ret
:display_false
- P1_LI_R1
- %35 ## '#'
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_R1
- %102 ## 'f'
- P1_LI_BR
- &putc
- P1_CALL
- P1_EPILOGUE_N2
- P1_RET
+ li_r1 %35 ## '#'
+ li_br &putc
+ call
+ li_r1 %102 ## 'f'
+ li_br &putc
+ call
+ epilogue_n2
+ ret
:display_fixnum
- P1_MOV_R1_R2
- P1_SARI_R1_R1_3 ## signed shift; value (assume non-negative here)
- P1_LI_R2
- %1 ## fd = stdout
- P1_LI_BR
- &display_uint
- P1_CALL
- P1_EPILOGUE_N2
- P1_RET
+ mov_r1,r2
+ sari_r1,r1,3 ## signed shift; value (assume non-negative here)
+ li_r2 %1 ## fd = stdout
+ li_br &display_uint
+ call
+ epilogue_n2
+ ret
:display_symbol
## r2 = tagged symbol. Strip tag, read header, then write bytes.
- P1_ADDI_R2_R2_NEG5 ## r2 = raw header ptr (tag=0b101 → -5)
- P1_LD_R3_R2_0 ## r3 = header
+ addi_r2,r2,neg5 ## r2 = raw header ptr (tag=0b101 → -5)
+ ld_r3,r2,0 ## r3 = header
## Low 48 bits = length. Mask by SHL/SHR 16.
- P1_SHLI_R3_R3_16 ## clear top 16
- P1_SHRI_R3_R3_16 ## r3 = length (0..2^48)
- P1_ADDI_R2_R2_8 ## r2 = name ptr
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %1
- P1_SYSCALL
- P1_EPILOGUE_N2
- P1_RET
+ shli_r3,r3,16 ## clear top 16
+ shri_r3,r3,16 ## r3 = length (0..2^48)
+ addi_r2,r2,8 ## r2 = name ptr
+ li_r0 sys_write
+ li_r1 %1
+ syscall
+ epilogue_n2
+ ret
:display_pair
## r2 = tagged pair. Shares display's PROLOGUE_N2 frame.
- P1_ST_R6_SP_8 ## save r6 into display's slot 1
- P1_ST_R7_SP_16 ## save r7 into display's slot 2
+ st_r6,sp,8 ## save r6 into display's slot 1
+ st_r7,sp,16 ## save r7 into display's slot 2
- P1_MOV_R6_R2 ## r6 = tagged pair (we'll walk cdr chain)
+ mov_r6,r2 ## r6 = tagged pair (we'll walk cdr chain)
- P1_LI_R1
- %40 ## '('
- P1_LI_BR
- &putc
- P1_CALL
+ li_r1 %40 ## '('
+ li_br &putc
+ call
:display_pair_loop
## car(r6)
- P1_MOV_R1_R6
- P1_LI_BR
- &car
- P1_CALL
- P1_MOV_R1_R0
- P1_LI_BR
- &display
- P1_CALL
+ mov_r1,r6
+ li_br &car
+ call
+ mov_r1,r0
+ li_br &display
+ call
## cdr(r6)
- P1_MOV_R1_R6
- P1_LI_BR
- &cdr
- P1_CALL
- P1_MOV_R6_R0
+ mov_r1,r6
+ li_br &cdr
+ call
+ mov_r6,r0
## If cdr == nil, done.
- P1_LI_R1
- NIL
- P1_LI_BR
- &display_pair_close
- P1_BEQ_R6_R1
+ li_r1 NIL
+ li_br &display_pair_close
+ beq_r6,r1
## If cdr is a pair, space + loop.
- P1_MOV_R1_R6
- P1_ANDI_R1_R1_7
- P1_LI_R2
- TAG_PAIR
- P1_LI_BR
- &display_pair_continue
- P1_BEQ_R1_R2
+ mov_r1,r6
+ andi_r1,r1,7
+ li_r2 TAG_PAIR
+ li_br &display_pair_continue
+ beq_r1,r2
## Otherwise, improper: " . x)".
- P1_LI_R1
- %32 ## ' '
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_R1
- %46 ## '.'
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_R1
- %32
- P1_LI_BR
- &putc
- P1_CALL
- P1_MOV_R1_R6
- P1_LI_BR
- &display
- P1_CALL
- P1_LI_BR
- &display_pair_close
- P1_B
+ li_r1 %32 ## ' '
+ li_br &putc
+ call
+ li_r1 %46 ## '.'
+ li_br &putc
+ call
+ li_r1 %32
+ li_br &putc
+ call
+ mov_r1,r6
+ li_br &display
+ call
+ li_br &display_pair_close
+ b
:display_pair_continue
- P1_LI_R1
- %32 ## ' '
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_BR
- &display_pair_loop
- P1_B
+ li_r1 %32 ## ' '
+ li_br &putc
+ call
+ li_br &display_pair_loop
+ b
:display_pair_close
- P1_LI_R1
- %41 ## ')'
- P1_LI_BR
- &putc
- P1_CALL
+ li_r1 %41 ## ')'
+ li_br &putc
+ call
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N2
- P1_RET
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n2
+ ret
## ---- display_string(r2=tagged_string) ------------------------------
@@ -2201,18 +1753,16 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## stdout. Shares display's PROLOGUE_N2 frame, so EPILOGUE_N2 + RET
## unwinds back to display's caller.
:display_string
- P1_ADDI_R2_R2_NEG4 ## r2 = raw header ptr
- P1_LD_R3_R2_0 ## r3 = header word
- P1_SHLI_R3_R3_16
- P1_SHRI_R3_R3_16 ## r3 = length (low 48 bits)
- P1_ADDI_R2_R2_8 ## r2 = payload ptr
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- %1
- P1_SYSCALL
- P1_EPILOGUE_N2
- P1_RET
+ addi_r2,r2,neg4 ## r2 = raw header ptr
+ ld_r3,r2,0 ## r3 = header word
+ shli_r3,r3,16
+ shri_r3,r3,16 ## r3 = length (low 48 bits)
+ addi_r2,r2,8 ## r2 = payload ptr
+ li_r0 sys_write
+ li_r1 %1
+ syscall
+ epilogue_n2
+ ret
## ---- write(r1=val) -------------------------------------------------
@@ -2221,57 +1771,41 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## symbol works because write's PROLOGUE_N2 frame matches display's —
## those handlers unwind the right amount on their own EPILOGUE_N2.
:write
- P1_PROLOGUE_N2
-
- P1_LI_R2
- NIL
- P1_LI_BR
- &display_nil
- P1_BEQ_R1_R2 ## nil
-
- P1_LI_R2
- TRUE
- P1_LI_BR
- &display_true
- P1_BEQ_R1_R2 ## #t
-
- P1_LI_R2
- FALSE
- P1_LI_BR
- &display_false
- P1_BEQ_R1_R2 ## #f
-
- P1_MOV_R2_R1
- P1_ANDI_R1_R1_7 ## r1 = tag
- P1_LI_R3
- TAG_FIXNUM
- P1_LI_BR
- &display_fixnum
- P1_BEQ_R1_R3
- P1_LI_R3
- TAG_PAIR
- P1_LI_BR
- &write_pair
- P1_BEQ_R1_R3
- P1_LI_R3
- TAG_SYMBOL
- P1_LI_BR
- &display_symbol
- P1_BEQ_R1_R3
- P1_LI_R3
- TAG_STRING
- P1_LI_BR
- &write_string
- P1_BEQ_R1_R3
+ prologue_n2
+
+ li_r2 NIL
+ li_br &display_nil
+ beq_r1,r2 ## nil
+
+ li_r2 TRUE
+ li_br &display_true
+ beq_r1,r2 ## #t
+
+ li_r2 FALSE
+ li_br &display_false
+ beq_r1,r2 ## #f
+
+ mov_r2,r1
+ andi_r1,r1,7 ## r1 = tag
+ li_r3 TAG_FIXNUM
+ li_br &display_fixnum
+ beq_r1,r3
+ li_r3 TAG_PAIR
+ li_br &write_pair
+ beq_r1,r3
+ li_r3 TAG_SYMBOL
+ li_br &display_symbol
+ beq_r1,r3
+ li_r3 TAG_STRING
+ li_br &write_string
+ beq_r1,r3
## Unknown (closure/prim, etc.) — emit '?' placeholder.
- P1_LI_R1
- %63
- P1_LI_BR
- &putc
- P1_CALL
- P1_EPILOGUE_N2
- P1_RET
+ li_r1 %63
+ li_br &putc
+ call
+ epilogue_n2
+ ret
## ---- write_string(r2=tagged_string) --------------------------------
@@ -2279,170 +1813,133 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## write's PROLOGUE_N2 frame; r6=cursor, r7=remaining-bytes saved in
## the two slots across putc calls.
:write_string
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
-
- P1_ADDI_R2_R2_NEG4
- P1_LD_R3_R2_0
- P1_SHLI_R3_R3_16
- P1_SHRI_R3_R3_16 ## r3 = length
- P1_ADDI_R2_R2_8 ## r2 = payload ptr
- P1_MOV_R6_R2 ## r6 = cursor
- P1_MOV_R7_R3 ## r7 = length
-
- P1_LI_R1
- %34 ## '"'
- P1_LI_BR
- &putc
- P1_CALL
+ st_r6,sp,8
+ st_r7,sp,16
+
+ addi_r2,r2,neg4
+ ld_r3,r2,0
+ shli_r3,r3,16
+ shri_r3,r3,16 ## r3 = length
+ addi_r2,r2,8 ## r2 = payload ptr
+ mov_r6,r2 ## r6 = cursor
+ mov_r7,r3 ## r7 = length
+
+ li_r1 %34 ## '"'
+ li_br &putc
+ call
:write_string_loop
- P1_LI_BR
- &write_string_done
- P1_BEQZ_R7 ## length == 0 → done
+ li_br &write_string_done
+ beqz_r7 ## length == 0 → done
- P1_LB_R1_R6_0 ## r1 = *cursor
+ lb_r1,r6,0 ## r1 = *cursor
- P1_LI_R2
- %34 ## '"'
- P1_LI_BR
- &write_string_escape
- P1_BEQ_R1_R2
+ li_r2 %34 ## '"'
+ li_br &write_string_escape
+ beq_r1,r2
- P1_LI_R2
- %92 ## '\\'
- P1_LI_BR
- &write_string_escape
- P1_BEQ_R1_R2
+ li_r2 %92 ## '\\'
+ li_br &write_string_escape
+ beq_r1,r2
- P1_LI_BR
- &putc
- P1_CALL
+ li_br &putc
+ call
:write_string_next
- P1_ADDI_R6_R6_1
- P1_ADDI_R7_R7_NEG1
- P1_LI_BR
- &write_string_loop
- P1_B
+ addi_r6,r6,1
+ addi_r7,r7,neg1
+ li_br &write_string_loop
+ b
:write_string_escape
## Emit '\\' then re-emit the char (cursor still points to it).
- P1_LI_R1
- %92
- P1_LI_BR
- &putc
- P1_CALL
- P1_LB_R1_R6_0
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_BR
- &write_string_next
- P1_B
+ li_r1 %92
+ li_br &putc
+ call
+ lb_r1,r6,0
+ li_br &putc
+ call
+ li_br &write_string_next
+ b
:write_string_done
- P1_LI_R1
- %34 ## '"'
- P1_LI_BR
- &putc
- P1_CALL
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N2
- P1_RET
+ li_r1 %34 ## '"'
+ li_br &putc
+ call
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n2
+ ret
## ---- write_pair(r2=tagged_pair) ------------------------------------
## Mirror of display_pair but recurses through write (strings quoted).
## Shares write's PROLOGUE_N2 frame.
:write_pair
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
+ st_r6,sp,8
+ st_r7,sp,16
- P1_MOV_R6_R2 ## r6 = tagged pair cursor
+ mov_r6,r2 ## r6 = tagged pair cursor
- P1_LI_R1
- %40 ## '('
- P1_LI_BR
- &putc
- P1_CALL
+ li_r1 %40 ## '('
+ li_br &putc
+ call
:write_pair_loop
- P1_MOV_R1_R6
- P1_LI_BR
- &car
- P1_CALL
- P1_MOV_R1_R0
- P1_LI_BR
- &write
- P1_CALL
-
- P1_MOV_R1_R6
- P1_LI_BR
- &cdr
- P1_CALL
- P1_MOV_R6_R0
-
- P1_LI_R1
- NIL
- P1_LI_BR
- &write_pair_close
- P1_BEQ_R6_R1
-
- P1_MOV_R1_R6
- P1_ANDI_R1_R1_7
- P1_LI_R2
- TAG_PAIR
- P1_LI_BR
- &write_pair_continue
- P1_BEQ_R1_R2
+ mov_r1,r6
+ li_br &car
+ call
+ mov_r1,r0
+ li_br &write
+ call
+
+ mov_r1,r6
+ li_br &cdr
+ call
+ mov_r6,r0
+
+ li_r1 NIL
+ li_br &write_pair_close
+ beq_r6,r1
+
+ mov_r1,r6
+ andi_r1,r1,7
+ li_r2 TAG_PAIR
+ li_br &write_pair_continue
+ beq_r1,r2
## improper tail: " . x)"
- P1_LI_R1
- %32
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_R1
- %46
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_R1
- %32
- P1_LI_BR
- &putc
- P1_CALL
- P1_MOV_R1_R6
- P1_LI_BR
- &write
- P1_CALL
- P1_LI_BR
- &write_pair_close
- P1_B
+ li_r1 %32
+ li_br &putc
+ call
+ li_r1 %46
+ li_br &putc
+ call
+ li_r1 %32
+ li_br &putc
+ call
+ mov_r1,r6
+ li_br &write
+ call
+ li_br &write_pair_close
+ b
:write_pair_continue
- P1_LI_R1
- %32
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_BR
- &write_pair_loop
- P1_B
+ li_r1 %32
+ li_br &putc
+ call
+ li_br &write_pair_loop
+ b
:write_pair_close
- P1_LI_R1
- %41 ## ')'
- P1_LI_BR
- &putc
- P1_CALL
+ li_r1 %41 ## ')'
+ li_br &putc
+ call
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N2
- P1_RET
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n2
+ ret
## ================ Step 6: Eval =======================================
@@ -2457,132 +1954,111 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## Prepends (sym . val) to the global alist. Last-write-wins semantics
## fall out naturally because lookup_alist returns the leftmost match.
:gset
- P1_PROLOGUE_N2
- P1_ST_R1_SP_8 ## save sym
- P1_ST_R2_SP_16 ## save val
+ prologue_n2
+ st_r1,sp,8 ## save sym
+ st_r2,sp,16 ## save val
- P1_LI_BR
- &cons
- P1_CALL ## r0 = (sym . val)
+ li_br &cons
+ call ## r0 = (sym . val)
- P1_MOV_R1_R0
- P1_LI_R2
- &global_env_cell
- P1_LD_R2_R2_0 ## r2 = old global alist
- P1_LI_BR
- &cons
- P1_CALL ## r0 = new alist
+ mov_r1,r0
+ li_r2 &global_env_cell
+ ld_r2,r2,0 ## r2 = old global alist
+ li_br &cons
+ call ## r0 = new alist
- P1_LI_R2
- &global_env_cell
- P1_ST_R0_R2_0
- P1_EPILOGUE_N2
- P1_RET
+ li_r2 &global_env_cell
+ st_r0,r2,0
+ epilogue_n2
+ ret
## ---- lookup_alist(r1=sym, r2=env) -> r0 = pair or nil ---------------
## Walks alist env returning the (sym . val) cons cell that matches, or
## nil on miss. Caller distinguishes via tag/nil check.
:lookup_alist
- P1_PROLOGUE_N3
- P1_MOV_R3_SP
- P1_ST_R1_SP_8 ## slot 1 = sym
- P1_ST_R2_SP_16 ## slot 2 = cursor
+ prologue_n3
+ mov_r3,sp
+ st_r1,sp,8 ## slot 1 = sym
+ st_r2,sp,16 ## slot 2 = cursor
:lookup_alist_loop
- P1_MOV_R3_SP
- P1_LD_R2_SP_16
- P1_LI_R1
- %7
- P1_LI_BR
- &lookup_alist_miss
- P1_BEQ_R2_R1 ## cursor == nil → miss
+ mov_r3,sp
+ ld_r2,sp,16
+ li_r1 %7
+ li_br &lookup_alist_miss
+ beq_r2,r1 ## cursor == nil → miss
## pair = car(cursor)
- P1_MOV_R1_R2
- P1_LI_BR
- &car
- P1_CALL ## r0 = (k . v)
+ mov_r1,r2
+ li_br &car
+ call ## r0 = (k . v)
- P1_ST_R0_SP_24 ## slot 3 = pair
+ st_r0,sp,24 ## slot 3 = pair
- P1_MOV_R1_R0
- P1_LI_BR
- &car
- P1_CALL ## r0 = key
+ mov_r1,r0
+ li_br &car
+ call ## r0 = key
- P1_MOV_R3_SP
- P1_LD_R1_SP_8
- P1_LI_BR
- &lookup_alist_hit
- P1_BEQ_R0_R1
+ mov_r3,sp
+ ld_r1,sp,8
+ li_br &lookup_alist_hit
+ beq_r0,r1
## advance cursor := cdr(cursor)
- P1_LD_R1_SP_16
- P1_LI_BR
- &cdr
- P1_CALL
- P1_ST_R0_SP_16
- P1_LI_BR
- &lookup_alist_loop
- P1_B
+ ld_r1,sp,16
+ li_br &cdr
+ call
+ st_r0,sp,16
+ li_br &lookup_alist_loop
+ b
:lookup_alist_hit
- P1_LD_R0_SP_24
- P1_EPILOGUE_N3
- P1_RET
+ ld_r0,sp,24
+ epilogue_n3
+ ret
:lookup_alist_miss
- P1_LI_R0
- %7
- P1_EPILOGUE_N3
- P1_RET
+ li_r0 %7
+ epilogue_n3
+ ret
## ---- lookup(r1=sym, r2=env) -> r0 = value --------------------------
## Local first, global second. Errors out via &err_unbound on miss.
:lookup
- P1_PROLOGUE_N2
- P1_ST_R1_SP_8 ## save sym for possible global retry
-
- P1_LI_BR
- &lookup_alist
- P1_CALL ## r0 = local pair or nil
-
- P1_LI_R1
- %7
- P1_LI_BR
- &lookup_global
- P1_BEQ_R0_R1
-
- P1_MOV_R1_R0
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = value
- P1_EPILOGUE_N2
- P1_RET
+ prologue_n2
+ st_r1,sp,8 ## save sym for possible global retry
+
+ li_br &lookup_alist
+ call ## r0 = local pair or nil
+
+ li_r1 %7
+ li_br &lookup_global
+ beq_r0,r1
+
+ mov_r1,r0
+ li_br &cdr
+ call ## r0 = value
+ epilogue_n2
+ ret
:lookup_global
- P1_LD_R1_SP_8
- P1_LI_R2
- &global_env_cell
- P1_LD_R2_R2_0
- P1_LI_BR
- &lookup_alist
- P1_CALL
-
- P1_LI_R1
- %7
- P1_LI_BR
- &err_unbound
- P1_BEQ_R0_R1
-
- P1_MOV_R1_R0
- P1_LI_BR
- &cdr
- P1_CALL
- P1_EPILOGUE_N2
- P1_RET
+ ld_r1,sp,8
+ li_r2 &global_env_cell
+ ld_r2,r2,0
+ li_br &lookup_alist
+ call
+
+ li_r1 %7
+ li_br &err_unbound
+ beq_r0,r1
+
+ mov_r1,r0
+ li_br &cdr
+ call
+ epilogue_n2
+ ret
## ---- env_extend(r1=names, r2=vals, r3=env) -> r0 = new env ---------
@@ -2591,80 +2067,69 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## vals, env-acc, name-temp) and cons clobbers r0-r3 so name has to
## live somewhere stable across the val-car call.
:env_extend
- P1_PROLOGUE_N4
- P1_MOV_R0_R3 ## save env before clobbering r3
- P1_MOV_R3_SP
- P1_ST_R1_SP_8 ## slot 1 = names
- P1_ST_R2_SP_16 ## slot 2 = vals
- P1_ST_R0_SP_24 ## slot 3 = env accumulator
+ prologue_n4
+ mov_r0,r3 ## save env before clobbering r3
+ mov_r3,sp
+ st_r1,sp,8 ## slot 1 = names
+ st_r2,sp,16 ## slot 2 = vals
+ st_r0,sp,24 ## slot 3 = env accumulator
:env_extend_loop
- P1_MOV_R3_SP
- P1_LD_R1_SP_8
- P1_LI_R2
- %7
- P1_LI_BR
- &env_extend_done
- P1_BEQ_R1_R2 ## names == nil → done
-
- P1_LD_R1_SP_16
- P1_LI_R2
- %7
- P1_LI_BR
- &err_arity
- P1_BEQ_R1_R2 ## vals == nil → arity error
+ mov_r3,sp
+ ld_r1,sp,8
+ li_r2 %7
+ li_br &env_extend_done
+ beq_r1,r2 ## names == nil → done
+
+ ld_r1,sp,16
+ li_r2 %7
+ li_br &err_arity
+ beq_r1,r2 ## vals == nil → arity error
## name = car(names)
- P1_LD_R1_SP_8
- P1_LI_BR
- &car
- P1_CALL ## r0 = name
- P1_ST_R0_SP_32 ## slot 4 = name
+ ld_r1,sp,8
+ li_br &car
+ call ## r0 = name
+ st_r0,sp,32 ## slot 4 = name
## val = car(vals)
- P1_LD_R1_SP_16
- P1_LI_BR
- &car
- P1_CALL ## r0 = val
+ ld_r1,sp,16
+ li_br &car
+ call ## r0 = val
## pair = cons(name, val)
- P1_MOV_R2_R0
- P1_LD_R1_SP_32
- P1_LI_BR
- &cons
- P1_CALL ## r0 = (name . val)
+ mov_r2,r0
+ ld_r1,sp,32
+ li_br &cons
+ call ## r0 = (name . val)
## env := cons(pair, env)
- P1_MOV_R1_R0
- P1_LD_R2_SP_24
- P1_LI_BR
- &cons
- P1_CALL ## r0 = new env
+ mov_r1,r0
+ ld_r2,sp,24
+ li_br &cons
+ call ## r0 = new env
- P1_ST_R0_SP_24
+ st_r0,sp,24
## names := cdr(names)
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL
- P1_ST_R0_SP_8
+ ld_r1,sp,8
+ li_br &cdr
+ call
+ st_r0,sp,8
## vals := cdr(vals)
- P1_LD_R1_SP_16
- P1_LI_BR
- &cdr
- P1_CALL
- P1_ST_R0_SP_16
+ ld_r1,sp,16
+ li_br &cdr
+ call
+ st_r0,sp,16
- P1_LI_BR
- &env_extend_loop
- P1_B
+ li_br &env_extend_loop
+ b
:env_extend_done
- P1_LD_R0_SP_24
- P1_EPILOGUE_N4
- P1_RET
+ ld_r0,sp,24
+ epilogue_n4
+ ret
## ---- make_closure(r1=params, r2=body, r3=env) -> r0 = tagged -------
@@ -2673,34 +2138,31 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## heap lets us skip writing the header's low 7 bytes and only stamp
## byte 7 with the type code.
:make_closure
- P1_PROLOGUE_N3
- P1_MOV_R0_R3 ## save env
- P1_ST_R1_SP_8 ## slot 1 = params
- P1_ST_R2_SP_16 ## slot 2 = body
- P1_ST_R0_SP_24 ## slot 3 = env
+ prologue_n3
+ mov_r0,r3 ## save env
+ st_r1,sp,8 ## slot 1 = params
+ st_r2,sp,16 ## slot 2 = body
+ st_r0,sp,24 ## slot 3 = env
- P1_LI_R1
- %32 ## 32 bytes
- P1_LI_BR
- &alloc
- P1_CALL ## r0 = raw ptr
+ li_r1 %32 ## 32 bytes
+ li_br &alloc
+ call ## r0 = raw ptr
- P1_LI_R1
- %4
- P1_SB_R1_R0_7 ## type = 4 (closure)
+ li_r1 %4
+ sb_r1,r0,7 ## type = 4 (closure)
- P1_LD_R1_SP_8
- P1_ST_R1_R0_8
- P1_LD_R1_SP_16
- P1_ST_R1_R0_16
- P1_LD_R1_SP_24
- P1_ST_R1_R0_24
+ ld_r1,sp,8
+ st_r1,r0,8
+ ld_r1,sp,16
+ st_r1,r0,16
+ ld_r1,sp,24
+ st_r1,r0,24
- P1_ORI_R0_R0_4
- P1_ORI_R0_R0_2 ## tag = 0b110 = 6
+ ori_r0,r0,4
+ ori_r0,r0,2 ## tag = 0b110 = 6
- P1_EPILOGUE_N3
- P1_RET
+ epilogue_n3
+ ret
## ---- make_primitive(r1=code_id, r2=arity, r3=type) -> r0 = tagged --
@@ -2709,80 +2171,70 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## closures so apply's tag check still works; the type byte forks
## there. Arity is ignored for variadic (type 6) — callers pass 0.
:make_primitive
- P1_PROLOGUE_N3
- P1_MOV_R0_R3 ## save type → r0 (frees r3)
- P1_ST_R1_SP_8 ## slot 1 = code_id
- P1_ST_R2_SP_16 ## slot 2 = arity
- P1_ST_R0_SP_24 ## slot 3 = type
+ prologue_n3
+ mov_r0,r3 ## save type → r0 (frees r3)
+ st_r1,sp,8 ## slot 1 = code_id
+ st_r2,sp,16 ## slot 2 = arity
+ st_r0,sp,24 ## slot 3 = type
- P1_LI_R1
- %16 ## 16 bytes
- P1_LI_BR
- &alloc
- P1_CALL ## r0 = raw ptr
+ li_r1 %16 ## 16 bytes
+ li_br &alloc
+ call ## r0 = raw ptr
- P1_LD_R1_SP_24
- P1_SB_R1_R0_7 ## byte 7 = type
- P1_LD_R1_SP_16
- P1_SB_R1_R0_0 ## byte 0 = arity
- P1_LD_R1_SP_8
- P1_ST_R1_R0_8 ## +8 = code id
+ ld_r1,sp,24
+ sb_r1,r0,7 ## byte 7 = type
+ ld_r1,sp,16
+ sb_r1,r0,0 ## byte 0 = arity
+ ld_r1,sp,8
+ st_r1,r0,8 ## +8 = code id
- P1_ORI_R0_R0_4
- P1_ORI_R0_R0_2 ## tag = 0b110 = 6
+ ori_r0,r0,4
+ ori_r0,r0,2 ## tag = 0b110 = 6
- P1_EPILOGUE_N3
- P1_RET
+ epilogue_n3
+ ret
## ---- eval_args(r1=args, r2=env) -> r0 = evaluated args list --------
## Recursive map: eval each, cons the results left-to-right.
:eval_args
- P1_PROLOGUE_N3
- P1_MOV_R3_SP
- P1_ST_R1_SP_8 ## slot 1 = args cursor
- P1_ST_R2_SP_16 ## slot 2 = env
+ prologue_n3
+ mov_r3,sp
+ st_r1,sp,8 ## slot 1 = args cursor
+ st_r2,sp,16 ## slot 2 = env
- P1_LI_R2
- %7
- P1_LI_BR
- &eval_args_done
- P1_BEQ_R1_R2
+ li_r2 %7
+ li_br &eval_args_done
+ beq_r1,r2
## head = eval(car(args), env)
- P1_LI_BR
- &car
- P1_CALL
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval
- P1_CALL ## r0 = head value
+ li_br &car
+ call
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval
+ call ## r0 = head value
- P1_ST_R0_SP_24
+ st_r0,sp,24
## tail = eval_args(cdr(args), env)
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval_args
- P1_CALL ## r0 = tail
-
- P1_MOV_R2_R0
- P1_LD_R1_SP_24
- P1_LI_BR
- &cons ## tail: cons is last work in this frame
- P1_TAIL_N3
+ ld_r1,sp,8
+ li_br &cdr
+ call
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval_args
+ call ## r0 = tail
+
+ mov_r2,r0
+ ld_r1,sp,24
+ li_br &cons ## tail: cons is last work in this frame
+ tail_n3
:eval_args_done
- P1_LI_R0
- %7
- P1_EPILOGUE_N3
- P1_RET
+ li_r0 %7
+ epilogue_n3
+ ret
## ---- apply(r1=callee, r2=args) -> r0 = result ----------------------
@@ -2792,56 +2244,48 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## body, closure-env (prim paths repurpose slots 3/4 for code_id /
## expected_arity).
:apply
- P1_PROLOGUE_N4
- P1_MOV_R3_SP
- P1_ST_R1_SP_8 ## slot 1 = callee (tagged)
- P1_ST_R2_SP_16 ## slot 2 = args
-
- P1_ANDI_R1_R1_7
- P1_LI_R0
- TAG_PROC
- P1_LI_BR
- &err_not_callable
- P1_BNE_R1_R0
-
- P1_MOV_R3_SP
- P1_LD_R1_SP_8
- P1_ADDI_R1_R1_NEG6 ## r1 = raw ptr
+ prologue_n4
+ mov_r3,sp
+ st_r1,sp,8 ## slot 1 = callee (tagged)
+ st_r2,sp,16 ## slot 2 = args
+
+ andi_r1,r1,7
+ li_r0 TAG_PROC
+ li_br &err_not_callable
+ bne_r1,r0
+
+ mov_r3,sp
+ ld_r1,sp,8
+ addi_r1,r1,neg6 ## r1 = raw ptr
## Fork on header type byte.
- P1_LB_R0_R1_7 ## r0 = type
- P1_LI_R2
- TYPE_PRIM_FIXED
- P1_LI_BR
- &apply_prim_fixed
- P1_BEQ_R0_R2
- P1_LI_R2
- TYPE_PRIM_VARIADIC
- P1_LI_BR
- &apply_prim_variadic
- P1_BEQ_R0_R2
+ lb_r0,r1,7 ## r0 = type
+ li_r2 TYPE_PRIM_FIXED
+ li_br &apply_prim_fixed
+ beq_r0,r2
+ li_r2 TYPE_PRIM_VARIADIC
+ li_br &apply_prim_variadic
+ beq_r0,r2
## Fall through: type == 4 (closure).
- P1_LD_R0_R1_8 ## params
- P1_ST_R0_SP_8 ## slot 1 = params (overwrite)
- P1_LD_R0_R1_16 ## body
- P1_ST_R0_SP_24 ## slot 3 = body
- P1_LD_R0_R1_24 ## closure env
- P1_ST_R0_SP_32 ## slot 4 = closure env
+ ld_r0,r1,8 ## params
+ st_r0,sp,8 ## slot 1 = params (overwrite)
+ ld_r0,r1,16 ## body
+ st_r0,sp,24 ## slot 3 = body
+ ld_r0,r1,24 ## closure env
+ st_r0,sp,32 ## slot 4 = closure env
## env_extend(params, args, closure_env)
- P1_LD_R1_SP_8
- P1_LD_R2_SP_16
- P1_LD_R3_SP_32
- P1_LI_BR
- &env_extend
- P1_CALL ## r0 = new env
+ ld_r1,sp,8
+ ld_r2,sp,16
+ ld_r3,sp,32
+ li_br &env_extend
+ call ## r0 = new env
- P1_MOV_R2_R0
- P1_LD_R1_SP_24 ## r1 = body
- P1_LI_BR
- &eval
- P1_TAIL_N4 ## Scheme tail call: closure body
+ mov_r2,r0
+ ld_r1,sp,24 ## r1 = body
+ li_br &eval
+ tail_n4 ## Scheme tail call: closure body
## ---- apply_prim_fixed (r1 = raw prim ptr, inside apply's frame) ----
@@ -2851,87 +2295,74 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## apply's caller since EPILOGUE_N4 already restored lr.
:apply_prim_fixed
## r3 is still sp from the MOV above; slot 3/4 are free.
- P1_LB_R0_R1_0 ## r0 = expected arity
- P1_ST_R0_R3_32 ## slot 4 = expected arity
- P1_LD_R0_R1_8 ## r0 = code id
- P1_ST_R0_R3_24 ## slot 3 = code id
-
- P1_LD_R1_R3_16 ## r1 = args
- P1_LI_BR
- &marshal_argv
- P1_CALL ## r0 = argc, r2 = &prim_argv
-
- P1_MOV_R3_SP
- P1_LD_R1_SP_32
- P1_LI_BR
- &err_arity
- P1_BNE_R0_R1
-
- P1_MOV_R1_R0
- P1_LD_R3_SP_24 ## r3 = code id
- P1_EPILOGUE_N4
- P1_LI_BR
- &prim_dispatch
- P1_B
+ lb_r0,r1,0 ## r0 = expected arity
+ st_r0,r3,32 ## slot 4 = expected arity
+ ld_r0,r1,8 ## r0 = code id
+ st_r0,r3,24 ## slot 3 = code id
+
+ ld_r1,r3,16 ## r1 = args
+ li_br &marshal_argv
+ call ## r0 = argc, r2 = &prim_argv
+
+ mov_r3,sp
+ ld_r1,sp,32
+ li_br &err_arity
+ bne_r0,r1
+
+ mov_r1,r0
+ ld_r3,sp,24 ## r3 = code id
+ epilogue_n4
+ li_br &prim_dispatch
+ b
## ---- apply_prim_variadic (r1 = raw prim ptr) ----------------------
:apply_prim_variadic
- P1_LD_R0_R1_8 ## r0 = code id
- P1_ST_R0_R3_24 ## slot 3 = code id
+ ld_r0,r1,8 ## r0 = code id
+ st_r0,r3,24 ## slot 3 = code id
- P1_LD_R1_R3_16 ## r1 = args
- P1_LI_BR
- &marshal_argv
- P1_CALL ## r0 = argc, r2 = &prim_argv
+ ld_r1,r3,16 ## r1 = args
+ li_br &marshal_argv
+ call ## r0 = argc, r2 = &prim_argv
- P1_MOV_R1_R0
- P1_LD_R3_SP_24 ## r3 = code id
- P1_EPILOGUE_N4
- P1_LI_BR
- &prim_dispatch
- P1_B
+ mov_r1,r0
+ ld_r3,sp,24 ## r3 = code id
+ epilogue_n4
+ li_br &prim_dispatch
+ b
## ---- marshal_argv(r1 = args list) -> r0 = argc, r2 = &prim_argv ---
## Walks the tagged-pair list, storing each car into prim_argv[i*8].
## Overflow beyond PRIM_ARGV_SLOTS is an error (err_too_many_args).
:marshal_argv
- P1_PROLOGUE
- P1_LI_R2
- &prim_argv ## r2 = cursor
- P1_LI_R3
- %0 ## r3 = count
+ prologue
+ li_r2 &prim_argv ## r2 = cursor
+ li_r3 %0 ## r3 = count
:marshal_argv_loop
- P1_LI_R0
- %7
- P1_LI_BR
- &marshal_argv_done
- P1_BEQ_R1_R0 ## list == nil → done
-
- P1_LI_R0
- %32 ## PRIM_ARGV_SLOTS = 32
- P1_LI_BR
- &err_too_many_args
- P1_BEQ_R3_R0
-
- P1_ADDI_R0_R1_NEG2 ## r0 = raw pair ptr
- P1_LD_R1_R0_0 ## r1 = car (we'll load cdr next)
- P1_ST_R1_R2_0 ## *cursor = car
- P1_LD_R1_R0_8 ## r1 = cdr → next list
- P1_ADDI_R2_R2_8 ## cursor += 8
- P1_ADDI_R3_R3_1 ## count++
- P1_LI_BR
- &marshal_argv_loop
- P1_B
+ li_r0 %7
+ li_br &marshal_argv_done
+ beq_r1,r0 ## list == nil → done
+
+ li_r0 %32 ## PRIM_ARGV_SLOTS = 32
+ li_br &err_too_many_args
+ beq_r3,r0
+
+ addi_r0,r1,neg2 ## r0 = raw pair ptr
+ ld_r1,r0,0 ## r1 = car (we'll load cdr next)
+ st_r1,r2,0 ## *cursor = car
+ ld_r1,r0,8 ## r1 = cdr → next list
+ addi_r2,r2,8 ## cursor += 8
+ addi_r3,r3,1 ## count++
+ li_br &marshal_argv_loop
+ b
:marshal_argv_done
- P1_MOV_R0_R3 ## r0 = count
- P1_LI_R2
- &prim_argv ## r2 = buffer base
- P1_EPILOGUE
- P1_RET
+ mov_r0,r3 ## r0 = count
+ li_r2 &prim_argv ## r2 = buffer base
+ epilogue
+ ret
## ---- prim_dispatch(r1=argc, r2=argv, r3=code_id) -------------------
@@ -2940,308 +2371,188 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## already set up, and RET returns to apply's caller (since apply
## already ran EPILOGUE_N4 before branching here).
:prim_dispatch
- P1_LI_BR
- &prim_add
- P1_BEQZ_R3
- P1_LI_R0
- %1
- P1_LI_BR
- &prim_sub
- P1_BEQ_R3_R0
- P1_LI_R0
- %2
- P1_LI_BR
- &prim_mul
- P1_BEQ_R3_R0
- P1_LI_R0
- %3
- P1_LI_BR
- &prim_div
- P1_BEQ_R3_R0
- P1_LI_R0
- %4
- P1_LI_BR
- &prim_mod
- P1_BEQ_R3_R0
- P1_LI_R0
- %5
- P1_LI_BR
- &prim_numeq
- P1_BEQ_R3_R0
- P1_LI_R0
- %6
- P1_LI_BR
- &prim_lt
- P1_BEQ_R3_R0
- P1_LI_R0
- %7
- P1_LI_BR
- &prim_gt
- P1_BEQ_R3_R0
- P1_LI_R0
- %8
- P1_LI_BR
- &prim_le
- P1_BEQ_R3_R0
- P1_LI_R0
- %9
- P1_LI_BR
- &prim_ge
- P1_BEQ_R3_R0
- P1_LI_R0
- %10
- P1_LI_BR
- &prim_zerop
- P1_BEQ_R3_R0
- P1_LI_R0
- %11
- P1_LI_BR
- &prim_negativep
- P1_BEQ_R3_R0
- P1_LI_R0
- %12
- P1_LI_BR
- &prim_positivep
- P1_BEQ_R3_R0
- P1_LI_R0
- %13
- P1_LI_BR
- &prim_abs
- P1_BEQ_R3_R0
- P1_LI_R0
- %14
- P1_LI_BR
- &prim_min
- P1_BEQ_R3_R0
- P1_LI_R0
- %15
- P1_LI_BR
- &prim_max
- P1_BEQ_R3_R0
- P1_LI_R0
- %16
- P1_LI_BR
- &prim_bitand
- P1_BEQ_R3_R0
- P1_LI_R0
- %17
- P1_LI_BR
- &prim_bitor
- P1_BEQ_R3_R0
- P1_LI_R0
- %18
- P1_LI_BR
- &prim_bitxor
- P1_BEQ_R3_R0
- P1_LI_R0
- %19
- P1_LI_BR
- &prim_bitnot
- P1_BEQ_R3_R0
- P1_LI_R0
- %20
- P1_LI_BR
- &prim_ashift
- P1_BEQ_R3_R0
- P1_LI_R0
- %21
- P1_LI_BR
- &prim_numberp
- P1_BEQ_R3_R0
- P1_LI_R0
- %22
- P1_LI_BR
- &prim_symbolp
- P1_BEQ_R3_R0
- P1_LI_R0
- %23
- P1_LI_BR
- &prim_stringp
- P1_BEQ_R3_R0
- P1_LI_R0
- %24
- P1_LI_BR
- &prim_vectorp
- P1_BEQ_R3_R0
- P1_LI_R0
- %25
- P1_LI_BR
- &prim_procp
- P1_BEQ_R3_R0
- P1_LI_R0
- %26
- P1_LI_BR
- &prim_eqp
- P1_BEQ_R3_R0
- P1_LI_R0
- %27
- P1_LI_BR
- &prim_cons
- P1_BEQ_R3_R0
- P1_LI_R0
- %28
- P1_LI_BR
- &prim_car
- P1_BEQ_R3_R0
- P1_LI_R0
- %29
- P1_LI_BR
- &prim_cdr
- P1_BEQ_R3_R0
- P1_LI_R0
- %30
- P1_LI_BR
- &prim_pairp
- P1_BEQ_R3_R0
- P1_LI_R0
- %31
- P1_LI_BR
- &prim_nullp
- P1_BEQ_R3_R0
- P1_LI_R0
- %32
- P1_LI_BR
- &prim_list
- P1_BEQ_R3_R0
- P1_LI_R0
- %33
- P1_LI_BR
- &prim_length
- P1_BEQ_R3_R0
- P1_LI_R0
- %34
- P1_LI_BR
- &prim_listp
- P1_BEQ_R3_R0
- P1_LI_R0
- %35
- P1_LI_BR
- &prim_append
- P1_BEQ_R3_R0
- P1_LI_R0
- %36
- P1_LI_BR
- &prim_reverse
- P1_BEQ_R3_R0
- P1_LI_R0
- %37
- P1_LI_BR
- &prim_assoc
- P1_BEQ_R3_R0
- P1_LI_R0
- %38
- P1_LI_BR
- &prim_member
- P1_BEQ_R3_R0
- P1_LI_R0
- %39
- P1_LI_BR
- &prim_string_length
- P1_BEQ_R3_R0
- P1_LI_R0
- %40
- P1_LI_BR
- &prim_string_ref
- P1_BEQ_R3_R0
- P1_LI_R0
- %41
- P1_LI_BR
- &prim_substring
- P1_BEQ_R3_R0
- P1_LI_R0
- %42
- P1_LI_BR
- &prim_string_append
- P1_BEQ_R3_R0
- P1_LI_R0
- %43
- P1_LI_BR
- &prim_string_to_symbol
- P1_BEQ_R3_R0
- P1_LI_R0
- %44
- P1_LI_BR
- &prim_symbol_to_string
- P1_BEQ_R3_R0
- P1_LI_R0
- %45
- P1_LI_BR
- &prim_make_vector
- P1_BEQ_R3_R0
- P1_LI_R0
- %46
- P1_LI_BR
- &prim_vector_ref
- P1_BEQ_R3_R0
- P1_LI_R0
- %47
- P1_LI_BR
- &prim_vector_set
- P1_BEQ_R3_R0
- P1_LI_R0
- %48
- P1_LI_BR
- &prim_vector_length
- P1_BEQ_R3_R0
- P1_LI_R0
- %49
- P1_LI_BR
- &prim_vector_to_list
- P1_BEQ_R3_R0
- P1_LI_R0
- %50
- P1_LI_BR
- &prim_list_to_vector
- P1_BEQ_R3_R0
- P1_LI_R0
- %51
- P1_LI_BR
- &prim_display
- P1_BEQ_R3_R0
- P1_LI_R0
- %52
- P1_LI_BR
- &prim_write
- P1_BEQ_R3_R0
- P1_LI_R0
- %53
- P1_LI_BR
- &prim_newline
- P1_BEQ_R3_R0
- P1_LI_R0
- %54
- P1_LI_BR
- &prim_format
- P1_BEQ_R3_R0
- P1_LI_R0
- %55
- P1_LI_BR
- &prim_error
- P1_BEQ_R3_R0
- P1_LI_R0
- %56
- P1_LI_BR
- &prim_read_file
- P1_BEQ_R3_R0
- P1_LI_R0
- %57
- P1_LI_BR
- &prim_write_file
- P1_BEQ_R3_R0
- P1_LI_R0
- %58
- P1_LI_BR
- &prim_equal
- P1_BEQ_R3_R0
- P1_LI_R0
- %59
- P1_LI_BR
- &prim_apply
- P1_BEQ_R3_R0
-
- P1_LI_BR
- &err_bad_prim
- P1_B
+ li_br &prim_add
+ beqz_r3
+ li_r0 %1
+ li_br &prim_sub
+ beq_r3,r0
+ li_r0 %2
+ li_br &prim_mul
+ beq_r3,r0
+ li_r0 %3
+ li_br &prim_div
+ beq_r3,r0
+ li_r0 %4
+ li_br &prim_mod
+ beq_r3,r0
+ li_r0 %5
+ li_br &prim_numeq
+ beq_r3,r0
+ li_r0 %6
+ li_br &prim_lt
+ beq_r3,r0
+ li_r0 %7
+ li_br &prim_gt
+ beq_r3,r0
+ li_r0 %8
+ li_br &prim_le
+ beq_r3,r0
+ li_r0 %9
+ li_br &prim_ge
+ beq_r3,r0
+ li_r0 %10
+ li_br &prim_zerop
+ beq_r3,r0
+ li_r0 %11
+ li_br &prim_negativep
+ beq_r3,r0
+ li_r0 %12
+ li_br &prim_positivep
+ beq_r3,r0
+ li_r0 %13
+ li_br &prim_abs
+ beq_r3,r0
+ li_r0 %14
+ li_br &prim_min
+ beq_r3,r0
+ li_r0 %15
+ li_br &prim_max
+ beq_r3,r0
+ li_r0 %16
+ li_br &prim_bitand
+ beq_r3,r0
+ li_r0 %17
+ li_br &prim_bitor
+ beq_r3,r0
+ li_r0 %18
+ li_br &prim_bitxor
+ beq_r3,r0
+ li_r0 %19
+ li_br &prim_bitnot
+ beq_r3,r0
+ li_r0 %20
+ li_br &prim_ashift
+ beq_r3,r0
+ li_r0 %21
+ li_br &prim_numberp
+ beq_r3,r0
+ li_r0 %22
+ li_br &prim_symbolp
+ beq_r3,r0
+ li_r0 %23
+ li_br &prim_stringp
+ beq_r3,r0
+ li_r0 %24
+ li_br &prim_vectorp
+ beq_r3,r0
+ li_r0 %25
+ li_br &prim_procp
+ beq_r3,r0
+ li_r0 %26
+ li_br &prim_eqp
+ beq_r3,r0
+ li_r0 %27
+ li_br &prim_cons
+ beq_r3,r0
+ li_r0 %28
+ li_br &prim_car
+ beq_r3,r0
+ li_r0 %29
+ li_br &prim_cdr
+ beq_r3,r0
+ li_r0 %30
+ li_br &prim_pairp
+ beq_r3,r0
+ li_r0 %31
+ li_br &prim_nullp
+ beq_r3,r0
+ li_r0 %32
+ li_br &prim_list
+ beq_r3,r0
+ li_r0 %33
+ li_br &prim_length
+ beq_r3,r0
+ li_r0 %34
+ li_br &prim_listp
+ beq_r3,r0
+ li_r0 %35
+ li_br &prim_append
+ beq_r3,r0
+ li_r0 %36
+ li_br &prim_reverse
+ beq_r3,r0
+ li_r0 %37
+ li_br &prim_assoc
+ beq_r3,r0
+ li_r0 %38
+ li_br &prim_member
+ beq_r3,r0
+ li_r0 %39
+ li_br &prim_string_length
+ beq_r3,r0
+ li_r0 %40
+ li_br &prim_string_ref
+ beq_r3,r0
+ li_r0 %41
+ li_br &prim_substring
+ beq_r3,r0
+ li_r0 %42
+ li_br &prim_string_append
+ beq_r3,r0
+ li_r0 %43
+ li_br &prim_string_to_symbol
+ beq_r3,r0
+ li_r0 %44
+ li_br &prim_symbol_to_string
+ beq_r3,r0
+ li_r0 %45
+ li_br &prim_make_vector
+ beq_r3,r0
+ li_r0 %46
+ li_br &prim_vector_ref
+ beq_r3,r0
+ li_r0 %47
+ li_br &prim_vector_set
+ beq_r3,r0
+ li_r0 %48
+ li_br &prim_vector_length
+ beq_r3,r0
+ li_r0 %49
+ li_br &prim_vector_to_list
+ beq_r3,r0
+ li_r0 %50
+ li_br &prim_list_to_vector
+ beq_r3,r0
+ li_r0 %51
+ li_br &prim_display
+ beq_r3,r0
+ li_r0 %52
+ li_br &prim_write
+ beq_r3,r0
+ li_r0 %53
+ li_br &prim_newline
+ beq_r3,r0
+ li_r0 %54
+ li_br &prim_format
+ beq_r3,r0
+ li_r0 %55
+ li_br &prim_error
+ beq_r3,r0
+ li_r0 %56
+ li_br &prim_read_file
+ beq_r3,r0
+ li_r0 %57
+ li_br &prim_write_file
+ beq_r3,r0
+ li_r0 %58
+ li_br &prim_equal
+ beq_r3,r0
+ li_r0 %59
+ li_br &prim_apply
+ beq_r3,r0
+
+ li_br &err_bad_prim
+ b
## ---- Primitive bodies ----------------------------------------------
@@ -3254,300 +2565,259 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## (+ ...) — variadic sum. Tagged fixnum (v<<3)|1: untag each, add
## to decoded accumulator, retag at end.
:prim_add
- P1_LI_R3
- %0 ## acc = 0
- P1_SHLI_R1_R1_3
- P1_ADD_R1_R1_R2 ## r1 = argv_end
+ li_r3 %0 ## acc = 0
+ shli_r1,r1,3
+ add_r1,r1,r2 ## r1 = argv_end
:prim_add_loop
- P1_LI_BR
- &prim_add_done
- P1_BEQ_R2_R1
- P1_LD_R0_R2_0
- P1_SARI_R0_R0_3
- P1_ADD_R3_R3_R0
- P1_ADDI_R2_R2_8
- P1_LI_BR
- &prim_add_loop
- P1_B
+ li_br &prim_add_done
+ beq_r2,r1
+ ld_r0,r2,0
+ sari_r0,r0,3
+ add_r3,r3,r0
+ addi_r2,r2,8
+ li_br &prim_add_loop
+ b
:prim_add_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (- x) negates; (- x y ...) folds subtraction from the left.
:prim_sub
- P1_LI_R0
- %1
- P1_LI_BR
- &prim_sub_negate
- P1_BEQ_R1_R0 ## argc == 1 → unary negate
-
- P1_LD_R3_R2_0
- P1_SARI_R3_R3_3 ## r3 = decoded first
- P1_ADDI_R2_R2_8
- P1_ADDI_R1_R1_NEG1
- P1_SHLI_R1_R1_3
- P1_ADD_R1_R1_R2 ## r1 = argv_end
+ li_r0 %1
+ li_br &prim_sub_negate
+ beq_r1,r0 ## argc == 1 → unary negate
+
+ ld_r3,r2,0
+ sari_r3,r3,3 ## r3 = decoded first
+ addi_r2,r2,8
+ addi_r1,r1,neg1
+ shli_r1,r1,3
+ add_r1,r1,r2 ## r1 = argv_end
:prim_sub_loop
- P1_LI_BR
- &prim_sub_done
- P1_BEQ_R2_R1
- P1_LD_R0_R2_0
- P1_SARI_R0_R0_3
- P1_SUB_R3_R3_R0
- P1_ADDI_R2_R2_8
- P1_LI_BR
- &prim_sub_loop
- P1_B
+ li_br &prim_sub_done
+ beq_r2,r1
+ ld_r0,r2,0
+ sari_r0,r0,3
+ sub_r3,r3,r0
+ addi_r2,r2,8
+ li_br &prim_sub_loop
+ b
:prim_sub_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
:prim_sub_negate
- P1_LD_R3_R2_0
- P1_SARI_R3_R3_3
- P1_LI_R0
- %0
- P1_SUB_R3_R0_R3
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ ld_r3,r2,0
+ sari_r3,r3,3
+ li_r0 %0
+ sub_r3,r0,r3
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (* ...) — variadic product. Identity 1.
:prim_mul
- P1_LI_R3
- %1 ## acc = 1
- P1_SHLI_R1_R1_3
- P1_ADD_R1_R1_R2
+ li_r3 %1 ## acc = 1
+ shli_r1,r1,3
+ add_r1,r1,r2
:prim_mul_loop
- P1_LI_BR
- &prim_mul_done
- P1_BEQ_R2_R1
- P1_LD_R0_R2_0
- P1_SARI_R0_R0_3
- P1_MUL_R3_R3_R0
- P1_ADDI_R2_R2_8
- P1_LI_BR
- &prim_mul_loop
- P1_B
+ li_br &prim_mul_done
+ beq_r2,r1
+ ld_r0,r2,0
+ sari_r0,r0,3
+ mul_r3,r3,r0
+ addi_r2,r2,8
+ li_br &prim_mul_loop
+ b
:prim_mul_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (/ x y) — binary integer division (signed).
:prim_div
- P1_LD_R3_R2_0
- P1_SARI_R3_R3_3
- P1_LD_R0_R2_8
- P1_SARI_R0_R0_3
- P1_DIV_R3_R3_R0
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ ld_r3,r2,0
+ sari_r3,r3,3
+ ld_r0,r2,8
+ sari_r0,r0,3
+ div_r3,r3,r0
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (% x y) — binary signed remainder. Scheme calls this `modulo`
## / `remainder`; we bind the primitive as `%` to stay fixnum-only
## and avoid the sign-convention split.
:prim_mod
- P1_LD_R3_R2_0
- P1_SARI_R3_R3_3
- P1_LD_R0_R2_8
- P1_SARI_R0_R0_3
- P1_REM_R3_R3_R0
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ ld_r3,r2,0
+ sari_r3,r3,3
+ ld_r0,r2,8
+ sari_r0,r0,3
+ rem_r3,r3,r0
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (= x y) — binary fixnum equality. Because tagged fixnums share
## the same low-3-bit tag (001) and the payload is bit-identical
## for equal values, we compare the tagged words directly.
:prim_numeq
- P1_LD_R3_R2_0
- P1_LD_R0_R2_8
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- FALSE ## #f
- P1_RET
+ ld_r3,r2,0
+ ld_r0,r2,8
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 FALSE ## #f
+ ret
## Shared "return #t" tail used by comparison/predicate primitives.
:prim_true
- P1_LI_R0
- TRUE
- P1_RET
+ li_r0 TRUE
+ ret
## (< x y). Tagged-fixnum order preserves decoded order (shift-by-3
## is monotone for 61-bit signed values).
:prim_lt
- P1_LD_R3_R2_0
- P1_LD_R0_R2_8
- P1_LI_BR
- &prim_true
- P1_BLT_R3_R0
- P1_LI_R0
- %23
- P1_RET
+ ld_r3,r2,0
+ ld_r0,r2,8
+ li_br &prim_true
+ blt_r3,r0
+ li_r0 %23
+ ret
## (> x y) ≡ (< y x).
:prim_gt
- P1_LD_R3_R2_0
- P1_LD_R0_R2_8
- P1_LI_BR
- &prim_true
- P1_BLT_R0_R3
- P1_LI_R0
- %23
- P1_RET
+ ld_r3,r2,0
+ ld_r0,r2,8
+ li_br &prim_true
+ blt_r0,r3
+ li_r0 %23
+ ret
## (<= x y) ≡ !(y < x). Invert the BLT result.
:prim_le
- P1_LD_R3_R2_0
- P1_LD_R0_R2_8
- P1_LI_BR
- &prim_le_false
- P1_BLT_R0_R3
- P1_LI_R0
- TRUE ## #t
- P1_RET
+ ld_r3,r2,0
+ ld_r0,r2,8
+ li_br &prim_le_false
+ blt_r0,r3
+ li_r0 TRUE ## #t
+ ret
:prim_le_false
- P1_LI_R0
- %23
- P1_RET
+ li_r0 %23
+ ret
## (>= x y) ≡ !(x < y).
:prim_ge
- P1_LD_R3_R2_0
- P1_LD_R0_R2_8
- P1_LI_BR
- &prim_ge_false
- P1_BLT_R3_R0
- P1_LI_R0
- %15
- P1_RET
+ ld_r3,r2,0
+ ld_r0,r2,8
+ li_br &prim_ge_false
+ blt_r3,r0
+ li_r0 %15
+ ret
:prim_ge_false
- P1_LI_R0
- %23
- P1_RET
+ li_r0 %23
+ ret
## (zero? x). Tagged fixnum 0 = 0x01.
:prim_zerop
- P1_LD_R3_R2_0
- P1_LI_R0
- %1
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- %23
- P1_RET
+ ld_r3,r2,0
+ li_r0 %1
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 %23
+ ret
## (negative? x) — tagged-compare against 0x01.
:prim_negativep
- P1_LD_R3_R2_0
- P1_LI_R0
- %1
- P1_LI_BR
- &prim_true
- P1_BLT_R3_R0
- P1_LI_R0
- %23
- P1_RET
+ ld_r3,r2,0
+ li_r0 %1
+ li_br &prim_true
+ blt_r3,r0
+ li_r0 %23
+ ret
## (positive? x).
:prim_positivep
- P1_LD_R3_R2_0
- P1_LI_R0
- %1
- P1_LI_BR
- &prim_true
- P1_BLT_R0_R3
- P1_LI_R0
- %23
- P1_RET
+ ld_r3,r2,0
+ li_r0 %1
+ li_br &prim_true
+ blt_r0,r3
+ li_r0 %23
+ ret
## (abs x) — branch-on-sign; negate by 0 - v.
:prim_abs
- P1_LD_R3_R2_0
- P1_SARI_R3_R3_3 ## decode
- P1_LI_R0
- %0
- P1_LI_BR
- &prim_abs_done
- P1_BLT_R0_R3 ## 0 < v → already positive
- P1_SUB_R3_R0_R3 ## v = -v
+ ld_r3,r2,0
+ sari_r3,r3,3 ## decode
+ li_r0 %0
+ li_br &prim_abs_done
+ blt_r0,r3 ## 0 < v → already positive
+ sub_r3,r0,r3 ## v = -v
:prim_abs_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (min ...) — variadic; first arg is seed, each later arg replaces
## acc if strictly smaller. Comparing tagged fixnums directly keeps
## the body untagging-free.
:prim_min
- P1_LD_R3_R2_0 ## r3 = acc (tagged)
- P1_ADDI_R2_R2_8
- P1_ADDI_R1_R1_NEG1
- P1_SHLI_R1_R1_3
- P1_ADD_R1_R1_R2
+ ld_r3,r2,0 ## r3 = acc (tagged)
+ addi_r2,r2,8
+ addi_r1,r1,neg1
+ shli_r1,r1,3
+ add_r1,r1,r2
:prim_min_loop
- P1_LI_BR
- &prim_min_done
- P1_BEQ_R2_R1
- P1_LD_R0_R2_0
- P1_LI_BR
- &prim_min_skip
- P1_BLT_R3_R0 ## acc < x → keep acc
- P1_MOV_R3_R0
+ li_br &prim_min_done
+ beq_r2,r1
+ ld_r0,r2,0
+ li_br &prim_min_skip
+ blt_r3,r0 ## acc < x → keep acc
+ mov_r3,r0
:prim_min_skip
- P1_ADDI_R2_R2_8
- P1_LI_BR
- &prim_min_loop
- P1_B
+ addi_r2,r2,8
+ li_br &prim_min_loop
+ b
:prim_min_done
- P1_MOV_R0_R3
- P1_RET
+ mov_r0,r3
+ ret
## (max ...) — acc replaces on strictly greater.
:prim_max
- P1_LD_R3_R2_0
- P1_ADDI_R2_R2_8
- P1_ADDI_R1_R1_NEG1
- P1_SHLI_R1_R1_3
- P1_ADD_R1_R1_R2
+ ld_r3,r2,0
+ addi_r2,r2,8
+ addi_r1,r1,neg1
+ shli_r1,r1,3
+ add_r1,r1,r2
:prim_max_loop
- P1_LI_BR
- &prim_max_done
- P1_BEQ_R2_R1
- P1_LD_R0_R2_0
- P1_LI_BR
- &prim_max_skip
- P1_BLT_R0_R3 ## x < acc → keep acc
- P1_MOV_R3_R0
+ li_br &prim_max_done
+ beq_r2,r1
+ ld_r0,r2,0
+ li_br &prim_max_skip
+ blt_r0,r3 ## x < acc → keep acc
+ mov_r3,r0
:prim_max_skip
- P1_ADDI_R2_R2_8
- P1_LI_BR
- &prim_max_loop
- P1_B
+ addi_r2,r2,8
+ li_br &prim_max_loop
+ b
:prim_max_done
- P1_MOV_R0_R3
- P1_RET
+ mov_r0,r3
+ ret
## (bit-and ...) — variadic fold. Identity is all-ones; we seed the
@@ -3555,163 +2825,139 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## preserved through AND on tagged fixnums, but we still untag/retag
## to match the shape of the other variadic bit ops.
:prim_bitand
- P1_LI_R3
- %0
- P1_ADDI_R3_R3_NEG1 ## r3 = -1
- P1_SHLI_R1_R1_3
- P1_ADD_R1_R1_R2
+ li_r3 %0
+ addi_r3,r3,neg1 ## r3 = -1
+ shli_r1,r1,3
+ add_r1,r1,r2
:prim_bitand_loop
- P1_LI_BR
- &prim_bitand_done
- P1_BEQ_R2_R1
- P1_LD_R0_R2_0
- P1_SARI_R0_R0_3
- P1_AND_R3_R3_R0
- P1_ADDI_R2_R2_8
- P1_LI_BR
- &prim_bitand_loop
- P1_B
+ li_br &prim_bitand_done
+ beq_r2,r1
+ ld_r0,r2,0
+ sari_r0,r0,3
+ and_r3,r3,r0
+ addi_r2,r2,8
+ li_br &prim_bitand_loop
+ b
:prim_bitand_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (bit-or ...) — identity 0.
:prim_bitor
- P1_LI_R3
- %0
- P1_SHLI_R1_R1_3
- P1_ADD_R1_R1_R2
+ li_r3 %0
+ shli_r1,r1,3
+ add_r1,r1,r2
:prim_bitor_loop
- P1_LI_BR
- &prim_bitor_done
- P1_BEQ_R2_R1
- P1_LD_R0_R2_0
- P1_SARI_R0_R0_3
- P1_OR_R3_R3_R0
- P1_ADDI_R2_R2_8
- P1_LI_BR
- &prim_bitor_loop
- P1_B
+ li_br &prim_bitor_done
+ beq_r2,r1
+ ld_r0,r2,0
+ sari_r0,r0,3
+ or_r3,r3,r0
+ addi_r2,r2,8
+ li_br &prim_bitor_loop
+ b
:prim_bitor_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (bit-xor ...) — identity 0.
:prim_bitxor
- P1_LI_R3
- %0
- P1_SHLI_R1_R1_3
- P1_ADD_R1_R1_R2
+ li_r3 %0
+ shli_r1,r1,3
+ add_r1,r1,r2
:prim_bitxor_loop
- P1_LI_BR
- &prim_bitxor_done
- P1_BEQ_R2_R1
- P1_LD_R0_R2_0
- P1_SARI_R0_R0_3
- P1_XOR_R3_R3_R0
- P1_ADDI_R2_R2_8
- P1_LI_BR
- &prim_bitxor_loop
- P1_B
+ li_br &prim_bitxor_done
+ beq_r2,r1
+ ld_r0,r2,0
+ sari_r0,r0,3
+ xor_r3,r3,r0
+ addi_r2,r2,8
+ li_br &prim_bitxor_loop
+ b
:prim_bitxor_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (bit-not x) — ~x = -1 - x.
:prim_bitnot
- P1_LD_R3_R2_0
- P1_SARI_R3_R3_3
- P1_LI_R0
- %0
- P1_ADDI_R0_R0_NEG1 ## r0 = -1
- P1_SUB_R3_R0_R3 ## r3 = -1 - r3
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ ld_r3,r2,0
+ sari_r3,r3,3
+ li_r0 %0
+ addi_r0,r0,neg1 ## r0 = -1
+ sub_r3,r0,r3 ## r3 = -1 - r3
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (arithmetic-shift n k) — k>=0 left shift, k<0 arithmetic right.
:prim_ashift
- P1_LD_R3_R2_0
- P1_SARI_R3_R3_3 ## r3 = n (decoded)
- P1_LD_R0_R2_8
- P1_SARI_R0_R0_3 ## r0 = k (decoded, signed)
- P1_LI_BR
- &prim_ashift_neg
- P1_BLTZ_R0 ## k < 0 → right shift by -k
- P1_SHL_R3_R3_R0
- P1_LI_BR
- &prim_ashift_done
- P1_B
+ ld_r3,r2,0
+ sari_r3,r3,3 ## r3 = n (decoded)
+ ld_r0,r2,8
+ sari_r0,r0,3 ## r0 = k (decoded, signed)
+ li_br &prim_ashift_neg
+ bltz_r0 ## k < 0 → right shift by -k
+ shl_r3,r3,r0
+ li_br &prim_ashift_done
+ b
:prim_ashift_neg
- P1_SUB_R0_R1_R0 ## r0 = -k
- P1_SAR_R3_R3_R0
+ sub_r0,r1,r0 ## r0 = -k
+ sar_r3,r3,r0
:prim_ashift_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (number? x) — true iff tag is 1 (fixnum).
:prim_numberp
- P1_LD_R3_R2_0
- P1_ANDI_R3_R3_7
- P1_LI_R0
- TAG_FIXNUM
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- FALSE
- P1_RET
+ ld_r3,r2,0
+ andi_r3,r3,7
+ li_r0 TAG_FIXNUM
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 FALSE
+ ret
## (symbol? x) — tag is 5.
:prim_symbolp
- P1_LD_R3_R2_0
- P1_ANDI_R3_R3_7
- P1_LI_R0
- TAG_SYMBOL
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- FALSE
- P1_RET
+ ld_r3,r2,0
+ andi_r3,r3,7
+ li_r0 TAG_SYMBOL
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 FALSE
+ ret
## (string? x) — tag is 4.
:prim_stringp
- P1_LD_R3_R2_0
- P1_ANDI_R3_R3_7
- P1_LI_R0
- TAG_STRING
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- FALSE
- P1_RET
+ ld_r3,r2,0
+ andi_r3,r3,7
+ li_r0 TAG_STRING
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 FALSE
+ ret
## (vector? x) — tag is 3.
:prim_vectorp
- P1_LD_R3_R2_0
- P1_ANDI_R3_R3_7
- P1_LI_R0
- TAG_VECTOR
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- FALSE
- P1_RET
+ ld_r3,r2,0
+ andi_r3,r3,7
+ li_r0 TAG_VECTOR
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 FALSE
+ ret
## (procedure? x) — tag 6 AND header type ∈ {4,5,6}. Any of the three
@@ -3719,423 +2965,366 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## tag-6 value shape (if we add one later) would need explicit
## enumeration here.
:prim_procp
- P1_LD_R3_R2_0
- P1_MOV_R0_R3
- P1_ANDI_R0_R0_7
- P1_LI_R1
- TAG_PROC
- P1_LI_BR
- &prim_procp_false
- P1_BNE_R0_R1 ## tag != 6 → #f
-
- P1_ADDI_R3_R3_NEG6 ## strip tag
- P1_LB_R0_R3_7 ## r0 = type byte
- P1_LI_R1
- TYPE_CLOSURE
- P1_LI_BR
- &prim_true
- P1_BEQ_R0_R1
- P1_LI_R1
- TYPE_PRIM_FIXED
- P1_LI_BR
- &prim_true
- P1_BEQ_R0_R1
- P1_LI_R1
- TYPE_PRIM_VARIADIC
- P1_LI_BR
- &prim_true
- P1_BEQ_R0_R1
+ ld_r3,r2,0
+ mov_r0,r3
+ andi_r0,r0,7
+ li_r1 TAG_PROC
+ li_br &prim_procp_false
+ bne_r0,r1 ## tag != 6 → #f
+
+ addi_r3,r3,neg6 ## strip tag
+ lb_r0,r3,7 ## r0 = type byte
+ li_r1 TYPE_CLOSURE
+ li_br &prim_true
+ beq_r0,r1
+ li_r1 TYPE_PRIM_FIXED
+ li_br &prim_true
+ beq_r0,r1
+ li_r1 TYPE_PRIM_VARIADIC
+ li_br &prim_true
+ beq_r0,r1
:prim_procp_false
- P1_LI_R0
- FALSE
- P1_RET
+ li_r0 FALSE
+ ret
## (eq? x y) — pointer/bit identity. Fixnums, interned symbols, and
## singletons all compare correctly this way; pairs/strings/vectors/
## closures compare by heap address (distinct allocations are #f).
:prim_eqp
- P1_LD_R3_R2_0
- P1_LD_R0_R2_8
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- FALSE
- P1_RET
+ ld_r3,r2,0
+ ld_r0,r2,8
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 FALSE
+ ret
## ---- Step-10d list-core primitives ---------------------------------
## (cons a d) — wraps the internal `cons` helper which calls alloc;
## need PROLOGUE to save lr across the call.
:prim_cons
- P1_PROLOGUE
- P1_LD_R1_R2_0 ## r1 = car arg
- P1_LD_R2_R2_8 ## r2 = cdr arg (uses old r2 base)
- P1_LI_BR
- &cons
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ prologue
+ ld_r1,r2,0 ## r1 = car arg
+ ld_r2,r2,8 ## r2 = cdr arg (uses old r2 base)
+ li_br &cons
+ call
+ epilogue
+ ret
## (car p) — unsafe (no tag check). Inlined: strip 0b010 tag, load +0.
:prim_car
- P1_LD_R1_R2_0
- P1_ADDI_R1_R1_NEG2
- P1_LD_R0_R1_0
- P1_RET
+ ld_r1,r2,0
+ addi_r1,r1,neg2
+ ld_r0,r1,0
+ ret
## (cdr p) — symmetric.
:prim_cdr
- P1_LD_R1_R2_0
- P1_ADDI_R1_R1_NEG2
- P1_LD_R0_R1_8
- P1_RET
+ ld_r1,r2,0
+ addi_r1,r1,neg2
+ ld_r0,r1,8
+ ret
## (pair? x) — tag is 2.
:prim_pairp
- P1_LD_R3_R2_0
- P1_ANDI_R3_R3_7
- P1_LI_R0
- TAG_PAIR
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- %23
- P1_RET
+ ld_r3,r2,0
+ andi_r3,r3,7
+ li_r0 TAG_PAIR
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 %23
+ ret
## (null? x) — equals nil singleton (0x07).
:prim_nullp
- P1_LD_R3_R2_0
- P1_LI_R0
- NIL
- P1_LI_BR
- &prim_true
- P1_BEQ_R3_R0
- P1_LI_R0
- %23
- P1_RET
+ ld_r3,r2,0
+ li_r0 NIL
+ li_br &prim_true
+ beq_r3,r0
+ li_r0 %23
+ ret
## (list ...) — variadic; build (a b c ...) by walking argv from the
## tail and consing onto an accumulator (initially nil). Walking from
## the tail avoids needing a reverse pass.
:prim_list
- P1_PROLOGUE_N3
- P1_MOV_R3_SP
- P1_LI_R0
- NIL ## nil
- P1_ST_R0_SP_8 ## slot1 = accumulator
- P1_ST_R2_SP_24 ## slot3 = base
- P1_SHLI_R1_R1_3 ## r1 = argc * 8
- P1_ADD_R1_R1_R2 ## r1 = end ptr (one past last)
- P1_ST_R1_SP_16 ## slot2 = cursor
+ prologue_n3
+ mov_r3,sp
+ li_r0 NIL ## nil
+ st_r0,sp,8 ## slot1 = accumulator
+ st_r2,sp,24 ## slot3 = base
+ shli_r1,r1,3 ## r1 = argc * 8
+ add_r1,r1,r2 ## r1 = end ptr (one past last)
+ st_r1,sp,16 ## slot2 = cursor
:prim_list_loop
- P1_MOV_R3_SP
- P1_LD_R0_SP_16 ## cursor
- P1_LD_R1_SP_24 ## base
- P1_LI_BR
- &prim_list_done
- P1_BEQ_R0_R1
- P1_ADDI_R0_R0_NEG8 ## cursor -= 8
- P1_ST_R0_SP_16
- P1_LD_R1_R0_0 ## r1 = arg
- P1_LD_R2_SP_8 ## r2 = accumulator
- P1_LI_BR
- &cons
- P1_CALL
- P1_ST_R0_SP_8 ## accumulator = new pair
- P1_LI_BR
- &prim_list_loop
- P1_B
+ mov_r3,sp
+ ld_r0,sp,16 ## cursor
+ ld_r1,sp,24 ## base
+ li_br &prim_list_done
+ beq_r0,r1
+ addi_r0,r0,neg8 ## cursor -= 8
+ st_r0,sp,16
+ ld_r1,r0,0 ## r1 = arg
+ ld_r2,sp,8 ## r2 = accumulator
+ li_br &cons
+ call
+ st_r0,sp,8 ## accumulator = new pair
+ li_br &prim_list_loop
+ b
:prim_list_done
- P1_LD_R0_SP_8
- P1_EPILOGUE_N3
- P1_RET
+ ld_r0,sp,8
+ epilogue_n3
+ ret
## (length lst) — count pairs until nil. No proper-list check; an
## improper or non-list tail will dereference a bogus ptr (matching
## the seed's "no validation on bad input" stance).
:prim_length
- P1_LD_R1_R2_0
- P1_LI_R3
- %0
+ ld_r1,r2,0
+ li_r3 %0
:prim_length_loop
- P1_LI_R0
- %7
- P1_LI_BR
- &prim_length_done
- P1_BEQ_R1_R0
- P1_ADDI_R0_R1_NEG2
- P1_LD_R1_R0_8
- P1_ADDI_R3_R3_1
- P1_LI_BR
- &prim_length_loop
- P1_B
+ li_r0 %7
+ li_br &prim_length_done
+ beq_r1,r0
+ addi_r0,r1,neg2
+ ld_r1,r0,8
+ addi_r3,r3,1
+ li_br &prim_length_loop
+ b
:prim_length_done
- P1_SHLI_R0_R3_3
- P1_ORI_R0_R0_1
- P1_RET
+ shli_r0,r3,3
+ ori_r0,r0,1
+ ret
## (list? x) — walks to nil. Returns #t at nil, #f at any non-pair
## node. No cycle check (per LISP.md §equal? policy).
:prim_listp
- P1_LD_R1_R2_0
+ ld_r1,r2,0
:prim_listp_loop
- P1_LI_R0
- %7
- P1_LI_BR
- &prim_true
- P1_BEQ_R1_R0
- P1_MOV_R0_R1
- P1_ANDI_R0_R0_7
- P1_LI_R3
- %2
- P1_LI_BR
- &prim_listp_false
- P1_BNE_R0_R3
- P1_ADDI_R0_R1_NEG2
- P1_LD_R1_R0_8
- P1_LI_BR
- &prim_listp_loop
- P1_B
+ li_r0 %7
+ li_br &prim_true
+ beq_r1,r0
+ mov_r0,r1
+ andi_r0,r0,7
+ li_r3 %2
+ li_br &prim_listp_false
+ bne_r0,r3
+ addi_r0,r1,neg2
+ ld_r1,r0,8
+ li_br &prim_listp_loop
+ b
:prim_listp_false
- P1_LI_R0
- %23
- P1_RET
+ li_r0 %23
+ ret
## append_one(r1=xs, r2=ys) -> r0 = xs ++ ys. Copies xs's spine; ys
## is shared by reference. Recursive — bounded by xs's length.
:append_one
- P1_PROLOGUE_N2
- P1_LI_R0
- %7
- P1_LI_BR
- &append_one_base
- P1_BEQ_R1_R0
- P1_ST_R1_SP_8 ## save xs
- P1_ST_R2_SP_16 ## save ys
- P1_ADDI_R0_R1_NEG2
- P1_LD_R1_R0_8 ## r1 = cdr(xs)
- P1_LI_BR
- &append_one
- P1_CALL ## r0 = appended tail
- P1_MOV_R2_R0
- P1_LD_R0_SP_8
- P1_ADDI_R0_R0_NEG2
- P1_LD_R1_R0_0 ## r1 = car(xs)
- P1_LI_BR
- &cons
- P1_CALL
- P1_EPILOGUE_N2
- P1_RET
+ prologue_n2
+ li_r0 %7
+ li_br &append_one_base
+ beq_r1,r0
+ st_r1,sp,8 ## save xs
+ st_r2,sp,16 ## save ys
+ addi_r0,r1,neg2
+ ld_r1,r0,8 ## r1 = cdr(xs)
+ li_br &append_one
+ call ## r0 = appended tail
+ mov_r2,r0
+ ld_r0,sp,8
+ addi_r0,r0,neg2
+ ld_r1,r0,0 ## r1 = car(xs)
+ li_br &cons
+ call
+ epilogue_n2
+ ret
:append_one_base
- P1_MOV_R0_R2
- P1_EPILOGUE_N2
- P1_RET
+ mov_r0,r2
+ epilogue_n2
+ ret
## (append ...) — variadic; the last argument is shared (not copied),
## all earlier arguments have their spines copied. Right-to-left fold.
:prim_append
- P1_PROLOGUE_N3
- P1_LI_BR
- &prim_append_zero
- P1_BEQZ_R1
- P1_MOV_R3_SP
- P1_ST_R2_SP_8 ## slot1 = argv base
- P1_ADDI_R1_R1_NEG1 ## r1 = argc-1
- P1_SHLI_R1_R1_3 ## r1 = (argc-1)*8
- P1_ADD_R1_R1_R2 ## r1 = &argv[argc-1]
- P1_ST_R1_SP_24 ## slot3 = cursor
- P1_LD_R0_R1_0 ## r0 = last arg
- P1_ST_R0_SP_16 ## slot2 = result
+ prologue_n3
+ li_br &prim_append_zero
+ beqz_r1
+ mov_r3,sp
+ st_r2,sp,8 ## slot1 = argv base
+ addi_r1,r1,neg1 ## r1 = argc-1
+ shli_r1,r1,3 ## r1 = (argc-1)*8
+ add_r1,r1,r2 ## r1 = &argv[argc-1]
+ st_r1,sp,24 ## slot3 = cursor
+ ld_r0,r1,0 ## r0 = last arg
+ st_r0,sp,16 ## slot2 = result
:prim_append_loop
- P1_MOV_R3_SP
- P1_LD_R0_SP_24 ## cursor
- P1_LD_R1_SP_8 ## base
- P1_LI_BR
- &prim_append_done
- P1_BEQ_R0_R1
- P1_ADDI_R0_R0_NEG8
- P1_ST_R0_SP_24
- P1_LD_R1_R0_0 ## r1 = arg at cursor
- P1_LD_R2_SP_16 ## r2 = result
- P1_LI_BR
- &append_one
- P1_CALL
- P1_ST_R0_SP_16
- P1_LI_BR
- &prim_append_loop
- P1_B
+ mov_r3,sp
+ ld_r0,sp,24 ## cursor
+ ld_r1,sp,8 ## base
+ li_br &prim_append_done
+ beq_r0,r1
+ addi_r0,r0,neg8
+ st_r0,sp,24
+ ld_r1,r0,0 ## r1 = arg at cursor
+ ld_r2,sp,16 ## r2 = result
+ li_br &append_one
+ call
+ st_r0,sp,16
+ li_br &prim_append_loop
+ b
:prim_append_done
- P1_LD_R0_SP_16
- P1_EPILOGUE_N3
- P1_RET
+ ld_r0,sp,16
+ epilogue_n3
+ ret
:prim_append_zero
- P1_LI_R0
- NIL
- P1_EPILOGUE_N3
- P1_RET
+ li_r0 NIL
+ epilogue_n3
+ ret
## (reverse lst) — single-pass cons-reverse onto nil accumulator.
:prim_reverse
- P1_PROLOGUE_N2
- P1_LD_R0_R2_0
- P1_MOV_R3_SP
- P1_ST_R0_SP_8 ## slot1 = current
- P1_LI_R0
- %7
- P1_ST_R0_SP_16 ## slot2 = accumulator (nil)
+ prologue_n2
+ ld_r0,r2,0
+ mov_r3,sp
+ st_r0,sp,8 ## slot1 = current
+ li_r0 %7
+ st_r0,sp,16 ## slot2 = accumulator (nil)
:prim_reverse_loop
- P1_MOV_R3_SP
- P1_LD_R0_SP_8
- P1_LI_R1
- %7
- P1_LI_BR
- &prim_reverse_done
- P1_BEQ_R0_R1
- P1_ADDI_R0_R0_NEG2
- P1_LD_R1_R0_0 ## r1 = car
- P1_LD_R2_R0_8 ## r2 = cdr (next current)
- P1_ST_R2_SP_8 ## slot1 = next
- P1_LD_R2_SP_16 ## r2 = accumulator
- P1_LI_BR
- &cons
- P1_CALL
- P1_ST_R0_SP_16
- P1_LI_BR
- &prim_reverse_loop
- P1_B
+ mov_r3,sp
+ ld_r0,sp,8
+ li_r1 %7
+ li_br &prim_reverse_done
+ beq_r0,r1
+ addi_r0,r0,neg2
+ ld_r1,r0,0 ## r1 = car
+ ld_r2,r0,8 ## r2 = cdr (next current)
+ st_r2,sp,8 ## slot1 = next
+ ld_r2,sp,16 ## r2 = accumulator
+ li_br &cons
+ call
+ st_r0,sp,16
+ li_br &prim_reverse_loop
+ b
:prim_reverse_done
- P1_LD_R0_SP_16
- P1_EPILOGUE_N2
- P1_RET
+ ld_r0,sp,16
+ epilogue_n2
+ ret
## (assoc key alist) — eq?-keyed alist lookup. Returns the matched
## (key . val) cell or #f.
:prim_assoc
- P1_LD_R3_R2_0 ## r3 = key
- P1_LD_R0_R2_8 ## r0 = alist cursor
+ ld_r3,r2,0 ## r3 = key
+ ld_r0,r2,8 ## r0 = alist cursor
:prim_assoc_loop
- P1_LI_R1
- %7
- P1_LI_BR
- &prim_assoc_miss
- P1_BEQ_R0_R1
- P1_ADDI_R1_R0_NEG2 ## raw alist cell
- P1_LD_R2_R1_0 ## r2 = inner pair (tagged)
- P1_ADDI_R2_R2_NEG2
- P1_LD_R2_R2_0 ## r2 = candidate key
- P1_LI_BR
- &prim_assoc_hit
- P1_BEQ_R2_R3
- P1_LD_R0_R1_8 ## advance alist
- P1_LI_BR
- &prim_assoc_loop
- P1_B
+ li_r1 %7
+ li_br &prim_assoc_miss
+ beq_r0,r1
+ addi_r1,r0,neg2 ## raw alist cell
+ ld_r2,r1,0 ## r2 = inner pair (tagged)
+ addi_r2,r2,neg2
+ ld_r2,r2,0 ## r2 = candidate key
+ li_br &prim_assoc_hit
+ beq_r2,r3
+ ld_r0,r1,8 ## advance alist
+ li_br &prim_assoc_loop
+ b
:prim_assoc_hit
- P1_LD_R0_R1_0 ## return inner pair
- P1_RET
+ ld_r0,r1,0 ## return inner pair
+ ret
:prim_assoc_miss
- P1_LI_R0
- %23
- P1_RET
+ li_r0 %23
+ ret
## (member x lst) — eq?-keyed; returns the first sublist whose car
## equals x, else #f.
:prim_member
- P1_LD_R3_R2_0 ## r3 = needle
- P1_LD_R0_R2_8 ## r0 = list cursor
+ ld_r3,r2,0 ## r3 = needle
+ ld_r0,r2,8 ## r0 = list cursor
:prim_member_loop
- P1_LI_R1
- %7
- P1_LI_BR
- &prim_member_miss
- P1_BEQ_R0_R1
- P1_ADDI_R1_R0_NEG2
- P1_LD_R2_R1_0 ## r2 = car
- P1_LI_BR
- &prim_member_hit
- P1_BEQ_R2_R3
- P1_LD_R0_R1_8 ## next sublist (tagged)
- P1_LI_BR
- &prim_member_loop
- P1_B
+ li_r1 %7
+ li_br &prim_member_miss
+ beq_r0,r1
+ addi_r1,r0,neg2
+ ld_r2,r1,0 ## r2 = car
+ li_br &prim_member_hit
+ beq_r2,r3
+ ld_r0,r1,8 ## next sublist (tagged)
+ li_br &prim_member_loop
+ b
:prim_member_hit
- P1_RET ## r0 already = current sublist
+ ret ## r0 already = current sublist
:prim_member_miss
- P1_LI_R0
- %23
- P1_RET
+ li_r0 %23
+ ret
## ---- (string-length s) — fixnum length out of header ---------------
:prim_string_length
- P1_LD_R1_R2_0
- P1_ADDI_R1_R1_NEG4 ## raw header
- P1_LD_R0_R1_0
- P1_SHLI_R0_R0_16
- P1_SHRI_R0_R0_16 ## low 48b = length
- P1_SHLI_R0_R0_3
- P1_ORI_R0_R0_1 ## fixnum encode
- P1_RET
+ ld_r1,r2,0
+ addi_r1,r1,neg4 ## raw header
+ ld_r0,r1,0
+ shli_r0,r0,16
+ shri_r0,r0,16 ## low 48b = length
+ shli_r0,r0,3
+ ori_r0,r0,1 ## fixnum encode
+ ret
## ---- (string-ref s i) — zero-extended byte as fixnum ---------------
:prim_string_ref
- P1_LD_R1_R2_0 ## tagged string
- P1_LD_R0_R2_8 ## tagged idx
- P1_SARI_R0_R0_3 ## raw idx
- P1_ADDI_R1_R1_NEG4 ## raw header
- P1_ADDI_R1_R1_8 ## payload base
- P1_ADD_R1_R1_R0 ## r1 = payload + idx
- P1_LB_R0_R1_0
- P1_SHLI_R0_R0_3
- P1_ORI_R0_R0_1
- P1_RET
+ ld_r1,r2,0 ## tagged string
+ ld_r0,r2,8 ## tagged idx
+ sari_r0,r0,3 ## raw idx
+ addi_r1,r1,neg4 ## raw header
+ addi_r1,r1,8 ## payload base
+ add_r1,r1,r0 ## r1 = payload + idx
+ lb_r0,r1,0
+ shli_r0,r0,3
+ ori_r0,r0,1
+ ret
## ---- (substring s start end) — copies s[start:end] -----------------
:prim_substring
- P1_PROLOGUE_N3
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
-
- P1_LD_R1_R2_0 ## tagged string
- P1_LD_R0_R2_8 ## tagged start
- P1_LD_R3_R2_16 ## tagged end
- P1_SARI_R0_R0_3 ## raw start
- P1_SARI_R3_R3_3 ## raw end
-
- P1_ADDI_R1_R1_NEG4 ## raw header
- P1_ADDI_R1_R1_8 ## payload base
- P1_SUB_R3_R3_R0 ## r3 = end - start (save len before r0 clobber)
- P1_MOV_R7_R3 ## r7 = len
- P1_MOV_R2_R0 ## r2 = start
- P1_ADD_R6_R1_R2 ## src = payload + start
-
- P1_MOV_R1_R6
- P1_MOV_R2_R7
- P1_LI_BR
- &make_string
- P1_CALL
-
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N3
- P1_RET
+ prologue_n3
+ st_r6,sp,8
+ st_r7,sp,16
+
+ ld_r1,r2,0 ## tagged string
+ ld_r0,r2,8 ## tagged start
+ ld_r3,r2,16 ## tagged end
+ sari_r0,r0,3 ## raw start
+ sari_r3,r3,3 ## raw end
+
+ addi_r1,r1,neg4 ## raw header
+ addi_r1,r1,8 ## payload base
+ sub_r3,r3,r0 ## r3 = end - start (save len before r0 clobber)
+ mov_r7,r3 ## r7 = len
+ mov_r2,r0 ## r2 = start
+ add_r6,r1,r2 ## src = payload + start
+
+ mov_r1,r6
+ mov_r2,r7
+ li_br &make_string
+ call
+
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n3
+ ret
## ---- (string-append ...) — variadic concat, two-pass ---------------
@@ -4143,322 +3332,287 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## then byte_copy each payload. argv is always &prim_argv so we don't
## need to spill the r2 it came in on.
:prim_string_append
- P1_PROLOGUE_N4
- P1_ST_R6_SP_8 ## save r6 (cursor/total reuse)
- P1_ST_R7_SP_16 ## save r7 (i)
- P1_ST_R1_SP_24 ## slot3 = argc
-
- P1_LI_R6
- %0 ## r6 = total length
- P1_LI_R7
- %0 ## r7 = i
+ prologue_n4
+ st_r6,sp,8 ## save r6 (cursor/total reuse)
+ st_r7,sp,16 ## save r7 (i)
+ st_r1,sp,24 ## slot3 = argc
+
+ li_r6 %0 ## r6 = total length
+ li_r7 %0 ## r7 = i
:psa_lp1
- P1_MOV_R3_SP
- P1_LD_R0_R3_24 ## argc
- P1_LI_BR
- &psa_done1
- P1_BEQ_R7_R0
-
- P1_LI_R0
- &prim_argv
- P1_SHLI_R3_R7_3
- P1_ADD_R0_R0_R3
- P1_LD_R0_R0_0 ## tagged str
- P1_ADDI_R0_R0_NEG4
- P1_LD_R0_R0_0 ## header
- P1_SHLI_R0_R0_16
- P1_SHRI_R0_R0_16 ## len
- P1_ADD_R6_R6_R0
- P1_ADDI_R7_R7_1
- P1_LI_BR
- &psa_lp1
- P1_B
+ mov_r3,sp
+ ld_r0,r3,24 ## argc
+ li_br &psa_done1
+ beq_r7,r0
+
+ li_r0 &prim_argv
+ shli_r3,r7,3
+ add_r0,r0,r3
+ ld_r0,r0,0 ## tagged str
+ addi_r0,r0,neg4
+ ld_r0,r0,0 ## header
+ shli_r0,r0,16
+ shri_r0,r0,16 ## len
+ add_r6,r6,r0
+ addi_r7,r7,1
+ li_br &psa_lp1
+ b
:psa_done1
- P1_MOV_R1_R6 ## total len
- P1_LI_BR
- &alloc_string
- P1_CALL ## r0 = tagged result
- P1_MOV_R3_SP
- P1_ST_R0_R3_32 ## slot4 = tagged result
+ mov_r1,r6 ## total len
+ li_br &alloc_string
+ call ## r0 = tagged result
+ mov_r3,sp
+ st_r0,r3,32 ## slot4 = tagged result
## r6 = payload cursor
- P1_ADDI_R6_R0_NEG4
- P1_ADDI_R6_R6_8
- P1_LI_R7
- %0 ## i = 0
+ addi_r6,r0,neg4
+ addi_r6,r6,8
+ li_r7 %0 ## i = 0
:psa_lp2
- P1_MOV_R3_SP
- P1_LD_R0_R3_24
- P1_LI_BR
- &psa_done2
- P1_BEQ_R7_R0
-
- P1_LI_R0
- &prim_argv
- P1_SHLI_R3_R7_3
- P1_ADD_R0_R0_R3
- P1_LD_R2_R0_0 ## tagged str
- P1_ADDI_R2_R2_NEG4 ## raw header
- P1_LD_R3_R2_0
- P1_SHLI_R3_R3_16
- P1_SHRI_R3_R3_16 ## len
- P1_ADDI_R2_R2_8 ## src payload
- P1_MOV_R1_R6 ## dst
- P1_LI_BR
- &byte_copy
- P1_CALL ## r0 = dst end
- P1_MOV_R6_R0
- P1_ADDI_R7_R7_1
- P1_LI_BR
- &psa_lp2
- P1_B
+ mov_r3,sp
+ ld_r0,r3,24
+ li_br &psa_done2
+ beq_r7,r0
+
+ li_r0 &prim_argv
+ shli_r3,r7,3
+ add_r0,r0,r3
+ ld_r2,r0,0 ## tagged str
+ addi_r2,r2,neg4 ## raw header
+ ld_r3,r2,0
+ shli_r3,r3,16
+ shri_r3,r3,16 ## len
+ addi_r2,r2,8 ## src payload
+ mov_r1,r6 ## dst
+ li_br &byte_copy
+ call ## r0 = dst end
+ mov_r6,r0
+ addi_r7,r7,1
+ li_br &psa_lp2
+ b
:psa_done2
- P1_MOV_R3_SP
- P1_LD_R0_R3_32
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N4
- P1_RET
+ mov_r3,sp
+ ld_r0,r3,32
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n4
+ ret
## ---- (string->symbol s) — intern the string's bytes ----------------
:prim_string_to_symbol
- P1_PROLOGUE
- P1_LD_R0_R2_0
- P1_ADDI_R0_R0_NEG4
- P1_LD_R2_R0_0
- P1_SHLI_R2_R2_16
- P1_SHRI_R2_R2_16 ## len
- P1_ADDI_R1_R0_8 ## payload
- P1_LI_BR
- &intern
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ prologue
+ ld_r0,r2,0
+ addi_r0,r0,neg4
+ ld_r2,r0,0
+ shli_r2,r2,16
+ shri_r2,r2,16 ## len
+ addi_r1,r0,8 ## payload
+ li_br &intern
+ call
+ epilogue
+ ret
## ---- (symbol->string sym) — copy sym name into a fresh string -----
:prim_symbol_to_string
- P1_PROLOGUE
- P1_LD_R0_R2_0
- P1_ADDI_R0_R0_NEG5 ## raw sym ptr
- P1_LD_R2_R0_0
- P1_SHLI_R2_R2_16
- P1_SHRI_R2_R2_16 ## len
- P1_ADDI_R1_R0_8 ## src payload
- P1_LI_BR
- &make_string
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ prologue
+ ld_r0,r2,0
+ addi_r0,r0,neg5 ## raw sym ptr
+ ld_r2,r0,0
+ shli_r2,r2,16
+ shri_r2,r2,16 ## len
+ addi_r1,r0,8 ## src payload
+ li_br &make_string
+ call
+ epilogue
+ ret
## ---- (make-vector n init) — n-slot vector filled with init --------
:prim_make_vector
- P1_PROLOGUE
- P1_LD_R1_R2_0 ## tagged n
- P1_SARI_R1_R1_3 ## raw n
- P1_LD_R2_R2_8 ## init (tagged)
- P1_LI_BR
- &make_vector
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ prologue
+ ld_r1,r2,0 ## tagged n
+ sari_r1,r1,3 ## raw n
+ ld_r2,r2,8 ## init (tagged)
+ li_br &make_vector
+ call
+ epilogue
+ ret
## ---- (vector-ref v i) — unsafe slot read ---------------------------
:prim_vector_ref
- P1_LD_R1_R2_0
- P1_LD_R3_R2_8
- P1_SARI_R3_R3_3 ## raw idx
- P1_ADDI_R1_R1_NEG3 ## raw vec
- P1_ADDI_R1_R1_8 ## payload base
- P1_SHLI_R3_R3_3 ## idx*8
- P1_MOV_R2_R3 ## stage in r2 (no ADD_R1_R1_R3)
- P1_ADD_R1_R1_R2
- P1_LD_R0_R1_0
- P1_RET
+ ld_r1,r2,0
+ ld_r3,r2,8
+ sari_r3,r3,3 ## raw idx
+ addi_r1,r1,neg3 ## raw vec
+ addi_r1,r1,8 ## payload base
+ shli_r3,r3,3 ## idx*8
+ mov_r2,r3 ## stage in r2 (no ADD_R1_R1_R3)
+ add_r1,r1,r2
+ ld_r0,r1,0
+ ret
## ---- (vector-set! v i val) -> unspec --------------------------------
:prim_vector_set
- P1_LD_R1_R2_0
- P1_LD_R3_R2_8
- P1_LD_R0_R2_16
- P1_SARI_R3_R3_3
- P1_ADDI_R1_R1_NEG3
- P1_ADDI_R1_R1_8
- P1_SHLI_R3_R3_3
- P1_MOV_R2_R3 ## stage idx*8 in r2
- P1_ADD_R1_R1_R2
- P1_ST_R0_R1_0
- P1_LI_R0
- UNSPEC
- P1_RET
+ ld_r1,r2,0
+ ld_r3,r2,8
+ ld_r0,r2,16
+ sari_r3,r3,3
+ addi_r1,r1,neg3
+ addi_r1,r1,8
+ shli_r3,r3,3
+ mov_r2,r3 ## stage idx*8 in r2
+ add_r1,r1,r2
+ st_r0,r1,0
+ li_r0 UNSPEC
+ ret
## ---- (vector-length v) — fixnum slot count -------------------------
:prim_vector_length
- P1_LD_R1_R2_0
- P1_ADDI_R1_R1_NEG3
- P1_LD_R0_R1_0
- P1_SHLI_R0_R0_16
- P1_SHRI_R0_R0_16
- P1_SHLI_R0_R0_3
- P1_ORI_R0_R0_1
- P1_RET
+ ld_r1,r2,0
+ addi_r1,r1,neg3
+ ld_r0,r1,0
+ shli_r0,r0,16
+ shri_r0,r0,16
+ shli_r0,r0,3
+ ori_r0,r0,1
+ ret
## ---- (vector->list v) — cons-snake from tail to head ---------------
## Walks slots end → base, pushing each onto an accumulator. Result
## order matches slot order.
:prim_vector_to_list
- P1_PROLOGUE_N4
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
-
- P1_LD_R0_R2_0 ## tagged vec
- P1_ADDI_R0_R0_NEG3 ## raw
- P1_LD_R3_R0_0
- P1_SHLI_R3_R3_16
- P1_SHRI_R3_R3_16 ## len
- P1_ADDI_R0_R0_8 ## payload base
- P1_SHLI_R1_R3_3
- P1_MOV_R2_R0 ## r2 = payload base
- P1_ADD_R6_R1_R2 ## r6 = end cursor = base + len*8
-
- P1_MOV_R3_SP
- P1_ST_R0_R3_24 ## slot3 = base ptr
-
- P1_LI_R7
- NIL ## acc
+ prologue_n4
+ st_r6,sp,8
+ st_r7,sp,16
+
+ ld_r0,r2,0 ## tagged vec
+ addi_r0,r0,neg3 ## raw
+ ld_r3,r0,0
+ shli_r3,r3,16
+ shri_r3,r3,16 ## len
+ addi_r0,r0,8 ## payload base
+ shli_r1,r3,3
+ mov_r2,r0 ## r2 = payload base
+ add_r6,r1,r2 ## r6 = end cursor = base + len*8
+
+ mov_r3,sp
+ st_r0,r3,24 ## slot3 = base ptr
+
+ li_r7 NIL ## acc
:pvtl_loop
- P1_MOV_R3_SP
- P1_LD_R0_R3_24
- P1_LI_BR
- &pvtl_done
- P1_BEQ_R6_R0
-
- P1_ADDI_R6_R6_NEG8
- P1_LD_R1_R6_0 ## element
- P1_MOV_R2_R7 ## acc
- P1_LI_BR
- &cons
- P1_CALL
- P1_MOV_R7_R0
- P1_LI_BR
- &pvtl_loop
- P1_B
+ mov_r3,sp
+ ld_r0,r3,24
+ li_br &pvtl_done
+ beq_r6,r0
+
+ addi_r6,r6,neg8
+ ld_r1,r6,0 ## element
+ mov_r2,r7 ## acc
+ li_br &cons
+ call
+ mov_r7,r0
+ li_br &pvtl_loop
+ b
:pvtl_done
- P1_MOV_R0_R7
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N4
- P1_RET
+ mov_r0,r7
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n4
+ ret
## ---- (list->vector lst) — count then fill ---------------------------
:prim_list_to_vector
- P1_PROLOGUE_N4
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
+ prologue_n4
+ st_r6,sp,8
+ st_r7,sp,16
- P1_LD_R0_R2_0 ## tagged list
- P1_MOV_R3_SP
- P1_ST_R0_R3_24 ## slot3 = list head
+ ld_r0,r2,0 ## tagged list
+ mov_r3,sp
+ st_r0,r3,24 ## slot3 = list head
- P1_LI_R6
- %0 ## r6 = count
- P1_MOV_R7_R0 ## r7 = cursor
+ li_r6 %0 ## r6 = count
+ mov_r7,r0 ## r7 = cursor
:pltv_lp1
- P1_LI_R0
- NIL
- P1_LI_BR
- &pltv_done1
- P1_BEQ_R7_R0
- P1_ADDI_R0_R7_NEG2 ## raw pair
- P1_LD_R7_R0_8 ## next
- P1_ADDI_R6_R6_1
- P1_LI_BR
- &pltv_lp1
- P1_B
+ li_r0 NIL
+ li_br &pltv_done1
+ beq_r7,r0
+ addi_r0,r7,neg2 ## raw pair
+ ld_r7,r0,8 ## next
+ addi_r6,r6,1
+ li_br &pltv_lp1
+ b
:pltv_done1
- P1_MOV_R1_R6 ## raw len
- P1_LI_R2
- NIL
- P1_LI_BR
- &make_vector
- P1_CALL ## r0 = tagged vector
- P1_MOV_R3_SP
- P1_ST_R0_R3_32 ## slot4 = result
-
- P1_ADDI_R6_R0_NEG3
- P1_ADDI_R6_R6_8 ## r6 = payload cursor
- P1_LD_R7_R3_24 ## r7 = list cursor
+ mov_r1,r6 ## raw len
+ li_r2 NIL
+ li_br &make_vector
+ call ## r0 = tagged vector
+ mov_r3,sp
+ st_r0,r3,32 ## slot4 = result
+
+ addi_r6,r0,neg3
+ addi_r6,r6,8 ## r6 = payload cursor
+ ld_r7,r3,24 ## r7 = list cursor
:pltv_lp2
- P1_LI_R0
- NIL
- P1_LI_BR
- &pltv_done2
- P1_BEQ_R7_R0
- P1_ADDI_R0_R7_NEG2
- P1_LD_R1_R0_0 ## car
- P1_LD_R7_R0_8 ## next
- P1_ST_R1_R6_0
- P1_ADDI_R6_R6_8
- P1_LI_BR
- &pltv_lp2
- P1_B
+ li_r0 NIL
+ li_br &pltv_done2
+ beq_r7,r0
+ addi_r0,r7,neg2
+ ld_r1,r0,0 ## car
+ ld_r7,r0,8 ## next
+ st_r1,r6,0
+ addi_r6,r6,8
+ li_br &pltv_lp2
+ b
:pltv_done2
- P1_MOV_R3_SP
- P1_LD_R0_R3_32
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N4
- P1_RET
+ mov_r3,sp
+ ld_r0,r3,32
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n4
+ ret
## ---- (display x) — runtime printer (unspec result) ------------------
:prim_display
- P1_PROLOGUE
- P1_LD_R1_R2_0
- P1_LI_BR
- &display
- P1_CALL
- P1_LI_R0
- UNSPEC
- P1_EPILOGUE
- P1_RET
+ prologue
+ ld_r1,r2,0
+ li_br &display
+ call
+ li_r0 UNSPEC
+ epilogue
+ ret
## ---- (write x) — quoting printer ------------------------------------
:prim_write
- P1_PROLOGUE
- P1_LD_R1_R2_0
- P1_LI_BR
- &write
- P1_CALL
- P1_LI_R0
- UNSPEC
- P1_EPILOGUE
- P1_RET
+ prologue
+ ld_r1,r2,0
+ li_br &write
+ call
+ li_r0 UNSPEC
+ epilogue
+ ret
## ---- (newline) — emit '\n' -----------------------------------------
:prim_newline
- P1_PROLOGUE
- P1_LI_R1
- %10
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_R0
- UNSPEC
- P1_EPILOGUE
- P1_RET
+ prologue
+ li_r1 %10
+ li_br &putc
+ call
+ li_r0 UNSPEC
+ epilogue
+ ret
## ---- (format fmt args...) — minimal printf-ish ---------------------
@@ -4466,278 +3620,223 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## ~% (newline), ~~ (literal '~'). Unknown directives consume their char
## silently. argv is &prim_argv; arg_index counts past the fmt string.
:prim_format
- P1_PROLOGUE_N4
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
-
- P1_MOV_R3_SP
- P1_ST_R1_R3_24 ## slot3 = argc
- P1_LI_R0
- %1
- P1_ST_R0_R3_32 ## slot4 = arg_index (skip fmt)
-
- P1_LD_R0_R2_0 ## tagged fmt string
- P1_ADDI_R0_R0_NEG4
- P1_LD_R7_R0_0
- P1_SHLI_R7_R7_16
- P1_SHRI_R7_R7_16 ## r7 = len
- P1_ADDI_R6_R0_8 ## r6 = cursor
+ prologue_n4
+ st_r6,sp,8
+ st_r7,sp,16
+
+ mov_r3,sp
+ st_r1,r3,24 ## slot3 = argc
+ li_r0 %1
+ st_r0,r3,32 ## slot4 = arg_index (skip fmt)
+
+ ld_r0,r2,0 ## tagged fmt string
+ addi_r0,r0,neg4
+ ld_r7,r0,0
+ shli_r7,r7,16
+ shri_r7,r7,16 ## r7 = len
+ addi_r6,r0,8 ## r6 = cursor
:pf_loop
- P1_LI_BR
- &pf_done
- P1_BEQZ_R7
-
- P1_LB_R0_R6_0
- P1_LI_R1
- %126 ## '~'
- P1_LI_BR
- &pf_directive
- P1_BEQ_R0_R1
-
- P1_MOV_R1_R0
- P1_LI_BR
- &putc
- P1_CALL
- P1_ADDI_R6_R6_1
- P1_ADDI_R7_R7_NEG1
- P1_LI_BR
- &pf_loop
- P1_B
+ li_br &pf_done
+ beqz_r7
+
+ lb_r0,r6,0
+ li_r1 %126 ## '~'
+ li_br &pf_directive
+ beq_r0,r1
+
+ mov_r1,r0
+ li_br &putc
+ call
+ addi_r6,r6,1
+ addi_r7,r7,neg1
+ li_br &pf_loop
+ b
:pf_directive
- P1_ADDI_R6_R6_1
- P1_ADDI_R7_R7_NEG1
- P1_LI_BR
- &pf_done
- P1_BEQZ_R7
-
- P1_LB_R0_R6_0
- P1_ADDI_R6_R6_1
- P1_ADDI_R7_R7_NEG1
-
- P1_LI_R1
- %37 ## '%'
- P1_LI_BR
- &pf_newline
- P1_BEQ_R0_R1
-
- P1_LI_R1
- %126 ## '~'
- P1_LI_BR
- &pf_emit_tilde
- P1_BEQ_R0_R1
+ addi_r6,r6,1
+ addi_r7,r7,neg1
+ li_br &pf_done
+ beqz_r7
+
+ lb_r0,r6,0
+ addi_r6,r6,1
+ addi_r7,r7,neg1
+
+ li_r1 %37 ## '%'
+ li_br &pf_newline
+ beq_r0,r1
+
+ li_r1 %126 ## '~'
+ li_br &pf_emit_tilde
+ beq_r0,r1
## a/s/d — fetch arg
- P1_LI_R1
- &prim_argv
- P1_MOV_R3_SP
- P1_LD_R2_R3_32
- P1_SHLI_R2_R2_3
- P1_ADD_R1_R1_R2
- P1_LD_R1_R1_0 ## r1 = tagged arg
- P1_LD_R2_R3_32
- P1_ADDI_R2_R2_1
- P1_ST_R2_R3_32
-
- P1_LI_R2
- %97 ## 'a'
- P1_LI_BR
- &pf_dir_a
- P1_BEQ_R0_R2
- P1_LI_R2
- %115 ## 's'
- P1_LI_BR
- &pf_dir_s
- P1_BEQ_R0_R2
- P1_LI_R2
- %100 ## 'd'
- P1_LI_BR
- &pf_dir_d
- P1_BEQ_R0_R2
-
- P1_LI_BR
- &pf_loop
- P1_B
+ li_r1 &prim_argv
+ mov_r3,sp
+ ld_r2,r3,32
+ shli_r2,r2,3
+ add_r1,r1,r2
+ ld_r1,r1,0 ## r1 = tagged arg
+ ld_r2,r3,32
+ addi_r2,r2,1
+ st_r2,r3,32
+
+ li_r2 %97 ## 'a'
+ li_br &pf_dir_a
+ beq_r0,r2
+ li_r2 %115 ## 's'
+ li_br &pf_dir_s
+ beq_r0,r2
+ li_r2 %100 ## 'd'
+ li_br &pf_dir_d
+ beq_r0,r2
+
+ li_br &pf_loop
+ b
:pf_dir_a
- P1_LI_BR
- &display
- P1_CALL
- P1_LI_BR
- &pf_loop
- P1_B
+ li_br &display
+ call
+ li_br &pf_loop
+ b
:pf_dir_s
- P1_LI_BR
- &write
- P1_CALL
- P1_LI_BR
- &pf_loop
- P1_B
+ li_br &write
+ call
+ li_br &pf_loop
+ b
:pf_dir_d
- P1_SARI_R1_R1_3
- P1_LI_R2
- %1 ## fd = 1 (stdout)
- P1_LI_BR
- &display_uint
- P1_CALL
- P1_LI_BR
- &pf_loop
- P1_B
+ sari_r1,r1,3
+ li_r2 %1 ## fd = 1 (stdout)
+ li_br &display_uint
+ call
+ li_br &pf_loop
+ b
:pf_newline
- P1_LI_R1
- %10
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_BR
- &pf_loop
- P1_B
+ li_r1 %10
+ li_br &putc
+ call
+ li_br &pf_loop
+ b
:pf_emit_tilde
- P1_LI_R1
- %126
- P1_LI_BR
- &putc
- P1_CALL
- P1_LI_BR
- &pf_loop
- P1_B
+ li_r1 %126
+ li_br &putc
+ call
+ li_br &pf_loop
+ b
:pf_done
- P1_LI_R0
- UNSPEC
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N4
- P1_RET
+ li_r0 UNSPEC
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n4
+ ret
## ---- (error msg) — print and exit(1) -------------------------------
:prim_error
- P1_LD_R0_R2_0
- P1_ADDI_R0_R0_NEG4
- P1_LD_R2_R0_0
- P1_SHLI_R2_R2_16
- P1_SHRI_R2_R2_16
- P1_ADDI_R1_R0_8
- P1_LI_BR
- &error
- P1_B
+ ld_r0,r2,0
+ addi_r0,r0,neg4
+ ld_r2,r0,0
+ shli_r2,r2,16
+ shri_r2,r2,16
+ addi_r1,r0,8
+ li_br &error
+ b
## ---- (read-file path) — slurp into a fresh string ------------------
## Uses io_buf as scratch (512B); make_string copies into the heap.
:prim_read_file
- P1_PROLOGUE_N3
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
-
- P1_LD_R1_R2_0
- P1_LI_BR
- &string_to_c_path
- P1_CALL ## r0 = &path_buf
-
- P1_MOV_R2_R0
- P1_LI_R0
- SYS_OPENAT
- P1_LI_R1
- %-100
- P1_LI_R3
- %0
- P1_LI_R4
- %0
- P1_SYSCALL ## r0 = fd or err
-
- P1_LI_BR
- &err_open
- P1_BLTZ_R0
-
- P1_MOV_R6_R0 ## r6 = fd
-
- P1_MOV_R1_R6
- P1_LI_R2
- &io_buf
- P1_LI_R3
- %512
- P1_LI_BR
- &read_file_all
- P1_CALL ## r0 = bytes_read
- P1_MOV_R7_R0
-
- P1_LI_R0
- SYS_CLOSE
- P1_MOV_R1_R6
- P1_SYSCALL
-
- P1_LI_R1
- &io_buf
- P1_MOV_R2_R7
- P1_LI_BR
- &make_string
- P1_CALL
-
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N3
- P1_RET
+ prologue_n3
+ st_r6,sp,8
+ st_r7,sp,16
+
+ ld_r1,r2,0
+ li_br &string_to_c_path
+ call ## r0 = &path_buf
+
+ mov_r2,r0
+ li_r0 sys_openat
+ li_r1 %-100
+ li_r3 %0
+ li_r4 %0
+ syscall ## r0 = fd or err
+
+ li_br &err_open
+ bltz_r0
+
+ mov_r6,r0 ## r6 = fd
+
+ mov_r1,r6
+ li_r2 &io_buf
+ li_r3 %512
+ li_br &read_file_all
+ call ## r0 = bytes_read
+ mov_r7,r0
+
+ li_r0 sys_close
+ mov_r1,r6
+ syscall
+
+ li_r1 &io_buf
+ mov_r2,r7
+ li_br &make_string
+ call
+
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n3
+ ret
## ---- (write-file path data) — overwrite/truncate ------------------
:prim_write_file
- P1_PROLOGUE_N3
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
-
- P1_LD_R7_R2_8 ## r7 = tagged data string
-
- P1_LD_R1_R2_0 ## tagged path
- P1_LI_BR
- &string_to_c_path
- P1_CALL ## r0 = &path_buf
-
- P1_MOV_R2_R0
- P1_LI_R0
- SYS_OPENAT
- P1_LI_R1
- %-100
- P1_LI_R3
- %577 ## O_WRONLY|O_CREAT|O_TRUNC
- P1_LI_R4
- %420 ## mode 0644
- P1_SYSCALL ## r0 = fd
-
- P1_LI_BR
- &err_open
- P1_BLTZ_R0
-
- P1_MOV_R6_R0 ## r6 = fd
-
- P1_MOV_R1_R7
- P1_ADDI_R1_R1_NEG4 ## raw header
- P1_LD_R3_R1_0
- P1_SHLI_R3_R3_16
- P1_SHRI_R3_R3_16 ## len
- P1_ADDI_R2_R1_8 ## payload
- P1_MOV_R1_R6 ## fd
- P1_LI_BR
- &write_file_all
- P1_CALL
-
- P1_LI_R0
- SYS_CLOSE
- P1_MOV_R1_R6
- P1_SYSCALL
-
- P1_LI_R0
- UNSPEC
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N3
- P1_RET
+ prologue_n3
+ st_r6,sp,8
+ st_r7,sp,16
+
+ ld_r7,r2,8 ## r7 = tagged data string
+
+ ld_r1,r2,0 ## tagged path
+ li_br &string_to_c_path
+ call ## r0 = &path_buf
+
+ mov_r2,r0
+ li_r0 sys_openat
+ li_r1 %-100
+ li_r3 %577 ## O_WRONLY|O_CREAT|O_TRUNC
+ li_r4 %420 ## mode 0644
+ syscall ## r0 = fd
+
+ li_br &err_open
+ bltz_r0
+
+ mov_r6,r0 ## r6 = fd
+
+ mov_r1,r7
+ addi_r1,r1,neg4 ## raw header
+ ld_r3,r1,0
+ shli_r3,r3,16
+ shri_r3,r3,16 ## len
+ addi_r2,r1,8 ## payload
+ mov_r1,r6 ## fd
+ li_br &write_file_all
+ call
+
+ li_r0 sys_close
+ mov_r1,r6
+ syscall
+
+ li_r0 UNSPEC
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n3
+ ret
## ---- equal_helper(r1=a, r2=b) -> r0 = 0|1 --------------------------
@@ -4746,239 +3845,206 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## Always saves r6/r7 (slot1/slot2); slot3/slot4 store tagged a/b for
## paths that need them across recursive calls.
:equal_helper
- P1_PROLOGUE_N4
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
-
- P1_LI_BR
- &eq_true
- P1_BEQ_R1_R2
-
- P1_MOV_R3_R1
- P1_ANDI_R3_R3_7
- P1_MOV_R0_R2
- P1_ANDI_R0_R0_7
- P1_LI_BR
- &eq_false
- P1_BNE_R3_R0
-
- P1_LI_R0
- TAG_PAIR
- P1_LI_BR
- &eq_pair
- P1_BEQ_R3_R0
- P1_LI_R0
- TAG_STRING
- P1_LI_BR
- &eq_string
- P1_BEQ_R3_R0
- P1_LI_R0
- TAG_VECTOR
- P1_LI_BR
- &eq_vector
- P1_BEQ_R3_R0
+ prologue_n4
+ st_r6,sp,8
+ st_r7,sp,16
+
+ li_br &eq_true
+ beq_r1,r2
+
+ mov_r3,r1
+ andi_r3,r3,7
+ mov_r0,r2
+ andi_r0,r0,7
+ li_br &eq_false
+ bne_r3,r0
+
+ li_r0 TAG_PAIR
+ li_br &eq_pair
+ beq_r3,r0
+ li_r0 TAG_STRING
+ li_br &eq_string
+ beq_r3,r0
+ li_r0 TAG_VECTOR
+ li_br &eq_vector
+ beq_r3,r0
:eq_false
- P1_LI_R0
- %0
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N4
- P1_RET
+ li_r0 %0
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n4
+ ret
:eq_true
- P1_LI_R0
- %1
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N4
- P1_RET
+ li_r0 %1
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n4
+ ret
:eq_pair
- P1_ST_R1_SP_24 ## slot3 = tagged a
- P1_ST_R2_SP_32 ## slot4 = tagged b
-
- P1_ADDI_R0_R1_NEG2
- P1_LD_R1_R0_0 ## a.car
- P1_ADDI_R0_R2_NEG2
- P1_LD_R2_R0_0 ## b.car
-
- P1_LI_BR
- &equal_helper
- P1_CALL
- P1_LI_BR
- &eq_false
- P1_BEQZ_R0
-
- P1_MOV_R3_SP
- P1_LD_R0_R3_24
- P1_ADDI_R0_R0_NEG2
- P1_LD_R1_R0_8 ## a.cdr
- P1_LD_R0_R3_32
- P1_ADDI_R0_R0_NEG2
- P1_LD_R2_R0_8 ## b.cdr
- P1_LI_BR
- &equal_helper
- P1_CALL
-
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N4
- P1_RET
+ st_r1,sp,24 ## slot3 = tagged a
+ st_r2,sp,32 ## slot4 = tagged b
+
+ addi_r0,r1,neg2
+ ld_r1,r0,0 ## a.car
+ addi_r0,r2,neg2
+ ld_r2,r0,0 ## b.car
+
+ li_br &equal_helper
+ call
+ li_br &eq_false
+ beqz_r0
+
+ mov_r3,sp
+ ld_r0,r3,24
+ addi_r0,r0,neg2
+ ld_r1,r0,8 ## a.cdr
+ ld_r0,r3,32
+ addi_r0,r0,neg2
+ ld_r2,r0,8 ## b.cdr
+ li_br &equal_helper
+ call
+
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n4
+ ret
:eq_string
- P1_ADDI_R1_R1_NEG4
- P1_ADDI_R2_R2_NEG4
- P1_LD_R3_R1_0
- P1_SHLI_R3_R3_16
- P1_SHRI_R3_R3_16 ## len_a
- P1_LD_R0_R2_0
- P1_SHLI_R0_R0_16
- P1_SHRI_R0_R0_16 ## len_b
- P1_LI_BR
- &eq_false
- P1_BNE_R3_R0
-
- P1_ADDI_R6_R1_8 ## a payload cursor
- P1_ADDI_R7_R2_8 ## b payload cursor
+ addi_r1,r1,neg4
+ addi_r2,r2,neg4
+ ld_r3,r1,0
+ shli_r3,r3,16
+ shri_r3,r3,16 ## len_a
+ ld_r0,r2,0
+ shli_r0,r0,16
+ shri_r0,r0,16 ## len_b
+ li_br &eq_false
+ bne_r3,r0
+
+ addi_r6,r1,8 ## a payload cursor
+ addi_r7,r2,8 ## b payload cursor
:eq_string_loop
- P1_LI_BR
- &eq_true
- P1_BEQZ_R3
- P1_LB_R0_R6_0
- P1_LB_R1_R7_0
- P1_LI_BR
- &eq_false
- P1_BNE_R0_R1
- P1_ADDI_R6_R6_1
- P1_ADDI_R7_R7_1
- P1_ADDI_R3_R3_NEG1
- P1_LI_BR
- &eq_string_loop
- P1_B
+ li_br &eq_true
+ beqz_r3
+ lb_r0,r6,0
+ lb_r1,r7,0
+ li_br &eq_false
+ bne_r0,r1
+ addi_r6,r6,1
+ addi_r7,r7,1
+ addi_r3,r3,neg1
+ li_br &eq_string_loop
+ b
:eq_vector
- P1_ADDI_R1_R1_NEG3
- P1_ADDI_R2_R2_NEG3
- P1_LD_R3_R1_0
- P1_SHLI_R3_R3_16
- P1_SHRI_R3_R3_16 ## len_a
- P1_LD_R0_R2_0
- P1_SHLI_R0_R0_16
- P1_SHRI_R0_R0_16 ## len_b
- P1_LI_BR
- &eq_false
- P1_BNE_R3_R0
-
- P1_ADDI_R6_R1_8 ## a payload cursor
- P1_ADDI_R7_R2_8 ## b payload cursor
+ addi_r1,r1,neg3
+ addi_r2,r2,neg3
+ ld_r3,r1,0
+ shli_r3,r3,16
+ shri_r3,r3,16 ## len_a
+ ld_r0,r2,0
+ shli_r0,r0,16
+ shri_r0,r0,16 ## len_b
+ li_br &eq_false
+ bne_r3,r0
+
+ addi_r6,r1,8 ## a payload cursor
+ addi_r7,r2,8 ## b payload cursor
:eq_vector_loop
- P1_LI_BR
- &eq_true
- P1_BEQZ_R3
-
- P1_LD_R1_R6_0
- P1_LD_R2_R7_0
- P1_ST_R3_SP_24 ## save remaining count
-
- P1_LI_BR
- &equal_helper
- P1_CALL
- P1_LI_BR
- &eq_false
- P1_BEQZ_R0
-
- P1_MOV_R3_SP
- P1_LD_R3_R3_24
- P1_ADDI_R6_R6_8
- P1_ADDI_R7_R7_8
- P1_ADDI_R3_R3_NEG1
- P1_LI_BR
- &eq_vector_loop
- P1_B
+ li_br &eq_true
+ beqz_r3
+
+ ld_r1,r6,0
+ ld_r2,r7,0
+ st_r3,sp,24 ## save remaining count
+
+ li_br &equal_helper
+ call
+ li_br &eq_false
+ beqz_r0
+
+ mov_r3,sp
+ ld_r3,r3,24
+ addi_r6,r6,8
+ addi_r7,r7,8
+ addi_r3,r3,neg1
+ li_br &eq_vector_loop
+ b
## ---- (equal? a b) — wraps equal_helper ----------------------------
:prim_equal
- P1_PROLOGUE
- P1_LD_R1_R2_0
- P1_LD_R2_R2_8
- P1_LI_BR
- &equal_helper
- P1_CALL
-
- P1_LI_BR
- &peq_true
- P1_BNEZ_R0
- P1_LI_R0
- FALSE
- P1_EPILOGUE
- P1_RET
+ prologue
+ ld_r1,r2,0
+ ld_r2,r2,8
+ li_br &equal_helper
+ call
+
+ li_br &peq_true
+ bnez_r0
+ li_r0 FALSE
+ epilogue
+ ret
:peq_true
- P1_LI_R0
- TRUE
- P1_EPILOGUE
- P1_RET
+ li_r0 TRUE
+ epilogue
+ ret
## ---- (apply proc arg ... last-list) ---------------------------------
## argc >= 2. Build args = (arg1 ... arg{n-1} ++ last-list), then call
## the C-level apply with (callee, args).
:prim_apply
- P1_PROLOGUE_N4
- P1_ST_R6_SP_8
- P1_ST_R7_SP_16
+ prologue_n4
+ st_r6,sp,8
+ st_r7,sp,16
- P1_LD_R6_R2_0 ## r6 = callee
+ ld_r6,r2,0 ## r6 = callee
## acc = argv[argc-1] (the trailing list)
- P1_ADDI_R3_R1_NEG1
- P1_SHLI_R0_R3_3
- P1_LI_R7
- &prim_argv
- P1_ADD_R7_R7_R0
- P1_LD_R7_R7_0 ## r7 = acc
-
- P1_ADDI_R3_R1_NEG2 ## i = argc - 2
+ addi_r3,r1,neg1
+ shli_r0,r3,3
+ li_r7 &prim_argv
+ add_r7,r7,r0
+ ld_r7,r7,0 ## r7 = acc
+
+ addi_r3,r1,neg2 ## i = argc - 2
:papply_lp
- P1_LI_R0
- %1
- P1_LI_BR
- &papply_done
- P1_BLT_R3_R0 ## i < 1 → done
-
- P1_SHLI_R0_R3_3
- P1_LI_R1
- &prim_argv
- P1_ADD_R1_R1_R0
- P1_LD_R1_R1_0 ## r1 = arg
-
- P1_ST_R3_SP_24 ## save i
-
- P1_MOV_R2_R7
- P1_LI_BR
- &cons
- P1_CALL ## r0 = (arg . acc)
- P1_MOV_R7_R0
-
- P1_MOV_R3_SP
- P1_LD_R3_R3_24
- P1_ADDI_R3_R3_NEG1
- P1_LI_BR
- &papply_lp
- P1_B
+ li_r0 %1
+ li_br &papply_done
+ blt_r3,r0 ## i < 1 → done
+
+ shli_r0,r3,3
+ li_r1 &prim_argv
+ add_r1,r1,r0
+ ld_r1,r1,0 ## r1 = arg
+
+ st_r3,sp,24 ## save i
+
+ mov_r2,r7
+ li_br &cons
+ call ## r0 = (arg . acc)
+ mov_r7,r0
+
+ mov_r3,sp
+ ld_r3,r3,24
+ addi_r3,r3,neg1
+ li_br &papply_lp
+ b
:papply_done
- P1_MOV_R1_R6
- P1_MOV_R2_R7
- P1_LI_BR
- &apply
- P1_CALL
+ mov_r1,r6
+ mov_r2,r7
+ li_br &apply
+ call
- P1_LD_R6_SP_8
- P1_LD_R7_SP_16
- P1_EPILOGUE_N4
- P1_RET
+ ld_r6,sp,8
+ ld_r7,sp,16
+ epilogue_n4
+ ret
@@ -4986,196 +4052,157 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## Self-evaluating: nil/fixnum/string/closure. Symbols → lookup. Pairs
## → eval_pair (special-form or application dispatch).
:eval
- P1_PROLOGUE_N3
- P1_MOV_R3_SP
- P1_ST_R1_SP_8 ## slot 1 = expr
- P1_ST_R2_SP_16 ## slot 2 = env
-
- P1_LI_R2
- %7
- P1_LI_BR
- &eval_self_slot1
- P1_BEQ_R1_R2
-
- P1_ANDI_R1_R1_7 ## r1 = tag
-
- P1_LI_R2
- %1
- P1_LI_BR
- &eval_self_slot1
- P1_BEQ_R1_R2 ## fixnum
-
- P1_LI_R2
- %5
- P1_LI_BR
- &eval_sym
- P1_BEQ_R1_R2
-
- P1_LI_R2
- %2
- P1_LI_BR
- &eval_pair
- P1_BEQ_R1_R2
+ prologue_n3
+ mov_r3,sp
+ st_r1,sp,8 ## slot 1 = expr
+ st_r2,sp,16 ## slot 2 = env
+
+ li_r2 %7
+ li_br &eval_self_slot1
+ beq_r1,r2
+
+ andi_r1,r1,7 ## r1 = tag
+
+ li_r2 %1
+ li_br &eval_self_slot1
+ beq_r1,r2 ## fixnum
+
+ li_r2 %5
+ li_br &eval_sym
+ beq_r1,r2
+
+ li_r2 %2
+ li_br &eval_pair
+ beq_r1,r2
## Other tags (string, closure) self-evaluate.
- P1_LI_BR
- &eval_self_slot1
- P1_B
+ li_br &eval_self_slot1
+ b
:eval_self_slot1
- P1_LD_R0_SP_8
- P1_EPILOGUE_N3
- P1_RET
+ ld_r0,sp,8
+ epilogue_n3
+ ret
:eval_sym
- P1_LD_R1_SP_8
- P1_LD_R2_SP_16
- P1_LI_BR
- &lookup
- P1_TAIL_N3
+ ld_r1,sp,8
+ ld_r2,sp,16
+ li_br &lookup
+ tail_n3
:eval_pair
## Compound expression. Dispatch on car against cached sym_*
## pointers; otherwise treat as function application.
- P1_LD_R1_SP_8
- P1_LI_BR
- &car
- P1_CALL ## r0 = callee-expr
-
- P1_LI_R1
- &sym_quote
- P1_LD_R1_R1_0
- P1_LI_BR
- &eval_quote
- P1_BEQ_R0_R1
-
- P1_LI_R1
- &sym_if
- P1_LD_R1_R1_0
- P1_LI_BR
- &eval_if
- P1_BEQ_R0_R1
-
- P1_LI_R1
- &sym_begin
- P1_LD_R1_R1_0
- P1_LI_BR
- &eval_begin
- P1_BEQ_R0_R1
-
- P1_LI_R1
- &sym_lambda
- P1_LD_R1_R1_0
- P1_LI_BR
- &eval_lambda
- P1_BEQ_R0_R1
-
- P1_LI_R1
- &sym_define
- P1_LD_R1_R1_0
- P1_LI_BR
- &eval_define
- P1_BEQ_R0_R1
+ ld_r1,sp,8
+ li_br &car
+ call ## r0 = callee-expr
+
+ li_r1 &sym_quote
+ ld_r1,r1,0
+ li_br &eval_quote
+ beq_r0,r1
+
+ li_r1 &sym_if
+ ld_r1,r1,0
+ li_br &eval_if
+ beq_r0,r1
+
+ li_r1 &sym_begin
+ ld_r1,r1,0
+ li_br &eval_begin
+ beq_r0,r1
+
+ li_r1 &sym_lambda
+ ld_r1,r1,0
+ li_br &eval_lambda
+ beq_r0,r1
+
+ li_r1 &sym_define
+ ld_r1,r1,0
+ li_br &eval_define
+ beq_r0,r1
## Application: callee = eval(callee-expr, env)
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval
- P1_CALL ## r0 = callee value
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval
+ call ## r0 = callee value
- P1_ST_R0_SP_24 ## slot 3 = callee
+ st_r0,sp,24 ## slot 3 = callee
## args = eval_args(cdr(expr), env)
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval_args
- P1_CALL ## r0 = args list
-
- P1_MOV_R2_R0
- P1_LD_R1_SP_24
- P1_LI_BR
- &apply
- P1_TAIL_N3 ## Scheme tail call: application
+ ld_r1,sp,8
+ li_br &cdr
+ call
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval_args
+ call ## r0 = args list
+
+ mov_r2,r0
+ ld_r1,sp,24
+ li_br &apply
+ tail_n3 ## Scheme tail call: application
## ---- eval_quote / eval_if / eval_begin -----------------------------
## All run inside eval's PROLOGUE_N3 frame: slot 1 = expr, slot 2 =
## env, slot 3 = per-form scratch.
:eval_quote
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = (x)
- P1_MOV_R1_R0
- P1_LI_BR
- &car ## tail: r0 = x
- P1_TAIL_N3
+ ld_r1,sp,8
+ li_br &cdr
+ call ## r0 = (x)
+ mov_r1,r0
+ li_br &car ## tail: r0 = x
+ tail_n3
:eval_if
## (if cond then else). Save (then else) tail into slot 3, eval
## cond, branch to the correct arm.
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = (cond then else)
- P1_MOV_R1_R0
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = (then else)
- P1_ST_R0_SP_24
-
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = (cond then else)
- P1_MOV_R1_R0
- P1_LI_BR
- &car
- P1_CALL ## r0 = cond expr
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval
- P1_CALL ## r0 = cond value
-
- P1_LI_R1
- %7
- P1_LI_BR
- &eval_if_else
- P1_BEQ_R0_R1
+ ld_r1,sp,8
+ li_br &cdr
+ call ## r0 = (cond then else)
+ mov_r1,r0
+ li_br &cdr
+ call ## r0 = (then else)
+ st_r0,sp,24
+
+ ld_r1,sp,8
+ li_br &cdr
+ call ## r0 = (cond then else)
+ mov_r1,r0
+ li_br &car
+ call ## r0 = cond expr
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval
+ call ## r0 = cond value
+
+ li_r1 %7
+ li_br &eval_if_else
+ beq_r0,r1
## Then branch: eval car(slot3)
- P1_LD_R1_SP_24
- P1_LI_BR
- &car
- P1_CALL
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval ## Scheme tail: then-branch
- P1_TAIL_N3
+ ld_r1,sp,24
+ li_br &car
+ call
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval ## Scheme tail: then-branch
+ tail_n3
:eval_if_else
## Else branch: eval car(cdr(slot3))
- P1_LD_R1_SP_24
- P1_LI_BR
- &cdr
- P1_CALL
- P1_MOV_R1_R0
- P1_LI_BR
- &car
- P1_CALL
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval ## Scheme tail: else-branch
- P1_TAIL_N3
+ ld_r1,sp,24
+ li_br &cdr
+ call
+ mov_r1,r0
+ li_br &car
+ call
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval ## Scheme tail: else-branch
+ tail_n3
:eval_begin
## (begin e1 e2 ... en). Slot 1 = cursor over the body list. The
@@ -5183,389 +4210,262 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## cdr(cursor): nil next → TAIL eval the current head; otherwise
## CALL eval and advance. Slot 3 bridges the saved next-cursor
## across the CALL eval in the non-tail branch.
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = body list
- P1_MOV_R3_SP
- P1_ST_R0_SP_8 ## slot 1 := cursor
+ ld_r1,sp,8
+ li_br &cdr
+ call ## r0 = body list
+ mov_r3,sp
+ st_r0,sp,8 ## slot 1 := cursor
:eval_begin_loop
- P1_MOV_R3_SP
- P1_LD_R1_SP_8
- P1_LI_R2
- %7
- P1_LI_BR
- &eval_begin_empty
- P1_BEQ_R1_R2 ## cursor == nil → empty begin → nil
+ mov_r3,sp
+ ld_r1,sp,8
+ li_r2 %7
+ li_br &eval_begin_empty
+ beq_r1,r2 ## cursor == nil → empty begin → nil
## next = cdr(cursor)
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = next
+ li_br &cdr
+ call ## r0 = next
- P1_LI_R1
- %7
- P1_LI_BR
- &eval_begin_tail
- P1_BEQ_R0_R1 ## next == nil → tail-eval last form
+ li_r1 %7
+ li_br &eval_begin_tail
+ beq_r0,r1 ## next == nil → tail-eval last form
## Non-tail: stash next in slot 3, CALL eval(car(cursor), env),
## discard result, advance cursor := next.
- P1_ST_R0_SP_24 ## slot 3 := next
- P1_LD_R1_SP_8
- P1_LI_BR
- &car
- P1_CALL
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval
- P1_CALL
-
- P1_LD_R0_SP_24
- P1_ST_R0_SP_8 ## cursor := next
- P1_LI_BR
- &eval_begin_loop
- P1_B
+ st_r0,sp,24 ## slot 3 := next
+ ld_r1,sp,8
+ li_br &car
+ call
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval
+ call
+
+ ld_r0,sp,24
+ st_r0,sp,8 ## cursor := next
+ li_br &eval_begin_loop
+ b
:eval_begin_tail
## Scheme tail: TAIL eval(car(cursor), env). Frame torn down.
- P1_LD_R1_SP_8
- P1_LI_BR
- &car
- P1_CALL ## r0 = head expr
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval
- P1_TAIL_N3
+ ld_r1,sp,8
+ li_br &car
+ call ## r0 = head expr
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval
+ tail_n3
:eval_begin_empty
- P1_LI_R0
- %7
- P1_EPILOGUE_N3
- P1_RET
+ li_r0 %7
+ epilogue_n3
+ ret
:eval_lambda
## (lambda params body). Slot 1 gets repurposed to hold params
## once we no longer need the original expr.
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = (params body)
- P1_ST_R0_SP_24 ## slot 3 = (params body)
-
- P1_MOV_R1_R0
- P1_LI_BR
- &car
- P1_CALL ## r0 = params
- P1_ST_R0_SP_8 ## slot 1 := params
-
- P1_LD_R1_SP_24
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = (body)
- P1_MOV_R1_R0
- P1_LI_BR
- &car
- P1_CALL ## r0 = body
-
- P1_MOV_R2_R0
- P1_LD_R1_SP_8 ## r1 = params
- P1_LD_R3_SP_16 ## r3 = env
- P1_LI_BR
- &make_closure ## tail: no Scheme-visible work after
- P1_TAIL_N3
+ ld_r1,sp,8
+ li_br &cdr
+ call ## r0 = (params body)
+ st_r0,sp,24 ## slot 3 = (params body)
+
+ mov_r1,r0
+ li_br &car
+ call ## r0 = params
+ st_r0,sp,8 ## slot 1 := params
+
+ ld_r1,sp,24
+ li_br &cdr
+ call ## r0 = (body)
+ mov_r1,r0
+ li_br &car
+ call ## r0 = body
+
+ mov_r2,r0
+ ld_r1,sp,8 ## r1 = params
+ ld_r3,sp,16 ## r3 = env
+ li_br &make_closure ## tail: no Scheme-visible work after
+ tail_n3
:eval_define
## (define sym val-expr). gset-binds the evaluated val into the
## global alist, returns nil.
- P1_LD_R1_SP_8
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = (sym val-expr)
- P1_ST_R0_SP_24 ## slot 3 := (sym val-expr)
-
- P1_MOV_R1_R0
- P1_LI_BR
- &car
- P1_CALL ## r0 = sym
- P1_ST_R0_SP_8 ## slot 1 := sym
-
- P1_LD_R1_SP_24
- P1_LI_BR
- &cdr
- P1_CALL ## r0 = (val-expr)
- P1_MOV_R1_R0
- P1_LI_BR
- &car
- P1_CALL ## r0 = val-expr
- P1_MOV_R1_R0
- P1_LD_R2_SP_16
- P1_LI_BR
- &eval
- P1_CALL ## r0 = val
-
- P1_MOV_R2_R0
- P1_LD_R1_SP_8
- P1_LI_BR
- &gset
- P1_CALL
-
- P1_LI_R0
- %7
- P1_EPILOGUE_N3
- P1_RET
+ ld_r1,sp,8
+ li_br &cdr
+ call ## r0 = (sym val-expr)
+ st_r0,sp,24 ## slot 3 := (sym val-expr)
+
+ mov_r1,r0
+ li_br &car
+ call ## r0 = sym
+ st_r0,sp,8 ## slot 1 := sym
+
+ ld_r1,sp,24
+ li_br &cdr
+ call ## r0 = (val-expr)
+ mov_r1,r0
+ li_br &car
+ call ## r0 = val-expr
+ mov_r1,r0
+ ld_r2,sp,16
+ li_br &eval
+ call ## r0 = val
+
+ mov_r2,r0
+ ld_r1,sp,8
+ li_br &gset
+ call
+
+ li_r0 %7
+ epilogue_n3
+ ret
## ---- Step-6 error landing pads --------------------------------------
:err_unbound
- P1_LI_R1
- &msg_unbound
- P1_LI_R2
- %14 ## strlen("unbound symbol") == 14
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_unbound
+ li_r2 %14 ## strlen("unbound symbol") == 14
+ li_br &error
+ b
:err_arity
- P1_LI_R1
- &msg_arity
- P1_LI_R2
- %14 ## strlen("arity mismatch") == 14
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_arity
+ li_r2 %14 ## strlen("arity mismatch") == 14
+ li_br &error
+ b
:err_not_callable
- P1_LI_R1
- &msg_not_callable
- P1_LI_R2
- %12 ## strlen("not callable") == 12
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_not_callable
+ li_r2 %12 ## strlen("not callable") == 12
+ li_br &error
+ b
:err_too_many_args
- P1_LI_R1
- &msg_too_many_args
- P1_LI_R2
- %21 ## strlen("primitive argc > 32") == 21
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_too_many_args
+ li_r2 %21 ## strlen("primitive argc > 32") == 21
+ li_br &error
+ b
:err_bad_prim
- P1_LI_R1
- &msg_bad_prim
- P1_LI_R2
- %20 ## strlen("unknown primitive id") == 20
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_bad_prim
+ li_r2 %20 ## strlen("unknown primitive id") == 20
+ li_br &error
+ b
:err_path_too_long
- P1_LI_R1
- &msg_path_too_long
- P1_LI_R2
- %18
- P1_LI_BR
- &error
- P1_B
+ li_r1 &msg_path_too_long
+ li_r2 %18
+ li_br &error
+ b
## ---- Static strings -------------------------------------------------
-:msg_error_prefix
-"error: "
:msg_newline
"
"
-:msg_oom
-"heap exhausted"
-:msg_intern_not_eq
-"intern: foo a != foo b (same name)"
-:msg_intern_collision
-"intern: foo == bar (distinct names collided)"
-:msg_reader_bad
-"reader: malformed input"
-:msg_at
-" at "
-:msg_colon
-":"
-:msg_unbound
-"unbound symbol"
-:msg_arity
-"arity mismatch"
-:msg_not_callable
-"not callable"
-:msg_usage
-"usage: lisp <file.scm>"
-:msg_open_fail
-"failed to open source file"
-:msg_src_too_big
-"source file too large"
-:msg_too_many_args
-"primitive argc > 32"
-:msg_bad_prim
-"unknown primitive id"
-:msg_path_too_long
-"file path too long"
+:msg_error_prefix "error: "
+:msg_oom "heap exhausted"
+:msg_intern_not_eq "intern: foo a != foo b (same name)"
+:msg_intern_collision "intern: foo == bar (distinct names collided)"
+:msg_reader_bad "reader: malformed input"
+:msg_at " at "
+:msg_colon ":"
+:msg_unbound "unbound symbol"
+:msg_arity "arity mismatch"
+:msg_not_callable "not callable"
+:msg_usage "usage: lisp <file.scm>"
+:msg_open_fail "failed to open source file"
+:msg_src_too_big "source file too large"
+:msg_too_many_args "primitive argc > 32"
+:msg_bad_prim "unknown primitive id"
+:msg_path_too_long "file path too long"
## Interned name samples used by the self-test.
-:str_foo
-"foo"
-:str_bar
-"bar"
+:str_foo "foo"
+:str_bar "bar"
## Special-form name strings. Lengths are baked into _start's intern
## calls (update both sides together).
-:str_quote
-"quote"
-:str_if
-"if"
-:str_begin
-"begin"
-:str_lambda
-"lambda"
-:str_define
-"define"
-
+:str_quote "quote"
+:str_if "if"
+:str_begin "begin"
+:str_lambda "lambda"
+:str_define "define"
## Primitive name strings (step 10b). The registration table below
## holds (ptr, len, code_id, type, arity) for each. _start walks the
## table, interns each name, and binds a freshly-built primitive into
## global_env.
-:str_prim_plus
-"+"
-:str_prim_minus
-"-"
-:str_prim_mul
-"*"
-:str_prim_div
-"/"
-:str_prim_mod
-"%"
-:str_prim_numeq
-"="
-:str_prim_lt
-"<"
-:str_prim_gt
-">"
-:str_prim_le
-"<="
-:str_prim_ge
-">="
-:str_prim_zerop
-"zero?"
-:str_prim_negativep
-"negative?"
-:str_prim_positivep
-"positive?"
-:str_prim_abs
-"abs"
-:str_prim_min
-"min"
-:str_prim_max
-"max"
-:str_prim_bitand
-"bit-and"
-:str_prim_bitor
-"bit-or"
-:str_prim_bitxor
-"bit-xor"
-:str_prim_bitnot
-"bit-not"
-:str_prim_ashift
-"arithmetic-shift"
-:str_prim_numberp
-"number?"
-:str_prim_symbolp
-"symbol?"
-:str_prim_stringp
-"string?"
-:str_prim_vectorp
-"vector?"
-:str_prim_procp
-"procedure?"
-:str_prim_eqp
-"eq?"
+:str_prim_plus "+"
+:str_prim_minus "-"
+:str_prim_mul "*"
+:str_prim_div "/"
+:str_prim_mod "%"
+:str_prim_numeq "="
+:str_prim_lt "<"
+:str_prim_gt ">"
+:str_prim_le "<="
+:str_prim_ge ">="
+:str_prim_zerop "zero?"
+:str_prim_negativep "negative?"
+:str_prim_positivep "positive?"
+:str_prim_abs "abs"
+:str_prim_min "min"
+:str_prim_max "max"
+:str_prim_bitand "bit-and"
+:str_prim_bitor "bit-or"
+:str_prim_bitxor "bit-xor"
+:str_prim_bitnot "bit-not"
+:str_prim_ashift "arithmetic-shift"
+:str_prim_numberp "number?"
+:str_prim_symbolp "symbol?"
+:str_prim_stringp "string?"
+:str_prim_vectorp "vector?"
+:str_prim_procp "procedure?"
+:str_prim_eqp "eq?"
## Step-10d list-core names.
-:str_prim_cons
-"cons"
-:str_prim_car
-"car"
-:str_prim_cdr
-"cdr"
-:str_prim_pairp
-"pair?"
-:str_prim_nullp
-"null?"
-:str_prim_list
-"list"
-:str_prim_length
-"length"
-:str_prim_listp
-"list?"
-:str_prim_append
-"append"
-:str_prim_reverse
-"reverse"
-:str_prim_assoc
-"assoc"
-:str_prim_member
-"member"
+:str_prim_cons "cons"
+:str_prim_car "car"
+:str_prim_cdr "cdr"
+:str_prim_pairp "pair?"
+:str_prim_nullp "null?"
+:str_prim_list "list"
+:str_prim_length "length"
+:str_prim_listp "list?"
+:str_prim_append "append"
+:str_prim_reverse "reverse"
+:str_prim_assoc "assoc"
+:str_prim_member "member"
## Step-10e string / vector / I/O / equal? / apply names.
-:str_prim_string_length
-"string-length"
-:str_prim_string_ref
-"string-ref"
-:str_prim_substring
-"substring"
-:str_prim_string_append
-"string-append"
-:str_prim_string_to_symbol
-"string->symbol"
-:str_prim_symbol_to_string
-"symbol->string"
-:str_prim_make_vector
-"make-vector"
-:str_prim_vector_ref
-"vector-ref"
-:str_prim_vector_set
-"vector-set!"
-:str_prim_vector_length
-"vector-length"
-:str_prim_vector_to_list
-"vector->list"
-:str_prim_list_to_vector
-"list->vector"
-:str_prim_display
-"display"
-:str_prim_write
-"write"
-:str_prim_newline
-"newline"
-:str_prim_format
-"format"
-:str_prim_error
-"error"
-:str_prim_read_file
-"read-file"
-:str_prim_write_file
-"write-file"
-:str_prim_equal
-"equal?"
-:str_prim_apply
-"apply"
+:str_prim_string_length "string-length"
+:str_prim_string_ref "string-ref"
+:str_prim_substring "substring"
+:str_prim_string_append "string-append"
+:str_prim_string_to_symbol "string->symbol"
+:str_prim_symbol_to_string "symbol->string"
+:str_prim_make_vector "make-vector"
+:str_prim_vector_ref "vector-ref"
+:str_prim_vector_set "vector-set!"
+:str_prim_vector_length "vector-length"
+:str_prim_vector_to_list "vector->list"
+:str_prim_list_to_vector "list->vector"
+:str_prim_display "display"
+:str_prim_write "write"
+:str_prim_newline "newline"
+:str_prim_format "format"
+:str_prim_error "error"
+:str_prim_read_file "read-file"
+:str_prim_write_file "write-file"
+:str_prim_equal "equal?"
+:str_prim_apply "apply"
:prelude_src
-"(define map (lambda (f xs) (if (null? xs) (quote ()) (cons (f (car xs)) (map f (cdr xs))))))
-(define filter (lambda (p xs) (if (null? xs) (quote ()) (if (p (car xs)) (cons (car xs) (filter p (cdr xs))) (filter p (cdr xs))))))
-(define fold (lambda (f acc xs) (if (null? xs) acc (fold f (f acc (car xs)) (cdr xs)))))
-"
+"(define map (lambda (f xs) (if (null? xs) (quote ()) (cons (f (car xs)) (map f (cdr xs))))))"
+"(define filter (lambda (p xs) (if (null? xs) (quote ()) (if (p (car xs)) (cons (car xs) (filter p (cdr xs))) (filter p (cdr xs))))))"
+"(define fold (lambda (f acc xs) (if (null? xs) acc (fold f (f acc (car xs)) (cdr xs)))))"
:prelude_src_end
@@ -5574,704 +4474,387 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
## with ADDI +40.
:prim_table
## (+ ...) variadic
-&str_prim_plus
-%0
-%1
-%0
-%0
-%0
-%6
-%0
-%0
-%0
+&str_prim_plus %0
+%1 %0
+%0 %0
+%6 %0
+%0 %0
## (- x ...) variadic (fixes unary-negate branch in body)
-&str_prim_minus
-%0
-%1
-%0
-%1
-%0
-%6
-%0
-%0
-%0
+&str_prim_minus %0
+%1 %0
+%1 %0
+%6 %0
+%0 %0
## (* ...) variadic
-&str_prim_mul
-%0
-%1
-%0
-%2
-%0
-%6
-%0
-%0
-%0
+&str_prim_mul %0
+%1 %0
+%2 %0
+%6 %0
+%0 %0
## (/ x y) fixed 2
-&str_prim_div
-%0
-%1
-%0
-%3
-%0
-%5
-%0
-%2
-%0
+&str_prim_div %0
+%1 %0
+%3 %0
+%5 %0
+%2 %0
## (% x y) fixed 2
-&str_prim_mod
-%0
-%1
-%0
-%4
-%0
-%5
-%0
-%2
-%0
+&str_prim_mod %0
+%1 %0
+%4 %0
+%5 %0
+%2 %0
## (= x y) fixed 2
-&str_prim_numeq
-%0
-%1
-%0
-%5
-%0
-%5
-%0
-%2
-%0
+&str_prim_numeq %0
+%1 %0
+%5 %0
+%5 %0
+%2 %0
## (< x y) fixed 2
-&str_prim_lt
-%0
-%1
-%0
-%6
-%0
-%5
-%0
-%2
-%0
+&str_prim_lt %0
+%1 %0
+%6 %0
+%5 %0
+%2 %0
## (> x y) fixed 2
-&str_prim_gt
-%0
-%1
-%0
-%7
-%0
-%5
-%0
-%2
-%0
+&str_prim_gt %0
+%1 %0
+%7 %0
+%5 %0
+%2 %0
## (<= x y) fixed 2
-&str_prim_le
-%0
-%2
-%0
-%8
-%0
-%5
-%0
-%2
-%0
+&str_prim_le %0
+%2 %0
+%8 %0
+%5 %0
+%2 %0
## (>= x y) fixed 2
-&str_prim_ge
-%0
-%2
-%0
-%9
-%0
-%5
-%0
-%2
-%0
+&str_prim_ge %0
+%2 %0
+%9 %0
+%5 %0
+%2 %0
## (zero? x) fixed 1
-&str_prim_zerop
-%0
-%5
-%0
-%10
-%0
-%5
-%0
-%1
-%0
+&str_prim_zerop %0
+%5 %0
+%10 %0
+%5 %0
+%1 %0
## (negative? x) fixed 1
-&str_prim_negativep
-%0
-%9
-%0
-%11
-%0
-%5
-%0
-%1
-%0
+&str_prim_negativep %0
+%9 %0
+%11 %0
+%5 %0
+%1 %0
## (positive? x) fixed 1
-&str_prim_positivep
-%0
-%9
-%0
-%12
-%0
-%5
-%0
-%1
-%0
+&str_prim_positivep %0
+%9 %0
+%12 %0
+%5 %0
+%1 %0
## (abs x) fixed 1
-&str_prim_abs
-%0
-%3
-%0
-%13
-%0
-%5
-%0
-%1
-%0
+&str_prim_abs %0
+%3 %0
+%13 %0
+%5 %0
+%1 %0
## (min ...) variadic — arity 0 ignored, but ≥1 enforced by body load
-&str_prim_min
-%0
-%3
-%0
-%14
-%0
-%6
-%0
-%0
-%0
+&str_prim_min %0
+%3 %0
+%14 %0
+%6 %0
+%0 %0
## (max ...) variadic
-&str_prim_max
-%0
-%3
-%0
-%15
-%0
-%6
-%0
-%0
-%0
+&str_prim_max %0
+%3 %0
+%15 %0
+%6 %0
+%0 %0
## (bit-and ...) variadic
-&str_prim_bitand
-%0
-%7
-%0
-%16
-%0
-%6
-%0
-%0
-%0
+&str_prim_bitand %0
+%7 %0
+%16 %0
+%6 %0
+%0 %0
## (bit-or ...) variadic
-&str_prim_bitor
-%0
-%6
-%0
-%17
-%0
-%6
-%0
-%0
-%0
+&str_prim_bitor %0
+%6 %0
+%17 %0
+%6 %0
+%0 %0
## (bit-xor ...) variadic
-&str_prim_bitxor
-%0
-%7
-%0
-%18
-%0
-%6
-%0
-%0
-%0
+&str_prim_bitxor %0
+%7 %0
+%18 %0
+%6 %0
+%0 %0
## (bit-not x) fixed 1
-&str_prim_bitnot
-%0
-%7
-%0
-%19
-%0
-%5
-%0
-%1
-%0
+&str_prim_bitnot %0
+%7 %0
+%19 %0
+%5 %0
+%1 %0
## (arithmetic-shift n k) fixed 2
-&str_prim_ashift
-%0
-%16
-%0
-%20
-%0
-%5
-%0
-%2
-%0
+&str_prim_ashift %0
+%16 %0
+%20 %0
+%5 %0
+%2 %0
## (number? x) fixed 1
-&str_prim_numberp
-%0
-%7
-%0
-%21
-%0
-%5
-%0
-%1
-%0
+&str_prim_numberp %0
+%7 %0
+%21 %0
+%5 %0
+%1 %0
## (symbol? x) fixed 1
-&str_prim_symbolp
-%0
-%7
-%0
-%22
-%0
-%5
-%0
-%1
-%0
+&str_prim_symbolp %0
+%7 %0
+%22 %0
+%5 %0
+%1 %0
## (string? x) fixed 1
-&str_prim_stringp
-%0
-%7
-%0
-%23
-%0
-%5
-%0
-%1
-%0
+&str_prim_stringp %0
+%7 %0
+%23 %0
+%5 %0
+%1 %0
## (vector? x) fixed 1
-&str_prim_vectorp
-%0
-%7
-%0
-%24
-%0
-%5
-%0
-%1
-%0
+&str_prim_vectorp %0
+%7 %0
+%24 %0
+%5 %0
+%1 %0
## (procedure? x) fixed 1
-&str_prim_procp
-%0
-%10
-%0
-%25
-%0
-%5
-%0
-%1
-%0
+&str_prim_procp %0
+%10 %0
+%25 %0
+%5 %0
+%1 %0
## (eq? x y) fixed 2
-&str_prim_eqp
-%0
-%3
-%0
-%26
-%0
-%5
-%0
-%2
-%0
+&str_prim_eqp %0
+%3 %0
+%26 %0
+%5 %0
+%2 %0
## (cons a d) fixed 2
-&str_prim_cons
-%0
-%4
-%0
-%27
-%0
-%5
-%0
-%2
-%0
+&str_prim_cons %0
+%4 %0
+%27 %0
+%5 %0
+%2 %0
## (car p) fixed 1
-&str_prim_car
-%0
-%3
-%0
-%28
-%0
-%5
-%0
-%1
-%0
+&str_prim_car %0
+%3 %0
+%28 %0
+%5 %0
+%1 %0
## (cdr p) fixed 1
-&str_prim_cdr
-%0
-%3
-%0
-%29
-%0
-%5
-%0
-%1
-%0
+&str_prim_cdr %0
+%3 %0
+%29 %0
+%5 %0
+%1 %0
## (pair? x) fixed 1
-&str_prim_pairp
-%0
-%5
-%0
-%30
-%0
-%5
-%0
-%1
-%0
+&str_prim_pairp %0
+%5 %0
+%30 %0
+%5 %0
+%1 %0
## (null? x) fixed 1
-&str_prim_nullp
-%0
-%5
-%0
-%31
-%0
-%5
-%0
-%1
-%0
+&str_prim_nullp %0
+%5 %0
+%31 %0
+%5 %0
+%1 %0
## (list ...) variadic
-&str_prim_list
-%0
-%4
-%0
-%32
-%0
-%6
-%0
-%0
-%0
+&str_prim_list %0
+%4 %0
+%32 %0
+%6 %0
+%0 %0
## (length lst) fixed 1
-&str_prim_length
-%0
-%6
-%0
-%33
-%0
-%5
-%0
-%1
-%0
+&str_prim_length %0
+%6 %0
+%33 %0
+%5 %0
+%1 %0
## (list? x) fixed 1
-&str_prim_listp
-%0
-%5
-%0
-%34
-%0
-%5
-%0
-%1
-%0
+&str_prim_listp %0
+%5 %0
+%34 %0
+%5 %0
+%1 %0
## (append ...) variadic
-&str_prim_append
-%0
-%6
-%0
-%35
-%0
-%6
-%0
-%0
-%0
+&str_prim_append %0
+%6 %0
+%35 %0
+%6 %0
+%0 %0
## (reverse lst) fixed 1
-&str_prim_reverse
-%0
-%7
-%0
-%36
-%0
-%5
-%0
-%1
-%0
+&str_prim_reverse %0
+%7 %0
+%36 %0
+%5 %0
+%1 %0
## (assoc key alist) fixed 2
-&str_prim_assoc
-%0
-%5
-%0
-%37
-%0
-%5
-%0
-%2
-%0
+&str_prim_assoc %0
+%5 %0
+%37 %0
+%5 %0
+%2 %0
## (member x lst) fixed 2
-&str_prim_member
-%0
-%6
-%0
-%38
-%0
-%5
-%0
-%2
-%0
+&str_prim_member %0
+%6 %0
+%38 %0
+%5 %0
+%2 %0
## (string-length s) fixed 1
-&str_prim_string_length
-%0
-%13
-%0
-%39
-%0
-%5
-%0
-%1
-%0
+&str_prim_string_length %0
+%13 %0
+%39 %0
+%5 %0
+%1 %0
## (string-ref s i) fixed 2
-&str_prim_string_ref
-%0
-%10
-%0
-%40
-%0
-%5
-%0
-%2
-%0
+&str_prim_string_ref %0
+%10 %0
+%40 %0
+%5 %0
+%2 %0
## (substring s start end) fixed 3
-&str_prim_substring
-%0
-%9
-%0
-%41
-%0
-%5
-%0
-%3
-%0
+&str_prim_substring %0
+%9 %0
+%41 %0
+%5 %0
+%3 %0
## (string-append ...) variadic
-&str_prim_string_append
-%0
-%13
-%0
-%42
-%0
-%6
-%0
-%0
-%0
+&str_prim_string_append %0
+%13 %0
+%42 %0
+%6 %0
+%0 %0
## (string->symbol s) fixed 1
-&str_prim_string_to_symbol
-%0
-%14
-%0
-%43
-%0
-%5
-%0
-%1
-%0
+&str_prim_string_to_symbol %0
+%14 %0
+%43 %0
+%5 %0
+%1 %0
## (symbol->string sym) fixed 1
-&str_prim_symbol_to_string
-%0
-%14
-%0
-%44
-%0
-%5
-%0
-%1
-%0
+&str_prim_symbol_to_string %0
+%14 %0
+%44 %0
+%5 %0
+%1 %0
## (make-vector n init) fixed 2
-&str_prim_make_vector
-%0
-%11
-%0
-%45
-%0
-%5
-%0
-%2
-%0
+&str_prim_make_vector %0
+%11 %0
+%45 %0
+%5 %0
+%2 %0
## (vector-ref v i) fixed 2
-&str_prim_vector_ref
-%0
-%10
-%0
-%46
-%0
-%5
-%0
-%2
-%0
+&str_prim_vector_ref %0
+%10 %0
+%46 %0
+%5 %0
+%2 %0
## (vector-set! v i x) fixed 3
-&str_prim_vector_set
-%0
-%11
-%0
-%47
-%0
-%5
-%0
-%3
-%0
+&str_prim_vector_set %0
+%11 %0
+%47 %0
+%5 %0
+%3 %0
## (vector-length v) fixed 1
-&str_prim_vector_length
-%0
-%13
-%0
-%48
-%0
-%5
-%0
-%1
-%0
+&str_prim_vector_length %0
+%13 %0
+%48 %0
+%5 %0
+%1 %0
## (vector->list v) fixed 1
-&str_prim_vector_to_list
-%0
-%12
-%0
-%49
-%0
-%5
-%0
-%1
-%0
+&str_prim_vector_to_list %0
+%12 %0
+%49 %0
+%5 %0
+%1 %0
## (list->vector lst) fixed 1
-&str_prim_list_to_vector
-%0
-%12
-%0
-%50
-%0
-%5
-%0
-%1
-%0
+&str_prim_list_to_vector %0
+%12 %0
+%50 %0
+%5 %0
+%1 %0
## (display x) fixed 1
-&str_prim_display
-%0
-%7
-%0
-%51
-%0
-%5
-%0
-%1
-%0
+&str_prim_display %0
+%7 %0
+%51 %0
+%5 %0
+%1 %0
## (write x) fixed 1
-&str_prim_write
-%0
-%5
-%0
-%52
-%0
-%5
-%0
-%1
-%0
+&str_prim_write %0
+%5 %0
+%52 %0
+%5 %0
+%1 %0
## (newline) fixed 0
-&str_prim_newline
-%0
-%7
-%0
-%53
-%0
-%5
-%0
-%0
-%0
+&str_prim_newline %0
+%7 %0
+%53 %0
+%5 %0
+%0 %0
## (format fmt ...) variadic
-&str_prim_format
-%0
-%6
-%0
-%54
-%0
-%6
-%0
-%0
-%0
+&str_prim_format %0
+%6 %0
+%54 %0
+%6 %0
+%0 %0
## (error msg) fixed 1
-&str_prim_error
-%0
-%5
-%0
-%55
-%0
-%5
-%0
-%1
-%0
+&str_prim_error %0
+%5 %0
+%55 %0
+%5 %0
+%1 %0
## (read-file path) fixed 1
-&str_prim_read_file
-%0
-%9
-%0
-%56
-%0
-%5
-%0
-%1
-%0
+&str_prim_read_file %0
+%9 %0
+%56 %0
+%5 %0
+%1 %0
## (write-file path data) fixed 2
-&str_prim_write_file
-%0
-%10
-%0
-%57
-%0
-%5
-%0
-%2
-%0
+&str_prim_write_file %0
+%10 %0
+%57 %0
+%5 %0
+%2 %0
## (equal? a b) fixed 2
-&str_prim_equal
-%0
-%6
-%0
-%58
-%0
-%5
-%0
-%2
-%0
+&str_prim_equal %0
+%6 %0
+%58 %0
+%5 %0
+%2 %0
## (apply proc arg ... last-list) variadic
-&str_prim_apply
-%0
-%5
-%0
-%59
-%0
-%6
-%0
-%0
-%0
+&str_prim_apply %0
+%5 %0
+%59 %0
+%6 %0
+%0 %0
## End sentinel: zero name pointer.
-%0
-%0
-%0
-%0
-%0
-%0
-%0
-%0
-%0
-%0
+%0 %0
+%0 %0
+%0 %0
+%0 %0
+%0 %0
## ---- Special-form symbol slots --------------------------------------
## Zero-initialized; _start populates each slot with the interned
## tagged-symbol pointer so eval_pair can dispatch by pointer identity.
-:sym_quote
-%0
-%0
-:sym_if
-%0
-%0
-:sym_begin
-%0
-%0
-:sym_lambda
-%0
-%0
-:sym_define
-%0
-%0
+:sym_quote %0 %0
+:sym_if %0 %0
+:sym_begin %0 %0
+:sym_lambda %0 %0
+:sym_define %0 %0
## Global-binding alist head. Zero-initialized (which is a valid
## untagged pair/nil sentinel? No — nil = 0x07. Seed to nil on entry
## from _start; the zero here would be interpreted as a pair pointer
## otherwise).
-:global_env_cell
-NIL
-%0
+:global_env_cell NIL %0
## ---- Primitive argv scratch buffer (32 slots × 8B = 256B) -----------
@@ -6280,597 +4863,179 @@ NIL
## primitives need more. Zeroed so a stray read sees the 0 tagged
## sentinel (not a valid value — harmless).
:prim_argv
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
## Reader-state save area for eval_source().
-:saved_src_base
-%0
-%0
-:saved_src_len
-%0
-%0
-:saved_src_cursor
-%0
-%0
-:saved_src_line
-%0
-%0
-:saved_src_col
-%0
-%0
+:saved_src_base %0 %0
+:saved_src_len %0 %0
+:saved_src_cursor %0 %0
+:saved_src_line %0 %0
+:saved_src_col %0 %0
## Shared buffers for pathname marshaling, string literal decoding, and
## file I/O primitives.
:path_buf
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
:reader_string_buf
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
:io_buf
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
-ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
+ZERO32 ZERO32
## ---- Symbol table (4096 slots × 8 bytes = 32 KiB) -------------------
## Open-addressing hash table. Empty slot = 0 (no valid tagged value
## is 0). LISP.md §GC §Roots makes this a named BSS root.
:symbol_table
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
:symbol_table_end
@@ -6878,262 +5043,70 @@ ZERO32
## Step 9 will grow this to 20 MiB via ELF memsz > filesz; for now a
## file-inlined block is fine (makes the binary ~50 KiB).
:heap_start
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
-ZERO32 ZERO32 ZERO32
-ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
:heap_tail
@@ -7143,263 +5116,70 @@ ZERO32
## Kept out of the Scheme heap so the reader's raw byte pointers don't
## fight the bump allocator.
:src_buf
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
-ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
+ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32 ZERO32
:src_buf_end
-
:ELF_end
diff --git a/src/p1_gen.py b/src/p1_gen.py
@@ -1096,6 +1096,19 @@ def rows():
## ---------- File emission -----------------------------------------------
+def lower_name(name: str) -> str:
+ """Transform an uppercase row name to the user-facing mnemonic.
+ First '_' binds op → first operand with underscore; subsequent
+ '_' become ',' (e.g. MOV_R4_R0 → mov_r4,r0, ADD_R1_R1_R2 →
+ add_r1,r1,r2). Single-'_' names (PROLOGUE_N3, SYS_WRITE, LI_R0)
+ keep their lone underscore."""
+ low = name.lower()
+ head, _, rest = low.partition('_')
+ if not rest:
+ return head
+ return f'{head}_{rest.replace("_", ",")}'
+
+
def emit(arch: str) -> str:
enc = ENCODERS[arch]
out = [HEADER.format(arch=arch).rstrip(), '']
@@ -1105,7 +1118,7 @@ def emit(arch: str) -> str:
out.append('')
out.append('## ---- ' + row.text + ' ' + '-' * max(0, 60 - len(row.text)))
continue
- name = 'P1_' + row.name if not row.name.startswith('SYS_') else row.name
+ name = lower_name(row.name)
if name in seen:
raise RuntimeError(f'duplicate DEFINE: {name}')
seen.add(name)
diff --git a/tests/demo.M1 b/tests/demo.M1
@@ -49,49 +49,43 @@
## poisons the chain; a broken LI_R6 (wrong dest reg or wrong
## literal-slot offset) puts the wrong value in r6 and MOV
## propagates it.
- P1_LI_R6
- '05000000' # r6 = 5 via LI_R6 (discriminator)
- P1_LI_R1
- '00000000' # clobber r1 before the MOV
- P1_MOV_R1_R6 # r1 = r6 = 5
- P1_LI_R2
- '03000000' # r2 = 3 (arith partner & shift amount)
- P1_LI_R5
- '05000000' # r5 = 5 (AND partner)
+ li_r6 '05000000' # r6 = 5 via LI_R6 (discriminator)
+ li_r1 '00000000' # clobber r1 before the MOV
+ mov_r1,r6 # r1 = r6 = 5
+ li_r2 '03000000' # r2 = 3 (arith partner & shift amount)
+ li_r5 '05000000' # r5 = 5 (AND partner)
## Tranche 1: reg-reg-reg arith.
- P1_ADD_R1_R1_R2 # 5 + 3 = 8
- P1_SUB_R1_R1_R2 # 8 - 3 = 5
- P1_XOR_R1_R1_R2 # 5 ^ 3 = 6
- P1_OR_R1_R1_R2 # 6 | 3 = 7
- P1_AND_R1_R1_R5 # 7 & 5 = 5
- P1_MUL_R1_R1_R2 # 5 * 3 = 15
- P1_DIV_R1_R1_R2 # 15 / 3 = 5
- P1_LI_R5
- '07000000' # r5 = 7 for REM
- P1_REM_R1_R1_R5 # 5 % 7 = 5
- P1_SHL_R1_R1_R2 # 5 << 3 = 40
- P1_SHR_R1_R1_R2 # 40 >> 3 = 5
+ add_r1,r1,r2 # 5 + 3 = 8
+ sub_r1,r1,r2 # 8 - 3 = 5
+ xor_r1,r1,r2 # 5 ^ 3 = 6
+ or_r1,r1,r2 # 6 | 3 = 7
+ and_r1,r1,r5 # 7 & 5 = 5
+ mul_r1,r1,r2 # 5 * 3 = 15
+ div_r1,r1,r2 # 15 / 3 = 5
+ li_r5 '07000000' # r5 = 7 for REM
+ rem_r1,r1,r5 # 5 % 7 = 5
+ shl_r1,r1,r2 # 5 << 3 = 40
+ shr_r1,r1,r2 # 40 >> 3 = 5
## SAR discriminator: on positive values SAR and SHR agree, so
## put a negative value in r4 and check that SAR preserves the
## sign bits. Then fold r4 into r1 so a misbehaving SAR poisons
## the accumulator.
- P1_LI_R4
- '00000000' # r4 = 0
- P1_ADDI_R4_R4_NEG1 # r4 = 0 + (-1) = -1 (sign-extended 64-bit)
- P1_SAR_R4_R4_R2 # r4 = -1 >> 3 = -1 (SHR would be 0x1FFF...FFFF)
- P1_ADD_R1_R1_R4 # r1 = 5 + (-1) = 4
- P1_ADDI_R1_R1_1 # r1 = 4 + 1 = 5
+ li_r4 '00000000' # r4 = 0
+ addi_r4,r4,neg1 # r4 = 0 + (-1) = -1 (sign-extended 64-bit)
+ sar_r4,r4,r2 # r4 = -1 >> 3 = -1 (SHR would be 0x1FFF...FFFF)
+ add_r1,r1,r4 # r1 = 5 + (-1) = 4
+ addi_r1,r1,1 # r1 = 4 + 1 = 5
## Tranche 2: immediate forms. Chain 5 → 8 → 5 → 10 → 5 → 4 → 5
## plus a SARI discriminator via r4.
- P1_ADDI_R1_R1_3 # 5 + 3 = 8
- P1_ADDI_R1_R1_NEG3 # 8 + (-3) = 5 (signed imm12)
- P1_SHLI_R1_R1_1 # 5 << 1 = 10 (non-zero shift)
- P1_SHRI_R1_R1_1 # 10 >> 1 = 5
- P1_ANDI_R1_R1_6 # 5 & 6 = 4 (0b101 & 0b110 = 0b100)
- P1_ORI_R1_R1_1 # 4 | 1 = 5 (aarch64 bitmask-immediate
+ addi_r1,r1,3 # 5 + 3 = 8
+ addi_r1,r1,neg3 # 8 + (-3) = 5 (signed imm12)
+ shli_r1,r1,1 # 5 << 1 = 10 (non-zero shift)
+ shri_r1,r1,1 # 10 >> 1 = 5
+ andi_r1,r1,6 # 5 & 6 = 4 (0b101 & 0b110 = 0b100)
+ ori_r1,r1,1 # 4 | 1 = 5 (aarch64 bitmask-immediate
# requires valid-mask imm; 5 is invalid, 1 is
# valid. Tranche 1 OR_R1_R1_R2 (6|3=7) already
# discriminates OR from ADD/XOR on overlapping
@@ -99,39 +93,33 @@
# exists and doesn't crash, plus distinguishes
# from AND (4&1=0 would fail the chain).)
- P1_LI_R4
- '00000000'
- P1_ADDI_R4_R4_NEG1 # r4 = -1
- P1_SARI_R4_R4_1 # r4 = -1 >> 1 = -1 (SHRI would be 0x7FFF...FFFF)
- P1_ADD_R1_R1_R4 # r1 = 5 + (-1) = 4
- P1_ADDI_R1_R1_1 # r1 = 5
+ li_r4 '00000000'
+ addi_r4,r4,neg1 # r4 = -1
+ sari_r4,r4,1 # r4 = -1 >> 1 = -1 (SHRI would be 0x7FFF...FFFF)
+ add_r1,r1,r4 # r1 = 5 + (-1) = 4
+ addi_r1,r1,1 # r1 = 5
## Tranche 3: memory round-trip. For each width, store r1,
## clobber r1 to 0, then reload. A broken ST/LD leaves r1 != 5.
- P1_LA_R4
- &scratch
+ la_r4 &scratch
- P1_ST_R1_R4_0 # [scratch+0..8] = r1 (= 5)
- P1_LI_R1
- '00000000'
- P1_LD_R1_R4_0 # r1 = [scratch+0..8] -> 5
+ st_r1,r4,0 # [scratch+0..8] = r1 (= 5)
+ li_r1 '00000000'
+ ld_r1,r4,0 # r1 = [scratch+0..8] -> 5
## Non-zero imm12 on the 64-bit forms. Distinct value 8 at +8 so
## an LD_R4_8 that silently aliased to +0 would read 5 and fail the
## SUB step; a broken ST_R4_8 leaves [+8]=0 (scratch init) which the
## LD observes. The +0 round-trip above anchors the imm12=0 case.
- P1_LI_R1
- '08000000' # distinct from 5
- P1_ST_R1_R4_8 # [scratch+8..16] = 8
- P1_LI_R1
- '00000000'
- P1_LD_R1_R4_8 # r1 = [scratch+8..16] -> 8
- P1_SUB_R1_R1_R2 # r1 = 8 - 3 = 5 (r2 still 3 from setup)
-
- P1_SB_R1_R4_16 # [scratch+16] = r1 (low byte)
- P1_LI_R1
- '00000000'
- P1_LB_R1_R4_16 # r1 = zext [scratch+16] -> 5
+ li_r1 '08000000' # distinct from 5
+ st_r1,r4,8 # [scratch+8..16] = 8
+ li_r1 '00000000'
+ ld_r1,r4,8 # r1 = [scratch+8..16] -> 8
+ sub_r1,r1,r2 # r1 = 8 - 3 = 5 (r2 still 3 from setup)
+
+ sb_r1,r4,16 # [scratch+16] = r1 (low byte)
+ li_r1 '00000000'
+ lb_r1,r4,16 # r1 = zext [scratch+16] -> 5
## Negative imm12 on the memory forms. LA to scratch_mid (= scratch+16)
## then round-trip a distinct sentinel (13) via [r4 + -8] = scratch+8.
@@ -140,126 +128,94 @@
## miscompiled to the same wrong offset" bug could still false-pass,
## but the common cases (sign bit dropped, imm zero-extended) blow
## up via segfault or a mismatched round-trip value.
- P1_LA_R4
- &scratch_mid
- P1_LI_R1
- '0D000000' # r1 = 13 (distinct sentinel)
- P1_ST_R1_R4_NEG8 # [scratch+8] = 13 (overwrites +8 slot's old 8)
- P1_LI_R1
- '00000000'
- P1_LD_R1_R4_NEG8 # r1 = [scratch+8] -> 13
- P1_ADDI_R1_R1_NEG3 # r1 = 13 - 3 = 10
- P1_SHRI_R1_R1_1 # r1 = 10 >> 1 = 5
+ la_r4 &scratch_mid
+ li_r1 '0D000000' # r1 = 13 (distinct sentinel)
+ st_r1,r4,neg8 # [scratch+8] = 13 (overwrites +8 slot's old 8)
+ li_r1 '00000000'
+ ld_r1,r4,neg8 # r1 = [scratch+8] -> 13
+ addi_r1,r1,neg3 # r1 = 13 - 3 = 10
+ shri_r1,r1,1 # r1 = 10 >> 1 = 5
## Tranche 4: branches. r2=0, r3=1 to start; each subtest resets
## as needed. Taken-path subtests clobber r1 on fall-through;
## fall-through subtests clobber r1 on incorrect branch.
- P1_LI_R2
- '00000000' # r2 = 0
- P1_LI_R3
- '01000000' # r3 = 1
+ li_r2 '00000000' # r2 = 0
+ li_r3 '01000000' # r3 = 1
## B — unconditional. Correct: jump to b4_1_ok, skipping clobber.
- P1_LI_BR
- &b4_1_ok
- P1_B
- P1_LI_R1
- '00000000'
+ li_br &b4_1_ok
+ b
+ li_r1 '00000000'
:b4_1_ok
## BEQ taken: r3=0 so r2==r3.
- P1_LI_R3
- '00000000'
- P1_LI_BR
- &b4_2_ok
- P1_BEQ_R2_R3 # 0 == 0, taken
- P1_LI_R1
- '00000000'
+ li_r3 '00000000'
+ li_br &b4_2_ok
+ beq_r2,r3 # 0 == 0, taken
+ li_r1 '00000000'
:b4_2_ok
- P1_LI_R3
- '01000000' # restore r3 = 1
+ li_r3 '01000000' # restore r3 = 1
## BEQ fall-through: 0 != 1, branch must NOT fire. If it
## (incorrectly) fires we jump to b4_3_bad and clobber r1.
- P1_LI_BR
- &b4_3_bad
- P1_BEQ_R2_R3 # 0 == 1? no, fall through
- P1_LI_BR
- &b4_3_ok
- P1_B
+ li_br &b4_3_bad
+ beq_r2,r3 # 0 == 1? no, fall through
+ li_br &b4_3_ok
+ b
:b4_3_bad
- P1_LI_R1
- '00000000'
+ li_r1 '00000000'
:b4_3_ok
## BNE taken: 0 != 1.
- P1_LI_BR
- &b4_4_ok
- P1_BNE_R2_R3 # 0 != 1, taken
- P1_LI_R1
- '00000000'
+ li_br &b4_4_ok
+ bne_r2,r3 # 0 != 1, taken
+ li_r1 '00000000'
:b4_4_ok
## BNE fall-through: r3=0 so r2==r3; branch must NOT fire.
- P1_LI_R3
- '00000000'
- P1_LI_BR
- &b4_5_bad
- P1_BNE_R2_R3 # 0 != 0? no, fall through
- P1_LI_BR
- &b4_5_ok
- P1_B
+ li_r3 '00000000'
+ li_br &b4_5_bad
+ bne_r2,r3 # 0 != 0? no, fall through
+ li_br &b4_5_ok
+ b
:b4_5_bad
- P1_LI_R1
- '00000000'
+ li_r1 '00000000'
:b4_5_ok
- P1_LI_R3
- '01000000' # restore r3 = 1
+ li_r3 '01000000' # restore r3 = 1
## BLT taken: 0 < 1 (signed).
- P1_LI_BR
- &b4_6_ok
- P1_BLT_R2_R3 # 0 < 1, taken
- P1_LI_R1
- '00000000'
+ li_br &b4_6_ok
+ blt_r2,r3 # 0 < 1, taken
+ li_r1 '00000000'
:b4_6_ok
## BLT fall-through: 1 < 0 is false.
- P1_LI_R2
- '01000000' # r2 = 1
- P1_LI_R3
- '00000000' # r3 = 0
- P1_LI_BR
- &b4_7_bad
- P1_BLT_R2_R3 # 1 < 0? no, fall through
- P1_LI_BR
- &b4_7_ok
- P1_B
+ li_r2 '01000000' # r2 = 1
+ li_r3 '00000000' # r3 = 0
+ li_br &b4_7_bad
+ blt_r2,r3 # 1 < 0? no, fall through
+ li_br &b4_7_ok
+ b
:b4_7_bad
- P1_LI_R1
- '00000000'
+ li_r1 '00000000'
:b4_7_ok
## BLT signed discrimination: -1 < 0 must be taken. If BLT were
## accidentally unsigned, -1 as 0xFFFF...FFFF > 0 and the branch
## would not fire.
- P1_LI_R2
- '00000000' # r2 = 0
- P1_LI_R4
- '00000000'
- P1_ADDI_R4_R4_NEG1 # r4 = -1 (sign-extended)
- P1_LI_BR
- &b4_8_ok
- P1_BLT_R4_R2 # -1 < 0 (signed)? yes, taken
- P1_LI_R1
- '00000000'
+ li_r2 '00000000' # r2 = 0
+ li_r4 '00000000'
+ addi_r4,r4,neg1 # r4 = -1 (sign-extended)
+ li_br &b4_8_ok
+ blt_r4,r2 # -1 < 0 (signed)? yes, taken
+ li_r1 '00000000'
:b4_8_ok
## Tranche 5: CALL / RET / PROLOGUE / EPILOGUE / TAIL.
## fn_identity does its own nested CALL to fn_inner — if PROLOGUE
## doesn't spill lr correctly, the inner CALL clobbers the
## return-to-_start address and we crash or hang. The function
- ## bodies live inline below the subtests, guarded by a P1_B over
+ ## bodies live inline below the subtests, guarded by a b over
## them so we don't fall through after the last subtest.
##
## Stack-balance discriminator for TAIL: snapshot sp into r6
@@ -267,85 +223,67 @@
## nets to sp_after == sp_before. A TAIL that skips its epilogue
## leaks fn_parent_tail's 16-byte frame — the delta is folded
## into the accumulator below via SUB r1, r1, delta.
- P1_MOV_R6_SP # r6 = sp snapshot (pre-tranche)
+ mov_r6,sp # r6 = sp snapshot (pre-tranche)
- P1_LI_BR
- &fn_identity
- P1_CALL # nested-CALL test: returns r1 unchanged
+ li_br &fn_identity
+ call # nested-CALL test: returns r1 unchanged
- P1_LI_BR
- &fn_parent_tail
- P1_CALL # TAIL test: fn_identity RETs to here
+ li_br &fn_parent_tail
+ call # TAIL test: fn_identity RETs to here
- P1_LI_BR
- &b5_end
- P1_B # skip over the inlined function bodies
+ li_br &b5_end
+ b # skip over the inlined function bodies
:fn_inner
- P1_PROLOGUE
- P1_EPILOGUE
- P1_RET
+ prologue
+ epilogue
+ ret
:fn_identity
- P1_PROLOGUE
- P1_LI_BR
- &fn_inner
- P1_CALL
- P1_EPILOGUE
- P1_RET
+ prologue
+ li_br &fn_inner
+ call
+ epilogue
+ ret
:fn_parent_tail
- P1_PROLOGUE
- P1_LI_BR
- &fn_identity
- P1_TAIL
+ prologue
+ li_br &fn_identity
+ tail
:b5_end
- P1_MOV_R2_SP # r2 = sp snapshot (post-tranche)
- P1_SUB_R2_R2_R6 # r2 = sp_after - sp_before (0 if balanced)
- P1_SUB_R1_R1_R2 # r1 -= delta; unchanged (= 5) iff balanced
+ mov_r2,sp # r2 = sp snapshot (post-tranche)
+ sub_r2,r2,r6 # r2 = sp_after - sp_before (0 if balanced)
+ sub_r1,r1,r2 # r1 -= delta; unchanged (= 5) iff balanced
- P1_MOV_R6_R1 # r6 = 5 (callee-saved, survives syscalls)
+ mov_r6,r1 # r6 = 5 (callee-saved, survives syscalls)
## write(1, &prefix, 5) — "P1 = "
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- '01000000'
- P1_LI_R2
- &prefix
- P1_LI_R3
- '05000000'
- P1_SYSCALL
+ li_r0 sys_write
+ li_r1 '01000000'
+ li_r2 &prefix
+ li_r3 '05000000'
+ syscall
## write(1, &digits + r6, 1) — the computed digit ('5')
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- '01000000'
- P1_LI_R2
- &digits
- P1_ADD_R2_R2_R6 # r2 = &digits + 5
- P1_LI_R3
- '01000000'
- P1_SYSCALL
+ li_r0 sys_write
+ li_r1 '01000000'
+ li_r2 &digits
+ add_r2,r2,r6 # r2 = &digits + 5
+ li_r3 '01000000'
+ syscall
## write(1, &newline, 1)
- P1_LI_R0
- SYS_WRITE
- P1_LI_R1
- '01000000'
- P1_LI_R2
- &newline
- P1_LI_R3
- '01000000'
- P1_SYSCALL
+ li_r0 sys_write
+ li_r1 '01000000'
+ li_r2 &newline
+ li_r3 '01000000'
+ syscall
## exit(r6) — exit status = computed result
- P1_LI_R0
- SYS_EXIT
- P1_MOV_R1_R6
- P1_SYSCALL
+ li_r0 sys_exit
+ mov_r1,r6
+ syscall
:prefix
"P1 = "
@@ -359,11 +297,7 @@
## is RWX (see ELF-<arch>.hex2 ph_flags=7) so we can store into this
## region at runtime. scratch_mid = scratch+16, the base address for
## the negative-imm12 LD/ST test ([scratch_mid + -8] = [scratch+8]).
-:scratch
-'0000000000000000'
-'0000000000000000'
-:scratch_mid
-'0000000000000000'
-'0000000000000000'
+:scratch '0000000000000000' '0000000000000000'
+:scratch_mid '0000000000000000' '0000000000000000'
:ELF_end
diff --git a/tests/hello.M1 b/tests/hello.M1
@@ -8,22 +8,16 @@
:_start
## write(fd=1, buf=&msg, count=14)
- P1_LI_R0
- SYS_WRITE # r0 = syscall number (write)
- P1_LI_R1
- '01000000' # r1 = fd (stdout)
- P1_LI_R2
- &msg # r2 = buf
- P1_LI_R3
- '0E000000' # r3 = count (14)
- P1_SYSCALL
+ li_r0 sys_write # r0 = syscall number (write)
+ li_r1 '01000000' # r1 = fd (stdout)
+ li_r2 &msg # r2 = buf
+ li_r3 '0E000000' # r3 = count (14)
+ syscall
## exit(0)
- P1_LI_R0
- SYS_EXIT # r0 = syscall number (exit)
- P1_LI_R1
- '00000000' # r1 = status
- P1_SYSCALL
+ li_r0 sys_exit # r0 = syscall number (exit)
+ li_r1 '00000000' # r1 = status
+ syscall
:msg
"Hello, world!