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/export-ddr-dm1-facing-cache.ts

/** Transplant one witnessed local DM1 escape onto the replayed eleven-host board. */
import {readFileSync,writeFileSync,mkdirSync} from 'node:fs'
import {resolve} from 'node:path'
import {createHash} from 'node:crypto'
import {fanoutTracePath} from '@tscircuit/props'
import {auditCompositeHostTopology} from './ddr-composite-routing-context'
import {verifyDdrCapture} from './ddr-capture-provenance'
import {applyFacingExitReplacements} from './ddr-facing-context'
import {objectHash} from './improve-ddr-a9-power-launches'
import {auditDdrLocalEscapeContacts} from './audit-ddr-local-escape-contacts'
import {verifyDdrSystemCopper,auditDdrTraceJunctions} from './check-ddr-system-copper'
import {auditRouteAngles} from './check-route-angles'
const [capture,parentDir,trialDir,out]=process.argv.slice(2)
if(!out)throw Error('Usage: capture current-parent DM1-trial output')
const hashes:Record<string,string>={},hash=(p:string)=>createHash('sha256').update(readFileSync(p)).digest('hex'),read=(p:string)=>{p=resolve(p);hashes[p]=hash(p);return JSON.parse(readFileSync(p,'utf8'))}
const {captureHash,snapshot}=verifyDdrCapture(capture),parent=read(resolve(parentDir,'candidate.circuit.json')),parentHost=read(resolve(parentDir,'host-bundle.json')),parentReport=read(resolve(parentDir,'report.json')),cacheBefore=snapshot.pathsByByte[1],exitContract={changedBalls:[],exits:[]},trial=read(resolve(trialDir,'report.json')),changes=read(resolve(trialDir,'replacements.json')),candidate=read(resolve(trialDir,'candidate.circuit.json')),host=read(resolve(trialDir,'host-bundle.json')),input=read(resolve(trialDir,'routing-input.json'))
if(!trial.accepted||trial.captureHash!==captureHash||trial.parentCircuitSha256!==objectHash(parent)||trial.candidateCircuitSha256!==objectHash(candidate)||parentReport.candidateCircuitSha256!==objectHash(parent)||changes.invalidatedHostTraces.length!==1||changes.invalidatedHostTraces[0].source_trace_id!=='source_trace_674'||host.traces.length!==11)throw Error('DM1 trial identity/provenance mismatch')
for(const[p,h]of Object.entries(trial.inputHashes)){if(hash(p)!==h)throw Error('DM1 trial inputs changed');hashes[p]=h as string}
const retired=changes.invalidatedHostTraces[0],remaining=parent.filter((e:any)=>!(e.type==='pcb_trace'&&e.pcb_trace_id===retired.pcb_trace_id))
if(objectHash(parentHost.traces.find((t:any)=>t.pcb_trace_id===retired.pcb_trace_id))!==objectHash(retired)||objectHash(host)!==objectHash({...parentHost,traces:parentHost.traces.filter((t:any)=>t.pcb_trace_id!==retired.pcb_trace_id)})||objectHash(applyFacingExitReplacements(remaining,changes))!==objectHash(candidate))throw Error('Undeclared change or retirement')
const t=changes.traces[0].after,source=candidate.find((e:any)=>e.type==='source_port'&&e.source_port_id===changes.breakoutPoints[0].before.source_port_id),connections=input.connections
if(source?.name!=='ball_B7')throw Error('Expected DM1 RAM B7')
const fresh=[...host.traces,t],ids=new Set(fresh.map((t:any)=>t.pcb_trace_id)),physical=verifyDdrSystemCopper(candidate.filter((e:any)=>!ids.has(e.pcb_trace_id)),fresh,connections,{}),topology=auditCompositeHostTopology(candidate,host.traces,connections),localContacts=auditDdrLocalEscapeContacts(candidate,t,connections),allAngles=auditRouteAngles(candidate.filter((e:any)=>e.type==='pcb_trace')),allJunctions=auditDdrTraceJunctions(candidate,connections)
const context={cache:cacheBefore,exitContract}
const placement=snapshot.placements[1],cache=structuredClone(context.cache),index=cache.findIndex((p:any)=>p.connection===`U1.${source.name}`)
if(index<0||cache.length!==72)throw Error('Missing complete inherited RAM cache')
cache[index]={...cache[index],route:t.route.map((p:any)=>p.route_type==='wire'?{route_type:'wire',x:placement.pcbX-p.x,y:placement.pcbY-p.y,layer:p.layer,width:p.width}:{route_type:'via',x:placement.pcbX-p.x,y:placement.pcbY-p.y,from_layer:p.from_layer,to_layer:p.to_layer,via_diameter:p.via_diameter,via_hole_diameter:p.via_hole_diameter})}
for(let i=0;i<72;i++){fanoutTracePath.parse(cache[i]);if(i!==index&&objectHash(cache[i])!==objectHash(context.cache[i]))throw Error('Unrelated inherited cache changed')}
const bounds=(paths:any[])=>{const points=paths.flatMap((p:any)=>p.route);return{minX:Math.min(...points.map((p:any)=>p.x)),maxX:Math.max(...points.map((p:any)=>p.x)),minY:Math.min(...points.map((p:any)=>p.y)),maxY:Math.max(...points.map((p:any)=>p.y))}},before=bounds(snapshot.pathsByByte[1]),after=bounds(cache),cacheAngles=auditRouteAngles(cache)
if(after.minX<before.minX-1e-7||after.maxX>before.maxX+1e-7||after.minY<before.minY-1e-7||after.maxY>before.maxY+1e-7)throw Error('RAM envelope grew')
const end=t.route.at(-1),prev=[...t.route].reverse().find((p:any)=>p.route_type==='wire'&&p.layer===end.layer&&Math.hypot(p.x-end.x,p.y-end.y)>1e-7),d=Math.hypot(end.x-prev.x,end.y-prev.y),tangent={x:(end.x-prev.x)/d,y:(end.y-prev.y)/d}
if(tangent.x<=0||!['inner2'].includes(end.layer))throw Error('Wrong DM1 direction/layer')
const ball=source.name.slice(5),contract={...exitContract,candidateCircuitSha256:objectHash(candidate),ramByte1CacheSha256:objectHash(cache),changedBalls:[...exitContract.changedBalls,ball],unchangedPaths:71,pathCount:72,paddingChangeMm:0,paddingChangeBySideMm:{left:0,right:0,top:0,bottom:0},priorCenterlineBounds:before,newCenterlineBounds:after,exits:[...exitContract.exits,{ball,terminal:'DM1',worldSide:'right',localSide:'left',worldExit:{x:end.x,y:end.y,layer:end.layer},localExit:{x:placement.pcbX-end.x,y:placement.pcbY-end.y,layer:end.layer},tangent:{world:tangent,local:{x:-tangent.x,y:-tangent.y}},tangentDegrees:{world:Math.atan2(tangent.y,tangent.x)*180/Math.PI,local:Math.atan2(-tangent.y,-tangent.x)*180/Math.PI},logicalViaTransition:`top->${end.layer}`,physicalViaSpan:'all ten layers',traceWidthMm:.12}],scope:'Isolated RAM1 DM1 right-facing escape; eleven other hosts preserved, old overlong DM1 host retired pending replacement. One cache path changed relative to frozen source; no new padding.'}
if(!physical.errors.length&&!physical.violations.length&&topology.valid&&localContacts.valid&&allAngles.valid&&allJunctions.valid&&cacheAngles.valid&&trial.lengthBudget.optimisticTotalMm<=trial.lengthBudget.nominalMm+1e-7){
 for(const[p,h]of Object.entries(hashes))if(hash(p)!==h)throw Error('Input changed')
 mkdirSync(out,{recursive:true});const write=(n:string,v:any)=>writeFileSync(resolve(out,n),JSON.stringify(v,null,2)+'\n')
 const report={...parentReport,accepted:true,captureHash,candidateCircuitSha256:objectHash(candidate),supportCircuitSha256:objectHash(candidate),hostTracesSha256:objectHash(host.traces),hostBundleSha256:objectHash(host),ramByte1CacheSha256:objectHash(cache),connectedHostCount:11,preservedHostCount:11,physical,topology,allAngles,allJunctions,localContacts,cacheAngles,inputFileHashes:hashes,parentDirectory:resolve(parentDir),parentCandidateSha256:objectHash(parent),lengthBudget:trial.lengthBudget,scope:contract.scope}
 delete report.originalCopperReplacementsSha256
 write('candidate.circuit.json',candidate);write('host-bundle.json',host);write('routing-input.json',{...input,traces:host.traces});write('replacements.json',changes);write('ram-byte1-facing-progress.trace-paths.json',cache);write('ram-byte1-exit-contract.json',contract);write('exit-contract.json',{...read(resolve(parentDir,'exit-contract.json')),candidateCircuitSha256:objectHash(candidate)});write('ram-byte0-facing-progress.trace-paths.json',read(resolve(parentDir,'ram-byte0-facing-progress.trace-paths.json')));write('report.json',report);write('source-provenance.json',{captureHash,inputFileHashes:hashes,parentReport,trial,retiredHost:retired})
 const p=Bun.spawn(['bun','scripts/audit-ddr-global-power-launches.ts',resolve(out),resolve(capture)],{stdout:'inherit',stderr:'inherit'});if(await p.exited!==0)throw Error('Power audit failed');const power=JSON.parse(readFileSync(resolve(out,'ram-power-launch-audit.json'),'utf8'));if(power.launchQualified!==56||power.total!==60)throw Error('Power launch regression');write('report.json',{...report,launchAuditSha256:objectHash(power),launchQualified:56});console.log(JSON.stringify({accepted:true,ball,hosts:11,cache:cache.length,floor:trial.lengthBudget.optimisticTotalMm}))
}else throw Error('Current DM1 escape failed full checks')