diff --git a/README.md b/README.md index bbb26d4..7d364b3 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ To turn the structured decompile output into conservative C-like pseudocode: - Parses the DTC vector table described by the manual and decodes DTC register-information blocks. - Tracks SCI setup writes and can infer baud rates from SMR/BRR when `--clock-hz` is supplied. - Annotates SCI protocol actions such as TDRE waits, TDR writes, RDR reads, RX/TX interrupt enables, and receive-error clears. +- Reconstructs evidence-supported SCI1 serial frame candidates, including the apparent six-byte TX/RX units and XOR checksum seeded by `0x5A`. - Adds a Sony RCP-TX7 board profile that ties H8/536 pin 66 `P95/TXD` and pin 67 `P96/RXD` to the MAX202 RS232 transceiver. - Flags/manual-annotates TEMP-register access ordering for FRT and A/D 16-bit peripheral registers. - Scans unreached ROM ranges for ASCII strings and pointer-table candidates. @@ -109,6 +110,7 @@ python h8536_pseudocode.py --help - `h8536/timing.py`: block and loop cycle summaries. - `h8536/sci.py`: SCI setup tracking and baud inference. - `h8536/sci_protocol.py`: SCI transmit/receive/status semantic annotations. +- `h8536/serial_reconstruction.py`: cautious higher-level SCI frame reconstruction from decompiled evidence. - `h8536/board_profile.py`: Sony RCP-TX7 board-trace annotations, including the MAX202 RS232 path. - `h8536/peripheral_access.py`: FRT/A-D TEMP-register access analysis. - `h8536/pseudocode.py`: JSON-to-C-like pseudocode generation. diff --git a/build/rom_decompiled.asm b/build/rom_decompiled.asm index 54caa0c..4391e30 100644 --- a/build/rom_decompiled.asm +++ b/build/rom_decompiled.asm @@ -230,6 +230,11 @@ ; H8 pin 67 P96/RXD (RXD) -> MAX202 pin 12 ; SCI2 pin routing is disabled by SYSCR2.P9SCI2E=0 in the observed setup. +; Serial Protocol Reconstruction +; TX candidate: 6 bytes H'F858-H'F85D, checksum H'F85D seeded by H'005A (confidence high 0.95) +; RX candidate: 6 bytes capture H'F868-H'F86D, validate H'F860-H'F865 checksum H'F865 seeded by H'005A (confidence high 0.9) +; caveat: candidate frame means six consecutive bytes within the observed RX timing/state machine, not a proven delimited packet + ; LCD/Text Scan ; search 'CONNECT': not literal, hits=0 ; near: H'A025 'COMPLETED', H'8E79 'ON CONT1 OFF~X', H'8F55 'ON CONT2 OFF~X', H'94A9 'ON' @@ -3017,25 +3022,25 @@ BA2A: 26 FA BNE loc_BA26 ; cycles=3/7 nt/t BA2C: 15 F9 C0 06 64 MOV:G.B #H'64, @H'F9C0 ; refs ram_F9C0 in on_chip_ram; cycles=9 BA31: 15 F9 C4 06 07 MOV:G.B #H'07, @H'F9C4 ; refs ram_F9C4 in on_chip_ram; cycles=9 BA36: 1D F8 50 80 MOV:G.W @H'F850, R0 ; refs ram_F850 in on_chip_ram; cycles=7 -BA3A: 1D F8 58 90 MOV:G.W R0, @H'F858 ; refs ram_F858 in on_chip_ram; cycles=7 +BA3A: 1D F8 58 90 MOV:G.W R0, @H'F858 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F858 in on_chip_ram; cycles=7 BA3E: 1D F8 52 80 MOV:G.W @H'F852, R0 ; refs ram_F852 in on_chip_ram; cycles=7 -BA42: 1D F8 5A 90 MOV:G.W R0, @H'F85A ; refs ram_F85A in on_chip_ram; cycles=7 +BA42: 1D F8 5A 90 MOV:G.W R0, @H'F85A ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F85A in on_chip_ram; cycles=7 BA46: 15 F8 54 80 MOV:G.B @H'F854, R0 ; refs ram_F854 in on_chip_ram; cycles=7 -BA4A: 15 F8 5C 90 MOV:G.B R0, @H'F85C ; refs ram_F85C in on_chip_ram; cycles=7 -BA4E: 50 5A MOV:E.B #H'5A, R0 ; dataflow R0=H'5A; cycles=2 -BA50: 15 F8 58 60 XOR.B @H'F858, R0 ; refs ram_F858 in on_chip_ram; cycles=7 -BA54: 15 F8 59 60 XOR.B @H'F859, R0 ; refs ram_F859 in on_chip_ram; cycles=7 -BA58: 15 F8 5A 60 XOR.B @H'F85A, R0 ; refs ram_F85A in on_chip_ram; cycles=7 -BA5C: 15 F8 5B 60 XOR.B @H'F85B, R0 ; refs ram_F85B in on_chip_ram; cycles=7 -BA60: 15 F8 5C 60 XOR.B @H'F85C, R0 ; refs ram_F85C in on_chip_ram; cycles=7 -BA64: 15 F8 5D 90 MOV:G.B R0, @H'F85D ; refs ram_F85D in on_chip_ram; cycles=7 +BA4A: 15 F8 5C 90 MOV:G.B R0, @H'F85C ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F85C in on_chip_ram; cycles=7 +BA4E: 50 5A MOV:E.B #H'5A, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX checksum starts from seed H'005A; confidence high; dataflow R0=H'5A; cycles=2 +BA50: 15 F8 58 60 XOR.B @H'F858, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F858 in on_chip_ram; cycles=7 +BA54: 15 F8 59 60 XOR.B @H'F859, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F859 in on_chip_ram; cycles=7 +BA58: 15 F8 5A 60 XOR.B @H'F85A, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F85A in on_chip_ram; cycles=7 +BA5C: 15 F8 5B 60 XOR.B @H'F85B, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F85B in on_chip_ram; cycles=7 +BA60: 15 F8 5C 60 XOR.B @H'F85C, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F85C in on_chip_ram; cycles=7 +BA64: 15 F8 5D 90 MOV:G.B R0, @H'F85D ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate checksum byte write targets H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F85D in on_chip_ram; cycles=7 loc_BA68: BA68: 15 FE DC F7 BTST.B #7, @SCI1_SSR ; wait for SCI1 transmit data register empty (TDRE=1); SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR in register_field; cycles=7 BA6C: 27 FA BEQ loc_BA68 ; repeat SCI1 transmit-empty wait while TDRE=0; cycles=3/7 nt/t -BA6E: 15 F8 58 80 MOV:G.B @H'F858, R0 ; refs ram_F858 in on_chip_ram; cycles=7 -BA72: 15 FE DB 90 MOV:G.B R0, @SCI1_TDR ; SCI1_TDR; write RS232/SCI byte to SCI1 TDR for transmission; SCI1 TDR write transmits on traced RS232/MAX202 path: H8 pin 66 P95/TXD -> MAX202 pin 11; cycles=7 -BA76: 15 F9 C2 06 01 MOV:G.B #H'01, @H'F9C2 ; refs ram_F9C2 in on_chip_ram; cycles=9 +BA6E: 15 F8 58 80 MOV:G.B @H'F858, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: initial SCI1 TDR send is supported by a read from H'F858; confidence high; refs ram_F858 in on_chip_ram; cycles=7 +BA72: 15 FE DB 90 MOV:G.B R0, @SCI1_TDR ; SCI1_TDR; write RS232/SCI byte to SCI1 TDR for transmission; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: initial SCI1 TDR send is supported by a read from H'F858; confidence high; SCI1 TDR write transmits on traced RS232/MAX202 path: H8 pin 66 P95/TXD -> MAX202 pin 11; cycles=7 +BA76: 15 F9 C2 06 01 MOV:G.B #H'01, @H'F9C2 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: write evidence supports TX index H'F9C2 being initialized to 1; confidence high; refs ram_F9C2 in on_chip_ram; cycles=9 BA7B: 15 FE DC D7 BCLR.B #7, @SCI1_SSR ; clear TDRE (bit 7) of SCI1_SSR; clear SCI1 transmit data register empty flag (TDRE); SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 BA7F: 15 FE DA C7 BSET.B #7, @SCI1_SCR ; set TIE (bit 7) of SCI1_SCR; enable SCI1 TX interrupt (TIE); SCI1 SCR write TE=1 RE=1; TE/RE select the traced RS232/MAX202 pins (P95/TXD pin 66 to MAX202 pin 11, P96/RXD pin 67 to MAX202 pin 12); cycles=8 BA83: 19 RTS ; cycles=13 @@ -3055,14 +3060,14 @@ BAA7: 20 48 BRA loc_BAF1 ; cycles=8 loc_BAA9: BAA9: BF 90 MOV:G.W R0, @-R7 ; cycles=5 -BAAB: 15 F9 C2 80 MOV:G.B @H'F9C2, R0 ; refs ram_F9C2 in on_chip_ram; cycles=6 +BAAB: 15 F9 C2 80 MOV:G.B @H'F9C2, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high; refs ram_F9C2 in on_chip_ram; cycles=6 BAAF: A0 12 EXTU.B R0 ; cycles=3 -BAB1: F0 F8 58 80 MOV:G.B @(-H'07A8,R0), R0 ; cycles=6 -BAB5: 15 FE DB 90 MOV:G.B R0, @SCI1_TDR ; SCI1_TDR; write RS232/SCI byte to SCI1 TDR for transmission; SCI1 TDR write transmits on traced RS232/MAX202 path: H8 pin 66 P95/TXD -> MAX202 pin 11; cycles=6 +BAB1: F0 F8 58 80 MOV:G.B @(-H'07A8,R0), R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high; cycles=6 +BAB5: 15 FE DB 90 MOV:G.B R0, @SCI1_TDR ; SCI1_TDR; write RS232/SCI byte to SCI1 TDR for transmission; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high; SCI1 TDR write transmits on traced RS232/MAX202 path: H8 pin 66 P95/TXD -> MAX202 pin 11; cycles=6 BAB9: CF 80 MOV:G.W @R7+, R0 ; cycles=6 BABB: 15 FE DC D7 BCLR.B #7, @SCI1_SSR ; clear TDRE (bit 7) of SCI1_SSR; clear SCI1 transmit data register empty flag (TDRE); SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 -BABF: 15 F9 C2 08 ADD:Q.B #1, @H'F9C2 ; refs ram_F9C2 in on_chip_ram; cycles=8 -BAC3: 15 F9 C2 04 06 CMP:G.B #H'06, @H'F9C2 ; refs ram_F9C2 in on_chip_ram; cycles=6 +BABF: 15 F9 C2 08 ADD:Q.B #1, @H'F9C2 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR increments TX index H'F9C2; confidence high; refs ram_F9C2 in on_chip_ram; cycles=8 +BAC3: 15 F9 C2 04 06 CMP:G.B #H'06, @H'F9C2 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR compares TX index to frame length 6; confidence high; refs ram_F9C2 in on_chip_ram; cycles=6 BAC8: 26 27 BNE loc_BAF1 ; cycles=3/7 nt/t BACA: 15 FE DA D7 BCLR.B #7, @SCI1_SCR ; clear TIE (bit 7) of SCI1_SCR; disable SCI1 TX interrupt (TIE); SCI1 SCR write TE=1 RE=1; TE/RE select the traced RS232/MAX202 pins (P95/TXD pin 66 to MAX202 pin 11, P96/RXD pin 67 to MAX202 pin 12); cycles=9 BACE: 15 F7 95 F6 BTST.B #6, @H'F795 ; refs ram_F795 in on_chip_ram; cycles=7 @@ -3133,7 +3138,7 @@ BB63: 15 FE DC D3 BCLR.B #3, @SCI1_SSR ; clear PER (bit 3) of SCI1_SSR; clear vec_sci1_rxi_BB67: BB67: 12 03 STM.W {R0,R1}, @-SP ; cycles=12 BB69: 15 FE DC D6 BCLR.B #6, @SCI1_SSR ; clear RDRF (bit 6) of SCI1_SSR; clear SCI1 receive-data-full flag (RDRF); SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 -BB6D: 15 FE DD 80 MOV:G.B @SCI1_RDR, R0 ; read SCI1 received byte from RDR; SCI1 RDR read receives from traced RS232/MAX202 path: MAX202 pin 12 -> H8 pin 67 P96/RXD; refs SCI1_RDR in register_field; cycles=6 +BB6D: 15 FE DD 80 MOV:G.B @SCI1_RDR, R0 ; read SCI1 received byte from RDR; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: SCI1 RX ISR reads a byte from SCI1_RDR; confidence high; SCI1 RDR read receives from traced RS232/MAX202 path: MAX202 pin 12 -> H8 pin 67 P96/RXD; refs SCI1_RDR in register_field; cycles=6 BB71: 15 F9 C1 16 TST.B @H'F9C1 ; refs ram_F9C1 in on_chip_ram; cycles=6 BB75: 26 06 BNE loc_BB7D ; cycles=3/8 nt/t BB77: 15 F9 C3 13 CLR.B @H'F9C3 ; refs ram_F9C3 in on_chip_ram; cycles=8 @@ -3148,12 +3153,12 @@ BB88: 20 19 BRA loc_BBA3 ; cycles=7 loc_BB8A: BB8A: 15 F9 C3 81 MOV:G.B @H'F9C3, R1 ; refs ram_F9C3 in on_chip_ram; cycles=7 BB8E: A1 12 EXTU.B R1 ; cycles=3 -BB90: F1 F8 68 90 MOV:G.B R0, @(-H'0798,R1) ; cycles=7 -BB94: A1 08 ADD:Q.B #1, R1 ; cycles=4 -BB96: 15 F9 C3 91 MOV:G.B R1, @H'F9C3 ; refs ram_F9C3 in on_chip_ram; cycles=7 -BB9A: 41 06 CMP:E #H'06, R1 ; cycles=2 +BB90: F1 F8 68 90 MOV:G.B R0, @(-H'0798,R1) ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: received bytes are stored into candidate capture buffer H'F868-H'F86D; confidence high; cycles=7 +BB94: A1 08 ADD:Q.B #1, R1 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX byte count/index is incremented and stored at H'F9C3; confidence high; cycles=4 +BB96: 15 F9 C3 91 MOV:G.B R1, @H'F9C3 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX byte count/index is incremented and stored at H'F9C3; confidence high; refs ram_F9C3 in on_chip_ram; cycles=7 +BB9A: 41 06 CMP:E #H'06, R1 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX ISR compares incremented count to candidate frame length 6; confidence high; cycles=2 BB9C: 26 05 BNE loc_BBA3 ; cycles=3/7 nt/t -BB9E: 15 F9 C5 06 14 MOV:G.B #H'14, @H'F9C5 ; refs ram_F9C5 in on_chip_ram; cycles=9 +BB9E: 15 F9 C5 06 14 MOV:G.B #H'14, @H'F9C5 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX ISR sets H'F9C5 after count reaches 6; confidence high; refs ram_F9C5 in on_chip_ram; cycles=9 loc_BBA3: BBA3: 15 F9 C1 06 05 MOV:G.B #H'05, @H'F9C1 ; refs ram_F9C1 in on_chip_ram; cycles=9 @@ -3161,24 +3166,24 @@ BBA8: 02 03 LDM.W @SP+, {R0,R1} ; cycles=14 BBAA: 0A RTE ; cycles=13 loc_BBAB: -BBAB: 15 F9 C3 04 06 CMP:G.B #H'06, @H'F9C3 ; refs ram_F9C3 in on_chip_ram; cycles=6 +BBAB: 15 F9 C3 04 06 CMP:G.B #H'06, @H'F9C3 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing path requires H'F9C3 to equal 6; confidence high; refs ram_F9C3 in on_chip_ram; cycles=6 BBB0: 36 02 BC BNE loc_BE6F ; cycles=3/7 nt/t -BBB3: 1D F8 68 80 MOV:G.W @H'F868, R0 ; refs ram_F868 in on_chip_ram; cycles=6 -BBB7: 1D F8 60 90 MOV:G.W R0, @H'F860 ; refs ram_F860 in on_chip_ram; cycles=6 -BBBB: 1D F8 6A 80 MOV:G.W @H'F86A, R0 ; refs ram_F86A in on_chip_ram; cycles=6 -BBBF: 1D F8 62 90 MOV:G.W R0, @H'F862 ; refs ram_F862 in on_chip_ram; cycles=6 -BBC3: 1D F8 6C 80 MOV:G.W @H'F86C, R0 ; refs ram_F86C in on_chip_ram; cycles=6 -BBC7: 1D F8 64 90 MOV:G.W R0, @H'F864 ; refs ram_F864 in on_chip_ram; cycles=6 +BBB3: 1D F8 68 80 MOV:G.W @H'F868, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F868 in on_chip_ram; cycles=6 +BBB7: 1D F8 60 90 MOV:G.W R0, @H'F860 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F860 in on_chip_ram; cycles=6 +BBBB: 1D F8 6A 80 MOV:G.W @H'F86A, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F86A in on_chip_ram; cycles=6 +BBBF: 1D F8 62 90 MOV:G.W R0, @H'F862 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F862 in on_chip_ram; cycles=6 +BBC3: 1D F8 6C 80 MOV:G.W @H'F86C, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F86C in on_chip_ram; cycles=6 +BBC7: 1D F8 64 90 MOV:G.W R0, @H'F864 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F864 in on_chip_ram; cycles=6 BBCB: 15 F9 C3 13 CLR.B @H'F9C3 ; refs ram_F9C3 in on_chip_ram; cycles=8 BBCF: 15 FA A4 F7 BTST.B #7, @H'FAA4 ; refs ram_FAA4 in on_chip_ram; cycles=6 BBD3: 36 02 53 BNE loc_BE29 ; cycles=3/8 nt/t -BBD6: 50 5A MOV:E.B #H'5A, R0 ; dataflow R0=H'5A; cycles=2 -BBD8: 15 F8 60 60 XOR.B @H'F860, R0 ; refs ram_F860 in on_chip_ram; cycles=7 -BBDC: 15 F8 61 60 XOR.B @H'F861, R0 ; refs ram_F861 in on_chip_ram; cycles=7 -BBE0: 15 F8 62 60 XOR.B @H'F862, R0 ; refs ram_F862 in on_chip_ram; cycles=7 -BBE4: 15 F8 63 60 XOR.B @H'F863, R0 ; refs ram_F863 in on_chip_ram; cycles=7 -BBE8: 15 F8 64 60 XOR.B @H'F864, R0 ; refs ram_F864 in on_chip_ram; cycles=7 -BBEC: 15 F8 65 70 CMP:G.B @H'F865, R0 ; refs ram_F865 in on_chip_ram; cycles=7 +BBD6: 50 5A MOV:E.B #H'5A, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: candidate RX checksum validation starts from seed H'005A; confidence high; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; dataflow R0=H'5A; cycles=2 +BBD8: 15 F8 60 60 XOR.B @H'F860, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F860 in on_chip_ram; cycles=7 +BBDC: 15 F8 61 60 XOR.B @H'F861, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F861 in on_chip_ram; cycles=7 +BBE0: 15 F8 62 60 XOR.B @H'F862, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F862 in on_chip_ram; cycles=7 +BBE4: 15 F8 63 60 XOR.B @H'F863, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F863 in on_chip_ram; cycles=7 +BBE8: 15 F8 64 60 XOR.B @H'F864, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F864 in on_chip_ram; cycles=7 +BBEC: 15 F8 65 70 CMP:G.B @H'F865, R0 ; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F865 in on_chip_ram; cycles=7 BBF0: 36 02 36 BNE loc_BE29 ; cycles=3/7 nt/t BBF3: 15 FA A6 13 CLR.B @H'FAA6 ; refs ram_FAA6 in on_chip_ram; cycles=8 BBF7: 15 F8 61 85 MOV:G.B @H'F861, R5 ; refs ram_F861 in on_chip_ram; cycles=6 @@ -3395,11 +3400,11 @@ BDFF: 15 FA A2 13 CLR.B @H'FAA2 ; refs ram_FAA2 in on_chip_ram; cycles=8 BE03: 20 6A BRA loc_BE6F ; cycles=8 loc_BE05: -BE05: 1D F8 58 80 MOV:G.W @H'F858, R0 ; refs ram_F858 in on_chip_ram; cycles=6 +BE05: 1D F8 58 80 MOV:G.W @H'F858, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F858 in on_chip_ram; cycles=6 BE09: 1D F8 50 90 MOV:G.W R0, @H'F850 ; refs ram_F850 in on_chip_ram; cycles=6 -BE0D: 1D F8 5A 80 MOV:G.W @H'F85A, R0 ; refs ram_F85A in on_chip_ram; cycles=6 +BE0D: 1D F8 5A 80 MOV:G.W @H'F85A, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F85A in on_chip_ram; cycles=6 BE11: 1D F8 52 90 MOV:G.W R0, @H'F852 ; refs ram_F852 in on_chip_ram; cycles=6 -BE15: 1D F8 5C 80 MOV:G.W @H'F85C, R0 ; refs ram_F85C in on_chip_ram; cycles=6 +BE15: 1D F8 5C 80 MOV:G.W @H'F85C, R0 ; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F85C in on_chip_ram; cycles=6 BE19: 1D F8 54 90 MOV:G.W R0, @H'F854 ; refs ram_F854 in on_chip_ram; cycles=6 BE1D: 15 F9 C0 06 1F MOV:G.B #H'1F, @H'F9C0 ; refs ram_F9C0 in on_chip_ram; cycles=9 BE22: 1E FC 01 BSR loc_BA26 ; cycles=13 diff --git a/build/rom_decompiled.json b/build/rom_decompiled.json index 91ebf33..64954c8 100644 --- a/build/rom_decompiled.json +++ b/build/rom_decompiled.json @@ -16995,6 +16995,976 @@ } ] }, + "serial_reconstruction": { + "kind": "serial_reconstruction", + "candidates": [ + { + "id": "sci1_tx_frame_f858_len6_candidate", + "kind": "candidate_sci1_tx_frame", + "channel": "SCI1", + "frame_length": 6, + "buffer_start": 63576, + "buffer_start_hex": "H'F858", + "buffer_end": 63581, + "buffer_end_hex": "H'F85D", + "checksum_address": 63581, + "checksum_address_hex": "H'F85D", + "tx_index_address": 63938, + "tx_index_address_hex": "H'F9C2", + "tdr_address": 65243, + "tdr_address_hex": "H'FEDB", + "checksum_seed": 90, + "checksum_seed_hex": "H'005A", + "checksum_formula": "checksum = 0x5A ^ byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4", + "confidence": "high", + "confidence_score": 0.95, + "confidence_reason": "all required independent evidence groups were observed", + "required_evidence_count": 9, + "observed_evidence_count": 9, + "missing_evidence": [], + "evidence_addresses": { + "tx_buffer_region": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "tx_checksum_seed": [ + 47694 + ], + "checksum_byte": [ + 47716 + ], + "xor_checksum_chain": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "initial_send_from_buffer_start": [ + 47726, + 47730 + ], + "tx_index_initialized_to_one": [ + 47734 + ], + "tx_isr_indexed_send": [ + 47787, + 47793, + 47797 + ], + "tx_index_increment": [ + 47807 + ], + "tx_index_compare_frame_length": [ + 47811 + ] + }, + "evidence_addresses_hex": { + "tx_buffer_region": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "tx_checksum_seed": [ + "H'BA4E" + ], + "checksum_byte": [ + "H'BA64" + ], + "xor_checksum_chain": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "initial_send_from_buffer_start": [ + "H'BA6E", + "H'BA72" + ], + "tx_index_initialized_to_one": [ + "H'BA76" + ], + "tx_isr_indexed_send": [ + "H'BAAB", + "H'BAB1", + "H'BAB5" + ], + "tx_index_increment": [ + "H'BABF" + ], + "tx_index_compare_frame_length": [ + "H'BAC3" + ] + }, + "evidence": [ + { + "kind": "tx_buffer_region", + "summary": "TX buffer-region references cluster around H'F858-H'F85D", + "addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "instructions": [ + "MOV:G.W R0, @H'F858", + "MOV:G.W R0, @H'F85A", + "MOV:G.B R0, @H'F85C", + "XOR.B @H'F858, R0", + "XOR.B @H'F859, R0", + "XOR.B @H'F85A, R0", + "XOR.B @H'F85B, R0", + "XOR.B @H'F85C, R0", + "MOV:G.B R0, @H'F85D", + "MOV:G.B @H'F858, R0", + "MOV:G.W @H'F858, R0", + "MOV:G.W @H'F85A, R0", + "MOV:G.W @H'F85C, R0" + ], + "distinct_buffer_addresses": [ + 63576, + 63577, + 63578, + 63579, + 63580, + 63581 + ], + "distinct_buffer_addresses_hex": [ + "H'F858", + "H'F859", + "H'F85A", + "H'F85B", + "H'F85C", + "H'F85D" + ] + }, + { + "kind": "tx_checksum_seed", + "summary": "candidate TX checksum starts from seed H'005A", + "addresses": [ + 47694 + ], + "addresses_hex": [ + "H'BA4E" + ], + "instructions": [ + "MOV:E.B #H'5A, R0" + ] + }, + { + "kind": "checksum_byte", + "summary": "candidate checksum byte write targets H'F85D", + "addresses": [ + 47716 + ], + "addresses_hex": [ + "H'BA64" + ], + "instructions": [ + "MOV:G.B R0, @H'F85D" + ] + }, + { + "kind": "xor_checksum_chain", + "summary": "XOR chain appears to feed the H'F85D checksum byte", + "addresses": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "addresses_hex": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "instructions": [ + "XOR.B @H'F858, R0", + "XOR.B @H'F859, R0", + "XOR.B @H'F85A, R0", + "XOR.B @H'F85B, R0", + "XOR.B @H'F85C, R0", + "MOV:G.B R0, @H'F85D" + ] + }, + { + "kind": "initial_send_from_buffer_start", + "summary": "initial SCI1 TDR send is supported by a read from H'F858", + "addresses": [ + 47726, + 47730 + ], + "addresses_hex": [ + "H'BA6E", + "H'BA72" + ], + "instructions": [ + "MOV:G.B @H'F858, R0", + "MOV:G.B R0, @SCI1_TDR" + ] + }, + { + "kind": "tx_index_initialized_to_one", + "summary": "write evidence supports TX index H'F9C2 being initialized to 1", + "addresses": [ + 47734 + ], + "addresses_hex": [ + "H'BA76" + ], + "instructions": [ + "MOV:G.B #H'01, @H'F9C2" + ] + }, + { + "kind": "tx_isr_indexed_send", + "summary": "candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer", + "addresses": [ + 47787, + 47793, + 47797 + ], + "addresses_hex": [ + "H'BAAB", + "H'BAB1", + "H'BAB5" + ], + "instructions": [ + "MOV:G.B @H'F9C2, R0", + "MOV:G.B @(-H'07A8,R0), R0", + "MOV:G.B R0, @SCI1_TDR" + ] + }, + { + "kind": "tx_index_increment", + "summary": "candidate TX ISR increments TX index H'F9C2", + "addresses": [ + 47807 + ], + "addresses_hex": [ + "H'BABF" + ], + "instructions": [ + "ADD:Q.B #1, @H'F9C2" + ] + }, + { + "kind": "tx_index_compare_frame_length", + "summary": "candidate TX ISR compares TX index to frame length 6", + "addresses": [ + 47811 + ], + "addresses_hex": [ + "H'BAC3" + ], + "instructions": [ + "CMP:G.B #H'06, @H'F9C2" + ] + } + ], + "short_comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A", + "comment": "candidate/evidence-supported SCI1 6-byte TX frame hypothesis using buffer H'F858-H'F85D with checksum byte H'F85D seeded by H'005A" + }, + { + "id": "sci1_rx_frame_f868_len6_candidate", + "kind": "candidate_sci1_rx_frame", + "channel": "SCI1", + "frame_length": 6, + "capture_buffer_start": 63592, + "capture_buffer_start_hex": "H'F868", + "capture_buffer_end": 63597, + "capture_buffer_end_hex": "H'F86D", + "validation_buffer_start": 63584, + "validation_buffer_start_hex": "H'F860", + "validation_buffer_end": 63589, + "validation_buffer_end_hex": "H'F865", + "checksum_address": 63589, + "checksum_address_hex": "H'F865", + "rx_index_address": 63939, + "rx_index_address_hex": "H'F9C3", + "rdr_address": 65245, + "rdr_address_hex": "H'FEDD", + "interbyte_timeout_address": 63937, + "interbyte_timeout_address_hex": "H'F9C1", + "complete_timer_address": 63941, + "complete_timer_address_hex": "H'F9C5", + "checksum_seed": 90, + "checksum_seed_hex": "H'005A", + "checksum_formula": "checksum = 0x5A ^ byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4", + "confidence": "high", + "confidence_score": 0.9, + "confidence_reason": "RX count, copy, and checksum-validation evidence were observed; no explicit header/sync byte was identified", + "caveat": "candidate frame means six consecutive bytes within the observed RX timing/state machine, not a proven delimited packet", + "required_evidence_count": 9, + "observed_evidence_count": 9, + "missing_evidence": [], + "evidence_addresses": { + "rx_rdr_read": [ + 47981 + ], + "rx_indexed_store": [ + 48016 + ], + "rx_index_increment_store": [ + 48020, + 48022 + ], + "rx_isr_compare_frame_length": [ + 48026 + ], + "rx_complete_timer": [ + 48030 + ], + "rx_processor_requires_six_bytes": [ + 48043 + ], + "rx_copy_capture_to_frame_buffer": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "rx_checksum_seed": [ + 48086 + ], + "rx_xor_checksum_validation": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ] + }, + "evidence_addresses_hex": { + "rx_rdr_read": [ + "H'BB6D" + ], + "rx_indexed_store": [ + "H'BB90" + ], + "rx_index_increment_store": [ + "H'BB94", + "H'BB96" + ], + "rx_isr_compare_frame_length": [ + "H'BB9A" + ], + "rx_complete_timer": [ + "H'BB9E" + ], + "rx_processor_requires_six_bytes": [ + "H'BBAB" + ], + "rx_copy_capture_to_frame_buffer": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "rx_checksum_seed": [ + "H'BBD6" + ], + "rx_xor_checksum_validation": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ] + }, + "evidence": [ + { + "kind": "rx_rdr_read", + "summary": "SCI1 RX ISR reads a byte from SCI1_RDR", + "addresses": [ + 47981 + ], + "addresses_hex": [ + "H'BB6D" + ], + "instructions": [ + "MOV:G.B @SCI1_RDR, R0" + ] + }, + { + "kind": "rx_indexed_store", + "summary": "received bytes are stored into candidate capture buffer H'F868-H'F86D", + "addresses": [ + 48016 + ], + "addresses_hex": [ + "H'BB90" + ], + "instructions": [ + "MOV:G.B R0, @(-H'0798,R1)" + ] + }, + { + "kind": "rx_index_increment_store", + "summary": "RX byte count/index is incremented and stored at H'F9C3", + "addresses": [ + 48020, + 48022 + ], + "addresses_hex": [ + "H'BB94", + "H'BB96" + ], + "instructions": [ + "ADD:Q.B #1, R1", + "MOV:G.B R1, @H'F9C3" + ] + }, + { + "kind": "rx_isr_compare_frame_length", + "summary": "RX ISR compares incremented count to candidate frame length 6", + "addresses": [ + 48026 + ], + "addresses_hex": [ + "H'BB9A" + ], + "instructions": [ + "CMP:E #H'06, R1" + ] + }, + { + "kind": "rx_complete_timer", + "summary": "RX ISR sets H'F9C5 after count reaches 6", + "addresses": [ + 48030 + ], + "addresses_hex": [ + "H'BB9E" + ], + "instructions": [ + "MOV:G.B #H'14, @H'F9C5" + ] + }, + { + "kind": "rx_processor_requires_six_bytes", + "summary": "RX processing path requires H'F9C3 to equal 6", + "addresses": [ + 48043 + ], + "addresses_hex": [ + "H'BBAB" + ], + "instructions": [ + "CMP:G.B #H'06, @H'F9C3" + ] + }, + { + "kind": "rx_copy_capture_to_frame_buffer", + "summary": "RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865", + "addresses": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "addresses_hex": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "instructions": [ + "MOV:G.W @H'F868, R0", + "MOV:G.W @H'F86A, R0", + "MOV:G.W @H'F86C, R0", + "MOV:G.W R0, @H'F860", + "MOV:G.W R0, @H'F862", + "MOV:G.W R0, @H'F864" + ] + }, + { + "kind": "rx_checksum_seed", + "summary": "candidate RX checksum validation starts from seed H'005A", + "addresses": [ + 48086 + ], + "addresses_hex": [ + "H'BBD6" + ], + "instructions": [ + "MOV:E.B #H'5A, R0" + ] + }, + { + "kind": "rx_xor_checksum_validation", + "summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "instructions": [ + "MOV:E.B #H'5A, R0", + "XOR.B @H'F860, R0", + "XOR.B @H'F861, R0", + "XOR.B @H'F862, R0", + "XOR.B @H'F863, R0", + "XOR.B @H'F864, R0", + "CMP:G.B @H'F865, R0" + ] + } + ], + "short_comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A", + "comment": "candidate/evidence-supported SCI1 6-byte RX frame hypothesis using capture buffer H'F868-H'F86D; checksum byte H'F865 is validated against XOR seeded by H'005A" + } + ], + "evidence": [ + { + "kind": "tx_buffer_region", + "summary": "TX buffer-region references cluster around H'F858-H'F85D", + "addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "instructions": [ + "MOV:G.W R0, @H'F858", + "MOV:G.W R0, @H'F85A", + "MOV:G.B R0, @H'F85C", + "XOR.B @H'F858, R0", + "XOR.B @H'F859, R0", + "XOR.B @H'F85A, R0", + "XOR.B @H'F85B, R0", + "XOR.B @H'F85C, R0", + "MOV:G.B R0, @H'F85D", + "MOV:G.B @H'F858, R0", + "MOV:G.W @H'F858, R0", + "MOV:G.W @H'F85A, R0", + "MOV:G.W @H'F85C, R0" + ], + "distinct_buffer_addresses": [ + 63576, + 63577, + 63578, + 63579, + 63580, + 63581 + ], + "distinct_buffer_addresses_hex": [ + "H'F858", + "H'F859", + "H'F85A", + "H'F85B", + "H'F85C", + "H'F85D" + ] + }, + { + "kind": "tx_checksum_seed", + "summary": "candidate TX checksum starts from seed H'005A", + "addresses": [ + 47694 + ], + "addresses_hex": [ + "H'BA4E" + ], + "instructions": [ + "MOV:E.B #H'5A, R0" + ] + }, + { + "kind": "checksum_byte", + "summary": "candidate checksum byte write targets H'F85D", + "addresses": [ + 47716 + ], + "addresses_hex": [ + "H'BA64" + ], + "instructions": [ + "MOV:G.B R0, @H'F85D" + ] + }, + { + "kind": "xor_checksum_chain", + "summary": "XOR chain appears to feed the H'F85D checksum byte", + "addresses": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "addresses_hex": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "instructions": [ + "XOR.B @H'F858, R0", + "XOR.B @H'F859, R0", + "XOR.B @H'F85A, R0", + "XOR.B @H'F85B, R0", + "XOR.B @H'F85C, R0", + "MOV:G.B R0, @H'F85D" + ] + }, + { + "kind": "initial_send_from_buffer_start", + "summary": "initial SCI1 TDR send is supported by a read from H'F858", + "addresses": [ + 47726, + 47730 + ], + "addresses_hex": [ + "H'BA6E", + "H'BA72" + ], + "instructions": [ + "MOV:G.B @H'F858, R0", + "MOV:G.B R0, @SCI1_TDR" + ] + }, + { + "kind": "tx_index_initialized_to_one", + "summary": "write evidence supports TX index H'F9C2 being initialized to 1", + "addresses": [ + 47734 + ], + "addresses_hex": [ + "H'BA76" + ], + "instructions": [ + "MOV:G.B #H'01, @H'F9C2" + ] + }, + { + "kind": "tx_isr_indexed_send", + "summary": "candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer", + "addresses": [ + 47787, + 47793, + 47797 + ], + "addresses_hex": [ + "H'BAAB", + "H'BAB1", + "H'BAB5" + ], + "instructions": [ + "MOV:G.B @H'F9C2, R0", + "MOV:G.B @(-H'07A8,R0), R0", + "MOV:G.B R0, @SCI1_TDR" + ] + }, + { + "kind": "tx_index_increment", + "summary": "candidate TX ISR increments TX index H'F9C2", + "addresses": [ + 47807 + ], + "addresses_hex": [ + "H'BABF" + ], + "instructions": [ + "ADD:Q.B #1, @H'F9C2" + ] + }, + { + "kind": "tx_index_compare_frame_length", + "summary": "candidate TX ISR compares TX index to frame length 6", + "addresses": [ + 47811 + ], + "addresses_hex": [ + "H'BAC3" + ], + "instructions": [ + "CMP:G.B #H'06, @H'F9C2" + ] + }, + { + "kind": "rx_rdr_read", + "summary": "SCI1 RX ISR reads a byte from SCI1_RDR", + "addresses": [ + 47981 + ], + "addresses_hex": [ + "H'BB6D" + ], + "instructions": [ + "MOV:G.B @SCI1_RDR, R0" + ] + }, + { + "kind": "rx_indexed_store", + "summary": "received bytes are stored into candidate capture buffer H'F868-H'F86D", + "addresses": [ + 48016 + ], + "addresses_hex": [ + "H'BB90" + ], + "instructions": [ + "MOV:G.B R0, @(-H'0798,R1)" + ] + }, + { + "kind": "rx_index_increment_store", + "summary": "RX byte count/index is incremented and stored at H'F9C3", + "addresses": [ + 48020, + 48022 + ], + "addresses_hex": [ + "H'BB94", + "H'BB96" + ], + "instructions": [ + "ADD:Q.B #1, R1", + "MOV:G.B R1, @H'F9C3" + ] + }, + { + "kind": "rx_isr_compare_frame_length", + "summary": "RX ISR compares incremented count to candidate frame length 6", + "addresses": [ + 48026 + ], + "addresses_hex": [ + "H'BB9A" + ], + "instructions": [ + "CMP:E #H'06, R1" + ] + }, + { + "kind": "rx_complete_timer", + "summary": "RX ISR sets H'F9C5 after count reaches 6", + "addresses": [ + 48030 + ], + "addresses_hex": [ + "H'BB9E" + ], + "instructions": [ + "MOV:G.B #H'14, @H'F9C5" + ] + }, + { + "kind": "rx_processor_requires_six_bytes", + "summary": "RX processing path requires H'F9C3 to equal 6", + "addresses": [ + 48043 + ], + "addresses_hex": [ + "H'BBAB" + ], + "instructions": [ + "CMP:G.B #H'06, @H'F9C3" + ] + }, + { + "kind": "rx_copy_capture_to_frame_buffer", + "summary": "RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865", + "addresses": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "addresses_hex": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "instructions": [ + "MOV:G.W @H'F868, R0", + "MOV:G.W @H'F86A, R0", + "MOV:G.W @H'F86C, R0", + "MOV:G.W R0, @H'F860", + "MOV:G.W R0, @H'F862", + "MOV:G.W R0, @H'F864" + ] + }, + { + "kind": "rx_checksum_seed", + "summary": "candidate RX checksum validation starts from seed H'005A", + "addresses": [ + 48086 + ], + "addresses_hex": [ + "H'BBD6" + ], + "instructions": [ + "MOV:E.B #H'5A, R0" + ] + }, + { + "kind": "rx_xor_checksum_validation", + "summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "instructions": [ + "MOV:E.B #H'5A, R0", + "XOR.B @H'F860, R0", + "XOR.B @H'F861, R0", + "XOR.B @H'F862, R0", + "XOR.B @H'F863, R0", + "XOR.B @H'F864, R0", + "CMP:G.B @H'F865, R0" + ] + } + ], + "required_evidence": { + "tx": [ + "tx_buffer_region", + "tx_checksum_seed", + "checksum_byte", + "xor_checksum_chain", + "initial_send_from_buffer_start", + "tx_index_initialized_to_one", + "tx_isr_indexed_send", + "tx_index_increment", + "tx_index_compare_frame_length" + ], + "rx": [ + "rx_rdr_read", + "rx_indexed_store", + "rx_index_increment_store", + "rx_isr_compare_frame_length", + "rx_complete_timer", + "rx_processor_requires_six_bytes", + "rx_copy_capture_to_frame_buffer", + "rx_checksum_seed", + "rx_xor_checksum_validation" + ] + } + }, "board_profile": { "board": "sony_rcp_tx7", "name": "Sony RCP-TX7", @@ -156316,6 +157286,49 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47674, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [], @@ -156384,6 +157397,49 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47682, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [], @@ -156452,6 +157508,49 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47690, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [], @@ -156475,6 +157574,25 @@ "references": [], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47694, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_checksum_seed", + "evidence_summary": "candidate TX checksum starts from seed H'005A", + "evidence_addresses": [ + 47694 + ], + "evidence_addresses_hex": [ + "H'BA4E" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX checksum starts from seed H'005A; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [ @@ -156537,6 +157655,76 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47696, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + }, + { + "address": 47696, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "xor_checksum_chain", + "evidence_summary": "XOR chain appears to feed the H'F85D checksum byte", + "evidence_addresses": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "evidence_addresses_hex": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [ @@ -156588,6 +157776,76 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47700, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + }, + { + "address": 47700, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "xor_checksum_chain", + "evidence_summary": "XOR chain appears to feed the H'F85D checksum byte", + "evidence_addresses": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "evidence_addresses_hex": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [], @@ -156623,6 +157881,76 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47704, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + }, + { + "address": 47704, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "xor_checksum_chain", + "evidence_summary": "XOR chain appears to feed the H'F85D checksum byte", + "evidence_addresses": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "evidence_addresses_hex": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [], @@ -156658,6 +157986,76 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47708, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + }, + { + "address": 47708, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "xor_checksum_chain", + "evidence_summary": "XOR chain appears to feed the H'F85D checksum byte", + "evidence_addresses": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "evidence_addresses_hex": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [], @@ -156693,6 +158091,76 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47712, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + }, + { + "address": 47712, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "xor_checksum_chain", + "evidence_summary": "XOR chain appears to feed the H'F85D checksum byte", + "evidence_addresses": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "evidence_addresses_hex": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [], @@ -156728,6 +158196,93 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47716, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + }, + { + "address": 47716, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "checksum_byte", + "evidence_summary": "candidate checksum byte write targets H'F85D", + "evidence_addresses": [ + 47716 + ], + "evidence_addresses_hex": [ + "H'BA64" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate checksum byte write targets H'F85D; confidence high" + }, + { + "address": 47716, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "xor_checksum_chain", + "evidence_summary": "XOR chain appears to feed the H'F85D checksum byte", + "evidence_addresses": [ + 47696, + 47700, + 47704, + 47708, + 47712, + 47716 + ], + "evidence_addresses_hex": [ + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high" + } + ], "dataflow": { "block": 47660, "changes": [], @@ -156911,6 +158466,68 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47726, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + }, + { + "address": 47726, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "initial_send_from_buffer_start", + "evidence_summary": "initial SCI1 TDR send is supported by a read from H'F858", + "evidence_addresses": [ + 47726, + 47730 + ], + "evidence_addresses_hex": [ + "H'BA6E", + "H'BA72" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: initial SCI1 TDR send is supported by a read from H'F858; confidence high" + } + ], "dataflow": { "block": 47726, "changes": [ @@ -156998,6 +158615,27 @@ ] } ], + "serial_reconstruction": [ + { + "address": 47730, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "initial_send_from_buffer_start", + "evidence_summary": "initial SCI1 TDR send is supported by a read from H'F858", + "evidence_addresses": [ + 47726, + 47730 + ], + "evidence_addresses_hex": [ + "H'BA6E", + "H'BA72" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: initial SCI1 TDR send is supported by a read from H'F858; confidence high" + } + ], "board_profile": { "accesses": [ { @@ -157046,6 +158684,25 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47734, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_index_initialized_to_one", + "evidence_summary": "write evidence supports TX index H'F9C2 being initialized to 1", + "evidence_addresses": [ + 47734 + ], + "evidence_addresses_hex": [ + "H'BA76" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: write evidence supports TX index H'F9C2 being initialized to 1; confidence high" + } + ], "dataflow": { "block": 47726, "changes": [], @@ -157796,6 +159453,29 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47787, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_isr_indexed_send", + "evidence_summary": "candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer", + "evidence_addresses": [ + 47787, + 47793, + 47797 + ], + "evidence_addresses_hex": [ + "H'BAAB", + "H'BAB1", + "H'BAB5" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high" + } + ], "dataflow": { "block": 47785, "changes": [ @@ -157874,6 +159554,29 @@ "references": [], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47793, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_isr_indexed_send", + "evidence_summary": "candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer", + "evidence_addresses": [ + 47787, + 47793, + 47797 + ], + "evidence_addresses_hex": [ + "H'BAAB", + "H'BAB1", + "H'BAB5" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high" + } + ], "dataflow": { "block": 47785, "changes": [ @@ -157948,6 +159651,29 @@ ] } ], + "serial_reconstruction": [ + { + "address": 47797, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_isr_indexed_send", + "evidence_summary": "candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer", + "evidence_addresses": [ + 47787, + 47793, + 47797 + ], + "evidence_addresses_hex": [ + "H'BAAB", + "H'BAB1", + "H'BAB5" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high" + } + ], "board_profile": { "accesses": [ { @@ -158099,6 +159825,25 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47807, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_index_increment", + "evidence_summary": "candidate TX ISR increments TX index H'F9C2", + "evidence_addresses": [ + 47807 + ], + "evidence_addresses_hex": [ + "H'BABF" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR increments TX index H'F9C2; confidence high" + } + ], "dataflow": { "block": 47785, "changes": [], @@ -158131,6 +159876,25 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 47811, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_index_compare_frame_length", + "evidence_summary": "candidate TX ISR compares TX index to frame length 6", + "evidence_addresses": [ + 47811 + ], + "evidence_addresses_hex": [ + "H'BAC3" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR compares TX index to frame length 6; confidence high" + } + ], "dataflow": { "block": 47785, "changes": [], @@ -160594,6 +162358,25 @@ ] } ], + "serial_reconstruction": [ + { + "address": 47981, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_rdr_read", + "evidence_summary": "SCI1 RX ISR reads a byte from SCI1_RDR", + "evidence_addresses": [ + 47981 + ], + "evidence_addresses_hex": [ + "H'BB6D" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: SCI1 RX ISR reads a byte from SCI1_RDR; confidence high" + } + ], "board_profile": { "accesses": [ { @@ -161028,6 +162811,25 @@ "references": [], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48016, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_indexed_store", + "evidence_summary": "received bytes are stored into candidate capture buffer H'F868-H'F86D", + "evidence_addresses": [ + 48016 + ], + "evidence_addresses_hex": [ + "H'BB90" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: received bytes are stored into candidate capture buffer H'F868-H'F86D; confidence high" + } + ], "dataflow": { "block": 48010, "changes": [], @@ -161052,6 +162854,27 @@ "references": [], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48020, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_index_increment_store", + "evidence_summary": "RX byte count/index is incremented and stored at H'F9C3", + "evidence_addresses": [ + 48020, + 48022 + ], + "evidence_addresses_hex": [ + "H'BB94", + "H'BB96" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX byte count/index is incremented and stored at H'F9C3; confidence high" + } + ], "dataflow": { "block": 48010, "changes": [ @@ -161100,6 +162923,27 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48022, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_index_increment_store", + "evidence_summary": "RX byte count/index is incremented and stored at H'F9C3", + "evidence_addresses": [ + 48020, + 48022 + ], + "evidence_addresses_hex": [ + "H'BB94", + "H'BB96" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX byte count/index is incremented and stored at H'F9C3; confidence high" + } + ], "dataflow": { "block": 48010, "changes": [], @@ -161123,6 +162967,25 @@ "references": [], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48026, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_isr_compare_frame_length", + "evidence_summary": "RX ISR compares incremented count to candidate frame length 6", + "evidence_addresses": [ + 48026 + ], + "evidence_addresses_hex": [ + "H'BB9A" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX ISR compares incremented count to candidate frame length 6; confidence high" + } + ], "dataflow": { "block": 48010, "changes": [], @@ -161183,6 +163046,25 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48030, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_complete_timer", + "evidence_summary": "RX ISR sets H'F9C5 after count reaches 6", + "evidence_addresses": [ + 48030 + ], + "evidence_addresses_hex": [ + "H'BB9E" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX ISR sets H'F9C5 after count reaches 6; confidence high" + } + ], "dataflow": { "block": 48030, "changes": [ @@ -161349,6 +163231,25 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48043, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_processor_requires_six_bytes", + "evidence_summary": "RX processing path requires H'F9C3 to equal 6", + "evidence_addresses": [ + 48043 + ], + "evidence_addresses_hex": [ + "H'BBAB" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing path requires H'F9C3 to equal 6; confidence high" + } + ], "dataflow": { "block": 48043, "changes": [ @@ -161421,6 +163322,35 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48051, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_copy_capture_to_frame_buffer", + "evidence_summary": "RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865", + "evidence_addresses": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "evidence_addresses_hex": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high" + } + ], "dataflow": { "block": 48051, "changes": [ @@ -161480,6 +163410,35 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48055, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_copy_capture_to_frame_buffer", + "evidence_summary": "RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865", + "evidence_addresses": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "evidence_addresses_hex": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high" + } + ], "dataflow": { "block": 48051, "changes": [], @@ -161512,6 +163471,35 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48059, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_copy_capture_to_frame_buffer", + "evidence_summary": "RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865", + "evidence_addresses": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "evidence_addresses_hex": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high" + } + ], "dataflow": { "block": 48051, "changes": [], @@ -161546,6 +163534,35 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48063, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_copy_capture_to_frame_buffer", + "evidence_summary": "RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865", + "evidence_addresses": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "evidence_addresses_hex": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high" + } + ], "dataflow": { "block": 48051, "changes": [], @@ -161578,6 +163595,35 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48067, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_copy_capture_to_frame_buffer", + "evidence_summary": "RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865", + "evidence_addresses": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "evidence_addresses_hex": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high" + } + ], "dataflow": { "block": 48051, "changes": [], @@ -161612,6 +163658,35 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48071, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_copy_capture_to_frame_buffer", + "evidence_summary": "RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865", + "evidence_addresses": [ + 48051, + 48059, + 48067, + 48055, + 48063, + 48071 + ], + "evidence_addresses_hex": [ + "H'BBB3", + "H'BBBB", + "H'BBC3", + "H'BBB7", + "H'BBBF", + "H'BBC7" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high" + } + ], "dataflow": { "block": 48051, "changes": [], @@ -161727,6 +163802,54 @@ "references": [], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48086, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_checksum_seed", + "evidence_summary": "candidate RX checksum validation starts from seed H'005A", + "evidence_addresses": [ + 48086 + ], + "evidence_addresses_hex": [ + "H'BBD6" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: candidate RX checksum validation starts from seed H'005A; confidence high" + }, + { + "address": 48086, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_xor_checksum_validation", + "evidence_summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "evidence_addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "evidence_addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high" + } + ], "dataflow": { "block": 48086, "changes": [ @@ -161801,6 +163924,37 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48088, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_xor_checksum_validation", + "evidence_summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "evidence_addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "evidence_addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high" + } + ], "dataflow": { "block": 48086, "changes": [ @@ -161852,6 +164006,37 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48092, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_xor_checksum_validation", + "evidence_summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "evidence_addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "evidence_addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high" + } + ], "dataflow": { "block": 48086, "changes": [], @@ -161887,6 +164072,37 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48096, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_xor_checksum_validation", + "evidence_summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "evidence_addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "evidence_addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high" + } + ], "dataflow": { "block": 48086, "changes": [], @@ -161922,6 +164138,37 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48100, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_xor_checksum_validation", + "evidence_summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "evidence_addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "evidence_addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high" + } + ], "dataflow": { "block": 48086, "changes": [], @@ -161957,6 +164204,37 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48104, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_xor_checksum_validation", + "evidence_summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "evidence_addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "evidence_addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high" + } + ], "dataflow": { "block": 48086, "changes": [], @@ -161992,6 +164270,37 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48108, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_rx_frame_f868_len6_candidate", + "candidate_kind": "candidate_sci1_rx_frame", + "evidence": "rx_xor_checksum_validation", + "evidence_summary": "RX path XORs H'F860-H'F864 and compares the result with H'F865", + "evidence_addresses": [ + 48086, + 48088, + 48092, + 48096, + 48100, + 48104, + 48108 + ], + "evidence_addresses_hex": [ + "H'BBD6", + "H'BBD8", + "H'BBDC", + "H'BBE0", + "H'BBE4", + "H'BBE8", + "H'BBEC" + ], + "confidence": "high", + "confidence_score": 0.9, + "comment": "candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high" + } + ], "dataflow": { "block": 48086, "changes": [], @@ -169637,6 +171946,49 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48645, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + } + ], "dataflow": { "block": 48645, "changes": [ @@ -169728,6 +172080,49 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48653, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + } + ], "dataflow": { "block": 48645, "changes": [], @@ -169794,6 +172189,49 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48661, + "action": "serial_reconstruction_evidence", + "candidate_id": "sci1_tx_frame_f858_len6_candidate", + "candidate_kind": "candidate_sci1_tx_frame", + "evidence": "tx_buffer_region", + "evidence_summary": "TX buffer-region references cluster around H'F858-H'F85D", + "evidence_addresses": [ + 47674, + 47682, + 47690, + 47696, + 47700, + 47704, + 47708, + 47712, + 47716, + 47726, + 48645, + 48653, + 48661 + ], + "evidence_addresses_hex": [ + "H'BA3A", + "H'BA42", + "H'BA4A", + "H'BA50", + "H'BA54", + "H'BA58", + "H'BA5C", + "H'BA60", + "H'BA64", + "H'BA6E", + "H'BE05", + "H'BE0D", + "H'BE15" + ], + "confidence": "high", + "confidence_score": 0.95, + "comment": "candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high" + } + ], "dataflow": { "block": 48645, "changes": [], diff --git a/build/rom_pseudocode.c b/build/rom_pseudocode.c index 319be9c..c47f2e0 100644 --- a/build/rom_pseudocode.c +++ b/build/rom_pseudocode.c @@ -2836,24 +2836,24 @@ void loc_BA26(void) MEM8[0xF9C0] = (uint8_t)(0x64); /* BA2C; MOV:G.B #H'64, @H'F9C0; refs ram_F9C0; cycles=9 */ MEM8[0xF9C4] = (uint8_t)(0x07); /* BA31; MOV:G.B #H'07, @H'F9C4; refs ram_F9C4; cycles=9 */ R0 = (uint16_t)(MEM16[0xF850]); /* BA36; MOV:G.W @H'F850, R0; refs ram_F850; cycles=7 */ - MEM16[0xF858] = (uint16_t)(R0); /* BA3A; MOV:G.W R0, @H'F858; refs ram_F858; cycles=7 */ + MEM16[0xF858] = (uint16_t)(R0); /* BA3A; MOV:G.W R0, @H'F858; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F858; cycles=7 */ R0 = (uint16_t)(MEM16[0xF852]); /* BA3E; MOV:G.W @H'F852, R0; refs ram_F852; cycles=7 */ - MEM16[0xF85A] = (uint16_t)(R0); /* BA42; MOV:G.W R0, @H'F85A; refs ram_F85A; cycles=7 */ + MEM16[0xF85A] = (uint16_t)(R0); /* BA42; MOV:G.W R0, @H'F85A; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F85A; cycles=7 */ R0 = (uint8_t)(MEM8[0xF854]); /* BA46; MOV:G.B @H'F854, R0; refs ram_F854; cycles=7 */ - MEM8[0xF85C] = (uint8_t)(R0); /* BA4A; MOV:G.B R0, @H'F85C; refs ram_F85C; cycles=7 */ - R0 = (uint8_t)(0x5A); /* BA4E; MOV:E.B #H'5A, R0; dataflow R0=0x5A; cycles=2 */ - R0 ^= (uint8_t)(MEM8[0xF858]); /* BA50; XOR.B @H'F858, R0; refs ram_F858; cycles=7 */ - R0 ^= (uint8_t)(MEM8[0xF859]); /* BA54; XOR.B @H'F859, R0; refs ram_F859; cycles=7 */ - R0 ^= (uint8_t)(MEM8[0xF85A]); /* BA58; XOR.B @H'F85A, R0; refs ram_F85A; cycles=7 */ - R0 ^= (uint8_t)(MEM8[0xF85B]); /* BA5C; XOR.B @H'F85B, R0; refs ram_F85B; cycles=7 */ - R0 ^= (uint8_t)(MEM8[0xF85C]); /* BA60; XOR.B @H'F85C, R0; refs ram_F85C; cycles=7 */ - MEM8[0xF85D] = (uint8_t)(R0); /* BA64; MOV:G.B R0, @H'F85D; refs ram_F85D; cycles=7 */ + MEM8[0xF85C] = (uint8_t)(R0); /* BA4A; MOV:G.B R0, @H'F85C; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F85C; cycles=7 */ + R0 = (uint8_t)(0x5A); /* BA4E; MOV:E.B #H'5A, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX checksum starts from seed H'005A; confidence high; dataflow R0=0x5A; cycles=2 */ + R0 ^= (uint8_t)(MEM8[0xF858]); /* BA50; XOR.B @H'F858, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F858; cycles=7 */ + R0 ^= (uint8_t)(MEM8[0xF859]); /* BA54; XOR.B @H'F859, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F859; cycles=7 */ + R0 ^= (uint8_t)(MEM8[0xF85A]); /* BA58; XOR.B @H'F85A, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F85A; cycles=7 */ + R0 ^= (uint8_t)(MEM8[0xF85B]); /* BA5C; XOR.B @H'F85B, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F85B; cycles=7 */ + R0 ^= (uint8_t)(MEM8[0xF85C]); /* BA60; XOR.B @H'F85C, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F85C; cycles=7 */ + MEM8[0xF85D] = (uint8_t)(R0); /* BA64; MOV:G.B R0, @H'F85D; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate checksum byte write targets H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: XOR chain appears to feed the H'F85D checksum byte; confidence high; refs ram_F85D; cycles=7 */ do { set_flags_btst(SCI1_SSR, 7); /* BA68; BTST.B #7, @SCI1_SSR; wait for SCI1 transmit data register empty (TDRE=1); SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=7 */ } while (Z); /* BA6C; BEQ loc_BA68; repeat SCI1 transmit-empty wait while TDRE=0; cycles=3/7 nt/t */ - R0 = (uint8_t)(MEM8[0xF858]); /* BA6E; MOV:G.B @H'F858, R0; refs ram_F858; cycles=7 */ - SCI1_TDR = (uint8_t)(R0); /* BA72; MOV:G.B R0, @SCI1_TDR; SCI1_TDR; write RS232/SCI byte to SCI1 TDR for transmission; SCI1 TDR write transmits on traced RS232/MAX202 path: H8 pin 66 P95/TXD -> MAX202 pin 11; refs SCI1_TDR; cycles=7 */ - MEM8[0xF9C2] = (uint8_t)(0x01); /* BA76; MOV:G.B #H'01, @H'F9C2; refs ram_F9C2; cycles=9 */ + R0 = (uint8_t)(MEM8[0xF858]); /* BA6E; MOV:G.B @H'F858, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: initial SCI1 TDR send is supported by a read from H'F858; confidence high; refs ram_F858; cycles=7 */ + SCI1_TDR = (uint8_t)(R0); /* BA72; MOV:G.B R0, @SCI1_TDR; SCI1_TDR; write RS232/SCI byte to SCI1 TDR for transmission; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: initial SCI1 TDR send is supported by a read from H'F858; confidence high; SCI1 TDR write transmits on traced RS232/MAX202 path: H8 pin 66 P95/TXD -> MAX202 pin 11; refs SCI1_TDR; cycles=7 */ + MEM8[0xF9C2] = (uint8_t)(0x01); /* BA76; MOV:G.B #H'01, @H'F9C2; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: write evidence supports TX index H'F9C2 being initialized to 1; confidence high; refs ram_F9C2; cycles=9 */ SCI1_SSR &= ~BIT(7); /* BA7B; BCLR.B #7, @SCI1_SSR; clear TDRE (bit 7) of SCI1_SSR; clear SCI1 transmit data register empty flag (TDRE); SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ SCI1_SCR |= BIT(7); /* BA7F; BSET.B #7, @SCI1_SCR; set TIE (bit 7) of SCI1_SCR; enable SCI1 TX interrupt (TIE); SCI1 SCR write TE=1 RE=1; TE/RE select the traced RS232/MAX202 pins (P95/TXD pin 66 to MAX202 pin 11, P96/RXD pin 67 to MAX202 pin 12); refs SCI1_SCR; cycles=8 */ return; /* BA83; RTS; cycles=13 */ @@ -2875,14 +2875,14 @@ void vec_sci1_txi_BA84(void) goto loc_BAF1; /* BAA7; BRA loc_BAF1; cycles=8 */ loc_BAA9: MEM16[--R7] = (uint16_t)(R0); /* BAA9; MOV:G.W R0, @-R7; cycles=5 */ - R0 = (uint8_t)(MEM8[0xF9C2]); /* BAAB; MOV:G.B @H'F9C2, R0; refs ram_F9C2; cycles=6 */ + R0 = (uint8_t)(MEM8[0xF9C2]); /* BAAB; MOV:G.B @H'F9C2, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high; refs ram_F9C2; cycles=6 */ R0 = zero_extend8(R0); /* BAAF; EXTU.B R0; cycles=3 */ - R0 = (uint8_t)(MEM8[R0 - 0x07A8]); /* BAB1; MOV:G.B @(-H'07A8,R0), R0; cycles=6 */ - SCI1_TDR = (uint8_t)(R0); /* BAB5; MOV:G.B R0, @SCI1_TDR; SCI1_TDR; write RS232/SCI byte to SCI1 TDR for transmission; SCI1 TDR write transmits on traced RS232/MAX202 path: H8 pin 66 P95/TXD -> MAX202 pin 11; refs SCI1_TDR; cycles=6 */ + R0 = (uint8_t)(MEM8[R0 - 0x07A8]); /* BAB1; MOV:G.B @(-H'07A8,R0), R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high; cycles=6 */ + SCI1_TDR = (uint8_t)(R0); /* BAB5; MOV:G.B R0, @SCI1_TDR; SCI1_TDR; write RS232/SCI byte to SCI1 TDR for transmission; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR sends SCI1 TDR from indexed H'F858 buffer; confidence high; SCI1 TDR write transmits on traced RS232/MAX202 path: H8 pin 66 P95/TXD -> MAX202 pin 11; refs SCI1_TDR; cycles=6 */ R0 = (uint16_t)(MEM16[R7++]); /* BAB9; MOV:G.W @R7+, R0; cycles=6 */ SCI1_SSR &= ~BIT(7); /* BABB; BCLR.B #7, @SCI1_SSR; clear TDRE (bit 7) of SCI1_SSR; clear SCI1 transmit data register empty flag (TDRE); SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ - MEM8[0xF9C2] += (uint8_t)(1); /* BABF; ADD:Q.B #1, @H'F9C2; refs ram_F9C2; cycles=8 */ - set_flags_cmp8(MEM8[0xF9C2], 0x06); /* BAC3; CMP:G.B #H'06, @H'F9C2; refs ram_F9C2; cycles=6 */ + MEM8[0xF9C2] += (uint8_t)(1); /* BABF; ADD:Q.B #1, @H'F9C2; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR increments TX index H'F9C2; confidence high; refs ram_F9C2; cycles=8 */ + set_flags_cmp8(MEM8[0xF9C2], 0x06); /* BAC3; CMP:G.B #H'06, @H'F9C2; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: candidate TX ISR compares TX index to frame length 6; confidence high; refs ram_F9C2; cycles=6 */ if (!Z) goto loc_BAF1; /* BAC8; BNE loc_BAF1; cycles=3/7 nt/t */ SCI1_SCR &= ~BIT(7); /* BACA; BCLR.B #7, @SCI1_SCR; clear TIE (bit 7) of SCI1_SCR; disable SCI1 TX interrupt (TIE); SCI1 SCR write TE=1 RE=1; TE/RE select the traced RS232/MAX202 pins (P95/TXD pin 66 to MAX202 pin 11, P96/RXD pin 67 to MAX202 pin 12); refs SCI1_SCR; cycles=9 */ set_flags_btst(MEM8[0xF795], 6); /* BACE; BTST.B #6, @H'F795; refs ram_F795; cycles=7 */ @@ -2955,7 +2955,7 @@ void vec_sci1_rxi_BB67(void) /* vector sources: sci1_rxi */ push_registers(R0, R1); /* BB67; STM.W {R0,R1}, @-SP; cycles=12 */ SCI1_SSR &= ~BIT(6); /* BB69; BCLR.B #6, @SCI1_SSR; clear RDRF (bit 6) of SCI1_SSR; clear SCI1 receive-data-full flag (RDRF); SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ - R0 = (uint8_t)(SCI1_RDR); /* BB6D; MOV:G.B @SCI1_RDR, R0; read SCI1 received byte from RDR; SCI1 RDR read receives from traced RS232/MAX202 path: MAX202 pin 12 -> H8 pin 67 P96/RXD; refs SCI1_RDR; cycles=6 */ + R0 = (uint8_t)(SCI1_RDR); /* BB6D; MOV:G.B @SCI1_RDR, R0; read SCI1 received byte from RDR; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: SCI1 RX ISR reads a byte from SCI1_RDR; confidence high; SCI1 RDR read receives from traced RS232/MAX202 path: MAX202 pin 12 -> H8 pin 67 P96/RXD; refs SCI1_RDR; cycles=6 */ set_flags_tst8(MEM8[0xF9C1]); /* BB71; TST.B @H'F9C1; refs ram_F9C1; cycles=6 */ if (!Z) goto loc_BB7D; /* BB75; BNE loc_BB7D; cycles=3/8 nt/t */ MEM8[0xF9C3] = 0; /* BB77; CLR.B @H'F9C3; refs ram_F9C3; cycles=8 */ @@ -2968,12 +2968,12 @@ loc_BB7D: loc_BB8A: R1 = (uint8_t)(MEM8[0xF9C3]); /* BB8A; MOV:G.B @H'F9C3, R1; refs ram_F9C3; cycles=7 */ R1 = zero_extend8(R1); /* BB8E; EXTU.B R1; cycles=3 */ - MEM8[R1 - 0x0798] = (uint8_t)(R0); /* BB90; MOV:G.B R0, @(-H'0798,R1); cycles=7 */ - R1 += (uint8_t)(1); /* BB94; ADD:Q.B #1, R1; cycles=4 */ - MEM8[0xF9C3] = (uint8_t)(R1); /* BB96; MOV:G.B R1, @H'F9C3; refs ram_F9C3; cycles=7 */ - set_flags_cmp8(R1, 0x06); /* BB9A; CMP:E #H'06, R1; cycles=2 */ + MEM8[R1 - 0x0798] = (uint8_t)(R0); /* BB90; MOV:G.B R0, @(-H'0798,R1); candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: received bytes are stored into candidate capture buffer H'F868-H'F86D; confidence high; cycles=7 */ + R1 += (uint8_t)(1); /* BB94; ADD:Q.B #1, R1; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX byte count/index is incremented and stored at H'F9C3; confidence high; cycles=4 */ + MEM8[0xF9C3] = (uint8_t)(R1); /* BB96; MOV:G.B R1, @H'F9C3; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX byte count/index is incremented and stored at H'F9C3; confidence high; refs ram_F9C3; cycles=7 */ + set_flags_cmp8(R1, 0x06); /* BB9A; CMP:E #H'06, R1; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX ISR compares incremented count to candidate frame length 6; confidence high; cycles=2 */ if (!Z) goto loc_BBA3; /* BB9C; BNE loc_BBA3; cycles=3/7 nt/t */ - MEM8[0xF9C5] = (uint8_t)(0x14); /* BB9E; MOV:G.B #H'14, @H'F9C5; refs ram_F9C5; cycles=9 */ + MEM8[0xF9C5] = (uint8_t)(0x14); /* BB9E; MOV:G.B #H'14, @H'F9C5; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX ISR sets H'F9C5 after count reaches 6; confidence high; refs ram_F9C5; cycles=9 */ loc_BBA3: MEM8[0xF9C1] = (uint8_t)(0x05); /* BBA3; MOV:G.B #H'05, @H'F9C1; refs ram_F9C1; cycles=9 */ pop_registers(R0, R1); /* BBA8; LDM.W @SP+, {R0,R1}; cycles=14 */ @@ -2982,24 +2982,24 @@ loc_BBA3: void loc_BBAB(void) { - set_flags_cmp8(MEM8[0xF9C3], 0x06); /* BBAB; CMP:G.B #H'06, @H'F9C3; refs ram_F9C3; cycles=6 */ + set_flags_cmp8(MEM8[0xF9C3], 0x06); /* BBAB; CMP:G.B #H'06, @H'F9C3; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing path requires H'F9C3 to equal 6; confidence high; refs ram_F9C3; cycles=6 */ if (!Z) goto loc_BE6F; /* BBB0; BNE loc_BE6F; cycles=3/7 nt/t */ - R0 = (uint16_t)(MEM16[0xF868]); /* BBB3; MOV:G.W @H'F868, R0; refs ram_F868; cycles=6 */ - MEM16[0xF860] = (uint16_t)(R0); /* BBB7; MOV:G.W R0, @H'F860; refs ram_F860; cycles=6 */ - R0 = (uint16_t)(MEM16[0xF86A]); /* BBBB; MOV:G.W @H'F86A, R0; refs ram_F86A; cycles=6 */ - MEM16[0xF862] = (uint16_t)(R0); /* BBBF; MOV:G.W R0, @H'F862; refs ram_F862; cycles=6 */ - R0 = (uint16_t)(MEM16[0xF86C]); /* BBC3; MOV:G.W @H'F86C, R0; refs ram_F86C; cycles=6 */ - MEM16[0xF864] = (uint16_t)(R0); /* BBC7; MOV:G.W R0, @H'F864; refs ram_F864; cycles=6 */ + R0 = (uint16_t)(MEM16[0xF868]); /* BBB3; MOV:G.W @H'F868, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F868; cycles=6 */ + MEM16[0xF860] = (uint16_t)(R0); /* BBB7; MOV:G.W R0, @H'F860; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F860; cycles=6 */ + R0 = (uint16_t)(MEM16[0xF86A]); /* BBBB; MOV:G.W @H'F86A, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F86A; cycles=6 */ + MEM16[0xF862] = (uint16_t)(R0); /* BBBF; MOV:G.W R0, @H'F862; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F862; cycles=6 */ + R0 = (uint16_t)(MEM16[0xF86C]); /* BBC3; MOV:G.W @H'F86C, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F86C; cycles=6 */ + MEM16[0xF864] = (uint16_t)(R0); /* BBC7; MOV:G.W R0, @H'F864; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX processing copies candidate capture buffer H'F868-H'F86D to validation buffer H'F860-H'F865; confidence high; refs ram_F864; cycles=6 */ MEM8[0xF9C3] = 0; /* BBCB; CLR.B @H'F9C3; refs ram_F9C3; cycles=8 */ set_flags_btst(MEM8[0xFAA4], 7); /* BBCF; BTST.B #7, @H'FAA4; refs ram_FAA4; cycles=6 */ if (!Z) goto loc_BE29; /* BBD3; BNE loc_BE29; cycles=3/8 nt/t */ - R0 = (uint8_t)(0x5A); /* BBD6; MOV:E.B #H'5A, R0; dataflow R0=0x5A; cycles=2 */ - R0 ^= (uint8_t)(MEM8[0xF860]); /* BBD8; XOR.B @H'F860, R0; refs ram_F860; cycles=7 */ - R0 ^= (uint8_t)(MEM8[0xF861]); /* BBDC; XOR.B @H'F861, R0; refs ram_F861; cycles=7 */ - R0 ^= (uint8_t)(MEM8[0xF862]); /* BBE0; XOR.B @H'F862, R0; refs ram_F862; cycles=7 */ - R0 ^= (uint8_t)(MEM8[0xF863]); /* BBE4; XOR.B @H'F863, R0; refs ram_F863; cycles=7 */ - R0 ^= (uint8_t)(MEM8[0xF864]); /* BBE8; XOR.B @H'F864, R0; refs ram_F864; cycles=7 */ - set_flags_cmp8(R0, MEM8[0xF865]); /* BBEC; CMP:G.B @H'F865, R0; refs ram_F865; cycles=7 */ + R0 = (uint8_t)(0x5A); /* BBD6; MOV:E.B #H'5A, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: candidate RX checksum validation starts from seed H'005A; confidence high; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; dataflow R0=0x5A; cycles=2 */ + R0 ^= (uint8_t)(MEM8[0xF860]); /* BBD8; XOR.B @H'F860, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F860; cycles=7 */ + R0 ^= (uint8_t)(MEM8[0xF861]); /* BBDC; XOR.B @H'F861, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F861; cycles=7 */ + R0 ^= (uint8_t)(MEM8[0xF862]); /* BBE0; XOR.B @H'F862, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F862; cycles=7 */ + R0 ^= (uint8_t)(MEM8[0xF863]); /* BBE4; XOR.B @H'F863, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F863; cycles=7 */ + R0 ^= (uint8_t)(MEM8[0xF864]); /* BBE8; XOR.B @H'F864, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F864; cycles=7 */ + set_flags_cmp8(R0, MEM8[0xF865]); /* BBEC; CMP:G.B @H'F865, R0; candidate/evidence-supported SCI1 6-byte RX frame; capture H'F868-H'F86D, validate H'F860-H'F865, checksum H'F865 seeded by H'005A; evidence: RX path XORs H'F860-H'F864 and compares the result with H'F865; confidence high; refs ram_F865; cycles=7 */ if (!Z) goto loc_BE29; /* BBF0; BNE loc_BE29; cycles=3/7 nt/t */ MEM8[0xFAA6] = 0; /* BBF3; CLR.B @H'FAA6; refs ram_FAA6; cycles=8 */ R5 = (uint8_t)(MEM8[0xF861]); /* BBF7; MOV:G.B @H'F861, R5; refs ram_F861; cycles=6 */ @@ -3193,11 +3193,11 @@ loc_BDDB: MEM8[0xFAA2] = 0; /* BDFF; CLR.B @H'FAA2; refs ram_FAA2; cycles=8 */ goto loc_BE6F; /* BE03; BRA loc_BE6F; cycles=8 */ loc_BE05: - R0 = (uint16_t)(MEM16[0xF858]); /* BE05; MOV:G.W @H'F858, R0; refs ram_F858; cycles=6 */ + R0 = (uint16_t)(MEM16[0xF858]); /* BE05; MOV:G.W @H'F858, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F858; cycles=6 */ MEM16[0xF850] = (uint16_t)(R0); /* BE09; MOV:G.W R0, @H'F850; refs ram_F850; cycles=6 */ - R0 = (uint16_t)(MEM16[0xF85A]); /* BE0D; MOV:G.W @H'F85A, R0; refs ram_F85A; cycles=6 */ + R0 = (uint16_t)(MEM16[0xF85A]); /* BE0D; MOV:G.W @H'F85A, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F85A; cycles=6 */ MEM16[0xF852] = (uint16_t)(R0); /* BE11; MOV:G.W R0, @H'F852; refs ram_F852; cycles=6 */ - R0 = (uint16_t)(MEM16[0xF85C]); /* BE15; MOV:G.W @H'F85C, R0; refs ram_F85C; cycles=6 */ + R0 = (uint16_t)(MEM16[0xF85C]); /* BE15; MOV:G.W @H'F85C, R0; candidate/evidence-supported SCI1 6-byte TX frame; H'F858-H'F85D, checksum H'F85D seeded by H'005A; evidence: TX buffer-region references cluster around H'F858-H'F85D; confidence high; refs ram_F85C; cycles=6 */ MEM16[0xF854] = (uint16_t)(R0); /* BE19; MOV:G.W R0, @H'F854; refs ram_F854; cycles=6 */ MEM8[0xF9C0] = (uint8_t)(0x1F); /* BE1D; MOV:G.B #H'1F, @H'F9C0; refs ram_F9C0; cycles=9 */ loc_BA26(); /* BE22; BSR loc_BA26; cycles=13 */ diff --git a/h8536/cli.py b/h8536/cli.py index cc161b8..0460ac4 100644 --- a/h8536/cli.py +++ b/h8536/cli.py @@ -18,6 +18,7 @@ from .render import format_callgraph_dot, format_listing, write_json from .rom import Rom from .sci import analyze_sci from .sci_protocol import analyze_sci_protocol +from .serial_reconstruction import analyze_serial_reconstruction from .symbols import discover_symbols from .timing import summarize_timing from .vectors import read_dtc_vectors_max, read_dtc_vectors_min, read_vectors_max, read_vectors_min @@ -90,6 +91,7 @@ def main() -> int: timing_summary = summarize_timing(instructions, labels, call_graph) if args.timing else None sci_analysis = analyze_sci(instructions, clock_hz=args.clock_hz) sci_protocol = analyze_sci_protocol(instructions) + serial_reconstruction = analyze_serial_reconstruction(instructions) board_profile = ( None if args.board_profile == "none" @@ -116,6 +118,7 @@ def main() -> int: show_cycles=args.cycles, sci_analysis=sci_analysis, sci_protocol=sci_protocol, + serial_reconstruction=serial_reconstruction, board_profile=board_profile, peripheral_access=peripheral_access, indirect_flow=indirect_flow, @@ -139,6 +142,7 @@ def main() -> int: timing_summary=timing_summary, sci_analysis=sci_analysis, sci_protocol=sci_protocol, + serial_reconstruction=serial_reconstruction, board_profile=board_profile, peripheral_access=peripheral_access, indirect_flow=indirect_flow, diff --git a/h8536/pseudocode.py b/h8536/pseudocode.py index bf2f87d..27705f6 100644 --- a/h8536/pseudocode.py +++ b/h8536/pseudocode.py @@ -904,6 +904,10 @@ def _metadata_comments(ins: JsonObject) -> list[str]: if isinstance(event, dict) and event.get("comment"): comments.append(str(event["comment"])) + for item in ins.get("serial_reconstruction", []): + if isinstance(item, dict) and item.get("comment"): + comments.append(str(item["comment"])) + board_profile = ins.get("board_profile") if isinstance(board_profile, dict) and board_profile.get("comment"): comments.append(str(board_profile["comment"])) diff --git a/h8536/render.py b/h8536/render.py index ea1f233..886c486 100644 --- a/h8536/render.py +++ b/h8536/render.py @@ -25,6 +25,11 @@ from .sci_protocol import ( sci_protocol_json_payload, sci_protocol_metadata_for_instruction, ) +from .serial_reconstruction import ( + serial_reconstruction_comment_for_instruction, + serial_reconstruction_json_payload, + serial_reconstruction_metadata_for_instruction, +) from .symbols import symbol_for_address from .tables import IO_REGISTERS from .timing import format_timing_summary @@ -248,6 +253,42 @@ def _board_profile_lines(board_profile: dict[str, object] | None) -> list[str]: return lines +def _serial_reconstruction_lines(serial_reconstruction: dict[str, object] | None) -> list[str]: + if not serial_reconstruction: + return [] + candidates = serial_reconstruction.get("candidates", []) + if not isinstance(candidates, list) or not candidates: + return [] + + lines = ["; Serial Protocol Reconstruction"] + for candidate in candidates: + if not isinstance(candidate, dict): + continue + kind = str(candidate.get("kind", "candidate")) + confidence = candidate.get("confidence") + score = candidate.get("confidence_score") + if kind == "candidate_sci1_tx_frame": + lines.append( + f"; TX candidate: {candidate['frame_length']} bytes " + f"{candidate['buffer_start_hex']}-{candidate['buffer_end_hex']}, " + f"checksum {candidate['checksum_address_hex']} seeded by {candidate['checksum_seed_hex']} " + f"(confidence {confidence} {score})", + ) + elif kind == "candidate_sci1_rx_frame": + lines.append( + f"; RX candidate: {candidate['frame_length']} bytes " + f"capture {candidate['capture_buffer_start_hex']}-{candidate['capture_buffer_end_hex']}, " + f"validate {candidate['validation_buffer_start_hex']}-{candidate['validation_buffer_end_hex']} " + f"checksum {candidate['checksum_address_hex']} seeded by {candidate['checksum_seed_hex']} " + f"(confidence {confidence} {score})", + ) + caveat = candidate.get("caveat") + if caveat: + lines.append(f"; caveat: {caveat}") + lines.append("") + return lines + + def format_listing( rom_path: Path, rom: Rom, @@ -262,6 +303,7 @@ def format_listing( show_cycles: bool = False, sci_analysis: dict[str, object] | None = None, sci_protocol: dict[str, object] | None = None, + serial_reconstruction: dict[str, object] | None = None, board_profile: dict[str, object] | None = None, peripheral_access: dict[str, object] | None = None, indirect_flow: dict[str, object] | None = None, @@ -328,6 +370,7 @@ def format_listing( lines.extend(_symbol_lines(symbols)) lines.extend(_board_profile_lines(board_profile)) + lines.extend(_serial_reconstruction_lines(serial_reconstruction)) lines.extend(_lcd_text_lines(lcd_text)) lines.extend(_lcd_driver_lines(lcd_driver)) @@ -347,6 +390,7 @@ def format_listing( ins.comment, sci_comment_for_instruction(sci_analysis, address), sci_protocol_comment_for_instruction(sci_protocol, address), + serial_reconstruction_comment_for_instruction(serial_reconstruction, address), board_comment_for_instruction(board_profile, address), peripheral_comment_for_instruction(peripheral_access, address), indirect_comment_for_instruction(indirect_flow, address), @@ -375,6 +419,7 @@ def write_json( timing_summary: dict[str, list[dict[str, object]]] | None = None, sci_analysis: dict[str, object] | None = None, sci_protocol: dict[str, object] | None = None, + serial_reconstruction: dict[str, object] | None = None, board_profile: dict[str, object] | None = None, peripheral_access: dict[str, object] | None = None, indirect_flow: dict[str, object] | None = None, @@ -404,6 +449,7 @@ def write_json( "timing_summary": timing_summary or {"blocks": [], "loops": []}, "sci": sci_json_payload(sci_analysis), "sci_protocol": sci_protocol_json_payload(sci_protocol), + "serial_reconstruction": serial_reconstruction_json_payload(serial_reconstruction), "board_profile": board_json_payload(board_profile), "peripheral_access": peripheral_json_payload(peripheral_access), "indirect_flow": indirect_flow or {"sites": []}, @@ -416,6 +462,7 @@ def write_json( ins, sci_analysis, sci_protocol, + serial_reconstruction, board_profile, peripheral_access, indirect_flow, @@ -477,6 +524,7 @@ def _instruction_payload( ins: Instruction, sci_analysis: dict[str, object] | None = None, sci_protocol: dict[str, object] | None = None, + serial_reconstruction: dict[str, object] | None = None, board_profile: dict[str, object] | None = None, peripheral_access: dict[str, object] | None = None, indirect_flow: dict[str, object] | None = None, @@ -514,6 +562,9 @@ def _instruction_payload( sci_protocol_metadata = sci_protocol_metadata_for_instruction(sci_protocol, ins.address) if sci_protocol_metadata: payload["sci_protocol"] = sci_protocol_metadata + serial_reconstruction_metadata = serial_reconstruction_metadata_for_instruction(serial_reconstruction, ins.address) + if serial_reconstruction_metadata: + payload["serial_reconstruction"] = serial_reconstruction_metadata board_metadata = board_metadata_for_instruction(board_profile, ins.address) if board_metadata: payload["board_profile"] = board_metadata diff --git a/h8536/serial_reconstruction.py b/h8536/serial_reconstruction.py new file mode 100644 index 0000000..aa087dc --- /dev/null +++ b/h8536/serial_reconstruction.py @@ -0,0 +1,863 @@ +from __future__ import annotations + +from collections.abc import Iterable, Mapping + +from .formatting import h16, parse_int +from .model import Instruction + + +SCI1_TDR_ADDRESS = 0xFEDB +SCI1_RDR_ADDRESS = 0xFEDD +TX_BUFFER_START = 0xF858 +TX_CHECKSUM_ADDRESS = 0xF85D +TX_BUFFER_END = TX_CHECKSUM_ADDRESS +TX_INDEX_ADDRESS = 0xF9C2 +TX_FRAME_LENGTH = 6 +CHECKSUM_SEED = 0x5A + +RX_FRAME_START = 0xF860 +RX_CHECKSUM_ADDRESS = 0xF865 +RX_FRAME_END = RX_CHECKSUM_ADDRESS +RX_CAPTURE_START = 0xF868 +RX_CAPTURE_END = 0xF86D +RX_INDEX_ADDRESS = 0xF9C3 +RX_INTERBYTE_TIMEOUT_ADDRESS = 0xF9C1 +RX_COMPLETE_TIMER_ADDRESS = 0xF9C5 +RX_FRAME_LENGTH = 6 + +_BUFFER_DATA_END = TX_CHECKSUM_ADDRESS - 1 +_MIN_BUFFER_REFERENCES = 3 + +_TX_REQUIRED_EVIDENCE = ( + "tx_buffer_region", + "tx_checksum_seed", + "checksum_byte", + "xor_checksum_chain", + "initial_send_from_buffer_start", + "tx_index_initialized_to_one", + "tx_isr_indexed_send", + "tx_index_increment", + "tx_index_compare_frame_length", +) + +_RX_REQUIRED_EVIDENCE = ( + "rx_rdr_read", + "rx_indexed_store", + "rx_index_increment_store", + "rx_isr_compare_frame_length", + "rx_complete_timer", + "rx_processor_requires_six_bytes", + "rx_copy_capture_to_frame_buffer", + "rx_checksum_seed", + "rx_xor_checksum_validation", +) + + +def analyze_serial_reconstruction( + instructions: Mapping[int, Instruction] | Iterable[Instruction], +) -> dict[str, object]: + """Reconstruct conservative serial-frame candidates from independent evidence.""" + ordered = _instruction_sequence(instructions) + evidence = _collect_tx_evidence(ordered) + _collect_rx_evidence(ordered) + candidates = [ + candidate + for candidate in ( + _tx_candidate_from_evidence(evidence), + _rx_candidate_from_evidence(evidence), + ) + if candidate is not None + ] + + annotations: dict[int, list[str]] = {} + instruction_metadata: dict[int, list[dict[str, object]]] = {} + + for candidate in candidates: + for item in candidate["evidence"]: + if not isinstance(item, Mapping): + continue + comment = _comment_for_evidence(candidate, item) + for address in item.get("addresses", []): + if not isinstance(address, int): + continue + annotations.setdefault(address, []) + if comment not in annotations[address]: + annotations[address].append(comment) + instruction_metadata.setdefault(address, []).append( + _instruction_metadata(candidate, item, address, comment), + ) + + return { + "kind": "serial_reconstruction", + "candidates": candidates, + "evidence": evidence, + "required_evidence": { + "tx": list(_TX_REQUIRED_EVIDENCE), + "rx": list(_RX_REQUIRED_EVIDENCE), + }, + "annotations": { + address: "; ".join(parts) + for address, parts in sorted(annotations.items()) + }, + "instructions": instruction_metadata, + } + + +def serial_reconstruction_comment_for_instruction( + analysis: Mapping[str, object] | None, + address: int, +) -> str: + if not analysis: + return "" + annotations = analysis.get("annotations") + if not isinstance(annotations, Mapping): + return "" + comment = annotations.get(address) + if comment is None: + comment = annotations.get(str(address)) + return str(comment) if comment else "" + + +def serial_reconstruction_metadata_for_instruction( + analysis: Mapping[str, object] | None, + address: int, +) -> list[dict[str, object]]: + if not analysis: + return [] + instructions = analysis.get("instructions") + if not isinstance(instructions, Mapping): + return [] + metadata = instructions.get(address) + if metadata is None: + metadata = instructions.get(str(address)) + return list(metadata) if isinstance(metadata, list) else [] + + +def serial_reconstruction_json_payload(analysis: Mapping[str, object] | None) -> dict[str, object]: + if not analysis: + return { + "kind": "serial_reconstruction", + "candidates": [], + "evidence": [], + "required_evidence": { + "tx": list(_TX_REQUIRED_EVIDENCE), + "rx": list(_RX_REQUIRED_EVIDENCE), + }, + } + return { + "kind": analysis.get("kind", "serial_reconstruction"), + "candidates": analysis.get("candidates", []), + "evidence": analysis.get("evidence", []), + "required_evidence": analysis.get( + "required_evidence", + {"tx": list(_TX_REQUIRED_EVIDENCE), "rx": list(_RX_REQUIRED_EVIDENCE)}, + ), + } + + +def _collect_tx_evidence(ordered: list[Instruction]) -> list[dict[str, object]]: + evidence: list[dict[str, object]] = [] + + buffer_references = _buffer_region_references(ordered) + if len({ref for ins in buffer_references for ref in _buffer_refs(ins)}) >= _MIN_BUFFER_REFERENCES: + evidence.append( + _evidence( + "tx_buffer_region", + buffer_references, + summary=( + f"TX buffer-region references cluster around {h16(TX_BUFFER_START)}" + f"-{h16(TX_BUFFER_END)}" + ), + distinct_buffer_addresses=sorted( + {ref for ins in buffer_references for ref in _buffer_refs(ins)} + ), + ), + ) + + checksum_seed = _checksum_seed_before_xor(ordered, TX_BUFFER_START, _BUFFER_DATA_END) + if checksum_seed: + evidence.append( + _evidence( + "tx_checksum_seed", + checksum_seed, + summary=f"candidate TX checksum starts from seed {h16(CHECKSUM_SEED)}", + ), + ) + + checksum_writes = [ins for ins in ordered if _is_write_to_address(ins, TX_CHECKSUM_ADDRESS)] + if checksum_writes: + evidence.append( + _evidence( + "checksum_byte", + checksum_writes, + summary=f"candidate checksum byte write targets {h16(TX_CHECKSUM_ADDRESS)}", + ), + ) + + xor_chain = _xor_checksum_chain(ordered, checksum_writes) + if xor_chain: + evidence.append( + _evidence( + "xor_checksum_chain", + xor_chain, + summary=f"XOR chain appears to feed the {h16(TX_CHECKSUM_ADDRESS)} checksum byte", + ), + ) + + initial_send = _initial_send_from_buffer_start(ordered) + if initial_send: + evidence.append( + _evidence( + "initial_send_from_buffer_start", + initial_send, + summary=f"initial SCI1 TDR send is supported by a read from {h16(TX_BUFFER_START)}", + ), + ) + + index_init = [ins for ins in ordered if _is_index_initialized_to_one(ins)] + if index_init: + evidence.append( + _evidence( + "tx_index_initialized_to_one", + index_init, + summary=f"write evidence supports TX index {h16(TX_INDEX_ADDRESS)} being initialized to 1", + ), + ) + + isr_sequence = _indexed_tx_isr_sequence(ordered) + if isr_sequence: + evidence.append( + _evidence( + "tx_isr_indexed_send", + isr_sequence["send"], + summary=( + f"candidate TX ISR sends SCI1 TDR from indexed {h16(TX_BUFFER_START)} buffer" + ), + ), + ) + evidence.append( + _evidence( + "tx_index_increment", + isr_sequence["increment"], + summary=f"candidate TX ISR increments TX index {h16(TX_INDEX_ADDRESS)}", + ), + ) + evidence.append( + _evidence( + "tx_index_compare_frame_length", + isr_sequence["compare"], + summary=f"candidate TX ISR compares TX index to frame length {TX_FRAME_LENGTH}", + ), + ) + + return evidence + + +def _collect_rx_evidence(ordered: list[Instruction]) -> list[dict[str, object]]: + evidence: list[dict[str, object]] = [] + + rdr_reads = [ins for ins in ordered if _is_read_from_address(ins, SCI1_RDR_ADDRESS)] + if rdr_reads: + evidence.append( + _evidence( + "rx_rdr_read", + rdr_reads, + summary="SCI1 RX ISR reads a byte from SCI1_RDR", + ), + ) + + indexed_stores = [ins for ins in ordered if _is_indexed_capture_store(ins)] + if indexed_stores: + evidence.append( + _evidence( + "rx_indexed_store", + indexed_stores, + summary=f"received bytes are stored into candidate capture buffer {h16(RX_CAPTURE_START)}-{h16(RX_CAPTURE_END)}", + ), + ) + + index_store = _rx_index_increment_store(ordered) + if index_store: + evidence.append( + _evidence( + "rx_index_increment_store", + index_store, + summary=f"RX byte count/index is incremented and stored at {h16(RX_INDEX_ADDRESS)}", + ), + ) + + isr_length_checks = [ + ins + for ins in ordered + if _mnemonic_root(ins.mnemonic) in {"CMP", "CMP:E", "CMP:G", "CMP:I"} + and _immediate_source_value(ins.operands) == RX_FRAME_LENGTH + and _destination_operand(ins.operands).upper() in {"R1", "R1L"} + ] + if isr_length_checks: + evidence.append( + _evidence( + "rx_isr_compare_frame_length", + isr_length_checks, + summary=f"RX ISR compares incremented count to candidate frame length {RX_FRAME_LENGTH}", + ), + ) + + complete_timers = [ + ins + for ins in ordered + if _is_write_to_address(ins, RX_COMPLETE_TIMER_ADDRESS) + and _immediate_source_value(ins.operands) == 0x14 + ] + if complete_timers: + evidence.append( + _evidence( + "rx_complete_timer", + complete_timers, + summary=f"RX ISR sets {h16(RX_COMPLETE_TIMER_ADDRESS)} after count reaches {RX_FRAME_LENGTH}", + ), + ) + + processor_length_checks = [ + ins + for ins in ordered + if _mnemonic_root(ins.mnemonic) in {"CMP", "CMP:E", "CMP:G", "CMP:I"} + and RX_INDEX_ADDRESS in ins.references + and _immediate_source_value(ins.operands) == RX_FRAME_LENGTH + ] + if processor_length_checks: + evidence.append( + _evidence( + "rx_processor_requires_six_bytes", + processor_length_checks, + summary=f"RX processing path requires {h16(RX_INDEX_ADDRESS)} to equal {RX_FRAME_LENGTH}", + ), + ) + + copies = _rx_copy_capture_to_frame_buffer(ordered) + if copies: + evidence.append( + _evidence( + "rx_copy_capture_to_frame_buffer", + copies, + summary=( + f"RX processing copies candidate capture buffer {h16(RX_CAPTURE_START)}-{h16(RX_CAPTURE_END)} " + f"to validation buffer {h16(RX_FRAME_START)}-{h16(RX_FRAME_END)}" + ), + ), + ) + + checksum_seed = _checksum_seed_before_xor(ordered, RX_FRAME_START, RX_CHECKSUM_ADDRESS - 1) + if checksum_seed: + evidence.append( + _evidence( + "rx_checksum_seed", + checksum_seed, + summary=f"candidate RX checksum validation starts from seed {h16(CHECKSUM_SEED)}", + ), + ) + + checksum_validation = _rx_xor_checksum_validation(ordered) + if checksum_validation: + evidence.append( + _evidence( + "rx_xor_checksum_validation", + checksum_validation, + summary=( + f"RX path XORs {h16(RX_FRAME_START)}-{h16(RX_CHECKSUM_ADDRESS - 1)} " + f"and compares the result with {h16(RX_CHECKSUM_ADDRESS)}" + ), + ), + ) + + return evidence + + +def _tx_candidate_from_evidence(evidence: list[dict[str, object]]) -> dict[str, object] | None: + evidence_by_key = {str(item["kind"]): item for item in evidence} + missing = [key for key in _TX_REQUIRED_EVIDENCE if key not in evidence_by_key] + if missing: + return None + + evidence_addresses = { + key: list(evidence_by_key[key]["addresses"]) + for key in _TX_REQUIRED_EVIDENCE + } + candidate: dict[str, object] = { + "id": "sci1_tx_frame_f858_len6_candidate", + "kind": "candidate_sci1_tx_frame", + "channel": "SCI1", + "frame_length": TX_FRAME_LENGTH, + "buffer_start": TX_BUFFER_START, + "buffer_start_hex": h16(TX_BUFFER_START), + "buffer_end": TX_BUFFER_END, + "buffer_end_hex": h16(TX_BUFFER_END), + "checksum_address": TX_CHECKSUM_ADDRESS, + "checksum_address_hex": h16(TX_CHECKSUM_ADDRESS), + "tx_index_address": TX_INDEX_ADDRESS, + "tx_index_address_hex": h16(TX_INDEX_ADDRESS), + "tdr_address": SCI1_TDR_ADDRESS, + "tdr_address_hex": h16(SCI1_TDR_ADDRESS), + "checksum_seed": CHECKSUM_SEED, + "checksum_seed_hex": h16(CHECKSUM_SEED), + "checksum_formula": "checksum = 0x5A ^ byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4", + "confidence": "high", + "confidence_score": 0.95, + "confidence_reason": "all required independent evidence groups were observed", + "required_evidence_count": len(_TX_REQUIRED_EVIDENCE), + "observed_evidence_count": len(_TX_REQUIRED_EVIDENCE), + "missing_evidence": [], + "evidence_addresses": evidence_addresses, + "evidence_addresses_hex": { + key: [h16(address) for address in addresses] + for key, addresses in evidence_addresses.items() + }, + "evidence": [evidence_by_key[key] for key in _TX_REQUIRED_EVIDENCE], + "short_comment": ( + f"candidate/evidence-supported SCI1 {TX_FRAME_LENGTH}-byte TX frame; " + f"{h16(TX_BUFFER_START)}-{h16(TX_BUFFER_END)}, checksum {h16(TX_CHECKSUM_ADDRESS)} " + f"seeded by {h16(CHECKSUM_SEED)}" + ), + "comment": ( + f"candidate/evidence-supported SCI1 {TX_FRAME_LENGTH}-byte TX frame hypothesis " + f"using buffer {h16(TX_BUFFER_START)}-{h16(TX_BUFFER_END)} with checksum byte " + f"{h16(TX_CHECKSUM_ADDRESS)} seeded by {h16(CHECKSUM_SEED)}" + ), + } + return candidate + + +def _rx_candidate_from_evidence(evidence: list[dict[str, object]]) -> dict[str, object] | None: + evidence_by_key = {str(item["kind"]): item for item in evidence} + missing = [key for key in _RX_REQUIRED_EVIDENCE if key not in evidence_by_key] + if missing: + return None + + evidence_addresses = { + key: list(evidence_by_key[key]["addresses"]) + for key in _RX_REQUIRED_EVIDENCE + } + return { + "id": "sci1_rx_frame_f868_len6_candidate", + "kind": "candidate_sci1_rx_frame", + "channel": "SCI1", + "frame_length": RX_FRAME_LENGTH, + "capture_buffer_start": RX_CAPTURE_START, + "capture_buffer_start_hex": h16(RX_CAPTURE_START), + "capture_buffer_end": RX_CAPTURE_END, + "capture_buffer_end_hex": h16(RX_CAPTURE_END), + "validation_buffer_start": RX_FRAME_START, + "validation_buffer_start_hex": h16(RX_FRAME_START), + "validation_buffer_end": RX_FRAME_END, + "validation_buffer_end_hex": h16(RX_FRAME_END), + "checksum_address": RX_CHECKSUM_ADDRESS, + "checksum_address_hex": h16(RX_CHECKSUM_ADDRESS), + "rx_index_address": RX_INDEX_ADDRESS, + "rx_index_address_hex": h16(RX_INDEX_ADDRESS), + "rdr_address": SCI1_RDR_ADDRESS, + "rdr_address_hex": h16(SCI1_RDR_ADDRESS), + "interbyte_timeout_address": RX_INTERBYTE_TIMEOUT_ADDRESS, + "interbyte_timeout_address_hex": h16(RX_INTERBYTE_TIMEOUT_ADDRESS), + "complete_timer_address": RX_COMPLETE_TIMER_ADDRESS, + "complete_timer_address_hex": h16(RX_COMPLETE_TIMER_ADDRESS), + "checksum_seed": CHECKSUM_SEED, + "checksum_seed_hex": h16(CHECKSUM_SEED), + "checksum_formula": "checksum = 0x5A ^ byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4", + "confidence": "high", + "confidence_score": 0.9, + "confidence_reason": ( + "RX count, copy, and checksum-validation evidence were observed; no explicit header/sync byte was identified" + ), + "caveat": "candidate frame means six consecutive bytes within the observed RX timing/state machine, not a proven delimited packet", + "required_evidence_count": len(_RX_REQUIRED_EVIDENCE), + "observed_evidence_count": len(_RX_REQUIRED_EVIDENCE), + "missing_evidence": [], + "evidence_addresses": evidence_addresses, + "evidence_addresses_hex": { + key: [h16(address) for address in addresses] + for key, addresses in evidence_addresses.items() + }, + "evidence": [evidence_by_key[key] for key in _RX_REQUIRED_EVIDENCE], + "short_comment": ( + f"candidate/evidence-supported SCI1 {RX_FRAME_LENGTH}-byte RX frame; " + f"capture {h16(RX_CAPTURE_START)}-{h16(RX_CAPTURE_END)}, validate " + f"{h16(RX_FRAME_START)}-{h16(RX_FRAME_END)}, checksum {h16(RX_CHECKSUM_ADDRESS)} " + f"seeded by {h16(CHECKSUM_SEED)}" + ), + "comment": ( + f"candidate/evidence-supported SCI1 {RX_FRAME_LENGTH}-byte RX frame hypothesis " + f"using capture buffer {h16(RX_CAPTURE_START)}-{h16(RX_CAPTURE_END)}; " + f"checksum byte {h16(RX_CHECKSUM_ADDRESS)} is validated against XOR seeded by {h16(CHECKSUM_SEED)}" + ), + } + + +def _comment_for_evidence(candidate: Mapping[str, object], item: Mapping[str, object]) -> str: + base = str(candidate.get("short_comment") or candidate["comment"]) + return ( + f"{base}; evidence: {item['summary']}; " + f"confidence {candidate['confidence']}" + ) + + +def _instruction_metadata( + candidate: Mapping[str, object], + item: Mapping[str, object], + address: int, + comment: str, +) -> dict[str, object]: + return { + "address": address, + "action": "serial_reconstruction_evidence", + "candidate_id": candidate["id"], + "candidate_kind": candidate["kind"], + "evidence": item["kind"], + "evidence_summary": item["summary"], + "evidence_addresses": list(item["addresses"]), + "evidence_addresses_hex": list(item["addresses_hex"]), + "confidence": candidate["confidence"], + "confidence_score": candidate["confidence_score"], + "comment": comment, + } + + +def _buffer_region_references(ordered: list[Instruction]) -> list[Instruction]: + return [ins for ins in ordered if _buffer_refs(ins)] + + +def _buffer_refs(ins: Instruction) -> list[int]: + return sorted({ref for ref in ins.references if TX_BUFFER_START <= ref <= TX_BUFFER_END}) + + +def _xor_checksum_chain( + ordered: list[Instruction], + checksum_writes: list[Instruction], +) -> list[Instruction]: + for checksum_write in checksum_writes: + index = ordered.index(checksum_write) + window = ordered[max(0, index - 16) : index] + xors = [ + ins + for ins in window + if _mnemonic_root(ins.mnemonic) == "XOR" + and any(TX_BUFFER_START <= ref <= _BUFFER_DATA_END for ref in ins.references) + ] + if len(xors) >= 2: + return xors + [checksum_write] + return [] + + +def _checksum_seed_before_xor(ordered: list[Instruction], start: int, end: int) -> list[Instruction]: + for index, ins in enumerate(ordered): + if ( + _mnemonic_root(ins.mnemonic) == "XOR" + and any(start <= ref <= end for ref in ins.references) + ): + for candidate in reversed(ordered[max(0, index - 6) : index]): + if _immediate_source_value(candidate.operands) == CHECKSUM_SEED: + return [candidate] + return [] + + +def _initial_send_from_buffer_start(ordered: list[Instruction]) -> list[Instruction]: + for index, ins in enumerate(ordered): + if not _is_sci1_tdr_write(ins): + continue + source, _destination = _source_destination_operands(ins.operands) + if _operand_mentions_address(source, TX_BUFFER_START) and not _is_indexed_operand(source): + return [ins] + for candidate in reversed(ordered[max(0, index - 3) : index]): + if _is_nonindexed_read_from_buffer_start(candidate): + return [candidate, ins] + return [] + + +def _indexed_tx_isr_sequence(ordered: list[Instruction]) -> dict[str, list[Instruction]] | None: + for index, ins in enumerate(ordered): + if not _is_sci1_tdr_write(ins): + continue + + prior = ordered[max(0, index - 6) : index] + indexed_reads = [candidate for candidate in prior if _is_indexed_buffer_read(candidate)] + if not indexed_reads and _is_indexed_buffer_read(ins): + indexed_reads = [ins] + if not indexed_reads: + continue + index_reads = [candidate for candidate in prior if _is_read_from_address(candidate, TX_INDEX_ADDRESS)] + if not index_reads: + continue + + after = ordered[index + 1 : index + 9] + increments = [candidate for candidate in after if _is_index_increment(candidate)] + compares = [candidate for candidate in after if _is_compare_index_to_frame_length(candidate)] + if not increments or not compares: + continue + if increments[0].address > compares[0].address: + continue + + send = _dedupe_instructions([index_reads[-1], indexed_reads[-1], ins]) + return { + "send": send, + "increment": [increments[0]], + "compare": [compares[0]], + } + return None + + +def _is_index_initialized_to_one(ins: Instruction) -> bool: + return ( + _mnemonic_root(ins.mnemonic) in {"MOV:G", "MOV:S"} + and _is_write_to_address(ins, TX_INDEX_ADDRESS) + and _immediate_source_value(ins.operands) == 1 + ) + + +def _is_index_increment(ins: Instruction) -> bool: + if not _is_write_to_address(ins, TX_INDEX_ADDRESS): + return False + root = _mnemonic_root(ins.mnemonic) + if root in {"ADD:Q", "ADD:G", "ADDS"}: + return _immediate_source_value(ins.operands) == 1 + return root in {"INC", "INC:G"} + + +def _is_compare_index_to_frame_length(ins: Instruction) -> bool: + return ( + _mnemonic_root(ins.mnemonic) in {"CMP", "CMP:E", "CMP:G", "CMP:I"} + and TX_INDEX_ADDRESS in ins.references + and _immediate_source_value(ins.operands) == TX_FRAME_LENGTH + ) + + +def _is_sci1_tdr_write(ins: Instruction) -> bool: + return _is_write_to_address(ins, SCI1_TDR_ADDRESS) + + +def _is_nonindexed_read_from_buffer_start(ins: Instruction) -> bool: + return ( + _is_read_from_address(ins, TX_BUFFER_START) + and not _is_indexed_operand(_source_destination_operands(ins.operands)[0]) + ) + + +def _is_indexed_buffer_read(ins: Instruction) -> bool: + source, _destination = _source_destination_operands(ins.operands) + return ( + (_is_read_from_address(ins, TX_BUFFER_START) or _operand_mentions_address(source, TX_BUFFER_START)) + and _is_indexed_operand(source) + ) + + +def _is_indexed_capture_store(ins: Instruction) -> bool: + _source, destination = _source_destination_operands(ins.operands) + return ( + _access_direction(ins, RX_CAPTURE_START) == "write" + and _operand_mentions_address(destination, RX_CAPTURE_START) + and _is_indexed_operand(destination) + ) + + +def _rx_index_increment_store(ordered: list[Instruction]) -> list[Instruction]: + for index, ins in enumerate(ordered): + if _is_write_to_address(ins, RX_INDEX_ADDRESS): + window = ordered[max(0, index - 4) : index + 1] + increments = [ + candidate + for candidate in window + if _mnemonic_root(candidate.mnemonic) in {"ADD:Q", "ADD:G", "ADDS", "INC", "INC:G"} + and _destination_operand(candidate.operands).upper() in {"R1", "R1L"} + and (_immediate_source_value(candidate.operands) in {None, 1}) + ] + if increments: + return [increments[-1], ins] + return [] + + +def _rx_copy_capture_to_frame_buffer(ordered: list[Instruction]) -> list[Instruction]: + copies: list[Instruction] = [] + capture_reads = [ + ins for ins in ordered if any(RX_CAPTURE_START <= ref <= RX_CAPTURE_END for ref in ins.references) + ] + frame_writes = [ + ins for ins in ordered if any(RX_FRAME_START <= ref <= RX_FRAME_END for ref in ins.references) + ] + if len(capture_reads) >= 3 and len(frame_writes) >= 3: + copies.extend(capture_reads[:3]) + copies.extend(frame_writes[:3]) + return _dedupe_instructions(copies) + + +def _rx_xor_checksum_validation(ordered: list[Instruction]) -> list[Instruction]: + for index, ins in enumerate(ordered): + if ( + _mnemonic_root(ins.mnemonic) in {"CMP", "CMP:E", "CMP:G", "CMP:I"} + and RX_CHECKSUM_ADDRESS in ins.references + ): + window = ordered[max(0, index - 16) : index] + xors = [ + candidate + for candidate in window + if _mnemonic_root(candidate.mnemonic) == "XOR" + and any(RX_FRAME_START <= ref <= RX_CHECKSUM_ADDRESS - 1 for ref in candidate.references) + ] + seed = [ + candidate + for candidate in window + if _immediate_source_value(candidate.operands) == CHECKSUM_SEED + ] + if len(xors) >= 5 and seed: + return [seed[-1], *xors, ins] + return [] + + +def _is_read_from_address(ins: Instruction, address: int) -> bool: + source, destination = _source_destination_operands(ins.operands) + if _operand_mentions_address(source, address): + return True + if address not in ins.references: + return False + if source.startswith("@") and not _operand_mentions_any_reference(destination, ins.references): + return True + return _access_direction(ins, address) == "read" + + +def _is_write_to_address(ins: Instruction, address: int) -> bool: + _source, destination = _source_destination_operands(ins.operands) + if _operand_mentions_address(destination, address): + return _access_direction(ins, address) == "write" + if address not in ins.references: + return False + return _access_direction(ins, address) == "write" + + +def _access_direction(ins: Instruction, address: int) -> str | None: + root = _mnemonic_root(ins.mnemonic) + if root in {"BTST", "CMP", "CMP:E", "CMP:G", "CMP:I", "MOVFPE", "TST"}: + return "read" + if root in {"BCLR", "BNOT", "BSET", "CLR", "INC", "INC:G", "NEG", "NOT"}: + return "write" + if root in {"ADD:Q", "ADD:G", "ADDS", "ADDX", "AND", "OR", "SUB", "SUBS", "SUBX", "XOR"}: + return "write" + if root in {"MOV:G", "MOV:S", "MOVTPE"}: + source, destination = _source_destination_operands(ins.operands) + if _operand_mentions_address(destination, address): + return "write" + if _operand_mentions_address(source, address): + return "read" + if address in ins.references: + if destination.startswith("@") and not _operand_mentions_any_reference(source, ins.references): + return "write" + if source.startswith("@") and not _operand_mentions_any_reference(destination, ins.references): + return "read" + if root in {"MOV:L", "MOV:F"}: + return "read" + if root == "STC": + return "write" + if root == "LDC": + return "read" + return None + + +def _evidence( + kind: str, + instructions: list[Instruction], + *, + summary: str, + **extra: object, +) -> dict[str, object]: + addresses = [ins.address for ins in _dedupe_instructions(instructions)] + item: dict[str, object] = { + "kind": kind, + "summary": summary, + "addresses": addresses, + "addresses_hex": [h16(address) for address in addresses], + "instructions": [ins.text for ins in _dedupe_instructions(instructions)], + } + item.update(extra) + if "distinct_buffer_addresses" in item and isinstance(item["distinct_buffer_addresses"], list): + item["distinct_buffer_addresses_hex"] = [ + h16(address) + for address in item["distinct_buffer_addresses"] + if isinstance(address, int) + ] + return item + + +def _dedupe_instructions(instructions: list[Instruction]) -> list[Instruction]: + output: list[Instruction] = [] + seen: set[int] = set() + for ins in instructions: + if ins.address in seen: + continue + seen.add(ins.address) + output.append(ins) + return output + + +def _instruction_sequence( + instructions: Mapping[int, Instruction] | Iterable[Instruction], +) -> list[Instruction]: + values = instructions.values() if isinstance(instructions, Mapping) else instructions + return sorted(values, key=lambda ins: ins.address) + + +def _source_destination_operands(operands: str) -> tuple[str, str]: + depth = 0 + split_at: int | None = None + for index, char in enumerate(operands): + if char in "({": + depth += 1 + elif char in ")}" and depth: + depth -= 1 + elif char == "," and depth == 0: + split_at = index + if split_at is None: + operand = operands.strip() + return "", operand + return operands[:split_at].strip(), operands[split_at + 1 :].strip() + + +def _destination_operand(operands: str) -> str: + return _source_destination_operands(operands)[1] + + +def _immediate_source_value(operands: str) -> int | None: + source, _destination = _source_destination_operands(operands) + if not source.startswith("#"): + return None + try: + return parse_int(source[1:]) & 0xFFFF + except ValueError: + return None + + +def _operand_mentions_any_reference(operand: str, references: list[int]) -> bool: + return any(_operand_mentions_address(operand, address) for address in references) + + +def _operand_mentions_address(operand: str, address: int) -> bool: + operand_upper = operand.upper().replace(" ", "") + names = { + SCI1_TDR_ADDRESS: ("SCI1_TDR",), + TX_BUFFER_START: ("TX_BUFFER",), + TX_CHECKSUM_ADDRESS: ("TX_CHECKSUM",), + TX_INDEX_ADDRESS: ("TX_INDEX",), + } + if any(name in operand_upper for name in names.get(address, ())): + return True + negative = (0x10000 - address) & 0xFFFF + return ( + f"H'{address:04X}" in operand_upper + or f"0X{address:04X}" in operand_upper + or f"${address:04X}" in operand_upper + or f"-H'{negative:04X}" in operand_upper + or f"-0X{negative:04X}" in operand_upper + or f"-${negative:04X}" in operand_upper + ) + + +def _is_indexed_operand(operand: str) -> bool: + operand_upper = operand.upper().replace(" ", "") + return operand_upper.startswith("@(") and ",R" in operand_upper + + +def _mnemonic_root(mnemonic: str) -> str: + return mnemonic.rsplit(".", 1)[0].upper() diff --git a/tests/test_serial_reconstruction.py b/tests/test_serial_reconstruction.py new file mode 100644 index 0000000..c60f8ed --- /dev/null +++ b/tests/test_serial_reconstruction.py @@ -0,0 +1,142 @@ +import json +import unittest + +from h8536.model import Instruction +from h8536.serial_reconstruction import ( + analyze_serial_reconstruction, + serial_reconstruction_comment_for_instruction, + serial_reconstruction_json_payload, + serial_reconstruction_metadata_for_instruction, +) + + +def ins( + address: int, + mnemonic: str, + operands: str = "", + references: list[int] | None = None, + kind: str = "normal", + targets: list[int] | None = None, +) -> Instruction: + return Instruction( + address, + b"", + mnemonic, + operands, + kind=kind, + targets=targets or [], + references=references or [], + ) + + +class SerialReconstructionTest(unittest.TestCase): + def test_candidate_sci1_tx_frame_length_and_checksum_pattern(self): + instructions = { + 0x3000: ins(0x3000, "MOV:G.B", "#H'02, @H'F858", [0xF858]), + 0x3004: ins(0x3004, "MOV:G.B", "@H'F858, R0", [0xF858]), + 0x3008: ins(0x3008, "MOV:G.B", "R0, @SCI1_TDR", [0xFEDB]), + 0x300C: ins(0x300C, "MOV:G.B", "#1, @H'F9C2", [0xF9C2]), + 0x301C: ins(0x301C, "MOV:E.B", "#H'5A, R1", []), + 0x3020: ins(0x3020, "XOR.B", "@H'F858, R1", [0xF858]), + 0x3024: ins(0x3024, "XOR.B", "@H'F859, R1", [0xF859]), + 0x3028: ins(0x3028, "XOR.B", "@H'F85A, R1", [0xF85A]), + 0x302C: ins(0x302C, "XOR.B", "@H'F85B, R1", [0xF85B]), + 0x3030: ins(0x3030, "XOR.B", "@H'F85C, R1", [0xF85C]), + 0x3034: ins(0x3034, "MOV:G.B", "R1, @H'F85D", [0xF85D]), + 0x3100: ins(0x3100, "MOV:G.B", "@H'F9C2, R2", [0xF9C2]), + 0x3104: ins(0x3104, "MOV:G.B", "@(-H'07A8,R2), R0", []), + 0x3108: ins(0x3108, "MOV:G.B", "R0, @SCI1_TDR", [0xFEDB]), + 0x310C: ins(0x310C, "ADD:Q.B", "#1, @H'F9C2", [0xF9C2]), + 0x3110: ins(0x3110, "CMP:G.B", "#6, @H'F9C2", [0xF9C2]), + } + + analysis = analyze_serial_reconstruction(instructions) + + self.assertEqual(len(analysis["candidates"]), 1) + candidate = analysis["candidates"][0] + self.assertEqual(candidate["kind"], "candidate_sci1_tx_frame") + self.assertEqual(candidate["channel"], "SCI1") + self.assertEqual(candidate["frame_length"], 6) + self.assertEqual(candidate["buffer_start"], 0xF858) + self.assertEqual(candidate["checksum_address"], 0xF85D) + self.assertEqual(candidate["tx_index_address"], 0xF9C2) + self.assertEqual(candidate["checksum_seed"], 0x5A) + self.assertEqual(candidate["confidence"], "high") + self.assertEqual(candidate["confidence_score"], 0.95) + self.assertEqual(candidate["missing_evidence"], []) + + evidence_addresses = candidate["evidence_addresses"] + self.assertIn(0x3034, evidence_addresses["checksum_byte"]) + self.assertIn(0x3034, evidence_addresses["xor_checksum_chain"]) + self.assertIn(0x3108, evidence_addresses["tx_isr_indexed_send"]) + self.assertEqual(evidence_addresses["tx_index_compare_frame_length"], [0x3110]) + self.assertEqual(evidence_addresses["tx_checksum_seed"], [0x301C]) + + checksum_comment = serial_reconstruction_comment_for_instruction(analysis, 0x3034) + self.assertIn("candidate/evidence-supported SCI1 6-byte TX frame", checksum_comment) + self.assertIn("checksum H'F85D", checksum_comment) + self.assertIn("confidence high", checksum_comment) + + metadata = serial_reconstruction_metadata_for_instruction(analysis, 0x3108) + self.assertEqual(metadata[0]["candidate_id"], "sci1_tx_frame_f858_len6_candidate") + self.assertEqual(metadata[0]["evidence"], "tx_isr_indexed_send") + self.assertIn(0x3108, metadata[0]["evidence_addresses"]) + + payload = serial_reconstruction_json_payload(analysis) + self.assertEqual(payload["candidates"][0]["frame_length"], 6) + json.dumps(payload) + + def test_candidate_sci1_rx_frame_length_and_checksum_validation_pattern(self): + instructions = { + 0x5000: ins(0x5000, "MOV:G.B", "@SCI1_RDR, R0", [0xFEDD]), + 0x5004: ins(0x5004, "MOV:G.B", "R0, @(-H'0798,R1)", []), + 0x5008: ins(0x5008, "ADD:Q.B", "#1, R1", []), + 0x500C: ins(0x500C, "MOV:G.B", "R1, @H'F9C3", [0xF9C3]), + 0x5010: ins(0x5010, "CMP:E", "#H'06, R1", []), + 0x5014: ins(0x5014, "MOV:G.B", "#H'14, @H'F9C5", [0xF9C5]), + 0x5100: ins(0x5100, "CMP:G.B", "#H'06, @H'F9C3", [0xF9C3]), + 0x5104: ins(0x5104, "MOV:G.W", "@H'F868, R0", [0xF868]), + 0x5108: ins(0x5108, "MOV:G.W", "R0, @H'F860", [0xF860]), + 0x510C: ins(0x510C, "MOV:G.W", "@H'F86A, R0", [0xF86A]), + 0x5110: ins(0x5110, "MOV:G.W", "R0, @H'F862", [0xF862]), + 0x5114: ins(0x5114, "MOV:G.W", "@H'F86C, R0", [0xF86C]), + 0x5118: ins(0x5118, "MOV:G.W", "R0, @H'F864", [0xF864]), + 0x5120: ins(0x5120, "MOV:E.B", "#H'5A, R0", []), + 0x5124: ins(0x5124, "XOR.B", "@H'F860, R0", [0xF860]), + 0x5128: ins(0x5128, "XOR.B", "@H'F861, R0", [0xF861]), + 0x512C: ins(0x512C, "XOR.B", "@H'F862, R0", [0xF862]), + 0x5130: ins(0x5130, "XOR.B", "@H'F863, R0", [0xF863]), + 0x5134: ins(0x5134, "XOR.B", "@H'F864, R0", [0xF864]), + 0x5138: ins(0x5138, "CMP:G.B", "@H'F865, R0", [0xF865]), + } + + analysis = analyze_serial_reconstruction(instructions) + + candidate = next(item for item in analysis["candidates"] if item["kind"] == "candidate_sci1_rx_frame") + self.assertEqual(candidate["frame_length"], 6) + self.assertEqual(candidate["capture_buffer_start"], 0xF868) + self.assertEqual(candidate["validation_buffer_start"], 0xF860) + self.assertEqual(candidate["checksum_address"], 0xF865) + self.assertEqual(candidate["checksum_seed"], 0x5A) + self.assertIn("no explicit header", candidate["confidence_reason"]) + + comment = serial_reconstruction_comment_for_instruction(analysis, 0x5138) + self.assertIn("candidate/evidence-supported SCI1 6-byte RX frame", comment) + self.assertIn("checksum H'F865", comment) + self.assertIn("confidence high", comment) + + def test_lone_tdr_write_does_not_emit_reconstruction(self): + instructions = { + 0x4000: ins(0x4000, "MOV:G.B", "R0, @SCI1_TDR", [0xFEDB]), + } + + analysis = analyze_serial_reconstruction(instructions) + + self.assertEqual(analysis["candidates"], []) + self.assertEqual(serial_reconstruction_comment_for_instruction(analysis, 0x4000), "") + self.assertEqual(serial_reconstruction_metadata_for_instruction(analysis, 0x4000), []) + self.assertEqual(serial_reconstruction_json_payload(analysis)["candidates"], []) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_serial_reconstruction_integration.py b/tests/test_serial_reconstruction_integration.py new file mode 100644 index 0000000..f4dc60a --- /dev/null +++ b/tests/test_serial_reconstruction_integration.py @@ -0,0 +1,69 @@ +import json +import tempfile +import unittest +from pathlib import Path + +from h8536.model import Instruction +from h8536.pseudocode import PseudocodeOptions, generate_pseudocode +from h8536.render import format_listing, write_json +from h8536.rom import Rom +from h8536.serial_reconstruction import analyze_serial_reconstruction + + +def ins(address: int, mnemonic: str, operands: str = "", references: list[int] | None = None) -> Instruction: + return Instruction(address, b"", mnemonic, operands, references=references or []) + + +class SerialReconstructionIntegrationTest(unittest.TestCase): + def test_listing_json_and_pseudocode_include_candidate_frame_reconstruction(self): + instructions = { + 0x3000: ins(0x3000, "MOV:G.B", "@H'F858, R0", [0xF858]), + 0x3004: ins(0x3004, "MOV:G.B", "R0, @SCI1_TDR", [0xFEDB]), + 0x3008: ins(0x3008, "MOV:G.B", "#1, @H'F9C2", [0xF9C2]), + 0x3010: ins(0x3010, "MOV:E.B", "#H'5A, R0", []), + 0x3014: ins(0x3014, "XOR.B", "@H'F858, R0", [0xF858]), + 0x3018: ins(0x3018, "XOR.B", "@H'F859, R0", [0xF859]), + 0x301C: ins(0x301C, "XOR.B", "@H'F85A, R0", [0xF85A]), + 0x3020: ins(0x3020, "XOR.B", "@H'F85B, R0", [0xF85B]), + 0x3024: ins(0x3024, "XOR.B", "@H'F85C, R0", [0xF85C]), + 0x3028: ins(0x3028, "MOV:G.B", "R0, @H'F85D", [0xF85D]), + 0x3030: ins(0x3030, "MOV:G.B", "@H'F9C2, R1", [0xF9C2]), + 0x3034: ins(0x3034, "MOV:G.B", "@(-H'07A8,R1), R0", []), + 0x3038: ins(0x3038, "MOV:G.B", "R0, @SCI1_TDR", [0xFEDB]), + 0x303C: ins(0x303C, "ADD:Q.B", "#1, @H'F9C2", [0xF9C2]), + 0x3040: ins(0x3040, "CMP:G.B", "#6, @H'F9C2", [0xF9C2]), + } + analysis = analyze_serial_reconstruction(instructions) + + listing = format_listing( + Path("rom.bin"), + Rom(b"\xFF" * 0x20), + instructions, + {}, + {}, + "min", + traced=False, + serial_reconstruction=analysis, + ) + self.assertIn("; Serial Protocol Reconstruction", listing) + self.assertIn("TX candidate: 6 bytes", listing) + self.assertIn("candidate/evidence-supported SCI1 6-byte TX frame", listing) + + with tempfile.TemporaryDirectory() as tmp: + path = Path(tmp) / "out.json" + write_json(path, instructions, {}, {}, serial_reconstruction=analysis) + payload = json.loads(path.read_text(encoding="utf-8")) + + self.assertEqual(payload["serial_reconstruction"]["candidates"][0]["frame_length"], 6) + tdr_instruction = next(item for item in payload["instructions"] if item["address"] == 0x3038) + self.assertIn("serial_reconstruction", tdr_instruction) + + pseudocode = generate_pseudocode( + payload, + options=PseudocodeOptions(include_addresses=False, include_asm=False, structured=False), + ) + self.assertIn("candidate/evidence-supported SCI1 6-byte TX frame", pseudocode) + + +if __name__ == "__main__": + unittest.main()