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-d5-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 {loadAcceptedDq7Context,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='-8.5',targetLayer='inner4',gridArg='.1',statesArg='300000']=process.argv.slice(2)
const signal='DDR_D5'
const gridStep=Number(gridArg),maximumSearchStates=Number(statesArg)
if(!Number.isFinite(gridStep)||gridStep<.02||gridStep>.1||!Number.isInteger(maximumSearchStates)||maximumSearchStates<1||maximumSearchStates>1000000)throw Error('Invalid bounded search configuration')
if(!capture||!finalDir||!out||!Number.isFinite(Number(yArg))||!['inner2','inner4','inner6'].includes(targetLayer))throw Error('Usage: capture actual-parent output exit-y inner2|inner4|inner6')
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 verified=verifyDdrCapture(capture),actual=read(resolve(finalDir,'candidate.circuit.json')),actualHost=read(resolve(finalDir,'host-bundle.json')),actualInput=read(resolve(finalDir,'routing-input.json')),actualReport=read(resolve(finalDir,'report.json')),map=read(resolve(capture,'signal-map.json')),captureHash=verified.captureHash
if(actualReport.captureHash!==captureHash||actualHost.captureHash!==captureHash||actualHost.layerSpace!=='physical'||actualReport.candidateCircuitSha256!==objectHash(actual)||actualReport.hostTracesSha256!==objectHash(actualHost.traces))throw Error('Actual twelve-host board provenance differs')
for(const t of actualHost.traces)if(objectHash(actual.find((e:any)=>e.pcb_trace_id===t.pcb_trace_id))!==objectHash(t))throw Error('Actual host bundle differs')
for(const c of actualInput.connections)for(const p of c.pointsToConnect){const e=actual.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('Actual source exit differs')}
let parentReplay:any
if(finalDir.endsWith('ddr-twelve-dq1-connected')){
 const manifest=read(resolve(finalDir,'original-copper-replacements.json')),parent=read(resolve(manifest.parentDirectory,'candidate.circuit.json')),key=(e:any)=>`${e.type}:${e[`${e.type}_id`]}`
 if(manifest.captureHash!==captureHash||manifest.parentCircuitSha256!==objectHash(parent)||manifest.candidateCircuitSha256!==objectHash(actual))throw Error('DQ1 manifest parent/hash differs')
 for(const[p,h]of Object.entries(manifest.inputHashes??{})){if(fh(p)!==h)throw Error('Stale DQ1 manifest input');bound.set(p,h as string)}
 const replay=new Map(parent.map((e:any)=>[key(e),e])),touched=new Set<string>();if(replay.size!==parent.length)throw Error('Duplicate parent object identity')
 for(const w of manifest.replacements){if(touched.has(w.id)||key(w.before)!==w.id||key(w.after)!==w.id||objectHash(replay.get(w.id))!==objectHash(w.before))throw Error('Invalid replacement witness');touched.add(w.id);replay.set(w.id,w.after)}
 for(const e of manifest.removals){const k=key(e);if(touched.has(k)||objectHash(replay.get(k))!==objectHash(e))throw Error('Invalid removal');touched.add(k);replay.delete(k)}
 const added=new Set<string>();for(const e of manifest.additions){const k=key(e);if(added.has(k)||replay.has(k))throw Error('Invalid addition');added.add(k);replay.set(k,e)}
 if(objectHash([...replay.values()])!==objectHash(actual))throw Error('Exact replay differs from actual candidate')
 parentReplay={manifestSha256:objectHash(manifest),parentSha256:objectHash(parent),replacementCount:manifest.replacements.length,removalCount:manifest.removals.length,additionCount:manifest.additions.length,exact:true}
}
if(process.env.DDR_DQ1_TUNING){
 const tuningDir=process.env.DDR_DQ1_TUNING,m=read(resolve(tuningDir,'original-copper-replacements.json')),next=read(resolve(tuningDir,'candidate.circuit.json')),nextHost=read(resolve(tuningDir,'host-bundle.json'))
 validateDeclaredDdrReplacements(actual,next,m)
 if(m.captureHash!==captureHash||nextHost.captureHash!==captureHash||nextHost.traces.length!==12)throw Error('DQ1 tuning provenance differs')
 actual.splice(0,actual.length,...next);actualHost.traces=nextHost.traces
}
const baselineTopology=auditCompositeHostTopology(actual,actualHost.traces,actualInput.connections)
if(actualHost.traces.length!==12||!baselineTopology.valid||!auditRouteAngles(actual.filter((e:any)=>e.type==='pcb_trace')).valid||!auditDdrTraceJunctions(actual,actualInput.connections).valid)throw Error('Actual final baseline fails')
const hostIds=new Set(actualHost.traces.map((t:any)=>t.pcb_trace_id)),assertUnchanged=()=>{verifyDdrCapture(capture);for(const[p,h]of bound)if(fh(p)!==h)throw Error('Actual board changed during experiment')}
const context={candidate:actual,host:actualHost,input:actualInput,fixed:actual.filter((e:any)=>!hostIds.has(e.pcb_trace_id)),assertUnchanged,evidence:{actualInputHashes:Object.fromEntries(bound),actualParentPath:resolve(process.env.DDR_DQ1_TUNING??finalDir,'candidate.circuit.json'),parentReplay,baselineTopology}}, {candidate,host,input}=context
const entry=map.find((m:any)=>m.cpuSignal===signal),connection=input.connections.find((c:any)=>c.source_trace_id===entry?.sourceTraceId)
if(connection?.pointsToConnect[1]?.layer!=='inner6')throw Error('D5 CPU exit must use inner6')
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!==0||host.traces.length!==12)throw Error('Expected unhosted D5 and twelve retained 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[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:targetLayer},source={...old.route[0],pointId:ram.pointId},target={x:-6.040077,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 bounds=process.env.DDR_NARROW_REGION==='1'?{minX:-17.2,maxX:target.x,minY:-10.9,maxY:-5.3}:{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,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,maximumRouteOrderAttempts:1,maximumSearchStates,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('near-terminal-obstacles.json', [via,target].map(p=>({point:p,obstacles:obstacles.filter((o:any)=>o.layers.includes(targetLayer)&&Math.abs(o.center.x-p.x)<=o.width/2+1&&Math.abs(o.center.y-p.y)<=o.height/2+1)})));
write('input-evidence.json',{...context.evidence,signal,connection,target,source,via,bounds,gridStep,maximumSearchStates,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 gridNodeCount=(Math.floor((bounds.maxX-bounds.minX)/gridStep)+1)*(Math.floor((bounds.maxY-bounds.minY)/gridStep)+1),installedGridNodeLimit=160000
const started=Date.now(),steps=routeViaMinimalWindingAlternativesSteps(params,1,process.env.DDR_FRONTIER_AUDIT==='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}const v=s.value.visualization; const points=(v?.points??[]).filter((p:any)=>p.label==='expanded in current step'||p.label==='open frontier'); progress.push({...s.value,visualization:undefined,frontierSample:points});write('progress.json',progress)}if(!finished)steps.return([])
const raw=result[0]?.[0]?.trace
let envelope:any
const {snapshot}=verifyDdrCapture(capture),placement=snapshot.placements[0],modulePoints=snapshot.pathsByByte[0].flatMap((p:any)=>p.route.map((q:any)=>({x:placement.pcbX-q.x,y:placement.pcbY-q.y}))),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
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 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,{})
 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[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:28.899838000000003,optimisticTotalMm:0}
 lengthBudget.optimisticTotalMm=lengthBudget.ramEscapeMm+lengthBudget.cpuEscapeMm+lengthBudget.hostFloorMm
 accepted=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))&&lengthBudget.optimisticTotalMm<=lengthBudget.nominalMm+1e-7
}
context.assertUnchanged();write('report.json',{captureHash,accepted,finished,planningRegion:bounds,restrictedSearchRegion:process.env.DDR_NARROW_REGION==='1',gridStep,gridNodeCount,installedGridNodeLimit,preflightRejected:gridNodeCount>installedGridNodeLimit,maximumSearchStates,expandedStateCount:progress.at(-1)?.expandedStateCount,stateLimitReached:progress.at(-1)?.expandedStateCount>=maximumSearchStates,alternatives:result.length,elapsedSeconds:(Date.now()-started)/1000,physical,allAngles,allJunctions,topology,localContacts,envelope,lengthBudget,parentCircuitSha256:objectHash(candidate),invalidatedHostTraces:invalidated,retainedHostCount:retained.length,interpretation,scope:'Actual accepted twelve-host composite copper retained. Only D5 post-via escape and its exit replaced; twelve endpoint-only hosts preserved. Octile budget excludes obstacles and any necessary host transition when target layer differs from CPU inner6. Inner6 shares CA/CK routing and adjacent inner5 reference; electrical return path and SI remain unqualified; no complete DDR or D5 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,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