code wiki / _hdl_build / nx_alu_netlist_build.nx

nx_alu_netlist_build.nx source

↩ module page · 102 lines · 3447 B

1// nx_alu_netlist_build.nx -- builds the ALU op-select netlist IN MEMORY as the 2// ONE source the gate-sim (nx_nxgate_sim.nx) verifies. 3// 4// Mirrors synth_emit_alu_gates.nx's topology exactly: 5// per op K in 1..NX_RV64IM_ALU_N-1: 6// CONST(K) opcode literal 7// subnet = KIND(a, b) KIND = nx_alu_op_to_gate_kind(K) <-- SHARED 8// match = EQ(op_in, CONST(K)) 9// cascade: 10// prev0 = CONST(0) the INVALID branch 11// prev = MUX(match_K, subnet_K, prev) for K = 1..N-1 12// result = last MUX fanout 13// 14// Because the per-op subnet KIND comes from the SAME nx_alu_op_to_gate_kind the 15// text emitter uses, nx_gsim_run over this netlist verifies the emitter's ACTUAL 16// op->kind decisions. This is the SIL-3 closure: one source, two consumers 17// (text serializer + functional sim), no hand-kept copy. 18// 19// Cells are emitted in topological order (every fanin net is driven by an 20// earlier cell), which nx_gsim_run (combinational, single forward pass) needs. 21// 22// Caller allocates cells[] (>= 128 NxGsimCell) and a vals[] net array 23// (>= n_nets i64). Net ids 0/1/2 are reserved for a / b / op_in primary inputs. 24 25import "nx_nxgate_sim.nx" 26import "nx_alu_op_kind.nx" 27import "rv64im_min_alu.nx" 28 29const NX_ALUNL_A: i64 = 0 30const NX_ALUNL_B: i64 = 1 31const NX_ALUNL_OPIN: i64 = 2 32 33struct NxAluNetlist { 34 n_cells: i64 35 n_nets: i64 36 result: i64 // net id holding the cascade result 37} 38 39func nx_alu_nl_set(cells: *NxGsimCell, idx: i64, kind: i64, 40 fanout: i64, f0: i64, f1: i64, f2: i64, val: i64) -> i64 { 41 cells[idx].kind = kind 42 cells[idx].fanout = fanout 43 cells[idx].f0 = f0 44 cells[idx].f1 = f1 45 cells[idx].f2 = f2 46 cells[idx].val = val 47 return 0 48} 49 50func nx_alu_netlist_build(cells: *NxGsimCell, info: *NxAluNetlist) -> i64 { 51 let sub_nets: *i64 = sys_mmap(8 * NX_RV64IM_ALU_N) as *i64 52 let match_nets: *i64 = sys_mmap(8 * NX_RV64IM_ALU_N) as *i64 53 54 var cell_i: i64 = 0 55 var net_i: i64 = 3 // 0=a 1=b 2=op_in are primary inputs 56 57 // ----- Phase 1: per-op CONST + subnet + match ----- 58 var op: i64 = 1 59 while op < NX_RV64IM_ALU_N { 60 let c_net: i64 = net_i 61 net_i = net_i + 1 62 nx_alu_nl_set(cells, cell_i, NX_GATE_KIND_CONST, c_net, 0 - 1, 0 - 1, 0 - 1, op) 63 cell_i = cell_i + 1 64 65 let kind: i64 = nx_alu_op_to_gate_kind(op) 66 let s_net: i64 = net_i 67 net_i = net_i + 1 68 nx_alu_nl_set(cells, cell_i, kind, s_net, NX_ALUNL_A, NX_ALUNL_B, 0 - 1, 0) 69 cell_i = cell_i + 1 70 sub_nets[op] = s_net 71 72 let m_net: i64 = net_i 73 net_i = net_i + 1 74 nx_alu_nl_set(cells, cell_i, NX_GATE_KIND_EQ, m_net, NX_ALUNL_OPIN, c_net, 0 - 1, 0) 75 cell_i = cell_i + 1 76 match_nets[op] = m_net 77 78 op = op + 1 79 } 80 81 // ----- Phase 2: cascade MUX ----- 82 let prev0: i64 = net_i 83 net_i = net_i + 1 84 nx_alu_nl_set(cells, cell_i, NX_GATE_KIND_CONST, prev0, 0 - 1, 0 - 1, 0 - 1, 0) 85 cell_i = cell_i + 1 86 87 var prev: i64 = prev0 88 op = 1 89 while op < NX_RV64IM_ALU_N { 90 let x_net: i64 = net_i 91 net_i = net_i + 1 92 nx_alu_nl_set(cells, cell_i, NX_GATE_KIND_MUX, x_net, match_nets[op], sub_nets[op], prev, 0) 93 cell_i = cell_i + 1 94 prev = x_net 95 op = op + 1 96 } 97 98 info.n_cells = cell_i 99 info.n_nets = net_i 100 info.result = prev 101 return 0 102}