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-facing-composite-exit.ts
/** One bounded existing-winding experiment against the actual composite copper. */
import {writeFileSync,mkdirSync} from 'node:fs'
import {resolve} from 'node:path'
import {loadDdrCompositeRoutingContext} from './ddr-composite-routing-context'
import {applyFacingExitReplacements} from './ddr-facing-context'
import {explicitFacingViaContinuation} from './ddr-facing-via-continuation'
import {objectHash} from './improve-ddr-a9-power-launches'
import {verifyDdrSystemCopper,auditDdrTraceJunctions} from './check-ddr-system-copper'
import {auditRouteAngles} from './check-route-angles'
const [capture,composite,out,signal='DDR_DQM0',yArg='-7.1']=process.argv.slice(2)
if(!capture||!composite||!out||!Number.isFinite(Number(yArg)))throw Error('Usage: capture composite output signal exit-y')
const context=await loadDdrCompositeRoutingContext(capture,composite),{candidate,host,input,map,captureHash}=context
const entry=map.find((m:any)=>m.cpuSignal===signal),connection=input.connections.find((c:any)=>c.source_trace_id===entry?.sourceTraceId)
if(!connection||connection.ramByte!==0||!['DM','DQ1','DQ3','DQ5','DQ7'].includes(connection.ramTerminal))throw Error('Expected byte0 odd/data mask')
const invalidated=host.traces.filter((t:any)=>t.connection_name===connection.name)
if(invalidated.length!==1)throw Error('Expected exactly one explicitly invalidated existing host')
const invalidatedIds=new Set(invalidated.map((t:any)=>t.pcb_trace_id)),retained=host.traces.filter((t:any)=>!invalidatedIds.has(t.pcb_trace_id))
const ram=connection.pointsToConnect[0],exit=candidate.find((e:any)=>e.pcb_breakout_point_id===ram.pointId),old=candidate.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===exit.source_trace_id),viaIndex=old.route.findIndex((p:any)=>p.route_type==='via')
if(viaIndex<0||old.route.filter((p:any)=>p.route_type==='via').length!==1)throw Error('Expected one retained via')
const via={...old.route[viaIndex],to_layer:'inner4'},source={...old.route[0],pointId:ram.pointId},target={x:-6.040077,y:Number(yArg),layer:'inner4'}
const removedObstacleIds:string[]=[]
const obstacles=input.obstacles.filter((o:any)=>{
const prefix=`fixed_trace_${old.pcb_trace_id}_`
if(!o.obstacleId?.startsWith(prefix))return true
const index=Number(o.obstacleId.slice(prefix.length).split('_')[0])
if(Number.isInteger(index)&&index>viaIndex){removedObstacleIds.push(o.obstacleId);return false}return true
})
const srj={...input,obstacles,traces:retained},sourceObstacle=obstacles.find((o:any)=>o.connectedTo.includes(connection.name)&&o.layers.includes('top')&&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 actual source obstacle')
const localConnection={...connection,pointsToConnect:[source,target]},prepared:any={connection:localConnection,connectionIndex:0,sourcePoint:source,sourcePointIndex:0,sourceLayer:'top',sourceObstacle,targetPoint:target}
const bounds={minX:-18,maxX:target.x,minY:-13,maxY:-3}
if(target.y<bounds.minY||target.y>bounds.maxY)throw Error('Outside unchanged local bounds')
const bus:any={busId:signal,direction:'right',exitEdge:'right',termination:{type:'boundary'},connections:[prepared],componentId:'RAM-facing-escape',componentObstacles:[sourceObstacle],componentBounds:bounds,sharedBoundary:bounds,xCoordinates:[via.x],yCoordinates:[via.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,bus,targetLayer:'inner4',terminals:[{connection:prepared,viaPoint:via,exitPoint:target}],acceptedPlans:[],layerNames:['top',...Array.from({length:8},(_,i)=>`inner${i+1}`),'bottom'],traceWidth:.12,viaDiameter:via.via_diameter,viaHoleDiameter:via.via_hole_diameter,clearance:.1016,allowBlindAndBuriedVias:false,allowSourceLayerRouting:true,gridStep:.1,maximumRouteOrderAttempts:1,maximumSearchStates:300000,heuristicWeight:1.2,sourceEscapePaths:new Map([[0,old.route.slice(0,viaIndex).map((p:any)=>({x:p.x,y:p.y}))]])}
mkdirSync(out,{recursive:true});const write=(p:string,x:any)=>writeFileSync(resolve(out,p),JSON.stringify(x,null,2)+'\n')
write('input-evidence.json',{...context.evidence,signal,connection,target,source,via,bounds,removedObstacleIds,invalidatedHostTraces:invalidated,retainedHostCount:retained.length,obstacleCount:obstacles.length,retainedDQ7ObstacleCount:obstacles.filter((o:any)=>o.obstacleId.includes('saved_fanout_pcb_group_3_39')).length})
const started=Date.now(),steps=routeViaMinimalWindingAlternativesSteps(params,1),progress:any[]=[];let result:any[]=[],finished=false
while(Date.now()-started<55000){const s=steps.next();if(s.done){result=s.value;finished=true;break}progress.push({...s.value,visualization:undefined});write('progress.json',progress)}if(!finished)steps.return([])
const raw=result[0]?.[0]?.trace
let accepted=false,physical:any,allAngles:any,allJunctions:any,lengthBudget:any,changes:any,updated:any,interpretation:any
if(raw){
write('raw.json',raw);interpretation=explicitFacingViaContinuation(old,raw,'inner4')
const after=interpretation.after,last=after.route.at(-1),previous=[...after.route].reverse().find((p:any)=>p.route_type==='wire'&&p.layer===target.layer&&Math.hypot(p.x-target.x,p.y-target.y)>1e-7)
if(last.layer!==target.layer||Math.hypot(last.x-target.x,last.y-target.y)>1e-7||!previous||last.x<=previous.x)throw Error('Wrong exit/tangent')
changes={traces:[{before:old,after}],breakoutPoints:[{before:exit,after:{...exit,...target}}]}
updated=applyFacingExitReplacements(candidate.filter((e:any)=>!invalidatedIds.has(e.pcb_trace_id)),changes)
const connections=input.connections.map((c:any)=>({...c,pointsToConnect:c.pointsToConnect.map((p:any)=>p.pointId===ram.pointId?{...p,...target}:p)})),fresh=[...retained,after],freshIds=new Set(fresh.map((t:any)=>t.pcb_trace_id))
physical=verifyDdrSystemCopper(updated.filter((e:any)=>!freshIds.has(e.pcb_trace_id)),fresh,connections,{})
allAngles=auditRouteAngles(updated.filter((e:any)=>e.type==='pcb_trace'));allJunctions=auditDdrTraceJunctions(updated,connections)
const planar=(r:any[])=>r.reduce((s:number,p:any,i:number)=>{const q=r[i-1];return s+(p.route_type==='wire'&&q?.route_type==='wire'&&p.layer===q.layer?Math.hypot(p.x-q.x,p.y-q.y):0)},0)
const cpu=connection.pointsToConnect[1],cpuExit=candidate.find((e:any)=>e.pcb_breakout_point_id===cpu.pointId),cpuTrace=candidate.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===cpuExit.source_trace_id),dx=Math.abs(cpu.x-target.x),dy=Math.abs(cpu.y-target.y)
lengthBudget={ramEscapeMm:planar(after.route),cpuEscapeMm:planar(cpuTrace.route),hostFloorMm:Math.max(dx,dy)+(Math.SQRT2-1)*Math.min(dx,dy),nominalMm:context.nominal.bytes.find((b:any)=>b.byte===0).dqlmPairedDataMaximumMm,optimisticTotalMm:0}
lengthBudget.optimisticTotalMm=lengthBudget.ramEscapeMm+lengthBudget.cpuEscapeMm+lengthBudget.hostFloorMm
accepted=!physical.errors.length&&!physical.violations.length&&physical.angles.valid&&!physical.joinedBends.length&&allAngles.valid&&allJunctions.valid&&retained.every((t:any)=>physical.connectivity.some((c:any)=>c.name===t.connection_name&&c.connected)&&objectHash(updated.find((e:any)=>e.pcb_trace_id===t.pcb_trace_id))===objectHash(t))&&lengthBudget.optimisticTotalMm<=lengthBudget.nominalMm+1e-7
}
context.assertUnchanged();write('report.json',{captureHash,accepted,finished,alternatives:result.length,elapsedSeconds:(Date.now()-started)/1000,physical,allAngles,allJunctions,lengthBudget,parentCircuitSha256:objectHash(candidate),invalidatedHostTraces:invalidated,retainedHostCount:retained.length,interpretation,scope:'Actual composite obstacles retained including DQ7; only DM0 host and post-via escape retired. Local profile feasibility; no full-interface or same-net topology qualification.'})
if(changes)write('replacements.json',{...changes,invalidatedHostTraces:invalidated})
if(accepted){write('candidate.circuit.json',updated);write('host-bundle.json',{...host,traces:retained})}
console.log(JSON.stringify({accepted,finished,alternatives:result.length,lengthBudget,violations:physical?.violations.length}));if(!accepted)process.exitCode=1