#!/usr/bin/env python3 """Test whether BCM4500 register A8 auto-clears after write commands. If A8 auto-clears to 0x00 (or 0x02) after writing 0x03, then bcm_poll_ready() would always return TRUE, masking the fact that the DSP isn't processing commands. Uses enhanced 0xB6 diagnostic: wValue = page, wIndex = A8 command (0 = default READ) Returns 8 bytes: [0] write_A6_ok [1] A6 readback [2] write_A8_ok [3] A8 IMMEDIATE readback (no delay) [4] A8 after 2ms delay [5] A7 data result [6] A6 final state [7] echo: command sent """ import sys import time sys.path.insert(0, 'tools') from skywalker_lib import SkyWalker1 CMD_I2C_DIAG = 0xB6 CMD_I2C_RAW_READ = 0xB5 BCM4500_ADDR = 0x08 sw = SkyWalker1() sw.open() print('=== A8 Auto-Clear Test ===') print(f'Firmware: {sw.get_fw_version()}') # Boot with full sequence print('\n--- Booting BCM4500 (full boot) ---') result = sw._vendor_in(0x89, value=1, index=0, length=3) cfg, stage = result[0], result[1] print(f' Config: 0x{cfg:02X}, Stage: 0x{stage:02X}') # Read A8 default state before any commands print('\n--- A8 default state (after boot, before diagnostic) ---') a8_default = sw._vendor_in(CMD_I2C_RAW_READ, value=BCM4500_ADDR, index=0xA8, length=1) print(f' A8 default: 0x{a8_default[0]:02X} (bit0={a8_default[0] & 0x01})') # Test 1: READ command (0x01) — this was the previous behavior print('\n=== Test 1: A8 with READ command (0x01) ===') diag1 = sw._vendor_in(CMD_I2C_DIAG, value=0x06, index=0x01, length=8) print(f' A6 write ok: {diag1[0]}') print(f' A6 readback: 0x{diag1[1]:02X}') print(f' A8 write ok: {diag1[2]}') print(f' A8 IMMEDIATE: 0x{diag1[3]:02X} (bit0={diag1[3] & 0x01})') print(f' A8 after 2ms: 0x{diag1[4]:02X} (bit0={diag1[4] & 0x01})') print(f' A7 data: 0x{diag1[5]:02X}') print(f' A6 final: 0x{diag1[6]:02X}') print(f' Command sent: 0x{diag1[7]:02X}') # Reset A8 back to default by reading time.sleep(0.01) # Test 2: WRITE command (0x03) — the one used by init blocks print('\n=== Test 2: A8 with WRITE command (0x03) ===') diag2 = sw._vendor_in(CMD_I2C_DIAG, value=0x06, index=0x03, length=8) print(f' A6 write ok: {diag2[0]}') print(f' A6 readback: 0x{diag2[1]:02X}') print(f' A8 write ok: {diag2[2]}') print(f' A8 IMMEDIATE: 0x{diag2[3]:02X} (bit0={diag2[3] & 0x01})') print(f' A8 after 2ms: 0x{diag2[4]:02X} (bit0={diag2[4] & 0x01})') print(f' A7 data: 0x{diag2[5]:02X}') print(f' A6 final: 0x{diag2[6]:02X}') print(f' Command sent: 0x{diag2[7]:02X}') # Test 3: Try other A8 values print('\n=== Test 3: Various A8 values ===') for cmd in [0x00, 0x02, 0x04, 0xFF]: time.sleep(0.01) diag = sw._vendor_in(CMD_I2C_DIAG, value=0x00, index=cmd, length=8) print(f' CMD=0x{cmd:02X}: A8_imm=0x{diag[3]:02X} A8_2ms=0x{diag[4]:02X} ' f'A7=0x{diag[5]:02X}') # Analysis print('\n=== Analysis ===') if diag2[3] != 0x03 or diag2[4] != 0x03: print(f' !! A8 AUTO-CLEARS after WRITE command!') print(f' Wrote 0x03, immediate={diag2[3]:02X}, after_2ms={diag2[4]:02X}') if (diag2[3] & 0x01) == 0 or (diag2[4] & 0x01) == 0: print(f' bcm_poll_ready() sees bit0=0 → always returns TRUE') print(f' Init blocks appear to succeed but DSP never processes them!') else: print(f' A8 retains WRITE command (0x03). No auto-clear.') if (diag1[3] == 0x01) and (diag2[3] == 0x03): print(f' Both READ and WRITE commands stick. DSP is genuinely not processing.') sw.close() print('\n=== Done ===')