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.'}
}