from pathlib import Path
import json
R=Path(__file__).resolve().parent
TIMING=0x30521317
# Assumptions, not measurements: HSI16 +/-5%, Standard-mode max transitions.
# RM0454 sec25.4.11 + DS12991 Table65 + UM10204 Standard-mode limits.
def constraints(word,f):
 p=(word>>28)&15;sc=(word>>20)&15;sd=(word>>16)&15;h=(word>>8)&255;l=word&255
 tc=1e9/f;tp=(p+1)*tc
 return {'high_min_ns':(h+1)*tp,'low_min_ns':(l+1)*tp,'period_min_ns':(h+l+2)*tp,
 'setup_ns':(sc+1)*tp,'hold_programmed_ns':sd*tp,
 'hold_lower_ns':max(0.,300-50-3*tc),'hold_upper_ns':3450-1000-260-4*tc}
def valid(d):return d['high_min_ns']>=4000 and d['low_min_ns']>=4700 and d['period_min_ns']>=10000 and d['setup_ns']>=1250 and d['hold_lower_ns']<=d['hold_programmed_ns']<=d['hold_upper_ns']
rows=[constraints(TIMING,f) for f in range(15200000,16800001,16000)]
assert all(valid(d) for d in rows)
# Real rejected alternatives: under-sized setup delay and zero high/low counters.
assert not all(valid(constraints(TIMING^(1<<20),f)) for f in [15200000,16800000])
assert not valid(constraints(TIMING&~0xffff,16800000))
out={'candidate_TIMINGR':hex(TIMING),'frequency_assumption_Hz':[15200000,16800000],'rise_assumption_max_ns':1000,'fall_assumption_max_ns':300,'analog_filter_assumption_ns':[50,260],'DNF':0,'sampled_frequencies':len(rows),'lowest_high_counter_ns':min(d['high_min_ns'] for d in rows),'lowest_low_counter_ns':min(d['low_min_ns'] for d in rows),'lowest_period_counter_ns':min(d['period_min_ns'] for d in rows),'highest_clock_rate_upper_bound_Hz':1e9/min(d['period_min_ns'] for d in rows),'lowest_setup_ns':min(d['setup_ns'] for d in rows),'negative_candidates':'REJECTED','scope':'Counter/hold/setup inequalities only. Actual rise/fall, oscillator frequency, START/STOP and signal integrity must be measured; not a bus qualification.','physical_measurements':False}
(R/'timing_model.json').write_text(json.dumps(out,indent=2)+'\n');print(json.dumps(out))
