boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs

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:
Mlint.sh | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/lisp.M1 | 9740+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/p1_gen.py | 15++++++++++++++-
Mtests/demo.M1 | 340++++++++++++++++++++++++++++++++-----------------------------------------------
Mtests/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!