code wiki / _hdl_build / nx_fpga_regfile.nx
nx_fpga_regfile.nx source
↩ module page · 140 lines · 6210 B
1// nx_fpga_regfile.nx -- LIB: RUNG 10 -- a REGISTER FILE on the SEQUENTIAL fabric (the core CPU storage). R
2// registers x W bits of DFF state; an addressed WRITE port (waddr,wdata,we -- clocked: reg[waddr]<-wdata on TICK
3// iff we) and an addressed combinational READ port (raddr -> reg[raddr]). Register 0 (x0) is HARDWIRED to 0
4// (its DFF D = const0; always reads 0). Address decode = ONE LUT4 per register (init 1<<r over the addr bits,
5// unused LUT pins tied to const0) -- works for R<=16 (AB<=4); R=32 needs a 2-level decode (a follow-on). Read =
6// decode-then-gated-OR (exactly one register selected). Built on nx_fpga_seq (DFF + seq_tick) + nx_fpga_lut.
7//
8// PIs (npi = 2*AB + W + 1): raddr[0..AB-1] | waddr[AB..2AB-1] | wdata[2AB..2AB+W-1] | we[2AB+W].
9// NEVER-BRICK (#26): bounded state (caller-owned q[]), bounded tick, deterministic, x0 invariant, no hw write.
10// license_tier: ORIGINAL
11import "nx_fpga_seq.nx"
12import "nx_fpga_lut.nx"
13import "nx_fpga_fabric.nx"
14import "nx_syscalls.nx"
15
16// set a LUT4 cell's 4 input sources to the AB address-bit PIs (base addr0_pi) then const0 for the rest.
17func rf_addr_inputs(src: *i64, cell: i64, addr0_pi: i64, ab: i64, const0_src: i64) -> i64 {
18 var j: i64 = 0
19 while j < 4 {
20 if j < ab { src[cell*4+j] = addr0_pi + j } else { src[cell*4+j] = const0_src }
21 j = j + 1
22 }
23 return 0
24}
25
26func seq_build_regfile(R: i64, W: i64, AB: i64, kind: *i64, init: *i64, src: *i64, po_src: *i64) -> i64 {
27 let npi: i64 = 2*AB + W + 1
28 let RADDR0: i64 = 0
29 let WADDR0: i64 = AB
30 let WDATA0: i64 = 2*AB
31 let WE: i64 = 2*AB + W
32 let kAND: i64 = fl_gate_to_lut4(FL_AND)
33 let kOR: i64 = fl_gate_to_lut4(FL_OR)
34 let kMUX: i64 = fl_gate_to_lut4(FL_MUX)
35 // ---- cell-index plan ----
36 let C0: i64 = R*W // const0
37 let WSEL: i64 = R*W + 1 // wsel_r = WSEL + r
38 let WRITE: i64 = WSEL + R // write_r = WRITE + r
39 let DBASE: i64 = WRITE + R // Dmux[r][i] = DBASE + (r-1)*W + i (r=1..R-1)
40 let RSEL: i64 = DBASE + (R-1)*W // rsel_r = RSEL + r
41 let GBASE: i64 = RSEL + R // gated[r][i] = GBASE + r*W + i
42 let OBASE: i64 = GBASE + R*W // or[i][k] = OBASE + i*(R-1) + k (k=0..R-2)
43 let const0_src: i64 = npi + C0
44
45 // const0
46 kind[C0]=0; init[C0]=0; src[C0*4+0]=0; src[C0*4+1]=0; src[C0*4+2]=0; src[C0*4+3]=0
47
48 // DFF cells (state) + their D wiring
49 var r: i64 = 0
50 while r < R {
51 var i: i64 = 0
52 while i < W {
53 let dff: i64 = r*W + i
54 kind[dff]=1; init[dff]=0
55 if r == 0 { src[dff*4+0] = const0_src } else { src[dff*4+0] = npi + (DBASE + (r-1)*W + i) }
56 src[dff*4+1]=0; src[dff*4+2]=0; src[dff*4+3]=0
57 i = i + 1
58 }
59 r = r + 1
60 }
61 // write decode: wsel_r = (waddr==r), write_r = wsel_r AND we
62 r = 0
63 while r < R {
64 let ws: i64 = WSEL + r
65 kind[ws]=0; init[ws]=(1 << r); rf_addr_inputs(src, ws, WADDR0, AB, const0_src)
66 let wr: i64 = WRITE + r
67 kind[wr]=0; init[wr]=kAND; src[wr*4+0]=npi+ws; src[wr*4+1]=WE; src[wr*4+2]=npi+ws; src[wr*4+3]=npi+ws
68 r = r + 1
69 }
70 // D-feed MUX for r=1..R-1: Dmux[r][i] = write_r ? wdata_i : reg[r][i]
71 r = 1
72 while r < R {
73 var i: i64 = 0
74 while i < W {
75 let dm: i64 = DBASE + (r-1)*W + i
76 kind[dm]=0; init[dm]=kMUX
77 src[dm*4+0]=npi+(WRITE+r); src[dm*4+1]=npi+(r*W+i); src[dm*4+2]=WDATA0+i; src[dm*4+3]=npi+(r*W+i)
78 i = i + 1
79 }
80 r = r + 1
81 }
82 // read: rsel_r = (raddr==r); gated[r][i] = rsel_r AND reg[r][i]; out_i = OR over r
83 r = 0
84 while r < R {
85 let rs: i64 = RSEL + r
86 kind[rs]=0; init[rs]=(1 << r); rf_addr_inputs(src, rs, RADDR0, AB, const0_src)
87 var i: i64 = 0
88 while i < W {
89 let g: i64 = GBASE + r*W + i
90 kind[g]=0; init[g]=kAND; src[g*4+0]=npi+rs; src[g*4+1]=npi+(r*W+i); src[g*4+2]=npi+rs; src[g*4+3]=npi+rs
91 i = i + 1
92 }
93 r = r + 1
94 }
95 // OR-reduce per bit
96 var i: i64 = 0
97 while i < W {
98 var k: i64 = 0
99 while k < R - 1 {
100 let oc: i64 = OBASE + i*(R-1) + k
101 kind[oc]=0; init[oc]=kOR
102 var in0: i64 = npi + (GBASE + 0*W + i)
103 if k > 0 { in0 = npi + (OBASE + i*(R-1) + k - 1) }
104 let in1: i64 = npi + (GBASE + (k+1)*W + i)
105 src[oc*4+0]=in0; src[oc*4+1]=in1; src[oc*4+2]=in0; src[oc*4+3]=in0
106 k = k + 1
107 }
108 po_src[i] = npi + (OBASE + i*(R-1) + (R-2))
109 i = i + 1
110 }
111 return npi
112}
113
114// total cell count for an R x W register file
115func rf_ncells(R: i64, W: i64) -> i64 { return (R*W) + 1 + R + R + (R-1)*W + R + R*W + W*(R-1) }
116
117// WRITE reg[addr] = val on a clock tick (we=1). raddr set to 0 (read port idle).
118func rf_write(R: i64, W: i64, AB: i64, kind: *i64, init: *i64, src: *i64, pi: *i64, cellout: *i64, q: *i64, addr: i64, val: i64) -> i64 {
119 var j: i64 = 0
120 while j < AB { pi[j] = 0; pi[AB+j] = (addr >> j) & 1; j = j + 1 } // raddr=0, waddr=addr
121 var i: i64 = 0
122 while i < W { pi[2*AB + i] = (val >> i) & 1; i = i + 1 } // wdata=val
123 pi[2*AB + W] = 1 // we=1
124 seq_tick(rf_ncells(R, W), 2*AB + W + 1, kind, init, src, pi, cellout, q)
125 return 0
126}
127
128// READ reg[addr] combinationally (no tick; we=0).
129func rf_read(R: i64, W: i64, AB: i64, kind: *i64, init: *i64, src: *i64, pi: *i64, cellout: *i64, q: *i64, po_src: *i64, addr: i64) -> i64 {
130 var j: i64 = 0
131 while j < AB { pi[j] = (addr >> j) & 1; pi[AB+j] = 0; j = j + 1 } // raddr=addr, waddr=0
132 var i: i64 = 0
133 while i < W { pi[2*AB + i] = 0; i = i + 1 }
134 pi[2*AB + W] = 0 // we=0 (no write)
135 seq_eval(rf_ncells(R, W), 2*AB + W + 1, kind, init, src, pi, cellout, q)
136 var s: i64 = 0
137 i = 0
138 while i < W { s = s | ((fab_po(po_src[i], 2*AB + W + 1, pi, cellout) & 1) << i); i = i + 1 }
139 return s
140}