serial reconstruction
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"]))
|
||||
|
||||
@@ -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
|
||||
|
||||
863
h8536/serial_reconstruction.py
Normal file
863
h8536/serial_reconstruction.py
Normal file
@@ -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()
|
||||
142
tests/test_serial_reconstruction.py
Normal file
142
tests/test_serial_reconstruction.py
Normal file
@@ -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()
|
||||
69
tests/test_serial_reconstruction_integration.py
Normal file
69
tests/test_serial_reconstruction_integration.py
Normal file
@@ -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()
|
||||
Reference in New Issue
Block a user