seveibar/am3352-ram-dogbone-and-single-layer-route-test

AM3352BZCZ100 processor connected to a W631GG6MB-12 DDR3 memory chip through a routed, length-matched 16-bit DDR interface with clock/data-strobe pairs and control/address signals.

Version
0.0.9
License
unset
Stars
0

routing/algorithms.ts

import plan from "./coupled-route-plan.json"
import { materializePlan, checkTiming } from "./coupled-plan"

export const run = (fn: () => any) => {
 const handlers: Record<string, (event:any)=>void> = {}
 return { on(event:string,cb:any){handlers[event]=cb;return this}, stop(){},
 start(){try{handlers.complete?.({traces:fn()})}catch(error){handlers.error?.({error})}} }
}
export function layerFor(_input:any, name:string) {
 const route=plan.routes.find(r=>r.name===name)
 if(!route)throw new Error(`No planned signal layer for ${name}`)
 return route.layer
}
export const exitFor=(p:any)=>({x:p.x+0.4,y:p.y-0.4})
export function makeDogbones(input:any) {
 return input.connections.flatMap((c:any)=>c.pointsToConnect.map((p:any,i:number)=>{
  const layer=layerFor(input,c.name)
  // Half-pitch diagonal: local dogbone only, never a package-boundary fanout.
  const exit=exitFor(p)
  return {type:"pcb_trace",pcb_trace_id:`dogbone_${c.name}_${i}`,connection_name:c.name,source_trace_id:c.source_trace_id??c.name,
   route:[
    {route_type:"wire",x:p.x,y:p.y,layer:"top",width:0.1,start_pcb_port_id:p.pcb_port_id},
    {route_type:"wire",...exit,layer:"top",width:0.1},
    {route_type:"via",...exit,from_layer:"top",to_layer:layer,via_diameter:0.3,via_hole_diameter:0.15},
    {route_type:"wire",...exit,layer,width:0.1},
   ]}
 }))
}

// A 1 um lateral bias avoids degenerate collinear top stubs in native geometry tests.
// The same translation is applied to every via and signal-layer route.
const ROUTE_X_BIAS = 0.001
export async function dogboneFanout(input:any) {
 return run(()=>makeDogbones(input).map((t:any)=>({...t,route:t.route.map((p:any,i:number)=>i?{...p,x:p.x+ROUTE_X_BIAS}:p)})))
}
// Routes are explicit board-specific guides. They are not a general placement router.
export function createRoutingPhases(){
 let routed=false,tuned=false
 return {
  singleLayerRoute:async(input:any)=>run(()=>{
   const traces=materializePlan(input,"guide");routed=true;return traces
  }),
  coupledTuning:async(input:any)=>run(()=>{
   if(!routed)throw new Error("Coupled tuning requires the guide-routing phase")
   const traces=materializePlan(input,"tuned")
   checkTiming(input,traces)
   tuned=true
   return traces
  }),
  ordinaryTurnCleanup:async(input:any)=>run(()=>{
   if(!tuned)throw new Error("Turn cleanup requires the coupled-tuning phase")
   const traces=materializePlan(input,"simplified")
   checkTiming(input,traces)
   return traces
  })
 }
}