from pathlib import Path
import subprocess,re,struct,json,hashlib
p=Path(__file__).resolve().parent;o=p/'build';elf=o/'drill_compute_A100.elf';binary=o/'drill_compute_A100.bin'
dis=(o/'disassembly.txt').read_text();nm=subprocess.check_output(['arm-none-eabi-nm','--defined-only',str(elf)],text=True);attrs=subprocess.check_output(['arm-none-eabi-readelf','-A',str(elf)],text=True)
required=['Reset_Handler','SystemInit','drill_safe_boot','drill_clock_init','drill_smo_step','mfoc_step','run_synthetic','main','drill_compute_diagnostic']
for symbol in required:assert re.search(r'\b'+symbol+r'\b',nm),symbol
reset=dis.split('<Reset_Handler>:')[1].split('\n\n')[0]
assert re.search(r'bl\s+.*<SystemInit>.*dsb.*isb.*bl\s+.*<main>',reset,re.S)
assert 'Tag_ABI_VFP_args: VFP registers' in attrs and 'Tag_FP_arch: VFPv4-D16' in attrs
assert re.search(r'\bvdiv\.f32\b',dis) and re.search(r'\bvmul\.f32\b',dis)
assert not re.search(r'\bdrill_pwm_\w+\b|\bdrill_dual_\w+\b|\bdrill_spi_\w+\b',nm)
sp,reset_vector=struct.unpack_from('<II',binary.read_bytes());assert sp==0x20005800 and reset_vector&1 and 0x08000000<=reset_vector&~1<0x08020000
source=(p/'target_diag_main.c').read_text();assert 'gpio_f_outputs = (1u << 1u)' in source and 'GPIOF->MODER' in source
assert 'DWT->CYCCNT' in source and 'o.angle_valid&&o.observer_locked' in source
# Source audit plus linked-symbol checks, not exhaustive MMIO execution proof.
assert 'TIM1->' not in source and 'ADC1->' not in source and 'SPI2->' not in source
size=subprocess.check_output(['arm-none-eabi-size',str(elf)],text=True).splitlines()[-1].split()
r={'status':'LINKED_DIAGNOSTIC_STATIC_READBACK_PASS_NOT_EXECUTED','bin_sha256':hashlib.sha256(binary.read_bytes()).hexdigest(),'elf_sha256':hashlib.sha256(elf.read_bytes()).hexdigest(),'flash_image_bytes':len(binary.read_bytes()),'RAM_linker_region_bytes':int(size[1])+int(size[2]),'hard_float_ABI':True,'startup_FPU_barriers_before_main':True,'GPIO_map':'A83_PF1','observer_and_FOC_linked':True,'DWT_capture_in_source':True,'physical_execution':False,'actual_DWT_cycles':None,'motor_run_permission':False,'full_runtime_budget_verified':False}
(o/'static-verification-A100.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r,indent=2))
