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/prepare-ddr-zq-resistors.tsx
import {checkPadPadClearance,checkPadTraceClearance,checkViaPadClearance,checkPcbComponentOverlap} from '@tscircuit/checks'
import {RootCircuit} from '@tscircuit/core'
import {readFileSync,writeFileSync,mkdirSync} from 'node:fs'
import {resolve} from 'node:path'
import {createHash} from 'node:crypto'
import {verifyDdrSystemCopper,auditDdrTraceJunctions} from './check-ddr-system-copper'
const[boardArg,outArg]=process.argv.slice(2);if(!boardArg||!outArg)throw Error('Usage: current-board output')
const board=resolve(boardArg),out=resolve(outArg),read=(p:string)=>JSON.parse(readFileSync(p,'utf8')),hash=(v:any)=>createHash('sha256').update(JSON.stringify(v)).digest('hex'),parent=read(`${board}/candidate.circuit.json`),manifest=read(`${board}/current-evidence-manifest.json`)
if(hash(parent)!==manifest.candidateCircuitSha256)throw Error('Stale parent')
const launches=parent.filter((e:any)=>e.type==='source_port'&&e.port_hints?.includes('SIG_ZQ')).map((p:any)=>{const source=parent.find((e:any)=>e.type==='source_trace'&&e.connected_source_port_ids?.includes(p.source_port_id)),trace=parent.find((e:any)=>e.type==='pcb_trace'&&e.source_trace_id===source.source_trace_id),end=trace.route.at(-1);if(end.layer!=='bottom')throw Error('Expected saved bottom ZQ escape');return{port:p,source,trace,end}})
if(launches.length!==2)throw Error('Expected two individual ZQ ports')
const c=new RootCircuit();c.add(<board width={64} height={42} routingDisabled>{launches.map((l:any,i:number)=><resistor key={i} name={`RZQ${i}`} resistance="240" footprint="0402" pcbX={l.end.x-1} pcbY={l.end.y} layer="bottom" />)}</board>);await c.renderUntilSettled()
const raw:any[]=c.getCircuitJson(),errors=raw.filter(e=>e.type.endsWith('_error'));if(errors.length)throw Error(JSON.stringify(errors))
const ids=new Map(raw.filter(e=>e[`${e.type}_id`]).map(e=>[e[`${e.type}_id`],`ddr_zq_${e[`${e.type}_id`]}`])),remap=(v:any):any=>Array.isArray(v)?v.map(remap):v&&typeof v==='object'?Object.fromEntries(Object.entries(v).map(([k,x])=>[k,remap(x)])):typeof v==='string'?ids.get(v)??v:v
const added=remap(raw).filter((e:any)=>!['pcb_board','source_board'].includes(e.type)),candidate=structuredClone(parent),wires:any[]=[],connections:any[]=[]
for(const[l,i]of launches.map((l:any,i:number)=>[l,i])){
const component=added.find((e:any)=>e.type==='source_component'&&e.name===`RZQ${i}`),sourcePorts=added.filter((e:any)=>e.type==='source_port'&&e.source_component_id===component.source_component_id),ports=added.filter((e:any)=>e.type==='pcb_port'&&sourcePorts.some((p:any)=>p.source_port_id===e.source_port_id))
const pads=added.filter((e:any)=>e.type==='pcb_smtpad'&&ports.some((p:any)=>p.pcb_port_id===e.pcb_port_id)).sort((a:any,b:any)=>b.x-a.x)
if(pads.length!==2||pads.some((p:any)=>p.layer!=='bottom'))throw Error('Expected two bottom resistor pads')
const signalPad=pads[0],groundPad=pads[1],signalPort=ports.find((p:any)=>p.pcb_port_id===signalPad.pcb_port_id),groundPort=ports.find((p:any)=>p.pcb_port_id===groundPad.pcb_port_id)
if(Math.abs(signalPad.y-l.end.y)>1e-7||signalPad.x>=l.end.x)throw Error('Resistor launch must continue west')
candidate.find((e:any)=>e.source_trace_id===l.source.source_trace_id&&e.type==='source_trace').connected_source_port_ids.push(signalPort.source_port_id)
const wire={type:'pcb_trace',pcb_trace_id:`ddr_zq_lead_${i}`,source_trace_id:l.source.source_trace_id,route:[{route_type:'wire',x:l.end.x,y:l.end.y,layer:'bottom',width:.12},{route_type:'wire',x:signalPad.x,y:signalPad.y,layer:'bottom',width:.12,end_pcb_port_id:signalPad.pcb_port_id}]};wires.push(wire)
component.supplier_part_numbers={};component.tolerance=1
connections.push({byte:i,resistor:component.name,resistanceOhms:component.resistance,tolerancePercent:1,zqSourcePort:l.port.source_port_id,resistorSignalPort:signalPort.source_port_id,resistorSignalPcbPort:signalPort.pcb_port_id,ramPcbPort:parent.find((e:any)=>e.type==='pcb_port'&&e.source_port_id===l.port.source_port_id).pcb_port_id,sourceTraceId:l.source.source_trace_id,resistorGroundPort:groundPort.source_port_id,groundPad,groundConnected:false})
}
candidate.push(...added)
const complete=[...candidate,...wires],newPadIds=new Set(added.filter((e:any)=>e.type==='pcb_smtpad').map((e:any)=>e.pcb_smtpad_id)),newErrors=[...checkPadPadClearance(complete,{minClearance:.1016}),...checkPadTraceClearance(complete,{minClearance:.1016}),...checkViaPadClearance(complete,{minClearance:.1016}),...checkPcbComponentOverlap(complete)].filter(e=>JSON.stringify(e).includes('ddr_zq_')),connectivity=verifyDdrSystemCopper(complete,[],connections.map(c=>({name:c.sourceTraceId,source_trace_id:c.sourceTraceId,pointsToConnect:[{pointId:c.ramPcbPort},{pointId:c.resistorSignalPcbPort}]})),{},2)
const physical=verifyDdrSystemCopper(candidate,wires,[],{},0),junctions=auditDdrTraceJunctions([...candidate,...wires]),report={parentCircuitSha256:hash(parent),candidateCircuitSha256:hash([...candidate,...wires]),accepted:false,newSupportPlacementErrors:newErrors,zqPadConnectivity:connectivity.connectivity,zqLeadsPhysicallyConnected:connectivity.connectivity.every(c=>c.connected),signalLeadGeometryValid:!physical.errors.length&&!physical.violations.length&&physical.angles.valid&&junctions.valid,connections,physical,junctions,scope:'Isolated physical 240-ohm resistor placement and ZQ leads. Ground returns remain unrouted; the generic DDR host checker disallows bottom-layer fresh signals and is diagnostic here, while bottom ZQ support uses the explicit placement/clearance and source-pad connectivity evidence. resistor tolerance is a procurement requirement, not a selected manufacturer part. No complete ZQ or DDR qualification.'}
mkdirSync(out,{recursive:true});writeFileSync(`${out}/candidate.circuit.json`,JSON.stringify([...candidate,...wires],null,2)+'\n');writeFileSync(`${out}/report.json`,JSON.stringify(report,null,2)+'\n');console.log(JSON.stringify({signalLeadGeometryValid:report.signalLeadGeometryValid,errors:physical.errors.length,violations:physical.violations.length,junctions:junctions.valid}))