#!/usr/bin/env python3 """Quick diagnostic: test if 0xA0 writes to I2C registers trigger hardware.""" import usb.core, usb.util, time VID, PID = 0x09C0, 0x0203 A0 = 0xA0 I2CS = 0xE678; I2DAT = 0xE679; I2CTL = 0xE67A; CPUCS = 0xE600 dev = usb.core.find(idVendor=VID, idProduct=PID) for cfg in dev: for intf in cfg: if dev.is_kernel_driver_active(intf.bInterfaceNumber): dev.detach_kernel_driver(intf.bInterfaceNumber) try: dev.set_configuration() except: pass def a0r(addr, n=1): return bytes(dev.ctrl_transfer( usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_IN, A0, addr, 0, n, 2000)) def a0w(addr, val): dev.ctrl_transfer( usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_OUT, A0, addr, 0, bytes([val]), 2000) # Pre-halt flush try: lock = dev.ctrl_transfer( usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_IN, 0x90, 0, 0, 1, 2000) print(f"Pre-halt flush (0x90): 0x{lock[0]:02X}") except Exception as e: print(f"Flush failed: {e}") # Halt a0w(CPUCS, 0x01) time.sleep(0.01) print(f"CPUCS after halt: 0x{a0r(CPUCS)[0]:02X}") print(f"\n=== Register State After Halt ===") i2cs_orig = a0r(I2CS)[0] i2ctl_orig = a0r(I2CTL)[0] print(f"I2CS: 0x{i2cs_orig:02X}") print(f"I2CTL: 0x{i2ctl_orig:02X}") # Test 1: I2CTL writability print(f"\n=== Test 1: I2CTL writability ===") print(f"I2CTL before: 0x{a0r(I2CTL)[0]:02X}") a0w(I2CTL, 0x00) time.sleep(0.001) v = a0r(I2CTL)[0] print(f"I2CTL after 0x00 write: 0x{v:02X} {'CHANGED' if v == 0x00 else 'unchanged'}") a0w(I2CTL, 0x01) time.sleep(0.001) v = a0r(I2CTL)[0] print(f"I2CTL after 0x01 write: 0x{v:02X}") # Test 2: Write START to I2CS, read back print(f"\n=== Test 2: I2CS START ===") print(f"I2CS before START: 0x{a0r(I2CS)[0]:02X}") a0w(I2CS, 0x80) # bmSTART for i in range(5): val = a0r(I2CS)[0] print(f" I2CS read {i}: 0x{val:02X}") time.sleep(0.002) # Test 3: Write to I2DAT print(f"\n=== Test 3: I2DAT write (EEPROM addr) ===") print(f"I2CS before I2DAT write: 0x{a0r(I2CS)[0]:02X}") a0w(I2DAT, 0xA2) # EEPROM 0x51<<1 for i in range(5): val = a0r(I2CS)[0] print(f" I2CS read {i}: 0x{val:02X}") time.sleep(0.002) # Test 4: Read I2DAT print(f"\n=== Test 4: I2DAT read ===") dat = a0r(I2DAT)[0] print(f"I2DAT read: 0x{dat:02X}") print(f"I2CS after I2DAT read: 0x{a0r(I2CS)[0]:02X}") # Test 5: Write STOP print(f"\n=== Test 5: I2CS STOP ===") a0w(I2CS, 0x40) # bmSTOP for i in range(3): val = a0r(I2CS)[0] print(f" I2CS read {i}: 0x{val:02X}") time.sleep(0.002) # Test 6: Write arbitrary values to I2CS print(f"\n=== Test 6: I2CS raw write/read ===") for test_val in [0x00, 0xFF, 0x04, 0x80]: a0w(I2CS, test_val) time.sleep(0.001) rb = a0r(I2CS)[0] changed = "CHANGED" if rb != i2cs_orig else "unchanged" print(f" Wrote 0x{test_val:02X}, read 0x{rb:02X} {changed}") # Test 7: XDATA RAM write/read (control test) print(f"\n=== Test 7: XDATA RAM control test ===") TEST_ADDR = 0x3C00 orig = a0r(TEST_ADDR)[0] a0w(TEST_ADDR, 0xBE) time.sleep(0.001) readback = a0r(TEST_ADDR)[0] ok = "OK" if readback == 0xBE else "FAIL" print(f"RAM[0x3C00]: wrote 0xBE, read 0x{readback:02X} {ok}") # Test 8: Try writing 0x04 to I2CS (BERR clear bit) print(f"\n=== Test 8: BERR clear bit ===") a0w(I2CS, 0x04) time.sleep(0.001) v = a0r(I2CS)[0] print(f"After writing 0x04: I2CS=0x{v:02X}") # Summary print(f"\n=== Summary ===") final_i2cs = a0r(I2CS)[0] print(f"Final I2CS: 0x{final_i2cs:02X} (started at 0x{i2cs_orig:02X})") if final_i2cs == i2cs_orig: print("I2CS NEVER CHANGED -- host-side I2C register writes ignored by hardware") print("\nImplication: 0xA0 writes reach XDATA address space but the I2C") print("controller only responds to 8051 MOVX instructions, not USB engine writes.") print("The boot ROM's 0xA0 handler uses a different bus path for register access.") else: print("I2CS DID CHANGE -- host-side I2C register writes may work!")