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-global-planes.ts

/** Isolated global PDN plane candidate. Does not mutate the frozen host capture.
 * Every conductor retains explicit schematic identity. All foreign through
 * barrels and planar copper are subtracted, including newly planned support.
 * Polygon boolean operations merge overlapping antipads; existing local voids
 * are retained except the eight explicitly rail-joined ground holes per plane.
 */
import {readFileSync,writeFileSync,mkdirSync} from 'node:fs'
import {resolve} from 'node:path'
import {createHash} from 'node:crypto'
import F from '@flatten-js/core'
import {verifyDdrCapture} from './ddr-capture-provenance'
import {verifyDdrSystemCopper} from './check-ddr-system-copper'
type P={x:number,y:number}
const hash=(v:any)=>createHash('sha256').update(JSON.stringify(v)).digest('hex')
const read=(p:string)=>JSON.parse(readFileSync(p,'utf8'))
class Union{p=new Map<string,string>();find(x:string):string{const p=this.p.get(x);if(!p){this.p.set(x,x);return x}if(p===x)return x;const r=this.find(p);this.p.set(x,r);return r}join(a:string,b:string){this.p.set(this.find(a),this.find(b))}}
function hull(points:P[]){const p=[...points].sort((a,b)=>a.x-b.x||a.y-b.y),cross=(a:P,b:P,c:P)=>(b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x),lo:P[]=[],hi:P[]=[];for(const a of p){while(lo.length>1&&cross(lo.at(-2)!,lo.at(-1)!,a)<=1e-12)lo.pop();lo.push(a)}for(const a of p.toReversed()){while(hi.length>1&&cross(hi.at(-2)!,hi.at(-1)!,a)<=1e-12)hi.pop();hi.push(a)}return [...lo.slice(0,-1),...hi.slice(0,-1)]}
const circle=(p:P,r:number)=>Array.from({length:32},(_,i)=>({x:p.x+r/Math.cos(Math.PI/32)*Math.cos(i*Math.PI/16),y:p.y+r/Math.cos(Math.PI/32)*Math.sin(i*Math.PI/16)}))
const poly=(points:P[])=>new F.Polygon(points.map(p=>[p.x,p.y]))
function ps(p:P,a:P,b:P){const dx=b.x-a.x,dy=b.y-a.y,t=Math.max(0,Math.min(1,((p.x-a.x)*dx+(p.y-a.y)*dy)/(dx*dx+dy*dy)||0));return Math.hypot(p.x-a.x-t*dx,p.y-a.y-t*dy)}
if(import.meta.main){
 const dir=resolve(process.argv[2]??'dist/ddr-system/host-taps-54af3e346b5e'),out=resolve(process.argv[3]??'dist/ddr-global-plane-plan'),{captureHash}=verifyDdrCapture(dir)
 const reuse=process.argv.includes('--reuse'),original=read(`${dir}/unrouted.circuit.json`),drop=read(`${dir}/${reuse?'power-via-reuse/candidate.json':'power-drop-exact-width/accepted-candidate.json'}`),host=read(`${dir}/data-d4-tuned/candidate.physical.json`),capRaw=read('dist/ddr-ram-decoupling-plan/candidate.circuit.json'),local=read(`${dir}/power-drop-exact-width/accepted-reference-planes.json`),connections=read(`${dir}/merged-routing-input.json`).connections
 if(drop.captureHash!==captureHash||host.captureHash!==captureHash||host.layerSpace!=='physical'||drop.replacements.length!==(reuse?28:24)||host.traces.length!==7)throw Error('Capture or expected candidate inventory mismatch')
 const ids=new Map(capRaw.filter((e:any)=>e[`${e.type}_id`]).map((e:any)=>[e[`${e.type}_id`],`power_plan_caps_${e[`${e.type}_id`]}`])),remap=(v:any):any=>Array.isArray(v)?v.map(remap):v&&typeof v==='object'?Object.fromEntries(Object.entries(v).map(([k,x])=>[k,remap(x)])):typeof v==='string'?ids.get(v)??v:v,caps=remap(capRaw).filter((e:any)=>!['pcb_board','source_board'].includes(e.type))
 const capRailConnections=caps.filter((e:any)=>e.type==='source_net').map((local:any)=>{
  const name=local.name==='DDR_1V5'?'VCC_DDR_1V5':local.name==='GND'?'GND':null
  if(!name)throw Error(`Unexpected cap rail ${local.name}`)
  const targets=original.filter((e:any)=>e.type==='source_net'&&e.name===name)
  if(targets.length!==1)throw Error(`Ambiguous global cap rail ${name}`)
  const ports=[...new Set(caps.filter((e:any)=>e.type==='source_trace'&&e.connected_source_net_ids?.includes(local.source_net_id)).flatMap((e:any)=>e.connected_source_port_ids??[]))]
  if(!ports.length)throw Error(`Cap rail has no actual source ports ${name}`)
  return {type:'source_trace',source_trace_id:`planned_capbank_${name}`,connected_source_port_ids:ports,connected_source_net_ids:[local.source_net_id,targets[0].source_net_id],name:`Cap bank connection to ${name}`}
 })
 const removed=new Set(drop.replacements.map((e:any)=>e.pcb_trace_id)),base=[...original.filter((e:any)=>e.type!=='pcb_copper_pour'&&!removed.has(e.pcb_trace_id)),...caps,...drop.supportConnections,...capRailConnections],all=[...base,...drop.replacements,...host.traces],aliases={...drop.aliases},electrical=new Union(),byId=new Map(all.map((e:any)=>[e[`${e.type}_id`],e]))
 for(const t of all.filter((e:any)=>e.type==='source_trace')){const ids=[t.source_trace_id,...t.connected_source_port_ids??[],...t.connected_source_net_ids??[]];for(const id of ids)electrical.join(ids[0],id)}
 for(const [a,b]of Object.entries(aliases))electrical.join(a,b as string)
 for(const c of connections)for(const id of [c.source_trace_id,...c.mergedConnectionNames??[],c.rootConnectionName].filter(Boolean))electrical.join(c.name,id)
 const net=(e:any):string=>{if(e.type==='pcb_via'&&e.pcb_trace_id){const owner=byId.get(e.pcb_trace_id)as any;if(!owner||owner.type!=='pcb_trace'||!owner.route.some((p:any)=>p.route_type==='via'&&Math.hypot(p.x-e.x,p.y-e.y)<1e-7&&Math.abs((p.via_diameter??.4572)-e.outer_diameter)<1e-7&&Math.abs((p.via_hole_diameter??.254)-e.hole_diameter)<1e-7))throw Error(`Unverified via owner ${e.pcb_via_id}`);const ownerNet=net(owner);for(const id of [e.source_net_id,e.source_trace_id].filter(Boolean))if(electrical.find(id)!==ownerNet)throw Error(`Conflicting via owner identity ${e.pcb_via_id}`);return ownerNet}const ids=[e.source_net_id,e.source_trace_id,e.source_port_id,e.pcb_port_id?(byId.get(e.pcb_port_id)as any)?.source_port_id:undefined,e.connection_name].filter(Boolean);if(!ids.length)throw Error(`Missing copper net identity ${e.type}:${e[`${e.type}_id`]}`);for(const id of ids)electrical.join(ids[0],id);return electrical.find(ids[0])}
 for(const e of [...all,...local].filter(e=>['pcb_trace','pcb_via','pcb_smtpad','pcb_copper_pour'].includes(e.type)))net(e)
 const rail=(name:string)=>{const es=original.filter((e:any)=>e.type==='source_net'&&e.name===name);if(es.length!==1)throw Error(`Ambiguous rail ${name}`);return es[0].source_net_id},gnd=rail('GND'),vdd=rail('VCC_DDR_1V5')
 type Copper={id:string,net:string,layers:string[],a:P,b:P,r:number,vertices?:P[]}
 const copper:Copper[]=[],layers=['top',...Array.from({length:8},(_,i)=>`inner${i+1}`),'bottom']
 for(const e of all){
  if(e.type==='pcb_via')copper.push({id:e.pcb_via_id,net:net(e),layers,a:e,b:e,r:e.outer_diameter/2})
  if(e.type==='pcb_trace')for(let i=0;i<e.route.length;i++){const p=e.route[i],q=e.route[i-1];if(p.route_type==='via')copper.push({id:`${e.pcb_trace_id}:via:${i}`,net:net(e),layers,a:p,b:p,r:(p.via_diameter??.4572)/2});else if(q?.route_type==='wire'&&q.layer===p.layer)copper.push({id:`${e.pcb_trace_id}:${i}`,net:net(e),layers:[p.layer],a:q,b:p,r:Math.max(p.width,q.width)/2})}
  if(e.type==='pcb_smtpad'&&['inner1','inner3','inner5'].includes(e.layer))throw Error('Unimplemented internal-layer pad offset; fail closed')
  if(['pcb_plated_hole','pcb_cutout'].includes(e.type))throw Error(`Unsupported copper ${e.type}`)
 }
 mkdirSync(out,{recursive:true});const planes:any[]=[],planeAudit:any[]=[]
 for(const [layer,source_net_id]of [['inner1',gnd],['inner3',vdd],['inner5',gnd]]){
  const target=electrical.find(source_net_id),foreign=copper.filter(c=>c.layers.includes(layer)&&c.net!==target),own=copper.filter(c=>c.layers.includes(layer)&&c.net===target),oldHoleRecords=local.filter((p:any)=>p.layer===layer).flatMap((p:any)=>p.brep_shape.inner_rings.map((r:any,i:number)=>({planeId:p.pcb_copper_pour_id,holeIndex:i,vertices:r.vertices}))),clearance=.105
  let region=poly([{x:-31,y:-20},{x:31,y:-20},{x:31,y:20},{x:-31,y:20}])
  const refillOwners=new Set(['3','5'].flatMap(group=>[16,49,51,53].map(index=>`saved_fanout_pcb_group_${group}_${index}:via:2`))),refillVias=own.filter(c=>refillOwners.has(c.id)),refilledHoles:any[]=[],oldHoles:P[][]=[]
  for(const h of oldHoleRecords){const matches=refillVias.filter(v=>poly(h.vertices).contains(new F.Point(v.a.x,v.a.y)));if(matches.length){if(matches.length!==1||target!==electrical.find(gnd))throw Error('Ambiguous authorized ground hole refill');refilledHoles.push({...h,viaId:matches[0].id,viaCenter:matches[0].a,reason:'Explicit support source_trace joins this previously independent VSS/VSSQ escape to CPU GND; remove obsolete ground antipad and revalidate all foreign conductors.'})}else oldHoles.push(h.vertices)}
  if(layer!=='inner3'&&refilledHoles.length!==8)throw Error(`Expected eight explicitly authorized obsolete ground holes on ${layer}, found ${refilledHoles.length}`)
  let count=0;for(const ring of oldHoles)region=F.BooleanOperations.subtract(region,poly(ring))
  for(const c of foreign){if(!(Number.isFinite(c.r)&&c.r>0))throw Error(`Invalid conductor radius ${c.id}`);region=F.BooleanOperations.subtract(region,poly(hull([...circle(c.a,c.r+clearance),...circle(c.b,c.r+clearance)])));if(++count%100===0)console.log(`${layer}: ${count}/${foreign.length} foreign conductors subtracted`)}
  const faces=[...region.faces],outers=faces.filter(f=>f.orientation()===-1),holes=faces.filter(f=>f.orientation()===1),vertices=(f:any)=>[...f.edges].map((e:any)=>({x:e.start.x,y:e.start.y}))
  if(outers.length!==1)throw Error(`Global plane fragmented into ${outers.length} islands on ${layer}`)
  const outer=vertices(outers[0]),rings=holes.map(vertices),edges=[outer,...rings].flatMap(r=>r.map((a,i)=>[a,r[(i+1)%r.length]]as[P,P]))
  const failures:any[]=[],contacts:any[]=[];let minGap=Infinity
  // Check all foreign copper independently against final boolean geometry.
  // Segment distanceTo accounts for an interior crossing, unlike endpoint-only sampling.
  for(const c of foreign){const seg=new F.Segment(new F.Point(c.a.x,c.a.y),new F.Point(c.b.x,c.b.y));const inside=region.contains(new F.Point(c.a.x,c.a.y))||region.contains(new F.Point(c.b.x,c.b.y));const distance=Math.hypot(c.b.x-c.a.x,c.b.y-c.a.y)<1e-12?Math.min(...edges.map(([a,b])=>ps(c.a,a,b))):seg.distanceTo(region)[0];const gap=(inside?0:distance)-c.r;minGap=Math.min(minGap,gap);if(gap<.1016-1e-7)failures.push({id:c.id,gap,a:c.a,b:c.b,r:c.r})}
  for(const c of own.filter(c=>c.a.x===c.b.x&&c.a.y===c.b.y)){const annulus=Array.from({length:32},(_,i)=>new F.Point(c.a.x+c.r*.9*Math.cos(i*Math.PI/16),c.a.y+c.r*.9*Math.sin(i*Math.PI/16))),n=annulus.filter(p=>region.contains(p)).length;contacts.push({id:c.id,x:c.a.x,y:c.a.y,annulusSamplesInPlane:n,total:32});}
  const missing=contacts.filter(c=>c.annulusSamplesInPlane!==32),unique=(xs:any[])=>[...new Map(xs.map(c=>[`${c.x.toFixed(7)},${c.y.toFixed(7)}`,c])).values()]
  const plane={type:'pcb_copper_pour',pcb_copper_pour_id:`planned_global_${layer}`,shape:'brep',layer,source_net_id,covered_with_solder_mask:true,brep_shape:{outer_ring:{vertices:outer},inner_rings:rings.map(vertices=>({vertices}))}}
  planes.push(plane);planeAudit.push({layer,source_net_id,outerComponents:outers.length,holes:rings.length,originalLocalHolesSubtracted:oldHoles.length,refilledHoles,foreignConductors:foreign.length,minForeignClearanceMm:minGap,failures,viaContacts:contacts,uniqueViaCount:unique(contacts).length,uniqueMissingFullAnnulusContacts:unique(missing),capViaContacts:contacts.filter(c=>c.id.startsWith('power_plan_caps_')),missingFullAnnulusContacts:missing,scope:'32 annulus samples plus full foreign-conductor distance; effective capacitance and complete PDN impedance unqualified.'})
  writeFileSync(`${out}/planes.partial.json`,JSON.stringify(planes,null,2));console.log(JSON.stringify({layer,holes:rings.length,failures:failures.length,contacts:contacts.length,missing:missing.length,minGap}))
 }
 const physical=verifyDdrSystemCopper([...base,...planes],[...host.traces,...drop.replacements],connections,aliases)
 const aliasFreePhysical=verifyDdrSystemCopper([...base,...planes],[...host.traces,...drop.replacements],connections,{})
 const candidate=[...all,...planes],report={captureHash,hostTracesSha256:hash(host.traces),dropReplacementsSha256:hash(drop.replacements),capCircuitSha256:hash(capRaw),localPlanesSha256:hash(local),aliases,capRailConnections,aliasFreePhysical,planeAudit,physical,retainedLocalPlanes:false,localVoidGeometryPreservedBySubtractionExceptExplicitGroundRefills:true,replacedOuterBoundary:'Global outline x +/-31mm, y +/-20mm; four local ground regions absorbed into two global ground planes.',scope:`Isolated partial PDN candidate, 28 caps, ${drop.replacements.length} early/reused drops and ${host.traces.length} immutable signal routes. ${38-drop.replacements.length} outer RAM power launches remain unresolved; no DDR signoff.`}
 writeFileSync(`${out}/candidate.circuit.json`,JSON.stringify(candidate,null,2));writeFileSync(`${out}/planes.json`,JSON.stringify(planes,null,2));writeFileSync(`${out}/report.json`,JSON.stringify(report,null,2));console.log(JSON.stringify({out,errors:physical.errors.length,violations:physical.violations.length,connected:physical.connectivity.filter(c=>c.connected).length}))
}