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/assemble-ddr-shorter-strobes.ts

/** Combine two exactly witnessed DQS0 replacements with the independently routed DQ7. */
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'
import { resolve } from 'node:path'
import { createHash } from 'node:crypto'
import { loadAcceptedDq7Context, auditCompositeHostTopology } from './ddr-composite-routing-context'
import { objectHash, validateDeclaredDdrReplacements } from './improve-ddr-a9-power-launches'
import { auditRouteAngles } from './check-route-angles'
import { auditDdrTraceJunctions } from './check-ddr-system-copper'
import { checkHostTerminalContract } from './route-ddr-sequential'

export function replaceExactStrobePair(elements:any[], replacements:any[]) {
 if(replacements.length!==2||new Set(replacements.map(r=>r.before.pcb_trace_id)).size!==2)throw Error('Expected exactly two distinct strobe replacements')
 for(const {before,after} of replacements){
  if(before.type!=='pcb_trace'||after.type!=='pcb_trace'||!['source_trace_564','source_trace_565'].includes(before.source_trace_id))throw Error('Unexpected DQS0 source')
  const {route:oldRoute,...oldMetadata}=before,{route:newRoute,...newMetadata}=after
  if(objectHash(oldMetadata)!==objectHash(newMetadata)||objectHash(oldRoute[0])!==objectHash(newRoute[0])||objectHash(oldRoute.at(-1))!==objectHash(newRoute.at(-1))||newRoute.some((p:any)=>p.route_type!=='wire'||p.layer!=='inner2'||p.width!==.12))throw Error('Strobe metadata, endpoints, width or layer changed')
  const found=elements.filter(e=>e.type==='pcb_trace'&&e.pcb_trace_id===before.pcb_trace_id)
  if(found.length!==1||objectHash(found[0])!==objectHash(before))throw Error('Exact prior strobe differs')
 }
 return elements.map(e=>replacements.find(r=>e.type==='pcb_trace'&&r.before.pcb_trace_id===e.pcb_trace_id)?.after??e)
}

