code wiki / (root) / nx_isa_cortexm_gate.nx

nx_isa_cortexm_gate.nx

buildroot/runtime/nx_isa_cortexm_gate.nx

37529 B834 linesdepth 4pulls 5 transitivereach 0 importersview sourcekind gate/prooftopic isa
docsdependenciesstructsconstsfunctions

about

nx_isa_cortexm_gate.nx -- THE ARMv7-M / Cortex-M CONFORMANCE RULER. WHY IT EXISTS: nx_emu_cortexm.nx has claimed "we emulate Cortex-M" since it was written and had NEVER been run by anything. nx_isa_conform_gate measures five of the estate's ten sovereign emulators and names cortexm in its own UNMEASURED list. This organ closes that row for cortexm alone, in its own file, so two seats working two architectures cannot clobber one shared source. THE LAW: expectations come FROM THE ARMv7-M ARCHITECTURE REFERENCE MANUAL -- encodings out of the Thumb instruction tables, results out of the operation pseudocode -- never from reading the emulator and writing down what it happens to do. Reading the decoder is allowed for exactly one purpose: learning which classes are IMPLEMENTED versus MISSING, so a gap is named rather than mistaken for a wrong answer. Calibrating the ruler to the subject is the one failure that makes every green here worthless. WHAT READING THE DECODER FOUND, AND WHAT WAS DONE ABOUT IT (2026-09-03): the emulator implemented NO conditional branch, NO unconditional branch, NO CMP in either form, and carried ONE flag (C) with no N, Z or V. A machine that cannot take a branch cannot run a loop, so more than half of these KATs were unrunnable by construction. The gap was CLOSED in nx_emu_cortexm.nx rather than reported -- full NZCV off one shared ARM adder, the condition-code table, B-cond, B, CBZ/CBNZ, the immediate add/sub forms, the whole data-processing register block, the shifter, byte/halfword access, SP- and PC-relative addressing. Every KAT below that exercises one of those was RED before that work and is GREEN after it; that transition is the only evidence that this gate can fire at all. FIVE OUTCOMES, NEVER ONE: PASS ran and matched the manual-derived expectation WRONG-ANSWER ran to completion and computed the wrong value UNSUPPORTED hit an instruction class the emulator does not implement RAN-OFF-END the interpreter loop ended without reaching an exit FAULT bad PC, out-of-range fetch, or the step budget Collapsing these into "FAIL" is what makes a gap unactionable: an unimplemented instruction class and a miscomputed result need OPPOSITE fixes. THE EXIT-STATUS MASK IS A REAL HAZARD AND IS DESIGNED AROUND. Cortex-M here halts on BKPT with result = r0 & 0xff, so every legitimate answer is 0..255 and the three negative sentinels can never collide with one -- but two KATs whose right and wrong answers differ only above bit 7 would be indistinguishable. Each expectation below

dependencies 3 imports · 0 importers

nx_gate_verdict.nx nx_syscalls.nx nx_emu_cortexm.nx nx_isa_cortexm_gate.nx

imports: nx_gate_verdict.nxnx_syscalls.nxnx_emu_cortexm.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main gv_head gv_puts sys_write gv_ctr sys_mmap nxa_die sys_write ↻ sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ sys_mmap ↻ gv_puts ↻ cx_nl sys_mmap ↻ sys_write ↻ cx_report cx_classify gv_puts ↻ gv_num sys_mmap ↻ sys_write ↻ sys_munmap cx_outcome_name cx_nl ↻ gv_cat gv_catn sys_mmap ↻ sys_munmap ↻ cx_imm_arith cx_guest

structs

none

consts

