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!")
|