0hmX/am3352
This code suite comprises TypeScript scripts that analyze, verify, and assemble complex DDR memory interface hardware, focusing on physical routing, via and pad placement, electrical clearance, and physical constraints, often involving precise geometric calculations and consistent provenance tracking.
- Version
- 1.0.5
- License
- unset
- Stars
- 0
scripts/plan-ddr-data-transition.ts
/** Bounded CPU-side layer-transition candidates for a declared data connection.
* Conventional full-depth barrel and explicit voids on every reference plane. */
import {readFileSync,writeFileSync,mkdirSync} from 'node:fs'
import {resolve} from 'node:path'
import {createHash} from 'node:crypto'
import {verifyDdrCapture} from './ddr-capture-provenance'
import {verifyDdrSystemCopper} from './check-ddr-system-copper'
import {planDdrGroundAntipads} from './ddr-ground-plane-antipads'
const [capture,integrated,signalName,out,sideArg]=process.argv.slice(2)
if(!capture||!integrated||!signalName||!out)throw Error('Usage: capture integrated-dir CPU-signal output')
const signs=sideArg===undefined?[-1,1]:sideArg==='above'?[1]:sideArg==='below'?[-1]:[]
if(!signs.length)throw Error('Transition side must be above or below')
const read=(p:string)=>JSON.parse(readFileSync(p,'utf8')),hash=(x:any)=>createHash('sha256').update(JSON.stringify(x)).digest('hex')
const {captureHash}=verifyDdrCapture(capture),circuit=read(resolve(integrated,'candidate.circuit.json')),host=read(resolve(integrated,'host-bundle.json')),report=read(resolve(integrated,'report.json')),input=read(resolve(capture,'routing-input.json')),map=read(resolve(capture,'signal-map.json'))
if(host.captureHash!==captureHash||report.captureHash!==captureHash||hash(host.traces)!==report.hostTracesSha256)throw Error('Integrated provenance mismatch')
const entry=map.find((m:any)=>m.cpuSignal===signalName),connection=input.connections.find((c:any)=>c.source_trace_id===entry?.sourceTraceId)
if(!connection||connection.pointsToConnect.length!==2)throw Error('Expected two-point data connection')
if(host.traces.some((t:any)=>t.connection_name===connection.name))throw Error('Data net already has host routing')
const [ram,cpu]=[...connection.pointsToConnect].sort((a:any,b:any)=>a.x-b.x)
if(cpu.layer===ram.layer||!['inner2','inner4'].includes(ram.layer))throw Error('Expected a DDR byte-layer transition')
const planes=circuit.filter((e:any)=>e.type==='pcb_copper_pour'),ids=new Set(host.traces.map((t:any)=>t.pcb_trace_id)),fixed=circuit.filter((e:any)=>e.type!=='pcb_copper_pour'&&!ids.has(e.pcb_trace_id)),attempts:any[]=[],accepted:any[]=[]
mkdirSync(out,{recursive:true})
search:for(const sign of signs)for(const dx of[.4,.6,.8,1,1.2,1.4,1.6,1.8,2,2.4])for(const dy of[.4,.8,1.2,1.6,2]){
const collar={x:cpu.x-.2,y:cpu.y},via={x:cpu.x-dx,y:cpu.y+sign*dy},ax=collar.x-via.x,ay=Math.abs(via.y-collar.y),m=Math.min(ax,ay),corner={x:collar.x-m,y:collar.y+sign*m}
const points=[cpu,collar,corner,via].filter((p,i,a)=>!i||Math.hypot(p.x-a[i-1].x,p.y-a[i-1].y)>1e-8)
const trace={type:'pcb_trace',pcb_trace_id:`planned_transition_${signalName}`,source_trace_id:connection.source_trace_id,connection_name:connection.name,route:[...points.map(p=>({route_type:'wire',x:p.x,y:p.y,layer:cpu.layer,width:.12})),{route_type:'via',...via,from_layer:cpu.layer,to_layer:ram.layer,via_diameter:.4572,via_hole_diameter:.254},{route_type:'wire',...via,layer:ram.layer,width:.12}]}
const conductor=verifyDdrSystemCopper(fixed,[...host.traces,trace],input.connections,{})
if(conductor.errors.length||conductor.violations.length||!conductor.angles.valid||conductor.joinedBends.length){attempts.push({dx,dy,sign,stage:'conductor-prefilter',errors:conductor.errors.length,violations:conductor.violations.length,angles:conductor.angles.violations.length,joins:conductor.joinedBends.length});continue}
let plan:any;try{plan=planDdrGroundAntipads(planes,[{...via,net:signalName}])}catch(error){attempts.push({dx,dy,sign,reason:String(error)});continue}
const physical=verifyDdrSystemCopper([...fixed,...plan.planes],[...host.traces,trace],input.connections,{})
const clean=!physical.errors.length&&!physical.violations.length&&physical.angles.valid&&!physical.joinedBends.length&&report.physical.connectivity.filter((c:any)=>c.connected).every((c:any)=>physical.connectivity.some(n=>n.name===c.name&&n.connected))
attempts.push({dx,dy,sign,clean,errors:physical.errors.length,violations:physical.violations.length,angles:physical.angles.violations.length,joins:physical.joinedBends.length})
if(clean){accepted.push({trace,sourceEscapePoints:points,via,source:cpu,target:ram,addedAntipads:plan.added});writeFileSync(resolve(out,'planes.json'),JSON.stringify(plan.planes,null,2));writeFileSync(resolve(out,'physical-report.json'),JSON.stringify({captureHash,...physical},null,2));break search}
}
writeFileSync(resolve(out,'transition-plan.json'),JSON.stringify({captureHash,parentCircuitSha256:hash(circuit),hostTracesSha256:hash(host.traces),connection,accepted,attempts,transitionSide:sideArg??'either',scope:'Verified partial layer transition; RAM connection still needs routing. No complete-net or timing claim.'},null,2));console.log(JSON.stringify({accepted:accepted.length,attempts:attempts.length,via:accepted[0]?.via}));if(!accepted.length)process.exitCode=1