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}