commit c24e386d1f9da71804e861ccfa961b6db0f6d924
parent b67850fbf7de470673af34368fe0342900082d26
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 23 Apr 2026 06:54:42 -0700
Add P1 m1m bootstrap stub
Diffstat:
| M | Makefile | | | 19 | ++++++++++++++++--- |
| A | src/m1m.M1 | | | 331 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | src/p1_gen.py | | | 6 | ++++++ |
3 files changed, 353 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
@@ -77,6 +77,15 @@ OUT_DIR := build/$(ARCH)
TOOLS_DIR := $(OUT_DIR)/tools
COMBINED_DIR := $(OUT_DIR)/combined
+ifeq ($(PROG),m1m)
+ ifneq ($(ARCH),aarch64)
+ $(error PROG=m1m is currently staged for ARCH=aarch64 only)
+ endif
+ P1_DEFS := $(OUT_DIR)/p1_m1m_aarch64.M1
+else
+ P1_DEFS := $(OUT_DIR)/p1_$(ARCH).M1
+endif
+
# stage0-posix uses mixed-case arch dirs (AArch64, AMD64) that don't match
# our lowercase ARCH. Map them so build/upstream/ mirrors upstream layout.
ARCH_DIR_aarch64 := AArch64
@@ -175,10 +184,10 @@ $(TOOLS_DIR)/M0 $(TOOLS_DIR)/hex2-0 $(TOOLS_DIR)/catm $(TOOLS_DIR)/hex0 $(TOOLS_
#
# M0 takes a single positional input (no -f flag), so we catm the pruned p1
# with PROG_SRC first. Intermediates stay in OUT_DIR so clean picks them up.
-$(OUT_DIR)/$(PROG).hex2: $(PROG_SRC) $(OUT_DIR)/p1_$(ARCH).M1 lint.sh $(TOOLS_DIR)/M0 $(TOOLS_DIR)/catm | $(OUT_DIR) $(IMAGE_STAMP)
- ./lint.sh $(OUT_DIR)/p1_$(ARCH).M1 $(PROG_SRC)
+$(OUT_DIR)/$(PROG).hex2: $(PROG_SRC) $(P1_DEFS) lint.sh $(TOOLS_DIR)/M0 $(TOOLS_DIR)/catm | $(OUT_DIR) $(IMAGE_STAMP)
+ ./lint.sh $(P1_DEFS) $(PROG_SRC)
awk 'NR==FNR{for(i=1;i<=NF;i++)u[$$i]=1;next} /^DEFINE /{if($$2 in u)print;next} {print}' \
- $(PROG_SRC) $(OUT_DIR)/p1_$(ARCH).M1 > $(OUT_DIR)/p1_$(ARCH).pruned.M1
+ $(PROG_SRC) $(P1_DEFS) > $(OUT_DIR)/p1_$(ARCH).pruned.M1
$(PODMAN) sh -ec ' \
cp $(OUT_DIR)/p1_$(ARCH).pruned.M1 /tmp/p1.M1 ; \
cp $(PROG_SRC) /tmp/prog.M1 ; \
@@ -308,3 +317,7 @@ clean:
# no staleness risk).
build/aarch64/p1_aarch64.M1 build/amd64/p1_amd64.M1 build/riscv64/p1_riscv64.M1 &: src/p1_gen.py
python3 src/p1_gen.py build
+
+build/aarch64/p1_m1m_aarch64.M1: build/aarch64/p1_aarch64.M1 src/m1m.M1 | build/aarch64
+ awk 'NR==FNR{for(i=1;i<=NF;i++)u[$$i]=1;next} /^DEFINE /{if($$2 in u)print;next} {print}' \
+ src/m1m.M1 build/aarch64/p1_aarch64.M1 > $@
diff --git a/src/m1m.M1 b/src/m1m.M1
@@ -0,0 +1,331 @@
+## m1m.M1 -- bootstrap M1 macro-expander executable shell.
+##
+## This file is intentionally raw P1 source: no M1M macros are used to build
+## the first macro expander. The executable contract matches src/m1macro.c:
+##
+## m1m input.M1 output.M1
+##
+## Current state: argv and file I/O are real, but the expander core is still
+## stubbed out with an explicit failure. Keeping the failure explicit avoids
+## accidentally treating an incomplete bootstrap stage as a pass-through
+## macro expander.
+
+DEFINE M1M_BUF_SIZE 00400000
+DEFINE O_WRONLY_CREAT_TRUNC 41020000
+DEFINE MODE_0644 A4010000
+DEFINE AT_FDCWD 9CFFFFFF
+DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000'
+
+:_start
+ ## Kernel entry stack: [sp+0]=argc, [sp+8]=argv[0],
+ ## [sp+16]=argv[1], [sp+24]=argv[2].
+ ld_r0,sp,0
+ li_r1 %3
+ li_br &err_usage
+ blt_r0,r1
+
+ ## Preserve output path in r6 while opening and reading input.
+ ld_r6,sp,24
+
+ ## openat(AT_FDCWD, argv[1], O_RDONLY=0, mode=0)
+ ld_r2,sp,16
+ li_r0 sys_openat
+ li_r1 AT_FDCWD
+ li_r3 %0
+ li_r4 %0
+ syscall
+
+ li_br &err_open_input
+ bltz_r0
+ mov_r5,r0
+
+ ## Read the complete input file into m1m_input_buf.
+ li_r7 %0
+:read_loop
+ li_r3 M1M_BUF_SIZE
+ li_br &read_done
+ beq_r7,r3
+
+ li_r0 sys_read
+ mov_r1,r5
+ li_r2 &m1m_input_buf
+ add_r2,r2,r7
+ li_r3 M1M_BUF_SIZE
+ sub_r3,r3,r7
+ syscall
+
+ li_br &read_done
+ beqz_r0
+ li_br &err_read
+ bltz_r0
+
+ add_r7,r7,r0
+ li_br &read_loop
+ b
+
+:read_done
+ li_r3 M1M_BUF_SIZE
+ li_br &err_input_too_big
+ beq_r7,r3
+
+ ## The parser/expander will fill m1m_output_buf and set r7 to its
+ ## output byte count. Until that core lands, fail loudly.
+ li_br &err_not_implemented
+ b
+
+ ## Unreachable until the expander core branches here.
+:write_output
+ ## openat(AT_FDCWD, argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0644)
+ li_r0 sys_openat
+ li_r1 AT_FDCWD
+ mov_r2,r6
+ li_r3 O_WRONLY_CREAT_TRUNC
+ li_r4 MODE_0644
+ syscall
+
+ li_br &err_open_output
+ bltz_r0
+ mov_r4,r0
+
+ ## Write r7 bytes from m1m_output_buf.
+ li_r5 %0
+:write_loop
+ li_br &write_done
+ beq_r5,r7
+
+ li_r0 sys_write
+ mov_r1,r4
+ li_r2 &m1m_output_buf
+ add_r2,r2,r5
+ sub_r3,r7,r5
+ syscall
+
+ li_br &err_write
+ bltz_r0
+ li_br &err_write
+ beqz_r0
+
+ add_r5,r5,r0
+ li_br &write_loop
+ b
+
+:write_done
+ li_r0 sys_exit
+ li_r1 %0
+ syscall
+
+:err_usage
+ li_r1 &msg_usage
+ li_r2 %29
+ li_br &fatal
+ b
+
+:err_open_input
+ li_r1 &msg_open_input
+ li_r2 %25
+ li_br &fatal
+ b
+
+:err_read
+ li_r1 &msg_read
+ li_r2 %20
+ li_br &fatal
+ b
+
+:err_input_too_big
+ li_r1 &msg_input_too_big
+ li_r2 %20
+ li_br &fatal
+ b
+
+:err_not_implemented
+ li_r1 &msg_not_implemented
+ li_r2 %29
+ li_br &fatal
+ b
+
+:err_open_output
+ li_r1 &msg_open_output
+ li_r2 %26
+ li_br &fatal
+ b
+
+:err_write
+ li_r1 &msg_write
+ li_r2 %22
+ li_br &fatal
+ b
+
+## fatal(msg, len): write "m1m: " + msg to stderr and exit 1.
+## Inputs: r1 = message pointer, r2 = message length.
+:fatal
+ mov_r6,r1
+ mov_r7,r2
+
+ li_r0 sys_write
+ li_r1 %2
+ li_r2 &msg_prefix
+ li_r3 %5
+ 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
+
+:msg_prefix "m1m: "
+:msg_newline "
+"
+:msg_usage "usage: m1m input.M1 output.M1"
+:msg_open_input "failed to open input file"
+:msg_read "failed to read input"
+:msg_input_too_big "input file too large"
+:msg_not_implemented "expander core not implemented"
+:msg_open_output "failed to open output file"
+:msg_write "failed to write output"
+
+:ELF_end
+
+## BSS. The ELF header maps this zero-filled region after the on-disk image.
+:m1m_input_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
+:m1m_output_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
+:ELF_bss_end
diff --git a/src/p1_gen.py b/src/p1_gen.py
@@ -1025,9 +1025,15 @@ RRR_TABLE = (
('ADD','r6','r1','r2'),
('ADD','r6','r6','r0'),
('ADD','r7','r1','r2'),
+ # m1m bootstrap file I/O buffer indexing.
+ ('ADD','r2','r2','r5'),
+ ('ADD','r2','r2','r7'),
('SUB','r2','r1','r6'),
('SUB','r3','r1','r6'),
('SUB','r2','r2','r1'), # prelude length = end - start
+ # m1m bootstrap file I/O remaining-byte counts.
+ ('SUB','r3','r3','r7'),
+ ('SUB','r3','r7','r5'),
('REM','r1','r1','r2'),
# bump-pointer + accumulator updates (originally kaem-minimal;
# retained in case lisp uses them — lint catches dead entries)