One-off diagnostic scripts from experiments 0xD7-0xDB investigating the I2C BERR deadlock. Documents the systematic elimination of software-only recovery approaches: - i2c_host_test.py: Proved 0xA0 register writes cannot drive I2C bus - i2c_register_test.py: Tested I2C register writability from host - i2c_recovery_boot.py: Attempted I2C state machine recovery via boot - eeprom_flash_a0.py: Host-side EEPROM flash attempt (failed) - boot_ab_test.py / boot_test.py: EEPROM boot reliability testing - a8_autoclear_test.py: BCM4500 command register auto-clear behavior - addr_gateway_test.py: BCM3440 gateway address routing analysis - stock_fw_compare.py / stock_fw_test.py: Stock vs custom fw analysis
127 lines
3.8 KiB
Python
127 lines
3.8 KiB
Python
#!/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!")
|