code wiki / _hdl_build / nx_rv64_amo_gate.nx

nx_rv64_amo_gate.nx source

↩ module page · 112 lines · 7491 B

1// nx_rv64_amo_gate.nx -- RV64A (atomics) conformance gate for the sovereign behavioral sim. 2// Closes the F107h atomics rung: proves lr/sc + amo{swap,add,and,or,xor,min,max,minu,maxu}.{w,d} 3// decode+execute correctly on rv64im_min_sim by asserting rd (old value) + memory (new value) 4// against HAND-COMPUTED expected results. Self-checking, deterministic, reproducible. expect_exit:0 5import "nx_syscalls.nx" 6import "nishi_hdl_primitives.nx" 7import "rv64im_min_decoder.nx" 8import "rv64im_min_alu.nx" 9import "rv64im_min_regfile.nx" 10import "rv64im_min_csr.nx" 11import "rv64im_min_clint.nx" 12import "rv64im_min_uart.nx" 13import "rv64im_min_virtio.nx" 14import "rv64im_min_sim.nx" 15 16func 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 } 17func g_ph(v: i64) -> i64 { 18 let b: *u8=sys_mmap(19); b[0]=48; b[1]=120; var i: i64=0 19 while i<16 { let nyb: i64=(v>>((15-i)*4))&15; if nyb<10 { b[2+i]=(48+nyb) as u8 } if nyb>=10 { b[2+i]=(87+nyb) as u8 } i=i+1 } 20 sys_write(1,b,18); return 0 21} 22func chk(name: *u8, got: i64, exp: i64, fails: *i64) -> i64 { 23 if got != exp { 24 fails[0]=fails[0]+1 25 g_puts(" FAIL "); g_puts(name); g_puts(" exp="); g_ph(exp); g_puts(" got="); g_ph(got); g_puts("\n" as *u8) 26 } 27 return 0 28} 29 30const AMO_MEMB: i64 = 0x80000000 31const AMO_MEMS: i64 = 65536 32const AMO_SCR: i64 = 0x80002000 // scratch address the amo targets 33 34// AMO instruction word: funct5[31:27] aq[26] rl[25] rs2[24:20] rs1[19:15] funct3[14:12] rd[11:7] opcode=0x2f 35func amo_enc(funct5: i64, rs2: i64, rs1: i64, funct3: i64, rd: i64) -> i64 { 36 return (funct5<<27) | (rs2<<20) | (rs1<<15) | (funct3<<12) | (rd<<7) | 0x2f 37} 38func wr64(mem: *u8, off: i64, v: i64) -> i64 { var i: i64=0; while i<8 { mem[off+i]=((v>>(i*8))&0xff) as u8; i=i+1 } return 0 } 39func 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 } 40func put_inst(mem: *u8, off: i64, inst: i64) -> i64 { 41 mem[off]=(inst&0xff) as u8; mem[off+1]=((inst>>8)&0xff) as u8; mem[off+2]=((inst>>16)&0xff) as u8; mem[off+3]=((inst>>24)&0xff) as u8; return 0 42} 43 44// execute ONE `amo<op>.<w|d> x7, x6, (x15)`: mem[SCR]=initval, x6=operand. out[0]=rd (old), out[1]=mem[SCR] (new). 45func run_amo(funct5: i64, funct3: i64, initval: i64, operand: i64, out: *i64) -> i64 { 46 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 47 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 48 let tx: *u8=sys_mmap(64); let mem: *u8=sys_mmap(AMO_MEMS) 49 let rf: *NxRv64imRegfile=sys_mmap(64) as *NxRv64imRegfile; let csr: *NxRv64imCsrFile=sys_mmap(64) as *NxRv64imCsrFile 50 let clint: *NxClint=sys_mmap(64) as *NxClint; let uart: *NxUart=sys_mmap(64) as *NxUart; let sim: *NxRv64imSim=sys_mmap(256) as *NxRv64imSim 51 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, 64) 52 nx_rv64im_sim_init(sim, rf, csr, clint, uart, AMO_MEMB, mem, AMO_MEMS, 0) 53 var z: i64=0; while z<AMO_MEMS { mem[z]=0 as u8; z=z+1 } 54 wr64(mem, AMO_SCR-AMO_MEMB, initval) 55 nx_rv64im_rf_write(rf, 15, AMO_SCR); nx_rv64im_rf_write(rf, 6, operand) 56 put_inst(mem, 0, amo_enc(funct5, 6, 15, funct3, 7)) 57 nx_rv64im_sim_step(sim) 58 out[0]=nx_rv64im_rf_read(rf, 7); out[1]=rd64(mem, AMO_SCR-AMO_MEMB) 59 return 0 60} 61 62// lr.d x7,(x15) [if do_lr] then sc.d x8,x6,(x15). out[0]=lr old, out[1]=sc result (0 ok / 1 fail), out[2]=mem[SCR]. 63func run_lrsc(initval: i64, scval: i64, do_lr: i64, out: *i64) -> i64 { 64 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 65 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 66 let tx: *u8=sys_mmap(64); let mem: *u8=sys_mmap(AMO_MEMS) 67 let rf: *NxRv64imRegfile=sys_mmap(64) as *NxRv64imRegfile; let csr: *NxRv64imCsrFile=sys_mmap(64) as *NxRv64imCsrFile 68 let clint: *NxClint=sys_mmap(64) as *NxClint; let uart: *NxUart=sys_mmap(64) as *NxUart; let sim: *NxRv64imSim=sys_mmap(256) as *NxRv64imSim 69 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, 64) 70 nx_rv64im_sim_init(sim, rf, csr, clint, uart, AMO_MEMB, mem, AMO_MEMS, 0) 71 var z: i64=0; while z<AMO_MEMS { mem[z]=0 as u8; z=z+1 } 72 wr64(mem, AMO_SCR-AMO_MEMB, initval) 73 nx_rv64im_rf_write(rf, 15, AMO_SCR); nx_rv64im_rf_write(rf, 6, scval) 74 var pcoff: i64=0 75 if do_lr==1 { put_inst(mem, 0, amo_enc(0x02, 0, 15, 3, 7)); pcoff=4 } // lr.d x7,(x15) (rs2=0) 76 put_inst(mem, pcoff, amo_enc(0x03, 6, 15, 3, 8)) // sc.d x8,x6,(x15) 77 if do_lr==1 { nx_rv64im_sim_step(sim) } 78 nx_rv64im_sim_step(sim) 79 out[0]=nx_rv64im_rf_read(rf, 7); out[1]=nx_rv64im_rf_read(rf, 8); out[2]=rd64(mem, AMO_SCR-AMO_MEMB) 80 return 0 81} 82 83func main() -> i64 { 84 g_puts("nx_rv64_amo_gate (RV64A atomics conformance on the sovereign behavioral sim)\n" as *u8) 85 let out: *i64=sys_mmap(32) as *i64 86 let fails: *i64=sys_mmap(8) as *i64; fails[0]=0 87 88 // ---- amo* .d (funct3=3) ---- 89 run_amo(0x00, 3, 100, 23, out); chk("amoadd.d/rd" as *u8, out[0], 100, fails); chk("amoadd.d/mem" as *u8, out[1], 123, fails) 90 run_amo(0x01, 3, 7, 99, out); chk("amoswap.d/rd" as *u8, out[0], 7, fails); chk("amoswap.d/mem" as *u8, out[1], 99, fails) 91 run_amo(0x0c, 3, 0xFF, 0x0F, out); chk("amoand.d/rd" as *u8, out[0], 0xFF, fails); chk("amoand.d/mem" as *u8, out[1], 0x0F, fails) 92 run_amo(0x08, 3, 0xF0, 0x0F, out); chk("amoor.d/rd" as *u8, out[0], 0xF0, fails); chk("amoor.d/mem" as *u8, out[1], 0xFF, fails) 93 run_amo(0x04, 3, 0xF0, 0x3C, out); chk("amoxor.d/rd" as *u8, out[0], 0xF0, fails); chk("amoxor.d/mem" as *u8, out[1], 0xCC, fails) 94 run_amo(0x10, 3, 10, 0-5, out); chk("amomin.d/rd" as *u8, out[0], 10, fails); chk("amomin.d/mem" as *u8, out[1], 0-5, fails) 95 run_amo(0x14, 3, 0-5, 10, out); chk("amomax.d/rd" as *u8, out[0], 0-5, fails); chk("amomax.d/mem" as *u8, out[1], 10, fails) 96 run_amo(0x18, 3, 10, 0-5, out); chk("amominu.d/rd" as *u8, out[0], 10, fails); chk("amominu.d/mem" as *u8, out[1], 10, fails) 97 run_amo(0x1c, 3, 10, 0-5, out); chk("amomaxu.d/rd" as *u8, out[0], 10, fails); chk("amomaxu.d/mem" as *u8, out[1], 0-5, fails) 98 // ---- amo* .w (funct3=2; rd sign-extended, store low-32) ---- 99 run_amo(0x00, 2, 100, 23, out); chk("amoadd.w/rd" as *u8, out[0], 100, fails); chk("amoadd.w/mem" as *u8, out[1], 123, fails) 100 run_amo(0x00, 2, 0xFFFFFFFF, 1, out); chk("amoadd.w.sext/rd" as *u8, out[0], 0-1, fails); chk("amoadd.w.sext/mem" as *u8, out[1], 0, fails) 101 // ---- lr/sc .d ---- 102 run_lrsc(42, 99, 1, out); chk("lr.d/old" as *u8, out[0], 42, fails); chk("sc.d.ok/res" as *u8, out[1], 0, fails); chk("sc.d.ok/mem" as *u8, out[2], 99, fails) 103 run_lrsc(42, 99, 0, out); chk("sc.d.nores/res" as *u8, out[1], 1, fails); chk("sc.d.nores/mem" as *u8, out[2], 42, fails) 104 105 g_puts("\n" as *u8) 106 if fails[0]==0 { 107 g_puts("verdict=GREEN (RV64A: lr/sc + 9 amo ops x {w,d} decode+execute match hand-computed reference; 27 assertions)\n" as *u8) 108 sys_exit(0); return 0 109 } 110 g_puts("verdict=RED ("); g_ph(fails[0]); g_puts(" assertion failures)\n" as *u8) 111 sys_exit(1); return 1 112}