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/retune-ddr-dq5-current.ts

/** Small existing-template DQ5 tuning with no host vias. */
import{readFileSync,writeFileSync,mkdirSync}from'node:fs'
import{resolve}from'node:path'
import{createHash}from'node:crypto'
import{addWestwardTuningExcursion}from'./tune-ddr-data-mask'
import{objectHash,validateDeclaredDdrReplacements}from'./improve-ddr-a9-power-launches'
import{verifyDdrSystemCopper,auditDdrTraceJunctions}from'./check-ddr-system-copper'
import{auditCompositeHostTopology}from'./ddr-composite-routing-context'
import{auditHostSelfContacts}from'./audit-ddr-host-self-contacts'
import{auditRouteAngles}from'./check-route-angles'
import{checkHostTerminalContract}from'./route-ddr-sequential'
const dir=resolve(process.argv[2]??'dist/ddr-fifteen-reference-repaired'),out=resolve(process.argv[3]??'dist/ddr-dq5-retuned-current'),hashes=new Map<string,string>(),fh=(p:string)=>createHash('sha256').update(readFileSync(p)).digest('hex'),read=(p:string)=>{hashes.set(p,fh(p));return JSON.parse(readFileSync(p,'utf8'))},parent=read(`${dir}/candidate.circuit.json`),prior=read(`${dir}/report.json`),target=prior.strobePair.meanMm,host=read(`${dir}/host-bundle.json`),input=read(`${dir}/routing-input.json`),before=parent.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id==='source_trace_580'),connection=input.connections.find((c:any)=>c.name==='source_trace_580'),planar=(r:any[])=>r.slice(1).reduce((n,p,i)=>n+(p.route_type==='wire'&&r[i].route_type==='wire'&&p.layer===r[i].layer?Math.hypot(p.x-r[i].x,p.y-r[i].y):0),0)
if(!prior.accepted||prior.candidateCircuitSha256!==objectHash(parent)||prior.captureHash!==host.captureHash||before.route.filter((p:any)=>p.route_type==='via').length!==0||objectHash(before)!==objectHash(host.traces.find((t:any)=>t.pcb_trace_id===before.pcb_trace_id)))throw Error('Expected exact DQ5host with no host vias')
const fixedWitnesses=connection.pointsToConnect.map((p:any)=>{const exit=parent.find((e:any)=>e.type==='pcb_breakout_point'&&e.pcb_breakout_point_id===p.pointId),ts=parent.filter((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===exit?.source_trace_id&&e.route.at(-1)?.layer===p.layer&&Math.hypot(e.route.at(-1).x-p.x,e.route.at(-1).y-p.y)<1e-7);if(ts.length!==1)throw Error('Expected unique actual CPU/RAM escape');return{exit,trace:ts[0],planarMm:planar(ts[0].route)}}),fixedMm=fixedWitnesses.reduce((n:number,w:any)=>n+w.planarMm,0),beforeMm=fixedMm+planar(before.route),delta=target-beforeMm
const actualStrobeLengths=['source_trace_564','source_trace_565'].map(name=>{const t=host.traces.find((t:any)=>t.connection_name===name),c=input.connections.find((c:any)=>c.name===name);return planar(t.route)+c.pointsToConnect.reduce((n:number,p:any)=>{const exit=parent.find((e:any)=>e.type==='pcb_breakout_point'&&e.pcb_breakout_point_id===p.pointId),saved=parent.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===exit?.source_trace_id&&e.route.at(-1)?.layer===p.layer&&Math.hypot(e.route.at(-1).x-p.x,e.route.at(-1).y-p.y)<1e-7);if(!saved)throw Error('Missing actual strobe escape');return n+planar(saved.route)},0)}),actualStrobeMean=actualStrobeLengths.reduce((a,b)=>a+b,0)/2
if(!Number.isFinite(target)||Math.abs(actualStrobeMean-target)>1e-7)throw Error('Strobe target differs from actual copper')
if(Math.abs(beforeMm-27.867581768)>1e-6||delta<=0)throw Error('Actual DQ5 length differs')
const rotated={...before,route:[...before.route].reverse()},attempts:any[]=[],started=Date.now();let accepted:any=null
search:for(const entry of[.3,1.7])for(const exit of[-.6])for(const sign of[-1,1]){
 if(Date.now()-started>55000)break
 let detour:any;try{detour=addWestwardTuningExcursion(rotated,1,entry,exit,delta,sign,.1)}catch{continue}
 const after={...before,route:[...detour.route].reverse()},fixed=parent.filter((e:any)=>e.type!=='pcb_trace'||e.pcb_trace_id!==before.pcb_trace_id),r=verifyDdrSystemCopper(fixed,[after],[],{},0),self=auditHostSelfContacts([after]),clean=!r.errors.length&&!r.violations.length&&r.angles.valid&&!r.joinedBends.length&&self.valid
 attempts.push({entry,exit,sign,clean,errors:r.errors,violations:r.violations.length,violationDetails:r.violations,selfContacts:self.contacts.length})
 if(!clean)continue
 const candidate=parent.map((e:any)=>e===before?after:e),traces=host.traces.map((t:any)=>t.pcb_trace_id===before.pcb_trace_id?after:t),topology=auditCompositeHostTopology(candidate,traces,input.connections),selfContacts=auditHostSelfContacts(traces),allAngles=auditRouteAngles(candidate.filter((e:any)=>e.type==='pcb_trace')),allJunctions=auditDdrTraceJunctions(candidate,input.connections),terminal=checkHostTerminalContract(traces,input.connections.filter((c:any)=>traces.some((t:any)=>t.connection_name===c.name))),measuredMm=fixedMm+planar(after.route)
 if(!topology.valid||!selfContacts.valid||!allAngles.valid||!allJunctions.valid||!terminal.valid)continue
 if(Math.abs(measuredMm-target)>1e-7||objectHash(after.route[0])!==objectHash(before.route[0])||objectHash(after.route.at(-1))!==objectHash(before.route.at(-1))||objectHash(after.route.filter((p:any)=>p.route_type==='via'))!==objectHash(before.route.filter((p:any)=>p.route_type==='via'))||after.route.filter((p:any)=>p.route_type==='wire').some((p:any)=>p.width!==.12))throw Error('Template changed actual endpoints/vias/width or target')
 accepted={candidate,traces,after,measuredMm,topology,selfContacts,allAngles,allJunctions,terminal,recipe:{entry,exit,sign,addedMm:delta,reversedForWestwardHelper:true,bevelMm:.1}};break search
}
mkdirSync(out,{recursive:true});const write=(n:string,v:any)=>writeFileSync(`${out}/${n}`,JSON.stringify(v,null,2));for(const[p,h]of hashes)if(fh(p)!==h)throw Error('Parent inputs changed')
if(accepted){const manifest={captureHash:host.captureHash,parentDirectory:dir,parentCircuitSha256:objectHash(parent),candidateCircuitSha256:objectHash(accepted.candidate),inputHashes:Object.fromEntries(hashes),fixedWitnesses,replacements:[{id:`pcb_trace:${before.pcb_trace_id}`,before,after:accepted.after,beforeSha256:objectHash(before),afterSha256:objectHash(accepted.after),reason:'Existing45degree excursion on DQ5 inner6 horizontal run; preserve zero host vias and actual endpoints.'}]},preservation=validateDeclaredDdrReplacements(parent,accepted.candidate,manifest);write('candidate.circuit.json',accepted.candidate);write('host-bundle.json',{...host,traces:accepted.traces});write('original-copper-replacements.json',manifest);write('report.json',{captureHash:host.captureHash,accepted:true,beforeMm,actualStrobeLengths,actualStrobeMean,targetMm:target,measuredMm:accepted.measuredMm,attempts,recipe:accepted.recipe,preservation,topology:accepted.topology,selfContacts:accepted.selfContacts,allAngles:accepted.allAngles,allJunctions:accepted.allJunctions,terminal:accepted.terminal,scope:'OneDQ5host retuned, all other retained hosts/source copper exact. Planar matching only; viadelay/SI/fullbyte completeness remainunqualified.'})}else write('report.json',{accepted:false,attempts,inputHashes:Object.fromEntries(hashes)})
console.log(JSON.stringify({accepted:Boolean(accepted),attempts:attempts.length,beforeMm,targetMm:target,measuredMm:accepted?.measuredMm,candidateHash:accepted?objectHash(accepted.candidate):null}))