65const CX_GUEST_BYTES: i64 = 1048576 // 1 MiB guest image
66const CX_ENTRY: i64 = 0 // KAT code is loaded at guest vaddr 0
67const CX_SP: i64 = 983040 // 960 KiB: above the code, inside the image
68const CX_DATA: i64 = 4096 // scratch word address, past any KAT's code
69const CX_MODE_FILE: i64 = 420 // 0644; 420 and 0x1a4 are the SAME constant and
73const CX_UNSUPPORTED: i64 = -1
74const CX_RANOFF: i64 = -2
75const CX_FAULT: i64 = -3
78const CX_O_PASS: i64 = 0
79const CX_O_WRONG: i64 = 1
80const CX_O_UNSUP: i64 = 2
81const CX_O_FAULT: i64 = 3
82const CX_O_RANOFF: i64 = 4
86const CX_NB_BYTES: i64 = 2048
87const CX_NB_OFF: i64 = 0
88const CX_NB_PTR: i64 = 1
89const CX_NB_ROW_MAX: i64 = 256
90const CX_BOX_BYTES: i64 = 32
92const CX_NL: i64 = 10
93const CX_SPACE: i64 = 32
94const CX_DIG_LO: i64 = 48
95const CX_DIG_HI: i64 = 57
96const CX_UNSEEDED: i64 = -1
97const CX_RBUF: i64 = 256
98const CX_B10: i64 = 10
101const CX_S3: i64 = 3
102const CX_S5: i64 = 5
103const CX_S6: i64 = 6
104const CX_S8: i64 = 8
105const CX_S9: i64 = 9
106const CX_S10: i64 = 10
107const CX_S11: i64 = 11
108const CX_S12: i64 = 12
109const CX_M3: i64 = 7
110const CX_M4: i64 = 15
111const CX_M5: i64 = 31
112const CX_M8: i64 = 255
113const CX_M11: i64 = 0x7FF
114const CX_BYTE: i64 = 255
115const CX_HWB: i64 = 2 // a Thumb halfword is two bytes
116const CX_PCBIAS: i64 = 4 // Thumb: the branch base is the instruction + 4
119const CX_T_LSLI: i64 = 0x0000
120const CX_T_LSRI: i64 = 0x0800
121const CX_T_ASRI: i64 = 0x1000
122const CX_T_ADDR: i64 = 0x1800
123const CX_T_SUBR: i64 = 0x1A00
124const CX_T_MOVI8: i64 = 0x2000
125const CX_T_ADDI8: i64 = 0x3000
126const CX_T_SUBI8: i64 = 0x3800
127const CX_T_AND: i64 = 0x4000
128const CX_T_CMPR: i64 = 0x4280
129const CX_T_ORR: i64 = 0x4300
130const CX_T_MUL: i64 = 0x4340
131const CX_T_STRI5: i64 = 0x6000
132const CX_T_LDRI5: i64 = 0x6800
133const CX_T_CBZ: i64 = 0xB100
134const CX_T_PUSH: i64 = 0xB400
135const CX_T_POP: i64 = 0xBC00
136const CX_T_BKPT: i64 = 0xBE00
137const CX_T_BCOND: i64 = 0xD000
138const CX_T_B: i64 = 0xE000
142const CX_T_UDF: i64 = 0xDE00
144const CX_T_MOVW: i64 = 0xF240
145const CX_T_MLA: i64 = 0xFB00
148const CX_C_NE: i64 = 1
149const CX_C_LT: i64 = 11
154const CX_A40: i64 = 40
155const CX_A2: i64 = 2
156const CX_A90: i64 = 90
157const CX_A48: i64 = 48
158const CX_A200: i64 = 200
159const CX_A7: i64 = 7
160const CX_A240: i64 = 240
161const CX_A15: i64 = 15
162const CX_A60: i64 = 60
163const CX_A6: i64 = 6
164const CX_A5: i64 = 5
165const CX_A8: i64 = 8
166const CX_A9: i64 = 9
167const CX_A33: i64 = 33
168const CX_A55: i64 = 55
169const CX_A42: i64 = 42
170const CX_SH24: i64 = 24
171const CX_SH31: i64 = 31
172const CX_LOOP_N: i64 = 10
173const CX_MOVW_TEST: i64 = 43981 // 0xABCD: imm4=A, i=1, imm3=3, imm8=CD -- all
177const CX_W_ARITH: i64 = 42 // 40 + 2
178const CX_W_SUB: i64 = 42 // 90 - 48; a reversed operand order gives 214
179const CX_W_IMM8: i64 = 233 // 200 + 40 - 7
180const CX_W_LOGIC: i64 = 60 // (240 | 15) & 60 = 255 & 60; all-AND gives 0, all-OR gives 255
181const CX_W_LSR: i64 = 1 // 0xFF000000 >> 31 logical
182const CX_W_ASR: i64 = 255 // 0xFF000000 >> 31 arithmetic = 0xFFFFFFFF, masked
183const CX_W_MUL: i64 = 42 // 6 * 7
184const CX_W_LOOP: i64 = 45 // sum 0..9
185const CX_W_SIGNED: i64 = 33 // BLT taken: 0xFF000000 < 1 as SIGNED
186const CX_W_UNSIGN: i64 = 7 // the value only an UNSIGNED compare would leave
187const CX_W_CBZ: i64 = 55
188const CX_W_CBZMISS: i64 = 9
189const CX_W_MOVW: i64 = 171 // 0xABCD >> 8 = 0xAB
190const CX_W_MLA: i64 = 42 // 5 * 8 + 2
191const CX_W_LDST: i64 = 200
192const CX_W_PUSHPOP: i64 = 42
555const CX_RATCHET: *u8 = "knowledge/status/isa_cortexm.ratchet"
556const CX_KEY: *u8 = "cortexm"

functions

