code wiki / _hdl_build / nx_nrtl.nx
nx_nrtl.nx source
↩ module page · 108 lines · 5464 B
1// nx_nrtl.nx -- LIB: NHDL H3+H4 -- sovereign RTL + SYNTHESIS (the Yosys competitor). H1/H2 gave a netlist format +
2// hierarchy that you EMIT from a fabric; this is the layer you AUTHOR in: a tiny RTL where you write bus-level
3// equations, and a SYNTHESIZER that LOWERS them to the LUT4 fabric -- reusing the proven fabric builders (ripple
4// adder, per-bit logic LUTs) + fab_append (R32a) to compose. Author 3 lines of RTL -> a 32-gate netlist, sovereignly.
5//
6// NRTL GRAMMAR (v1): single-char bus names (a,b,t,u,y...), 3-address combinational statements.
7// .nrtl 1
8// .module <name> <W> # bus width W
9// .in a b # input buses (each W bits; assigned PI nets in order)
10// .out y # the output bus
11// t = a & b # one binary op per statement: & (AND) | (OR) ^ (XOR) + (ADD), bit-parallel @ W
12// u = a ^ b
13// y = t + u
14// .end
15// SYNTHESIS: each statement -> build the op's fabric sub-network (logic LUTs or the ripple adder), fab_append it
16// wiring its inputs to the operand buses' nets; the result bus = the appended outputs. The output bus -> the POs.
17// NEVER-BRICK (#26): pure memory, bounded, deterministic, zero hardware-state writes. license_tier: ORIGINAL
18import "nx_nhdl.nx"
19import "nx_fpga_compose.nx"
20import "nx_fpga_adder.nx"
21import "nx_fpga_lut.nx"
22import "nx_fpga_fabric.nx"
23import "nx_syscalls.nx"
24
25// read one whitespace-delimited single char token (skips ws, returns the char, advances past it)
26func nr_rdc(buf: *u8, pp: *i64, len: i64) -> i64 { let p: i64=nh_skip_ws(buf,pp[0],len); let c: i64=buf[p] as i64; pp[0]=p+1; return c }
27
28// build a per-bit binary-logic-op fabric (ncells=W): cell i = a_i OP b_i. npi=2W (a[W] then b[W]). flk = FL_AND/OR/XOR.
29func build_bitop(W: i64, flk: i64, init: *i64, src: *i64, po: *i64) -> i64 {
30 let npi: i64=2*W
31 let k: i64=fl_gate_to_lut4(flk)
32 var i: i64=0
33 while i<W { init[i]=k; src[i*4+0]=i; src[i*4+1]=W+i; src[i*4+2]=i; src[i*4+3]=i; po[i]=npi+i; i=i+1 }
34 return npi
35}
36
37// SYNTHESIZE NRTL source -> a flat LUT4 fabric. Returns ncells; outnpi/outnpo/outW set; cpo filled with W output nets.
38func nrtl_synth(buf: *u8, len: i64, cinit: *i64, csrc: *i64, ckind: *i64, cpo: *i64, outnpi: *i64, outnpo: *i64, outW: *i64) -> i64 {
39 let pp: *i64=sys_mmap(16) as *i64; pp[0]=0
40 nh_skip_word(buf,pp,len) // .nrtl
41 nh_skip_word(buf,pp,len) // 1
42 nh_skip_word(buf,pp,len) // .module
43 nh_skip_word(buf,pp,len) // <name>
44 let W: i64=nh_rd_int(buf,pp,len)
45 outW[0]=W
46 let c2b: *i64=sys_mmap(8*256) as *i64; var ci: i64=0; while ci<256 { c2b[ci]=0-1; ci=ci+1 }
47 let bnet: *i64=sys_mmap(8*32*W) as *i64 // bus_net[bus*W + bit] = composed net
48 var nbus: i64=0
49 // .in -- read single-char input buses until the next '.' directive
50 nh_skip_word(buf,pp,len) // .in
51 var ninp: i64=0
52 var go1: i64=1
53 while go1==1 {
54 let p: i64=nh_skip_ws(buf,pp[0],len)
55 if (buf[p] as i64)==46 { go1=0 } else {
56 let c: i64=buf[p] as i64; pp[0]=p+1
57 c2b[c]=nbus
58 var bit: i64=0; while bit<W { bnet[nbus*W+bit]=ninp*W+bit; bit=bit+1 }
59 nbus=nbus+1; ninp=ninp+1
60 }
61 }
62 let NPI: i64=ninp*W + 1
63 let ZERO: i64=ninp*W
64 outnpi[0]=NPI; outnpo[0]=W
65 nh_skip_word(buf,pp,len) // .out
66 let outc: i64=nr_rdc(buf,pp,len)
67 // statements
68 let bi: *i64=sys_mmap(8*128) as *i64; let bs: *i64=sys_mmap(8*512) as *i64; let bpo: *i64=sys_mmap(8*64) as *i64; let bk: *i64=sys_mmap(8*128) as *i64
69 let inmap: *i64=sys_mmap(8*128) as *i64
70 var cn: i64=0
71 var go2: i64=1
72 while go2==1 {
73 let p: i64=nh_skip_ws(buf,pp[0],len)
74 if (buf[p] as i64)==46 { go2=0 } else { // '.end'
75 let dst: i64=nr_rdc(buf,pp,len)
76 let eq: i64=nr_rdc(buf,pp,len) // '='
77 let s1: i64=nr_rdc(buf,pp,len)
78 let op: i64=nr_rdc(buf,pp,len)
79 let s2: i64=nr_rdc(buf,pp,len)
80 let s1b: i64=c2b[s1]; let s2b: i64=c2b[s2]
81 var z: i64=0; while z<2*W { bk[z]=0; z=z+1 }
82 if op==43 { // '+' ADD -> ripple adder
83 let anpi: i64=fab_build_ripple_adder(W, bi, bs, bpo)
84 var b: i64=0; while b<W { inmap[b]=bnet[s1b*W+b]; inmap[W+b]=bnet[s2b*W+b]; b=b+1 }
85 inmap[2*W]=ZERO
86 let base: i64=fab_append(NPI, cinit, csrc, ckind, cn, anpi, 2*W, bi, bs, bk, inmap)
87 cn=cn+2*W
88 c2b[dst]=nbus
89 b=0; while b<W { bnet[nbus*W+b]=fab_sub_out(NPI, base, anpi, bpo[b], inmap); b=b+1 }
90 nbus=nbus+1
91 } else { // logic op
92 var flk: i64=FL_AND
93 if op==124 { flk=FL_OR }
94 if op==94 { flk=FL_XOR }
95 let bnpi: i64=build_bitop(W, flk, bi, bs, bpo)
96 var b: i64=0; while b<W { inmap[b]=bnet[s1b*W+b]; inmap[W+b]=bnet[s2b*W+b]; b=b+1 }
97 let base: i64=fab_append(NPI, cinit, csrc, ckind, cn, bnpi, W, bi, bs, bk, inmap)
98 cn=cn+W
99 c2b[dst]=nbus
100 b=0; while b<W { bnet[nbus*W+b]=fab_sub_out(NPI, base, bnpi, bpo[b], inmap); b=b+1 }
101 nbus=nbus+1
102 }
103 }
104 }
105 let ob: i64=c2b[outc]
106 var t: i64=0; while t<W { cpo[t]=bnet[ob*W+t]; t=t+1 }
107 return cn
108}