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/prepare-input.ts
import {readFileSync,writeFileSync} from 'node:fs'
import {FIXED_SUPPLY_DROPS} from '../src/fixed-supply-drops'
import {decouplingCaps} from '../src/DecouplingNetwork'
import {AM3352_POWER_PLANES} from '../src/layout'
import {AM3352_PINS} from '../src/pin-map'
const fixture=JSON.parse(readFileSync('scripts/fixtures/captured-seed.json','utf8'))
const {input,options}=fixture
const layers=['top','inner1','inner2','inner3','inner4','bottom']
// Six distinct rail pours; signal traces share these layers with clearance.
// Inner1 remains the ground reference, with no signal escape tracks on it.
const mapLayer=(l:string)=>({top:'top',bottom:'bottom',inner1:'inner1',inner2:'top',inner3:'bottom',inner4:'inner2',inner5:'inner3',inner6:'inner4',inner7:'inner2',inner8:'inner3'}[l]!)
input.layerCount=6;input.allowBlindAndBuriedVias=false
input.minViaDiameter=.4;input.minViaPadDiameter=.4;input.min_via_pad_diameter=.4
input.minViaHoleDiameter=.2;input.min_via_hole_diameter=.2
for(const o of input.obstacles){
if(o.circuitJsonMetadata?.pcb_via_id){o.layers=layers;o.width=.4;o.height=.4}
else o.layers=[...new Set(o.layers.map(mapLayer))]
}
for(const t of input.traces)for(const p of t.route){
if(p.layer)p.layer=mapLayer(p.layer)
if(p.route_type==='via'){p.from_layer=mapLayer(p.from_layer);p.to_layer=mapLayer(p.to_layer);p.layers=layers;p.via_diameter=.4;p.via_hole_diameter=.2}
}
for(const b of input.buses){if(b.termination?.type==='plane')b.termination.layer=mapLayer(b.termination.layer)==='top'?'inner2':mapLayer(b.termination.layer);delete b.allowedLayers;delete b.preferredLayers}
options.buses=input.buses
options.escapeLayers=['top','inner2','inner3','inner4','bottom']
options.allowBlindAndBuriedVias=false;options.viaDiameter=.4;options.viaHoleDiameter=.2
const placed=JSON.parse(readFileSync('dist/six-layer-placed.circuit.json','utf8'))
const fixedConnectionNames=new Set(input.connections.filter((c:any)=>FIXED_SUPPLY_DROPS.some(d=>{const p=AM3352_PINS.find(p=>p.ballName===d.ball)!;return Math.hypot(p.x-c.pointsToConnect[0].x,p.y-c.pointsToConnect[0].y)<1e-6})).map((c:any)=>c.name))
input.connections=input.connections.filter((c:any)=>!fixedConnectionNames.has(c.name))
input.buses=input.buses.filter((b:any)=>!b.connectionNames.some((n:string)=>fixedConnectionNames.has(n)))
// Keep the captured ball connectivity; rebuild every fixed capacitor pad, via
// and trace from the current rendered network. IDs use a separate namespace so
// adding components cannot alias the captured BGA port IDs.
const ballObstacles=input.obstacles.filter((o:any)=>AM3352_PINS.some(p=>p.ballName===o.circuitJsonMetadata?.source_port_name))
const netTokens=new Map<string,string[]>()
for(const plane of AM3352_POWER_PLANES){
const ball=AM3352_PINS.find(p=>plane.pins.includes(p.pinNumber))!.ballName
const ref=ballObstacles.find((o:any)=>o.circuitJsonMetadata.source_port_name===ball)
const names=input.connections.filter((c:any)=>plane.pins.some(n=>{const p=AM3352_PINS[n-1]!;return Math.hypot(p.x-c.pointsToConnect[0].x,p.y-c.pointsToConnect[0].y)<1e-6})).map((c:any)=>c.name)
netTokens.set(plane.netName,[...ref.connectedTo,...names])
}
for(const c of decouplingCaps.filter(c=>c.ball))netTokens.set(c.net,ballObstacles.find((o:any)=>o.circuitJsonMetadata.source_port_name===c.ball).connectedTo)
const tokens=(net:string)=>{const t=netTokens.get(net);if(!t)throw Error(`Unknown fixed-copper rail ${net}`);return t}
const netName=(id:string)=>placed.find((e:any)=>e.type==='source_net'&&e.source_net_id===id)?.name
input.obstacles=[...ballObstacles]
for(const c of decouplingCaps){
const sc=placed.find((e:any)=>e.type==='source_component'&&e.name===c.name)
const pc=placed.find((e:any)=>e.type==='pcb_component'&&e.source_component_id===sc.source_component_id)
const pads=placed.filter((e:any)=>e.type==='pcb_smtpad'&&e.pcb_component_id===pc.pcb_component_id)
for(const [i,pad] of pads.entries())input.obstacles.push({type:'rect',center:{x:pad.x,y:pad.y},width:pad.width,height:pad.height,layers:['bottom'],componentId:`fixed_${c.name}`,connectedTo:[...tokens(i===0?c.net:'GND'),`fixed_${c.name}_pad${i}`],circuitJsonMetadata:{pcb_smtpad_id:`fixed_${c.name}_pad${i}`}})
}
for(const v of placed.filter((e:any)=>e.type==='pcb_via'))input.obstacles.push({type:'rect',shape:'circle',center:{x:v.x,y:v.y},width:v.outer_diameter,height:v.outer_diameter,layers,connectedTo:[...tokens(netName(v.source_net_id)),`fixed_${v.pcb_via_id}`],circuitJsonMetadata:{pcb_via_id:`fixed_${v.pcb_via_id}`}})
input.traces=placed.filter((e:any)=>e.type==='pcb_trace').map((t:any)=>{
const st=placed.find((e:any)=>e.type==='source_trace'&&e.source_trace_id===t.source_trace_id)
const net=netName(st.connected_source_net_ids[0])
const representative=input.connections.find((c:any)=>tokens(net).includes(c.name))?.name??`fixed_${st.name}`
return {type:'pcb_trace',pcb_trace_id:`fixed_${t.pcb_trace_id}`,connection_name:representative,connectsTo:tokens(net),route:t.route.map(({start_pcb_port_id,end_pcb_port_id,...p}:any)=>p)}
})
options.densePlaneReservationBusIds=input.buses.filter((b:any)=>b.termination?.type==='plane').map((b:any)=>b.busId)
options.denseUnrestrictedPlaneRoutingBusIds=['U1_PIN86_DROP','U1_PIN139_DROP','U1_PIN156_DROP','U1_PIN174_DROP','U1_PIN141_DROP','U1_PIN317_DROP','U1_PIN2_DROP','U1_PIN267_DROP','U1_PIN222_DROP','U1_PIN168_DROP']
options.busDirections={...options.busDirections,U1_PIN86_DROP:'down',U1_PIN141_DROP:'up',U1_PIN139_DROP:'down',U1_PIN156_DROP:'down',U1_PIN174_DROP:'up'}
input.buses=input.buses.flatMap((b:any)=>b.termination?.type==='plane'||b.busId.startsWith('PAIR_')?[b]:b.connectionNames.map((n:string,i:number)=>({...b,busId:`${b.busId}_pin_${i}`,connectionNames:[n]})))
options.buses=input.buses
options.maxLayerCombinations=16
options.singleLayerAdaptiveExits=true
writeFileSync('scripts/fixtures/native.input.json',JSON.stringify(fixture,null,2)+'\n')