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/saved-paths.tsx
import { fanoutTracePath } from '@tscircuit/props'
import pathsJson from './generated/native.trace-paths.json'
import ddrLeftPathsJson from './generated/ddr_left.trace-paths.json'
import ddrTopPathsJson from './generated/ddr_top.trace-paths.json'
import ddrBottomPathsJson from './generated/ddr_bottom.trace-paths.json'
import { assertLayoutProfile, getAM3352Bounds, LAYOUT_PROFILES, type LayoutProfile } from './profiles'
import { UnroutedModule, AM3352SignalNets } from './UnroutedModule'
const pathsByProfile = {native:pathsJson.map(p=>fanoutTracePath.parse(p)),ddr_left:ddrLeftPathsJson.map(p=>fanoutTracePath.parse(p)),ddr_top:ddrTopPathsJson.map(p=>fanoutTracePath.parse(p)),ddr_bottom:ddrBottomPathsJson.map(p=>fanoutTracePath.parse(p))}
export function getAM3352TracePaths(profile:LayoutProfile='native'){assertLayoutProfile(profile);return pathsByProfile[profile]}
export const am3352TracePaths=getAM3352TracePaths('native')
export function Am3352Presolved({name='AM3352_SAVED',layoutProfile='native',pcbX=0,pcbY=0,pcbRotation=0}:{name?:string,layoutProfile?:LayoutProfile,pcbX?:number,pcbY?:number,pcbRotation?:number}) {
const bounds=getAM3352Bounds(layoutProfile)
const cx=(bounds.minX+bounds.maxX)/2,cy=(bounds.minY+bounds.maxY)/2,angle=pcbRotation*Math.PI/180
// Public placement and saved API paths stay anchored at the CPU center.
// Internally the rectangular fanout and its cached routes use boundary-center coordinates.
const width=bounds.maxX-bounds.minX,height=bounds.maxY-bounds.minY
const regionWidth=Math.abs(Math.cos(angle))*width+Math.abs(Math.sin(angle))*height,regionHeight=Math.abs(Math.sin(angle))*width+Math.abs(Math.cos(angle))*height
const localPaths=getAM3352TracePaths(layoutProfile).map(path=>({...path,route:path.route.map(point=>({...point,x:point.x-cx,y:point.y-cy}))}))
return <><fanout name={name} width={regionWidth} height={regionHeight} pcbX={pcbX+cx*Math.cos(angle)-cy*Math.sin(angle)} pcbY={pcbY+cx*Math.sin(angle)+cy*Math.cos(angle)} pcbRotation={pcbRotation} pcbTracePaths={localPaths}>
<group pcbX={-cx} pcbY={-cy}><UnroutedModule/></group>
</fanout><AM3352SignalNets signalNetPrefix={name}/></>
}
import type {GenericLocalAutorouter,SimpleRouteJson} from '@tscircuit/core'
// The sample's receiving pads coincide with saved exits. Power nets are
// connected by the profile copper planes generated after trace insertion.
export async function edgeContacts(input:SimpleRouteJson):Promise<GenericLocalAutorouter>{
const coincident=(c:SimpleRouteJson['connections'][number])=>{const p=c.pointsToConnect[0];return !!p&&c.pointsToConnect.every(q=>Math.hypot(q.x-p.x,q.y-p.y)<1e-5&&q.layer===p.layer)}
// Signal-net contacts are named source_net_* after internal escape nets are
// added. Only coincident net contacts belong here; supply nets use pours.
const traces=input.connections.filter(c=>!c.name.startsWith('source_net_')||(c.pointsToConnect.length>=2&&coincident(c))).map(c=>{
const p=c.pointsToConnect[0]!
if(c.pointsToConnect.some(q=>Math.hypot(q.x-p.x,q.y-p.y)>1e-5 || q.layer!==p.layer))throw Error(`Unrouted board connection ${c.name}`)
return {type:'pcb_trace' as const,pcb_trace_id:`edge:${c.name}`,connection_name:c.name,source_trace_id:c.source_trace_id,...c.name.startsWith('source_net_')?{source_net_id:c.name}:{},route:c.pointsToConnect.map(q=>({route_type:'wire' as const,x:q.x,y:q.y,layer:q.layer,width:.08128,...q.pcb_port_id?{end_pcb_port_id:q.pcb_port_id}:{}}))}
})
const handlers:Record<string,Array<(e:any)=>void>>={complete:[],error:[],progress:[]}
return {input,isRouting:false,start(){queueMicrotask(()=>handlers.complete.forEach(h=>h({type:'complete',traces})))},stop(){},on(e,h){handlers[e].push(h)},solveSync(){return traces},getOutputSimpleRouteJson(){return {...input,traces}}}
}