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-d13-cpu-facing-exit.ts

/** One bounded existing-winding experiment against the actual composite copper. */
import {readFileSync,writeFileSync,mkdirSync} from 'node:fs'
import {createHash} from 'node:crypto'
import {resolve} from 'node:path'
import {verifyDdrCapture} from './ddr-capture-provenance'
import {auditCompositeHostTopology} from './ddr-composite-routing-context'
import {supportCopperObstacles} from './ddr-support-routing-context'
import {applyFacingExitReplacements} from './ddr-facing-context'
import {explicitFacingViaContinuation} from './ddr-facing-via-continuation'
import {objectHash,validateDeclaredDdrReplacements} from './improve-ddr-a9-power-launches'
import {verifyDdrSystemCopper,auditDdrTraceJunctions} from './check-ddr-system-copper'
import {auditRouteAngles} from './check-route-angles'
import {auditDdrLocalEscapeContacts} from './audit-ddr-local-escape-contacts'
const [capture,finalDir,out,yArg='0',targetLayer='inner6',signal='DDR_D13']=process.argv.slice(2)
const localOnly=process.argv.includes('--local-only');if(!['DDR_D11','DDR_D13'].includes(signal))throw Error('Unsupported CPU swap member')
if(!capture||!finalDir||!out||!Number.isFinite(Number(yArg))||!['inner2','inner4','inner6'].includes(targetLayer))throw Error('Usage: capture current-board output exit-y [inner2|inner4|inner6]')
const {captureHash}=verifyDdrCapture(capture),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 candidate=read(resolve(finalDir,'candidate.circuit.json')),host=read(resolve(finalDir,'host-bundle.json')),input=read(resolve(finalDir,'routing-input.json')),report=read(resolve(finalDir,'report.json')),manifest=read(resolve(finalDir,'original-copper-replacements.json')),parent=read(resolve(manifest.parentDirectory??report.referenceRepair?.parentDir,'candidate.circuit.json')),nominal=read(resolve(finalDir,'current-byte-budgets.json')),map=read(resolve(capture,'signal-map.json'))
if(report.captureHash!==captureHash||host.captureHash!==captureHash||report.candidateCircuitSha256!==objectHash(candidate)||report.hostTracesSha256!==objectHash(host.traces)||report.originalCopperReplacementsSha256!==objectHash(manifest)||nominal.candidateCircuitSha256!==objectHash(candidate))throw Error('Current board provenance differs')
const removed=new Set((manifest.removals??[]).map((e:any)=>objectHash(e))),replacementMap=new Map(manifest.replacements.map((r:any)=>[objectHash(r.before),r.after])),replayed=[...parent.filter((e:any)=>!removed.has(objectHash(e))).map((e:any)=>replacementMap.get(objectHash(e))??e),...(manifest.additions??[])],multi=(a:any[])=>a.map(objectHash).sort();if(manifest.parentCircuitSha256!==objectHash(parent)||objectHash(multi(replayed))!==objectHash(multi(candidate)))throw Error('Exactparentmanifest replayfailed');const preservation={valid:true,parentCircuitSha256:objectHash(parent),candidateCircuitSha256:objectHash(candidate),exactManifestReplay:true}
for(const t of host.traces)if(objectHash(candidate.find((e:any)=>e.type==='pcb_trace'&&e.pcb_trace_id===t.pcb_trace_id))!==objectHash(t))throw Error('Actual host differs')
const baselineTopology=auditCompositeHostTopology(candidate,host.traces,input.connections)
if(host.traces.length<18||!baselineTopology.valid||!auditRouteAngles(candidate.filter((e:any)=>e.type==='pcb_trace')).valid||!auditDdrTraceJunctions(candidate,input.connections).valid)throw Error('Current baseline fails')
const hostIds=new Set(host.traces.map((t:any)=>t.pcb_trace_id)),assertUnchanged=()=>{verifyDdrCapture(capture);for(const[p,h]of bound)if(fh(p)!==h)throw Error('Input changed during experiment')}
const context={candidate,host,input,map,captureHash,nominal,fixed:candidate.filter((e:any)=>!hostIds.has(e.pcb_trace_id)),assertUnchanged,evidence:{preservation,baselineTopology,inputHashes:Object.fromEntries(bound)}}
const entry=map.find((m:any)=>m.cpuSignal===signal),connection=input.connections.find((c:any)=>c.source_trace_id===entry?.sourceTraceId)
if(!['inner4','inner6'].includes(connection?.pointsToConnect[1]?.layer))throw Error('Expected CPU inner4/6 exit')
if(!connection||connection.ramByte!==1||!['DM','DQ1','DQ3','DQ5','DQ7'].includes(connection.ramTerminal))throw Error('Expected byte1 odd/data mask')
const invalidated=host.traces.filter((t:any)=>t.connection_name===connection.name)
if(invalidated.length!==0||host.traces.length<18)throw Error('Expected unhosted D13 and at least18 verified parent hosts')
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[1],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:targetLayer},source={...old.route[0],pointId:ram.pointId},target={x:2.6899999999999995,y:Number(yArg),layer:targetLayer}
const removedObstacleIds=[`post-via-tail:${old.pcb_trace_id}`]
const padPort=old.route[0].start_pcb_port_id
const obstacles=context.fixed.filter((e:any)=>['pcb_trace','pcb_via','pcb_smtpad'].includes(e.type)).flatMap((element:any)=>{
 const isTrace=element.type==='pcb_trace'&&element.pcb_trace_id===old.pcb_trace_id
 const e=isTrace?{...element,route:element.route.slice(0,viaIndex+1)}:element
 const isPad=e.type==='pcb_smtpad'&&e.pcb_port_id===padPort
 const isVia=e.type==='pcb_via'&&e.pcb_trace_id===old.pcb_trace_id&&Math.hypot(e.x-via.x,e.y-via.y)<1e-7
 return supportCopperObstacles([e]).map(o=>({...o,...((e.type==='pcb_smtpad'&&e.shape==='circle')||e.type==='pcb_via'||o.obstacleId.startsWith('fixed_via_')||o.obstacleId.endsWith('_cap')?{shape:'circle'}:{}),connectedTo:isTrace||isPad||isVia?[connection.name]:[`reserved:${e[`${e.type}_id`]}`]}))
})
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 cpuPoints=candidate.filter((e:any)=>e.type==='pcb_trace'&&String(e.pcb_trace_id).startsWith('saved_fanout_pcb_group_2_')).flatMap((e:any)=>e.route); const bounds={minX:target.x,maxX:Math.max(...cpuPoints.map((p:any)=>p.x)),minY:Math.min(...cpuPoints.map((p:any)=>p.y)),maxY:Math.max(...cpuPoints.map((p:any)=>p.y))}
if(target.y<bounds.minY||target.y>bounds.maxY)throw Error('Outside unchanged local bounds')
const bus:any={busId:signal,direction:'left',exitEdge:'left',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,terminals:[{connection:prepared,viaPoint:via,exitPoint:target}],acceptedPlans:[],layerNames:['top',...Array.from({length:8},(_,i)=>`inner${i+1}`),'bottom'],traceWidth:.1016,viaDiameter:via.via_diameter,viaHoleDiameter:via.via_hole_diameter,clearance:.1016,allowBlindAndBuriedVias:false,allowSourceLayerRouting:true,gridStep:.1,...(process.argv.includes('--pad-aligned')?{alignGridToPads:true,gridStepDivisor:2}:{}),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,grid:{stepMm:.1,padAligned:process.argv.includes('--pad-aligned'),origin:process.argv.includes('--pad-aligned')?{x:via.x,y:via.y}:{x:bounds.minX,y:bounds.minY},scope:'Existing winding API alignment; original coarse bounds phase can miss narrow legal channels.'},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 envelope:any
const modulePoints=candidate.filter((e:any)=>e.type==='pcb_trace'&&String(e.pcb_trace_id).startsWith('saved_fanout_pcb_group_2_')).flatMap((e:any)=>e.route),moduleBounds={minX:Math.min(...modulePoints.map((p:any)=>p.x)),maxX:Math.max(...modulePoints.map((p:any)=>p.x)),minY:Math.min(...modulePoints.map((p:any)=>p.y)),maxY:Math.max(...modulePoints.map((p:any)=>p.y))}
let accepted=false,physical:any,allAngles:any,allJunctions:any,lengthBudget:any,changes:any,updated:any,interpretation:any,topology:any,localContacts:any,collarPhysical:any
if(raw){
 write('raw.json',raw);interpretation=explicitFacingViaContinuation(old,raw,targetLayer)
 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')
 envelope={bounds:moduleBounds,paddingChangeMm:0,valid:after.route.every((p:any)=>p.x>=moduleBounds.minX-1e-7&&p.x<=moduleBounds.maxX+1e-7&&p.y>=moduleBounds.minY-1e-7&&p.y<=moduleBounds.maxY+1e-7)}
 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 collarLength=Math.hypot(last.x-previous.x,last.y-previous.y),collarPoint={route_type:'wire',x:last.x+.2*(last.x-previous.x)/collarLength,y:last.y+.2*(last.y-previous.y)/collarLength,layer:last.layer,width:.1016};
 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,{})
 collarPhysical=verifyDdrSystemCopper(updated.filter((e:any)=>!freshIds.has(e.pcb_trace_id)),[...retained,{...after,route:[...after.route,collarPoint]}],connections,{});
 topology=auditCompositeHostTopology(updated,retained,connections)
 localContacts=auditDdrLocalEscapeContacts(updated,after,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[0],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(cpuTrace.route),cpuEscapeMm:planar(after.route),hostFloorMm:Math.max(dx,dy)+(Math.SQRT2-1)*Math.min(dx,dy),nominalMm:context.nominal.bytes.find((b:any)=>b.byte===1).nominalMm,optimisticTotalMm:0}
 lengthBudget.optimisticTotalMm=lengthBudget.ramEscapeMm+lengthBudget.cpuEscapeMm+lengthBudget.hostFloorMm
 accepted=!collarPhysical.errors.length&&!collarPhysical.violations.length&&collarPhysical.angles.valid&&envelope.valid&&topology.valid&&localContacts.valid&&!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))&&(localOnly||lengthBudget.optimisticTotalMm<=lengthBudget.nominalMm+1e-7)
}
context.assertUnchanged();write('report.json',{captureHash,accepted,localOnly,timingQualified:false,finished,alternatives:result.length,elapsedSeconds:(Date.now()-started)/1000,physical,collarPhysical,allAngles,allJunctions,topology,localContacts,envelope,lengthBudget,candidateCircuitSha256:updated?objectHash(updated):null,inputHashes:Object.fromEntries(bound),parentDirectory:resolve(finalDir),parentCircuitSha256:objectHash(candidate),invalidatedHostTraces:invalidated,retainedHostCount:retained.length,interpretation,scope:'Actual accepted ordered-DM composite obstacles retained. CPU L3/D13 escape revised; all verified parent hosts preserved. No complete DDR or new D13 host qualification.'})
if(changes)write('replacements.json',{...changes,invalidatedHostTraces:invalidated})
if(accepted){write('candidate.circuit.json',updated);write('host-bundle.json',{...host,traces:retained});write('routing-input.json',{...input,traces:retained,obstacles:undefined,connections:input.connections.map((c:any)=>({...c,pointsToConnect:c.pointsToConnect.map((p:any)=>p.pointId===ram.pointId?{...p,...target}:p)}))})}
console.log(JSON.stringify({accepted,finished,alternatives:result.length,lengthBudget,violations:physical?.violations.length}));if(!accepted)process.exitCode=1