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/route-ddr-transition.ts

/** Existing winding solver with a preverified layer transition. */
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 {prepareDdrHostSignalProjection} from './prepare-ddr-host-signal-projection'
import {loadDdrSupportRoutingContext} from './ddr-support-routing-context'
import {checkHostTerminalContract} from './route-ddr-sequential'
const {routeViaMinimalWindingAlternativesSteps}=await import(resolve('node_modules/@tscircuit/fanout-solver/lib/route-via-minimal-winding.ts'))
const [capture,integrated,transitionDir,out,stateArg]=process.argv.slice(2)
const maximumSearchStates=stateArg===undefined?100000:Number(stateArg)
if(!Number.isInteger(maximumSearchStates)||maximumSearchStates<1000||maximumSearchStates>1000000)throw Error('Search state budget must be1000–1000000')
if(!capture||!integrated||!transitionDir||!out)throw Error('Usage: capture integrated transition-plan-directory output')
const read=(p:string)=>JSON.parse(readFileSync(p,'utf8')),hash=(x:any)=>createHash('sha256').update(JSON.stringify(x)).digest('hex')
const {captureHash}=verifyDdrCapture(capture),original=read(resolve(capture,'unrouted.circuit.json')),host=read(resolve(integrated,'host-bundle.json')),circuit=read(resolve(integrated,'candidate.circuit.json')),plan=read(resolve(transitionDir,'transition-plan.json')),planes=read(resolve(transitionDir,'planes.json')),input=read(resolve(capture,'routing-input.json'))
if(plan.captureHash!==captureHash||plan.parentCircuitSha256!==hash(circuit)||plan.hostTracesSha256!==hash(host.traces)||plan.accepted.length!==1)throw Error('Transition provenance mismatch')
const t=plan.accepted[0],connection=plan.connection,context=await loadDdrSupportRoutingContext(capture,resolve(integrated,'candidate.circuit.json'),original,host.traces,captureHash),fixed=[...context.fixed.filter((e:any)=>e.type!=='pcb_copper_pour'),...planes]
const baseline=verifyDdrSystemCopper(fixed,[...host.traces,t.trace],input.connections,{})
if(baseline.errors.length||baseline.violations.length||!baseline.angles.valid||baseline.joinedBends.length)throw Error('Transition no longer physically valid')
const projection=prepareDdrHostSignalProjection(capture),inverse:Record<string,string>={top:'top',inner1:'inner2',inner2:'inner4',bottom:'inner6'},srj:any={...input,traces:host.traces,obstacles:[...projection.input.obstacles.map((o:any)=>({...o,layers:o.layers.map((l:string)=>inverse[l])})),...context.obstacles]}
// Start at the RAM escape so its actual outward tangent is preserved. End at
// the verified CPU via, where the layer transition terminates the planar run.
const source=t.target,target={...t.via,layer:t.target.layer}
const ramExit=original.find((e:any)=>e.type==='pcb_breakout_point'&&e.pcb_breakout_point_id===source.pointId)
const ramTrace=original.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===ramExit?.source_trace_id&&e.route.at(-1)?.layer===source.layer&&Math.hypot(e.route.at(-1).x-source.x,e.route.at(-1).y-source.y)<1e-7)
if(!ramTrace)throw Error('Missing exact RAM escape copper')
const prev=[...ramTrace.route].reverse().find((p:any)=>p.route_type==='wire'&&p.layer===source.layer&&Math.hypot(p.x-source.x,p.y-source.y)>1e-7)
if(!prev)throw Error('Missing RAM escape tangent')
const len=Math.hypot(source.x-prev.x,source.y-prev.y),collar={x:source.x+.2*(source.x-prev.x)/len,y:source.y+.2*(source.y-prev.y)/len}
const sourceObstacle=srj.obstacles.find((o:any)=>o.connectedTo.includes(connection.name)&&o.layers.includes(source.layer)&&Math.abs(o.center.x-source.x)<=o.width/2+1e-7&&Math.abs(o.center.y-source.y)<=o.height/2+1e-7)
if(!sourceObstacle)throw Error('Missing real source obstacle')
const prepared:any={connection,connectionIndex:0,sourcePoint:{...source,pcb_port_id:source.pointId},sourcePointIndex:connection.pointsToConnect.findIndex((p:any)=>p.pointId===source.pointId),sourceLayer:source.layer,sourceObstacle,targetPoint:target}
const bus:any={busId:connection.name,direction:'right',exitEdge:'right',termination:{type:'boundary'},connections:[prepared],componentId:'actual-RAM-DDR-exit',componentObstacles:[sourceObstacle],componentBounds:input.bounds,sharedBoundary:{...input.bounds,maxX:Math.max(4,t.source.x)},xCoordinates:[source.x],yCoordinates:[source.y],pitchX:.8,pitchY:.8}
const params:any={srj,bus,targetLayer:target.layer,terminals:[{connection:prepared,viaPoint:collar,exitPoint:target}],acceptedPlans:[],layerNames:['top',...Array.from({length:8},(_,i)=>`inner${i+1}`),'bottom'],traceWidth:.12,viaDiameter:.4572,viaHoleDiameter:.254,clearance:.1016,allowBlindAndBuriedVias:false,allowSourceLayerRouting:true,gridStep:.1,maximumRouteOrderAttempts:1,maximumSearchStates,heuristicWeight:1.2,sourceEscapePaths:new Map([[0,[source,collar]]])}
mkdirSync(out,{recursive:true});const write=(name:string,value:any)=>writeFileSync(resolve(out,name),JSON.stringify(value,null,2)+'\n'),started=Date.now(),steps=routeViaMinimalWindingAlternativesSteps(params,1),progress:any[]=[];let result:any=[]
while(true){if(Date.now()-started>55000){steps.return([]);break}const step=steps.next();if(step.done){result=step.value;break}progress.push({...step.value,visualization:undefined});write('progress.json',progress)}
const reversedTransition=[...t.trace.route].reverse().map((p:any)=>p.route_type==='via'?{...p,from_layer:p.to_layer,to_layer:p.from_layer}:p)
const traces=(result[0]??[]).map((p:any)=>({...p.trace,route:[...p.trace.route,...reversedTransition],source_trace_id:connection.source_trace_id,connectsTo:connection.pointsToConnect.map((p:any)=>p.pointId)})),terminal=checkHostTerminalContract(traces,[connection]),physical=verifyDdrSystemCopper(fixed,[...host.traces,...traces],input.connections,{})
const accepted=traces.length===1&&terminal.valid&&!physical.errors.length&&!physical.violations.length&&physical.angles.valid&&!physical.joinedBends.length&&physical.connectivity.some(c=>c.name===connection.name&&c.connected)
write('report.json',{captureHash,accepted,terminal,physical,source,collar,target,planningRegion:bus.sharedBoundary,transitionPlanSha256:hash(plan),maximumSearchStates,elapsedSeconds:(Date.now()-started)/1000,scope:'Layer-transition routing attempt; full interface timing and remaining nets unverified.'})
if(accepted){write('candidate.circuit.json',[...fixed,...host.traces,...traces]);write('host-bundle.json',{captureHash,layerSpace:'physical',traces:[...host.traces,...traces]})}
console.log(JSON.stringify({accepted,alternatives:result.length,errors:physical.errors.length,violations:physical.violations.length,angles:physical.angles.violations.length,joinedBends:physical.joinedBends.length}));if(!accepted)process.exitCode=1