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/check-ddr-integration.ts

import { readFileSync, mkdirSync, writeFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { createHash } from 'node:crypto'
import { auditRouteAngles } from './check-route-angles'
import { adaptDdrMemoryPaths, DDR_MEMORY_SIX_LAYER_MAP } from '../src/ddr-memory'

type Point = { x: number; y: number }
type Shape = { owner: string; layer: string; a: Point; b: Point; radius: number }
const dist = (a: Point, b: Point) => Math.hypot(a.x-b.x,a.y-b.y)
function pointSegment(p: Point, a: Point, b: Point) {
  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 dist(p,{x:a.x+t*dx,y:a.y+t*dy})
}
function segmentDistance(a:Point,b:Point,c:Point,d:Point) {
 const cross=(p:Point,q:Point,r:Point)=>(q.x-p.x)*(r.y-p.y)-(q.y-p.y)*(r.x-p.x)
 if(cross(a,b,c)*cross(a,b,d)<0&&cross(c,d,a)*cross(c,d,b)<0)return 0
 return Math.min(pointSegment(a,c,d),pointSegment(b,c,d),pointSegment(c,a,b),pointSegment(d,a,b))
}
const input = process.argv[2]
if (!input) throw new Error('Usage: bun scripts/check-ddr-integration.ts /path/to/memory-fanout')
const base = resolve(input)
const pins = JSON.parse(readFileSync(resolve(base,'src/pin-map.json'),'utf8')) as Array<Point & { ball:string; radius:number; routed:boolean }>
const layers = ['top', ...Array.from({length:8},(_,i)=>`inner${i+1}`), 'bottom']
const results = []
for(const profile of ['bus_grouped','outward_north','outward_south','inward_north','inward_south']) {
 const raw = readFileSync(resolve(base,`src/generated/${profile}.trace-paths.json`),'utf8')
 const sha256 = createHash('sha256').update(raw).digest('hex')
 const original = JSON.parse(raw)
 const paths = adaptDdrMemoryPaths(original, profile==='bus_grouped' ? DDR_MEMORY_SIX_LAYER_MAP : undefined, profile==='bus_grouped' ? .1168 : undefined).map(p => ({...p,route:p.route.map(q=>({...q,x:Number(q.x),y:Number(q.y)}))}))
 const geometry: Shape[] = pins.map(p=>({owner:`U1.ball_${p.ball}`,layer:'top',a:p,b:p,radius:p.radius}))
 let viaCount=0
 for(const path of paths) {
  for(const point of path.route) if(point.route_type==='via') {
   viaCount++
   // Conventional vias occupy every physical layer, not only entry/exit.
   for(const layer of layers) geometry.push({owner:path.connection,layer,a:point,b:point,radius:Number(point.via_diameter)/2})
  }
  for(let i=1;i<path.route.length;i++) {
   const a=path.route[i-1]!, b=path.route[i]!
   if(a.route_type==='wire'&&b.route_type==='wire'&&a.layer===b.layer) geometry.push({owner:path.connection,layer:String(a.layer),a,b,radius:Math.max(Number(a.width),Number(b.width))/2})
  }
 }
 let minClearanceMm=Infinity
 const violations: unknown[]=[]
 for(let i=0;i<geometry.length;i++)for(let j=i+1;j<geometry.length;j++) {
  const a=geometry[i]!,b=geometry[j]!
  if(a.owner===b.owner||a.layer!==b.layer)continue
  const gap=segmentDistance(a.a,a.b,b.a,b.b)-a.radius-b.radius
  minClearanceMm=Math.min(minClearanceMm,gap)
  if(gap<.1016-1e-8) violations.push({a:a.owner,b:b.owner,layer:a.layer,clearanceMm:gap})
 }
 const angles=auditRouteAngles(paths)
 results.push({profile,sha256,traceWidthOverrideMm:profile==='bus_grouped'?.1168:null,angles,routeCount:paths.length,viaCount,minClearanceMm,requiredClearanceMm:.1016,violationCount:violations.length,violations:violations.slice(0,10)})
}
mkdirSync('dist/ddr-integration',{recursive:true})
writeFileSync('dist/ddr-integration/memory-adapter-audit.json',JSON.stringify({source:base,scope:'Saved XY copper and original pads, expanded full-depth via barrels. Does not validate rendered adapter or host circuitry.',results},null,2)+'\n')
console.log(JSON.stringify(results.map(({violations,...r})=>r),null,2))
if(results.some(r=>r.violationCount || !r.angles.valid))process.exitCode=1