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

src/DecouplingNetwork.tsx

import {Fragment} from 'react'
import {AM3352_PINS} from './pin-map'
import {FIXED_SUPPLY_DROPS} from './fixed-supply-drops'
import additionalCaps from './additional-decoupling.json'
import capRouteElbowsJson from './generated/fixed-cap-elbows.json'
export type DecouplingCap = {name:string;x:number;y:number;rotation:number;capacitance:string;footprint:string;net:string;power:number[];ground:number[];ball?:string;supply?:string;targetBall?:string}
const core=[[-3.2,-1.6,0],[0,0,0],[3.2,-1.6,180],[-3.2,1.6,0],[0,1.6,0],[3.2,1.6,180],[-2.4,-3.2,0],[1.6,-3.2,0]]
const mpu=[[3.2,4,180],[0,4,0],[3.2,2.4,180],[3.2,0,180],[4.8,.8,180]]
const small=(positions:number[][],start:number,net:string)=>positions.map(([x,y,rotation],i)=>({name:`C${start+i}`,x:x!,y:y!,rotation:rotation!,capacitance:'10nF',footprint:'cap0201_nosilkscreen',net,power:[x!+(rotation===180?-.8:.8),y!],ground:[x!+(rotation===180?.8:-.8),y!],ball:undefined as string|undefined}))
export const decouplingCaps:DecouplingCap[]=[
 ...small(core,1,'VDD_CORE_1V1'),...small(mpu,9,'VDD_MPU_1V26'),
 ...['CAP_VDD_RTC','CAP_VDD_SRAM_CORE','CAP_VBB_MPU','CAP_VDD_SRAM_MPU'].map((net,i)=>{const p=AM3352_PINS.find(p=>p.name===net)!;const power=[p.x+.4,p.y+.4];const x=i===1?-.8:i===3?2.4:power[0]!;return {name:`C${14+i}`,x,y:power[1]!+.8,rotation:270,capacitance:'1uF',footprint:'cap0402_nosilkscreen',net,power,ground:[x,power[1]!+1.6],ball:p.ballName}}),
 {name:'C18',x:-.8,y:-2.4,rotation:90,capacitance:'10uF',footprint:'cap0603_nosilkscreen',net:'VDD_CORE_1V1',power:[-.8,-.8],ground:[0,-3.2],ball:undefined},
 {name:'C19',x:1.6,y:2.4,rotation:90,capacitance:'10uF',footprint:'cap0603_nosilkscreen',net:'VDD_MPU_1V26',power:[1.6,4],ground:[1.6,.8],ball:undefined},
]
// C12's supply via also provides the nearest through-hole drop for H13.
decouplingCaps.find(c=>c.name==='C12')!.power=[3.2,.8]
decouplingCaps.find(c=>c.name==='C12')!.x=3.4
decouplingCaps.find(c=>c.name==='C12')!.ground=[4,-.8]
for(const c of decouplingCaps.filter(c=>c.ball)){
 if(c.name==='C16'){c.x=0;c.y=6.4;c.rotation=0;c.ground=[-.8,7.2]}
 else {const left=c.name!=='C17';c.x=c.power[0]!+(left?-.8:.8);c.y=c.power[1]!;c.rotation=left?0:180;c.ground=[c.power[0]!+(left?-1.6:1.6),c.power[1]!]}
}
for(const c of decouplingCaps.filter(c=>c.name==='C9'||c.name==='C10'))c.y=3.8
decouplingCaps.find(c=>c.name==='C9')!.x=3.2
decouplingCaps.find(c=>c.name==='C9')!.power=[2.4,4]
Object.assign(decouplingCaps.find(c=>c.name==='C14')!,{x:-2.4,y:4,rotation:90,ground:[-2.4,3.2]})
Object.assign(decouplingCaps.find(c=>c.name==='C17')!,{x:-.3,y:3.8,rotation:0,power:[.8,4],ground:[-.8,4]})
Object.assign(decouplingCaps.find(c=>c.name==='C10')!,{x:-.8,y:2.8,rotation:0,power:[0,3.2],ground:[-1.6,3.2]})
for(const c of decouplingCaps)c.supply=c.ball?c.net:Number(c.name.slice(1))<=8||c.name==='C18'?'VDD_CORE':'VDD_MPU'
decouplingCaps.push(...additionalCaps as DecouplingCap[])
// Shared supply vias are emitted once. DDR HS capacitors have unique pairs,
// checked separately against every other capacitor's anchor coordinates.
const viaKey=(xy:number[],net:string)=>`${xy[0]!.toFixed(5)},${xy[1]!.toFixed(5)}:${net}`
const capVias=new Map<string,{name:string;x:number;y:number;net:string}>()
for(const c of decouplingCaps)for(const [suffix,xy,net] of [['P',c.power,c.net],['G',c.ground,'GND']] as const){
 const key=viaKey(xy,net)
 if(!capVias.has(key))capVias.set(key,{name:`V_${c.name}_${suffix}`,x:xy[0]!,y:xy[1]!,net})
}
const capVia=(c:DecouplingCap,power:boolean)=>capVias.get(viaKey(power?c.power:c.ground,power?c.net:'GND'))!.name
export const powerDropVias=[{name:'V_GND_M12',x:1.6,y:-2.4,net:'GND'},{name:'V_CORE_JK12',x:2.4,y:0,net:'VDD_CORE_1V1'},{name:'V_1V8_E14',x:4,y:3.2,net:'VCC_1V8'},{name:'V_1V8_H15',x:4.8,y:1.6,net:'VCC_1V8'},{name:'V_1V8_K13',x:3.2,y:-.8,net:'VCC_1V8'}]
powerDropVias.push(...FIXED_SUPPLY_DROPS.filter(d=>d.viaName!=='V_C1_P').map(d=>({name:d.viaName,x:d.via[0]!,y:d.via[1]!,net:d.net})))
// Fixed capacitor routes retain their original pad/via endpoints. Each waypoint
// replaces an arbitrary-angle segment with a 45-degree diagonal followed by an
// axis-aligned segment. Selected against all fixed and saved native copper at
// the existing 0.0762 mm clearance. Short endpoint legs remain inside the
// original pad or via annulus; these are not exposed tuning micro-jogs.
const capRouteElbows: Record<string,{x:number;y:number}> = capRouteElbowsJson
const capRoutePath=(c:DecouplingCap,power:boolean)=>{
 const elbow=capRouteElbows[`${c.name}_${power?'POWER':'GROUND'}`]
 // pcbPath coordinates are relative to the source component, including rotation.
 const angle=-c.rotation*Math.PI/180,dx=(elbow?.x??c.x)-c.x,dy=(elbow?.y??c.y)-c.y
 const local={x:dx*Math.cos(angle)-dy*Math.sin(angle),y:dx*Math.sin(angle)+dy*Math.cos(angle)}
 return [...elbow?[local]:[],`${capVia(c,power)}.bottom`]
}
export function DecouplingNetwork(){return <group name="DECOUPLING">{FIXED_SUPPLY_DROPS.map(d=><Fragment key={d.ball}><trace name={`FIXED_DROP_${d.ball}`} from={`U1.${d.ball}`} to={`${d.viaName}.top`} pcbPath={[...d.points.slice(1,-1).map(([x,y])=>({x:x!,y:y!})),`${d.viaName}.top`]} thickness={.08128}/></Fragment>)}{decouplingCaps.map(c=><Fragment key={c.name}>
 <capacitor name={c.name} capacitance={c.capacitance} footprint={c.footprint} maxVoltageRating="6.3V" layer="bottom" pcbX={c.x} pcbY={c.y} pcbRotation={c.rotation} pcbStyle={{silkscreenTextVisibility:'hidden'}}/>
 <trace name={`${c.name}_POWER`} from={`${c.name}.pin1`} to={`${capVia(c,true)}.bottom`} pcbPath={capRoutePath(c,true)} thickness={.127}/>
 <trace name={`${c.name}_GROUND`} from={`${c.name}.pin2`} to={`${capVia(c,false)}.bottom`} pcbPath={capRoutePath(c,false)} thickness={.127}/>
 {c.ball&&<trace name={`${c.name}_LDO`} from={`U1.${c.ball}`} to={`${capVia(c,true)}.top`} pcbPath={[`${capVia(c,true)}.top`]} thickness={.127}/>}
 </Fragment>)}{[...capVias.values()].map(v=><Fragment key={v.name}><via name={v.name} pcbX={v.x} pcbY={v.y} fromLayer="top" toLayer="bottom" holeDiameter={.2} outerDiameter={.4} connectsTo={`net.${v.net}`}/></Fragment>)}{powerDropVias.map(v=><Fragment key={v.name}><via name={v.name} pcbX={v.x} pcbY={v.y} fromLayer="top" toLayer="bottom" holeDiameter={.2} outerDiameter={.4} connectsTo={`net.${v.net}`}/></Fragment>)}</group>}