"""Execute the linked Thumb du_ok with frozen MMIO snapshots, count instructions.
Not a Cortex-M4 cycle simulator. Not real ADC/TIM1/SPI timing evidence.
Requires external unicorn==2.1.4; emulator code is not bundled into firmware.
"""
from pathlib import Path
import subprocess,re,json,hashlib
from unicorn import Uc,UC_ARCH_ARM,UC_MODE_THUMB,UC_MODE_MCLASS,UC_HOOK_CODE
from unicorn.arm_const import UC_ARM_REG_SP,UC_ARM_REG_LR,UC_ARM_REG_R0,UC_CPU_ARM_CORTEX_M4
import unicorn
p=Path(__file__).resolve().parent.parent;t=p/'firmware/固件/drill_target/build'
elf=t/'drill_control_g431cb.elf';binary=t/'drill_control_g431cb.bin'
syms={}
for line in subprocess.check_output(['arm-none-eabi-nm',str(elf)],text=True).splitlines():
 m=re.match(r'([0-9a-fA-F]+)\s+\w\s+(\S+)$',line)
 if m:syms[m[2]]=int(m[1],16)
u=Uc(UC_ARCH_ARM,UC_MODE_THUMB|UC_MODE_MCLASS);u.ctl_set_cpu_model(UC_CPU_ARM_CORTEX_M4)
for address,size in [(0x08000000,0x20000),(0x20000000,0x10000),(0x40000000,0x30000),(0x48000000,0x2000),(0x50000000,0x1000)]:u.mem_map(address,size)
u.mem_write(0x08000000,binary.read_bytes())
for name,address in [('FLASH',0x40022000),('PWR',0x40007000),('RCC',0x40021000),('GPIOA',0x48000000),('GPIOB',0x48000400),('GPIOF',0x48001400),('TIM1',0x40012c00),('TIM2',0x40000000),('SPI2',0x40003800),('ADC1',0x50000000),('ADC2',0x50000100),('ADC_COMMON',0x50000300)]:u.mem_write(address,(p/'performance_model'/ (name+'.bin')).read_bytes())
for name,value in [('owned',1),('sampling_owned',1),('state',1),('drill_config',5),('drill_dual_state',9),('drill_adc_state',0)]:u.mem_write(syms[name],bytes([value]))
u.mem_write(syms['SystemCoreClock'],(128000000).to_bytes(4,'little'))
u.reg_write(UC_ARM_REG_SP,0x20005800);u.reg_write(UC_ARM_REG_LR,0x0801fff1)
trace=[]
def count(uc,address,size,data):trace.append(address)
u.hook_add(UC_HOOK_CODE,count)
u.emu_start(syms['du_ok']|1,0x0801fff0,count=10000)
assert u.reg_read(UC_ARM_REG_R0)==1,'frozen healthy guard path must return true'
result={'binary_sha256':hashlib.sha256(binary.read_bytes()).hexdigest(),'emulator':unicorn.__version__,'function':'du_ok','healthy_stream_path_return':1,'executed_instruction_count':len(trace),'core_clock_candidate_Hz':128000000,'optimistic_one_instruction_per_cycle_at_128MHz_us':len(trace)/128,'one_instruction_per_cycle_is_only_an_estimate':True,'cycle_accurate':False,'physical_validation':False,'includes_DMA_data_copy_and_consumer':False,'decision':'Review core clock and total sampling/FOC service budget before qualifying 20kHz. One guard is repeated in the current loop.'}
print(json.dumps(result,indent=2));(p/'performance_model/guard_instruction_receipt_A78.json').write_text(json.dumps(result,indent=2)+'\n')
