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/safe-meanders.ts

/** Experimental replacement tuner. Never calls the elastic matcher or global rounder.
 * Returns false when a length target cannot be met with valid geometry.
 * Integration is gated on completing all bus and pair length targets.
 */
import {length,segmentDist} from './single-layer'
type P={x:number,y:number};type R={name:string,points:P[]}
const RADIUS=.12
function wave(w:number,h:number):P[]{
 const p:P[]=[{x:0,y:0}]
 for(const [cx,cy,start,end] of [[0,RADIUS,-90,0],[2*RADIUS,h-RADIUS,180,90],[w-2*RADIUS,h-RADIUS,90,0],[w,RADIUS,180,270]])for(let k=0;k<=18;k++){
  const a=(start+(end-start)*k/18)*Math.PI/180,q={x:cx+RADIUS*Math.cos(a),y:cy+RADIUS*Math.sin(a)}
  if(Math.hypot(q.x-p.at(-1)!.x,q.y-p.at(-1)!.y)>1e-8)p.push(q)
 }
 return p
}
const dist=(a:P,b:P)=>Math.hypot(a.x-b.x,a.y-b.y)
const bbox=(a:P,b:P,c:P,d:P,g:number)=>Math.max(a.x,b.x)+g>=Math.min(c.x,d.x)&&Math.max(c.x,d.x)+g>=Math.min(a.x,b.x)&&Math.max(a.y,b.y)+g>=Math.min(c.y,d.y)&&Math.max(c.y,d.y)+g>=Math.min(a.y,b.y)
export function tune(r:R,others:R[],vias:any[],target:number,tol=.05){
 const fixed:[P,P,number][]=[]
 for(const q of others)if(q!==r)for(let i=1;i<q.points.length;i++)fixed.push([q.points[i-1],q.points[i],.20005])
 for(const v of vias)if(v.net!==r.name)fixed.push([v,v,.30005])
 for(let pass=0;pass<80;pass++){
  const need=target-length(r.points);if(need<=tol)return true
  const ps=r.points;let best:any
  for(let i=0;i<ps.length-1;i++){
   const a=ps[i],b=ps[i+1],d=dist(a,b);if(d<.54)continue
   const u={x:(b.x-a.x)/d,y:(b.y-a.y)/d}
   for(const w of [.5,.7,1,1.5,2]){
    if(w+.04>d)continue
    for(let off=.02;off+w<d-.019;off+=.15){
     const o={x:a.x+off*u.x,y:a.y+off*u.y},q={x:o.x+w*u.x,y:o.y+w*u.y}
     // Trim a local 0.3 mm of arclength from both ends of the unchanged path.
     const own:[P,P,number][]=[]
     const left=[...ps.slice(0,i+1),o].reverse(),right=[q,...ps.slice(i+1)]
     for(const side of [left,right]){let skip=.3;for(let k=1;k<side.length;k++){const x=side[k-1],y=side[k],l=dist(x,y);if(skip>=l){skip-=l;continue}const z={x:x.x+(y.x-x.x)*skip/l,y:x.y+(y.y-x.y)*skip/l};skip=0;own.push([z,y,.20005])}}
     for(const sign of [1,-1]){
      const make=(h:number)=>wave(w,h).map(p=>({x:o.x+u.x*p.x-u.y*p.y*sign,y:o.y+u.y*p.x+u.x*p.y*sign}))
      const obstacles=[...fixed,...own]
      const valid=(h:number)=>{const c=make(h);const xs=c.map(p=>p.x),ys=c.map(p=>p.y),mn={x:Math.min(...xs),y:Math.min(...ys)},mx={x:Math.max(...xs),y:Math.max(...ys)};const near=obstacles.filter(([a,b,g])=>bbox(mn,mx,a,b,g));for(let j=1;j<c.length;j++){const x=c[j-1],y=c[j];if(Math.abs(y.x)>34.5||Math.abs(y.y)>29.5|| (Math.abs(y.x)<8&&(y.y> -7.5||y.y< -13.0)))return false;for(const [a,b,g] of near)if(bbox(x,y,a,b,g)&&segmentDist(x,y,a,b)<g)return false}return true}
      if(!valid(.24))continue
      let lo=.24,hi=Math.min(25,(need+8*RADIUS-2*Math.PI*RADIUS)/2);if(hi<lo)continue
      for(let k=0;k<13;k++){const m=(lo+hi)/2;if(valid(m))lo=m;else hi=m}
      const c=make(lo),gain=length(c)-w
      if(!best||gain>best.gain)best={i,c,gain};if(need-gain<=tol){r.points=[...ps.slice(0,i+1),...c,...ps.slice(i+1)];return true}
     }
    }
   }
  }
  if(!best)return false
  r.points=[...ps.slice(0,best.i+1),...best.c,...ps.slice(best.i+1)]
 }
 return target-length(r.points)<=tol
}