From e9e5ab859a2bc8a31cb510c2687e415b1d11e1df Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Fri, 20 Feb 2026 11:08:40 -0700 Subject: [PATCH] Add init block readback verification to match stock firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stock firmware at 0x0DDD reads back each init block from register A7 after writing and verifies the data matches (with bit 7 XOR'd on the block address byte). Without this readback, the BCM4500 may not finalize the write — our init blocks were "silently failing" (I2C succeeds, status reports booted, but SNR reads all zeros). Changes: - bcm_write_init_block: add pre-write bcm_poll_ready(), post-write A7 readback with XOR(0x80) on byte[0] and full data comparison - i2c_rd buffer: expand from 8 to 24 bytes for 16-byte block readback This is the most likely root cause of the BCM4500 "boots but doesn't work" issue (Task #5). Needs hardware test to confirm. --- firmware/skywalker1.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/firmware/skywalker1.c b/firmware/skywalker1.c index 9ed9afe..b33e935 100644 --- a/firmware/skywalker1.c +++ b/firmware/skywalker1.c @@ -132,7 +132,7 @@ volatile __bit got_sud; /* I2C scratch buffers in xdata (24 bytes: fits 20-byte EEPROM blocks) */ static __xdata BYTE i2c_buf[24]; -static __xdata BYTE i2c_rd[8]; +static __xdata BYTE i2c_rd[24]; /* TUNE_MONITOR result buffer: filled by OUT phase, returned by IN phase */ static __xdata BYTE tm_result[10]; @@ -847,6 +847,12 @@ static BOOL bcm_read_signal_block(void) { static BOOL bcm_write_init_block(const __code BYTE *data, BYTE len) { BYTE i; + /* Pre-write readiness check — stock firmware 0x0DE9 calls wait_for_ready() + * (0x2000) before each block. This polls A8 + additional conditions with + * up to 10 retries. Our simplified version polls A8 only. */ + if (!bcm_poll_ready()) + return FALSE; + /* Page select = 0 */ if (!bcm_direct_write(BCM_REG_PAGE, 0x00)) return FALSE; @@ -871,7 +877,34 @@ static BOOL bcm_write_init_block(const __code BYTE *data, BYTE len) { return FALSE; /* Wait for BCM4500 to process the write */ - return bcm_poll_ready(); + if (!bcm_poll_ready()) + return FALSE; + + /* Readback verification — stock firmware 0x0DDD does this after every + * init block write. The BCM4500 may require the readback to finalize + * the write (two-phase commit), or this catches silent write failures. + * + * Protocol (from disassembly at 0x0E61-0x0EE2): + * 1. Re-select page 0 (A6 = 0x00) + * 2. Read back len bytes from A7 into scratch buffer + * 3. First readback byte has bit 7 set by BCM4500 — XOR to clear + * 4. Compare all bytes against original data + */ + if (!bcm_direct_write(BCM_REG_PAGE, 0x00)) + return FALSE; + + if (!i2c_combined_read(BCM4500_ADDR, BCM_REG_DATA, len, i2c_rd)) + return FALSE; + + /* BCM4500 sets bit 7 of the block address byte in readback */ + i2c_rd[0] ^= 0x80; + + for (i = 0; i < len; i++) { + if (i2c_rd[i] != data[i]) + return FALSE; + } + + return TRUE; } /*