if(import.meta.main){
 const[capture,parent,ordered,acceptedDm,acceptedDq7,shorter,out,dq4Dir,dq7Dir,combinedParentDir]=process.argv.slice(2)
 if(!out)throw Error('Usage: capture composite-parent ordered-exit accepted-DM accepted-DQ7 shortened-pair output')
 const c=await loadAcceptedDq7Context(capture,parent,ordered,acceptedDm,acceptedDq7),hashes=new Map<string,string>(),fileHash=(p:string)=>createHash('sha256').update(readFileSync(p)).digest('hex'),read=(p:string)=>{p=resolve(p);hashes.set(p,fileHash(p));return JSON.parse(readFileSync(p,'utf8'))}
 const changes=read(resolve(shorter,'replacements.json')),pairReport=read(resolve(shorter,'report.json')),pairCandidate=read(resolve(shorter,'candidate.circuit.json')),pairHost=read(resolve(shorter,'host-bundle.json')),dmCandidate=read(resolve(acceptedDm,'candidate.circuit.json')),dmHost=read(resolve(acceptedDm,'host-bundle.json'))
 if(!pairReport.accepted||pairReport.parentCandidateSha256!==objectHash(dmCandidate)||objectHash(replaceExactStrobePair(dmCandidate,changes))!==objectHash(pairCandidate)||objectHash({...dmHost,traces:replaceExactStrobePair(dmHost.traces,changes)})!==objectHash(pairHost))throw Error('Shortened pair provenance mismatch')
 let candidate=replaceExactStrobePair(c.candidate,changes),host={...c.host,traces:replaceExactStrobePair(c.host.traces,changes)}
 let dq4Evidence:any=null
 if(dq4Dir){
  const m=read(resolve(dq4Dir,'original-copper-replacements.json')),r=read(resolve(dq4Dir,'report.json')),source=read(resolve(dq4Dir,'candidate.circuit.json'))
  if(!r.accepted||m.captureHash!==c.captureHash||m.replacements.length!==1||m.replacements[0].id!=='pcb_trace:source_trace_579_0')throw Error('Unexpected DQ4 replacement')
  const preservation=validateDeclaredDdrReplacements(c.candidate,source,m),change=m.replacements[0],beforeHost=host.traces.find((t:any)=>t.pcb_trace_id===change.before.pcb_trace_id)
  if(objectHash(beforeHost)!==objectHash(change.before))throw Error('DQ4 host prior differs')
  candidate=candidate.map((e:any)=>e.type==='pcb_trace'&&e.pcb_trace_id===change.before.pcb_trace_id?change.after:e);host={...host,traces:host.traces.map((e:any)=>e.pcb_trace_id===change.before.pcb_trace_id?change.after:e)}
  changes.push(change);dq4Evidence={manifest:m,sourceReport:r,preservation}
 }
 let dq7Evidence:any=null,immediateParent:any=null
 if(dq7Dir){
  if(!dq4Dir||!combinedParentDir)throw Error('DQ7 merge requires DQ4 and exact combined parent directory')
  const beforeCandidate=read(resolve(combinedParentDir,'candidate.circuit.json')),beforeReport=read(resolve(combinedParentDir,'report.json')),beforeHost=read(resolve(combinedParentDir,'host-bundle.json')),beforeManifest=read(resolve(combinedParentDir,'original-copper-replacements.json'))
  if(objectHash(candidate)!==objectHash(beforeCandidate)||objectHash(host)!==objectHash(beforeHost)||beforeReport.candidateCircuitSha256!==objectHash(beforeCandidate)||beforeReport.originalCopperReplacementsSha256!==objectHash(beforeManifest))throw Error('Combined parent does not match exact three-replacement replay')
  const change=read(resolve(dq7Dir,'dq7-replacement.json')),r=read(resolve(dq7Dir,'report.json')),source=read(resolve(dq7Dir,'candidate.circuit.json')),sourceHost=read(resolve(dq7Dir,'host-bundle.json'))
  if(!r.accepted||r.captureHash!==c.captureHash||change.id!=='pcb_trace:fanout:source_trace_582:source-0'||objectHash(host.traces.find((t:any)=>t.pcb_trace_id===change.before.pcb_trace_id))!==objectHash(change.before))throw Error('DQ7 tuning prior or identity differs')
  const {route:beforeRoute,...beforeMetadata}=change.before,{route:afterRoute,...afterMetadata}=change.after
  if(objectHash(beforeMetadata)!==objectHash(afterMetadata)||objectHash(beforeRoute[0])!==objectHash(afterRoute[0])||objectHash(beforeRoute.at(-1))!==objectHash(afterRoute.at(-1))||afterRoute.some((p:any)=>p.route_type!=='wire'||p.layer!=='inner4'||p.width!==.12))throw Error('DQ7 tuning moved endpoints or changed layer/width/vias')
  immediateParent={candidate:beforeCandidate,report:beforeReport,manifest:beforeManifest,change}
  candidate=candidate.map((e:any)=>e.type==='pcb_trace'&&e.pcb_trace_id===change.before.pcb_trace_id?change.after:e);host={...host,traces:host.traces.map((t:any)=>t.pcb_trace_id===change.before.pcb_trace_id?change.after:t)}
  if(objectHash(candidate)!==objectHash(source)||objectHash(host)!==objectHash(sourceHost))throw Error('DQ7 source contains additional changes')
  dq7Evidence={sourceReport:r,change};changes.push(change)
 }
 const connections=c.input.connections,pairConnections=connections.filter((x:any)=>x.ramByte===0&&['DQS_P','DQS_N'].includes(x.ramTerminal)),traces=pairConnections.map((x:any)=>host.traces.find((t:any)=>t.connection_name===x.name))
 if(pairConnections.length!==2||traces.some((t:any)=>!t)||host.traces.length!==11)throw Error('Actual pair or host count differs')
 const topology=auditCompositeHostTopology(candidate,host.traces,connections),allAngles=auditRouteAngles(candidate.filter((e:any)=>e.type==='pcb_trace')),allJunctions=auditDdrTraceJunctions(candidate,connections),terminal=checkHostTerminalContract(host.traces,connections.filter((x:any)=>host.traces.some((t:any)=>t.connection_name===x.name)))
 const auditPath=resolve('/Users/ankan/Documents/Codex/2026-09-10/what-x20/outputs/mt41k512m8da-107-it-p-fanout/scripts/audit-am3352-dqs-pair.ts');hashes.set(auditPath,fileHash(auditPath));if(hashes.get(auditPath)!==pairReport.externalPairAuditorSha256)throw Error('Pair auditor changed')
 const {verifyHostDqsPair}=await import(auditPath),pair=verifyHostDqsPair({...c.input,connections:pairConnections},c.fixed,traces)
 const planar=(r:any[])=>r.reduce((sum:number,b:any,i:number)=>{const a=r[i-1];return sum+(a?.route_type==='wire'&&b.route_type==='wire'&&a.layer===b.layer?Math.hypot(a.x-b.x,a.y-b.y):0)},0)
 const lengths=traces.map((t:any,i:number)=>planar(t.route)+pairConnections[i].pointsToConnect.reduce((sum:number,p:any)=>{const e=candidate.find((e:any)=>e.type==='pcb_breakout_point'&&e.pcb_breakout_point_id===p.pointId),saved=candidate.find((t:any)=>t.type==='pcb_trace'&&t.source_trace_id===e?.source_trace_id&&t.route.at(-1)?.layer===p.layer&&Math.hypot(t.route.at(-1).x-p.x,t.route.at(-1).y-p.y)<1e-7);if(!saved)throw Error('Missing actual strobe escape');return sum+planar(saved.route)},0)),mean=lengths.reduce((a:number,b:number)=>a+b,0)/2
 if(!topology.valid||!allAngles.valid||!allJunctions.valid||!terminal.valid||pair.status!=='pair-geometry-pass'||topology.physical.connectivity.filter(x=>x.connected).length!==11||Math.abs(mean-c.measuredDm.totalPlanarMm)>1e-6||lengths.some((n:number)=>n>c.measuredDm.nominalMm))throw Error('Combined strobe geometry or timing witness failed')
 const dq4=host.traces.find((t:any)=>t.pcb_trace_id==='source_trace_579_0');let dq4FullMm:number|undefined
 if(dq4Evidence){const conn=connections.find((x:any)=>x.name===dq4.connection_name);dq4FullMm=planar(dq4.route)+conn.pointsToConnect.reduce((sum:number,p:any)=>{const e=candidate.find((e:any)=>e.type==='pcb_breakout_point'&&e.pcb_breakout_point_id===p.pointId),t=candidate.find((t:any)=>t.type==='pcb_trace'&&t.source_trace_id===e?.source_trace_id&&t.route.at(-1)?.layer===p.layer&&Math.hypot(t.route.at(-1).x-p.x,t.route.at(-1).y-p.y)<1e-7);if(!t)throw Error('Missing DQ4 escape');return sum+planar(t.route)},0);if(Math.abs(dq4FullMm!-mean)>1e-6)throw Error('DQ4 no longer matches pair mean')}
 let dq7FullMm:number|undefined
 if(dq7Evidence){dq7FullMm=planar(dq7Evidence.change.after.route)+c.measuredDq7.escapeMm.reduce((a:number,b:number)=>a+b,0);if(Math.abs(dq7FullMm!-mean)>1e-6)throw Error('DQ7 no longer matches DQS0 mean')}
 const assertUnchanged=()=>{c.assertUnchanged();for(const[p,h]of hashes)if(fileHash(p)!==h)throw Error('Strobe assembly input changed')};assertUnchanged()
 const manifest={captureHash:c.captureHash,parentDirectory:resolve(combinedParentDir??acceptedDq7),parentCircuitSha256:objectHash(immediateParent?.candidate??c.candidate),candidateCircuitSha256:objectHash(candidate),replacements:immediateParent?[immediateParent.change]:changes,priorAssemblyManifest:immediateParent?.manifest,allOtherElementsExact:true,sourcePairDirectory:resolve(shorter),inputFileHashes:Object.fromEntries(hashes)}
 mkdirSync(out,{recursive:true});const write=(n:string,v:any)=>writeFileSync(resolve(out,n),JSON.stringify(v,null,2)+'\n'),{obstacles,...input}=c.input
 const report={...c.report,physical:topology.physical,terminalContract:terminal,fullCandidateAngles:allAngles,fixedJunctionAudit:allJunctions,candidateCircuitSha256:objectHash(candidate),supportCircuitSha256:objectHash(candidate),hostTracesSha256:objectHash(host.traces),hostBundleSha256:objectHash(host),connectedHostCount:11,preservedHostCount:dq7Evidence?10:dq4Evidence?8:9,dq4Evidence,dq4FullMm,dq7Evidence,dq7FullMm,originalCopperReplacementsSha256:objectHash(manifest),strobePair:{lengthsMm:lengths,meanMm:mean,targetDmMm:c.measuredDm.totalPlanarMm,pair},sourceProvenance:{...c.evidence,strobeInputHashes:Object.fromEntries(hashes)},scope:'Eleven endpoint-only hosts, DQS0 pair shortened to ordered DM0 mean. DQ12 and four power launches unresolved; full byte timing and DDR qualification remain incomplete.'}
 write('candidate.circuit.json',candidate);write('host-bundle.json',host);write('routing-input.json',{...input,traces:host.traces});write('original-copper-replacements.json',manifest);write('report.json',report);write('topology-report.json',topology);write('source-provenance.json',report.sourceProvenance);write('source-pair-report.json',pairReport);write('ram-byte0-facing-progress.trace-paths.json',c.cache);write('exit-contract.json',c.exitContract)
 const audit=Bun.spawn(['bun','scripts/audit-ddr-global-power-launches.ts',resolve(out),resolve(capture)],{stdout:'inherit',stderr:'inherit'});if(await audit.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 qualification changed');assertUnchanged();write('report.json',{...report,launchAuditSha256:objectHash(power),launchQualified:56,totalRamPowerPads:60});console.log(JSON.stringify({out,hosts:11,contacts:topology.contacts.length,power:56,lengths,mean}))
}