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}