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}