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-aligned-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{auditHostSelfContacts}from'./audit-ddr-host-self-contacts'
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],originalSource={...old.route[0]},source={route_type:'wire',x:-14.4,y:-8.2,width:.12,layer:'inner4'},prefix=[...old.route.slice(0,6),source],suffix=old.route.slice(8),target=suffix[0],collar={...source,y:source.y+.2}
if(prior.candidateCircuitSha256!==hash(parent)||host.traces.length!==21||power.launchQualified!==58||connection.ramTerminal!=='DM'||via.to_layer!=='inner4')throw Error('Expected current21/power58 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:prefix}:e,own=isTrace||(e.type==='pcb_via'&&e.pcb_trace_id===old.pcb_trace_id)||(e.type==='pcb_smtpad'&&e.pcb_port_id===originalSource.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={obstacleId:'declared-middle-launch',shape:'circle',center:{x:target.x,y:target.y},width:.12,height:.12,layers:['inner4'],connectedTo:[connection.name]},local={...connection,pointsToConnect:[target,source]},pc={connection:local,connectionIndex:0,sourcePoint:target,sourcePointIndex:0,sourceLayer:'inner4',sourceObstacle,targetPoint:source},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:[...obstacles,sourceObstacle,...supportCopperObstacles([{...old,route:suffix}]).map((o:any)=>({...o,connectedTo:[connection.name]}))],traces:[]},bus,targetLayer:'inner4',terminals:[{connection:pc,viaPoint:{...target,x:target.x-.2},exitPoint:source}],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,alignGridToPads:true,gridStepDivisor:2,gridOrigin:{x:-14.400046,y:-6.5},maximumRouteOrderAttempts:1,maximumSearchStates:300000,heuristicWeight:1,sourceEscapePaths:new Map([[0,[target,{...target,x:target.x-.2}]]])},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 raw=[...results[0][0].trace.route].reverse();if(raw.some((p:any)=>p.route_type!=='wire'||p.layer!=='inner4')||Math.hypot(raw[0].x-source.x,raw[0].y-source.y)>1e-7||Math.hypot(raw.at(-1).x-target.x,raw.at(-1).y-target.y)>1e-7)throw Error('Middle solver changed endpoints/layer');const after={...old,route:[...prefix,...raw.slice(1),...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);const selfContacts=auditHostSelfContacts([after]);diagnostic={physical,topology,angles,junctions,localContacts,selfContacts,oldLocalMm:planar(old.route),newLocalMm:planar(after.route),deltaMm:delta,oldMatchedTotalMm:28.423158,newTotalWithUnchangedHostMm:28.423158+delta,requiredHostCompensationMm:-delta,nominalMm:28.899838,frozenPrefixExact:hash(after.route.slice(0,prefix.length))===hash(prefix),frozenSuffixExact:hash(after.route.slice(-suffix.length))===hash(suffix),allHostsExact:host.traces.every((t:any)=>child.some((e:any)=>hash(e)===hash(t))),geometryClear:selfContacts.valid&&!physical.errors.length&&!physical.violations.length&&topology.valid&&angles.valid&&junctions.valid&&localContacts.valid}}
const plannerEvidence={source,sourceCollar:collar,target,preservedPrefix:prefix,preservedSuffix:suffix,requiredSuffixHeadingDegrees:45,allowedIncomingHeadingDegrees:[0,45,90],suffixHeadingEnforcement:'Final all-route and cross-trace junction audits reject incompatible solver arrival; winding API does not constrain target approach.',grid:{stepMm:.1,alignGridToPads:true,gridStepDivisor:2,origin:{x:-14.400046,y:-6.5}},reverseSearch:true,reservedSuffixCollar:[target,{...target,x:target.x-.2}],suffixCollarEnforcement:'Existing winding sourceEscapePaths in reverse forces forward eastbound suffix arrival.',retainedHostCount:host.traces.length};const report={plannerEvidence,accepted:false,timingQualified:false,scopeStatus:'Diagnostic only; fresh power/reference and exact matched-length acceptance are not established.',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, prefix through(-14.4,-8.2), suffix from(-13,-6.5), all21hosts 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}))