196func cx_nl() -> i64
called by 2: cx_reportmain calls 2: sys_mmapsys_write
207func cx_put_le16(code: *u8, off: i64, w: i64) -> i64
217func cx_put_t32(code: *u8, off: i64, hw1: i64, hw2: i64) -> i64
223func cx_guest() -> *u8 { return sys_mmap(CX_GUEST_BYTES) }
227func cx_movs(rd: i64, imm8: i64) -> i64 { return CX_T_MOVI8 | (rd << CX_S8) | (imm8 & CX_M8) }
228func cx_addr(rd: i64, rn: i64, rm: i64) -> i64 { return CX_T_ADDR | (rm << CX_S6) | (rn << CX_S3) | rd }
229func cx_subr(rd: i64, rn: i64, rm: i64) -> i64 { return CX_T_SUBR | (rm << CX_S6) | (rn << CX_S3) | rd }
called by 1: cx_sub
230func cx_addi8(rdn: i64, imm8: i64) -> i64 { return CX_T_ADDI8 | (rdn << CX_S8) | (imm8 & CX_M8) }
231func cx_subi8(rdn: i64, imm8: i64) -> i64 { return CX_T_SUBI8 | (rdn << CX_S8) | (imm8 & CX_M8) }
called by 1: cx_imm8_add_sub
233func cx_dpr(base: i64, rdn: i64, rm: i64) -> i64 { return base | (rm << CX_S3) | rdn }
235func cx_shi(base: i64, rd: i64, rm: i64, imm5: i64) -> i64 { return base | (imm5 << CX_S6) | (rm << CX_S3) | rd }
237func cx_lsi5(base: i64, rt: i64, rn: i64, imm5: i64) -> i64 { return base | (imm5 << CX_S6) | (rn << CX_S3) | rt }
called by 1: cx_load_store
238func cx_push(list8: i64) -> i64 { return CX_T_PUSH | (list8 & CX_M8) }
called by 1: cx_push_pop
239func cx_pop(list8: i64) -> i64 { return CX_T_POP | (list8 & CX_M8) }
called by 1: cx_push_pop
240func cx_bcond(cond: i64, hwoff: i64) -> i64 { return CX_T_BCOND | (cond << CX_S8) | (hwoff & CX_M8) }
241func cx_b(hwoff: i64) -> i64 { return CX_T_B | (hwoff & CX_M11) }
243func cx_cbz(rn: i64, hwoff: i64) -> i64 { return CX_T_CBZ | (((hwoff >> CX_S5) & 1) << CX_S9) | ((hwoff & CX_M5) << CX_S3) | rn }
called by 1: cx_cbz_taken
245func cx_movw_hw1(imm16: i64) -> i64 { return CX_T_MOVW | (((imm16 >> CX_S11) & 1) << CX_S10) | ((imm16 >> CX_S12) & CX_M4) }
246func cx_movw_hw2(rd: i64, imm16: i64) -> i64 { return (((imm16 >> CX_S8) & CX_M3) << CX_S12) | (rd << CX_S8) | (imm16 & CX_M8) }
248func cx_mla_hw1(rn: i64) -> i64 { return CX_T_MLA | rn }
called by 1: cx_thumb2_mla
249func cx_mla_hw2(rd: i64, ra: i64, rm: i64) -> i64 { return (ra << CX_S12) | (rd << CX_S8) | rm }
called by 1: cx_thumb2_mla
254func cx_hwoff(here: i64, target: i64) -> i64
262func cx_classify(got: i64, want: i64) -> i64
called by 2: cx_reportmain
270func cx_outcome_name(o: i64) -> *u8
called by 2: cx_reportmain
280func cx_report(kat: *u8, got: i64, want: i64, bx: *i64) -> i64
316func cx_imm_arith() -> i64
329func cx_sub() -> i64
342func cx_imm8_add_sub() -> i64
355func cx_logic() -> i64
371func cx_shift_logical() -> i64
381func cx_shift_arith() -> i64
394func cx_mul() -> i64
407func cx_branch_loop() -> i64
427func cx_signed_cond() -> i64
450func cx_cbz_taken() -> i64
473func cx_thumb2_movw() -> i64
484func cx_thumb2_mla() -> i64
502func cx_load_store() -> i64
517func cx_push_pop() -> i64
532func cx_udf_refused() -> i64
543func cx_fault_entry() -> i64
called by 1: main calls 2: cx_guestemu_cortexm_run_mem
558func cx_match_at(buf: *u8, n: i64, p: i64, s: *u8) -> i64
called by 1: cx_ratchet_read
572func cx_digits_at(buf: *u8, n: i64, p0: i64) -> i64
called by 1: cx_ratchet_read
596func cx_ratchet_read() -> i64
628func cx_ratchet_write(n: i64) -> i64
645func main(argc: i64, argv: *i64) -> i64