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-current-same-layer.ts
/** Same-layer continuation from a hash-bound current physical board, using the existing winding solver. */
import{readFileSync,writeFileSync,mkdirSync}from'node:fs'
import{resolve}from'node:path'
import{createHash}from'node:crypto'
import{verifyDdrCapture}from'./ddr-capture-provenance'
import{supportCopperObstacles}from'./ddr-support-routing-context'
import{terminalOnlyFixedObstacles}from'./ddr-terminal-copper-obstacles'
import{auditCompositeHostTopology}from'./ddr-composite-routing-context'
import{auditRouteAngles}from'./check-route-angles'
import{auditDdrTraceJunctions}from'./check-ddr-system-copper'
import{objectHash}from'./improve-ddr-a9-power-launches'
import{checkHostTerminalContract}from'./route-ddr-sequential'
import{verifyDdrSystemCopper}from'./check-ddr-system-copper'
const[capture,facing,signal,out,weightArg='1.2',statesArg='300000']=process.argv.slice(2),maximumSearchStates=Number(statesArg),heuristicWeight=Number(weightArg)
if(![1,1.2].includes(heuristicWeight)||!Number.isInteger(maximumSearchStates)||maximumSearchStates<1000||maximumSearchStates>1000000)throw Error('Invalid bounded search options')
if(!capture||!facing||!out)throw Error('Usage: capture current-board CPU-signal output [weight] [states]')
const bound=new Map<string,string>(),fh=(p:string)=>createHash('sha256').update(readFileSync(p)).digest('hex'),read=(p:string)=>{p=resolve(p);bound.set(p,fh(p));return JSON.parse(readFileSync(p,'utf8'))}
const {captureHash}=verifyDdrCapture(capture),candidate=read(resolve(facing,'candidate.circuit.json')),host=read(resolve(facing,'host-bundle.json')),input=read(resolve(facing,'routing-input.json')),report=read(resolve(facing,'report.json')),map=read(resolve(capture,'signal-map.json')),nominal=read(resolve(capture,'../../ddr-integrated-ten/dqlm-audit.json'))
if(report.captureHash!==captureHash||nominal.captureHash!==captureHash||host.captureHash!==captureHash||host.layerSpace!=='physical'||report.candidateCircuitSha256!==objectHash(candidate))throw Error('Unverified current board')
for(const t of host.traces)if(objectHash(candidate.find((e:any)=>e.pcb_trace_id===t.pcb_trace_id))!==objectHash(t))throw Error('Host differs')
for(const c of input.connections)for(const p of c.pointsToConnect){const e=candidate.find((e:any)=>e.pcb_breakout_point_id===p.pointId);if(!e||e.layer!==p.layer||Math.hypot(e.x-p.x,e.y-p.y)>1e-7)throw Error('Source-owned exit differs')}
const topology0=auditCompositeHostTopology(candidate,host.traces,input.connections)
if(!topology0.valid||!auditRouteAngles(candidate.filter((e:any)=>e.type==='pcb_trace')).valid||!auditDdrTraceJunctions(candidate,input.connections).valid)throw Error('Baseline validation failed')
const ids=new Set(host.traces.map((t:any)=>t.pcb_trace_id)),fixed=candidate.filter((e:any)=>!ids.has(e.pcb_trace_id)),context={topology:topology0,evidence:{inputHashes:Object.fromEntries(bound),escapeReport:report},invalidation:null,assertUnchanged:()=>{verifyDdrCapture(capture);for(const[p,h]of bound)if(fh(p)!==h)throw Error('Input changed during route')}},entry=map.find((m:any)=>m.cpuSignal===signal),connection=input.connections.find((c:any)=>c.source_trace_id===entry?.sourceTraceId)
input.traces=host.traces
if(!connection||connection.pointsToConnect.length!==2||host.traces.some((t:any)=>t.connection_name===connection.name))throw Error('Requires one unhosted two-terminal signal')
const[source,target]=[...connection.pointsToConnect].sort((a:any,b:any)=>a.x-b.x),layer=source.layer
if(layer!==target.layer||!['inner2','inner4','inner6'].includes(layer))throw Error('Requires same-layer signal terminals')
const terminalProjection=terminalOnlyFixedObstacles(fixed,connection);input.obstacles=terminalProjection.obstacles
const reservedCollars=process.argv.filter(a=>a.startsWith('--reserve-collar=')).map(a=>{const wanted=a.split('=')[1],entry=map.find((m:any)=>m.cpuSignal===wanted),net=input.connections.find((n:any)=>n.source_trace_id===entry?.sourceTraceId);if(!net||wanted===signal||host.traces.some((t:any)=>t.connection_name===net.name))throw Error('Expected another unhosted collar');const p=net.pointsToConnect.reduce((a:any,b:any)=>a.x<b.x?a:b),exit=candidate.find((e:any)=>e.pcb_breakout_point_id===p.pointId),trace=fixed.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===exit.source_trace_id),end=trace.route.at(-1),prev=[...trace.route].reverse().find((q:any)=>q.route_type==='wire'&&q.layer===end.layer&&Math.hypot(q.x-end.x,q.y-end.y)>1e-7),d=Math.hypot(end.x-prev.x,end.y-prev.y),extension={route_type:'wire',x:end.x+.2*(end.x-prev.x)/d,y:end.y+.2*(end.y-prev.y)/d,layer:end.layer,width:.12},projection={type:'pcb_trace',pcb_trace_id:`reserved-collar-${wanted}`,route:[{...end,width:.12},extension]};return{signal:wanted,originalTrace:trace,extendedTrace:{...trace,route:[...trace.route,extension]},projection}})
input.obstacles.push(...reservedCollars.flatMap(r=>supportCopperObstacles([r.projection]).map(o=>({...o,...(o.obstacleId.endsWith('_cap')?{shape:'circle'}:{}),connectedTo:[`reserved:${r.signal}:outward-collar`]}))))
const exit=candidate.find((e:any)=>e.pcb_breakout_point_id===source.pointId),saved=candidate.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===exit.source_trace_id&&e.route.at(-1)?.layer===layer&&Math.hypot(e.route.at(-1).x-source.x,e.route.at(-1).y-source.y)<1e-7)
if(!saved)throw Error('Missing actual RAM endpoint copper')
const previous=[...saved.route].reverse().find((p:any)=>p.route_type==='wire'&&p.layer===layer&&Math.hypot(p.x-source.x,p.y-source.y)>1e-7),d=Math.hypot(source.x-previous.x,source.y-previous.y),collar={x:source.x+.2*(source.x-previous.x)/d,y:source.y+.2*(source.y-previous.y)/d}
const sourceObstacle=input.obstacles.find((o:any)=>o.connectedTo.includes(connection.name)&&o.layers.includes(layer)&&Math.hypot(o.center.x-source.x,o.center.y-source.y)<1e-7)
if(!sourceObstacle)throw Error('Missing source-owned endpoint obstacle')
const prepared:any={connection,connectionIndex:0,sourcePoint:{...source,pcb_port_id:source.pointId},sourcePointIndex:connection.pointsToConnect.indexOf(source),sourceLayer:layer,sourceObstacle,targetPoint:target},bounds={...input.bounds,maxX:4}
const bus:any={busId:signal,direction:'right',exitEdge:'right',termination:{type:'boundary'},connections:[prepared],componentId:'RAM-facing-exit',componentObstacles:[sourceObstacle],componentBounds:input.bounds,sharedBoundary:bounds,xCoordinates:[source.x],yCoordinates:[source.y],pitchX:.8,pitchY:.8}
const{routeViaMinimalWindingAlternativesSteps}=await import(resolve('node_modules/@tscircuit/fanout-solver/lib/route-via-minimal-winding.ts'))
const params:any={srj:input,bus,targetLayer: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,sourceEscapePaths:new Map([[0,[source,collar]]])}
mkdirSync(out,{recursive:true});const write=(n:string,v:any)=>writeFileSync(resolve(out,n),JSON.stringify(v,null,2)+'\n');write('seed.circuit.json',candidate);write('seed-host-bundle.json',host);write('seed-topology.json',context.topology);write('input-evidence.json',{...context.evidence,signal,source,target,collar,reservedCollars,bounds,maximumSearchStates,heuristicWeight,terminalProjectionWitnesses:terminalProjection.witnesses,invalidation:context.invalidation})
const started=Date.now(),steps=routeViaMinimalWindingAlternativesSteps(params,1),progress:any[]=[];let alternatives:any[]=[],finished=false
while(Date.now()-started<55000){const s=steps.next();if(s.done){alternatives=s.value;finished=true;break}progress.push({...s.value,visualization:undefined});write('progress.json',progress)}if(!finished)steps.return([])
const traces=(alternatives[0]??[]).map((p:any)=>({...p.trace,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,{})
let lengths:any
if(traces.length===1){const planar=(route:any[])=>route.reduce((n:number,p:any,i:number)=>{const q=route[i-1];return n+(p.route_type==='wire'&&q?.route_type==='wire'&&p.layer===q.layer?Math.hypot(p.x-q.x,p.y-q.y):0)},0),cpuExit=candidate.find((e:any)=>e.pcb_breakout_point_id===target.pointId),cpu=candidate.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===cpuExit.source_trace_id&&e.route.at(-1)?.layer===layer&&Math.hypot(e.route.at(-1).x-target.x,e.route.at(-1).y-target.y)<1e-7);if(!cpu)throw Error('Missing actual CPU escape');lengths={ramMm:planar(saved.route),hostMm:planar(traces[0].route),cpuMm:planar(cpu.route),nominalMm:nominal.bytes.find((b:any)=>b.byte===connection.ramByte).dqlmPairedDataMaximumMm};lengths.fullPlanarMm=lengths.ramMm+lengths.hostMm+lengths.cpuMm}
const allAngles=auditRouteAngles([...candidate,...traces].filter((e:any)=>e.type==='pcb_trace')),allJunctions=auditDdrTraceJunctions([...candidate,...traces],input.connections),allTerminal=checkHostTerminalContract([...host.traces,...traces],input.connections.filter((c:any)=>[...host.traces,...traces].some((t:any)=>t.connection_name===c.name)))
const topology=auditCompositeHostTopology([...candidate,...traces],[...host.traces,...traces],input.connections)
const reservedCollarChecks=reservedCollars.map(r=>{const fresh=[...host.traces,...traces,r.extendedTrace],ids=new Set(fresh.map(t=>t.pcb_trace_id));return{signal:r.signal,physical:verifyDdrSystemCopper(candidate.filter((e:any)=>!ids.has(e.pcb_trace_id)),fresh,input.connections,{})}})
const accepted=reservedCollarChecks.every(c=>!c.physical.errors.length&&!c.physical.violations.length)&&topology.valid&&allAngles.valid&&allJunctions.valid&&allTerminal.valid&&physical.connectivity.filter((c:any)=>c.connected).length===host.traces.length+1&&traces.length===1&&traces[0].route.every((p:any)=>p.route_type==='wire'&&p.layer===layer)&&terminal.valid&&!physical.errors.length&&!physical.violations.length&&physical.angles.valid&&!physical.joinedBends.length&&physical.connectivity.some((c:any)=>c.name===connection.name&&c.connected)&&lengths.fullPlanarMm<=lengths.nominalMm+1e-7
context.assertUnchanged();write('report.json',{captureHash,accepted,reservedCollarChecks,finished,maximumSearchStates,heuristicWeight,expandedStateCount:progress.at(-1)?.expandedStateCount,elapsedSeconds:(Date.now()-started)/1000,physical,terminal,allTerminal,allAngles,allJunctions,topology,lengths,parentCandidateSha256:objectHash(candidate),sameNetTopologyStatus:'All prior hosts exact; every retained/new contact must be a source-owned endpoint.',scope:'Actual saved-exit host continuation; complete byte matching, references, impedance and remaining interface still unqualified.'});write('raw-traces.json',traces)
if(accepted){write('candidate.circuit.json',[...candidate,...traces]);write('routing-input.json',{...input,traces:[...host.traces,...traces],obstacles:undefined});write('host-bundle.json',{...host,traces:[...host.traces,...traces]})}
console.log(JSON.stringify({accepted,alternatives:alternatives.length,errors:physical.errors.length,violations:physical.violations.length,angles:physical.angles.violations.length,joins:physical.joinedBends.length,lengths}));if(!accepted)process.exitCode=1