code wiki / _hdl_build / nx_nrtl_opt.nx
nx_nrtl_opt.nx source
↩ module page · 69 lines · 3864 B
1// nx_nrtl_opt.nx -- LIB: NHDL logic-OPTIMIZATION pass (closes the QoR-behind axis). The synthesizer (H4) lowers RTL
2// to gates directly = correct but UNOPTIMIZED (the scorecard's one honest 'BEHIND' vs Yosys). This is the missing
3// optimizer: two general, equivalence-preserving netlist transforms measured by GATE-COUNT REDUCTION (the metric
4// logic-opt is judged on -- cited knowledge/library/eda_logicopt.txt: "cost = literal count, correlates with area"):
5// * CSE (common-subexpression elimination): cells with identical (kind, init, canonicalized-srcs) compute the
6// same value -> merge duplicates, redirect references.
7// * DCE (dead-cell elimination): cells not in the transitive fanin of any primary output are removed.
8// Both are SAFE BY CONSTRUCTION (they never change any output) -> the optimized netlist == the original, fewer gates.
9// NEVER-BRICK (#26): pure memory, bounded, deterministic. license_tier: ORIGINAL
10import "nx_fpga_fabric.nx"
11import "nx_syscalls.nx"
12
13// canonicalize a src net through the CSE rep map: a PI passes through; a cell c -> npi + rep[c] (its canonical twin)
14func opt_remap(s: i64, npi: i64, rep: *i64) -> i64 {
15 if s<npi { return s }
16 return npi + rep[s-npi]
17}
18
19// CSE + DCE. Writes the compact optimized fabric into o_kind/o_init/o_src/o_po; o_npo set. Returns the new cell count.
20func nrtl_opt(ncells: i64, npi: i64, npo: i64, kind: *i64, init: *i64, src: *i64, po: *i64,
21 o_kind: *i64, o_init: *i64, o_src: *i64, o_po: *i64, o_npo: *i64) -> i64 {
22 let rep: *i64=sys_mmap(8*(ncells+4)) as *i64 // rep[k] = canonical cell index for cell k
23 let rsrc: *i64=sys_mmap(8*4*(ncells+4)) as *i64 // canonicalized srcs per cell
24 let canon: *i64=sys_mmap(8*(ncells+4)) as *i64; var ncanon: i64=0
25 // ---- CSE: dedup cells by (kind, init, canonicalized srcs) ----
26 var k: i64=0
27 while k<ncells {
28 let r0: i64=opt_remap(src[k*4+0], npi, rep); let r1: i64=opt_remap(src[k*4+1], npi, rep)
29 let r2: i64=opt_remap(src[k*4+2], npi, rep); let r3: i64=opt_remap(src[k*4+3], npi, rep)
30 rsrc[k*4+0]=r0; rsrc[k*4+1]=r1; rsrc[k*4+2]=r2; rsrc[k*4+3]=r3
31 var found: i64=0-1; var ci: i64=0
32 while ci<ncanon {
33 let p: i64=canon[ci]
34 if kind[p]==kind[k] { if init[p]==init[k] { if rsrc[p*4+0]==r0 { if rsrc[p*4+1]==r1 { if rsrc[p*4+2]==r2 { if rsrc[p*4+3]==r3 { found=p } } } } } }
35 ci=ci+1
36 }
37 if found>=0 { rep[k]=found } else { rep[k]=k; canon[ncanon]=k; ncanon=ncanon+1 }
38 k=k+1
39 }
40 // ---- DCE: mark cells reachable from POs (through rep), reverse-topological ----
41 let live: *i64=sys_mmap(8*(ncells+4)) as *i64; var z: i64=0; while z<ncells { live[z]=0; z=z+1 }
42 var p2: i64=0
43 while p2<npo { let s: i64=opt_remap(po[p2], npi, rep); if s>=npi { live[s-npi]=1 } p2=p2+1 }
44 var kk: i64=ncells-1
45 while kk>=0 {
46 if rep[kk]==kk { if live[kk]==1 {
47 var j: i64=0; while j<4 { let s: i64=rsrc[kk*4+j]; if s>=npi { live[s-npi]=1 } j=j+1 }
48 } }
49 kk=kk-1
50 }
51 // ---- renumber the live canonical cells into a compact fabric ----
52 let newidx: *i64=sys_mmap(8*(ncells+4)) as *i64
53 var nn: i64=0; var k2: i64=0
54 while k2<ncells { if rep[k2]==k2 { if live[k2]==1 { newidx[k2]=nn; nn=nn+1 } } k2=k2+1 }
55 var w: i64=0; k2=0
56 while k2<ncells {
57 if rep[k2]==k2 { if live[k2]==1 {
58 o_kind[w]=kind[k2]; o_init[w]=init[k2]
59 var j: i64=0
60 while j<4 { let s: i64=rsrc[k2*4+j]; if s<npi { o_src[w*4+j]=s } else { o_src[w*4+j]=npi+newidx[s-npi] } j=j+1 }
61 w=w+1
62 } }
63 k2=k2+1
64 }
65 var p3: i64=0
66 while p3<npo { let s: i64=opt_remap(po[p3], npi, rep); if s<npi { o_po[p3]=s } else { o_po[p3]=npi+newidx[s-npi] } p3=p3+1 }
67 o_npo[0]=npo
68 return nn
69}