code wiki / _hdl_build / nx_isa_spec_test.nx

nx_isa_spec_test.nx source

↩ module page · 131 lines · 6318 B

1// nx_isa_spec_test.nx -- prove the SPEC-DRIVEN encoder: (1) it reproduces the 2// oracle-verified KAT words (the same ones riscv64-as emits, per nx_emu_rv64_test), 3// (2) instructions added by DATA (xor, or) encode correctly, and (3) a program the 4// SEARCH authored, lowered THROUGH the spec table to BOTH RV64 and AArch64, runs 5// correctly on the sovereign emulators. No per-instruction encoder was hand-written 6// -- each instruction is a data row + one shared format assembler. 7// 8// Known answer: KATs match, both arches execute x*C for the searched constants, 9// exit 0. 10 11import "nx_isa_spec.nx" 12import "nx_emu_rv64.nx" 13import "nx_emu_arm64.nx" 14 15func is_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 16func is_num(v: i64) -> i64 { 17 let b: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m } 18 let t: *u8 = sys_mmap(28); var k: i64 = 0 19 if m == 0 { t[0] = 48; k = 1 } 20 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 } 21 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 } 22 sys_write(1, b, k); return 0 23} 24func is_put_w(code: *u8, o: i64, w: i64) -> i64 { 25 code[o] = w & 0xff; code[o+1] = (w >> 8) & 0xff; code[o+2] = (w >> 16) & 0xff; code[o+3] = (w >> 24) & 0xff 26 return o + 4 27} 28 29// the GENERATOR (search): cheapest (x<<a) op (x<<b) == x*C. 30func is_eval(a: i64, op: i64, b: i64, x: i64) -> i64 { if op == 0 { return (x << a) + (x << b) } return (x << a) - (x << b) } 31func is_best(C: i64, out: *i64) -> i64 { 32 var a: i64 = 0 33 while a < 12 { 34 var b: i64 = 0 35 while b < 12 { 36 var op: i64 = 0 37 while op < 2 { 38 var ok: i64 = 1 39 var s: i64 = 19088743; var t: i64 = 0 40 while t < 20 { s = s * 6364136223846793005 + 1442695040888963407; if is_eval(a, op, b, s) != s * C { ok = 0 } t = t + 1 } 41 if ok == 1 { let c: i64 = 1 + a + b + b 42 if out[3] < 0 { out[0]=a; out[1]=op; out[2]=b; out[3]=c } else { if c < out[3] { out[0]=a; out[1]=op; out[2]=b; out[3]=c } } } 43 op = op + 1 44 } 45 b = b + 1 46 } 47 a = a + 1 48 } 49 if out[3] < 0 { return 0 } 50 return 1 51} 52 53// assemble x*C (plan a,op,b) for RV64 from the SPEC TABLE; run; return result. 54func is_run_rv(x: i64, a: i64, op: i64, b: i64) -> i64 { 55 let code: *u8 = sys_mmap(64); var o: i64 = 0 56 o = is_put_w(code, o, isa_emit(I_RV_ADDI, 11, 0, 0, x)) 57 o = is_put_w(code, o, isa_emit(I_RV_SLLI, 5, 11, 0, a)) 58 o = is_put_w(code, o, isa_emit(I_RV_SLLI, 6, 11, 0, b)) 59 if op == 0 { o = is_put_w(code, o, isa_emit(I_RV_ADD, 10, 5, 6, 0)) } else { o = is_put_w(code, o, isa_emit(I_RV_SUB, 10, 5, 6, 0)) } 60 o = is_put_w(code, o, isa_emit(I_RV_ADDI, 17, 0, 0, 93)) 61 o = is_put_w(code, o, isa_emit(I_RV_ECALL, 0, 0, 0, 0)) 62 return emu_rv64_run(code, o) 63} 64// same for AArch64 from the SPEC TABLE. 65func is_run_a64(x: i64, a: i64, op: i64, b: i64) -> i64 { 66 let code: *u8 = sys_mmap(64); var o: i64 = 0 67 o = is_put_w(code, o, isa_emit(I_A64_MOVZ, 1, 0, 0, x)) 68 o = is_put_w(code, o, isa_emit(I_A64_ADD, 9, 31, 1, a)) 69 if op == 0 { o = is_put_w(code, o, isa_emit(I_A64_ADD, 0, 9, 1, b)) } else { o = is_put_w(code, o, isa_emit(I_A64_SUB, 0, 9, 1, b)) } 70 o = is_put_w(code, o, isa_emit(I_A64_MOVZ, 8, 0, 0, 93)) 71 o = is_put_w(code, o, isa_emit(I_A64_SVC, 0, 0, 0, 0)) 72 return emu_arm64_run(code, o) 73} 74 75func main() -> i64 { 76 is_puts("=== SPEC-DRIVEN encoder: data rows + one assembler, multi-arch ===\n" as *u8) 77 var katfail: i64 = 0 78 79 // (1) oracle-verified KAT words (same as nx_emu_rv64_test / riscv64-as). 80 if isa_emit(I_RV_ADDI, 10, 0, 0, 40) != 0x02800513 { katfail = katfail + 1 } // addi a0,zero,40 81 if isa_emit(I_RV_ADD, 10, 10, 5, 0) != 0x00550533 { katfail = katfail + 1 } // add a0,a0,t0 82 if isa_emit(I_RV_SUB, 10, 10, 5, 0) != 0x40550533 { katfail = katfail + 1 } // sub a0,a0,t0 83 if isa_emit(I_RV_ECALL, 0, 0, 0, 0) != 0x73 { katfail = katfail + 1 } // ecall 84 if isa_emit(I_A64_SVC, 0, 0, 0, 0) != 0xD4000001 { katfail = katfail + 1 } // svc #0 85 // (2) instructions added by DATA (no new encoder code) -- xor / or, manual-checked. 86 if isa_emit(I_RV_XOR, 10, 10, 5, 0) != 0x00554533 { katfail = katfail + 1 } // xor a0,a0,t0 87 if isa_emit(I_RV_OR, 10, 10, 5, 0) != 0x00556533 { katfail = katfail + 1 } // or a0,a0,t0 88 is_puts(" KAT + new-by-data encodings mismatched: " as *u8); is_num(katfail); is_puts("\n" as *u8) 89 90 // (3) the search authors x*C; the SPEC TABLE lowers it to both ISAs; run them. 91 let consts: *i64 = sys_mmap(8 * 8) as *i64 92 var n: i64 = 0 93 consts[n] = 7; n = n + 1 94 consts[n] = 9; n = n + 1 95 consts[n] = 5; n = n + 1 96 let out: *i64 = sys_mmap(32) as *i64 97 var rv_ok: i64 = 0 98 var a64_ok: i64 = 0 99 var i: i64 = 0 100 while i < n { 101 let C: i64 = consts[i] 102 out[3] = 0 - 1 103 if is_best(C, out) == 1 { 104 let a: i64 = out[0]; let op: i64 = out[1]; let b: i64 = out[2] 105 let maxx: i64 = 255 / C 106 var rok: i64 = 1 107 var aok: i64 = 1 108 var x: i64 = 0 109 while x <= maxx { 110 if is_run_rv(x, a, op, b) != x * C { rok = 0 } 111 if is_run_a64(x, a, op, b) != x * C { aok = 0 } 112 x = x + 1 113 } 114 is_puts(" x*" as *u8); is_num(C); is_puts(" (spec-assembled) " as *u8) 115 if rok == 1 { rv_ok = rv_ok + 1; is_puts("RV64:exec-ok " as *u8) } else { is_puts("RV64:FAIL " as *u8) } 116 if aok == 1 { a64_ok = a64_ok + 1; is_puts("ARM64:exec-ok\n" as *u8) } else { is_puts("ARM64:FAIL\n" as *u8) } 117 } 118 i = i + 1 119 } 120 121 is_puts("----------------------------------------------------------------\n" as *u8) 122 is_puts(" spec-driven encoder proven: RV64 " as *u8); is_num(rv_ok); is_puts("/" as *u8); is_num(n) 123 is_puts(" ARM64 " as *u8); is_num(a64_ok); is_puts("/" as *u8); is_num(n); is_puts("\n" as *u8) 124 is_puts(" the team encodes any instruction from a DATA row -- no hand-written encoder.\n" as *u8) 125 126 if katfail != 0 { sys_exit(1); return 1 } 127 if rv_ok != n { sys_exit(2); return 2 } 128 if a64_ok != n { sys_exit(3); return 3 } 129 sys_exit(0) 130 return 0 131}