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

scripts/validate-rounded.py

"""Independent audit of phase handoff, angular continuity, and rounded geometry."""
import json,math
from pathlib import Path
root=Path(__file__).resolve().parents[1]
def read(phase):return json.loads((root/f'dist/autorouter-debug/phase-{phase}.output.traces.json').read_text())
def pieces(t):
 ps=t['route'];vs=[i for i,p in enumerate(ps) if p['route_type']=='via'];assert len(vs)==2
 return ps[:vs[0]+1],ps[vs[0]+1:vs[1]],ps[vs[1]:]
def metric(traces):
 angles=[]
 for t in traces:
  _,ps,_=pieces(t)
  for a,b,c in zip(ps,ps[1:],ps[2:]):
   ux,uy=b['x']-a['x'],b['y']-a['y'];vx,vy=c['x']-b['x'],c['y']-b['y']
   angles.append(abs(math.degrees(math.atan2(ux*vy-uy*vx,ux*vx+uy*vy))))
 return dict(maximumHeadingChangeDeg=max(angles),cornersOver45Deg=sum(a>45.001 for a in angles),acuteInteriorCorners=sum(a>90.001 for a in angles))
before,after=read(2),read(3);lookup={t['source_trace_id']:t for t in before};assert len(after)==47
for t in after:
 a,old,b=pieces(lookup[t['source_trace_id']]);p,new,q=pieces(t);assert a==p and b==q
 assert all(x['route_type']=='wire' and x['layer']==old[0]['layer'] and x['width']==.1 for x in new)
a,b=metric(before),metric(after);assert b['maximumHeadingChangeDeg']<=5.001
report=dict(criteriaVersion=2,before=a,after=b,signals=47,preservedDogboneVias=94,addedVias=0,minimumRadiusGuaranteed=False)
(root/'validation/rounded-score.json').write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(report,indent=2))