code wiki / _hdl_build / nx_fpga_pc.nx
nx_fpga_pc.nx source
↩ module page · 67 lines · 3013 B
1// nx_fpga_pc.nx -- LIB: RUNG 13a -- the PROGRAM COUNTER as a LOADABLE fabric register (the control-flow atom).
2// A clocked W-bit register that, on each TICK, either INCREMENTS (PC+1, the default sequential flow) or LOADS a
3// branch/jump target (when `load`=1). PC.D = load ? loadval : PC+1. Built on nx_fpga_seq (DFF + seq_tick).
4// PIs (npi = W+1): load[0] | loadval[1..W]. POs: the W PC bits. NEVER-BRICK (#26): bounded state, deterministic.
5// license_tier: ORIGINAL
6import "nx_fpga_seq.nx"
7import "nx_fpga_lut.nx"
8import "nx_fpga_fabric.nx"
9import "nx_syscalls.nx"
10const K_MAGIC_65535: i64 = 65535
11
12func seq_build_pc(width: i64, kind: *i64, init: *i64, src: *i64, po_src: *i64) -> i64 {
13 let npi: i64 = width + 1
14 let LOAD: i64 = 0
15 let LOADV: i64 = 1
16 let kXOR: i64 = fl_gate_to_lut4(FL_XOR)
17 let kAND: i64 = fl_gate_to_lut4(FL_AND)
18 let kMUX: i64 = fl_gate_to_lut4(FL_MUX)
19 // DFF cells 0..W-1 ; const1 cell W ; incrementer cells W+1..3W ; ldmux cells 3W+1..4W
20 var i: i64 = 0
21 while i < width {
22 kind[i]=1; init[i]=0
23 src[i*4+0] = npi + (3*width + 1 + i) // D = ldmux_i
24 src[i*4+1]=0; src[i*4+2]=0; src[i*4+3]=0
25 po_src[i] = npi + i
26 i = i + 1
27 }
28 kind[width]=0; init[width]=K_MAGIC_65535; src[width*4+0]=LOAD; src[width*4+1]=LOAD; src[width*4+2]=LOAD; src[width*4+3]=LOAD // const1
29 // incrementer (PC + 1): half-adder carry chain
30 i = 0
31 while i < width {
32 let sumc: i64 = width + 1 + 2*i
33 let cryc: i64 = width + 1 + 2*i + 1
34 let pc_i: i64 = npi + i
35 var carry: i64 = npi + width // carry_0 = const1
36 if i > 0 { carry = npi + (width + 2*i) } // carry_i = carry cell of bit i-1
37 kind[sumc]=0; init[sumc]=kXOR; src[sumc*4+0]=pc_i; src[sumc*4+1]=carry; src[sumc*4+2]=pc_i; src[sumc*4+3]=pc_i
38 kind[cryc]=0; init[cryc]=kAND; src[cryc*4+0]=pc_i; src[cryc*4+1]=carry; src[cryc*4+2]=pc_i; src[cryc*4+3]=pc_i
39 i = i + 1
40 }
41 // load mux: ldmux_i = load ? loadval_i : inc_i
42 i = 0
43 while i < width {
44 let lm: i64 = 3*width + 1 + i
45 let inc_i: i64 = npi + (width + 1 + 2*i) // incrementer sum cell of bit i
46 kind[lm]=0; init[lm]=kMUX
47 src[lm*4+0]=LOAD; src[lm*4+1]=inc_i; src[lm*4+2]=LOADV+i; src[lm*4+3]=inc_i
48 i = i + 1
49 }
50 return npi
51}
52func pc_ncells(width: i64) -> i64 { return 4*width + 1 }
53
54// read the current PC value from the register state q
55func pc_read(width: i64, q: *i64) -> i64 {
56 var s: i64 = 0; var i: i64 = 0
57 while i < width { s = s | ((q[i] & 1) << i); i = i + 1 }
58 return s
59}
60// clock the PC: load=1 -> PC<-loadval ; load=0 -> PC<-PC+1
61func pc_tick(width: i64, kind: *i64, init: *i64, src: *i64, pi: *i64, cellout: *i64, q: *i64, load: i64, loadval: i64) -> i64 {
62 pi[0] = load & 1
63 var i: i64 = 0
64 while i < width { pi[1+i] = (loadval >> i) & 1; i = i + 1 }
65 seq_tick(pc_ncells(width), width + 1, kind, init, src, pi, cellout, q)
66 return 0
67}