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/audit-ddr-local-escape-contacts.ts

import {verifyDdrSystemCopper} from './check-ddr-system-copper'
/** A local escape may touch only its actual source pad and retained launch via. */
export function auditDdrLocalEscapeContacts(candidate:any[],trace:any,connections:any[]){
 const source=trace.route[0],via=trace.route.find((p:any)=>p.route_type==='via')
 if(!via||trace.route.filter((p:any)=>p.route_type==='via').length!==1)throw Error('Expected one physical launch via')
 const same=(a:any,b:any)=>Math.hypot(a.x-b.x,a.y-b.y)<1e-7
 const sourcePad=candidate.find(e=>e.type==='pcb_smtpad'&&e.pcb_port_id===source.start_pcb_port_id&&same(e,source))
 if(!sourcePad)throw Error('Source pad ownership missing')
 const viaIds=new Set(candidate.filter(e=>e.type==='pcb_via'&&e.pcb_trace_id===trace.pcb_trace_id&&same(e,via)&&Math.abs(e.outer_diameter-via.via_diameter)<1e-7&&Math.abs(e.hole_diameter-via.via_hole_diameter)<1e-7).map(e=>e.pcb_via_id))
 // A short first leg may turn while still inside the annular pad. Permit only
 // the contiguous, radially outward launch until it first leaves that copper.
 const launchSegments:any[]=[],vi=trace.route.indexOf(via)
 for(const direction of [-1,1]){
  let index=vi+direction,p=trace.route[index]
  if(p?.route_type!=='wire'||!same(p,via))continue
  for(index+=direction;index>=0&&index<trace.route.length;index+=direction){
   const q=trace.route[index];if(q.route_type!=='wire'||q.layer!==p.layer)break
   if(same(p,q)){p=q;continue}
   const radius=via.via_diameter/2+Math.max(p.width,q.width)/2
   if(Math.hypot(p.x-via.x,p.y-via.y)>radius+1e-7||(p.x-via.x)*(q.x-p.x)+(p.y-via.y)*(q.y-p.y)<-1e-9)break
   launchSegments.push({a:p,b:q,layer:p.layer});p=q
  }
 }
 // Keep the actual parent trace available for emitted-via ownership resolution.
 // Its duplicate fresh representation is excluded from fixed-contact classification.
 const physical=verifyDdrSystemCopper(candidate,[trace],connections,{},50,{reportSameNetContacts:true})
 const contacts=(physical.sameNetContacts??[]).filter(c=>(c.aShape.fresh?c.bShape:c.aShape).traceId!==trace.pcb_trace_id).map(c=>{
  const fresh=c.aShape.fresh?c.aShape:c.bShape,fixed=c.aShape.fresh?c.bShape:c.aShape
  const atSource=fixed.join===sourcePad.pcb_smtpad_id&&fresh.layer===source.layer&&[fresh.a,fresh.b].some(p=>same(p,source))
  const atVia=viaIds.has(fixed.join)&&([fresh.a,fresh.b].some(p=>same(p,via))||launchSegments.some(s=>s.layer===fresh.layer&&((same(s.a,fresh.a)&&same(s.b,fresh.b))||(same(s.a,fresh.b)&&same(s.b,fresh.a)))))
  return {...c,valid:atSource||atVia,kind:atSource?'source-pad':atVia?'retained-via':'unexpected-own-copper-contact'}
 })
 const segments:any[]=[]
 for(let i=1;i<trace.route.length;i++){const a=trace.route[i-1],b=trace.route[i];if(a.route_type==='wire'&&b.route_type==='wire'&&a.layer===b.layer&&!same(a,b))segments.push({a,b,layer:a.layer,index:i})}
 const cross=(a:any,b:any,p:any)=>(b.x-a.x)*(p.y-a.y)-(b.y-a.y)*(p.x-a.x)
 const on=(p:any,a:any,b:any)=>Math.abs(cross(a,b,p))<1e-9&&p.x>=Math.min(a.x,b.x)-1e-9&&p.x<=Math.max(a.x,b.x)+1e-9&&p.y>=Math.min(a.y,b.y)-1e-9&&p.y<=Math.max(a.y,b.y)+1e-9
 const selfContacts:any[]=[]
 for(let i=0;i<segments.length;i++)for(let j=i+2;j<segments.length;j++){
  const a=segments[i],b=segments[j];if(a.layer!==b.layer)continue
  const intersects=cross(a.a,a.b,b.a)*cross(a.a,a.b,b.b)<0&&cross(b.a,b.b,a.a)*cross(b.a,b.b,a.b)<0
  if(intersects||on(a.a,b.a,b.b)||on(a.b,b.a,b.b)||on(b.a,a.a,a.b)||on(b.b,a.a,a.b))selfContacts.push({first:a.index,second:b.index,layer:a.layer})
 }
 return {valid:!physical.errors.length&&!physical.violations.length&&contacts.every(c=>c.valid)&&!selfContacts.length,errors:physical.errors,violations:physical.violations,contacts,selfContacts,scope:'Same-net contacts limited to source pad and contiguous radially outward launch through the existing via annulus; re-entry and nonadjacent centerline self-intersections rejected.'}
}