code wiki / _hdl_build / nx_rv64_snapshot_gate.nx

nx_rv64_snapshot_gate.nx source

↩ module page · 122 lines · 6114 B

1// nx_rv64_snapshot_gate.nx -- prove DETERMINISTIC snapshot/restore (F107i). Runs a compute program to halt 2// (reference hash A). Then on a second sim: run PARTWAY, snapshot, run to halt -> hash B (== A proves the 3// snapshot is non-disturbing + the continuation is deterministic); RESTORE the snapshot, run to halt -> hash 4// B2 (== A proves restore rewinds + continues byte-identically). Exact because the sim is bit-deterministic 5// (no float) -- the sovereign determinism exceed bet. Self-checking. expect_exit:0 6import "nx_syscalls.nx" 7import "nishi_hdl_primitives.nx" 8import "rv64im_min_decoder.nx" 9import "rv64im_min_alu.nx" 10import "rv64im_min_regfile.nx" 11import "rv64im_min_csr.nx" 12import "rv64im_min_clint.nx" 13import "rv64im_min_uart.nx" 14import "rv64im_min_virtio.nx" 15import "rv64im_min_sim.nx" 16import "nx_rv64_asm.nx" 17 18func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 19func g_ph(v: i64) -> i64 { 20 let b: *u8=sys_mmap(19); b[0]=48; b[1]=120; var i: i64=0 21 while i<16 { let n: i64=(v>>((15-i)*4))&15; if n<10 { b[2+i]=(48+n) as u8 } if n>=10 { b[2+i]=(87+n) as u8 } i=i+1 } 22 sys_write(1,b,18); return 0 23} 24 25const SN_MEMB: i64 = 0x80000000 26const SN_MEMS: i64 = 65536 27const SN_SCRATCH_OFF: i64 = 0x2000 28 29func state_hash(rf: *NxRv64imRegfile, mem: *u8, memsz: i64) -> i64 { 30 var h: i64 = 0 - 3750763034362895579 31 var i: i64 = 0 32 while i < 32 { 33 let v: i64 = nx_rv64im_rf_read(rf, i) 34 var k: i64 = 0 35 while k < 8 { h = (h ^ ((v >> (k*8)) & 0xff)) * 1099511628211; k = k + 1 } 36 i = i + 1 37 } 38 var m: i64 = 0 39 while m < memsz { h = (h ^ (mem[m] as i64)) * 1099511628211; m = m + 1 } 40 return h 41} 42func rd64(mem: *u8, off: i64) -> i64 { var v: i64=0; var i: i64=0; while i<8 { v=v|((mem[off+i] as i64)<<(i*8)); i=i+1 } return v } 43 44func build_prog(out: *u8) -> i64 { 45 let po: *i64 = sys_mmap(8) as *i64; po[0]=0 46 po[0]=ra_put(out, po[0], ra_i(0x13, 0, 5, 0, 0)) 47 po[0]=ra_put(out, po[0], ra_i(0x13, 0, 6, 0, 400)) 48 po[0]=ra_put(out, po[0], ra_i(0x13, 0, 7, 0, 0)) 49 let loop_off: i64 = po[0] 50 po[0]=ra_put(out, po[0], ra_i(0x13, 0, 5, 5, 1)) 51 po[0]=ra_put(out, po[0], ra_i(0x13, 0, 7, 7, 3)) 52 let bp: i64 = po[0] 53 po[0]=ra_put(out, po[0], ra_b(4, 5, 6, loop_off - bp)) 54 po[0]=ra_put(out, po[0], ra_u(0x37, 15, 0x80002)) 55 po[0]=ra_put(out, po[0], ra_i(0x13, 1, 15, 15, 32)) 56 po[0]=ra_put(out, po[0], ra_i(0x13, 5, 15, 15, 32)) 57 po[0]=ra_put(out, po[0], ra_s(0x23, 3, 15, 7, 0)) 58 po[0]=ra_put(out, po[0], ra_u(0x37, 10, 0x100)) 59 po[0]=ra_put(out, po[0], ra_u(0x37, 11, 0x5)) 60 po[0]=ra_put(out, po[0], ra_i(0x13, 0, 11, 11, 0x555)) 61 po[0]=ra_put(out, po[0], ra_s(0x23, 2, 10, 11, 0)) 62 return po[0] 63} 64 65func mk_sim(code: *u8, nb: i64, out_rf: *i64, out_mem: *i64) -> i64 { 66 let rf_st: *i64=sys_mmap(8*NX_RV64IM_RF_N_REGS) as *i64; let csr_st: *i64=sys_mmap(8*NX_CSR_SLOT_N) as *i64 67 let clint_st: *i64=sys_mmap(8*NX_CLINT_SLOT_N) as *i64; let uart_st: *i64=sys_mmap(8*NX_UART_SLOT_N) as *i64 68 let tx: *u8=sys_mmap(256); let mem: *u8=sys_mmap(SN_MEMS) 69 let rf: *NxRv64imRegfile=sys_mmap(64) as *NxRv64imRegfile; let csr: *NxRv64imCsrFile=sys_mmap(64) as *NxRv64imCsrFile 70 let clint: *NxClint=sys_mmap(64) as *NxClint; let uart: *NxUart=sys_mmap(64) as *NxUart; let sim: *NxRv64imSim=sys_mmap(256) as *NxRv64imSim 71 nx_rv64im_rf_init(rf, rf_st); nx_rv64im_csr_init(csr, csr_st, 0); nx_clint_init(clint, clint_st); nx_uart_init(uart, uart_st, tx, 256) 72 nx_rv64im_sim_init(sim, rf, csr, clint, uart, SN_MEMB, mem, SN_MEMS, 0) 73 var z: i64=0; while z<SN_MEMS { mem[z]=0 as u8; z=z+1 } 74 var i: i64=0; while i<nb { mem[i]=code[i]; i=i+1 } 75 out_rf[0] = rf as i64 76 out_mem[0] = mem as i64 77 return sim as i64 78} 79 80func main() -> i64 { 81 g_puts("nx_rv64_snapshot_gate (deterministic snapshot/restore -- F107i; leverages the no-float determinism)\n" as *u8) 82 let code: *u8 = sys_mmap(4096) 83 let nb: i64 = build_prog(code) 84 85 let rfp: *i64=sys_mmap(8) as *i64; let memp: *i64=sys_mmap(8) as *i64 86 var fails: i64 = 0 87 88 let simA: *NxRv64imSim = mk_sim(code, nb, rfp, memp) as *NxRv64imSim 89 let rfA: *NxRv64imRegfile = rfp[0] as *NxRv64imRegfile; let memA: *u8 = memp[0] as *u8 90 nx_rv64im_sim_run(simA, 10000000) 91 let hash_a: i64 = state_hash(rfA, memA, SN_MEMS) 92 let t2_a: i64 = nx_rv64im_rf_read(rfA, 7) 93 let scratch_a: i64 = rd64(memA, SN_SCRATCH_OFF) 94 95 let simB: *NxRv64imSim = mk_sim(code, nb, rfp, memp) as *NxRv64imSim 96 let rfB: *NxRv64imRegfile = rfp[0] as *NxRv64imRegfile; let memB: *u8 = memp[0] as *u8 97 nx_rv64im_sim_run(simB, 600) 98 let snapbuf: *u8 = sys_mmap(NX_RV64IM_SNAP_HDR + SN_MEMS + 64) 99 nx_rv64im_sim_snapshot(simB, snapbuf) 100 nx_rv64im_sim_run(simB, 10000000) 101 let hash_b: i64 = state_hash(rfB, memB, SN_MEMS) 102 103 nx_rv64im_sim_restore(simB, snapbuf) 104 nx_rv64im_sim_run(simB, 10000000) 105 let hash_b2: i64 = state_hash(rfB, memB, SN_MEMS) 106 107 g_puts(" program computed t2="); g_ph(t2_a); g_puts(" scratch_mem="); g_ph(scratch_a); g_puts(" (expect 0x4b0=1200)\n" as *u8) 108 if t2_a != 1200 { fails=fails+1; g_puts(" FAIL program did not compute t2=1200 (test would be vacuous)\n" as *u8) } 109 if scratch_a != 1200 { fails=fails+1; g_puts(" FAIL scratch memory != 1200 (memory side-effect missing)\n" as *u8) } 110 g_puts(" hash A (uninterrupted) = "); g_ph(hash_a); g_puts("\n" as *u8) 111 g_puts(" hash B (snapshot+continue) = "); g_ph(hash_b); g_puts("\n" as *u8) 112 g_puts(" hash B2 (restore+continue) = "); g_ph(hash_b2); g_puts("\n" as *u8) 113 if hash_b != hash_a { fails=fails+1; g_puts(" FAIL snapshot disturbed execution (B != A)\n" as *u8) } 114 if hash_b2 != hash_a { fails=fails+1; g_puts(" FAIL restore+continue diverged (B2 != A)\n" as *u8) } 115 116 if fails == 0 { 117 g_puts("verdict=GREEN (snapshot non-disturbing + restore byte-identical to uninterrupted; determinism exact)\n" as *u8) 118 sys_exit(0); return 0 119 } 120 g_puts("verdict=RED ("); g_ph(fails); g_puts(" failures)\n" as *u8) 121 sys_exit(1); return 1 122}