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}