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-dm0-around-f8.ts
/** Existing winding DM0 co-design around one proposed RAM0 F8 relocation. */
import{readFileSync,writeFileSync,mkdirSync}from'node:fs'
import{resolve}from'node:path'
import{createHash}from'node:crypto'
import{supportCopperObstacles}from'./ddr-support-routing-context'
import{planDdrGroundAntipads}from'./ddr-ground-plane-antipads'
import{refreshDdrPlaneContacts}from'./ddr-plane-contact-audit'
import{explicitFacingViaContinuation}from'./ddr-facing-via-continuation'
import{verifyDdrSystemCopper,auditDdrTraceJunctions}from'./check-ddr-system-copper'
import{auditRouteAngles}from'./check-route-angles'
import{auditCompositeHostTopology}from'./ddr-composite-routing-context'
import{auditDdrLocalEscapeContacts}from'./audit-ddr-local-escape-contacts'
import{sharedViaApproaches}from'./plan-ddr-ram-power-via-reuse'
const[dirArg,outArg]=process.argv.slice(2),dir=resolve(dirArg!),out=resolve(outArg!),hash=(v:any)=>createHash('sha256').update(JSON.stringify(v)).digest('hex'),bound:Record<string,string>={},read=(p:string)=>{p=resolve(p);bound[p]=createHash('sha256').update(readFileSync(p)).digest('hex');return JSON.parse(readFileSync(p,'utf8'))},parent=read(`${dir}/candidate.circuit.json`),host=read(`${dir}/host-bundle.json`),input=read(`${dir}/routing-input.json`),prior=read(`${dir}/report.json`),power=read(`${dir}/ram-power-launch-audit.json`),budget=read(`${dir}/current-byte-budgets.json`),old=parent.find((e:any)=>e.type==='pcb_trace'&&e.pcb_trace_id==='saved_fanout_pcb_group_3_36'),exit=parent.find((e:any)=>e.type==='pcb_breakout_point'&&e.source_trace_id===old.source_trace_id),connection=input.connections.find((c:any)=>c.pointsToConnect.some((p:any)=>p.pointId===exit.pcb_breakout_point_id)),vi=old.route.findIndex((p:any)=>p.route_type==='via'),via=old.route[vi],source={...old.route[0]},suffix=old.route.slice(-4),target=suffix[0]
if(prior.candidateCircuitSha256!==hash(parent)||host.traces.length!==20||power.launchQualified!==57||connection.ramTerminal!=='DM'||via.to_layer!=='inner4')throw Error('Expected current20/power57 DM0')
const f8=parent.find((e:any)=>e.type==='pcb_trace'&&e.pcb_trace_id==='saved_fanout_pcb_group_3_53'),f8v=parent.find((e:any)=>e.type==='pcb_via'&&e.pcb_trace_id===f8.pcb_trace_id),f8via={x:f8.route[0].x+.4,y:f8.route[0].y+.4},newF8={...f8,route:[...sharedViaApproaches(f8.route[0],f8via)[0]!,{...f8.route.find((p:any)=>p.route_type==='via'),...f8via}]},newF8v={...f8v,...f8via},e9=parent.find((e:any)=>e.type==='pcb_trace'&&e.pcb_trace_id==='saved_fanout_pcb_group_3_65'),g8=power.rows.find((r:any)=>r.byte===0&&r.ball==='G8').connectionVia,newE9={...e9,route:sharedViaApproaches(e9.route[0],g8)[0]!,connectsTo:[e9.source_trace_id,e9.route[0].start_pcb_port_id,'pcb_via_183']};delete newE9.connection_name
const changes=[{before:f8,after:newF8},{before:f8v,after:newF8v},{before:e9,after:newE9}],planePlan=planDdrGroundAntipads(parent.filter((e:any)=>e.type==='pcb_copper_pour'&&e.layer==='inner3'),[{...f8via,net:'foreign-ground'}],{clearanceMm:.107,minimumCopperWebMm:.127});changes.push({before:parent.find((e:any)=>e.type==='pcb_copper_pour'&&e.layer==='inner3'),after:planePlan.planes[0]});const base=parent.map((e:any)=>changes.find(c=>c.before===e)?.after??e)
const obstacles=base.filter((e:any)=>['pcb_trace','pcb_via','pcb_smtpad'].includes(e.type)).flatMap((e:any)=>{const isTrace=e===old,projected=isTrace?{...e,route:e.route.slice(0,vi+1)}:e,own=isTrace||(e.type==='pcb_via'&&e.pcb_trace_id===old.pcb_trace_id)||(e.type==='pcb_smtpad'&&e.pcb_port_id===source.start_pcb_port_id);return supportCopperObstacles([projected]).map((o:any)=>({...o,...((e.type==='pcb_smtpad'&&e.shape==='circle')||e.type==='pcb_via'||o.obstacleId.startsWith('fixed_via_')||o.obstacleId.endsWith('_cap')?{shape:'circle'}:{}),connectedTo:[own?connection.name:`reserved:${e[`${e.type}_id`]}`]}))}),sourceObstacle=obstacles.find((o:any)=>o.connectedTo[0]===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),local={...connection,pointsToConnect:[source,target]},pc={connection:local,connectionIndex:0,sourcePoint:source,sourcePointIndex:0,sourceLayer:'top',sourceObstacle,targetPoint:target},bounds={minX:-17.06005,maxX:-6.040077,minY:-12.660015,maxY:-.339985},bus={busId:'DM0-around-F8',direction:'right',exitEdge:'right',termination:{type:'boundary'},connections:[pc],componentId:'RAM0-DM',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')),params={srj:{...input,obstacles,traces:[]},bus,targetLayer:'inner4',terminals:[{connection:pc,viaPoint:via,exitPoint:target}],acceptedPlans:[],layerNames:['top',...Array.from({length:8},(_,i)=>`inner${i+1}`),'bottom'],traceWidth:.12,viaDiameter:.4572,viaHoleDiameter:.254,clearance:.1016,allowBlindAndBuriedVias:false,allowSourceLayerRouting:true,gridStep:.1,maximumRouteOrderAttempts:1,maximumSearchStates:300000,heuristicWeight:1,sourceEscapePaths:new Map([[0,old.route.slice(0,vi).map((p:any)=>({x:p.x,y:p.y}))]])},steps=routeViaMinimalWindingAlternativesSteps(params as any,1),progress:any[]=[],started=Date.now();let results:any[]=[],finished=false
while(Date.now()-started<55000){const s=steps.next();if(s.done){results=s.value;finished=true;break}progress.push({...s.value,visualization:undefined})}if(!finished)steps.return([])
const planar=(r:any[])=>r.slice(1).reduce((n:number,p:any,i:number)=>{const q=r[i];return n+(p.route_type==='wire'&&q.route_type==='wire'&&p.layer===q.layer?Math.hypot(p.x-q.x,p.y-q.y):0)},0);let diagnostic:any,child:any
if(results[0]?.length===1){const after=explicitFacingViaContinuation(old,results[0][0].trace,'inner4').after;after.route.push(...suffix.slice(1));child=base.map((e:any)=>e===old?after:e);changes.push({before:old,after});const fresh=[...host.traces,after,newF8,newE9],ids=new Set(fresh.map((e:any)=>e.pcb_trace_id)),fixed=child.filter((e:any)=>e.type!=='pcb_trace'||!ids.has(e.pcb_trace_id));fixed.push(after,newF8);const physical=verifyDdrSystemCopper(fixed,fresh,input.connections,{},50,{reportSameNetContacts:true}),topology=auditCompositeHostTopology(child,host.traces,input.connections),angles=auditRouteAngles(child.filter((e:any)=>e.type==='pcb_trace')),junctions=auditDdrTraceJunctions(child,input.connections),withoutOwnHost=child.filter((e:any)=>!host.traces.some((t:any)=>t.connection_name===connection.name&&t.pcb_trace_id===e.pcb_trace_id)),localContacts=auditDdrLocalEscapeContacts(withoutOwnHost,after,input.connections),delta=planar(after.route)-planar(old.route);diagnostic={physical,topology,angles,junctions,localContacts,oldLocalMm:planar(old.route),newLocalMm:planar(after.route),deltaMm:delta,oldMatchedTotalMm:28.423158,newTotalWithUnchangedHostMm:28.423158+delta,requiredHostCompensationMm:-delta,nominalMm:28.899838,frozenSuffixExact:hash(after.route.slice(-4))===hash(suffix),allHostsExact:host.traces.every((t:any)=>child.some((e:any)=>hash(e)===hash(t))),geometryClear:!physical.errors.length&&!physical.violations.length&&topology.valid&&angles.valid&&junctions.valid&&localContacts.valid}}
const report={captureHash:prior.captureHash,parentCircuitSha256:hash(parent),sourceHashes:bound,budget,finished,elapsedSeconds:(Date.now()-started)/1000,progress,raw:results,diagnostic,planePlan,scope:'Single existing winding DM0 local experiment around RAM0 F8 opposite launch. Old pad/via and final four vertices/exit+all20hosts frozen; F8/E9 support changes explicit. No accepted matching claim until required local-length compensation and all60 power/reference qualification are checked.'};mkdirSync(out,{recursive:true});for(const[p,h]of Object.entries(bound))if(createHash('sha256').update(readFileSync(p)).digest('hex')!==h)throw Error('Input changed');writeFileSync(`${out}/report.json`,JSON.stringify(report,null,2));if(child){writeFileSync(`${out}/candidate.circuit.json`,JSON.stringify(child,null,2));writeFileSync(`${out}/original-copper-replacements.json`,JSON.stringify({parentCircuitSha256:hash(parent),candidateCircuitSha256:hash(child),replacements:changes.map(c=>({id:`${c.before.type}:${c.before[`${c.before.type}_id`]}`,before:c.before,after:c.after,beforeSha256:hash(c.before),afterSha256:hash(c.after)}))},null,2))}console.log(JSON.stringify({finished,states:progress.at(-1)?.expandedStateCount,alternativeCount:results[0]?.length??0,diagnostic:diagnostic?{geometryClear:diagnostic.geometryClear,deltaMm:diagnostic.deltaMm,total:diagnostic.newTotalWithUnchangedHostMm,violations:diagnostic.physical.violations.length,angles:diagnostic.angles.valid,junctions:diagnostic.junctions.valid,local:diagnostic.localContacts.valid}:undefined}))