code wiki / _hdl_build / nx_nhdl.nx
nx_nhdl.nx source
↩ module page · 106 lines · 5576 B
1// nx_nhdl.nx -- LIB: NHDL H1 -- the sovereign Nishi netlist format (a Verilog COMPETITOR, not a Verilog emit).
2//
3// Operator 2026-06-26: "verilog should only be a benchmark build our own verilog competitor in nishi ecosystem
4// from the hardware rung up each rung." So instead of serializing our LUT4/DFF fabric to third-party Verilog
5// (now a benchmark yardstick only), this is OUR OWN textual netlist interchange format -- flat, instance-based
6// (cells=instances, nets=wires; the canonical netlist structure per the researched Wikipedia 'Netlist' entry:
7// a header + a per-instance table, one line per entry, space-separated fields). Designed to round-trip the
8// fabric byte-exact AND to be far more compact than Verilog's verbose `assign comb[k]=(INIT>>(...))&1; //@C...`.
9//
10// GRAMMAR (v1):
11// .nhdl 1
12// .module <name> <npi> <npo> <ncells>
13// L <init> <s0> <s1> <s2> <s3> # a LUT4 cell (combinational): 16-bit init + 4 input nets
14// D <dsrc> # a DFF cell (sequential): the D-input net (init unused, Q is caller state)
15// ... (ncells lines, in cell-index order; net s<npi => primary input s, else cell (s-npi)'s output)
16// .po <net0> <net1> ... <net_{npo-1}>
17// .end
18// NEVER-BRICK (#26): pure text emit/parse, bounded, deterministic, zero hardware-state writes. license_tier: ORIGINAL
19import "nx_syscalls.nx"
20
21func nh_ws(buf: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ buf[o]=s[i]; o=o+1; i=i+1 } return o }
22func nh_wi(buf: *u8, o: i64, v: i64) -> i64 {
23 var p: i64=o; var m: i64=v
24 if m<0 { buf[p]=45 as u8; p=p+1; m=0-m }
25 if m==0 { buf[p]=48 as u8; return p+1 }
26 let t: *u8=sys_mmap(28); var k: i64=0
27 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
28 var j: i64=0; while j<k { buf[p]=t[k-1-j]; p=p+1; j=j+1 }
29 return p
30}
31
32// EMIT the fabric as NHDL text into buf. Returns length.
33func nhdl_emit(buf: *u8, name: *u8, ncells: i64, npi: i64, npo: i64, kind: *i64, init: *i64, src: *i64, po: *i64) -> i64 {
34 var o: i64=0
35 o=nh_ws(buf,o,".nhdl 1\n\x00" as *u8)
36 o=nh_ws(buf,o,".module \x00" as *u8); o=nh_ws(buf,o,name)
37 o=nh_ws(buf,o," \x00" as *u8); o=nh_wi(buf,o,npi); o=nh_ws(buf,o," \x00" as *u8); o=nh_wi(buf,o,npo); o=nh_ws(buf,o," \x00" as *u8); o=nh_wi(buf,o,ncells); o=nh_ws(buf,o,"\n\x00" as *u8)
38 var k: i64=0
39 while k<ncells {
40 if kind[k]==1 {
41 o=nh_ws(buf,o,"D \x00" as *u8); o=nh_wi(buf,o,src[k*4+0]); o=nh_ws(buf,o,"\n\x00" as *u8)
42 } else {
43 o=nh_ws(buf,o,"L \x00" as *u8); o=nh_wi(buf,o,init[k])
44 o=nh_ws(buf,o," \x00" as *u8); o=nh_wi(buf,o,src[k*4+0])
45 o=nh_ws(buf,o," \x00" as *u8); o=nh_wi(buf,o,src[k*4+1])
46 o=nh_ws(buf,o," \x00" as *u8); o=nh_wi(buf,o,src[k*4+2])
47 o=nh_ws(buf,o," \x00" as *u8); o=nh_wi(buf,o,src[k*4+3]); o=nh_ws(buf,o,"\n\x00" as *u8)
48 }
49 k=k+1
50 }
51 o=nh_ws(buf,o,".po\x00" as *u8)
52 var p: i64=0; while p<npo { o=nh_ws(buf,o," \x00" as *u8); o=nh_wi(buf,o,po[p]); p=p+1 }
53 o=nh_ws(buf,o,"\n.end\n\x00" as *u8)
54 return o
55}
56
57func nh_isdig(c: i64) -> i64 { if c<48 { return 0 } if c>57 { return 0 } return 1 }
58func nh_isws(c: i64) -> i64 { if c==32 { return 1 } if c==10 { return 1 } if c==9 { return 1 } if c==13 { return 1 } return 0 }
59func nh_skip_ws(buf: *u8, p: i64, len: i64) -> i64 { var q: i64=p; var go: i64=1; while go==1 { if q<len { if nh_isws(buf[q] as i64)==1 { q=q+1 } else { go=0 } } else { go=0 } } return q }
60// skip one whitespace-delimited token (a keyword like .module / .po, or the module name)
61func nh_skip_word(buf: *u8, pp: *i64, len: i64) -> i64 {
62 var p: i64=nh_skip_ws(buf, pp[0], len)
63 var go: i64=1
64 while go==1 { if p<len { if nh_isws(buf[p] as i64)==1 { go=0 } else { p=p+1 } } else { go=0 } }
65 pp[0]=p; return 0
66}
67func nh_rd_int(buf: *u8, pp: *i64, len: i64) -> i64 {
68 var p: i64=nh_skip_ws(buf, pp[0], len)
69 var v: i64=0; var neg: i64=0
70 if p<len { if buf[p]==(45 as u8) { neg=1; p=p+1 } }
71 var go: i64=1
72 while go==1 { if p<len { if nh_isdig(buf[p] as i64)==1 { v=v*10+((buf[p] as i64)-48); p=p+1 } else { go=0 } } else { go=0 } }
73 if neg==1 { v=0-v }
74 pp[0]=p; return v
75}
76
77// PARSE NHDL text -> reconstruct kind/init/src/po (caller-allocated). npi via pnpi, npo via pnpo. Returns ncells.
78func nhdl_parse(buf: *u8, len: i64, kind: *i64, init: *i64, src: *i64, po: *i64, pnpi: *i64, pnpo: *i64) -> i64 {
79 let pp: *i64=sys_mmap(16) as *i64; pp[0]=0
80 nh_skip_word(buf, pp, len) // ".nhdl"
81 nh_skip_word(buf, pp, len) // version "1"
82 nh_skip_word(buf, pp, len) // ".module"
83 nh_skip_word(buf, pp, len) // <name>
84 let npi: i64=nh_rd_int(buf, pp, len)
85 let npo: i64=nh_rd_int(buf, pp, len)
86 let ncells: i64=nh_rd_int(buf, pp, len)
87 pnpi[0]=npi; pnpo[0]=npo
88 var k: i64=0
89 while k<ncells {
90 pp[0]=nh_skip_ws(buf, pp[0], len)
91 let kc: i64=buf[pp[0]] as i64 // 'L'(76)=LUT or 'D'(68)=DFF
92 pp[0]=pp[0]+1
93 if kc==68 {
94 kind[k]=1; init[k]=0
95 src[k*4+0]=nh_rd_int(buf, pp, len); src[k*4+1]=0; src[k*4+2]=0; src[k*4+3]=0
96 } else {
97 kind[k]=0
98 init[k]=nh_rd_int(buf, pp, len)
99 src[k*4+0]=nh_rd_int(buf, pp, len); src[k*4+1]=nh_rd_int(buf, pp, len); src[k*4+2]=nh_rd_int(buf, pp, len); src[k*4+3]=nh_rd_int(buf, pp, len)
100 }
101 k=k+1
102 }
103 nh_skip_word(buf, pp, len) // ".po"
104 var p: i64=0; while p<npo { po[p]=nh_rd_int(buf, pp, len); p=p+1 }
105 return ncells
106}