Add init block readback verification to match stock firmware

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.
This commit is contained in:
Ryan Malloy 2026-02-20 11:08:40 -07:00
parent 0d6facb321
commit e9e5ab859a

View File

@ -132,7 +132,7 @@ volatile __bit got_sud;
/* I2C scratch buffers in xdata (24 bytes: fits 20-byte EEPROM blocks) */ /* I2C scratch buffers in xdata (24 bytes: fits 20-byte EEPROM blocks) */
static __xdata BYTE i2c_buf[24]; 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 */ /* TUNE_MONITOR result buffer: filled by OUT phase, returned by IN phase */
static __xdata BYTE tm_result[10]; 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) { static BOOL bcm_write_init_block(const __code BYTE *data, BYTE len) {
BYTE i; 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 */ /* Page select = 0 */
if (!bcm_direct_write(BCM_REG_PAGE, 0x00)) if (!bcm_direct_write(BCM_REG_PAGE, 0x00))
return FALSE; return FALSE;
@ -871,7 +877,34 @@ static BOOL bcm_write_init_block(const __code BYTE *data, BYTE len) {
return FALSE; return FALSE;
/* Wait for BCM4500 to process the write */ /* 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;
} }
/* /*