code wiki / _hdl_build / nx_alu_select.nx

nx_alu_select.nx source

↩ module page · 163 lines · 8659 B

1// nx_alu_select.nx -- THE one ALU op-select builder, written against NxCellSink. 2// 3// Called with a MEM sink it fills an NxGsim the Verifier runs; called with a 4// TEXT sink it emits the .nxgate the shipping synth ships. Same code -> the 5// verifier proves exactly what the emitter ships (one source, two sinks). 6// 7// Topology (per op K in 1..N-1): CONST(K) opcode + subnet + EQ(op_in==K) match; 8// then a cascade MUX(match_K, subnet_K, prev). use_divider=1 makes DIV/DIVU take 9// the PROVEN restoring divider's quotient and REM/REMU its remainder (the first 10// hardware invention, in the shipped ALU); use_divider=0 keeps the single-cell 11// stub from the single-source op->kind map (the baseline that catches holes). 12// 13// na/nb/nop are pre-existing net ids for a / b / op_in in the sink's net space. 14// Returns the cascade result net id (caller wires it to the result port / records 15// it as the sim output). 16 17import "nx_cell_sink.nx" 18import "nx_alu_divider.nx" // nx_div_synth_sink 19import "nx_alu_op_kind.nx" // nx_alu_op_to_gate_kind 20import "rv64im_min_alu.nx" // NX_RV64IM_ALU_* 21import "nx_mul_wide.nx" // nx_mul_wide_sink (high-product for mulh) 22const K_MAGIC_4294967295: i64 = 4294967295 23const K_MAGIC_4294967296: i64 = 4294967296 24 25// sink mulh subnet: high 64 bits of a*b + two's-complement sign corrections. 26// mulhu (0,0) ; mulhsu (1,0) ; mulh (1,1). Matches behavioral nx_rv64im_mulh_*. 27func nx_alu_mulh_sink(k: *NxCellSink, na: i64, nb: i64, do_a: i64, do_b: i64) -> i64 { 28 let hio: *i64 = sys_mmap(8) as *i64 29 hio[0] = 0 30 let lo: i64 = nx_mul_wide_sink(k, na, nb, hio) 31 var hi: i64 = hio[0] 32 let c0: i64 = nx_sink_const(k, 64, 0) 33 if do_a == 1 { 34 let sa: i64 = nx_sink_cell(k, NX_GATE_KIND_LT, 1, na, c0, 0 - 1, 2) 35 let cora: i64 = nx_sink_cell(k, NX_GATE_KIND_MUX, 64, sa, nb, c0, 3) 36 hi = nx_sink_cell(k, NX_GATE_KIND_SUB, 64, hi, cora, 0 - 1, 2) 37 } 38 if do_b == 1 { 39 let sb: i64 = nx_sink_cell(k, NX_GATE_KIND_LT, 1, nb, c0, 0 - 1, 2) 40 let corb: i64 = nx_sink_cell(k, NX_GATE_KIND_MUX, 64, sb, na, c0, 3) 41 hi = nx_sink_cell(k, NX_GATE_KIND_SUB, 64, hi, corb, 0 - 1, 2) 42 } 43 return hi 44} 45 46// sink sign-extend of the low 32 bits (gate form of sext32). 47func nx_sext32_sink(k: *NxCellSink, v: i64) -> i64 { 48 let cmask: i64 = nx_sink_const(k, 64, K_MAGIC_4294967295) 49 let c31: i64 = nx_sink_const(k, 64, 31) 50 let c1: i64 = nx_sink_const(k, 64, 1) 51 let chi: i64 = nx_sink_const(k, 64, 0 - K_MAGIC_4294967296) 52 let c0: i64 = nx_sink_const(k, 64, 0) 53 let low: i64 = nx_sink_cell(k, NX_GATE_KIND_AND, 64, v, cmask, 0 - 1, 2) 54 let sbsh: i64 = nx_sink_cell(k, NX_GATE_KIND_SHR, 64, low, c31, 0 - 1, 2) 55 let sb: i64 = nx_sink_cell(k, NX_GATE_KIND_AND, 64, sbsh, c1, 0 - 1, 2) 56 let fill: i64 = nx_sink_cell(k, NX_GATE_KIND_MUX, 64, sb, chi, c0, 3) 57 return nx_sink_cell(k, NX_GATE_KIND_OR, 64, low, fill, 0 - 1, 2) 58} 59 60// sink W-suffix UNSIGNED div/rem (32-bit operands, sext32 result). 61func nx_wdiv_u_sink(k: *NxCellSink, na: i64, nb: i64, want_rem: i64) -> i64 { 62 let cmask: i64 = nx_sink_const(k, 64, K_MAGIC_4294967295) 63 let c0: i64 = nx_sink_const(k, 64, 0) 64 let a32: i64 = nx_sink_cell(k, NX_GATE_KIND_AND, 64, na, cmask, 0 - 1, 2) 65 let b32: i64 = nx_sink_cell(k, NX_GATE_KIND_AND, 64, nb, cmask, 0 - 1, 2) 66 let ro: *i64 = sys_mmap(8) as *i64 67 ro[0] = 0 68 let q: i64 = nx_div_synth_sink(k, a32, b32, 32, ro) 69 let r: i64 = ro[0] 70 let bz: i64 = nx_sink_cell(k, NX_GATE_KIND_EQ, 1, b32, c0, 0 - 1, 2) 71 if want_rem == 0 { 72 let qse: i64 = nx_sext32_sink(k, q) 73 let allone: i64 = nx_sink_const(k, 64, 0 - 1) 74 return nx_sink_cell(k, NX_GATE_KIND_MUX, 64, bz, allone, qse, 3) 75 } 76 let rse: i64 = nx_sext32_sink(k, r) 77 let ase: i64 = nx_sext32_sink(k, na) 78 return nx_sink_cell(k, NX_GATE_KIND_MUX, 64, bz, ase, rse, 3) 79} 80 81// sink W-suffix SIGNED div/rem (sext32 operands, abs+unsigned-divide+sign-correct). 82func nx_wdiv_s_sink(k: *NxCellSink, na: i64, nb: i64, want_rem: i64) -> i64 { 83 let cmask: i64 = nx_sink_const(k, 64, K_MAGIC_4294967295) 84 let c0: i64 = nx_sink_const(k, 64, 0) 85 let a32: i64 = nx_sext32_sink(k, na) 86 let b32: i64 = nx_sext32_sink(k, nb) 87 let sa: i64 = nx_sink_cell(k, NX_GATE_KIND_LT, 1, a32, c0, 0 - 1, 2) 88 let sb: i64 = nx_sink_cell(k, NX_GATE_KIND_LT, 1, b32, c0, 0 - 1, 2) 89 let aa: i64 = nx_sink_cell(k, NX_GATE_KIND_MUX, 64, sa, nx_sink_cell(k, NX_GATE_KIND_SUB, 64, c0, a32, 0 - 1, 2), a32, 3) 90 let bb: i64 = nx_sink_cell(k, NX_GATE_KIND_MUX, 64, sb, nx_sink_cell(k, NX_GATE_KIND_SUB, 64, c0, b32, 0 - 1, 2), b32, 3) 91 let ro: *i64 = sys_mmap(8) as *i64 92 ro[0] = 0 93 let qu: i64 = nx_div_synth_sink(k, aa, bb, 32, ro) 94 let ru: i64 = ro[0] 95 let qsign: i64 = nx_sink_cell(k, NX_GATE_KIND_XOR, 1, sa, sb, 0 - 1, 2) 96 let q: i64 = nx_sink_cell(k, NX_GATE_KIND_MUX, 64, qsign, nx_sink_cell(k, NX_GATE_KIND_SUB, 64, c0, qu, 0 - 1, 2), qu, 3) 97 let r: i64 = nx_sink_cell(k, NX_GATE_KIND_MUX, 64, sa, nx_sink_cell(k, NX_GATE_KIND_SUB, 64, c0, ru, 0 - 1, 2), ru, 3) 98 let b32low: i64 = nx_sink_cell(k, NX_GATE_KIND_AND, 64, nb, cmask, 0 - 1, 2) 99 let bz: i64 = nx_sink_cell(k, NX_GATE_KIND_EQ, 1, b32low, c0, 0 - 1, 2) 100 if want_rem == 0 { 101 let qse: i64 = nx_sext32_sink(k, q) 102 let allone: i64 = nx_sink_const(k, 64, 0 - 1) 103 return nx_sink_cell(k, NX_GATE_KIND_MUX, 64, bz, allone, qse, 3) 104 } 105 let rse: i64 = nx_sext32_sink(k, r) 106 let ase: i64 = nx_sext32_sink(k, na) 107 return nx_sink_cell(k, NX_GATE_KIND_MUX, 64, bz, ase, rse, 3) 108} 109 110func nx_alu_build_select(k: *NxCellSink, na: i64, nb: i64, nop: i64, use_divider: i64) -> i64 { 111 let sub_nets: *i64 = sys_mmap(8 * NX_RV64IM_ALU_N) as *i64 112 let match_nets: *i64 = sys_mmap(8 * NX_RV64IM_ALU_N) as *i64 113 let rem_out: *i64 = sys_mmap(8) as *i64 114 115 // ----- Phase 1: per-op CONST + subnet + match ----- 116 var op: i64 = 1 117 while op < NX_RV64IM_ALU_N { 118 let c_net: i64 = nx_sink_const(k, 8, op) 119 120 var sub: i64 = 0 - 1 121 if use_divider == 1 { 122 if op == NX_RV64IM_ALU_DIV { sub = nx_div_synth_sink(k, na, nb, 64, rem_out) } 123 if op == NX_RV64IM_ALU_DIVU { sub = nx_div_synth_sink(k, na, nb, 64, rem_out) } 124 if op == NX_RV64IM_ALU_REM { let q: i64 = nx_div_synth_sink(k, na, nb, 64, rem_out); sub = rem_out[0] } 125 if op == NX_RV64IM_ALU_REMU { let q: i64 = nx_div_synth_sink(k, na, nb, 64, rem_out); sub = rem_out[0] } 126 if op == NX_RV64IM_ALU_MULHU { sub = nx_alu_mulh_sink(k, na, nb, 0, 0) } 127 if op == NX_RV64IM_ALU_MULHSU { sub = nx_alu_mulh_sink(k, na, nb, 1, 0) } 128 if op == NX_RV64IM_ALU_MULH { sub = nx_alu_mulh_sink(k, na, nb, 1, 1) } 129 if op == NX_RV64IM_ALU_DIVUW { sub = nx_wdiv_u_sink(k, na, nb, 0) } 130 if op == NX_RV64IM_ALU_REMUW { sub = nx_wdiv_u_sink(k, na, nb, 1) } 131 if op == NX_RV64IM_ALU_DIVW { sub = nx_wdiv_s_sink(k, na, nb, 0) } 132 if op == NX_RV64IM_ALU_REMW { sub = nx_wdiv_s_sink(k, na, nb, 1) } 133 } 134 if sub < 0 { 135 let kind: i64 = nx_alu_op_to_gate_kind(op) 136 if kind >= 0 { 137 // RV64 spec: SLL/SRL/SRA take the shift amount from rs2[5:0] (low 6 bits). Mask the 138 // shift operand at the gate level so out-of-range amounts MATCH the behavioral ALU 139 // (closes the recorded rs2[5:0] shift-mask gap; in-range behavior is unchanged). The 140 // mask cells flow into BOTH the mem-sink verifier AND the shipped .nxgate emitter. 141 var bsh: i64 = nb 142 if op == NX_RV64IM_ALU_SLL { bsh = nx_sink_cell(k, NX_GATE_KIND_AND, 64, nb, nx_sink_const(k, 64, 63), 0 - 1, 2) } 143 if op == NX_RV64IM_ALU_SRL { bsh = nx_sink_cell(k, NX_GATE_KIND_AND, 64, nb, nx_sink_const(k, 64, 63), 0 - 1, 2) } 144 if op == NX_RV64IM_ALU_SRA { bsh = nx_sink_cell(k, NX_GATE_KIND_AND, 64, nb, nx_sink_const(k, 64, 63), 0 - 1, 2) } 145 sub = nx_sink_cell(k, kind, 64, na, bsh, 0 - 1, 2) 146 } 147 } 148 sub_nets[op] = sub 149 150 let m_net: i64 = nx_sink_cell(k, NX_GATE_KIND_EQ, 1, nop, c_net, 0 - 1, 2) 151 match_nets[op] = m_net 152 op = op + 1 153 } 154 155 // ----- Phase 2: cascade MUX ----- 156 var prev: i64 = nx_sink_const(k, 64, 0) 157 op = 1 158 while op < NX_RV64IM_ALU_N { 159 prev = nx_sink_cell(k, NX_GATE_KIND_MUX, 64, match_nets[op], sub_nets[op], prev, 3) 160 op = op + 1 161 } 162 return prev 163}