From d2e7609bbf9280faaddfa2bdab48b6674eda100f Mon Sep 17 00:00:00 2001 From: Aiden <68633820+awils27@users.noreply.github.com> Date: Mon, 25 May 2026 19:11:22 +1000 Subject: [PATCH] Emulator learnings folded back into decompiler --- build/rom_decompiled.asm | 41 +- build/rom_decompiled.json | 579 +++++++++++++++++- build/rom_pseudocode.c | 36 +- build/rom_serial_gate.json | 165 +++++ build/rom_serial_gate.txt | 15 + build/rom_serial_pseudocode.c | 40 +- h8536/render.py | 16 + h8536/sci_protocol.py | 30 +- h8536/serial_gate.py | 80 +++ h8536/serial_pseudocode.py | 135 +++- h8536/serial_reconstruction.py | 228 ++++++- tests/test_sci_protocol.py | 49 +- tests/test_serial_gate.py | 34 + tests/test_serial_pseudocode.py | 45 ++ tests/test_serial_reconstruction.py | 46 ++ .../test_serial_reconstruction_integration.py | 16 + 16 files changed, 1468 insertions(+), 87 deletions(-) diff --git a/build/rom_decompiled.asm b/build/rom_decompiled.asm index 27d8ad2..13ac83a 100644 --- a/build/rom_decompiled.asm +++ b/build/rom_decompiled.asm @@ -232,8 +232,13 @@ ; Serial Protocol Reconstruction ; TX candidate: 6 bytes H'F858-H'F85D, checksum H'F85D seeded by H'005A (confidence high 0.95) +; TX path: initial byte is written from the TX frame buffer, then subsequent bytes are sent by the TXI path when TDRE is reasserted ; 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 +; Serial RAM role candidates +; H'F9C0: post_tx_report_delay - post_tx_report_delay at H'F9C0 is a candidate/evidence-supported RAM timer role; FRT1 OCIA tick ISR H'BEEA decrements it +; H'F9C1: secondary_tx_report_delay - secondary_tx_report_delay at H'F9C1 is a candidate/evidence-supported RAM timer role; FRT1 OCIA tick ISR H'BEEA decrements it +; H'F9C6: periodic_report_countdown - periodic_report_countdown at H'F9C6 is a candidate/evidence-supported RAM timer role; FRT1 OCIA tick ISR H'BEEA decrements it ; LCD/Text Scan ; search 'CONNECT': not literal, hits=0 @@ -430,10 +435,10 @@ vec_reset_1000: 108B: 15 FE C8 06 3B MOV:G.B #H'3B, @PWM3_TCR ; PWM3_TCR = H'3B (OE=0 OS=0 CKS2=0 CKS1=1 CKS0=1); cycles=9 1090: 15 FE C9 06 7D MOV:G.B #H'7D, @PWM3_DTR ; PWM3_DTR = H'7D; cycles=9 1095: 15 FE D8 06 24 MOV:G.B #H'24, @SCI1_SMR ; SCI1_SMR = H'24 (C/A=0 CHR=0 PE=1 O/E=0 STOP=0 CKS1=0 CKS0=0; SCI async, 8-bit, even parity, 1 stop, clock phi); SCI1 SMR serial init for traced RS232/MAX202 path (H8 pin 66 P95/TXD to MAX202 pin 11; MAX202 pin 12 to H8 pin 67 P96/RXD); cycles=9 -109A: 15 FE DA 06 3C MOV:G.B #H'3C, @SCI1_SCR ; SCI1_SCR = H'3C (TIE=0 RIE=0 TE=1 RE=1 CKE1=0 CKE0=0; SCI enables TX,RX, internal clock); disable SCI1 TX interrupt (TIE); disable SCI1 receive and receive-error interrupts (RIE); enable SCI1 transmitter (TE); enable SCI1 receiver (RE); 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 +109A: 15 FE DA 06 3C MOV:G.B #H'3C, @SCI1_SCR ; SCI1_SCR = H'3C (TIE=0 RIE=0 TE=1 RE=1 CKE1=0 CKE0=0; SCI enables TX,RX, internal clock); disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE; disable SCI1 receive and receive-error interrupts (RIE); enable SCI1 transmitter (TE); enable SCI1 receiver (RE); 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 109F: 15 FE D9 06 07 MOV:G.B #H'07, @SCI1_BRR ; SCI1_BRR = H'07; SCI1 async 8-bit even parity 1 stop BRR N=7 CKS n=0; baud needs --clock-hz; SCI1 BRR serial init for traced RS232/MAX202 path (H8 pin 66 P95/TXD to MAX202 pin 11; MAX202 pin 12 to H8 pin 67 P96/RXD); cycles=9 10A4: 15 FE F0 06 24 MOV:G.B #H'24, @SCI2_SMR ; SCI2_SMR = H'24 (C/A=0 CHR=0 PE=1 O/E=0 STOP=0 CKS1=0 CKS0=0; SCI async, 8-bit, even parity, 1 stop, clock phi); SCI2 SMR write; not the traced MAX202 path; P9SCI2E=0 disables SCI2 pins P92/P93/P94, while the board trace is SCI1 P95/P96; cycles=9 -10A9: 15 FE F2 06 0C MOV:G.B #H'0C, @SCI2_SCR ; SCI2_SCR = H'0C (TIE=0 RIE=0 TE=0 RE=0 CKE1=0 CKE0=0; SCI enables none, internal clock); disable SCI2 TX interrupt (TIE); disable SCI2 receive and receive-error interrupts (RIE); disable SCI2 transmitter (TE); disable SCI2 receiver (RE); SCI2 SCR write; not the traced MAX202 path; P9SCI2E=0 disables SCI2 pins P92/P93/P94, while the board trace is SCI1 P95/P96; cycles=9 +10A9: 15 FE F2 06 0C MOV:G.B #H'0C, @SCI2_SCR ; SCI2_SCR = H'0C (TIE=0 RIE=0 TE=0 RE=0 CKE1=0 CKE0=0; SCI enables none, internal clock); disable SCI2 TX interrupt (TIE); gates TXI when hardware sets TDRE; disable SCI2 receive and receive-error interrupts (RIE); disable SCI2 transmitter (TE); disable SCI2 receiver (RE); SCI2 SCR write; not the traced MAX202 path; P9SCI2E=0 disables SCI2 pins P92/P93/P94, while the board trace is SCI1 P95/P96; cycles=9 10AE: 15 FE F1 06 07 MOV:G.B #H'07, @SCI2_BRR ; SCI2_BRR = H'07; SCI2 async 8-bit even parity 1 stop BRR N=7 CKS n=0; baud needs --clock-hz; SCI2 BRR write; not the traced MAX202 path; P9SCI2E=0 disables SCI2 pins P92/P93/P94, while the board trace is SCI1 P95/P96; cycles=9 10B3: 15 FE E8 06 19 MOV:G.B #H'19, @ADCSR ; ADCSR = H'19 (ADF=0 ADIE=0 ADST=0 SCAN=1 CKS=1 CH2=0 CH1=0 CH0=1; A/D halt, scan AN0-AN1, 138-state max, ADI disabled); cycles=9 10B8: 15 FE E9 06 7F MOV:G.B #H'7F, @H'FEE9 ; refs H'FEE9 in register_field; cycles=9 @@ -3041,8 +3046,8 @@ BA6C: 27 FA BEQ loc_BA68 ; repeat SCI1 transmit-empty wait while TDRE=0 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 +BA7B: 15 FE DC D7 BCLR.B #7, @SCI1_SSR ; clear TDRE (bit 7) of SCI1_SSR; clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts 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); gates TXI when hardware sets TDRE; 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 vec_sci1_txi_BA84: @@ -3054,7 +3059,7 @@ BA90: 15 F9 C3 16 TST.B @H'F9C3 ; refs ram_F9C3 in on_chip_ram; cycles=7 BA94: 27 13 BEQ loc_BAA9 ; cycles=3/7 nt/t BA96: 15 FA A2 D3 BCLR.B #3, @H'FAA2 ; refs ram_FAA2 in on_chip_ram; cycles=9 BA9A: 15 FA A3 13 CLR.B @H'FAA3 ; refs ram_FAA3 in on_chip_ram; cycles=9 -BA9E: 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 +BA9E: 15 FE DA D7 BCLR.B #7, @SCI1_SCR ; clear TIE (bit 7) of SCI1_SCR; disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE; 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 BAA2: 15 F9 C0 06 1F MOV:G.B #H'1F, @H'F9C0 ; refs ram_F9C0 in on_chip_ram; cycles=9 BAA7: 20 48 BRA loc_BAF1 ; cycles=8 @@ -3065,11 +3070,11 @@ BAAF: A0 12 EXTU.B R0 ; cycles=3 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 +BABB: 15 FE DC D7 BCLR.B #7, @SCI1_SSR ; clear TDRE (bit 7) of SCI1_SSR; clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts 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 ; 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 +BACA: 15 FE DA D7 BCLR.B #7, @SCI1_SCR ; clear TIE (bit 7) of SCI1_SCR; disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE; 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 BAD2: 26 14 BNE loc_BAE8 ; cycles=3/7 nt/t BAD4: 15 F7 91 F7 BTST.B #7, @H'F791 ; refs ram_F791 in on_chip_ram; cycles=7 @@ -3131,13 +3136,13 @@ BB56: 19 RTS ; cycles=12 vec_sci1_eri_BB57: BB57: 15 FA A4 C7 BSET.B #7, @H'FAA4 ; 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; refs ram_FAA4 in on_chip_ram; cycles=8 -BB5B: 15 FE DC D5 BCLR.B #5, @SCI1_SSR ; clear ORER (bit 5) of SCI1_SSR; clear SCI1 overrun error flag (ORER); 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 -BB5F: 15 FE DC D4 BCLR.B #4, @SCI1_SSR ; clear FER (bit 4) of SCI1_SSR; clear SCI1 framing error flag (FER); 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 -BB63: 15 FE DC D3 BCLR.B #3, @SCI1_SSR ; clear PER (bit 3) of SCI1_SSR; clear SCI1 parity error flag (PER); 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 +BB5B: 15 FE DC D5 BCLR.B #5, @SCI1_SSR ; clear ORER (bit 5) of SCI1_SSR; clear SCI1 ORER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state; 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 +BB5F: 15 FE DC D4 BCLR.B #4, @SCI1_SSR ; clear FER (bit 4) of SCI1_SSR; clear SCI1 FER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state; 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 +BB63: 15 FE DC D3 BCLR.B #3, @SCI1_SSR ; clear PER (bit 3) of SCI1_SSR; clear SCI1 PER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state; 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 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); 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: ROM clears SCI1 SSR.RDRF before reading SCI1_RDR; preserve this observed ordering even though the manual describes the canonical RDR-read then RDRF-clear sequence; 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: SCI1 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; cycles=8 +BB69: 15 FE DC D6 BCLR.B #6, @SCI1_SSR ; clear RDRF (bit 6) of SCI1_SSR; clear SCI1 RDRF with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state; 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: ROM clears SCI1 SSR.RDRF before reading SCI1_RDR; preserve this observed ordering even though the manual describes the canonical RDR-read then RDRF-clear sequence; 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: SCI1 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; 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; 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; 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: ROM clears SCI1 SSR.RDRF before reading SCI1_RDR; preserve this observed ordering even though the manual describes the canonical RDR-read then RDRF-clear sequence; 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: SCI1 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; 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 @@ -3495,20 +3500,20 @@ loc_BEE8: BEE8: 19 RTS ; cycles=12 vec_frt1_ocia_BEEA: -BEEA: 15 FE 91 D5 BCLR.B #5, @FRT1_TCSR ; clear OCFA (bit 5) of FRT1_TCSR; cycles=9 -BEEE: 15 F9 C0 16 TST.B @H'F9C0 ; refs ram_F9C0 in on_chip_ram; cycles=7 +BEEA: 15 FE 91 D5 BCLR.B #5, @FRT1_TCSR ; clear OCFA (bit 5) of FRT1_TCSR; candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported; candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported; candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported; cycles=9 +BEEE: 15 F9 C0 16 TST.B @H'F9C0 ; candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C0 in on_chip_ram; cycles=7 BEF2: 27 04 BEQ loc_BEF8 ; cycles=3/7 nt/t -BEF4: 15 F9 C0 0C ADD:Q.B #-1, @H'F9C0 ; refs ram_F9C0 in on_chip_ram; cycles=9 +BEF4: 15 F9 C0 0C ADD:Q.B #-1, @H'F9C0 ; candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C0 in on_chip_ram; cycles=9 loc_BEF8: -BEF8: 15 F9 C1 16 TST.B @H'F9C1 ; refs ram_F9C1 in on_chip_ram; cycles=7 +BEF8: 15 F9 C1 16 TST.B @H'F9C1 ; candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C1 in on_chip_ram; cycles=7 BEFC: 27 04 BEQ loc_BF02 ; cycles=3/7 nt/t -BEFE: 15 F9 C1 0C ADD:Q.B #-1, @H'F9C1 ; refs ram_F9C1 in on_chip_ram; cycles=9 +BEFE: 15 F9 C1 0C ADD:Q.B #-1, @H'F9C1 ; candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C1 in on_chip_ram; cycles=9 loc_BF02: -BF02: 1D F9 C6 16 TST.W @H'F9C6 ; refs ram_F9C6 in on_chip_ram; cycles=7 +BF02: 1D F9 C6 16 TST.W @H'F9C6 ; candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C6 in on_chip_ram; cycles=7 BF06: 27 04 BEQ loc_BF0C ; cycles=3/7 nt/t -BF08: 1D F9 C6 0C ADD:Q.W #-1, @H'F9C6 ; refs ram_F9C6 in on_chip_ram; cycles=9 +BF08: 1D F9 C6 0C ADD:Q.W #-1, @H'F9C6 ; candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C6 in on_chip_ram; cycles=9 loc_BF0C: BF0C: 15 F6 F6 F7 BTST.B #7, @H'F6F6 ; refs ram_F6F6 in on_chip_ram; cycles=7 diff --git a/build/rom_decompiled.json b/build/rom_decompiled.json index d3819d1..cb855cd 100644 --- a/build/rom_decompiled.json +++ b/build/rom_decompiled.json @@ -15679,7 +15679,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -15911,7 +15911,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 transmit data register empty flag (TDRE)", + "comment": "clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -15939,7 +15939,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "enable SCI1 TX interrupt (TIE)", + "comment": "enable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -15968,7 +15968,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16022,7 +16022,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 transmit data register empty flag (TDRE)", + "comment": "clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16050,7 +16050,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16079,7 +16079,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 overrun error flag (ORER)", + "comment": "clear SCI1 ORER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16107,7 +16107,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 framing error flag (FER)", + "comment": "clear SCI1 FER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16135,7 +16135,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 parity error flag (PER)", + "comment": "clear SCI1 PER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16163,7 +16163,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 receive-data-full flag (RDRF)", + "comment": "clear SCI1 RDRF with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16220,7 +16220,7 @@ "register": "SCR", "register_address": 65266, "register_address_hex": "H'FEF2", - "comment": "disable SCI2 TX interrupt (TIE)", + "comment": "disable SCI2 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16344,7 +16344,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16464,7 +16464,7 @@ "register": "SCR", "register_address": 65266, "register_address_hex": "H'FEF2", - "comment": "disable SCI2 TX interrupt (TIE)", + "comment": "disable SCI2 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16696,7 +16696,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 transmit data register empty flag (TDRE)", + "comment": "clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16724,7 +16724,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "enable SCI1 TX interrupt (TIE)", + "comment": "enable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16753,7 +16753,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16807,7 +16807,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 transmit data register empty flag (TDRE)", + "comment": "clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16835,7 +16835,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16864,7 +16864,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 overrun error flag (ORER)", + "comment": "clear SCI1 ORER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16892,7 +16892,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 framing error flag (FER)", + "comment": "clear SCI1 FER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16920,7 +16920,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 parity error flag (PER)", + "comment": "clear SCI1 PER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -16948,7 +16948,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 receive-data-full flag (RDRF)", + "comment": "clear SCI1 RDRF with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -17016,6 +17016,39 @@ "checksum_seed": 90, "checksum_seed_hex": "H'005A", "checksum_formula": "checksum = 0x5A ^ byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4", + "roles": [ + { + "name": "tx_frame", + "address": 63576, + "address_hex": "H'F858", + "end_address": 63581, + "end_address_hex": "H'F85D", + "summary": "evidence-supported candidate SCI1 TX frame buffer" + }, + { + "name": "tx_checksum", + "address": 63581, + "address_hex": "H'F85D", + "checksum_seed": 90, + "checksum_seed_hex": "H'005A", + "summary": "evidence-supported candidate SCI1 TX XOR checksum byte" + }, + { + "name": "tx_index", + "address": 63938, + "address_hex": "H'F9C2", + "summary": "evidence-supported candidate SCI1 TX frame index" + } + ], + "tx_path": { + "kind": "interrupt_driven_txi", + "initial_tdr_write_address": 47730, + "initial_tdr_write_address_hex": "H'BA72", + "txi_indexed_tdr_write_address": 47797, + "txi_indexed_tdr_write_address_hex": "H'BAB5", + "summary": "initial byte is written from the TX frame buffer, then subsequent bytes are sent by the TXI path when TDRE is reasserted", + "tdre_caveat": "TDRE reassertion is hardware/emulator timing context; static evidence is the indexed TXI send path." + }, "confidence": "high", "confidence_score": 0.95, "confidence_reason": "all required independent evidence groups were observed", @@ -17696,6 +17729,215 @@ "comment": "candidate/evidence-supported SCI1 6-byte RX frame hypothesis using capture buffer H'F868-H'F86D; checksum byte H'F865 is validated against XOR seeded by H'005A" } ], + "ram_roles": [ + { + "kind": "candidate_ram_role", + "name": "post_tx_report_delay", + "address": 63936, + "address_hex": "H'F9C0", + "width_bits": 8, + "confidence": "candidate/evidence-supported", + "summary": "post_tx_report_delay at H'F9C0 is a candidate/evidence-supported RAM timer role; FRT1 OCIA tick ISR H'BEEA decrements it", + "caveat": "role name is evidence-supported from static references plus emulator-guided timer behavior, not a proved firmware symbol", + "evidence": [ + { + "kind": "frt1_ocia_periodic_tick_isr", + "summary": "candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA", + "addresses": [ + 48874 + ], + "addresses_hex": [ + "H'BEEA" + ], + "instructions": [ + "BCLR.B #5, @FRT1_TCSR" + ], + "vector_address": 98, + "vector_address_hex": "H'0062", + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + }, + { + "kind": "post_tx_report_delay_tick_decrement", + "summary": "candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + "addresses": [ + 48878, + 48884 + ], + "addresses_hex": [ + "H'BEEE", + "H'BEF4" + ], + "instructions": [ + "TST.B @H'F9C0", + "ADD:Q.B #-1, @H'F9C0" + ], + "role_name": "post_tx_report_delay", + "ram_address": 63936, + "ram_address_hex": "H'F9C0", + "width_bits": 8, + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + } + ], + "evidence_addresses": { + "frt1_ocia_periodic_tick_isr": [ + 48874 + ], + "post_tx_report_delay_tick_decrement": [ + 48878, + 48884 + ] + }, + "evidence_addresses_hex": { + "frt1_ocia_periodic_tick_isr": [ + "H'BEEA" + ], + "post_tx_report_delay_tick_decrement": [ + "H'BEEE", + "H'BEF4" + ] + } + }, + { + "kind": "candidate_ram_role", + "name": "secondary_tx_report_delay", + "address": 63937, + "address_hex": "H'F9C1", + "width_bits": 8, + "confidence": "candidate/evidence-supported", + "summary": "secondary_tx_report_delay at H'F9C1 is a candidate/evidence-supported RAM timer role; FRT1 OCIA tick ISR H'BEEA decrements it", + "caveat": "role name is evidence-supported from static references plus emulator-guided timer behavior, not a proved firmware symbol", + "evidence": [ + { + "kind": "frt1_ocia_periodic_tick_isr", + "summary": "candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA", + "addresses": [ + 48874 + ], + "addresses_hex": [ + "H'BEEA" + ], + "instructions": [ + "BCLR.B #5, @FRT1_TCSR" + ], + "vector_address": 98, + "vector_address_hex": "H'0062", + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + }, + { + "kind": "secondary_tx_report_delay_tick_decrement", + "summary": "candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + "addresses": [ + 48888, + 48894 + ], + "addresses_hex": [ + "H'BEF8", + "H'BEFE" + ], + "instructions": [ + "TST.B @H'F9C1", + "ADD:Q.B #-1, @H'F9C1" + ], + "role_name": "secondary_tx_report_delay", + "ram_address": 63937, + "ram_address_hex": "H'F9C1", + "width_bits": 8, + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + } + ], + "evidence_addresses": { + "frt1_ocia_periodic_tick_isr": [ + 48874 + ], + "secondary_tx_report_delay_tick_decrement": [ + 48888, + 48894 + ] + }, + "evidence_addresses_hex": { + "frt1_ocia_periodic_tick_isr": [ + "H'BEEA" + ], + "secondary_tx_report_delay_tick_decrement": [ + "H'BEF8", + "H'BEFE" + ] + } + }, + { + "kind": "candidate_ram_role", + "name": "periodic_report_countdown", + "address": 63942, + "address_hex": "H'F9C6", + "width_bits": 16, + "confidence": "candidate/evidence-supported", + "summary": "periodic_report_countdown at H'F9C6 is a candidate/evidence-supported RAM timer role; FRT1 OCIA tick ISR H'BEEA decrements it", + "caveat": "role name is evidence-supported from static references plus emulator-guided timer behavior, not a proved firmware symbol", + "evidence": [ + { + "kind": "frt1_ocia_periodic_tick_isr", + "summary": "candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA", + "addresses": [ + 48874 + ], + "addresses_hex": [ + "H'BEEA" + ], + "instructions": [ + "BCLR.B #5, @FRT1_TCSR" + ], + "vector_address": 98, + "vector_address_hex": "H'0062", + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + }, + { + "kind": "periodic_report_countdown_tick_decrement", + "summary": "candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR", + "addresses": [ + 48898, + 48904 + ], + "addresses_hex": [ + "H'BF02", + "H'BF08" + ], + "instructions": [ + "TST.W @H'F9C6", + "ADD:Q.W #-1, @H'F9C6" + ], + "role_name": "periodic_report_countdown", + "ram_address": 63942, + "ram_address_hex": "H'F9C6", + "width_bits": 16, + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + } + ], + "evidence_addresses": { + "frt1_ocia_periodic_tick_isr": [ + 48874 + ], + "periodic_report_countdown_tick_decrement": [ + 48898, + 48904 + ] + }, + "evidence_addresses_hex": { + "frt1_ocia_periodic_tick_isr": [ + "H'BEEA" + ], + "periodic_report_countdown_tick_decrement": [ + "H'BF02", + "H'BF08" + ] + } + } + ], "evidence": [ { "kind": "tx_buffer_region", @@ -18094,6 +18336,89 @@ "XOR.B @H'F864, R0", "CMP:G.B @H'F865, R0" ] + }, + { + "kind": "frt1_ocia_periodic_tick_isr", + "summary": "candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA", + "addresses": [ + 48874 + ], + "addresses_hex": [ + "H'BEEA" + ], + "instructions": [ + "BCLR.B #5, @FRT1_TCSR" + ], + "vector_address": 98, + "vector_address_hex": "H'0062", + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + }, + { + "kind": "post_tx_report_delay_tick_decrement", + "summary": "candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + "addresses": [ + 48878, + 48884 + ], + "addresses_hex": [ + "H'BEEE", + "H'BEF4" + ], + "instructions": [ + "TST.B @H'F9C0", + "ADD:Q.B #-1, @H'F9C0" + ], + "role_name": "post_tx_report_delay", + "ram_address": 63936, + "ram_address_hex": "H'F9C0", + "width_bits": 8, + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + }, + { + "kind": "secondary_tx_report_delay_tick_decrement", + "summary": "candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + "addresses": [ + 48888, + 48894 + ], + "addresses_hex": [ + "H'BEF8", + "H'BEFE" + ], + "instructions": [ + "TST.B @H'F9C1", + "ADD:Q.B #-1, @H'F9C1" + ], + "role_name": "secondary_tx_report_delay", + "ram_address": 63937, + "ram_address_hex": "H'F9C1", + "width_bits": 8, + "isr_address": 48874, + "isr_address_hex": "H'BEEA" + }, + { + "kind": "periodic_report_countdown_tick_decrement", + "summary": "candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR", + "addresses": [ + 48898, + 48904 + ], + "addresses_hex": [ + "H'BF02", + "H'BF08" + ], + "instructions": [ + "TST.W @H'F9C6", + "ADD:Q.W #-1, @H'F9C6" + ], + "role_name": "periodic_report_countdown", + "ram_address": 63942, + "ram_address_hex": "H'F9C6", + "width_bits": 16, + "isr_address": 48874, + "isr_address_hex": "H'BEEA" } ], "required_evidence": { @@ -53154,7 +53479,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -53561,7 +53886,7 @@ "register": "SCR", "register_address": 65266, "register_address_hex": "H'FEF2", - "comment": "disable SCI2 TX interrupt (TIE)", + "comment": "disable SCI2 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -158900,7 +159225,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 transmit data register empty flag (TDRE)", + "comment": "clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -158991,7 +159316,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "enable SCI1 TX interrupt (TIE)", + "comment": "enable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -159419,7 +159744,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -159913,7 +160238,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 transmit data register empty flag (TDRE)", + "comment": "clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -160134,7 +160459,7 @@ "register": "SCR", "register_address": 65242, "register_address_hex": "H'FEDA", - "comment": "disable SCI1 TX interrupt (TIE)", + "comment": "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -162180,7 +162505,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 overrun error flag (ORER)", + "comment": "clear SCI1 ORER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -162286,7 +162611,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 framing error flag (FER)", + "comment": "clear SCI1 FER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -162392,7 +162717,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 parity error flag (PER)", + "comment": "clear SCI1 PER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -162522,7 +162847,7 @@ "register": "SSR", "register_address": 65244, "register_address_hex": "H'FEDC", - "comment": "clear SCI1 receive-data-full flag (RDRF)", + "comment": "clear SCI1 RDRF with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", "manual": [ "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", @@ -175356,6 +175681,62 @@ ], "comment": "clear OCFA (bit 5) of FRT1_TCSR", "valid": true, + "serial_reconstruction": [ + { + "address": 48874, + "action": "serial_reconstruction_ram_role", + "role_name": "post_tx_report_delay", + "role_kind": "candidate_ram_role", + "role_address": 63936, + "role_address_hex": "H'F9C0", + "evidence": "frt1_ocia_periodic_tick_isr", + "evidence_summary": "candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA", + "evidence_addresses": [ + 48874 + ], + "evidence_addresses_hex": [ + "H'BEEA" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported" + }, + { + "address": 48874, + "action": "serial_reconstruction_ram_role", + "role_name": "secondary_tx_report_delay", + "role_kind": "candidate_ram_role", + "role_address": 63937, + "role_address_hex": "H'F9C1", + "evidence": "frt1_ocia_periodic_tick_isr", + "evidence_summary": "candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA", + "evidence_addresses": [ + 48874 + ], + "evidence_addresses_hex": [ + "H'BEEA" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported" + }, + { + "address": 48874, + "action": "serial_reconstruction_ram_role", + "role_name": "periodic_report_countdown", + "role_kind": "candidate_ram_role", + "role_address": 63942, + "role_address_hex": "H'F9C6", + "evidence": "frt1_ocia_periodic_tick_isr", + "evidence_summary": "candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA", + "evidence_addresses": [ + 48874 + ], + "evidence_addresses_hex": [ + "H'BEEA" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported" + } + ], "dataflow": { "block": 48874, "changes": [ @@ -175402,6 +175783,28 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48878, + "action": "serial_reconstruction_ram_role", + "role_name": "post_tx_report_delay", + "role_kind": "candidate_ram_role", + "role_address": 63936, + "role_address_hex": "H'F9C0", + "evidence": "post_tx_report_delay_tick_decrement", + "evidence_summary": "candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + "evidence_addresses": [ + 48878, + 48884 + ], + "evidence_addresses_hex": [ + "H'BEEE", + "H'BEF4" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported" + } + ], "dataflow": { "block": 48874, "changes": [], @@ -175462,6 +175865,28 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48884, + "action": "serial_reconstruction_ram_role", + "role_name": "post_tx_report_delay", + "role_kind": "candidate_ram_role", + "role_address": 63936, + "role_address_hex": "H'F9C0", + "evidence": "post_tx_report_delay_tick_decrement", + "evidence_summary": "candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + "evidence_addresses": [ + 48878, + 48884 + ], + "evidence_addresses_hex": [ + "H'BEEE", + "H'BEF4" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported" + } + ], "dataflow": { "block": 48884, "changes": [ @@ -175508,6 +175933,28 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48888, + "action": "serial_reconstruction_ram_role", + "role_name": "secondary_tx_report_delay", + "role_kind": "candidate_ram_role", + "role_address": 63937, + "role_address_hex": "H'F9C1", + "evidence": "secondary_tx_report_delay_tick_decrement", + "evidence_summary": "candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + "evidence_addresses": [ + 48888, + 48894 + ], + "evidence_addresses_hex": [ + "H'BEF8", + "H'BEFE" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported" + } + ], "dataflow": { "block": 48888, "changes": [ @@ -175581,6 +176028,28 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48894, + "action": "serial_reconstruction_ram_role", + "role_name": "secondary_tx_report_delay", + "role_kind": "candidate_ram_role", + "role_address": 63937, + "role_address_hex": "H'F9C1", + "evidence": "secondary_tx_report_delay_tick_decrement", + "evidence_summary": "candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + "evidence_addresses": [ + 48888, + 48894 + ], + "evidence_addresses_hex": [ + "H'BEF8", + "H'BEFE" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported" + } + ], "dataflow": { "block": 48894, "changes": [ @@ -175627,6 +176096,28 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48898, + "action": "serial_reconstruction_ram_role", + "role_name": "periodic_report_countdown", + "role_kind": "candidate_ram_role", + "role_address": 63942, + "role_address_hex": "H'F9C6", + "evidence": "periodic_report_countdown_tick_decrement", + "evidence_summary": "candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR", + "evidence_addresses": [ + 48898, + 48904 + ], + "evidence_addresses_hex": [ + "H'BF02", + "H'BF08" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported" + } + ], "dataflow": { "block": 48898, "changes": [ @@ -175700,6 +176191,28 @@ ], "comment": "", "valid": true, + "serial_reconstruction": [ + { + "address": 48904, + "action": "serial_reconstruction_ram_role", + "role_name": "periodic_report_countdown", + "role_kind": "candidate_ram_role", + "role_address": 63942, + "role_address_hex": "H'F9C6", + "evidence": "periodic_report_countdown_tick_decrement", + "evidence_summary": "candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR", + "evidence_addresses": [ + 48898, + 48904 + ], + "evidence_addresses_hex": [ + "H'BF02", + "H'BF08" + ], + "confidence": "candidate/evidence-supported", + "comment": "candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported" + } + ], "dataflow": { "block": 48904, "changes": [ diff --git a/build/rom_pseudocode.c b/build/rom_pseudocode.c index d7e3b22..5c728c1 100644 --- a/build/rom_pseudocode.c +++ b/build/rom_pseudocode.c @@ -485,10 +485,10 @@ void vec_reset_1000(void) PWM3_TCR = (uint8_t)(0x3B); /* 108B; MOV:G.B #H'3B, @PWM3_TCR; PWM3_TCR = H'3B (OE=0 OS=0 CKS2=0 CKS1=1 CKS0=1); refs PWM3_TCR; cycles=9 */ PWM3_DTR = (uint8_t)(0x7D); /* 1090; MOV:G.B #H'7D, @PWM3_DTR; PWM3_DTR = H'7D; refs PWM3_DTR; cycles=9 */ SCI1_SMR = (uint8_t)(0x24); /* 1095; MOV:G.B #H'24, @SCI1_SMR; SCI1_SMR = H'24 (C/A=0 CHR=0 PE=1 O/E=0 STOP=0 CKS1=0 CKS0=0; SCI async, 8-bit, even parity, 1 stop, clock phi); SCI1 SMR serial init for traced RS232/MAX202 path (H8 pin 66 P95/TXD to MAX202 pin 11; MAX202 pin 12 to H8 pin 67 P96/RXD); refs SCI1_SMR; cycles=9 */ - SCI1_SCR = (uint8_t)(0x3C); /* 109A; MOV:G.B #H'3C, @SCI1_SCR; SCI1_SCR = H'3C (TIE=0 RIE=0 TE=1 RE=1 CKE1=0 CKE0=0; SCI enables TX,RX, internal clock); disable SCI1 TX interrupt (TIE); disable SCI1 receive and receive-error interrupts (RIE); enable SCI1 transmitter (TE); enable SCI1 receiver (RE); 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 */ + SCI1_SCR = (uint8_t)(0x3C); /* 109A; MOV:G.B #H'3C, @SCI1_SCR; SCI1_SCR = H'3C (TIE=0 RIE=0 TE=1 RE=1 CKE1=0 CKE0=0; SCI enables TX,RX, internal clock); disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE; disable SCI1 receive and receive-error interrupts (RIE); enable SCI1 transmitter (TE); enable SCI1 receiver (RE); 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 */ SCI1_BRR = (uint8_t)(0x07); /* 109F; MOV:G.B #H'07, @SCI1_BRR; SCI1_BRR = H'07; SCI1 async 8-bit even parity 1 stop BRR N=7 CKS n=0; baud needs --clock-hz; SCI1 BRR serial init for traced RS232/MAX202 path (H8 pin 66 P95/TXD to MAX202 pin 11; MAX202 pin 12 to H8 pin 67 P96/RXD); refs SCI1_BRR; cycles=9 */ SCI2_SMR = (uint8_t)(0x24); /* 10A4; MOV:G.B #H'24, @SCI2_SMR; SCI2_SMR = H'24 (C/A=0 CHR=0 PE=1 O/E=0 STOP=0 CKS1=0 CKS0=0; SCI async, 8-bit, even parity, 1 stop, clock phi); SCI2 SMR write; not the traced MAX202 path; P9SCI2E=0 disables SCI2 pins P92/P93/P94, while the board trace is SCI1 P95/P96; refs SCI2_SMR; cycles=9 */ - SCI2_SCR = (uint8_t)(0x0C); /* 10A9; MOV:G.B #H'0C, @SCI2_SCR; SCI2_SCR = H'0C (TIE=0 RIE=0 TE=0 RE=0 CKE1=0 CKE0=0; SCI enables none, internal clock); disable SCI2 TX interrupt (TIE); disable SCI2 receive and receive-error interrupts (RIE); disable SCI2 transmitter (TE); disable SCI2 receiver (RE); SCI2 SCR write; not the traced MAX202 path; P9SCI2E=0 disables SCI2 pins P92/P93/P94, while the board trace is SCI1 P95/P96; refs SCI2_SCR; cycles=9 */ + SCI2_SCR = (uint8_t)(0x0C); /* 10A9; MOV:G.B #H'0C, @SCI2_SCR; SCI2_SCR = H'0C (TIE=0 RIE=0 TE=0 RE=0 CKE1=0 CKE0=0; SCI enables none, internal clock); disable SCI2 TX interrupt (TIE); gates TXI when hardware sets TDRE; disable SCI2 receive and receive-error interrupts (RIE); disable SCI2 transmitter (TE); disable SCI2 receiver (RE); SCI2 SCR write; not the traced MAX202 path; P9SCI2E=0 disables SCI2 pins P92/P93/P94, while the board trace is SCI1 P95/P96; refs SCI2_SCR; cycles=9 */ SCI2_BRR = (uint8_t)(0x07); /* 10AE; MOV:G.B #H'07, @SCI2_BRR; SCI2_BRR = H'07; SCI2 async 8-bit even parity 1 stop BRR N=7 CKS n=0; baud needs --clock-hz; SCI2 BRR write; not the traced MAX202 path; P9SCI2E=0 disables SCI2 pins P92/P93/P94, while the board trace is SCI1 P95/P96; refs SCI2_BRR; cycles=9 */ ADCSR = (uint8_t)(0x19); /* 10B3; MOV:G.B #H'19, @ADCSR; ADCSR = H'19 (ADF=0 ADIE=0 ADST=0 SCAN=1 CKS=1 CH2=0 CH1=0 CH0=1; A/D halt, scan AN0-AN1, 138-state max, ADI disabled); refs ADCSR; cycles=9 */ MEM8[0xFEE9] = (uint8_t)(0x7F); /* 10B8; MOV:G.B #H'7F, @H'FEE9; cycles=9 */ @@ -2854,8 +2854,8 @@ void loc_BA26(void) 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 */ + SCI1_SSR &= ~BIT(7); /* BA7B; BCLR.B #7, @SCI1_SSR; clear TDRE (bit 7) of SCI1_SSR; clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts 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); gates TXI when hardware sets TDRE; 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 */ } @@ -2870,7 +2870,7 @@ void vec_sci1_txi_BA84(void) if (Z) goto loc_BAA9; /* BA94; BEQ loc_BAA9; cycles=3/7 nt/t */ MEM8[0xFAA2] &= ~BIT(3); /* BA96; BCLR.B #3, @H'FAA2; refs ram_FAA2; cycles=9 */ MEM8[0xFAA3] = 0; /* BA9A; CLR.B @H'FAA3; refs ram_FAA3; cycles=9 */ - SCI1_SCR &= ~BIT(7); /* BA9E; 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 */ + SCI1_SCR &= ~BIT(7); /* BA9E; BCLR.B #7, @SCI1_SCR; clear TIE (bit 7) of SCI1_SCR; disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE; 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 */ MEM8[0xF9C0] = (uint8_t)(0x1F); /* BAA2; MOV:G.B #H'1F, @H'F9C0; refs ram_F9C0; cycles=9 */ goto loc_BAF1; /* BAA7; BRA loc_BAF1; cycles=8 */ loc_BAA9: @@ -2880,11 +2880,11 @@ loc_BAA9: 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 */ + SCI1_SSR &= ~BIT(7); /* BABB; BCLR.B #7, @SCI1_SSR; clear TDRE (bit 7) of SCI1_SSR; clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts 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; 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 */ + SCI1_SCR &= ~BIT(7); /* BACA; BCLR.B #7, @SCI1_SCR; clear TIE (bit 7) of SCI1_SCR; disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE; 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 */ if (!Z) goto loc_BAE8; /* BAD2; BNE loc_BAE8; cycles=3/7 nt/t */ set_flags_btst(MEM8[0xF791], 7); /* BAD4; BTST.B #7, @H'F791; refs ram_F791; cycles=7 */ @@ -2945,16 +2945,16 @@ void vec_sci1_eri_BB57(void) { /* vector sources: sci1_eri */ MEM8[0xFAA4] |= BIT(7); /* BB57; BSET.B #7, @H'FAA4; 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; refs ram_FAA4; cycles=8 */ - SCI1_SSR &= ~BIT(5); /* BB5B; BCLR.B #5, @SCI1_SSR; clear ORER (bit 5) of SCI1_SSR; clear SCI1 overrun error flag (ORER); 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ - SCI1_SSR &= ~BIT(4); /* BB5F; BCLR.B #4, @SCI1_SSR; clear FER (bit 4) of SCI1_SSR; clear SCI1 framing error flag (FER); 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ - SCI1_SSR &= ~BIT(3); /* BB63; BCLR.B #3, @SCI1_SSR; clear PER (bit 3) of SCI1_SSR; clear SCI1 parity error flag (PER); 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ + SCI1_SSR &= ~BIT(5); /* BB5B; BCLR.B #5, @SCI1_SSR; clear ORER (bit 5) of SCI1_SSR; clear SCI1 ORER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state; 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ + SCI1_SSR &= ~BIT(4); /* BB5F; BCLR.B #4, @SCI1_SSR; clear FER (bit 4) of SCI1_SSR; clear SCI1 FER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state; 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ + SCI1_SSR &= ~BIT(3); /* BB63; BCLR.B #3, @SCI1_SSR; clear PER (bit 3) of SCI1_SSR; clear SCI1 PER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state; 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 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ } 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); 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: ROM clears SCI1 SSR.RDRF before reading SCI1_RDR; preserve this observed ordering even though the manual describes the canonical RDR-read then RDRF-clear sequence; 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: SCI1 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use; refs SCI1_SSR; cycles=8 */ + SCI1_SSR &= ~BIT(6); /* BB69; BCLR.B #6, @SCI1_SSR; clear RDRF (bit 6) of SCI1_SSR; clear SCI1 RDRF with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state; 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: ROM clears SCI1 SSR.RDRF before reading SCI1_RDR; preserve this observed ordering even though the manual describes the canonical RDR-read then RDRF-clear sequence; 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: SCI1 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; confidence high; 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; 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; 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: ROM clears SCI1 SSR.RDRF before reading SCI1_RDR; preserve this observed ordering even though the manual describes the canonical RDR-read then RDRF-clear sequence; 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: SCI1 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into the same RXI byte-capture path; 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 */ @@ -3284,18 +3284,18 @@ loc_BEE8: void vec_frt1_ocia_BEEA(void) { /* vector sources: frt1_ocia */ - FRT1_TCSR &= ~BIT(5); /* BEEA; BCLR.B #5, @FRT1_TCSR; clear OCFA (bit 5) of FRT1_TCSR; refs FRT1_TCSR; cycles=9 */ - set_flags_tst8(MEM8[0xF9C0]); /* BEEE; TST.B @H'F9C0; refs ram_F9C0; cycles=7 */ + FRT1_TCSR &= ~BIT(5); /* BEEA; BCLR.B #5, @FRT1_TCSR; clear OCFA (bit 5) of FRT1_TCSR; candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported; candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported; candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic tick ISR at H'BEEA for FRT1 OCIA vector H'0062 clears OCFA; confidence candidate/evidence-supported; refs FRT1_TCSR; cycles=9 */ + set_flags_tst8(MEM8[0xF9C0]); /* BEEE; TST.B @H'F9C0; candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C0; cycles=7 */ if (!Z) { /* BEF2; BEQ loc_BEF8; cycles=3/7 nt/t */ - MEM8[0xF9C0] += (uint8_t)(-1); /* BEF4; ADD:Q.B #-1, @H'F9C0; refs ram_F9C0; cycles=9 */ + MEM8[0xF9C0] += (uint8_t)(-1); /* BEF4; ADD:Q.B #-1, @H'F9C0; candidate/evidence-supported RAM role post_tx_report_delay at H'F9C0; evidence: candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C0; cycles=9 */ } - set_flags_tst8(MEM8[0xF9C1]); /* BEF8; TST.B @H'F9C1; refs ram_F9C1; cycles=7 */ + set_flags_tst8(MEM8[0xF9C1]); /* BEF8; TST.B @H'F9C1; candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C1; cycles=7 */ if (!Z) { /* BEFC; BEQ loc_BF02; cycles=3/7 nt/t */ - MEM8[0xF9C1] += (uint8_t)(-1); /* BEFE; ADD:Q.B #-1, @H'F9C1; refs ram_F9C1; cycles=9 */ + MEM8[0xF9C1] += (uint8_t)(-1); /* BEFE; ADD:Q.B #-1, @H'F9C1; candidate/evidence-supported RAM role secondary_tx_report_delay at H'F9C1; evidence: candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C1; cycles=9 */ } - set_flags_tst16(MEM16[0xF9C6]); /* BF02; TST.W @H'F9C6; refs ram_F9C6; cycles=7 */ + set_flags_tst16(MEM16[0xF9C6]); /* BF02; TST.W @H'F9C6; candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C6; cycles=7 */ if (!Z) { /* BF06; BEQ loc_BF0C; cycles=3/7 nt/t */ - MEM16[0xF9C6] += (uint16_t)(-1); /* BF08; ADD:Q.W #-1, @H'F9C6; refs ram_F9C6; cycles=9 */ + MEM16[0xF9C6] += (uint16_t)(-1); /* BF08; ADD:Q.W #-1, @H'F9C6; candidate/evidence-supported RAM role periodic_report_countdown at H'F9C6; evidence: candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR; confidence candidate/evidence-supported; refs ram_F9C6; cycles=9 */ } set_flags_btst(MEM8[0xF6F6], 7); /* BF0C; BTST.B #7, @H'F6F6; refs ram_F6F6; cycles=7 */ if (Z) goto loc_BF22; /* BF10; BEQ loc_BF22; cycles=3/7 nt/t */ diff --git a/build/rom_serial_gate.json b/build/rom_serial_gate.json index 352c791..ae219a5 100644 --- a/build/rom_serial_gate.json +++ b/build/rom_serial_gate.json @@ -498,6 +498,85 @@ ], "summary": "Requires FAA2 == 0, allows the FAA5.bit7 path only when F9C3 == 0, then requires F9C0 == 0 before BSR loc_BAF2.", "title": "loc_3FD3 gate into loc_BAF2" + }, + "timer_tick_evidence": { + "candidate_timer_roles": [ + { + "address": 63936, + "address_hex": "H'F9C0", + "evidence_address_hex": "H'BEF4", + "role": "candidate post-TX/report delay countdown" + }, + { + "address": 63937, + "address_hex": "H'F9C1", + "evidence_address_hex": "H'BEFE", + "role": "candidate secondary delay countdown" + }, + { + "address": 63942, + "address_hex": "H'F9C6", + "evidence_address_hex": "H'BF08", + "role": "candidate periodic report/heartbeat countdown" + } + ], + "handler_address_hex": "H'BEEA", + "items": [ + { + "address": 48874, + "address_hex": "H'BEEA", + "present": true, + "targets_hex": [], + "text": "BCLR.B #5, @FRT1_TCSR" + }, + { + "address": 48878, + "address_hex": "H'BEEE", + "present": true, + "targets_hex": [], + "text": "TST.B @H'F9C0" + }, + { + "address": 48884, + "address_hex": "H'BEF4", + "present": true, + "targets_hex": [], + "text": "ADD:Q.B #-1, @H'F9C0" + }, + { + "address": 48888, + "address_hex": "H'BEF8", + "present": true, + "targets_hex": [], + "text": "TST.B @H'F9C1" + }, + { + "address": 48894, + "address_hex": "H'BEFE", + "present": true, + "targets_hex": [], + "text": "ADD:Q.B #-1, @H'F9C1" + }, + { + "address": 48898, + "address_hex": "H'BF02", + "present": true, + "targets_hex": [], + "text": "TST.W @H'F9C6" + }, + { + "address": 48904, + "address_hex": "H'BF08", + "present": true, + "targets_hex": [], + "text": "ADD:Q.W #-1, @H'F9C6" + } + ], + "present": true, + "summary": "Static evidence links vector H'0062 to the FRT1 OCIA handler at H'BEEA; the handler clears FRT1_TCSR.OCFA and conditionally decrements H'F9C0, H'F9C1, and H'F9C6.", + "title": "FRT1 OCIA periodic tick countdowns", + "vector_address_hex": "H'0062", + "vector_target_label": "vec_frt1_ocia_BEEA" } }, "kind": "serial_gate", @@ -1047,6 +1126,87 @@ ], "write_count": 7 }, + { + "accesses": [ + { + "access": "write", + "address": 47853, + "address_hex": "H'BAED", + "function": "vec_sci1_txi_BA84", + "text": "CLR.B @H'F9C1" + }, + { + "access": "read", + "address": 47985, + "address_hex": "H'BB71", + "function": "vec_sci1_rxi_BB67", + "text": "TST.B @H'F9C1" + }, + { + "access": "write", + "address": 48035, + "address_hex": "H'BBA3", + "function": "vec_sci1_rxi_BB67", + "text": "MOV:G.B #H'05, @H'F9C1" + }, + { + "access": "read", + "address": 48888, + "address_hex": "H'BEF8", + "function": "vec_frt1_ocia_BEEA", + "text": "TST.B @H'F9C1" + }, + { + "access": "read_write", + "address": 48894, + "address_hex": "H'BEFE", + "function": "vec_frt1_ocia_BEEA", + "text": "ADD:Q.B #-1, @H'F9C1" + } + ], + "address": 63937, + "address_hex": "H'F9C1", + "read_count": 2, + "read_write_count": 1, + "sample_accesses": [ + { + "access": "write", + "address": 47853, + "address_hex": "H'BAED", + "function": "vec_sci1_txi_BA84", + "text": "CLR.B @H'F9C1" + }, + { + "access": "read", + "address": 47985, + "address_hex": "H'BB71", + "function": "vec_sci1_rxi_BB67", + "text": "TST.B @H'F9C1" + }, + { + "access": "write", + "address": 48035, + "address_hex": "H'BBA3", + "function": "vec_sci1_rxi_BB67", + "text": "MOV:G.B #H'05, @H'F9C1" + }, + { + "access": "read", + "address": 48888, + "address_hex": "H'BEF8", + "function": "vec_frt1_ocia_BEEA", + "text": "TST.B @H'F9C1" + }, + { + "access": "read_write", + "address": 48894, + "address_hex": "H'BEFE", + "function": "vec_frt1_ocia_BEEA", + "text": "ADD:Q.B #-1, @H'F9C1" + } + ], + "write_count": 2 + }, { "accesses": [ { @@ -1823,6 +1983,11 @@ "address_hex": "H'F9C0", "symbol": "ram_F9C0" }, + { + "address": 63937, + "address_hex": "H'F9C1", + "symbol": "ram_F9C1" + }, { "address": 63939, "address_hex": "H'F9C3", diff --git a/build/rom_serial_gate.txt b/build/rom_serial_gate.txt index 3e38a8e..63f5613 100644 --- a/build/rom_serial_gate.txt +++ b/build/rom_serial_gate.txt @@ -72,6 +72,19 @@ Evidence: - H'BDF7: BCLR.B #7, @H'F9B5 - H'BDFB: CLR.B @H'FAA3 - H'BDFF: CLR.B @H'FAA2 +- FRT1 OCIA periodic tick countdowns: present + Static evidence links vector H'0062 to the FRT1 OCIA handler at H'BEEA; the handler clears FRT1_TCSR.OCFA and conditionally decrements H'F9C0, H'F9C1, and H'F9C6. + - H'BEEA: BCLR.B #5, @FRT1_TCSR + - H'BEEE: TST.B @H'F9C0 + - H'BEF4: ADD:Q.B #-1, @H'F9C0 + - H'BEF8: TST.B @H'F9C1 + - H'BEFE: ADD:Q.B #-1, @H'F9C1 + - H'BF02: TST.W @H'F9C6 + - H'BF08: ADD:Q.W #-1, @H'F9C6 + Candidate timer roles: + - H'F9C0: candidate post-TX/report delay countdown + - H'F9C1: candidate secondary delay countdown + - H'F9C6: candidate periodic report/heartbeat countdown State address readers/writers: - H'F9B0: reads=4 writes=1 read/write=4 @@ -84,6 +97,8 @@ State address readers/writers: H'2806 read MOV:G.B @H'F9B9, R1; H'2822 write MOV:G.B R1, @H'F9B9; H'3E9E read MOV:G.B @H'F9B9, R0; H'BE70 read MOV:G.B @H'F9B9, R3 - H'F9C0: reads=3 writes=7 read/write=1 H'3FE5 read TST.B @H'F9C0; H'BA26 read TST.B @H'F9C0; H'BA2C write MOV:G.B #H'64, @H'F9C0; H'BAA2 write MOV:G.B #H'1F, @H'F9C0; H'BADA write MOV:G.B #H'09, @H'F9C0; H'BAE1 write MOV:G.B #H'09, @H'F9C0 +- H'F9C1: reads=2 writes=2 read/write=1 + H'BAED write CLR.B @H'F9C1; H'BB71 read TST.B @H'F9C1; H'BBA3 write MOV:G.B #H'05, @H'F9C1; H'BEF8 read TST.B @H'F9C1; H'BEFE read_write ADD:Q.B #-1, @H'F9C1 - H'F9C3: reads=6 writes=4 read/write=0 H'3FDF read TST.B @H'F9C3; H'4052 read TST.B @H'F9C3; H'BA90 read TST.B @H'F9C3; H'BB77 write CLR.B @H'F9C3; H'BB7D read CMP:G.B #H'05, @H'F9C3; H'BB8A read MOV:G.B @H'F9C3, R1 - H'F9C5: reads=2 writes=2 read/write=1 diff --git a/build/rom_serial_pseudocode.c b/build/rom_serial_pseudocode.c index 2754b1e..76be88a 100644 --- a/build/rom_serial_pseudocode.c +++ b/build/rom_serial_pseudocode.c @@ -84,9 +84,14 @@ extern volatile u8 MEM8[0x10000]; #define SCI_SSR_FER 0x10u #define SCI_SSR_PER 0x08u -#define TX_FRAME_LENGTH 6u +#define SCI1_TX_FRAME_LENGTH 6u +#define SCI1_TX_FRAME_BASE 0xF858u +#define SCI1_TX_FRAME_BYTE(n) MEM8[(u16)(SCI1_TX_FRAME_BASE + (n))] +#define SCI1_TX_FRAME_CHECKSUM SCI1_TX_FRAME_BYTE(5u) +#define SCI1_TX_INDEX MEM8[0xF9C2u] +#define TX_FRAME_LENGTH SCI1_TX_FRAME_LENGTH #define TX_FRAME(n) MEM8[(u16)(0xF858u + (n))] -#define TX_INDEX MEM8[0xF9C2u] +#define TX_INDEX SCI1_TX_INDEX #define RX_FRAME_LENGTH 6u #define RX_CAPTURE(n) MEM8[(u16)(0xF868u + (n))] @@ -204,6 +209,11 @@ extern volatile u8 MEM8[0x10000]; * - FAA3 mask H'80: Candidate bit/mask that marks an autonomous report pending. * - BED5 resend path: Candidate periodic resend path feeding the TX staging/send-builder flow. * - evidence: H'BB46, H'BEC5, H'BB4C, H'BB51, H'BECB, H'BED5 + * interrupt/timer architecture candidate: + * - FRT1 OCIA H'BEEA appears to be a periodic tick ISR for serial gate/cadence counters. + * - H'F9C0 tx_report_gate_counter_candidate: candidate gate counter used before entering the report builder. + * - H'F9C1 rx_interbyte_timeout_candidate: candidate RX interbyte timeout counter. + * - H'F9C6 periodic_resend_cadence_counter_candidate: candidate periodic resend/heartbeat cadence counter. */ static u8 sci1_rx_candidate_command(void) @@ -256,6 +266,26 @@ static bool sci1_candidate_periodic_resend_gate_open(void) return pending && period_elapsed && resend_countdown_active; } +void frt1_ocia_candidate_tick_isr(void) +{ + /* Candidate periodic tick at H'BEEA: decrement nonzero serial gate/cadence counters. */ + /* TX_REPORT_GATE_COUNTER_CANDIDATE: candidate gate counter used before entering the report builder. */ + if (MEM8[0xF9C0u] != 0u) { + MEM8[0xF9C0u] = (u8)(MEM8[0xF9C0u] - 1u); + } + + /* RX_INTERBYTE_TIMEOUT_CANDIDATE: candidate RX interbyte timeout counter. */ + if (MEM8[0xF9C1u] != 0u) { + MEM8[0xF9C1u] = (u8)(MEM8[0xF9C1u] - 1u); + } + + /* PERIODIC_RESEND_CADENCE_COUNTER_CANDIDATE: candidate periodic resend/heartbeat cadence counter. */ + if (MEM8[0xF9C6u] != 0u) { + MEM8[0xF9C6u] = (u8)(MEM8[0xF9C6u] - 1u); + } + +} + void sci1_process_candidate_protocol_command(void) { u8 command = sci1_rx_candidate_command(); @@ -359,6 +389,7 @@ void sci1_tx_start_candidate_frame(void) /* wait for transmit data register empty */ } + /* First byte is sent synchronously; TIE enables TXI for the remaining bytes. */ SCI1_TDR = TX_FRAME(0); TX_INDEX = 1u; SCI1_SSR &= (u8)~SCI_SSR_TDRE; @@ -367,6 +398,11 @@ void sci1_tx_start_candidate_frame(void) void sci1_txi_candidate_isr(void) { + /* TXI runs after hardware reasserts SSR.TDRE for the next transmit byte. */ + if ((SCI1_SSR & SCI_SSR_TDRE) == 0u) { + return; + } + if (TX_INDEX < TX_FRAME_LENGTH) { SCI1_TDR = TX_FRAME(TX_INDEX); TX_INDEX = (u8)(TX_INDEX + 1u); diff --git a/h8536/render.py b/h8536/render.py index 39f01c8..b34a44f 100644 --- a/h8536/render.py +++ b/h8536/render.py @@ -275,6 +275,11 @@ def _serial_reconstruction_lines(serial_reconstruction: dict[str, object] | None f"checksum {candidate['checksum_address_hex']} seeded by {candidate['checksum_seed_hex']} " f"(confidence {confidence} {score})", ) + tx_path = candidate.get("tx_path") + if isinstance(tx_path, dict): + lines.append( + f"; TX path: {tx_path.get('summary', 'interrupt-driven TXI path')}", + ) elif kind == "candidate_sci1_rx_frame": lines.append( f"; RX candidate: {candidate['frame_length']} bytes " @@ -286,6 +291,17 @@ def _serial_reconstruction_lines(serial_reconstruction: dict[str, object] | None caveat = candidate.get("caveat") if caveat: lines.append(f"; caveat: {caveat}") + ram_roles = serial_reconstruction.get("ram_roles", []) + if isinstance(ram_roles, list) and ram_roles: + lines.append("; Serial RAM role candidates") + for role in ram_roles: + if not isinstance(role, dict): + continue + address_text = str(role.get("address_hex") or h16(int(role.get("address") or 0))) + lines.append( + f"; {address_text}: " + f"{role.get('name', 'ram_role')} - {role.get('summary', '')}", + ) lines.append("") return lines diff --git a/h8536/sci_protocol.py b/h8536/sci_protocol.py index fb783ce..a6e9ea5 100644 --- a/h8536/sci_protocol.py +++ b/h8536/sci_protocol.py @@ -61,11 +61,26 @@ SSR_FLAGS = { } SSR_CLEAR_ACTIONS = { - 7: ("clear_tdre", "clear {channel} transmit data register empty flag (TDRE)"), - 6: ("clear_rdrf", "clear {channel} receive-data-full flag (RDRF)"), - 5: ("clear_orer", "clear {channel} overrun error flag (ORER)"), - 4: ("clear_fer", "clear {channel} framing error flag (FER)"), - 3: ("clear_per", "clear {channel} parity error flag (PER)"), + 7: ( + "clear_tdre", + "clear {channel} TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", + ), + 6: ( + "clear_rdrf", + "clear {channel} RDRF with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", + ), + 5: ( + "clear_orer", + "clear {channel} ORER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", + ), + 4: ( + "clear_fer", + "clear {channel} FER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", + ), + 3: ( + "clear_per", + "clear {channel} PER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", + ), } @@ -263,7 +278,10 @@ def _scr_bit_event( verb = "enable" if enabled else "disable" action_noun = noun.replace("/", "_").replace(" ", "_").lower() if bit == 7: - comment = f"{verb} {register.channel} TX interrupt (TIE)" + comment = ( + f"{verb} {register.channel} TX interrupt (TIE); " + "gates TXI when hardware sets TDRE" + ) elif bit == 6: comment = f"{verb} {register.channel} receive and receive-error interrupts (RIE)" elif bit == 5: diff --git a/h8536/serial_gate.py b/h8536/serial_gate.py index 05b9e88..9248444 100644 --- a/h8536/serial_gate.py +++ b/h8536/serial_gate.py @@ -17,6 +17,7 @@ KEY_STATE_ADDRESSES: tuple[int, ...] = ( 0xF9B5, 0xF9B9, 0xF9C0, + 0xF9C1, 0xF9C3, 0xF9C5, 0xF9C6, @@ -51,6 +52,7 @@ def analyze_serial_gate(payload: dict[str, Any]) -> JsonObject: "queue_send_gate_loc_BAF2": _queue_send_gate(by_address), "resend_gate_path": _resend_gate_path(by_address), "rx_session_maintenance": _rx_session_maintenance(by_address), + "timer_tick_evidence": _timer_tick_evidence(payload, by_address), } access_summary = _state_access_summary(instructions, labels) @@ -94,6 +96,11 @@ def format_text_report(analysis: dict[str, Any]) -> str: lines.append(f" {summary}") for item in section.get("items", []): lines.append(f" - {item['address_hex']}: {item['text']}") + roles = section.get("candidate_timer_roles", []) + if roles: + lines.append(" Candidate timer roles:") + for role in roles: + lines.append(f" - {role['address_hex']}: {role['role']}") lines.extend(["", "State address readers/writers:"]) for entry in analysis.get("state_accesses", []): @@ -266,6 +273,53 @@ def _rx_session_maintenance(by_address: dict[int, JsonObject]) -> JsonObject: } +def _timer_tick_evidence(payload: dict[str, Any], by_address: dict[int, JsonObject]) -> JsonObject: + vector = _vector_entry(payload, 0x0062, "frt1_ocia") + handler = _int_field(vector, "target") if vector else None + if handler is None: + handler = 0xBEEA + addresses = [handler, 0xBEEE, 0xBEF4, 0xBEF8, 0xBEFE, 0xBF02, 0xBF08] + has_vector = vector is not None and _int_field(vector, "target") == handler + has_handler_clear = _instruction_mentions(by_address.get(handler), ("FRT1_TCSR", "#5")) + decrement_addresses = (0xBEF4, 0xBEFE, 0xBF08) + has_decrements = all( + address in by_address and _access_kind(by_address[address], state_address) == "read_write" + for address, state_address in zip(decrement_addresses, (0xF9C0, 0xF9C1, 0xF9C6)) + ) + return { + "title": "FRT1 OCIA periodic tick countdowns", + "present": bool((has_vector or has_handler_clear) and has_decrements), + "summary": ( + "Static evidence links vector H'0062 to the FRT1 OCIA handler at H'BEEA; the handler " + "clears FRT1_TCSR.OCFA and conditionally decrements H'F9C0, H'F9C1, and H'F9C6." + ), + "vector_address_hex": h16(0x0062), + "handler_address_hex": h16(handler), + "vector_target_label": str(vector.get("target_label", "")) if vector else "", + "items": _items(by_address, addresses), + "candidate_timer_roles": [ + { + "address": 0xF9C0, + "address_hex": h16(0xF9C0), + "role": "candidate post-TX/report delay countdown", + "evidence_address_hex": h16(0xBEF4), + }, + { + "address": 0xF9C1, + "address_hex": h16(0xF9C1), + "role": "candidate secondary delay countdown", + "evidence_address_hex": h16(0xBEFE), + }, + { + "address": 0xF9C6, + "address_hex": h16(0xF9C6), + "role": "candidate periodic report/heartbeat countdown", + "evidence_address_hex": h16(0xBF08), + }, + ], + } + + def _state_access_summary(instructions: list[JsonObject], labels: dict[int, str]) -> list[JsonObject]: result: list[JsonObject] = [] for state_address in KEY_STATE_ADDRESSES: @@ -333,6 +387,32 @@ def _has_all(by_address: dict[int, JsonObject], addresses: tuple[int, ...]) -> b return all(address in by_address for address in addresses) +def _vector_entry(payload: dict[str, Any], address: int, name: str) -> JsonObject | None: + vectors = payload.get("vectors", []) + if not isinstance(vectors, list): + return None + for vector in vectors: + if not isinstance(vector, dict): + continue + if _int_field(vector, "address") == address or str(vector.get("name", "")).lower() == name: + return vector + return None + + +def _int_field(payload: JsonObject | None, key: str, default: int | None = None) -> int | None: + if not isinstance(payload, dict): + return default + value = payload.get(key) + return value if isinstance(value, int) else default + + +def _instruction_mentions(ins: JsonObject | None, fragments: tuple[str, ...]) -> bool: + if not isinstance(ins, dict): + return False + text = f"{ins.get('text', '')} {ins.get('operands', '')} {ins.get('comment', '')}".upper() + return all(fragment.upper() in text for fragment in fragments) + + def _text(by_address: dict[int, JsonObject], address: int) -> str: return str(by_address.get(address, {}).get("text", "")) diff --git a/h8536/serial_pseudocode.py b/h8536/serial_pseudocode.py index c2666e9..fa22d7e 100644 --- a/h8536/serial_pseudocode.py +++ b/h8536/serial_pseudocode.py @@ -301,11 +301,17 @@ def _declarations(tx_candidate: JsonObject | None, rx_candidate: JsonObject | No tx_start = _int_field(tx_candidate, "buffer_start", 0xF858) tx_index = _int_field(tx_candidate, "tx_index_address", 0xF9C2) length = _int_field(tx_candidate, "frame_length", 6) + checksum_index = max(length - 1, 0) lines.extend( [ - f"#define TX_FRAME_LENGTH {length}u", + f"#define SCI1_TX_FRAME_LENGTH {length}u", + f"#define SCI1_TX_FRAME_BASE {_c_hex(tx_start)}", + "#define SCI1_TX_FRAME_BYTE(n) MEM8[(u16)(SCI1_TX_FRAME_BASE + (n))]", + f"#define SCI1_TX_FRAME_CHECKSUM SCI1_TX_FRAME_BYTE({checksum_index}u)", + f"#define SCI1_TX_INDEX MEM8[{_c_hex(tx_index)}]", + "#define TX_FRAME_LENGTH SCI1_TX_FRAME_LENGTH", f"#define TX_FRAME(n) MEM8[(u16)({_c_hex(tx_start)} + (n))]", - f"#define TX_INDEX MEM8[{_c_hex(tx_index)}]", + "#define TX_INDEX SCI1_TX_INDEX", "", ], ) @@ -407,6 +413,7 @@ def _semantics_lines( lines.extend(_gate_queue_comment_lines(protocol.get("gate_queue_model"), opts, prefix=" * ")) lines.extend(_tx_report_comment_lines(protocol.get("tx_report_model"), opts, prefix=" * ")) lines.extend(_periodic_resend_comment_lines(protocol.get("periodic_resend_model"), opts, prefix=" * ")) + lines.extend(_timer_architecture_comment_lines(protocol, opts, prefix=" * ")) lines.append(" */") lines.append("") @@ -442,6 +449,7 @@ def _semantics_lines( ], ) lines.extend(_gate_queue_predicate_function_lines(protocol.get("gate_queue_model"))) + lines.extend(_timer_architecture_function_lines(protocol)) lines.extend( [ "void sci1_process_candidate_protocol_command(void)", @@ -741,6 +749,123 @@ def _periodic_resend_comment_lines( return lines +def _timer_architecture_comment_lines( + protocol: JsonObject, + opts: SerialPseudocodeOptions, + *, + prefix: str, +) -> list[str]: + model = _timer_architecture_model(protocol) + if not model: + return [] + + vector = str(model.get("vector_address_hex") or "H'BEEA") + source = str(model.get("source") or "FRT1 OCIA") + lines = [f"{prefix}interrupt/timer architecture candidate:"] + lines.append( + f"{prefix}- {source} {vector} appears to be a periodic tick ISR for serial gate/cadence counters.", + ) + counters = _timer_counter_models(model) + for counter in counters: + address = counter.get("address_hex") or _h(_int_field(counter, "address", 0)) + name = counter.get("name_candidate") or "counter_candidate" + role = _comment_text(str(counter.get("role") or counter.get("summary") or "candidate decrementing counter")) + lines.append(f"{prefix}- {address} {name}: {role}") + evidence = _hex_join(model.get("evidence_addresses_hex")) + if opts.include_evidence and evidence: + lines.append(f"{prefix}- evidence: {evidence}") + return lines + + +def _timer_architecture_function_lines(protocol: JsonObject) -> list[str]: + model = _timer_architecture_model(protocol) + if not model: + return [] + counters = _timer_counter_models(model) + if not counters: + return [] + + lines = [ + "void frt1_ocia_candidate_tick_isr(void)", + "{", + " /* Candidate periodic tick at H'BEEA: decrement nonzero serial gate/cadence counters. */", + ] + for counter in counters: + address = _int_field(counter, "address", 0) + if address == 0: + continue + name = _safe_identifier(str(counter.get("name_candidate") or f"counter_{address:04X}")).upper() + lines.extend( + [ + f" /* {name}: {_comment_text(str(counter.get('role') or counter.get('summary') or 'candidate counter'))} */", + f" if (MEM8[{_c_hex(address)}] != 0u) {{", + f" MEM8[{_c_hex(address)}] = (u8)(MEM8[{_c_hex(address)}] - 1u);", + " }", + "", + ], + ) + lines.extend(["}", ""]) + return lines + + +def _timer_architecture_model(protocol: JsonObject) -> JsonObject: + model = protocol.get("timer_interrupt_model") + if isinstance(model, dict): + return model + if isinstance(protocol.get("gate_queue_model"), dict) or isinstance(protocol.get("periodic_resend_model"), dict): + return { + "source": "FRT1 OCIA", + "vector_address_hex": "H'BEEA", + "counters": [ + { + "address": 0xF9C0, + "address_hex": "H'F9C0", + "name_candidate": "tx_report_gate_counter_candidate", + "role": "candidate gate counter used before entering the report builder.", + }, + { + "address": 0xF9C1, + "address_hex": "H'F9C1", + "name_candidate": "rx_interbyte_timeout_candidate", + "role": "candidate RX interbyte timeout counter.", + }, + { + "address": 0xF9C6, + "address_hex": "H'F9C6", + "name_candidate": "periodic_resend_cadence_counter_candidate", + "role": "candidate periodic resend/heartbeat cadence counter.", + }, + ], + } + return {} + + +def _timer_counter_models(model: JsonObject) -> list[JsonObject]: + counters = _object_list(model.get("counters")) + if counters: + return counters + return [ + { + "address": 0xF9C0, + "address_hex": "H'F9C0", + "name_candidate": "tx_report_gate_counter_candidate", + "role": "candidate gate counter used before entering the report builder.", + }, + { + "address": 0xF9C1, + "address_hex": "H'F9C1", + "name_candidate": "rx_interbyte_timeout_candidate", + "role": "candidate RX interbyte timeout counter.", + }, + { + "address": 0xF9C6, + "address_hex": "H'F9C6", + "name_candidate": "periodic_resend_cadence_counter_candidate", + "role": "candidate periodic resend/heartbeat cadence counter.", + }, + ] + + def _command_effect_switch_lines(command: JsonObject) -> list[str]: effects = _object_list(command.get("effects"))[:3] lines = [] @@ -835,6 +960,7 @@ def _tx_functions(candidate: JsonObject, opts: SerialPseudocodeOptions) -> list[ " /* wait for transmit data register empty */", " }", "", + " /* First byte is sent synchronously; TIE enables TXI for the remaining bytes. */", " SCI1_TDR = TX_FRAME(0);", " TX_INDEX = 1u;", " SCI1_SSR &= (u8)~SCI_SSR_TDRE;", @@ -843,6 +969,11 @@ def _tx_functions(candidate: JsonObject, opts: SerialPseudocodeOptions) -> list[ "", "void sci1_txi_candidate_isr(void)", "{", + " /* TXI runs after hardware reasserts SSR.TDRE for the next transmit byte. */", + " if ((SCI1_SSR & SCI_SSR_TDRE) == 0u) {", + " return;", + " }", + "", " if (TX_INDEX < TX_FRAME_LENGTH) {", " SCI1_TDR = TX_FRAME(TX_INDEX);", " TX_INDEX = (u8)(TX_INDEX + 1u);", diff --git a/h8536/serial_reconstruction.py b/h8536/serial_reconstruction.py index 43d823c..5ca0eaf 100644 --- a/h8536/serial_reconstruction.py +++ b/h8536/serial_reconstruction.py @@ -15,6 +15,12 @@ TX_BUFFER_END = TX_CHECKSUM_ADDRESS TX_INDEX_ADDRESS = 0xF9C2 TX_FRAME_LENGTH = 6 CHECKSUM_SEED = 0x5A +FRT1_OCIA_VECTOR_ADDRESS = 0x0062 +FRT1_OCIA_ISR_ADDRESS = 0xBEEA +FRT1_TCSR_ADDRESS = 0xFE91 +POST_TX_REPORT_DELAY_ADDRESS = 0xF9C0 +SECONDARY_TX_REPORT_DELAY_ADDRESS = 0xF9C1 +PERIODIC_REPORT_COUNTDOWN_ADDRESS = 0xF9C6 RX_FRAME_START = 0xF860 RX_CHECKSUM_ADDRESS = 0xF865 @@ -60,7 +66,7 @@ def analyze_serial_reconstruction( ) -> dict[str, object]: """Reconstruct conservative serial-frame candidates from independent evidence.""" ordered = _instruction_sequence(instructions) - evidence = _collect_tx_evidence(ordered) + _collect_rx_evidence(ordered) + evidence = _collect_tx_evidence(ordered) + _collect_rx_evidence(ordered) + _collect_timer_role_evidence(ordered) candidates = [ candidate for candidate in ( @@ -69,6 +75,7 @@ def analyze_serial_reconstruction( ) if candidate is not None ] + ram_roles = _ram_roles_from_evidence(evidence) annotations: dict[int, list[str]] = {} instruction_metadata: dict[int, list[dict[str, object]]] = {} @@ -88,9 +95,25 @@ def analyze_serial_reconstruction( _instruction_metadata(candidate, item, address, comment), ) + for role in ram_roles: + for item in role["evidence"]: + if not isinstance(item, Mapping): + continue + comment = _comment_for_ram_role(role, 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( + _ram_role_instruction_metadata(role, item, address, comment), + ) + return { "kind": "serial_reconstruction", "candidates": candidates, + "ram_roles": ram_roles, "evidence": evidence, "required_evidence": { "tx": list(_TX_REQUIRED_EVIDENCE), @@ -139,6 +162,7 @@ def serial_reconstruction_json_payload(analysis: Mapping[str, object] | None) -> return { "kind": "serial_reconstruction", "candidates": [], + "ram_roles": [], "evidence": [], "required_evidence": { "tx": list(_TX_REQUIRED_EVIDENCE), @@ -148,6 +172,7 @@ def serial_reconstruction_json_payload(analysis: Mapping[str, object] | None) -> return { "kind": analysis.get("kind", "serial_reconstruction"), "candidates": analysis.get("candidates", []), + "ram_roles": analysis.get("ram_roles", []), "evidence": analysis.get("evidence", []), "required_evidence": analysis.get( "required_evidence", @@ -408,6 +433,69 @@ def _collect_rx_evidence(ordered: list[Instruction]) -> list[dict[str, object]]: return evidence +def _collect_timer_role_evidence(ordered: list[Instruction]) -> list[dict[str, object]]: + evidence: list[dict[str, object]] = [] + + tick_ack = [ + ins + for ins in ordered + if ins.address == FRT1_OCIA_ISR_ADDRESS and _is_bclr_bit(ins, FRT1_TCSR_ADDRESS, 5) + ] + if tick_ack: + evidence.append( + _evidence( + "frt1_ocia_periodic_tick_isr", + tick_ack, + summary=( + f"candidate periodic tick ISR at {h16(FRT1_OCIA_ISR_ADDRESS)} " + f"for FRT1 OCIA vector {h16(FRT1_OCIA_VECTOR_ADDRESS)} clears OCFA" + ), + vector_address=FRT1_OCIA_VECTOR_ADDRESS, + vector_address_hex=h16(FRT1_OCIA_VECTOR_ADDRESS), + isr_address=FRT1_OCIA_ISR_ADDRESS, + isr_address_hex=h16(FRT1_OCIA_ISR_ADDRESS), + ), + ) + + for role_name, address, width_bits, summary in ( + ( + "post_tx_report_delay", + POST_TX_REPORT_DELAY_ADDRESS, + 8, + "candidate post-TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + ), + ( + "secondary_tx_report_delay", + SECONDARY_TX_REPORT_DELAY_ADDRESS, + 8, + "candidate secondary TX/report delay timer is decremented by the FRT1 OCIA periodic tick ISR", + ), + ( + "periodic_report_countdown", + PERIODIC_REPORT_COUNTDOWN_ADDRESS, + 16, + "candidate periodic report countdown is decremented by the FRT1 OCIA periodic tick ISR", + ), + ): + sequence = _timer_tick_decrement_sequence(ordered, address) + if sequence: + evidence.append( + _evidence( + f"{role_name}_tick_decrement", + sequence, + summary=summary, + role_name=role_name, + ram_address=address, + ram_address_hex=h16(address), + width_bits=width_bits, + isr_address=FRT1_OCIA_ISR_ADDRESS, + isr_address_hex=h16(FRT1_OCIA_ISR_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] @@ -436,6 +524,42 @@ def _tx_candidate_from_evidence(evidence: list[dict[str, object]]) -> dict[str, "checksum_seed": CHECKSUM_SEED, "checksum_seed_hex": h16(CHECKSUM_SEED), "checksum_formula": "checksum = 0x5A ^ byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4", + "roles": [ + { + "name": "tx_frame", + "address": TX_BUFFER_START, + "address_hex": h16(TX_BUFFER_START), + "end_address": TX_BUFFER_END, + "end_address_hex": h16(TX_BUFFER_END), + "summary": "evidence-supported candidate SCI1 TX frame buffer", + }, + { + "name": "tx_checksum", + "address": TX_CHECKSUM_ADDRESS, + "address_hex": h16(TX_CHECKSUM_ADDRESS), + "checksum_seed": CHECKSUM_SEED, + "checksum_seed_hex": h16(CHECKSUM_SEED), + "summary": "evidence-supported candidate SCI1 TX XOR checksum byte", + }, + { + "name": "tx_index", + "address": TX_INDEX_ADDRESS, + "address_hex": h16(TX_INDEX_ADDRESS), + "summary": "evidence-supported candidate SCI1 TX frame index", + }, + ], + "tx_path": { + "kind": "interrupt_driven_txi", + "initial_tdr_write_address": _last_address(evidence_by_key["initial_send_from_buffer_start"]), + "initial_tdr_write_address_hex": h16(_last_address(evidence_by_key["initial_send_from_buffer_start"])), + "txi_indexed_tdr_write_address": _last_address(evidence_by_key["tx_isr_indexed_send"]), + "txi_indexed_tdr_write_address_hex": h16(_last_address(evidence_by_key["tx_isr_indexed_send"])), + "summary": ( + "initial byte is written from the TX frame buffer, then subsequent bytes are sent " + "by the TXI path when TDRE is reasserted" + ), + "tdre_caveat": "TDRE reassertion is hardware/emulator timing context; static evidence is the indexed TXI send path.", + }, "confidence": "high", "confidence_score": 0.95, "confidence_reason": "all required independent evidence groups were observed", @@ -462,6 +586,46 @@ def _tx_candidate_from_evidence(evidence: list[dict[str, object]]) -> dict[str, return candidate +def _ram_roles_from_evidence(evidence: list[dict[str, object]]) -> list[dict[str, object]]: + evidence_by_key = {str(item["kind"]): item for item in evidence} + tick = evidence_by_key.get("frt1_ocia_periodic_tick_isr") + roles: list[dict[str, object]] = [] + for role_name, address, width_bits in ( + ("post_tx_report_delay", POST_TX_REPORT_DELAY_ADDRESS, 8), + ("secondary_tx_report_delay", SECONDARY_TX_REPORT_DELAY_ADDRESS, 8), + ("periodic_report_countdown", PERIODIC_REPORT_COUNTDOWN_ADDRESS, 16), + ): + decrement = evidence_by_key.get(f"{role_name}_tick_decrement") + if decrement is None: + continue + role_evidence = [item for item in (tick, decrement) if isinstance(item, Mapping)] + roles.append( + { + "kind": "candidate_ram_role", + "name": role_name, + "address": address, + "address_hex": h16(address), + "width_bits": width_bits, + "confidence": "candidate/evidence-supported", + "summary": ( + f"{role_name} at {h16(address)} is a candidate/evidence-supported RAM timer " + f"role; FRT1 OCIA tick ISR {h16(FRT1_OCIA_ISR_ADDRESS)} decrements it" + ), + "caveat": "role name is evidence-supported from static references plus emulator-guided timer behavior, not a proved firmware symbol", + "evidence": role_evidence, + "evidence_addresses": { + str(item["kind"]): list(item["addresses"]) + for item in role_evidence + }, + "evidence_addresses_hex": { + str(item["kind"]): list(item["addresses_hex"]) + for item in role_evidence + }, + }, + ) + return roles + + 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] @@ -572,6 +736,35 @@ def _instruction_metadata( } +def _comment_for_ram_role(role: Mapping[str, object], item: Mapping[str, object]) -> str: + return ( + f"candidate/evidence-supported RAM role {role['name']} at {role['address_hex']}; " + f"evidence: {item['summary']}; confidence {role['confidence']}" + ) + + +def _ram_role_instruction_metadata( + role: Mapping[str, object], + item: Mapping[str, object], + address: int, + comment: str, +) -> dict[str, object]: + return { + "address": address, + "action": "serial_reconstruction_ram_role", + "role_name": role["name"], + "role_kind": role["kind"], + "role_address": role["address"], + "role_address_hex": role["address_hex"], + "evidence": item["kind"], + "evidence_summary": item["summary"], + "evidence_addresses": list(item["addresses"]), + "evidence_addresses_hex": list(item["addresses_hex"]), + "confidence": role["confidence"], + "comment": comment, + } + + def _buffer_region_references(ordered: list[Instruction]) -> list[Instruction]: return [ins for ins in ordered if _buffer_refs(ins)] @@ -761,6 +954,31 @@ def _rx_xor_checksum_validation(ordered: list[Instruction]) -> list[Instruction] return [] +def _timer_tick_decrement_sequence(ordered: list[Instruction], address: int) -> list[Instruction]: + for index, ins in enumerate(ordered): + if not ( + ins.address >= FRT1_OCIA_ISR_ADDRESS + and _mnemonic_root(ins.mnemonic) == "TST" + and address in ins.references + ): + continue + window = ordered[index + 1 : index + 5] + decrement = next( + ( + candidate + for candidate in window + if candidate.address >= FRT1_OCIA_ISR_ADDRESS + and _is_write_to_address(candidate, address) + and _mnemonic_root(candidate.mnemonic) in {"ADD:Q", "ADD:G", "ADDS", "SUB", "SUBS"} + and _immediate_source_value(candidate.operands) in {0xFFFF, 0xFF, 1} + ), + None, + ) + if decrement is not None and "-1" in decrement.operands: + return [ins, decrement] + return [] + + def _rx_rdrf_clear_before_rdr_read(ordered: list[Instruction]) -> list[Instruction]: for index, ins in enumerate(ordered): if not _is_bclr_bit(ins, SCI1_SSR_ADDRESS, 6): @@ -950,6 +1168,13 @@ def _dedupe_ints(values: Iterable[int]) -> list[int]: return output +def _last_address(item: Mapping[str, object]) -> int: + addresses = item.get("addresses", []) + if not isinstance(addresses, list) or not addresses: + return 0 + return int(addresses[-1]) + + def _instruction_sequence( instructions: Mapping[int, Instruction] | Iterable[Instruction], ) -> list[Instruction]: @@ -997,6 +1222,7 @@ def _operand_mentions_address(operand: str, address: int) -> bool: SCI1_TDR_ADDRESS: ("SCI1_TDR",), SCI1_SSR_ADDRESS: ("SCI1_SSR",), SCI1_RDR_ADDRESS: ("SCI1_RDR",), + FRT1_TCSR_ADDRESS: ("FRT1_TCSR",), TX_BUFFER_START: ("TX_BUFFER",), TX_CHECKSUM_ADDRESS: ("TX_CHECKSUM",), TX_INDEX_ADDRESS: ("TX_INDEX",), diff --git a/tests/test_sci_protocol.py b/tests/test_sci_protocol.py index fc9c005..39542f1 100644 --- a/tests/test_sci_protocol.py +++ b/tests/test_sci_protocol.py @@ -72,11 +72,43 @@ class SciProtocolTest(unittest.TestCase): self.assertEqual( sci_protocol_comment_for_instruction(analysis, 0x2200), - "enable SCI1 TX interrupt (TIE)", + "enable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", ) self.assertEqual( sci_protocol_comment_for_instruction(analysis, 0x2204), - "disable SCI1 TX interrupt (TIE)", + "disable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", + ) + + def test_sci1_transmit_path_comments_tdr_tdre_and_tie_timing(self): + instructions = { + 0xBA72: ins(0xBA72, "MOV:G.B", "R0, @SCI1_TDR", references=[0xFEDB]), + 0xBA7B: ins(0xBA7B, "BCLR.B", "#7, @SCI1_SSR", references=[0xFEDC]), + 0xBA7F: ins(0xBA7F, "BSET.B", "#7, @SCI1_SCR", references=[0xFEDA]), + 0xBAB5: ins(0xBAB5, "MOV:G.B", "R1, @SCI1_TDR", references=[0xFEDB]), + 0xBABB: ins(0xBABB, "BCLR.B", "#7, @SCI1_SSR", references=[0xFEDC]), + } + + analysis = analyze_sci_protocol(instructions) + + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0xBA72), + "write RS232/SCI byte to SCI1 TDR for transmission", + ) + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0xBA7B), + "clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", + ) + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0xBA7F), + "enable SCI1 TX interrupt (TIE); gates TXI when hardware sets TDRE", + ) + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0xBAB5), + "write RS232/SCI byte to SCI1 TDR for transmission", + ) + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0xBABB), + "clear SCI1 TDRE after TDR write; TXI can fire again when hardware reasserts TDRE", ) def test_receive_path_clears_rdrf_then_reads_received_byte(self): @@ -89,7 +121,7 @@ class SciProtocolTest(unittest.TestCase): self.assertEqual( sci_protocol_comment_for_instruction(analysis, 0x2300), - "clear SCI1 receive-data-full flag (RDRF)", + "clear SCI1 RDRF with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", ) self.assertEqual( sci_protocol_comment_for_instruction(analysis, 0x2304), @@ -107,15 +139,15 @@ class SciProtocolTest(unittest.TestCase): self.assertEqual( sci_protocol_comment_for_instruction(analysis, 0x2400), - "clear SCI1 overrun error flag (ORER)", + "clear SCI1 ORER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", ) self.assertEqual( sci_protocol_comment_for_instruction(analysis, 0x2404), - "clear SCI1 framing error flag (FER)", + "clear SCI1 FER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", ) self.assertEqual( sci_protocol_comment_for_instruction(analysis, 0x2408), - "clear SCI1 parity error flag (PER)", + "clear SCI1 PER with SSR R/(W)* semantics: write 0 clears latched hardware flag, write 1 preserves hardware-owned state", ) def test_immediate_scr_write_reports_protocol_control_bits(self): @@ -126,7 +158,10 @@ class SciProtocolTest(unittest.TestCase): analysis = analyze_sci_protocol(instructions) comment = sci_protocol_comment_for_instruction(analysis, 0x2500) - self.assertIn("enable SCI2 TX interrupt (TIE)", comment) + self.assertIn( + "enable SCI2 TX interrupt (TIE); gates TXI when hardware sets TDRE", + comment, + ) self.assertIn("disable SCI2 receive and receive-error interrupts (RIE)", comment) self.assertIn("enable SCI2 transmitter (TE)", comment) self.assertIn("enable SCI2 receiver (RE)", comment) diff --git a/tests/test_serial_gate.py b/tests/test_serial_gate.py index c30868d..cef92e3 100644 --- a/tests/test_serial_gate.py +++ b/tests/test_serial_gate.py @@ -73,8 +73,19 @@ def fixture_payload() -> dict[str, object]: ins(0xBECB, "BTST.B #7, @H'FAA3", references=[0xFAA3]), ins(0xBED1, "CLR.B @H'F9C3", references=[0xF9C3]), ins(0xBED5, "BSR loc_BA26", targets=[0xBA26]), + ins(0xBEEA, "BCLR.B #5, @FRT1_TCSR"), + ins(0xBEEE, "TST.B @H'F9C0", references=[0xF9C0]), + ins(0xBEF2, "BEQ loc_BEF8", targets=[0xBEF8]), + ins(0xBEF4, "ADD:Q.B #-1, @H'F9C0", references=[0xF9C0]), + ins(0xBEF8, "TST.B @H'F9C1", references=[0xF9C1]), + ins(0xBEFC, "BEQ loc_BF02", targets=[0xBF02]), + ins(0xBEFE, "ADD:Q.B #-1, @H'F9C1", references=[0xF9C1]), + ins(0xBF02, "TST.W @H'F9C6", references=[0xF9C6]), + ins(0xBF06, "BEQ loc_BF0C", targets=[0xBF0C]), + ins(0xBF08, "ADD:Q.W #-1, @H'F9C6", references=[0xF9C6]), ] return { + "vectors": [{"address": 0x0062, "name": "frt1_ocia", "target": 0xBEEA, "target_label": "vec_frt1_ocia_BEEA"}], "call_graph": {"nodes": [{"start": 0x3FD3, "label": "loc_3FD3"}, {"start": 0xBAF2, "label": "loc_BAF2"}]}, "instructions": rows, } @@ -95,12 +106,26 @@ class SerialGateTest(unittest.TestCase): self.assertTrue(analysis["evidence"]["rx_session_maintenance"]["present"]) self.assertTrue(any("0x0007" in caveat and "0x0015" in caveat for caveat in analysis["caveats"])) + def test_json_analysis_includes_frt1_tick_timer_roles(self): + analysis = analyze_serial_gate(fixture_payload()) + tick = analysis["evidence"]["timer_tick_evidence"] + + self.assertTrue(tick["present"]) + self.assertEqual(tick["vector_address_hex"], "H'0062") + self.assertEqual(tick["handler_address_hex"], "H'BEEA") + self.assertIn("FRT1_TCSR.OCFA", tick["summary"]) + roles = {role["address"]: role for role in tick["candidate_timer_roles"]} + self.assertIn("post-TX/report delay", roles[0xF9C0]["role"]) + self.assertIn("secondary delay", roles[0xF9C1]["role"]) + self.assertIn("periodic report/heartbeat", roles[0xF9C6]["role"]) + def test_summarizes_key_state_readers_and_writers(self): analysis = analyze_serial_gate(fixture_payload()) accesses = {entry["address"]: entry for entry in analysis["state_accesses"]} self.assertGreaterEqual(accesses[0xF9B5]["read_count"], 1) self.assertGreaterEqual(accesses[0xF9B5]["read_write_count"], 1) + self.assertGreaterEqual(accesses[0xF9C1]["read_write_count"], 1) self.assertGreaterEqual(accesses[0xFAA3]["write_count"], 1) self.assertIn("sample_accesses", accesses[0xFAA2]) @@ -111,6 +136,15 @@ class SerialGateTest(unittest.TestCase): self.assertIn("capture overlays/runtime queue entries", text) self.assertIn("H'F9B5", text) + def test_text_report_mentions_frt1_tick_timer_roles(self): + text = format_text_report(analyze_serial_gate(fixture_payload())) + + self.assertIn("FRT1 OCIA periodic tick countdowns: present", text) + self.assertIn("H'BEEA: BCLR.B #5, @FRT1_TCSR", text) + self.assertIn("H'F9C0: candidate post-TX/report delay countdown", text) + self.assertIn("H'F9C1: candidate secondary delay countdown", text) + self.assertIn("H'F9C6: candidate periodic report/heartbeat countdown", text) + def test_cli_json_output_and_out_file(self): with tempfile.TemporaryDirectory() as tmp: input_path = Path(tmp) / "rom.json" diff --git a/tests/test_serial_pseudocode.py b/tests/test_serial_pseudocode.py index 88ed7f6..42f9aca 100644 --- a/tests/test_serial_pseudocode.py +++ b/tests/test_serial_pseudocode.py @@ -160,12 +160,23 @@ class SerialPseudocodeTest(unittest.TestCase): self.assertIn("No SCI1 RXI/TXI DTC vector entries are present", text) self.assertIn("MAX202 pin 11 traces to H8 pin 66", text) self.assertIn("Manual/0900766b802125d0.md:15823 TDR transmit data register", text) + self.assertIn("#define SCI1_TX_FRAME_LENGTH 6u", text) + self.assertIn("#define SCI1_TX_FRAME_BASE 0xF858u", text) + self.assertIn("#define SCI1_TX_FRAME_BYTE(n) MEM8[(u16)(SCI1_TX_FRAME_BASE + (n))]", text) + self.assertIn("#define SCI1_TX_FRAME_CHECKSUM SCI1_TX_FRAME_BYTE(5u)", text) + self.assertIn("#define SCI1_TX_INDEX MEM8[0xF9C2u]", text) self.assertIn("#define TX_FRAME(n) MEM8[(u16)(0xF858u + (n))]", text) self.assertIn("#define RX_CAPTURE(n) MEM8[(u16)(0xF868u + (n))]", text) self.assertIn("checksum ^= TX_FRAME(4);", text) self.assertIn("TX_FRAME(5) = sci1_tx_candidate_checksum();", text) + self.assertIn("First byte is sent synchronously; TIE enables TXI for the remaining bytes.", text) self.assertIn("SCI1_TDR = TX_FRAME(0);", text) + self.assertIn("TX_INDEX = 1u;", text) + self.assertIn("SCI1_SCR |= SCI_SCR_TIE;", text) self.assertIn("void sci1_txi_candidate_isr(void)", text) + self.assertIn("TXI runs after hardware reasserts SSR.TDRE", text) + self.assertIn("if ((SCI1_SSR & SCI_SSR_TDRE) == 0u)", text) + self.assertIn("SCI1_TDR = TX_FRAME(TX_INDEX);", text) self.assertIn("SCI1_SSR &= (u8)~SCI_SSR_RDRF;\n byte = SCI1_RDR;", text) self.assertIn("RX_CAPTURE(RX_INDEX) = byte;", text) self.assertIn("return sci1_process_rx_candidate_frame();", text) @@ -344,6 +355,31 @@ class SerialPseudocodeTest(unittest.TestCase): }, "evidence_addresses_hex": ["H'BE90", "H'BED5"], }, + "timer_interrupt_model": { + "source": "FRT1 OCIA", + "vector_address_hex": "H'BEEA", + "counters": [ + { + "address": 0xF9C0, + "address_hex": "H'F9C0", + "name_candidate": "tx_report_gate_counter_candidate", + "role": "candidate report gate counter.", + }, + { + "address": 0xF9C1, + "address_hex": "H'F9C1", + "name_candidate": "rx_interbyte_timeout_candidate", + "role": "candidate RX interbyte timeout counter.", + }, + { + "address": 0xF9C6, + "address_hex": "H'F9C6", + "name_candidate": "periodic_resend_cadence_counter_candidate", + "role": "candidate periodic resend cadence counter.", + }, + ], + "evidence_addresses_hex": ["H'BEEA", "H'BEF4"], + }, } ] } @@ -374,6 +410,15 @@ class SerialPseudocodeTest(unittest.TestCase): self.assertIn("heartbeat/periodic resend candidate:", text) self.assertIn("F9C6 reload H'01F4", text) self.assertIn("BED5 resend path", text) + self.assertIn("interrupt/timer architecture candidate:", text) + self.assertIn("FRT1 OCIA H'BEEA appears to be a periodic tick ISR", text) + self.assertIn("H'F9C0 tx_report_gate_counter_candidate: candidate report gate counter.", text) + self.assertIn("H'F9C1 rx_interbyte_timeout_candidate: candidate RX interbyte timeout counter.", text) + self.assertIn("H'F9C6 periodic_resend_cadence_counter_candidate: candidate periodic resend cadence counter.", text) + self.assertIn("void frt1_ocia_candidate_tick_isr(void)", text) + self.assertIn("MEM8[0xF9C0u] = (u8)(MEM8[0xF9C0u] - 1u);", text) + self.assertIn("MEM8[0xF9C1u] = (u8)(MEM8[0xF9C1u] - 1u);", text) + self.assertIn("MEM8[0xF9C6u] = (u8)(MEM8[0xF9C6u] - 1u);", text) self.assertIn("candidate effect: table_write_candidate; target primary_value_table_candidate", text) def test_tx_only_option_omits_rx_functions(self): diff --git a/tests/test_serial_reconstruction.py b/tests/test_serial_reconstruction.py index a67fa30..e331f96 100644 --- a/tests/test_serial_reconstruction.py +++ b/tests/test_serial_reconstruction.py @@ -61,6 +61,17 @@ class SerialReconstructionTest(unittest.TestCase): self.assertEqual(candidate["checksum_address"], 0xF85D) self.assertEqual(candidate["tx_index_address"], 0xF9C2) self.assertEqual(candidate["checksum_seed"], 0x5A) + self.assertEqual( + [role["name"] for role in candidate["roles"]], + ["tx_frame", "tx_checksum", "tx_index"], + ) + self.assertEqual(candidate["roles"][0]["address"], 0xF858) + self.assertEqual(candidate["roles"][1]["address"], 0xF85D) + self.assertEqual(candidate["roles"][2]["address"], 0xF9C2) + self.assertEqual(candidate["tx_path"]["kind"], "interrupt_driven_txi") + self.assertEqual(candidate["tx_path"]["initial_tdr_write_address"], 0x3008) + self.assertEqual(candidate["tx_path"]["txi_indexed_tdr_write_address"], 0x3108) + self.assertIn("TDRE", candidate["tx_path"]["summary"]) self.assertEqual(candidate["confidence"], "high") self.assertEqual(candidate["confidence_score"], 0.95) self.assertEqual(candidate["missing_evidence"], []) @@ -84,8 +95,43 @@ class SerialReconstructionTest(unittest.TestCase): payload = serial_reconstruction_json_payload(analysis) self.assertEqual(payload["candidates"][0]["frame_length"], 6) + self.assertEqual(payload["candidates"][0]["roles"][1]["name"], "tx_checksum") json.dumps(payload) + def test_candidate_timer_ram_roles_from_frt1_ocia_tick(self): + instructions = { + 0xBEEA: ins(0xBEEA, "BCLR.B", "#5, @FRT1_TCSR", [0xFE91]), + 0xBEEE: ins(0xBEEE, "TST.B", "@H'F9C0", [0xF9C0]), + 0xBEF4: ins(0xBEF4, "ADD:Q.B", "#-1, @H'F9C0", [0xF9C0]), + 0xBEF8: ins(0xBEF8, "TST.B", "@H'F9C1", [0xF9C1]), + 0xBEFE: ins(0xBEFE, "ADD:Q.B", "#-1, @H'F9C1", [0xF9C1]), + 0xBF02: ins(0xBF02, "TST.W", "@H'F9C6", [0xF9C6]), + 0xBF08: ins(0xBF08, "ADD:Q.W", "#-1, @H'F9C6", [0xF9C6]), + } + + analysis = analyze_serial_reconstruction(instructions) + + self.assertEqual(analysis["candidates"], []) + roles = {role["name"]: role for role in analysis["ram_roles"]} + self.assertEqual(set(roles), {"post_tx_report_delay", "secondary_tx_report_delay", "periodic_report_countdown"}) + self.assertEqual(roles["post_tx_report_delay"]["address"], 0xF9C0) + self.assertEqual(roles["secondary_tx_report_delay"]["address"], 0xF9C1) + self.assertEqual(roles["periodic_report_countdown"]["address"], 0xF9C6) + self.assertEqual(roles["periodic_report_countdown"]["width_bits"], 16) + self.assertIn("candidate/evidence-supported", roles["post_tx_report_delay"]["confidence"]) + self.assertIn("emulator-guided timer behavior", roles["post_tx_report_delay"]["caveat"]) + + payload = serial_reconstruction_json_payload(analysis) + self.assertEqual(payload["ram_roles"][0]["name"], "post_tx_report_delay") + json.dumps(payload) + + decrement_comment = serial_reconstruction_comment_for_instruction(analysis, 0xBEF4) + self.assertIn("RAM role post_tx_report_delay", decrement_comment) + self.assertIn("FRT1 OCIA periodic tick ISR", decrement_comment) + metadata = serial_reconstruction_metadata_for_instruction(analysis, 0xBF08) + self.assertEqual(metadata[0]["action"], "serial_reconstruction_ram_role") + self.assertEqual(metadata[0]["role_name"], "periodic_report_countdown") + def test_candidate_sci1_rx_frame_length_and_checksum_validation_pattern(self): instructions = { 0x4FF0: ins(0x4FF0, "BSET.B", "#7, @H'FAA4", [0xFAA4]), diff --git a/tests/test_serial_reconstruction_integration.py b/tests/test_serial_reconstruction_integration.py index f4dc60a..a6c3f18 100644 --- a/tests/test_serial_reconstruction_integration.py +++ b/tests/test_serial_reconstruction_integration.py @@ -32,6 +32,13 @@ class SerialReconstructionIntegrationTest(unittest.TestCase): 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]), + 0xBEEA: ins(0xBEEA, "BCLR.B", "#5, @FRT1_TCSR", [0xFE91]), + 0xBEEE: ins(0xBEEE, "TST.B", "@H'F9C0", [0xF9C0]), + 0xBEF4: ins(0xBEF4, "ADD:Q.B", "#-1, @H'F9C0", [0xF9C0]), + 0xBEF8: ins(0xBEF8, "TST.B", "@H'F9C1", [0xF9C1]), + 0xBEFE: ins(0xBEFE, "ADD:Q.B", "#-1, @H'F9C1", [0xF9C1]), + 0xBF02: ins(0xBF02, "TST.W", "@H'F9C6", [0xF9C6]), + 0xBF08: ins(0xBF08, "ADD:Q.W", "#-1, @H'F9C6", [0xF9C6]), } analysis = analyze_serial_reconstruction(instructions) @@ -47,7 +54,11 @@ class SerialReconstructionIntegrationTest(unittest.TestCase): ) self.assertIn("; Serial Protocol Reconstruction", listing) self.assertIn("TX candidate: 6 bytes", listing) + self.assertIn("TX path: initial byte is written from the TX frame buffer", listing) + self.assertIn("; Serial RAM role candidates", listing) + self.assertIn("periodic_report_countdown", listing) self.assertIn("candidate/evidence-supported SCI1 6-byte TX frame", listing) + self.assertIn("RAM role post_tx_report_delay", listing) with tempfile.TemporaryDirectory() as tmp: path = Path(tmp) / "out.json" @@ -55,14 +66,19 @@ class SerialReconstructionIntegrationTest(unittest.TestCase): payload = json.loads(path.read_text(encoding="utf-8")) self.assertEqual(payload["serial_reconstruction"]["candidates"][0]["frame_length"], 6) + self.assertEqual(payload["serial_reconstruction"]["candidates"][0]["tx_path"]["kind"], "interrupt_driven_txi") + self.assertEqual(payload["serial_reconstruction"]["ram_roles"][2]["name"], "periodic_report_countdown") tdr_instruction = next(item for item in payload["instructions"] if item["address"] == 0x3038) self.assertIn("serial_reconstruction", tdr_instruction) + timer_instruction = next(item for item in payload["instructions"] if item["address"] == 0xBF08) + self.assertEqual(timer_instruction["serial_reconstruction"][0]["role_name"], "periodic_report_countdown") 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) + self.assertIn("candidate/evidence-supported RAM role periodic_report_countdown", pseudocode) if __name__ == "__main__":