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/route-ddr-ram0-dq2-dq6-power.ts
/** Joint two-local-route repair; partial stages are never accepted. */
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{explicitFacingViaContinuation}from'./ddr-facing-via-continuation'
import{verifyDdrSystemCopper,auditDdrTraceJunctions}from'./check-ddr-system-copper'
import{auditRouteAngles}from'./check-route-angles'
const[parentArg,prepArg,outArg]=process.argv.slice(2),dir=resolve(parentArg!),out=resolve(outArg!),hash=(x:any)=>createHash('sha256').update(JSON.stringify(x)).digest('hex'),read=(p:string)=>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`),prep=read(`${prepArg}/power-preflight.json`),changes=[...prep.changes],same=(a:any,b:any)=>Math.hypot(a.x-b.x,a.y-b.y)<1e-7
if(hash(parent)!==prep.parentCircuitSha256||prior.candidateCircuitSha256!==hash(parent)||!prior.accepted||host.traces.length!==21)throw Error('Expected exact accepted21 parent')
let base=parent.map((e:any)=>changes.find(c=>c.before.type===e.type&&c.before[`${e.type}_id`]===e[`${e.type}_id`])?.after??e);const dq2=base.find((e:any)=>e.type==='pcb_trace'&&e.pcb_trace_id==='saved_fanout_pcb_group_3_14'),e7=base.find((e:any)=>e.type==='pcb_trace'&&e.pcb_trace_id==='saved_fanout_pcb_group_3_13'),pendingDq2={...dq2,route:dq2.route.slice(0,3)},stages:any[]=[],{routeViaMinimalWindingAlternativesSteps}=await import(resolve('node_modules/@tscircuit/fanout-solver/lib/route-via-minimal-winding.ts'))
mkdirSync(out,{recursive:true});const write=(n:string,v:any)=>writeFileSync(`${out}/${n}`,JSON.stringify(v,null,2))
async function run(old:any,stage:string,middle:boolean,retirePending=false){const name=stage,viaIndex=old.route.findIndex((p:any)=>p.route_type==='via'),prefix=middle?old.route.slice(0,9):old.route.slice(0,viaIndex+1),suffix=old.route.slice(-2),start=middle?prefix.at(-1):old.route[0],layer=middle?'inner6':'top',target=suffix[0],landing=middle?{x:start.x+.1,y:start.y}:old.route[viaIndex],routePrefix=middle?[{x:start.x,y:start.y},landing]:old.route.slice(0,viaIndex).map((p:any)=>({x:p.x,y:p.y})),connection={name,pointsToConnect:[start,target]},trimmed=structuredClone(prefix);if(middle){const a=trimmed.at(-2),b=trimmed.at(-1),d=Math.hypot(b.x-a.x,b.y-a.y);trimmed[trimmed.length-1]={...b,x:b.x+.25*(a.x-b.x)/d,y:b.y+.25*(a.y-b.y)/d}}
const obstacles=base.filter((e:any)=>['pcb_trace','pcb_via','pcb_smtpad'].includes(e.type)).flatMap((e:any)=>{let projected=e;if(e===old)projected={...e,route:trimmed};else if(retirePending&&e===dq2)projected=pendingDq2;const own=!middle&&(e===old||(e.type==='pcb_via'&&e.pcb_trace_id===old.pcb_trace_id)||(e.type==='pcb_smtpad'&&e.pcb_port_id===old.route[0].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?name:`reserved:${e[`${e.type}_id`]}`]}))});let sourceObstacle:any;if(middle){sourceObstacle={type:'rect',shape:'circle',obstacleId:'source-selector',center:{x:start.x,y:start.y},width:.12,height:.12,layers:[layer],connectedTo:[name]};obstacles.push(sourceObstacle)}else sourceObstacle=obstacles.find((o:any)=>o.connectedTo[0]===name&&o.layers.includes(layer)&&Math.abs(o.center.x-start.x)<=o.width/2+1e-7&&Math.abs(o.center.y-start.y)<=o.height/2+1e-7)
const pc={connection,connectionIndex:0,sourcePoint:{...start,pcb_port_id:middle?'dm-middle':start.start_pcb_port_id},sourcePointIndex:0,sourceLayer:layer,sourceObstacle,targetPoint:target},bounds=middle?{minX:-12.2,maxX:-6.040077,minY:3.4,maxY:5.4}:{minX:-11,maxX:-6.040077,minY:-12,maxY:-8.8},bus={busId:name,direction:'right',exitEdge:'right',termination:{type:'boundary'},connections:[pc],componentId:'local-power-codesign',componentObstacles:[sourceObstacle],componentBounds:bounds,sharedBoundary:bounds,xCoordinates:[landing.x],yCoordinates:[landing.y],pitchX:.8,pitchY:.8},params={srj:{...input,obstacles,traces:[]},bus,targetLayer:old.route[viaIndex].to_layer,terminals:[{connection:pc,viaPoint:landing,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:stage==='DQ6-second'?.01:.02,gridOrigin:{x:landing.x,y:landing.y},alignGridToPads:true,gridStepDivisor:2,maximumRouteOrderAttempts:1,maximumSearchStates:300000,heuristicWeight:1,sourceEscapePaths:new Map([[0,routePrefix]])},steps=routeViaMinimalWindingAlternativesSteps(params as any,1),progress:any[]=[],began=Date.now();let results:any[]=[],finished=false;while(Date.now()-began<55000){const s=steps.next();if(s.done){results=s.value;finished=true;break}progress.push({...s.value,visualization:undefined})}if(!finished)steps.return([])
let after:any;if(results[0]?.length===1){const raw=results[0][0].trace;if(middle){if(raw.route.some((p:any)=>p.route_type!=='wire'||p.layer!=='inner6')||!same(raw.route[0],start)||!same(raw.route.at(-1),target))throw Error('Middle endpoints/layer changed');after={...old,route:[...prefix,...raw.route.slice(1),...suffix.slice(1)]}}else{after=explicitFacingViaContinuation(old,raw,old.route[viaIndex].to_layer).after;after.route.push(...suffix.slice(1))}}
const result={stage,finished,progress,results,bounds,gridStep:stage==='DQ6-second'?.01:.02,gridOrigin:{x:landing.x,y:landing.y},after};stages.push(result);write(`${stage}.json`,result);return after}
const inheritedFirstDir=process.argv[5];let nextE7:any;if(inheritedFirstDir){const firstReport=read(`${inheritedFirstDir}/report.json`),firstStage=read(`${inheritedFirstDir}/DQ2-first.json`);if(firstReport.parentCircuitSha256!==hash(parent)||!firstStage.after)throw Error('First stage provenance mismatch');nextE7=firstStage.after;stages.push({...firstStage,stage:'DQ2-inherited',sourceStageSha256:hash(firstStage),sourceReportSha256:hash(firstReport)});}else nextE7=await run(e7,'DQ2-first',false,true);let nextDq2:any,diagnostic:any;if(nextE7){changes.push({before:e7,after:nextE7});base=base.map((e:any)=>e===e7?nextE7:e);nextDq2=await run(dq2,'DQ6-second',false)}
if(nextE7&&nextDq2){changes.push({before:dq2,after:nextDq2});base=base.map((e:any)=>e===dq2?nextDq2:e);const changedTraces=changes.filter(c=>c.after.type==='pcb_trace').map(c=>c.after),fresh=[...host.traces,...changedTraces],fixed=base.filter((e:any)=>e.type!=='pcb_copper_pour'),physical=verifyDdrSystemCopper(fixed,fresh,input.connections,{},50,{reportSameNetContacts:true}),angles=auditRouteAngles(base.filter((e:any)=>e.type==='pcb_trace')),junctions=auditDdrTraceJunctions(base,input.connections),planar=(r:any[])=>r.slice(1).reduce((n:number,b:any,i:number)=>{const a=r[i];return n+(a.route_type==='wire'&&b.route_type==='wire'&&a.layer===b.layer?Math.hypot(b.x-a.x,b.y-a.y):0)},0);diagnostic={physical,angles,junctions,dq2DeltaMm:planar(nextE7.route)-planar(e7.route),dq6DeltaMm:planar(nextDq2.route)-planar(dq2.route),all21HostsExact:host.traces.every((t:any)=>base.some((e:any)=>hash(e)===hash(t))),scope:'Joint conductor-only local proposal; planes/power/source owned contacts and nominal timing still need complete qualification.'};write('candidate.circuit.json',base);write('original-copper-replacements.json',{parentCircuitSha256:hash(parent),candidateCircuitSha256:hash(base),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)}))})}
write('report.json',{captureHash:prior.captureHash,parentCircuitSha256:hash(parent),preflightSha256:hash(prep),stages:stages.map(s=>({stage:s.stage,finished:s.finished,states:s.progress.at(-1)?.expandedStateCount,alternatives:s.results[0]?.length??0})),diagnostic,accepted:false,scope:'Both DQ2 and DQ6 required; neither isolated stage is accepted as a complete board. All current21 hosts and all58 qualified power launches reserved.'});console.log(JSON.stringify({stages:stages.map(s=>({stage:s.stage,finished:s.finished,states:s.progress.at(-1)?.expandedStateCount,alternatives:s.results[0]?.length??0})),diagnostic:diagnostic?{violations:diagnostic.physical.violations.length,dq2Delta:diagnostic.dq2DeltaMm,dq6Delta:diagnostic.dq6DeltaMm,angles:diagnostic.angles.valid,junctions:diagnostic.junctions.valid}:undefined}))