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/audit-ddr-reduced-spacing.ts
/** Available-copper DDR-to-DDR spacing exposure. No complete-board SI claim. */
import {readFileSync,writeFileSync} from 'node:fs'
import {resolve} from 'node:path'
import {pathToFileURL} from 'node:url'
import {createHash} from 'node:crypto'
import {ddrNetClass,AM3352_DDR3_REQUIREMENTS as rules} from '../src/ddr'
import {segmentProximityIntervals,unionSpacingIntervals,type SpacingInterval} from './ddr-spacing-intervals'
import {verifyDdrCapture} from './ddr-capture-provenance'
const [capture,integrated,ramDirectory]=process.argv.slice(2)
if(!capture||!integrated||!ramDirectory)throw Error('Usage: capture integrated-directory RAM-project-directory')
const read=(p:string)=>JSON.parse(readFileSync(p,'utf8')),hash=(p:string)=>createHash('sha256').update(readFileSync(p)).digest('hex')
const {captureHash}=verifyDdrCapture(capture),path=resolve(integrated,'candidate.circuit.json'),circuit=read(path),report=read(resolve(integrated,'report.json')),map=read(resolve(capture,'signal-map.json'))
if(report.captureHash!==captureHash)throw Error('Integrated capture mismatch')
const ownerPath=resolve(ramDirectory,'scripts/audit-am3352-obstacle-ownership.ts'),{getSourceNetOwnerForAudit}=await import(pathToFileURL(ownerPath).href),owner=getSourceNetOwnerForAudit(circuit),nets=new Map<string,{signal:string;cls:string}>()
for(const row of map){const cls=ddrNetClass(row.cpuSignal);if(!cls)continue;const net=owner(row.sourceTraceId);if(!net)throw Error(`Missing source net ${row.cpuSignal}`);const old=nets.get(net);if(old&&old.signal!==row.cpuSignal)throw Error('Distinct DDR signals have one source owner');nets.set(net,{signal:row.cpuSignal,cls})}
const segments:any[]=[]
for(const trace of circuit.filter((e:any)=>e.type==='pcb_trace')){
const net=owner(trace.pcb_trace_id),info=nets.get(net);if(!info)continue
for(let i=1;i<trace.route.length;i++){const a=trace.route[i-1],b=trace.route[i];if(a.route_type!=='wire'||b.route_type!=='wire'||a.layer!==b.layer)continue;const length=Math.hypot(b.x-a.x,b.y-a.y),width=Math.max(a.width,b.width);if(length<1e-8)continue;if(!Number.isFinite(width)||width<=0)throw Error('Invalid signal width');segments.push({a,b,length,width,layer:a.layer,net,...info,traceId:trace.pcb_trace_id,index:i})}
}
const totals=new Map<string,any>()
for(const a of segments){
const intervals:SpacingInterval[]=[],neighbors=new Set<string>()
for(const b of segments){
if(a.net===b.net||a.layer!==b.layer)continue
// Differential mates have a separate coupling/skew audit.
if(a.cls===b.cls&&['DQS0','DQS1','CK'].includes(a.cls))continue
const multiplier=a.cls===b.cls?rules.nominalSameClassSpacingWidths:rules.nominalOtherClassSpacingWidths,radius=multiplier*Math.max(a.width,b.width)
if(Math.max(a.a.x,a.b.x)+radius<Math.min(b.a.x,b.b.x)||Math.min(a.a.x,a.b.x)-radius>Math.max(b.a.x,b.b.x)||Math.max(a.a.y,a.b.y)+radius<Math.min(b.a.y,b.b.y)||Math.min(a.a.y,a.b.y)-radius>Math.max(b.a.y,b.b.y))continue
const overlap=segmentProximityIntervals(a.a,a.b,b.a,b.b,radius);if(overlap.length){intervals.push(...overlap);neighbors.add(b.signal)}
}
const union=unionSpacingIntervals(intervals),reduced=a.length*union.reduce((s,[lo,hi])=>s+hi-lo,0),row=totals.get(a.net)??{signal:a.signal,netClass:a.cls,availablePlanarMm:0,reducedSpacingMm:0,segments:[]}
row.availablePlanarMm+=a.length;row.reducedSpacingMm+=reduced;if(reduced>1e-8)row.segments.push({traceId:a.traceId,index:a.index,layer:a.layer,reducedMm:reduced,fractions:union,neighbors:[...neighbors].sort()});totals.set(a.net,row)
}
const rows=[...totals].map(([net,row])=>({...row,sourceToAllLoadsConnected:report.physical.connectivity.some((c:any)=>c.connected&&owner(c.name)===net),aggregateBelowBudget:row.reducedSpacingMm<=rules.reducedSpacingMaximumLengthMm+1e-7})).sort((a,b)=>b.reducedSpacingMm-a.reducedSpacingMm)
const output={captureHash,candidateSha256:hash(path),ownershipAuditorSha256:hash(ownerPath),nominalCenterSpacingWidths:{withinClass:3,betweenClasses:4},widthPolicy:'Use larger width for unequal-width segments (conservative).',maximumReducedSpacingMm:rules.reducedSpacingMaximumLengthMm,rows,scope:'Union of available wire-centerline lengths near other DDR nets on the same layer. Differential mates excluded for separate pair audit. Aggregates all copper per logical net, conservative for branched CA nets. Incomplete nets can accumulate additional exposure. Does not assess unrelated-signal keepouts, pads/vias, return paths, impedance or SI; never full DDR acceptance.'}
writeFileSync(resolve(integrated,'reduced-spacing-audit.json'),JSON.stringify(output,null,2)+'\n');console.log(JSON.stringify(rows.slice(0,8).map(({signal,reducedSpacingMm,availablePlanarMm,sourceToAllLoadsConnected,aggregateBelowBudget})=>({signal,reducedSpacingMm,availablePlanarMm,sourceToAllLoadsConnected,aggregateBelowBudget}))))