seveibar/am3352-dev-board-4layer-dogbone

Defines PCB footprints and pin mappings for a TI AM3352ZCZ100 processor, JST GH connectors, and assembly-part lookup helpers for capacitors, resistors, and headers.

Version
0.1.5
License
unset
Stars
0

scripts/test-ddr-validator.py

"""Check rejection of skew and uniformly overlong buses using synthetic route mutations."""
import copy,json,math,os,subprocess,sys,tempfile
from pathlib import Path
base=json.load(open('dist/index/circuit.json'))
nets={e['source_net_id']:e['name'] for e in base if e['type']=='source_net'}
traces={e['source_trace_id']:e for e in base if e['type']=='source_trace'}
def lengthen(c,names,extra):
 for name in names:
  candidates=[]
  for t in c:
   if t['type']!='pcb_trace' or not any(nets.get(s)==name for s in traces.get(t.get('source_trace_id'),{}).get('connected_source_net_ids',[])):continue
   for i,(a,b) in enumerate(zip(t['route'],t['route'][1:])):
    if a['route_type']==b['route_type']=='wire' and a['layer']==b['layer']:
     le=math.hypot(b['x']-a['x'],b['y']-a['y'])
     if le>.1:candidates.append((le,t,i,a,b))
  le,t,i,a,b=max(candidates,key=lambda x:x[0]);h=math.sqrt((le+extra)**2-le**2)/2
  p={**a,'x':(a['x']+b['x'])/2-(b['y']-a['y'])/le*h,'y':(a['y']+b['y'])/2+(b['x']-a['x'])/le*h}
  t['route'].insert(i+1,p)
with tempfile.TemporaryDirectory() as tmp:
 inp=Path(tmp)/'circuit.json';out=Path(tmp)/'report.json'
 def check(c):
  inp.write_text(json.dumps(c));r=subprocess.run([sys.executable,'scripts/check-ddr-skew.py','--strict'],env={**os.environ,'AUDIT_CIRCUIT':str(inp),'DDR_REPORT_PATH':str(out)},capture_output=True,text=True)
  assert out.exists(),r.stderr
  return r,json.loads(out.read_text())
 r,report=check(base);assert r.returncode==0,r.stderr
 c=copy.deepcopy(base);lengthen(c,['DDR_A0'],1.0);r,report=check(c)
 assert r.returncode!=0 and next(g for g in report['groups'] if g['group']=='Address/control + CK envelope')['status']=='FAIL'
 c=copy.deepcopy(base);addr=next(g['nets'] for g in report['groups'] if g['group']=='Address/control + CK envelope');nominal=next(g for g in report['groups'] if g['group']=='Address/control + CK nominal length');extra=nominal['allowedMaximumMm']-min(report['nets'][n]['pathLengthMm'] for n in addr)+.5;lengthen(c,addr,extra);r,report=check(c)
 assert r.returncode!=0
 assert next(g for g in report['groups'] if g['group']=='Address/control + CK envelope')['status']=='PASS'
 assert next(g for g in report['groups'] if g['group']=='Address/control + CK nominal length')['status']=='FAIL'
 c=copy.deepcopy(base);lengthen(c,['DDR_DQS0'],.2);r,report=check(c)
 assert r.returncode!=0 and next(g for g in report['groups'] if g['group']=='DQS0 differential pair')['status']=='FAIL'
print('DDR validator regression passed: valid board, address skew, uniformly overlong address bus, and differential skew')