diff --git a/README.md b/README.md index 2cdbad7..e8addb6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # H8/536 ROM Decompiler +The ROM used is from a SONY RCP-TX7 Camera Panel. Some of the code in this repo may be bias to the functions of that particular use case with the H8/536. + This repo now includes a standalone Python helper for the H8/536 ROM image: ```powershell @@ -33,6 +35,7 @@ To turn the structured decompile output into conservative C-like pseudocode: - Tracks SCI setup writes and can infer baud rates from SMR/BRR when `--clock-hz` is supplied. - Flags/manual-annotates TEMP-register access ordering for FRT and A/D 16-bit peripheral registers. - Scans unreached ROM ranges for ASCII strings and pointer-table candidates. +- Scans likely LCD/menu text records, groups display-text regions, and reports literal/near matches for terms such as `CONNECT`. - Emits function summaries and a direct-call graph in JSON, with optional Graphviz DOT output. - Tracks conservative per-basic-block register/control-register dataflow in JSON and comments known value changes. - Discovers RAM/external/global symbols from memory references and pointer tables, including read/write counts and xrefs. @@ -40,6 +43,7 @@ To turn the structured decompile output into conservative C-like pseudocode: - Adds Appendix A cycle estimates to JSON and can append them to ASM comments. - Summarizes straight-line block timing and backward-branch loop timing when requested. - Handles the E-clock transfer instructions `MOVFPE` and `MOVTPE`. +- Recognizes likely LCD E-clock access routines at `H'F200`/`H'F201`, including busy-flag polling and data/control writes. - Generates a separate C-like pseudocode view from the JSON, preserving labels, calls, branches, register names, inferred symbols, metadata comments, optional cycle notes, and simple structured `if`/`do while` patterns. The generated listing is written to: @@ -97,6 +101,8 @@ python h8536_pseudocode.py --help - `h8536/dataflow.py`: conservative register/control-register value tracking. - `h8536/symbols.py`: RAM/external/global symbol discovery from references and data tables. - `h8536/indirect.py`: indirect call/jump and pointer-table dispatch hints. +- `h8536/lcd_text.py`: LCD/menu text record scanning, fuzzy search, and text xrefs. +- `h8536/lcd_driver.py`: LCD E-clock access and busy-poll recognizer. - `h8536/timing.py`: block and loop cycle summaries. - `h8536/sci.py`: SCI setup tracking and baud inference. - `h8536/peripheral_access.py`: FRT/A-D TEMP-register access analysis. diff --git a/build/rom_decompiled.asm b/build/rom_decompiled.asm index 1d3d941..21c1111 100644 --- a/build/rom_decompiled.asm +++ b/build/rom_decompiled.asm @@ -10,6 +10,7 @@ ; - The register field is H'FE80-H'FFFF; names below come from appendix B. ; - @aa:8 short absolute operands use BR as the upper address byte. ; - SCI baud inference uses section 14.2.8 BRR formulas when SMR/BRR are known. +; - LCD inference treats E-clock H'F200/H'F201 accesses as status/control and data candidates. ; - Pass --clock-hz to convert SCI BRR settings into numeric baud rates. ; - Cycle counts use Appendix A tables A-7/A-8 for on-chip access with no external wait states. @@ -223,6 +224,82 @@ ; mem_F10E H'F10E program_or_external memory r=0 w=1 width=byte ; ... 206 more symbols omitted from listing header +; LCD/Text Scan +; search 'CONNECT': not literal, hits=0 +; near: H'A025 'COMPLETED', H'8E79 'ON CONT1 OFF~X', H'8F55 'ON CONT2 OFF~X', H'94A9 'ON' +; LCD text regions +; region H'63D7-H'6758 count=15 'OPERATION', 'PAINT', 'OPERATION', 'IRIS/M.BLK' +; region H'67E0-H'6831 count=2 'TLCS Xg', 'AGC GAIN AE Xh' +; region H'6A4F-H'6C47 count=8 'AUTO FUNC XjO', 'A.IRIS MODE Xj', 'AI BACK.L~Xj', 'AUTO FUNC Xk=' +; region H'6F84-H'6FC0 count=2 'OTHERS Xo', 'SHUTTER Xo' +; region H'7052-H'7477 count=15 'SET RCP', 'MASTER', 'OTHERS Xp', 'COPY TO SLAVES~Xp' +; region H'757A-H'7824 count=14 'BARS TYPE Xuz', 'SMPTE Xu', 'SPLIT Xu', 'FULLFIELD 75% Xu' +; region H'78B5-H'792F count=4 'OTHERS Xx', 'WHITE BLACK~Xx', 'COMM LINK ITEM-2Xx', 'FLARE Xy' +; region H'819C-H'87A9 count=28 'SHADING X', 'WHITE~X', 'SHADING AUTO SETX', 'BLACK~X' +; region H'883D-H'8959 count=7 'MATRIX X', 'STD FL~X', 'PRESET MATRIX X', 'H.SAT SPCL~X' +; region H'8A0C-H'8BAC count=7 'MATRIX X', 'ON SKIN OFF~X', 'SAT HUE X', 'MATRIX X' +; region H'8CB7-H'8CFD count=2 'FILTER X', '1 2 3 4 X' +; region H'8E57-H'8EA7 count=3 'LENS X', 'ON CONT1 OFF~X', 'FOCUS ZOOM X' +; ... 23 more LCD text regions +; LCD text candidates +; text H'41B0 len=35 medium '01020304050607080910111213141516X' +; text H'5B55 len=10 high '0123456789' +; text H'60F6 len=16 high '0123456789ABCDEF' +; text H'63D7 len=10 high 'OPERATION' xrefs=1 +; text H'63F5 len=10 high 'PAINT' xrefs=1 +; text H'6443 len=10 high 'OPERATION' xrefs=1 +; text H'6461 len=10 high 'IRIS/M.BLK' xrefs=1 +; text H'6490 len=10 high 'OPERATION' xrefs=1 +; text H'64AE len=10 high 'LOCK' xrefs=1 +; text H'652F len=19 high 'DYNA LATITUDE Xe/' xrefs=1 +; text H'6551 len=18 medium 'HIGH LOW~XeP' xrefs=1 +; text H'65C9 len=18 medium 'BLACK STR Xe' xrefs=1 +; text H'6644 len=19 medium 'BLACK STR XfD' xrefs=1 +; text H'6665 len=19 medium 'STRETCH LEVEL Xfe' xrefs=1 +; text H'6683 len=18 high 'POINT1 POINT2Xf' xrefs=1 +; text H'6706 len=18 medium 'BLACK STR Xg' xrefs=1 +; text H'6727 len=19 medium "COMPRESS LEVEL Xg'" xrefs=1 +; text H'6745 len=19 high 'POINT1 POINT2XgE' xrefs=1 +; text H'67E0 len=18 medium 'TLCS Xg' xrefs=1 +; text H'681F len=18 medium 'AGC GAIN AE Xh' xrefs=1 +; text H'693B len=19 medium 'AUTO FUNC Xi;' xrefs=1 +; text H'6A4F len=19 medium 'AUTO FUNC XjO' xrefs=1 +; text H'6A8E len=18 medium 'A.IRIS MODE Xj' xrefs=1 +; text H'6AAD len=17 medium 'AI BACK.L~Xj' xrefs=1 +; text H'6B3D len=19 medium 'AUTO FUNC Xk=' xrefs=1 +; text H'6B5E len=19 medium 'AUTO FOCUS Xk^' xrefs=1 +; text H'6BEF len=18 medium 'DIAG Xk' xrefs=1 +; text H'6C16 len=18 medium 'DIAG DATA Xl' xrefs=1 +; text H'6C35 len=18 medium 'RESET REQ~Xl4' xrefs=1 +; text H'6F84 len=18 medium 'OTHERS Xo' xrefs=1 +; text H'6FAE len=18 medium 'SHUTTER Xo' xrefs=1 +; text H'7052 len=14 medium 'SET RCP' xrefs=1 +; text H'706F len=14 medium 'MASTER' xrefs=1 +; text H'709F len=18 medium 'OTHERS Xp' xrefs=1 +; text H'70C0 len=18 medium 'COPY TO SLAVES~Xp' xrefs=1 +; text H'7144 len=19 medium 'CAM ID SET~XqD' xrefs=1 +; text H'71C9 len=18 medium 'OTHERS Xq' xrefs=1 +; text H'71F9 len=18 medium 'CAM ID IND Xq' xrefs=1 +; text H'7213 len=18 medium 'TITLE IND Xr' xrefs=1 +; text H'72A5 len=18 medium 'OTHERS Xr' xrefs=1 +; text H'72C7 len=17 medium 'CAM BARS~Xr' xrefs=1 +; text H'72E4 len=18 medium 'CLOCK IND Xr' xrefs=1 +; text H'7369 len=19 medium 'OTHERS Xsi' xrefs=1 +; text H'7393 len=18 high 'CENTER MARKER Xs' xrefs=1 +; text H'7425 len=19 medium 'OTHERS Xt%' xrefs=1 +; text H'7464 len=19 medium 'SAFETY ZONE Xtd' xrefs=1 +; text H'757A len=19 medium 'BARS TYPE Xuz' xrefs=1 +; text H'75A4 len=18 medium 'SMPTE Xu' xrefs=1 +; ... 192 more LCD text candidates + +; LCD Driver Candidates +; H'F200 lcd_status_control status/control register inferred from busy polling and command writes +; H'F201 lcd_data data register inferred from paired data reads/writes +; LCD routines +; routine H'3F40-H'3F74 lcd_wait_and_transfer lcd_command_or_address_write, lcd_data_read, lcd_data_write, lcd_status_read +; LCD busy loops +; loop H'3F4A->H'3F51 LCD busy-flag poll: read H'F200, test bit 7, branch until clear + ; Timing Summary ; Straight-line blocks ; block H'1000-H'10CB vec_reset_1000 ins=42 cycles=371 unknown=0 @@ -2135,23 +2212,23 @@ loc_3F40: 3F46: 0C 06 00 48 ORC.W #H'0600, SR ; cycles=4 loc_3F4A: -3F4A: 15 F2 00 00 80 MOVFPE.B @H'F200, R0 ; refs mem_F200 in program_or_external; cycles=13 -3F4F: A0 F7 BTST.B #7, R0 ; cycles=2 -3F51: 26 F7 BNE loc_3F4A ; cycles=3/8 nt/t +3F4A: 15 F2 00 00 80 MOVFPE.B @H'F200, R0 ; LCD status read from E-clock H'F200; LCD busy-flag poll: read H'F200, test bit 7, branch until clear; refs mem_F200 in program_or_external; cycles=13 +3F4F: A0 F7 BTST.B #7, R0 ; LCD busy-flag poll: read H'F200, test bit 7, branch until clear; cycles=2 +3F51: 26 F7 BNE loc_3F4A ; LCD busy-flag poll: read H'F200, test bit 7, branch until clear; cycles=3/8 nt/t 3F53: AC F8 BTST.W #8, R4 ; cycles=3 3F55: 26 16 BNE loc_3F6D ; cycles=3/8 nt/t 3F57: AC F9 BTST.W #9, R4 ; cycles=3 3F59: 26 07 BNE loc_3F62 ; cycles=3/8 nt/t -3F5B: 15 F2 00 00 94 MOVTPE.B R4, @H'F200 ; refs mem_F200 in program_or_external; cycles=13 +3F5B: 15 F2 00 00 94 MOVTPE.B R4, @H'F200 ; LCD command/address write to E-clock H'F200; refs mem_F200 in program_or_external; cycles=13 3F60: 20 10 BRA loc_3F72 ; cycles=7 loc_3F62: -3F62: 15 F2 01 00 94 MOVTPE.B R4, @H'F201 ; refs mem_F201 in program_or_external; cycles=13 +3F62: 15 F2 01 00 94 MOVTPE.B R4, @H'F201 ; LCD data write to E-clock H'F201; refs mem_F201 in program_or_external; cycles=13 3F67: 1D FB 00 08 ADD:Q.W #1, @H'FB00 ; refs ram_FB00 in on_chip_ram; cycles=8 3F6B: 20 05 BRA loc_3F72 ; cycles=8 loc_3F6D: -3F6D: 15 F2 01 00 84 MOVFPE.B @H'F201, R4 ; refs mem_F201 in program_or_external; cycles=13 +3F6D: 15 F2 01 00 84 MOVFPE.B @H'F201, R4 ; LCD data read from E-clock H'F201; refs mem_F201 in program_or_external; cycles=13 loc_3F72: 3F72: CF 88 LDC.W @R7+, SR ; cycles=7 diff --git a/build/rom_decompiled.json b/build/rom_decompiled.json index 1b5da1f..211e2c4 100644 --- a/build/rom_decompiled.json +++ b/build/rom_decompiled.json @@ -41530,6 +41530,6551 @@ "65063": "ram_FE27" } }, + "lcd_text": { + "strings": [ + { + "address": 16816, + "length": 35, + "text": " 01020304050607080910111213141516X", + "trimmed": "01020304050607080910111213141516X", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "segments": [ + { + "width": 10, + "chunks": [ + " 01020304", + "0506070809", + "1011121314", + "1516X" + ] + }, + { + "width": 16, + "chunks": [ + " 01020304050607", + "0809101112131415", + "16X" + ] + } + ] + }, + { + "address": 23381, + "length": 10, + "text": "0123456789", + "trimmed": "0123456789", + "kind": "printable_run", + "score": 1.15, + "confidence": "high" + }, + { + "address": 24822, + "length": 16, + "text": "0123456789ABCDEF", + "trimmed": "0123456789ABCDEF", + "kind": "printable_run", + "score": 1.15, + "confidence": "high" + }, + { + "address": 25559, + "length": 10, + "text": "OPERATION ", + "trimmed": "OPERATION", + "kind": "ff_terminated", + "score": 1.47, + "confidence": "high", + "ff_terminators": 3, + "xrefs": [ + { + "address": 25572, + "kind": "raw_mov_iw", + "target": 25556, + "delta": -3, + "register": "R0", + "instruction": "MOV:I.W #H'63D4, R0", + "following_bsr": { + "address": 25575, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 25589, + "length": 10, + "text": " PAINT ", + "trimmed": "PAINT", + "kind": "ff_terminated", + "score": 1.47, + "confidence": "high", + "ff_terminators": 3, + "xrefs": [ + { + "address": 25602, + "kind": "raw_mov_iw", + "target": 25586, + "delta": -3, + "register": "R0", + "instruction": "MOV:I.W #H'63F2, R0", + "following_bsr": { + "address": 25605, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 25667, + "length": 10, + "text": "OPERATION ", + "trimmed": "OPERATION", + "kind": "ff_terminated", + "score": 1.47, + "confidence": "high", + "ff_terminators": 3, + "xrefs": [ + { + "address": 25680, + "kind": "raw_mov_iw", + "target": 25664, + "delta": -3, + "register": "R0", + "instruction": "MOV:I.W #H'6440, R0", + "following_bsr": { + "address": 25683, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 25697, + "length": 10, + "text": "IRIS/M.BLK", + "trimmed": "IRIS/M.BLK", + "kind": "ff_terminated", + "score": 1.41, + "confidence": "high", + "ff_terminators": 3, + "xrefs": [ + { + "address": 25710, + "kind": "raw_mov_iw", + "target": 25694, + "delta": -3, + "register": "R0", + "instruction": "MOV:I.W #H'645E, R0", + "following_bsr": { + "address": 25713, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 25744, + "length": 10, + "text": "OPERATION ", + "trimmed": "OPERATION", + "kind": "ff_terminated", + "score": 1.47, + "confidence": "high", + "ff_terminators": 3, + "xrefs": [ + { + "address": 25757, + "kind": "raw_mov_iw", + "target": 25741, + "delta": -3, + "register": "R0", + "instruction": "MOV:I.W #H'648D, R0", + "following_bsr": { + "address": 25760, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 25774, + "length": 10, + "text": " LOCK ", + "trimmed": "LOCK", + "kind": "ff_terminated", + "score": 1.47, + "confidence": "high", + "ff_terminators": 3, + "xrefs": [ + { + "address": 25787, + "kind": "raw_mov_iw", + "target": 25771, + "delta": -3, + "register": "R0", + "instruction": "MOV:I.W #H'64AB, R0", + "following_bsr": { + "address": 25790, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 25903, + "length": 19, + "text": " DYNA LATITUDE Xe/", + "trimmed": "DYNA LATITUDE Xe/", + "kind": "printable_run", + "score": 1.064, + "confidence": "high", + "xrefs": [ + { + "address": 25919, + "kind": "raw_mov_iw", + "target": 25903, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'652F, R0", + "following_bsr": { + "address": 25922, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 25937, + "length": 18, + "text": "HIGH LOW~XeP", + "trimmed": "HIGH LOW~XeP", + "kind": "printable_run", + "score": 0.981, + "confidence": "medium", + "xrefs": [ + { + "address": 25952, + "kind": "raw_mov_iw", + "target": 25936, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'6550, R0", + "following_bsr": { + "address": 25955, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 26057, + "length": 18, + "text": " BLACK STR Xe", + "trimmed": "BLACK STR Xe", + "kind": "printable_run", + "score": 1.04, + "confidence": "medium", + "xrefs": [ + { + "address": 26073, + "kind": "raw_mov_iw", + "target": 26057, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'65C9, R0", + "following_bsr": { + "address": 26076, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 26180, + "length": 19, + "text": " BLACK STR XfD", + "trimmed": "BLACK STR XfD", + "kind": "printable_run", + "score": 1.047, + "confidence": "medium", + "xrefs": [ + { + "address": 26196, + "kind": "raw_mov_iw", + "target": 26180, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6644, R0", + "following_bsr": { + "address": 26199, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 26213, + "length": 19, + "text": " STRETCH LEVEL Xfe", + "trimmed": "STRETCH LEVEL Xfe", + "kind": "printable_run", + "score": 1.044, + "confidence": "medium", + "xrefs": [ + { + "address": 26229, + "kind": "raw_mov_iw", + "target": 26213, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6665, R0", + "following_bsr": { + "address": 26232, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 26243, + "length": 18, + "text": "POINT1 POINT2Xf", + "trimmed": "POINT1 POINT2Xf", + "kind": "printable_run", + "score": 1.069, + "confidence": "high", + "xrefs": [ + { + "address": 26259, + "kind": "raw_mov_iw", + "target": 26243, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6683, R0", + "following_bsr": { + "address": 26262, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 26374, + "length": 18, + "text": " BLACK STR Xg", + "trimmed": "BLACK STR Xg", + "kind": "printable_run", + "score": 1.04, + "confidence": "medium", + "xrefs": [ + { + "address": 26390, + "kind": "raw_mov_iw", + "target": 26374, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6706, R0", + "following_bsr": { + "address": 26393, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 26407, + "length": 19, + "text": " COMPRESS LEVEL Xg'", + "trimmed": "COMPRESS LEVEL Xg'", + "kind": "printable_run", + "score": 1.036, + "confidence": "medium", + "xrefs": [ + { + "address": 26423, + "kind": "raw_mov_iw", + "target": 26407, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6727, R0", + "following_bsr": { + "address": 26426, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 26437, + "length": 19, + "text": "POINT1 POINT2XgE", + "trimmed": "POINT1 POINT2XgE", + "kind": "printable_run", + "score": 1.074, + "confidence": "high", + "xrefs": [ + { + "address": 26453, + "kind": "raw_mov_iw", + "target": 26437, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6745, R0", + "following_bsr": { + "address": 26456, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 26592, + "length": 18, + "text": " TLCS Xg", + "trimmed": "TLCS Xg", + "kind": "printable_run", + "score": 0.996, + "confidence": "medium", + "xrefs": [ + { + "address": 26608, + "kind": "raw_mov_iw", + "target": 26592, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'67E0, R0", + "following_bsr": { + "address": 26611, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 26655, + "length": 18, + "text": " AGC GAIN AE Xh", + "trimmed": "AGC GAIN AE Xh", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 26671, + "kind": "raw_mov_iw", + "target": 26655, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'681F, R0", + "following_bsr": { + "address": 26674, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 26939, + "length": 19, + "text": " AUTO FUNC Xi;", + "trimmed": "AUTO FUNC Xi;", + "kind": "printable_run", + "score": 0.984, + "confidence": "medium", + "xrefs": [ + { + "address": 26955, + "kind": "raw_mov_iw", + "target": 26939, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'693B, R0", + "following_bsr": { + "address": 26958, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 27215, + "length": 19, + "text": " AUTO FUNC XjO", + "trimmed": "AUTO FUNC XjO", + "kind": "printable_run", + "score": 1.047, + "confidence": "medium", + "xrefs": [ + { + "address": 27231, + "kind": "raw_mov_iw", + "target": 27215, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6A4F, R0", + "following_bsr": { + "address": 27234, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 27278, + "length": 18, + "text": " A.IRIS MODE Xj", + "trimmed": "A.IRIS MODE Xj", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 27294, + "kind": "raw_mov_iw", + "target": 27278, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6A8E, R0", + "following_bsr": { + "address": 27297, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 27309, + "length": 17, + "text": "AI BACK.L~Xj", + "trimmed": "AI BACK.L~Xj", + "kind": "printable_run", + "score": 0.965, + "confidence": "medium", + "xrefs": [ + { + "address": 27324, + "kind": "raw_mov_iw", + "target": 27308, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'6AAC, R0", + "following_bsr": { + "address": 27327, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 27453, + "length": 19, + "text": " AUTO FUNC Xk=", + "trimmed": "AUTO FUNC Xk=", + "kind": "printable_run", + "score": 0.984, + "confidence": "medium", + "xrefs": [ + { + "address": 27469, + "kind": "raw_mov_iw", + "target": 27453, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6B3D, R0", + "following_bsr": { + "address": 27472, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 27486, + "length": 19, + "text": " AUTO FOCUS Xk^", + "trimmed": "AUTO FOCUS Xk^", + "kind": "printable_run", + "score": 0.997, + "confidence": "medium", + "xrefs": [ + { + "address": 27502, + "kind": "raw_mov_iw", + "target": 27486, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6B5E, R0", + "following_bsr": { + "address": 27505, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 27631, + "length": 18, + "text": " DIAG Xk", + "trimmed": "DIAG Xk", + "kind": "printable_run", + "score": 0.996, + "confidence": "medium", + "xrefs": [ + { + "address": 27647, + "kind": "raw_mov_iw", + "target": 27631, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6BEF, R0", + "following_bsr": { + "address": 27650, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 27670, + "length": 18, + "text": " DIAG DATA Xl", + "trimmed": "DIAG DATA Xl", + "kind": "printable_run", + "score": 1.04, + "confidence": "medium", + "xrefs": [ + { + "address": 27686, + "kind": "raw_mov_iw", + "target": 27670, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6C16, R0", + "following_bsr": { + "address": 27689, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 27701, + "length": 18, + "text": "RESET REQ~Xl4", + "trimmed": "RESET REQ~Xl4", + "kind": "printable_run", + "score": 0.992, + "confidence": "medium", + "xrefs": [ + { + "address": 27716, + "kind": "raw_mov_iw", + "target": 27700, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'6C34, R0", + "following_bsr": { + "address": 27719, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 28548, + "length": 18, + "text": " OTHERS Xo", + "trimmed": "OTHERS Xo", + "kind": "printable_run", + "score": 1.018, + "confidence": "medium", + "xrefs": [ + { + "address": 28564, + "kind": "raw_mov_iw", + "target": 28548, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6F84, R0", + "following_bsr": { + "address": 28567, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 28590, + "length": 18, + "text": " SHUTTER Xo", + "trimmed": "SHUTTER Xo", + "kind": "printable_run", + "score": 1.032, + "confidence": "medium", + "xrefs": [ + { + "address": 28606, + "kind": "raw_mov_iw", + "target": 28590, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'6FAE, R0", + "following_bsr": { + "address": 28609, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 28754, + "length": 14, + "text": " SET RCP ", + "trimmed": "SET RCP", + "kind": "printable_run", + "score": 0.971, + "confidence": "medium", + "xrefs": [ + { + "address": 28769, + "kind": "raw_mov_iw", + "target": 28753, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'7051, R0", + "following_bsr": { + "address": 28772, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 28783, + "length": 14, + "text": " MASTER ", + "trimmed": "MASTER", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 28798, + "kind": "raw_mov_iw", + "target": 28782, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'706E, R0", + "following_bsr": { + "address": 28801, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 28831, + "length": 18, + "text": " OTHERS Xp", + "trimmed": "OTHERS Xp", + "kind": "printable_run", + "score": 1.018, + "confidence": "medium", + "xrefs": [ + { + "address": 28847, + "kind": "raw_mov_iw", + "target": 28831, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'709F, R0", + "following_bsr": { + "address": 28850, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 28864, + "length": 18, + "text": " COPY TO SLAVES~Xp", + "trimmed": "COPY TO SLAVES~Xp", + "kind": "printable_run", + "score": 1.029, + "confidence": "medium", + "xrefs": [ + { + "address": 28880, + "kind": "raw_mov_iw", + "target": 28864, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'70C0, R0", + "following_bsr": { + "address": 28883, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 28996, + "length": 19, + "text": " CAM ID SET~XqD", + "trimmed": "CAM ID SET~XqD", + "kind": "printable_run", + "score": 1.004, + "confidence": "medium", + "xrefs": [ + { + "address": 29012, + "kind": "raw_mov_iw", + "target": 28996, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7144, R0", + "following_bsr": { + "address": 29015, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29129, + "length": 18, + "text": " OTHERS Xq", + "trimmed": "OTHERS Xq", + "kind": "printable_run", + "score": 1.018, + "confidence": "medium", + "xrefs": [ + { + "address": 29145, + "kind": "raw_mov_iw", + "target": 29129, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'71C9, R0", + "following_bsr": { + "address": 29148, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29177, + "length": 18, + "text": " CAM ID IND Xq", + "trimmed": "CAM ID IND Xq", + "kind": "printable_run", + "score": 1.04, + "confidence": "medium", + "xrefs": [ + { + "address": 29193, + "kind": "raw_mov_iw", + "target": 29177, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'71F9, R0", + "following_bsr": { + "address": 29196, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29203, + "length": 18, + "text": " TITLE IND Xr", + "trimmed": "TITLE IND Xr", + "kind": "printable_run", + "score": 1.04, + "confidence": "medium", + "xrefs": [ + { + "address": 29219, + "kind": "raw_mov_iw", + "target": 29203, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7213, R0", + "following_bsr": { + "address": 29222, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29349, + "length": 18, + "text": " OTHERS Xr", + "trimmed": "OTHERS Xr", + "kind": "printable_run", + "score": 1.018, + "confidence": "medium", + "xrefs": [ + { + "address": 29365, + "kind": "raw_mov_iw", + "target": 29349, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'72A5, R0", + "following_bsr": { + "address": 29368, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29383, + "length": 17, + "text": "CAM BARS~Xr", + "trimmed": "CAM BARS~Xr", + "kind": "printable_run", + "score": 0.971, + "confidence": "medium", + "xrefs": [ + { + "address": 29398, + "kind": "raw_mov_iw", + "target": 29382, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'72C6, R0", + "following_bsr": { + "address": 29401, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 29412, + "length": 18, + "text": " CLOCK IND Xr", + "trimmed": "CLOCK IND Xr", + "kind": "printable_run", + "score": 1.04, + "confidence": "medium", + "xrefs": [ + { + "address": 29428, + "kind": "raw_mov_iw", + "target": 29412, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'72E4, R0", + "following_bsr": { + "address": 29431, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29545, + "length": 19, + "text": " OTHERS Xsi", + "trimmed": "OTHERS Xsi", + "kind": "printable_run", + "score": 0.983, + "confidence": "medium", + "xrefs": [ + { + "address": 29561, + "kind": "raw_mov_iw", + "target": 29545, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7369, R0", + "following_bsr": { + "address": 29564, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29587, + "length": 18, + "text": " CENTER MARKER Xs", + "trimmed": "CENTER MARKER Xs", + "kind": "printable_run", + "score": 1.076, + "confidence": "high", + "xrefs": [ + { + "address": 29603, + "kind": "raw_mov_iw", + "target": 29587, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7393, R0", + "following_bsr": { + "address": 29606, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29733, + "length": 19, + "text": " OTHERS Xt%", + "trimmed": "OTHERS Xt%", + "kind": "printable_run", + "score": 1.007, + "confidence": "medium", + "xrefs": [ + { + "address": 29749, + "kind": "raw_mov_iw", + "target": 29733, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7425, R0", + "following_bsr": { + "address": 29752, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 29796, + "length": 19, + "text": " SAFETY ZONE Xtd", + "trimmed": "SAFETY ZONE Xtd", + "kind": "printable_run", + "score": 1.026, + "confidence": "medium", + "xrefs": [ + { + "address": 29812, + "kind": "raw_mov_iw", + "target": 29796, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7464, R0", + "following_bsr": { + "address": 29815, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30074, + "length": 19, + "text": " BARS TYPE Xuz", + "trimmed": "BARS TYPE Xuz", + "kind": "printable_run", + "score": 1.006, + "confidence": "medium", + "xrefs": [ + { + "address": 30090, + "kind": "raw_mov_iw", + "target": 30074, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'757A, R0", + "following_bsr": { + "address": 30093, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30116, + "length": 18, + "text": " SMPTE Xu", + "trimmed": "SMPTE Xu", + "kind": "printable_run", + "score": 1.008, + "confidence": "medium", + "xrefs": [ + { + "address": 30132, + "kind": "raw_mov_iw", + "target": 30116, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'75A4, R0" + } + ], + "xref_count": 1 + }, + { + "address": 30140, + "length": 18, + "text": " SPLIT Xu", + "trimmed": "SPLIT Xu", + "kind": "printable_run", + "score": 1.008, + "confidence": "medium", + "xrefs": [ + { + "address": 30156, + "kind": "raw_mov_iw", + "target": 30140, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'75BC, R0" + } + ], + "xref_count": 1 + }, + { + "address": 30176, + "length": 18, + "text": " FULLFIELD 75% Xu", + "trimmed": "FULLFIELD 75% Xu", + "kind": "printable_run", + "score": 1.059, + "confidence": "high", + "xrefs": [ + { + "address": 30192, + "kind": "raw_mov_iw", + "target": 30176, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'75E0, R0" + } + ], + "xref_count": 1 + }, + { + "address": 30199, + "length": 18, + "text": " EBU 75% Xu", + "trimmed": "EBU 75% Xu", + "kind": "printable_run", + "score": 0.996, + "confidence": "medium", + "xrefs": [ + { + "address": 30215, + "kind": "raw_mov_iw", + "target": 30199, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'75F7, R0" + } + ], + "xref_count": 1 + }, + { + "address": 30234, + "length": 18, + "text": " FULLFIELD100% Xv", + "trimmed": "FULLFIELD100% Xv", + "kind": "printable_run", + "score": 1.071, + "confidence": "high", + "xrefs": [ + { + "address": 30250, + "kind": "raw_mov_iw", + "target": 30234, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'761A, R0" + } + ], + "xref_count": 1 + }, + { + "address": 30257, + "length": 20, + "text": " EBU 100% Xv1 ", + "trimmed": "EBU 100% Xv1", + "kind": "printable_run", + "score": 1.02, + "confidence": "medium", + "xrefs": [ + { + "address": 30273, + "kind": "raw_mov_iw", + "target": 30257, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7631, R0" + } + ], + "xref_count": 1 + }, + { + "address": 30280, + "length": 20, + "text": " SNG XvH ", + "trimmed": "SNG XvH", + "kind": "printable_run", + "score": 0.992, + "confidence": "medium", + "xrefs": [ + { + "address": 30296, + "kind": "raw_mov_iw", + "target": 30280, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7648, R0" + } + ], + "xref_count": 1 + }, + { + "address": 30362, + "length": 18, + "text": " OTHERS Xv", + "trimmed": "OTHERS Xv", + "kind": "printable_run", + "score": 1.018, + "confidence": "medium", + "xrefs": [ + { + "address": 30378, + "kind": "raw_mov_iw", + "target": 30362, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'769A, R0", + "following_bsr": { + "address": 30381, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30404, + "length": 18, + "text": " SCREEN MODE Xv", + "trimmed": "SCREEN MODE Xv", + "kind": "printable_run", + "score": 1.059, + "confidence": "high", + "xrefs": [ + { + "address": 30420, + "kind": "raw_mov_iw", + "target": 30404, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'76C4, R0", + "following_bsr": { + "address": 30423, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30529, + "length": 19, + "text": " 4:3 XwA", + "trimmed": "4:3 XwA", + "kind": "printable_run", + "score": 0.971, + "confidence": "medium", + "xrefs": [ + { + "address": 30545, + "kind": "raw_mov_iw", + "target": 30529, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'7741, R0", + "following_bsr": { + "address": 30548, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30666, + "length": 18, + "text": " OTHERS Xw", + "trimmed": "OTHERS Xw", + "kind": "printable_run", + "score": 1.018, + "confidence": "medium", + "xrefs": [ + { + "address": 30682, + "kind": "raw_mov_iw", + "target": 30666, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'77CA, R0", + "following_bsr": { + "address": 30685, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30708, + "length": 18, + "text": "COMM LINK ITEM-1Xw", + "trimmed": "COMM LINK ITEM-1Xw", + "kind": "printable_run", + "score": 1.075, + "confidence": "high", + "xrefs": [ + { + "address": 30724, + "kind": "raw_mov_iw", + "target": 30708, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'77F4, R0", + "following_bsr": { + "address": 30727, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30739, + "length": 17, + "text": "GAIN SHUTTER~Xx", + "trimmed": "GAIN SHUTTER~Xx", + "kind": "printable_run", + "score": 1.018, + "confidence": "medium", + "xrefs": [ + { + "address": 30754, + "kind": "raw_mov_iw", + "target": 30738, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'7812, R0", + "following_bsr": { + "address": 30757, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30901, + "length": 18, + "text": " OTHERS Xx", + "trimmed": "OTHERS Xx", + "kind": "printable_run", + "score": 1.018, + "confidence": "medium", + "xrefs": [ + { + "address": 30917, + "kind": "raw_mov_iw", + "target": 30901, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'78B5, R0", + "following_bsr": { + "address": 30920, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30935, + "length": 17, + "text": "WHITE BLACK~Xx", + "trimmed": "WHITE BLACK~Xx", + "kind": "printable_run", + "score": 1.006, + "confidence": "medium", + "xrefs": [ + { + "address": 30950, + "kind": "raw_mov_iw", + "target": 30934, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'78D6, R0", + "following_bsr": { + "address": 30953, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 30964, + "length": 18, + "text": "COMM LINK ITEM-2Xx", + "trimmed": "COMM LINK ITEM-2Xx", + "kind": "printable_run", + "score": 1.075, + "confidence": "high", + "xrefs": [ + { + "address": 30980, + "kind": "raw_mov_iw", + "target": 30964, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'78F4, R0", + "following_bsr": { + "address": 30983, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 31006, + "length": 17, + "text": "FLARE Xy", + "trimmed": "FLARE Xy", + "kind": "printable_run", + "score": 0.994, + "confidence": "medium", + "xrefs": [ + { + "address": 31021, + "kind": "raw_mov_iw", + "target": 31005, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'791D, R0", + "following_bsr": { + "address": 31024, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33180, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 33196, + "kind": "raw_mov_iw", + "target": 33180, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'819C, R0", + "following_bsr": { + "address": 33199, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33213, + "length": 17, + "text": " WHITE~X", + "trimmed": "WHITE~X", + "kind": "printable_run", + "score": 1.007, + "confidence": "medium", + "xrefs": [ + { + "address": 33229, + "kind": "raw_mov_iw", + "target": 33213, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'81BD, R0", + "following_bsr": { + "address": 33232, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 33243, + "length": 17, + "text": "SHADING AUTO SETX", + "trimmed": "SHADING AUTO SETX", + "kind": "printable_run", + "score": 1.126, + "confidence": "high", + "xrefs": [ + { + "address": 33259, + "kind": "raw_mov_iw", + "target": 33243, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'81DB, R0", + "following_bsr": { + "address": 33262, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33273, + "length": 17, + "text": " BLACK~X", + "trimmed": "BLACK~X", + "kind": "printable_run", + "score": 1.007, + "confidence": "medium", + "xrefs": [ + { + "address": 33289, + "kind": "raw_mov_iw", + "target": 33273, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'81F9, R0", + "following_bsr": { + "address": 33292, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33361, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 33377, + "kind": "raw_mov_iw", + "target": 33361, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8251, R0", + "following_bsr": { + "address": 33380, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33394, + "length": 17, + "text": " WHITE V SAW X", + "trimmed": "WHITE V SAW X", + "kind": "printable_run", + "score": 1.083, + "confidence": "high", + "xrefs": [ + { + "address": 33410, + "kind": "raw_mov_iw", + "target": 33394, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8272, R0", + "following_bsr": { + "address": 33413, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33424, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 33440, + "kind": "raw_mov_iw", + "target": 33424, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8290, R0", + "following_bsr": { + "address": 33443, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 33545, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 33561, + "kind": "raw_mov_iw", + "target": 33545, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8309, R0", + "following_bsr": { + "address": 33564, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33578, + "length": 17, + "text": " WHITE V PARA X", + "trimmed": "WHITE V PARA X", + "kind": "printable_run", + "score": 1.097, + "confidence": "high", + "xrefs": [ + { + "address": 33594, + "kind": "raw_mov_iw", + "target": 33578, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'832A, R0", + "following_bsr": { + "address": 33597, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33608, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 33624, + "kind": "raw_mov_iw", + "target": 33608, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8348, R0", + "following_bsr": { + "address": 33627, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 33729, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 33745, + "kind": "raw_mov_iw", + "target": 33729, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'83C1, R0", + "following_bsr": { + "address": 33748, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33762, + "length": 17, + "text": " WHITE H SAW X", + "trimmed": "WHITE H SAW X", + "kind": "printable_run", + "score": 1.083, + "confidence": "high", + "xrefs": [ + { + "address": 33778, + "kind": "raw_mov_iw", + "target": 33762, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'83E2, R0", + "following_bsr": { + "address": 33781, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33792, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 33808, + "kind": "raw_mov_iw", + "target": 33792, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8400, R0", + "following_bsr": { + "address": 33811, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 33913, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 33929, + "kind": "raw_mov_iw", + "target": 33913, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8479, R0", + "following_bsr": { + "address": 33932, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33946, + "length": 17, + "text": " WHITE H PARA X", + "trimmed": "WHITE H PARA X", + "kind": "printable_run", + "score": 1.097, + "confidence": "high", + "xrefs": [ + { + "address": 33962, + "kind": "raw_mov_iw", + "target": 33946, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'849A, R0", + "following_bsr": { + "address": 33965, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 33976, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 33992, + "kind": "raw_mov_iw", + "target": 33976, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'84B8, R0", + "following_bsr": { + "address": 33995, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 34097, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 34113, + "kind": "raw_mov_iw", + "target": 34097, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8531, R0", + "following_bsr": { + "address": 34116, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34130, + "length": 17, + "text": " BLACK V SAW X", + "trimmed": "BLACK V SAW X", + "kind": "printable_run", + "score": 1.083, + "confidence": "high", + "xrefs": [ + { + "address": 34146, + "kind": "raw_mov_iw", + "target": 34130, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8552, R0", + "following_bsr": { + "address": 34149, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34160, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 34176, + "kind": "raw_mov_iw", + "target": 34160, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8570, R0", + "following_bsr": { + "address": 34179, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 34281, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 34297, + "kind": "raw_mov_iw", + "target": 34281, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'85E9, R0", + "following_bsr": { + "address": 34300, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34314, + "length": 17, + "text": " BLACK V PARA X", + "trimmed": "BLACK V PARA X", + "kind": "printable_run", + "score": 1.097, + "confidence": "high", + "xrefs": [ + { + "address": 34330, + "kind": "raw_mov_iw", + "target": 34314, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'860A, R0", + "following_bsr": { + "address": 34333, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34344, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 34360, + "kind": "raw_mov_iw", + "target": 34344, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8628, R0", + "following_bsr": { + "address": 34363, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 34465, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 34481, + "kind": "raw_mov_iw", + "target": 34465, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'86A1, R0", + "following_bsr": { + "address": 34484, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34498, + "length": 17, + "text": " BLACK H SAW X", + "trimmed": "BLACK H SAW X", + "kind": "printable_run", + "score": 1.083, + "confidence": "high", + "xrefs": [ + { + "address": 34514, + "kind": "raw_mov_iw", + "target": 34498, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'86C2, R0", + "following_bsr": { + "address": 34517, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34528, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 34544, + "kind": "raw_mov_iw", + "target": 34528, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'86E0, R0", + "following_bsr": { + "address": 34547, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 34649, + "length": 17, + "text": " SHADING X", + "trimmed": "SHADING X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 34665, + "kind": "raw_mov_iw", + "target": 34649, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8759, R0", + "following_bsr": { + "address": 34668, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34682, + "length": 17, + "text": " BLACK H PARA X", + "trimmed": "BLACK H PARA X", + "kind": "printable_run", + "score": 1.097, + "confidence": "high", + "xrefs": [ + { + "address": 34698, + "kind": "raw_mov_iw", + "target": 34682, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'877A, R0", + "following_bsr": { + "address": 34701, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34712, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 34728, + "kind": "raw_mov_iw", + "target": 34712, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8798, R0", + "following_bsr": { + "address": 34731, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 34877, + "length": 17, + "text": " MATRIX X", + "trimmed": "MATRIX X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 34893, + "kind": "raw_mov_iw", + "target": 34877, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'883D, R0", + "following_bsr": { + "address": 34896, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34911, + "length": 16, + "text": "STD FL~X", + "trimmed": "STD FL~X", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 34926, + "kind": "raw_mov_iw", + "target": 34910, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'885E, R0", + "following_bsr": { + "address": 34929, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 34940, + "length": 17, + "text": " PRESET MATRIX X", + "trimmed": "PRESET MATRIX X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 34956, + "kind": "raw_mov_iw", + "target": 34940, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'887C, R0", + "following_bsr": { + "address": 34959, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 34971, + "length": 16, + "text": "H.SAT SPCL~X", + "trimmed": "H.SAT SPCL~X", + "kind": "printable_run", + "score": 1.006, + "confidence": "medium", + "xrefs": [ + { + "address": 34986, + "kind": "raw_mov_iw", + "target": 34970, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'889A, R0", + "following_bsr": { + "address": 34989, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 35081, + "length": 17, + "text": " MATRIX X", + "trimmed": "MATRIX X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 35097, + "kind": "raw_mov_iw", + "target": 35081, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8909, R0", + "following_bsr": { + "address": 35100, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 35115, + "length": 16, + "text": "ON OFF~X", + "trimmed": "ON OFF~X", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 35130, + "kind": "raw_mov_iw", + "target": 35114, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'892A, R0", + "following_bsr": { + "address": 35133, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 35144, + "length": 17, + "text": " SAT HUE X", + "trimmed": "SAT HUE X", + "kind": "printable_run", + "score": 1.038, + "confidence": "medium", + "xrefs": [ + { + "address": 35160, + "kind": "raw_mov_iw", + "target": 35144, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8948, R0", + "following_bsr": { + "address": 35163, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 35340, + "length": 17, + "text": " MATRIX X", + "trimmed": "MATRIX X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 35356, + "kind": "raw_mov_iw", + "target": 35340, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8A0C, R0", + "following_bsr": { + "address": 35359, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 35374, + "length": 16, + "text": "ON SKIN OFF~X", + "trimmed": "ON SKIN OFF~X", + "kind": "printable_run", + "score": 1.025, + "confidence": "medium", + "xrefs": [ + { + "address": 35389, + "kind": "raw_mov_iw", + "target": 35373, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'8A2D, R0", + "following_bsr": { + "address": 35392, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 35403, + "length": 17, + "text": " SAT HUE X", + "trimmed": "SAT HUE X", + "kind": "printable_run", + "score": 1.038, + "confidence": "medium", + "xrefs": [ + { + "address": 35419, + "kind": "raw_mov_iw", + "target": 35403, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8A4B, R0", + "following_bsr": { + "address": 35422, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 35535, + "length": 17, + "text": " MATRIX X", + "trimmed": "MATRIX X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 35551, + "kind": "raw_mov_iw", + "target": 35535, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8ACF, R0", + "following_bsr": { + "address": 35554, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 35577, + "length": 17, + "text": " R-G R-B G-R X", + "trimmed": "R-G R-B G-R X", + "kind": "printable_run", + "score": 1.019, + "confidence": "medium", + "xrefs": [ + { + "address": 35593, + "kind": "raw_mov_iw", + "target": 35577, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8AF9, R0", + "following_bsr": { + "address": 35596, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 35697, + "length": 17, + "text": " MATRIX X", + "trimmed": "MATRIX X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 35713, + "kind": "raw_mov_iw", + "target": 35697, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8B71, R0", + "following_bsr": { + "address": 35716, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 35739, + "length": 17, + "text": " G-B B-R B-G X", + "trimmed": "G-B B-R B-G X", + "kind": "printable_run", + "score": 1.019, + "confidence": "medium", + "xrefs": [ + { + "address": 35755, + "kind": "raw_mov_iw", + "target": 35739, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8B9B, R0", + "following_bsr": { + "address": 35758, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 36023, + "length": 17, + "text": " FILTER X", + "trimmed": "FILTER X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 36039, + "kind": "raw_mov_iw", + "target": 36023, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8CB7, R0", + "following_bsr": { + "address": 36042, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 36076, + "length": 17, + "text": " 1 2 3 4 X", + "trimmed": "1 2 3 4 X", + "kind": "printable_run", + "score": 1.021, + "confidence": "medium", + "xrefs": [ + { + "address": 36092, + "kind": "raw_mov_iw", + "target": 36076, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8CEC, R0", + "following_bsr": { + "address": 36095, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 36231, + "length": 17, + "text": " A B C D X", + "trimmed": "A B C D X", + "kind": "printable_run", + "score": 1.021, + "confidence": "medium", + "xrefs": [ + { + "address": 36247, + "kind": "raw_mov_iw", + "target": 36231, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8D87, R0", + "following_bsr": { + "address": 36250, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 36439, + "length": 17, + "text": " LENS X", + "trimmed": "LENS X", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 36455, + "kind": "raw_mov_iw", + "target": 36439, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8E57, R0", + "following_bsr": { + "address": 36458, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 36473, + "length": 16, + "text": "ON CONT1 OFF~X", + "trimmed": "ON CONT1 OFF~X", + "kind": "printable_run", + "score": 1.037, + "confidence": "medium", + "xrefs": [ + { + "address": 36488, + "kind": "raw_mov_iw", + "target": 36472, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'8E78, R0", + "following_bsr": { + "address": 36491, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 36502, + "length": 17, + "text": "FOCUS ZOOM X", + "trimmed": "FOCUS ZOOM X", + "kind": "printable_run", + "score": 1.068, + "confidence": "high", + "xrefs": [ + { + "address": 36518, + "kind": "raw_mov_iw", + "target": 36502, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8E96, R0", + "following_bsr": { + "address": 36521, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 36659, + "length": 17, + "text": " PAN/TILT X", + "trimmed": "PAN/TILT X", + "kind": "printable_run", + "score": 1.065, + "confidence": "high", + "xrefs": [ + { + "address": 36675, + "kind": "raw_mov_iw", + "target": 36659, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8F33, R0", + "following_bsr": { + "address": 36678, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 36693, + "length": 16, + "text": "ON CONT2 OFF~X", + "trimmed": "ON CONT2 OFF~X", + "kind": "printable_run", + "score": 1.037, + "confidence": "medium", + "xrefs": [ + { + "address": 36708, + "kind": "raw_mov_iw", + "target": 36692, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'8F54, R0", + "following_bsr": { + "address": 36711, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 36722, + "length": 17, + "text": " PAN TILT X", + "trimmed": "PAN TILT X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 36738, + "kind": "raw_mov_iw", + "target": 36722, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'8F72, R0", + "following_bsr": { + "address": 36741, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 36912, + "length": 17, + "text": " SKIN GATE X", + "trimmed": "SKIN GATE X", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 36928, + "kind": "raw_mov_iw", + "target": 36912, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9030, R0", + "following_bsr": { + "address": 36931, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 36946, + "length": 16, + "text": "ON IND OFF~X", + "trimmed": "ON IND OFF~X", + "kind": "printable_run", + "score": 1.012, + "confidence": "medium", + "xrefs": [ + { + "address": 36961, + "kind": "raw_mov_iw", + "target": 36945, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9051, R0", + "following_bsr": { + "address": 36964, + "target": 23432, + "instruction": "BSR H'5B88" + } + }, + { + "address": 47692, + "kind": "raw_mov_iw", + "target": 36944, + "delta": -2, + "register": "R4", + "instruction": "MOV:I.W #H'9050, R4" + } + ], + "xref_count": 2 + }, + { + "address": 36975, + "length": 17, + "text": " GATE SIZE X", + "trimmed": "GATE SIZE X", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 36991, + "kind": "raw_mov_iw", + "target": 36975, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'906F, R0", + "following_bsr": { + "address": 36994, + "target": 23962, + "instruction": "BSR H'5D9A" + } + } + ], + "xref_count": 1 + }, + { + "address": 37078, + "length": 17, + "text": " SKIN GATE X", + "trimmed": "SKIN GATE X", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 37094, + "kind": "raw_mov_iw", + "target": 37078, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'90D6, R0", + "following_bsr": { + "address": 37097, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 37111, + "length": 17, + "text": " SIZE X", + "trimmed": "SIZE X", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 37127, + "kind": "raw_mov_iw", + "target": 37111, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'90F7, R0", + "following_bsr": { + "address": 37130, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 37141, + "length": 17, + "text": " R-Y B-Y X", + "trimmed": "R-Y B-Y X", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 37157, + "kind": "raw_mov_iw", + "target": 37141, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9115, R0", + "following_bsr": { + "address": 37160, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 37272, + "length": 17, + "text": " SKIN GATE X", + "trimmed": "SKIN GATE X", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 37288, + "kind": "raw_mov_iw", + "target": 37272, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9198, R0", + "following_bsr": { + "address": 37291, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 37305, + "length": 17, + "text": " POSI X", + "trimmed": "POSI X", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 37321, + "kind": "raw_mov_iw", + "target": 37305, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'91B9, R0", + "following_bsr": { + "address": 37324, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 37335, + "length": 17, + "text": " R-Y B-Y X", + "trimmed": "R-Y B-Y X", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 37351, + "kind": "raw_mov_iw", + "target": 37335, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'91D7, R0", + "following_bsr": { + "address": 37354, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 37477, + "length": 17, + "text": " SKIN DETAIL X", + "trimmed": "SKIN DETAIL X", + "kind": "printable_run", + "score": 1.097, + "confidence": "high", + "xrefs": [ + { + "address": 37493, + "kind": "raw_mov_iw", + "target": 37477, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9265, R0", + "following_bsr": { + "address": 37496, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 37548, + "length": 17, + "text": " OFF X", + "trimmed": "OFF X", + "kind": "printable_run", + "score": 1.023, + "confidence": "medium", + "xrefs": [ + { + "address": 37564, + "kind": "raw_mov_iw", + "target": 37548, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'92AC, R0", + "following_bsr": { + "address": 37567, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 37916, + "length": 14, + "text": " ITEM ", + "trimmed": "ITEM", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 37931, + "kind": "raw_mov_iw", + "target": 37915, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'941B, R0", + "following_bsr": { + "address": 37934, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 37945, + "length": 14, + "text": "NOT AVAILABLE ", + "trimmed": "NOT AVAILABLE", + "kind": "printable_run", + "score": 0.985, + "confidence": "medium", + "xrefs": [ + { + "address": 37960, + "kind": "raw_mov_iw", + "target": 37944, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9438, R0", + "following_bsr": { + "address": 37963, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38028, + "length": 14, + "text": " TLCS ", + "trimmed": "TLCS", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38043, + "kind": "raw_mov_iw", + "target": 38027, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'948B, R0", + "following_bsr": { + "address": 38046, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38057, + "length": 14, + "text": " ON ", + "trimmed": "ON", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38072, + "kind": "raw_mov_iw", + "target": 38056, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'94A8, R0", + "following_bsr": { + "address": 38075, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38140, + "length": 14, + "text": " FILTER ", + "trimmed": "FILTER", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38155, + "kind": "raw_mov_iw", + "target": 38139, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'94FB, R0", + "following_bsr": { + "address": 38158, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38396, + "length": 14, + "text": " KNEE ", + "trimmed": "KNEE", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38411, + "kind": "raw_mov_iw", + "target": 38395, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'95FB, R0", + "following_bsr": { + "address": 38414, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38437, + "length": 14, + "text": " AUTO ", + "trimmed": "AUTO", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38452, + "kind": "raw_mov_iw", + "target": 38436, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9624, R0" + } + ], + "xref_count": 1 + }, + { + "address": 38460, + "length": 14, + "text": " PRESET ", + "trimmed": "PRESET", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38475, + "kind": "raw_mov_iw", + "target": 38459, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'963B, R0" + } + ], + "xref_count": 1 + }, + { + "address": 38483, + "length": 14, + "text": " DL ", + "trimmed": "DL", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38498, + "kind": "raw_mov_iw", + "target": 38482, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9652, R0", + "following_bsr": { + "address": 38501, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38566, + "length": 14, + "text": " FLARE ", + "trimmed": "FLARE", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38581, + "kind": "raw_mov_iw", + "target": 38565, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'96A5, R0", + "following_bsr": { + "address": 38584, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38595, + "length": 14, + "text": " OFF ", + "trimmed": "OFF", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38610, + "kind": "raw_mov_iw", + "target": 38594, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'96C2, R0", + "following_bsr": { + "address": 38613, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38678, + "length": 14, + "text": " ATW ", + "trimmed": "ATW", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38693, + "kind": "raw_mov_iw", + "target": 38677, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9715, R0", + "following_bsr": { + "address": 38696, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38707, + "length": 14, + "text": " ON ", + "trimmed": "ON", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38722, + "kind": "raw_mov_iw", + "target": 38706, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9732, R0", + "following_bsr": { + "address": 38725, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38790, + "length": 14, + "text": " GAMMA ", + "trimmed": "GAMMA", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38805, + "kind": "raw_mov_iw", + "target": 38789, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9785, R0", + "following_bsr": { + "address": 38808, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38819, + "length": 14, + "text": " OFF ", + "trimmed": "OFF", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38834, + "kind": "raw_mov_iw", + "target": 38818, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'97A2, R0", + "following_bsr": { + "address": 38837, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38902, + "length": 14, + "text": " DETAIL ", + "trimmed": "DETAIL", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38917, + "kind": "raw_mov_iw", + "target": 38901, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'97F5, R0", + "following_bsr": { + "address": 38920, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 38931, + "length": 14, + "text": " OFF ", + "trimmed": "OFF", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 38946, + "kind": "raw_mov_iw", + "target": 38930, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9812, R0", + "following_bsr": { + "address": 38949, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39011, + "length": 17, + "text": " AUTO LEVEL X", + "trimmed": "AUTO LEVEL X", + "kind": "printable_run", + "score": 1.093, + "confidence": "high", + "xrefs": [ + { + "address": 39027, + "kind": "raw_mov_iw", + "target": 39011, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9863, R0", + "following_bsr": { + "address": 39030, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39061, + "length": 17, + "text": "START:PUSH AGAINX", + "trimmed": "START:PUSH AGAINX", + "kind": "printable_run", + "score": 1.121, + "confidence": "high", + "xrefs": [ + { + "address": 39077, + "kind": "raw_mov_iw", + "target": 39061, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9895, R0", + "following_bsr": { + "address": 39080, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39120, + "length": 17, + "text": "WHT/BLK BALANCE X", + "trimmed": "WHT/BLK BALANCE X", + "kind": "printable_run", + "score": 1.109, + "confidence": "high", + "xrefs": [ + { + "address": 39136, + "kind": "raw_mov_iw", + "target": 39120, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'98D0, R0", + "following_bsr": { + "address": 39139, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39150, + "length": 17, + "text": " NOT AUTO X", + "trimmed": "NOT AUTO X", + "kind": "printable_run", + "score": 1.073, + "confidence": "high", + "xrefs": [ + { + "address": 39166, + "kind": "raw_mov_iw", + "target": 39150, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'98EE, R0", + "following_bsr": { + "address": 39169, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39307, + "length": 17, + "text": " AUTO SKIN X", + "trimmed": "AUTO SKIN X", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 39323, + "kind": "raw_mov_iw", + "target": 39307, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'998B, R0", + "following_bsr": { + "address": 39326, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39340, + "length": 17, + "text": "START:PUSH AGAINX", + "trimmed": "START:PUSH AGAINX", + "kind": "printable_run", + "score": 1.121, + "confidence": "high", + "xrefs": [ + { + "address": 39356, + "kind": "raw_mov_iw", + "target": 39340, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'99AC, R0", + "following_bsr": { + "address": 39359, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39370, + "length": 17, + "text": " GATE SIZE X", + "trimmed": "GATE SIZE X", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 39386, + "kind": "raw_mov_iw", + "target": 39370, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'99CA, R0", + "following_bsr": { + "address": 39389, + "target": 23962, + "instruction": "BSR H'5D9A" + } + } + ], + "xref_count": 1 + }, + { + "address": 39499, + "length": 17, + "text": " AUTO SKIN X", + "trimmed": "AUTO SKIN X", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 39515, + "kind": "raw_mov_iw", + "target": 39499, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9A4B, R0", + "following_bsr": { + "address": 39518, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39533, + "length": 16, + "text": "ON WINDOW OFF~X", + "trimmed": "ON WINDOW OFF~X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 39548, + "kind": "raw_mov_iw", + "target": 39532, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9A6C, R0", + "following_bsr": { + "address": 39551, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 39562, + "length": 17, + "text": "H-POSI V-POSIX", + "trimmed": "H-POSI V-POSIX", + "kind": "printable_run", + "score": 1.068, + "confidence": "high", + "xrefs": [ + { + "address": 39578, + "kind": "raw_mov_iw", + "target": 39562, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9A8A, R0", + "following_bsr": { + "address": 39581, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 39719, + "length": 17, + "text": " AUTO SKIN X", + "trimmed": "AUTO SKIN X", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 39735, + "kind": "raw_mov_iw", + "target": 39719, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9B27, R0", + "following_bsr": { + "address": 39738, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 39753, + "length": 16, + "text": "ON WINDOW OFF~X", + "trimmed": "ON WINDOW OFF~X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 39768, + "kind": "raw_mov_iw", + "target": 39752, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9B48, R0", + "following_bsr": { + "address": 39771, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 39782, + "length": 17, + "text": "WIDTH HEIGHTX", + "trimmed": "WIDTH HEIGHTX", + "kind": "printable_run", + "score": 1.091, + "confidence": "high", + "xrefs": [ + { + "address": 39798, + "kind": "raw_mov_iw", + "target": 39782, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'9B66, R0", + "following_bsr": { + "address": 39801, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 39909, + "length": 9, + "text": "AUTO SKIN", + "trimmed": "AUTO SKIN", + "kind": "printable_run", + "score": 0.978, + "confidence": "medium", + "xrefs": [ + { + "address": 39922, + "kind": "raw_mov_iw", + "target": 39906, + "delta": -3, + "register": "R0", + "instruction": "MOV:I.W #H'9BE2, R0", + "following_bsr": { + "address": 39925, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 40313, + "length": 13, + "text": "WHITE SHADING", + "trimmed": "WHITE SHADING", + "kind": "printable_run", + "score": 0.985, + "confidence": "medium", + "xrefs": [ + { + "address": 40328, + "kind": "raw_mov_iw", + "target": 40312, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9D78, R0", + "following_bsr": { + "address": 40331, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 40342, + "length": 14, + "text": " AUTO SET ", + "trimmed": "AUTO SET", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 40357, + "kind": "raw_mov_iw", + "target": 40341, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9D95, R0", + "following_bsr": { + "address": 40360, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 40447, + "length": 13, + "text": "BLACK SHADING", + "trimmed": "BLACK SHADING", + "kind": "printable_run", + "score": 0.985, + "confidence": "medium", + "xrefs": [ + { + "address": 40462, + "kind": "raw_mov_iw", + "target": 40446, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9DFE, R0", + "following_bsr": { + "address": 40465, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 40476, + "length": 14, + "text": " AUTO SET ", + "trimmed": "AUTO SET", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 40491, + "kind": "raw_mov_iw", + "target": 40475, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9E1B, R0", + "following_bsr": { + "address": 40494, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 40856, + "length": 14, + "text": " COPY ", + "trimmed": "COPY", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 40871, + "kind": "raw_mov_iw", + "target": 40855, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9F97, R0", + "following_bsr": { + "address": 40874, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 40885, + "length": 14, + "text": " IN PROGRESS ", + "trimmed": "IN PROGRESS", + "kind": "printable_run", + "score": 0.982, + "confidence": "medium", + "xrefs": [ + { + "address": 40900, + "kind": "raw_mov_iw", + "target": 40884, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'9FB4, R0", + "following_bsr": { + "address": 40903, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 40968, + "length": 14, + "text": " COPY ", + "trimmed": "COPY", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 40983, + "kind": "raw_mov_iw", + "target": 40967, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A007, R0", + "following_bsr": { + "address": 40986, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 40997, + "length": 14, + "text": " COMPLETED ", + "trimmed": "COMPLETED", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 41012, + "kind": "raw_mov_iw", + "target": 40996, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A024, R0", + "following_bsr": { + "address": 41015, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 41372, + "length": 5, + "text": "WHITE", + "trimmed": "WHITE", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium" + }, + { + "address": 41416, + "length": 14, + "text": " AUTO ", + "trimmed": "AUTO", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 41431, + "kind": "raw_mov_iw", + "target": 41415, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A1C7, R0", + "following_bsr": { + "address": 41434, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 41483, + "length": 14, + "text": " OK ", + "trimmed": "OK", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 41498, + "kind": "raw_mov_iw", + "target": 41482, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A20A, R0", + "following_bsr": { + "address": 41501, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 41515, + "length": 14, + "text": "OK:UNDER1700K ", + "trimmed": "OK:UNDER1700K", + "kind": "printable_run", + "score": 0.977, + "confidence": "medium", + "xrefs": [ + { + "address": 41530, + "kind": "raw_mov_iw", + "target": 41514, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A22A, R0", + "following_bsr": { + "address": 41533, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 41547, + "length": 14, + "text": "OK:OVER10000K ", + "trimmed": "OK:OVER10000K", + "kind": "printable_run", + "score": 0.977, + "confidence": "medium", + "xrefs": [ + { + "address": 41562, + "kind": "raw_mov_iw", + "target": 41546, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A24A, R0", + "following_bsr": { + "address": 41565, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 41949, + "length": 14, + "text": " OPERATION ", + "trimmed": "OPERATION", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 41964, + "kind": "raw_mov_iw", + "target": 41948, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A3DC, R0", + "following_bsr": { + "address": 41967, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 41981, + "length": 14, + "text": " PRESET ", + "trimmed": "PRESET", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 41996, + "kind": "raw_mov_iw", + "target": 41980, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A3FC, R0", + "following_bsr": { + "address": 41999, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 42178, + "length": 5, + "text": "BLACK", + "trimmed": "BLACK", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium" + }, + { + "address": 42215, + "length": 14, + "text": " AUTO ", + "trimmed": "AUTO", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 42230, + "kind": "raw_mov_iw", + "target": 42214, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A4E6, R0", + "following_bsr": { + "address": 42233, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 42264, + "length": 14, + "text": " OK ", + "trimmed": "OK", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 42279, + "kind": "raw_mov_iw", + "target": 42263, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A517, R0", + "following_bsr": { + "address": 42282, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 42504, + "length": 14, + "text": " OPERATION ", + "trimmed": "OPERATION", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium", + "xrefs": [ + { + "address": 42519, + "kind": "raw_mov_iw", + "target": 42503, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A607, R0", + "following_bsr": { + "address": 42522, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 42701, + "length": 5, + "text": "FLARE", + "trimmed": "FLARE", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium" + }, + { + "address": 42726, + "length": 14, + "text": "RED GREEN BLUE", + "trimmed": "RED GREEN BLUE", + "kind": "printable_run", + "score": 0.971, + "confidence": "medium", + "xrefs": [ + { + "address": 42741, + "kind": "raw_mov_iw", + "target": 42725, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A6E5, R0", + "following_bsr": { + "address": 42744, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 43169, + "length": 17, + "text": " DETAIL X", + "trimmed": "DETAIL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 43185, + "kind": "raw_mov_iw", + "target": 43169, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'A8A1, R0", + "following_bsr": { + "address": 43188, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 43211, + "length": 17, + "text": " FREQ H/V X", + "trimmed": "FREQ H/V X", + "kind": "printable_run", + "score": 1.031, + "confidence": "medium", + "xrefs": [ + { + "address": 43227, + "kind": "raw_mov_iw", + "target": 43211, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'A8CB, R0", + "following_bsr": { + "address": 43230, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 43433, + "length": 17, + "text": " DETAIL X", + "trimmed": "DETAIL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 43449, + "kind": "raw_mov_iw", + "target": 43433, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'A9A9, R0", + "following_bsr": { + "address": 43452, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 43482, + "length": 16, + "text": "ON OFF~X", + "trimmed": "ON OFF~X", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 43497, + "kind": "raw_mov_iw", + "target": 43481, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'A9D9, R0", + "following_bsr": { + "address": 43500, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 43569, + "length": 17, + "text": " DETAIL X", + "trimmed": "DETAIL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 43585, + "kind": "raw_mov_iw", + "target": 43569, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AA31, R0", + "following_bsr": { + "address": 43588, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 43602, + "length": 17, + "text": " LEV V-DTLX", + "trimmed": "LEV V-DTLX", + "kind": "printable_run", + "score": 1.086, + "confidence": "high", + "xrefs": [ + { + "address": 43618, + "kind": "raw_mov_iw", + "target": 43602, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AA52, R0", + "following_bsr": { + "address": 43621, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 43632, + "length": 17, + "text": "CRISP DEP LIMITX", + "trimmed": "CRISP DEP LIMITX", + "kind": "printable_run", + "score": 1.115, + "confidence": "high", + "xrefs": [ + { + "address": 43648, + "kind": "raw_mov_iw", + "target": 43632, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AA70, R0", + "following_bsr": { + "address": 43651, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 43750, + "length": 17, + "text": " DETAIL X", + "trimmed": "DETAIL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 43766, + "kind": "raw_mov_iw", + "target": 43750, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AAE6, R0", + "following_bsr": { + "address": 43769, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 43783, + "length": 17, + "text": "HIGH AFTERX", + "trimmed": "HIGH AFTERX", + "kind": "printable_run", + "score": 1.068, + "confidence": "high", + "xrefs": [ + { + "address": 43799, + "kind": "raw_mov_iw", + "target": 43783, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AB07, R0", + "following_bsr": { + "address": 43802, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 43813, + "length": 17, + "text": "LIGHT GAMMAX", + "trimmed": "LIGHT GAMMAX", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 43829, + "kind": "raw_mov_iw", + "target": 43813, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AB25, R0", + "following_bsr": { + "address": 43832, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 43968, + "length": 17, + "text": " DETAIL X", + "trimmed": "DETAIL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 43984, + "kind": "raw_mov_iw", + "target": 43968, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'ABC0, R0", + "following_bsr": { + "address": 43987, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44001, + "length": 17, + "text": " APERTURE X", + "trimmed": "APERTURE X", + "kind": "printable_run", + "score": 1.088, + "confidence": "high", + "xrefs": [ + { + "address": 44017, + "kind": "raw_mov_iw", + "target": 44001, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'ABE1, R0", + "following_bsr": { + "address": 44020, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44031, + "length": 17, + "text": " LEVEL X", + "trimmed": "LEVEL X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 44047, + "kind": "raw_mov_iw", + "target": 44031, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'ABFF, R0", + "following_bsr": { + "address": 44050, + "target": 23962, + "instruction": "BSR H'5D9A" + } + } + ], + "xref_count": 1 + }, + { + "address": 44062, + "length": 16, + "text": "ON OFF~X", + "trimmed": "ON OFF~X", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 44077, + "kind": "raw_mov_iw", + "target": 44061, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'AC1D, R0", + "following_bsr": { + "address": 44080, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44178, + "length": 17, + "text": " DETAIL X", + "trimmed": "DETAIL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 44194, + "kind": "raw_mov_iw", + "target": 44178, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AC92, R0", + "following_bsr": { + "address": 44197, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44211, + "length": 17, + "text": " KNEE APERTURE X", + "trimmed": "KNEE APERTURE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 44227, + "kind": "raw_mov_iw", + "target": 44211, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'ACB3, R0", + "following_bsr": { + "address": 44230, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44241, + "length": 17, + "text": " LEVEL X", + "trimmed": "LEVEL X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 44257, + "kind": "raw_mov_iw", + "target": 44241, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'ACD1, R0", + "following_bsr": { + "address": 44260, + "target": 23962, + "instruction": "BSR H'5D9A" + } + } + ], + "xref_count": 1 + }, + { + "address": 44272, + "length": 16, + "text": "ON OFF~X", + "trimmed": "ON OFF~X", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 44287, + "kind": "raw_mov_iw", + "target": 44271, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'ACEF, R0", + "following_bsr": { + "address": 44290, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44363, + "length": 17, + "text": " DETAIL X", + "trimmed": "DETAIL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 44379, + "kind": "raw_mov_iw", + "target": 44363, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AD4B, R0", + "following_bsr": { + "address": 44382, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44396, + "length": 17, + "text": " CROSS COLOR X", + "trimmed": "CROSS COLOR X", + "kind": "printable_run", + "score": 1.097, + "confidence": "high", + "xrefs": [ + { + "address": 44412, + "kind": "raw_mov_iw", + "target": 44396, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AD6C, R0", + "following_bsr": { + "address": 44415, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44426, + "length": 17, + "text": " SUPPRESS X", + "trimmed": "SUPPRESS X", + "kind": "printable_run", + "score": 1.088, + "confidence": "high", + "xrefs": [ + { + "address": 44442, + "kind": "raw_mov_iw", + "target": 44426, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AD8A, R0", + "following_bsr": { + "address": 44445, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44574, + "length": 17, + "text": " DETAIL X", + "trimmed": "DETAIL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 44590, + "kind": "raw_mov_iw", + "target": 44574, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AE1E, R0", + "following_bsr": { + "address": 44593, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44608, + "length": 16, + "text": "ON RED OFF~X", + "trimmed": "ON RED OFF~X", + "kind": "printable_run", + "score": 1.012, + "confidence": "medium", + "xrefs": [ + { + "address": 44623, + "kind": "raw_mov_iw", + "target": 44607, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'AE3F, R0", + "following_bsr": { + "address": 44626, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 44637, + "length": 17, + "text": " COMB FILTER X", + "trimmed": "COMB FILTER X", + "kind": "printable_run", + "score": 1.097, + "confidence": "high", + "xrefs": [ + { + "address": 44653, + "kind": "raw_mov_iw", + "target": 44637, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AE5D, R0", + "following_bsr": { + "address": 44656, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44668, + "length": 16, + "text": "ON GRN OFF~X", + "trimmed": "ON GRN OFF~X", + "kind": "printable_run", + "score": 1.012, + "confidence": "medium", + "xrefs": [ + { + "address": 44683, + "kind": "raw_mov_iw", + "target": 44667, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'AE7B, R0", + "following_bsr": { + "address": 44686, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44782, + "length": 17, + "text": " GAMMA X", + "trimmed": "GAMMA X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 44798, + "kind": "raw_mov_iw", + "target": 44782, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AEEE, R0", + "following_bsr": { + "address": 44801, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 44816, + "length": 16, + "text": "ON OFF~X", + "trimmed": "ON OFF~X", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 44831, + "kind": "raw_mov_iw", + "target": 44815, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'AF0F, R0", + "following_bsr": { + "address": 44834, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 44845, + "length": 17, + "text": " RED MAST BLUE X", + "trimmed": "RED MAST BLUE X", + "kind": "printable_run", + "score": 1.1, + "confidence": "high", + "xrefs": [ + { + "address": 44861, + "kind": "raw_mov_iw", + "target": 44845, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AF2D, R0", + "following_bsr": { + "address": 44864, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 44997, + "length": 17, + "text": " GAMMA X", + "trimmed": "GAMMA X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 45013, + "kind": "raw_mov_iw", + "target": 44997, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'AFC5, R0", + "following_bsr": { + "address": 45016, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45060, + "length": 17, + "text": "GAMMA INIT GAIN X", + "trimmed": "GAMMA INIT GAIN X", + "kind": "printable_run", + "score": 1.115, + "confidence": "high", + "xrefs": [ + { + "address": 45076, + "kind": "raw_mov_iw", + "target": 45060, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B004, R0", + "following_bsr": { + "address": 45079, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45091, + "length": 16, + "text": "4.0 X", + "trimmed": "4.0 X", + "kind": "printable_run", + "score": 0.981, + "confidence": "medium", + "xrefs": [ + { + "address": 45106, + "kind": "raw_mov_iw", + "target": 45090, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'B022, R0", + "following_bsr": { + "address": 45109, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45249, + "length": 17, + "text": " KNEE X", + "trimmed": "KNEE X", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 45265, + "kind": "raw_mov_iw", + "target": 45249, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B0C1, R0", + "following_bsr": { + "address": 45268, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45283, + "length": 16, + "text": "PRESET X", + "trimmed": "PRESET X", + "kind": "printable_run", + "score": 1.038, + "confidence": "medium", + "xrefs": [ + { + "address": 45298, + "kind": "raw_mov_iw", + "target": 45282, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'B0E2, R0", + "following_bsr": { + "address": 45301, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45312, + "length": 17, + "text": " MANUAL KNEE X", + "trimmed": "MANUAL KNEE X", + "kind": "printable_run", + "score": 1.097, + "confidence": "high", + "xrefs": [ + { + "address": 45328, + "kind": "raw_mov_iw", + "target": 45312, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B100, R0", + "following_bsr": { + "address": 45331, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45343, + "length": 16, + "text": "VARIABLE X", + "trimmed": "VARIABLE X", + "kind": "printable_run", + "score": 1.062, + "confidence": "high", + "xrefs": [ + { + "address": 45358, + "kind": "raw_mov_iw", + "target": 45342, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'B11E, R0", + "following_bsr": { + "address": 45361, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45408, + "length": 17, + "text": " KNEE X", + "trimmed": "KNEE X", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 45424, + "kind": "raw_mov_iw", + "target": 45408, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B160, R0", + "following_bsr": { + "address": 45427, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45514, + "length": 17, + "text": "POINT SLOPEX", + "trimmed": "POINT SLOPEX", + "kind": "printable_run", + "score": 1.079, + "confidence": "high", + "xrefs": [ + { + "address": 45530, + "kind": "raw_mov_iw", + "target": 45514, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B1CA, R0", + "following_bsr": { + "address": 45533, + "target": 24100, + "instruction": "BSR H'5E24" + } + } + ], + "xref_count": 1 + }, + { + "address": 45637, + "length": 17, + "text": " PRESET X", + "trimmed": "PRESET X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 45653, + "kind": "raw_mov_iw", + "target": 45637, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B245, R0", + "following_bsr": { + "address": 45656, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45723, + "length": 17, + "text": " AUTO X", + "trimmed": "AUTO X", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 45739, + "kind": "raw_mov_iw", + "target": 45723, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B29B, R0", + "following_bsr": { + "address": 45742, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45808, + "length": 17, + "text": " DL X", + "trimmed": "DL X", + "kind": "printable_run", + "score": 1.01, + "confidence": "medium", + "xrefs": [ + { + "address": 45824, + "kind": "raw_mov_iw", + "target": 45808, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B2F0, R0", + "following_bsr": { + "address": 45827, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45927, + "length": 17, + "text": " KNEE X", + "trimmed": "KNEE X", + "kind": "printable_run", + "score": 1.041, + "confidence": "medium", + "xrefs": [ + { + "address": 45943, + "kind": "raw_mov_iw", + "target": 45927, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B367, R0", + "following_bsr": { + "address": 45946, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45960, + "length": 17, + "text": " WHITE CLIP X", + "trimmed": "WHITE CLIP X", + "kind": "printable_run", + "score": 1.093, + "confidence": "high", + "xrefs": [ + { + "address": 45976, + "kind": "raw_mov_iw", + "target": 45960, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B388, R0", + "following_bsr": { + "address": 45979, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 45990, + "length": 17, + "text": " LEVEL X", + "trimmed": "LEVEL X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 46006, + "kind": "raw_mov_iw", + "target": 45990, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B3A6, R0", + "following_bsr": { + "address": 46009, + "target": 23962, + "instruction": "BSR H'5D9A" + } + } + ], + "xref_count": 1 + }, + { + "address": 46021, + "length": 16, + "text": "ON OFF~X", + "trimmed": "ON OFF~X", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 46036, + "kind": "raw_mov_iw", + "target": 46020, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'B3C4, R0", + "following_bsr": { + "address": 46039, + "target": 23697, + "instruction": "BSR H'5C91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46144, + "length": 17, + "text": " FLARE X", + "trimmed": "FLARE X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 46160, + "kind": "raw_mov_iw", + "target": 46144, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B440, R0", + "following_bsr": { + "address": 46163, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46178, + "length": 16, + "text": "ON OFF~X", + "trimmed": "ON OFF~X", + "kind": "printable_run", + "score": 0.975, + "confidence": "medium", + "xrefs": [ + { + "address": 46193, + "kind": "raw_mov_iw", + "target": 46177, + "delta": -1, + "register": "R0", + "instruction": "MOV:I.W #H'B461, R0", + "following_bsr": { + "address": 46196, + "target": 23432, + "instruction": "BSR H'5B88" + } + } + ], + "xref_count": 1 + }, + { + "address": 46207, + "length": 17, + "text": " RED GREEN BLUE X", + "trimmed": "RED GREEN BLUE X", + "kind": "printable_run", + "score": 1.113, + "confidence": "high", + "xrefs": [ + { + "address": 46223, + "kind": "raw_mov_iw", + "target": 46207, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B47F, R0", + "following_bsr": { + "address": 46226, + "target": 24301, + "instruction": "BSR H'5EED" + } + } + ], + "xref_count": 1 + }, + { + "address": 46391, + "length": 17, + "text": " RECALL X", + "trimmed": "RECALL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 46407, + "kind": "raw_mov_iw", + "target": 46391, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B537, R0", + "following_bsr": { + "address": 46410, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46424, + "length": 17, + "text": "SCENE F. RECALL~X", + "trimmed": "SCENE F. RECALL~X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 46440, + "kind": "raw_mov_iw", + "target": 46424, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B558, R0", + "following_bsr": { + "address": 46443, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46457, + "length": 17, + "text": " SEL X", + "trimmed": "SEL X", + "kind": "printable_run", + "score": 1.023, + "confidence": "medium", + "xrefs": [ + { + "address": 46473, + "kind": "raw_mov_iw", + "target": 46457, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B579, R0", + "following_bsr": { + "address": 46476, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46632, + "length": 17, + "text": " RECALL X", + "trimmed": "RECALL X", + "kind": "printable_run", + "score": 1.067, + "confidence": "high", + "xrefs": [ + { + "address": 46648, + "kind": "raw_mov_iw", + "target": 46632, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B628, R0", + "following_bsr": { + "address": 46651, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46665, + "length": 17, + "text": "SETUP F. RECALL~X", + "trimmed": "SETUP F. RECALL~X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 46681, + "kind": "raw_mov_iw", + "target": 46665, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B649, R0", + "following_bsr": { + "address": 46684, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46698, + "length": 17, + "text": " SEL X", + "trimmed": "SEL X", + "kind": "printable_run", + "score": 1.023, + "confidence": "medium", + "xrefs": [ + { + "address": 46714, + "kind": "raw_mov_iw", + "target": 46698, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B66A, R0", + "following_bsr": { + "address": 46717, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46875, + "length": 17, + "text": " STORE X", + "trimmed": "STORE X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 46891, + "kind": "raw_mov_iw", + "target": 46875, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B71B, R0", + "following_bsr": { + "address": 46894, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46908, + "length": 17, + "text": " SCENE F. STORE~X", + "trimmed": "SCENE F. STORE~X", + "kind": "printable_run", + "score": 1.044, + "confidence": "medium", + "xrefs": [ + { + "address": 46924, + "kind": "raw_mov_iw", + "target": 46908, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B73C, R0", + "following_bsr": { + "address": 46927, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 46941, + "length": 17, + "text": " CUR SEL CHR X", + "trimmed": "CUR SEL CHR X", + "kind": "printable_run", + "score": 1.075, + "confidence": "high", + "xrefs": [ + { + "address": 46957, + "kind": "raw_mov_iw", + "target": 46941, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B75D, R0", + "following_bsr": { + "address": 46960, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 47139, + "length": 17, + "text": " STORE X", + "trimmed": "STORE X", + "kind": "printable_run", + "score": 1.05, + "confidence": "high", + "xrefs": [ + { + "address": 47155, + "kind": "raw_mov_iw", + "target": 47139, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B823, R0", + "following_bsr": { + "address": 47158, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 47172, + "length": 17, + "text": " SETUP F. STORE~X", + "trimmed": "SETUP F. STORE~X", + "kind": "printable_run", + "score": 1.044, + "confidence": "medium", + "xrefs": [ + { + "address": 47188, + "kind": "raw_mov_iw", + "target": 47172, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B844, R0", + "following_bsr": { + "address": 47191, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 47204, + "length": 17, + "text": " CUR SEL CHR X", + "trimmed": "CUR SEL CHR X", + "kind": "printable_run", + "score": 1.075, + "confidence": "high", + "xrefs": [ + { + "address": 47220, + "kind": "raw_mov_iw", + "target": 47204, + "delta": 0, + "register": "R0", + "instruction": "MOV:I.W #H'B864, R0", + "following_bsr": { + "address": 47223, + "target": 23185, + "instruction": "BSR H'5A91" + } + } + ], + "xref_count": 1 + }, + { + "address": 47506, + "length": 32, + "text": "01020304050607080910111213141516", + "trimmed": "01020304050607080910111213141516", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium" + }, + { + "address": 52953, + "length": 4, + "text": "1234", + "trimmed": "1234", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium" + }, + { + "address": 52958, + "length": 8, + "text": "8965.,-(", + "trimmed": "8965.,-(", + "kind": "printable_run", + "score": 1.0, + "confidence": "medium" + } + ], + "regions": [ + { + "start": 25559, + "end": 26456, + "count": 15, + "samples": [ + "OPERATION", + "PAINT", + "OPERATION", + "IRIS/M.BLK", + "OPERATION", + "LOCK", + "DYNA LATITUDE Xe/", + "HIGH LOW~XeP" + ] + }, + { + "start": 26592, + "end": 26673, + "count": 2, + "samples": [ + "TLCS Xg", + "AGC GAIN AE Xh" + ] + }, + { + "start": 27215, + "end": 27719, + "count": 8, + "samples": [ + "AUTO FUNC XjO", + "A.IRIS MODE Xj", + "AI BACK.L~Xj", + "AUTO FUNC Xk=", + "AUTO FOCUS Xk^", + "DIAG Xk", + "DIAG DATA Xl", + "RESET REQ~Xl4" + ] + }, + { + "start": 28548, + "end": 28608, + "count": 2, + "samples": [ + "OTHERS Xo", + "SHUTTER Xo" + ] + }, + { + "start": 28754, + "end": 29815, + "count": 15, + "samples": [ + "SET RCP", + "MASTER", + "OTHERS Xp", + "COPY TO SLAVES~Xp", + "CAM ID SET~XqD", + "OTHERS Xq", + "CAM ID IND Xq", + "TITLE IND Xr" + ] + }, + { + "start": 30074, + "end": 30756, + "count": 14, + "samples": [ + "BARS TYPE Xuz", + "SMPTE Xu", + "SPLIT Xu", + "FULLFIELD 75% Xu", + "EBU 75% Xu", + "FULLFIELD100% Xv", + "EBU 100% Xv1", + "SNG XvH" + ] + }, + { + "start": 30901, + "end": 31023, + "count": 4, + "samples": [ + "OTHERS Xx", + "WHITE BLACK~Xx", + "COMM LINK ITEM-2Xx", + "FLARE Xy" + ] + }, + { + "start": 33180, + "end": 34729, + "count": 28, + "samples": [ + "SHADING X", + "WHITE~X", + "SHADING AUTO SETX", + "BLACK~X", + "SHADING X", + "WHITE V SAW X", + "RED GREEN BLUE X", + "SHADING X" + ] + }, + { + "start": 34877, + "end": 35161, + "count": 7, + "samples": [ + "MATRIX X", + "STD FL~X", + "PRESET MATRIX X", + "H.SAT SPCL~X", + "MATRIX X", + "ON OFF~X", + "SAT HUE X" + ] + }, + { + "start": 35340, + "end": 35756, + "count": 7, + "samples": [ + "MATRIX X", + "ON SKIN OFF~X", + "SAT HUE X", + "MATRIX X", + "R-G R-B G-R X", + "MATRIX X", + "G-B B-R B-G X" + ] + }, + { + "start": 36023, + "end": 36093, + "count": 2, + "samples": [ + "FILTER X", + "1 2 3 4 X" + ] + }, + { + "start": 36439, + "end": 36519, + "count": 3, + "samples": [ + "LENS X", + "ON CONT1 OFF~X", + "FOCUS ZOOM X" + ] + }, + { + "start": 36659, + "end": 36739, + "count": 3, + "samples": [ + "PAN/TILT X", + "ON CONT2 OFF~X", + "PAN TILT X" + ] + }, + { + "start": 36912, + "end": 37565, + "count": 11, + "samples": [ + "SKIN GATE X", + "ON IND OFF~X", + "GATE SIZE X", + "SKIN GATE X", + "SIZE X", + "R-Y B-Y X", + "SKIN GATE X", + "POSI X" + ] + }, + { + "start": 37916, + "end": 38154, + "count": 5, + "samples": [ + "ITEM", + "NOT AVAILABLE", + "TLCS", + "ON", + "FILTER" + ] + }, + { + "start": 38396, + "end": 39167, + "count": 16, + "samples": [ + "KNEE", + "AUTO", + "PRESET", + "DL", + "FLARE", + "OFF", + "ATW", + "ON" + ] + }, + { + "start": 39307, + "end": 39579, + "count": 6, + "samples": [ + "AUTO SKIN X", + "START:PUSH AGAINX", + "GATE SIZE X", + "AUTO SKIN X", + "ON WINDOW OFF~X", + "H-POSI V-POSIX" + ] + }, + { + "start": 39719, + "end": 39918, + "count": 4, + "samples": [ + "AUTO SKIN X", + "ON WINDOW OFF~X", + "WIDTH HEIGHTX", + "AUTO SKIN" + ] + }, + { + "start": 40313, + "end": 40490, + "count": 4, + "samples": [ + "WHITE SHADING", + "AUTO SET", + "BLACK SHADING", + "AUTO SET" + ] + }, + { + "start": 40856, + "end": 41011, + "count": 4, + "samples": [ + "COPY", + "IN PROGRESS", + "COPY", + "COMPLETED" + ] + }, + { + "start": 41372, + "end": 41561, + "count": 5, + "samples": [ + "WHITE", + "AUTO", + "OK", + "OK:UNDER1700K", + "OK:OVER10000K" + ] + }, + { + "start": 41949, + "end": 41995, + "count": 2, + "samples": [ + "OPERATION", + "PRESET" + ] + }, + { + "start": 42178, + "end": 42278, + "count": 3, + "samples": [ + "BLACK", + "AUTO", + "OK" + ] + }, + { + "start": 42701, + "end": 42740, + "count": 2, + "samples": [ + "FLARE", + "RED GREEN BLUE" + ] + }, + { + "start": 43169, + "end": 43228, + "count": 2, + "samples": [ + "DETAIL X", + "FREQ H/V X" + ] + }, + { + "start": 43433, + "end": 43830, + "count": 8, + "samples": [ + "DETAIL X", + "ON OFF~X", + "DETAIL X", + "LEV V-DTLX", + "CRISP DEP LIMITX", + "DETAIL X", + "HIGH AFTERX", + "LIGHT GAMMAX" + ] + }, + { + "start": 43968, + "end": 44443, + "count": 11, + "samples": [ + "DETAIL X", + "APERTURE X", + "LEVEL X", + "ON OFF~X", + "DETAIL X", + "KNEE APERTURE X", + "LEVEL X", + "ON OFF~X" + ] + }, + { + "start": 44574, + "end": 44862, + "count": 7, + "samples": [ + "DETAIL X", + "ON RED OFF~X", + "COMB FILTER X", + "ON GRN OFF~X", + "GAMMA X", + "ON OFF~X", + "RED MAST BLUE X" + ] + }, + { + "start": 44997, + "end": 45107, + "count": 3, + "samples": [ + "GAMMA X", + "GAMMA INIT GAIN X", + "4.0 X" + ] + }, + { + "start": 45249, + "end": 46224, + "count": 16, + "samples": [ + "KNEE X", + "PRESET X", + "MANUAL KNEE X", + "VARIABLE X", + "KNEE X", + "POINT SLOPEX", + "PRESET X", + "AUTO X" + ] + }, + { + "start": 46391, + "end": 46474, + "count": 3, + "samples": [ + "RECALL X", + "SCENE F. RECALL~X", + "SEL X" + ] + }, + { + "start": 46632, + "end": 46715, + "count": 3, + "samples": [ + "RECALL X", + "SETUP F. RECALL~X", + "SEL X" + ] + }, + { + "start": 46875, + "end": 46958, + "count": 3, + "samples": [ + "STORE X", + "SCENE F. STORE~X", + "CUR SEL CHR X" + ] + }, + { + "start": 47139, + "end": 47221, + "count": 3, + "samples": [ + "STORE X", + "SETUP F. STORE~X", + "CUR SEL CHR X" + ] + }, + { + "start": 52953, + "end": 52966, + "count": 2, + "samples": [ + "1234", + "8965.,-(" + ] + } + ], + "searches": [ + { + "term": "CONNECT", + "literal_hits": [], + "candidate_hits": [], + "near_matches": [ + { + "address": 40997, + "text": " COMPLETED ", + "trimmed": "COMPLETED", + "score": 0.5 + }, + { + "address": 36473, + "text": "ON CONT1 OFF~X", + "trimmed": "ON CONT1 OFF~X", + "score": 0.444 + }, + { + "address": 36693, + "text": "ON CONT2 OFF~X", + "trimmed": "ON CONT2 OFF~X", + "score": 0.444 + }, + { + "address": 38057, + "text": " ON ", + "trimmed": "ON", + "score": 0.444 + }, + { + "address": 38707, + "text": " ON ", + "trimmed": "ON", + "score": 0.444 + }, + { + "address": 40342, + "text": " AUTO SET ", + "trimmed": "AUTO SET", + "score": 0.429 + }, + { + "address": 40476, + "text": " AUTO SET ", + "trimmed": "AUTO SET", + "score": 0.429 + }, + { + "address": 46908, + "text": " SCENE F. STORE~X", + "trimmed": "SCENE F. STORE~X", + "score": 0.421 + }, + { + "address": 29733, + "text": " OTHERS Xt%", + "trimmed": "OTHERS Xt%", + "score": 0.4 + }, + { + "address": 29796, + "text": " SAFETY ZONE Xtd", + "trimmed": "SAFETY ZONE Xtd", + "score": 0.4 + }, + { + "address": 46424, + "text": "SCENE F. RECALL~X", + "trimmed": "SCENE F. RECALL~X", + "score": 0.4 + }, + { + "address": 26243, + "text": "POINT1 POINT2Xf", + "trimmed": "POINT1 POINT2Xf", + "score": 0.381 + } + ], + "status": "not_found" + } + ], + "notes": [ + "LCD text scan is byte-oriented and conservative; strings may be inline script fields.", + "Raw xrefs include MOV:I.W immediates to the string address and nearby record prefixes." + ] + }, + "lcd_driver": { + "addresses": [ + { + "address": 61952, + "name": "lcd_status_control", + "role": "status/control register inferred from busy polling and command writes" + }, + { + "address": 61953, + "name": "lcd_data", + "role": "data register inferred from paired data reads/writes" + } + ], + "accesses": [ + { + "address": 16202, + "instruction": "MOVFPE.B @H'F200, R0", + "lcd_address": 61952, + "lcd_name": "lcd_status_control", + "direction": "read", + "role": "lcd_status_read", + "register": "R0", + "summary": "LCD status read from E-clock H'F200" + }, + { + "address": 16219, + "instruction": "MOVTPE.B R4, @H'F200", + "lcd_address": 61952, + "lcd_name": "lcd_status_control", + "direction": "write", + "role": "lcd_command_or_address_write", + "register": "R4", + "summary": "LCD command/address write to E-clock H'F200" + }, + { + "address": 16226, + "instruction": "MOVTPE.B R4, @H'F201", + "lcd_address": 61953, + "lcd_name": "lcd_data", + "direction": "write", + "role": "lcd_data_write", + "register": "R4", + "summary": "LCD data write to E-clock H'F201" + }, + { + "address": 16237, + "instruction": "MOVFPE.B @H'F201, R4", + "lcd_address": 61953, + "lcd_name": "lcd_data", + "direction": "read", + "role": "lcd_data_read", + "register": "R4", + "summary": "LCD data read from E-clock H'F201" + } + ], + "polling_loops": [ + { + "read_address": 16202, + "test_address": 16207, + "branch_address": 16209, + "register": "R0", + "bit": 7, + "summary": "LCD busy-flag poll: read H'F200, test bit 7, branch until clear" + } + ], + "routines": [ + { + "start": 16192, + "end": 16244, + "accesses": [ + { + "address": 16202, + "instruction": "MOVFPE.B @H'F200, R0", + "lcd_address": 61952, + "lcd_name": "lcd_status_control", + "direction": "read", + "role": "lcd_status_read", + "register": "R0", + "summary": "LCD status read from E-clock H'F200" + }, + { + "address": 16219, + "instruction": "MOVTPE.B R4, @H'F200", + "lcd_address": 61952, + "lcd_name": "lcd_status_control", + "direction": "write", + "role": "lcd_command_or_address_write", + "register": "R4", + "summary": "LCD command/address write to E-clock H'F200" + }, + { + "address": 16226, + "instruction": "MOVTPE.B R4, @H'F201", + "lcd_address": 61953, + "lcd_name": "lcd_data", + "direction": "write", + "role": "lcd_data_write", + "register": "R4", + "summary": "LCD data write to E-clock H'F201" + }, + { + "address": 16237, + "instruction": "MOVFPE.B @H'F201, R4", + "lcd_address": 61953, + "lcd_name": "lcd_data", + "direction": "read", + "role": "lcd_data_read", + "register": "R4", + "summary": "LCD data read from E-clock H'F201" + } + ], + "roles": [ + "lcd_command_or_address_write", + "lcd_data_read", + "lcd_data_write", + "lcd_status_read" + ], + "role_hint": "lcd_wait_and_transfer" + } + ], + "instructions": { + "16202": [ + { + "address": 16202, + "instruction": "MOVFPE.B @H'F200, R0", + "lcd_address": 61952, + "lcd_name": "lcd_status_control", + "direction": "read", + "role": "lcd_status_read", + "register": "R0", + "summary": "LCD status read from E-clock H'F200" + }, + { + "address": 16202, + "kind": "lcd_busy_status_read", + "summary": "LCD busy-flag poll: read H'F200, test bit 7, branch until clear", + "loop_start": 16202 + } + ], + "16219": [ + { + "address": 16219, + "instruction": "MOVTPE.B R4, @H'F200", + "lcd_address": 61952, + "lcd_name": "lcd_status_control", + "direction": "write", + "role": "lcd_command_or_address_write", + "register": "R4", + "summary": "LCD command/address write to E-clock H'F200" + } + ], + "16226": [ + { + "address": 16226, + "instruction": "MOVTPE.B R4, @H'F201", + "lcd_address": 61953, + "lcd_name": "lcd_data", + "direction": "write", + "role": "lcd_data_write", + "register": "R4", + "summary": "LCD data write to E-clock H'F201" + } + ], + "16237": [ + { + "address": 16237, + "instruction": "MOVFPE.B @H'F201, R4", + "lcd_address": 61953, + "lcd_name": "lcd_data", + "direction": "read", + "role": "lcd_data_read", + "register": "R4", + "summary": "LCD data read from E-clock H'F201" + } + ], + "16207": [ + { + "address": 16207, + "kind": "lcd_busy_flag_test", + "summary": "LCD busy-flag poll: read H'F200, test bit 7, branch until clear", + "loop_start": 16202 + } + ], + "16209": [ + { + "address": 16209, + "kind": "lcd_busy_wait_branch", + "summary": "LCD busy-flag poll: read H'F200, test bit 7, branch until clear", + "loop_start": 16202 + } + ] + } + }, "instructions": [ { "address": 4096, @@ -115708,7 +122253,25 @@ "notes": [ "R0 unknown after memory load" ] - } + }, + "lcd_driver": [ + { + "address": 16202, + "instruction": "MOVFPE.B @H'F200, R0", + "lcd_address": 61952, + "lcd_name": "lcd_status_control", + "direction": "read", + "role": "lcd_status_read", + "register": "R0", + "summary": "LCD status read from E-clock H'F200" + }, + { + "address": 16202, + "kind": "lcd_busy_status_read", + "summary": "LCD busy-flag poll: read H'F200, test bit 7, branch until clear", + "loop_start": 16202 + } + ] }, { "address": 16207, @@ -115732,7 +122295,15 @@ "block": 16202, "changes": [], "notes": [] - } + }, + "lcd_driver": [ + { + "address": 16207, + "kind": "lcd_busy_flag_test", + "summary": "LCD busy-flag poll: read H'F200, test bit 7, branch until clear", + "loop_start": 16202 + } + ] }, { "address": 16209, @@ -115760,7 +122331,15 @@ "block": 16202, "changes": [], "notes": [] - } + }, + "lcd_driver": [ + { + "address": 16209, + "kind": "lcd_busy_wait_branch", + "summary": "LCD busy-flag poll: read H'F200, test bit 7, branch until clear", + "loop_start": 16202 + } + ] }, { "address": 16211, @@ -115935,7 +122514,19 @@ } ], "notes": [] - } + }, + "lcd_driver": [ + { + "address": 16219, + "instruction": "MOVTPE.B R4, @H'F200", + "lcd_address": 61952, + "lcd_name": "lcd_status_control", + "direction": "write", + "role": "lcd_command_or_address_write", + "register": "R4", + "summary": "LCD command/address write to E-clock H'F200" + } + ] }, { "address": 16224, @@ -116008,7 +122599,19 @@ } ], "notes": [] - } + }, + "lcd_driver": [ + { + "address": 16226, + "instruction": "MOVTPE.B R4, @H'F201", + "lcd_address": 61953, + "lcd_name": "lcd_data", + "direction": "write", + "role": "lcd_data_write", + "register": "R4", + "summary": "LCD data write to E-clock H'F201" + } + ] }, { "address": 16231, @@ -116128,7 +122731,19 @@ "notes": [ "R4 unknown after memory load" ] - } + }, + "lcd_driver": [ + { + "address": 16237, + "instruction": "MOVFPE.B @H'F201, R4", + "lcd_address": 61953, + "lcd_name": "lcd_data", + "direction": "read", + "role": "lcd_data_read", + "register": "R4", + "summary": "LCD data read from E-clock H'F201" + } + ] }, { "address": 16242, diff --git a/build/rom_pseudocode.c b/build/rom_pseudocode.c index 90fccd0..08f74f9 100644 --- a/build/rom_pseudocode.c +++ b/build/rom_pseudocode.c @@ -2116,21 +2116,21 @@ void loc_3F40(void) SR &= (uint16_t)(0x00FF); /* 3F42; ANDC.W #H'00FF, SR; cycles=4 */ SR |= (uint16_t)(0x0600); /* 3F46; ORC.W #H'0600, SR; cycles=4 */ do { - R0 = read_eclock(MEM8[0xF200]); /* 3F4A; MOVFPE.B @H'F200, R0; refs mem_F200; cycles=13 */ - set_flags_btst(R0, 7); /* 3F4F; BTST.B #7, R0; cycles=2 */ - } while (!Z); /* 3F51; BNE loc_3F4A; cycles=3/8 nt/t */ + R0 = read_eclock(MEM8[0xF200]); /* 3F4A; MOVFPE.B @H'F200, R0; LCD status read from E-clock H'F200; LCD busy-flag poll: read H'F200, test bit 7, branch until clear; refs mem_F200; cycles=13 */ + set_flags_btst(R0, 7); /* 3F4F; BTST.B #7, R0; LCD busy-flag poll: read H'F200, test bit 7, branch until clear; cycles=2 */ + } while (!Z); /* 3F51; BNE loc_3F4A; LCD busy-flag poll: read H'F200, test bit 7, branch until clear; cycles=3/8 nt/t */ set_flags_btst(R4, 8); /* 3F53; BTST.W #8, R4; cycles=3 */ if (!Z) goto loc_3F6D; /* 3F55; BNE loc_3F6D; cycles=3/8 nt/t */ set_flags_btst(R4, 9); /* 3F57; BTST.W #9, R4; cycles=3 */ if (!Z) goto loc_3F62; /* 3F59; BNE loc_3F62; cycles=3/8 nt/t */ - write_eclock(MEM8[0xF200], R4); /* 3F5B; MOVTPE.B R4, @H'F200; refs mem_F200; cycles=13 */ + write_eclock(MEM8[0xF200], R4); /* 3F5B; MOVTPE.B R4, @H'F200; LCD command/address write to E-clock H'F200; refs mem_F200; cycles=13 */ goto loc_3F72; /* 3F60; BRA loc_3F72; cycles=7 */ loc_3F62: - write_eclock(MEM8[0xF201], R4); /* 3F62; MOVTPE.B R4, @H'F201; refs mem_F201; cycles=13 */ + write_eclock(MEM8[0xF201], R4); /* 3F62; MOVTPE.B R4, @H'F201; LCD data write to E-clock H'F201; refs mem_F201; cycles=13 */ MEM16[0xFB00] += (uint16_t)(1); /* 3F67; ADD:Q.W #1, @H'FB00; refs ram_FB00; cycles=8 */ goto loc_3F72; /* 3F6B; BRA loc_3F72; cycles=8 */ loc_3F6D: - R4 = read_eclock(MEM8[0xF201]); /* 3F6D; MOVFPE.B @H'F201, R4; refs mem_F201; cycles=13 */ + R4 = read_eclock(MEM8[0xF201]); /* 3F6D; MOVFPE.B @H'F201, R4; LCD data read from E-clock H'F201; refs mem_F201; cycles=13 */ loc_3F72: SR = (uint16_t)(MEM16[R7++]); /* 3F72; LDC.W @R7+, SR; cycles=7 */ return; /* 3F74; RTS; cycles=12 */ diff --git a/h8536/board_profile.py b/h8536/board_profile.py new file mode 100644 index 0000000..7953a00 --- /dev/null +++ b/h8536/board_profile.py @@ -0,0 +1,521 @@ +from __future__ import annotations + +from collections.abc import Mapping + +from .formatting import parse_int +from .model import Instruction + + +SCI_REGISTERS: dict[str, dict[str, int]] = { + "SCI1": { + "SMR": 0xFED8, + "BRR": 0xFED9, + "SCR": 0xFEDA, + "TDR": 0xFEDB, + "SSR": 0xFEDC, + "RDR": 0xFEDD, + }, + "SCI2": { + "SMR": 0xFEF0, + "BRR": 0xFEF1, + "SCR": 0xFEF2, + "TDR": 0xFEF3, + "SSR": 0xFEF4, + "RDR": 0xFEF5, + }, +} + +SCI_REGISTER_BY_ADDRESS = { + address: (channel, register) + for channel, registers in SCI_REGISTERS.items() + for register, address in registers.items() +} + +SYSCR2_ADDRESS = 0xFEFD +SYSCR2_INITIAL = 0x80 +P9SCI2E_BIT = 0 +SCR_INITIAL = 0x0C + +MANUAL_REFERENCES = [ + "Manual/0900766b802125d0.md:2417 FP-80 H8/536 pin 66 is P95/TXD", + "Manual/0900766b802125d0.md:2418 FP-80 H8/536 pin 67 is P96/RXD", + "Manual/0900766b802125d0.md:11192 Port 9 carries SCI1 and SCI2 serial signals", + "Manual/0900766b802125d0.md:11201 P96 is RXD1 input", + "Manual/0900766b802125d0.md:11202 P95 is TXD1 output", + "Manual/0900766b802125d0.md:15725 SCI1 RXD input pin", + "Manual/0900766b802125d0.md:15726 SCI1 TXD output pin", + "Manual/0900766b802125d0.md:15750 SCI register table starts with SCI1 RDR/TDR/SMR/SCR/SSR/BRR", + "Manual/0900766b802125d0.md:15758 SCI register table lists SCI2 RDR/TDR/SMR/SCR/SSR/BRR", + "Manual/0900766b802125d0.md:15794 RDR receive data register", + "Manual/0900766b802125d0.md:15823 TDR transmit data register", + "Manual/0900766b802125d0.md:15969 SCR enables and disables SCI functions", + "Manual/0900766b802125d0.md:16009 SCR.TE makes the TXD pin output", + "Manual/0900766b802125d0.md:16029 SCR.RE makes the RXD pin input", + "Manual/0900766b802125d0.md:16090 SSR contains transmit/receive status flags", + "Manual/0900766b802125d0.md:10560 SYSCR2 controls port 9 pin functions", + "Manual/0900766b802125d0.md:10631 SYSCR2.P9SCI2E controls the SCI2 functions of P92-P94", +] + +BOARD_PROFILES = { + "sony_rcp_tx7": { + "name": "Sony RCP-TX7", + "summary": "Board trace ties the H8/536 SCI1 pins to a MAX202 RS232 transceiver.", + "manual_references": MANUAL_REFERENCES, + "traces": [ + { + "channel": "SCI1", + "signal": "TXD", + "h8_pin": 66, + "h8_pin_name": "P95/TXD", + "h8_function": "TXD1", + "max202_pin": 11, + "evidence": "MAX202 pin 11 traces to H8 pin 66", + }, + { + "channel": "SCI1", + "signal": "RXD", + "h8_pin": 67, + "h8_pin_name": "P96/RXD", + "h8_function": "RXD1", + "max202_pin": 12, + "evidence": "MAX202 pin 12 traces to H8 pin 67", + }, + ], + }, +} + +_READ_ONLY_ROOTS = {"BTST", "CMP", "CMP:E", "CMP:G", "CMP:I", "MOVFPE", "TST"} +_BIT_WRITE_ROOTS = {"BCLR", "BNOT", "BSET"} + + +def analyze_board_profile( + instructions: Mapping[int, Instruction], + board: str = "sony_rcp_tx7", +) -> dict[str, object]: + """Annotate board-specific serial-path accesses without changing disassembly output.""" + if board not in BOARD_PROFILES: + raise ValueError(f"unsupported board profile: {board}") + + profile = BOARD_PROFILES[board] + annotations: dict[int, str] = {} + instruction_metadata: dict[int, dict[str, object]] = {} + channels = _initial_channel_payload(profile) + register_values: dict[int, int | None] = { + SYSCR2_ADDRESS: SYSCR2_INITIAL, + SCI_REGISTERS["SCI1"]["SCR"]: SCR_INITIAL, + SCI_REGISTERS["SCI2"]["SCR"]: SCR_INITIAL, + } + + for address in sorted(instructions): + ins = instructions[address] + access_kind = _access_kind(ins) + access_records: list[dict[str, object]] = [] + comments: list[str] = [] + + if SYSCR2_ADDRESS in _expanded_references(ins, access_kind): + value = _write_value(ins, SYSCR2_ADDRESS, register_values.get(SYSCR2_ADDRESS), 1, 0) + if access_kind == "write": + register_values[SYSCR2_ADDRESS] = value + record = _syscr2_access(ins, access_kind, register_values.get(SYSCR2_ADDRESS)) + access_records.append(record) + comments.append(str(record["comment"])) + + for target in _sci_targets(ins, access_kind): + register_address = int(target["register_address"]) + value = _write_value( + ins, + register_address, + register_values.get(register_address), + int(target["width"]), + int(target["index"]), + ) + if access_kind == "write": + register_values[register_address] = value + + channel = str(target["channel"]) + register = str(target["register"]) + p9sci2e = _bit_state(register_values.get(SYSCR2_ADDRESS), P9SCI2E_BIT) + record = _sci_access( + ins, + channel, + register, + register_address, + access_kind, + value, + register_values.get(register_address), + p9sci2e, + ) + access_records.append(record) + comments.append(str(record["comment"])) + channel_payload = channels[channel] + channel_accesses = channel_payload["accesses"] + if isinstance(channel_accesses, list): + channel_accesses.append(record) + if register == "SCR": + channel_payload["scr"] = _scr_metadata(register_values.get(register_address)) + + if access_records: + comment = "; ".join(_dedupe(comments)) + annotations[ins.address] = comment + instruction_metadata[ins.address] = { + "accesses": access_records, + "comment": comment, + } + + channels["SCI2"]["p9sci2e"] = _bit_state(register_values.get(SYSCR2_ADDRESS), P9SCI2E_BIT) + + return { + "board": board, + "name": profile["name"], + "summary": profile["summary"], + "manual_references": list(profile["manual_references"]), + "traces": [dict(trace) for trace in profile["traces"]], + "channels": channels, + "annotations": annotations, + "instructions": instruction_metadata, + "state": { + "SYSCR2": _register_state(register_values.get(SYSCR2_ADDRESS)), + "P9SCI2E": _bit_state(register_values.get(SYSCR2_ADDRESS), P9SCI2E_BIT), + }, + } + + +def board_comment_for_instruction(analysis: Mapping[str, object] | None, address: int) -> str: + if not analysis: + return "" + annotations = analysis.get("annotations") + if not isinstance(annotations, Mapping): + return "" + comment = annotations.get(address) + if comment is None: + comment = annotations.get(str(address)) + return str(comment) if comment else "" + + +def board_metadata_for_instruction( + analysis: Mapping[str, object] | None, + address: int, +) -> dict[str, object] | None: + if not analysis: + return None + instructions = analysis.get("instructions") + if not isinstance(instructions, Mapping): + return None + metadata = instructions.get(address) + if metadata is None: + metadata = instructions.get(str(address)) + return metadata if isinstance(metadata, dict) else None + + +def _initial_channel_payload(profile: Mapping[str, object]) -> dict[str, dict[str, object]]: + traces = [dict(trace) for trace in profile["traces"] if isinstance(trace, Mapping)] + return { + "SCI1": { + "traced_to_max202": True, + "path": "RS232/MAX202", + "pins": traces, + "scr": _scr_metadata(SCR_INITIAL), + "accesses": [], + }, + "SCI2": { + "traced_to_max202": False, + "path": None, + "note": "Sony RCP-TX7 MAX202 board traces are on SCI1 P95/P96, not SCI2 P92/P93.", + "p9sci2e": False, + "scr": _scr_metadata(SCR_INITIAL), + "accesses": [], + }, + } + + +def _syscr2_access(ins: Instruction, access: str, value: int | None) -> dict[str, object]: + p9sci2e = _bit_state(value, P9SCI2E_BIT) + comment = _syscr2_comment(access, p9sci2e) + record: dict[str, object] = { + "address": ins.address, + "instruction": ins.text, + "register": "SYSCR2", + "register_address": SYSCR2_ADDRESS, + "access": access, + "p9sci2e": p9sci2e, + "comment": comment, + } + if value is not None: + record["value"] = value + record["value_hex"] = _hex8(value) + return record + + +def _sci_access( + ins: Instruction, + channel: str, + register: str, + register_address: int, + access: str, + value: int | None, + state_value: int | None, + p9sci2e: bool | None, +) -> dict[str, object]: + comment = _sci_comment(channel, register, access, value if value is not None else state_value, p9sci2e) + record: dict[str, object] = { + "address": ins.address, + "instruction": ins.text, + "channel": channel, + "register": register, + "register_address": register_address, + "access": access, + "traced_to_max202": channel == "SCI1", + "comment": comment, + } + if value is not None: + record["value"] = value + record["value_hex"] = _hex8(value) + if register == "SCR": + record["scr"] = _scr_metadata(value if value is not None else state_value) + if channel == "SCI2": + record["p9sci2e"] = p9sci2e + return record + + +def _sci_comment( + channel: str, + register: str, + access: str, + value: int | None, + p9sci2e: bool | None, +) -> str: + if channel == "SCI1": + return _sci1_comment(register, access, value) + return _sci2_comment(register, access, p9sci2e) + + +def _sci1_comment(register: str, access: str, value: int | None) -> str: + if register in {"SMR", "BRR"}: + return ( + f"SCI1 {register} 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)" + ) + if register == "SCR": + bits = _scr_bits_text(value) + suffix = f" {bits}" if bits else "" + return ( + f"SCI1 SCR {access}{suffix}; TE/RE select the traced RS232/MAX202 pins " + "(P95/TXD pin 66 to MAX202 pin 11, P96/RXD pin 67 to MAX202 pin 12)" + ) + if register == "TDR": + verb = "transmits" if access == "write" else "accesses transmit buffer" + return ( + f"SCI1 TDR {access} {verb} on traced RS232/MAX202 path: " + "H8 pin 66 P95/TXD -> MAX202 pin 11" + ) + if register == "RDR": + verb = "receives" if access == "read" else "accesses receive buffer" + return ( + f"SCI1 RDR {access} {verb} from traced RS232/MAX202 path: " + "MAX202 pin 12 -> H8 pin 67 P96/RXD" + ) + if register == "SSR": + return "SCI1 SSR status for traced RS232/MAX202 path; TDRE/RDRF/error flags gate TDR/RDR use" + return f"SCI1 {register} {access} on traced RS232/MAX202 path" + + +def _sci2_comment(register: str, access: str, p9sci2e: bool | None) -> str: + prefix = f"SCI2 {register} {access}; not the traced MAX202 path" + if p9sci2e is False: + return ( + f"{prefix}; P9SCI2E=0 disables SCI2 pins P92/P93/P94, " + "while the board trace is SCI1 P95/P96" + ) + if p9sci2e is True: + return f"{prefix}; P9SCI2E=1 may route SCI2 pins, but the board trace is SCI1 P95/P96" + return f"{prefix}; P9SCI2E state unknown, and the board trace is SCI1 P95/P96" + + +def _syscr2_comment(access: str, p9sci2e: bool | None) -> str: + if p9sci2e is False: + return ( + f"SYSCR2 {access} leaves P9SCI2E=0; SCI2 pins are disabled, " + "so SCI2 is not the traced MAX202 path; traced RS232/MAX202 remains SCI1 P95/P96" + ) + if p9sci2e is True: + return ( + f"SYSCR2 {access} sets P9SCI2E=1; SCI2 pins may be enabled, " + "but Sony RCP-TX7 MAX202 traces are SCI1 P95/P96" + ) + return f"SYSCR2 {access}; P9SCI2E unknown, board trace remains SCI1 P95/P96" + + +def _sci_targets(ins: Instruction, access: str) -> list[dict[str, object]]: + width = _mnemonic_width(ins.mnemonic) + targets: list[dict[str, object]] = [] + seen: set[int] = set() + for base_address in ins.references: + target_width = width if _operand_references_memory(ins, access) else 1 + for index in range(target_width): + register_address = base_address + index + if register_address in seen: + continue + register_info = SCI_REGISTER_BY_ADDRESS.get(register_address) + if register_info is None: + continue + seen.add(register_address) + channel, register = register_info + targets.append( + { + "channel": channel, + "register": register, + "register_address": register_address, + "width": target_width, + "index": index, + }, + ) + return targets + + +def _expanded_references(ins: Instruction, access: str) -> set[int]: + width = _mnemonic_width(ins.mnemonic) + target_width = width if _operand_references_memory(ins, access) else 1 + addresses: set[int] = set() + for base_address in ins.references: + for index in range(target_width): + addresses.add(base_address + index) + return addresses + + +def _operand_references_memory(ins: Instruction, access: str) -> bool: + operand = _destination_operand(ins.operands) if access == "write" else _source_operand(ins.operands) + return bool(operand and operand.startswith("@")) + + +def _access_kind(ins: Instruction) -> str: + root = _mnemonic_root(ins.mnemonic) + if root in _READ_ONLY_ROOTS: + return "read" + destination = _destination_operand(ins.operands) + if destination and destination.startswith("@"): + return "write" + return "read" + + +def _write_value( + ins: Instruction, + register_address: int, + current_value: int | None, + width: int, + index: int, +) -> int | None: + if _access_kind(ins) != "write": + return None + + root = _mnemonic_root(ins.mnemonic) + if root == "CLR": + return 0 + if root in _BIT_WRITE_ROOTS: + bit = _immediate_bit(ins.operands) + if bit is None or current_value is None: + return None + if root == "BSET": + return (current_value | (1 << bit)) & 0xFF + if root == "BCLR": + return (current_value & ~(1 << bit)) & 0xFF + return (current_value ^ (1 << bit)) & 0xFF + + value = _immediate_source_value(ins.operands) + if value is None: + return None + return _byte_for_target(value, width, index) + + +def _destination_operand(operands: str) -> str | None: + operands = operands.strip() + if not operands: + return None + if "," not in operands: + return operands + return operands.rsplit(",", 1)[1].strip() + + +def _source_operand(operands: str) -> str | None: + operands = operands.strip() + if not operands: + return None + if "," not in operands: + return operands + return operands.rsplit(",", 1)[0].strip() + + +def _immediate_source_value(operands: str) -> int | None: + source = _source_operand(operands) or "" + if not source.startswith("#"): + return None + try: + return parse_int(source[1:]) + except ValueError: + return None + + +def _immediate_bit(operands: str) -> int | None: + value = _immediate_source_value(operands) + if value is None: + return None + return value if 0 <= value <= 7 else None + + +def _mnemonic_root(mnemonic: str) -> str: + return mnemonic.split(".", 1)[0] + + +def _mnemonic_width(mnemonic: str) -> int: + return 2 if mnemonic.endswith(".W") else 1 + + +def _byte_for_target(value: int, width: int, index: int) -> int: + shift = 8 * (width - index - 1) + return (value >> shift) & 0xFF + + +def _scr_metadata(value: int | None) -> dict[str, object]: + metadata = _register_state(value) + metadata.update( + { + "tie": None if value is None else bool(value & 0x80), + "rie": None if value is None else bool(value & 0x40), + "tx_enabled": None if value is None else bool(value & 0x20), + "rx_enabled": None if value is None else bool(value & 0x10), + }, + ) + return metadata + + +def _register_state(value: int | None) -> dict[str, object]: + return { + "value": value, + "value_hex": None if value is None else _hex8(value), + } + + +def _scr_bits_text(value: int | None) -> str: + if value is None: + return "" + return f"TE={1 if value & 0x20 else 0} RE={1 if value & 0x10 else 0}" + + +def _bit_state(value: int | None, bit: int) -> bool | None: + if value is None: + return None + return bool(value & (1 << bit)) + + +def _dedupe(items: list[str]) -> list[str]: + seen: set[str] = set() + output: list[str] = [] + for item in items: + if item in seen: + continue + seen.add(item) + output.append(item) + return output + + +def _hex8(value: int) -> str: + return f"H'{value & 0xFF:02X}" diff --git a/h8536/cli.py b/h8536/cli.py index 0d1de56..b19e210 100644 --- a/h8536/cli.py +++ b/h8536/cli.py @@ -10,6 +10,8 @@ from .dataflow import analyze_dataflow from .decoder import H8536Decoder from .formatting import parse_int from .indirect import analyze_indirect_flow +from .lcd_driver import analyze_lcd_driver +from .lcd_text import analyze_lcd_text from .peripheral_access import analyze_peripheral_access from .render import format_callgraph_dot, format_listing, write_json from .rom import Rom @@ -81,6 +83,8 @@ def main() -> int: sci_analysis = analyze_sci(instructions, clock_hz=args.clock_hz) peripheral_access = analyze_peripheral_access(instructions) indirect_flow = analyze_indirect_flow(rom, instructions, labels) + lcd_text = analyze_lcd_text(rom, instructions, start=args.start, end=end) + lcd_driver = analyze_lcd_driver(instructions) args.out.parent.mkdir(parents=True, exist_ok=True) args.out.write_text( @@ -101,6 +105,8 @@ def main() -> int: indirect_flow=indirect_flow, dataflow=dataflow, symbols=symbols, + lcd_text=lcd_text, + lcd_driver=lcd_driver, ), encoding="utf-8", ) @@ -120,6 +126,8 @@ def main() -> int: indirect_flow=indirect_flow, dataflow=dataflow, symbols=symbols, + lcd_text=lcd_text, + lcd_driver=lcd_driver, ) if args.callgraph_dot: args.callgraph_dot.parent.mkdir(parents=True, exist_ok=True) diff --git a/h8536/lcd_driver.py b/h8536/lcd_driver.py new file mode 100644 index 0000000..df8d947 --- /dev/null +++ b/h8536/lcd_driver.py @@ -0,0 +1,311 @@ +from __future__ import annotations + +import re +from collections.abc import Iterable, Mapping + +from .formatting import h16 +from .model import Instruction + + +LCD_STATUS_CONTROL = 0xF200 +LCD_DATA = 0xF201 +LCD_ADDRESSES = { + LCD_STATUS_CONTROL: "lcd_status_control", + LCD_DATA: "lcd_data", +} +ADDRESS_RE = re.compile(r"H'(?P[0-9A-Fa-f]{4})|0x(?P[0-9A-Fa-f]{4})") +REGISTER_RE = re.compile(r"\b(?PR[0-7])\b") + + +def analyze_lcd_driver(instructions: Mapping[int, Instruction] | Iterable[Instruction]) -> dict[str, object]: + ordered = _instruction_sequence(instructions) + by_address = {ins.address: ins for ins in ordered} + accesses = [_access_for_instruction(ins) for ins in ordered] + accesses = [access for access in accesses if access] + instruction_metadata: dict[int, list[dict[str, object]]] = {} + for access in accesses: + instruction_metadata.setdefault(int(access["address"]), []).append(access) + + polling_loops = _find_polling_loops(ordered, by_address) + for loop in polling_loops: + for address, role in ( + (int(loop["read_address"]), "lcd_busy_status_read"), + (int(loop["test_address"]), "lcd_busy_flag_test"), + (int(loop["branch_address"]), "lcd_busy_wait_branch"), + ): + instruction_metadata.setdefault(address, []).append( + { + "address": address, + "kind": role, + "summary": loop["summary"], + "loop_start": loop["read_address"], + }, + ) + + routines = _routine_candidates(ordered, accesses, polling_loops) + return { + "addresses": [ + {"address": address, "name": name, "role": _address_role(address)} + for address, name in LCD_ADDRESSES.items() + ], + "accesses": accesses, + "polling_loops": polling_loops, + "routines": routines, + "instructions": instruction_metadata, + } + + +def lcd_comment_for_instruction(analysis: Mapping[str, object] | None, address: int) -> str: + metadata = lcd_metadata_for_instruction(analysis, address) + if not metadata: + return "" + summaries = [] + for item in metadata: + if isinstance(item, Mapping) and item.get("summary"): + summary = str(item["summary"]) + if summary not in summaries: + summaries.append(summary) + return "; ".join(summaries) + + +def lcd_metadata_for_instruction( + analysis: Mapping[str, object] | None, + address: int, +) -> list[dict[str, object]]: + if not analysis: + return [] + instructions = analysis.get("instructions") + if not isinstance(instructions, Mapping): + return [] + metadata = instructions.get(address) + return list(metadata) if isinstance(metadata, list) else [] + + +def _instruction_sequence(instructions: Mapping[int, Instruction] | Iterable[Instruction]) -> list[Instruction]: + values = instructions.values() if isinstance(instructions, Mapping) else instructions + return sorted(values, key=lambda ins: ins.address) + + +def _access_for_instruction(ins: Instruction) -> dict[str, object] | None: + address = _lcd_address_for_instruction(ins) + if address is None: + return None + direction = _direction_for_instruction(ins, address) + role = _access_role(ins, address, direction) + register = _last_register(ins.operands) + return { + "address": ins.address, + "instruction": ins.text, + "lcd_address": address, + "lcd_name": LCD_ADDRESSES[address], + "direction": direction, + "role": role, + "register": register, + "summary": _access_summary(address, direction, role), + } + + +def _lcd_address_for_instruction(ins: Instruction) -> int | None: + for address in ins.references: + if address in LCD_ADDRESSES: + return address + for match in ADDRESS_RE.finditer(ins.operands): + value = int(match.group("hex") or match.group("c_hex"), 16) + if value in LCD_ADDRESSES: + return value + return None + + +def _direction_for_instruction(ins: Instruction, lcd_address: int) -> str: + mnemonic = ins.mnemonic.upper() + operands = [part.strip() for part in ins.operands.split(",")] + if mnemonic.startswith("MOVFPE"): + return "read" + if mnemonic.startswith("MOVTPE"): + return "write" + if len(operands) >= 2: + source_has_lcd = _operand_has_address(operands[0], lcd_address) + dest_has_lcd = _operand_has_address(operands[-1], lcd_address) + if source_has_lcd and not dest_has_lcd: + return "read" + if dest_has_lcd and not source_has_lcd: + return "write" + return "unknown" + + +def _operand_has_address(operand: str, address: int) -> bool: + return f"H'{address:04X}" in operand.upper() or f"0X{address:04X}" in operand.upper() + + +def _access_role(ins: Instruction, address: int, direction: str) -> str: + if address == LCD_STATUS_CONTROL and direction == "read": + return "lcd_status_read" + if address == LCD_STATUS_CONTROL and direction == "write": + return "lcd_command_or_address_write" + if address == LCD_DATA and direction == "read": + return "lcd_data_read" + if address == LCD_DATA and direction == "write": + return "lcd_data_write" + return "lcd_access" + + +def _access_summary(address: int, direction: str, role: str) -> str: + if role == "lcd_status_read": + return f"LCD status read from E-clock {h16(address)}" + if role == "lcd_command_or_address_write": + return f"LCD command/address write to E-clock {h16(address)}" + if role == "lcd_data_read": + return f"LCD data read from E-clock {h16(address)}" + if role == "lcd_data_write": + return f"LCD data write to E-clock {h16(address)}" + return f"LCD {direction} at E-clock {h16(address)}" + + +def _find_polling_loops( + ordered: list[Instruction], + by_address: Mapping[int, Instruction], +) -> list[dict[str, object]]: + loops: list[dict[str, object]] = [] + for index, ins in enumerate(ordered): + access = _access_for_instruction(ins) + if not access or access["role"] != "lcd_status_read": + continue + register = access.get("register") + if not isinstance(register, str): + continue + test = _next_register_bit_test(ordered, index, register) + if test is None: + continue + branch = _next_back_branch_to(ordered, by_address, ordered.index(test), ins.address, test.address) + if branch is None: + continue + loops.append( + { + "read_address": ins.address, + "test_address": test.address, + "branch_address": branch.address, + "register": register, + "bit": 7, + "summary": f"LCD busy-flag poll: read {h16(LCD_STATUS_CONTROL)}, test bit 7, branch until clear", + }, + ) + return loops + + +def _next_register_bit_test(ordered: list[Instruction], index: int, register: str) -> Instruction | None: + for candidate in ordered[index + 1 : index + 5]: + if not candidate.mnemonic.upper().startswith("BTST"): + continue + if "#7" not in candidate.operands: + continue + if re.search(rf"\b{re.escape(register)}\b", candidate.operands): + return candidate + return None + + +def _next_back_branch_to( + ordered: list[Instruction], + by_address: Mapping[int, Instruction], + index: int, + read_address: int, + test_address: int, +) -> Instruction | None: + _ = by_address + for candidate in ordered[index + 1 : index + 5]: + if candidate.kind != "branch": + continue + targets = [int(target) for target in candidate.targets] + if read_address in targets or test_address in targets: + return candidate + return None + + +def _routine_candidates( + ordered: list[Instruction], + accesses: list[dict[str, object]], + polling_loops: list[dict[str, object]], +) -> list[dict[str, object]]: + if not accesses: + return [] + address_to_access = {int(access["address"]): access for access in accesses} + loop_addresses = {int(loop["read_address"]) for loop in polling_loops} + routines: dict[tuple[int, int], dict[str, object]] = {} + for address in sorted(address_to_access): + start, end = _routine_span(ordered, address) + key = (start, end) + routine = routines.setdefault( + key, + { + "start": start, + "end": end, + "accesses": [], + "roles": [], + "role_hint": "lcd_access", + }, + ) + routine["accesses"].append(address_to_access[address]) + for routine in routines.values(): + roles = sorted({str(access["role"]) for access in routine["accesses"]}) + routine["roles"] = roles + routine["role_hint"] = _routine_role_hint(routine, loop_addresses) + return sorted(routines.values(), key=lambda item: int(item["start"])) + + +def _routine_span(ordered: list[Instruction], address: int) -> tuple[int, int]: + addresses = [ins.address for ins in ordered] + index = addresses.index(address) + start = ordered[index].address + cursor = index - 1 + while cursor >= 0: + previous = ordered[cursor] + if previous.kind in {"return", "rte"}: + break + if previous.address + max(previous.size, 1) != start: + break + start = previous.address + cursor -= 1 + + end = ordered[index].address + cursor = index + while cursor < len(ordered): + current = ordered[cursor] + end = current.address + if current.kind in {"return", "rte"}: + break + next_index = cursor + 1 + if next_index >= len(ordered): + break + next_address = ordered[next_index].address + if current.address + max(current.size, 1) != next_address: + break + cursor = next_index + return start, end + + +def _routine_role_hint(routine: Mapping[str, object], loop_addresses: set[int]) -> str: + access_addresses = {int(access["address"]) for access in routine.get("accesses", []) if isinstance(access, Mapping)} + roles = {str(role) for role in routine.get("roles", [])} + if access_addresses & loop_addresses and "lcd_data_write" in roles and "lcd_command_or_address_write" in roles: + return "lcd_wait_and_transfer" + if access_addresses & loop_addresses: + return "lcd_wait_ready" + if "lcd_data_write" in roles: + return "lcd_write_data" + if "lcd_command_or_address_write" in roles: + return "lcd_write_command_or_address" + if "lcd_data_read" in roles: + return "lcd_read_data" + return "lcd_access" + + +def _last_register(operands: str) -> str | None: + matches = list(REGISTER_RE.finditer(operands)) + return matches[-1].group("reg") if matches else None + + +def _address_role(address: int) -> str: + if address == LCD_STATUS_CONTROL: + return "status/control register inferred from busy polling and command writes" + if address == LCD_DATA: + return "data register inferred from paired data reads/writes" + return "unknown" diff --git a/h8536/lcd_text.py b/h8536/lcd_text.py new file mode 100644 index 0000000..c91969c --- /dev/null +++ b/h8536/lcd_text.py @@ -0,0 +1,386 @@ +from __future__ import annotations + +from collections.abc import Iterable, Mapping +from difflib import SequenceMatcher + +from .formatting import h16 +from .model import Instruction +from .rom import Rom + + +DISPLAY_PRINTABLE = set(range(0x20, 0x7F)) +DISPLAY_PUNCTUATION = set(b" ./:-+,%()[]") +DEFAULT_SEARCH_TERMS = ("CONNECT",) +MOV_IW_FIRST_OPCODE = 0x58 +MOV_IW_LAST_OPCODE = 0x5F + + +def analyze_lcd_text( + rom: Rom, + instructions: Mapping[int, Instruction] | Iterable[Instruction] | None = None, + *, + start: int | None = None, + end: int | None = None, + search_terms: Iterable[str] = DEFAULT_SEARCH_TERMS, + max_candidates: int = 240, +) -> dict[str, object]: + """Find likely fixed-width LCD/menu strings and their nearby raw xrefs. + + The firmware stores some display text as inline menu/script records rather + than as plain null-terminated strings. This pass scans the ROM bytes + directly, then correlates likely text fields with decoded and raw immediate + address loads such as ``MOV:I.W #H'63D4, R0``. + """ + + lower = 0 if start is None else max(0, start) + upper = rom.end if end is None else min(rom.end, end) + candidates = _unique_candidates( + [ + *_ff_terminated_candidates(rom, lower, upper), + *_printable_run_candidates(rom, lower, upper), + ], + ) + candidates = sorted(candidates, key=lambda item: (-float(item["score"]), int(item["address"])))[:max_candidates] + candidates.sort(key=lambda item: int(item["address"])) + + instruction_list = _instruction_sequence(instructions) + xrefs_by_address = _xref_map(rom, candidates, instruction_list) + for candidate in candidates: + xrefs = xrefs_by_address.get(int(candidate["address"]), []) + if xrefs: + candidate["xrefs"] = xrefs + candidate["xref_count"] = len(xrefs) + + regions = _group_regions(candidates) + searches = [_search_term(rom, candidates, term) for term in search_terms] + return { + "strings": candidates, + "regions": regions, + "searches": searches, + "notes": [ + "LCD text scan is byte-oriented and conservative; strings may be inline script fields.", + "Raw xrefs include MOV:I.W immediates to the string address and nearby record prefixes.", + ], + } + + +def lcd_text_comment_for_instruction(analysis: Mapping[str, object] | None, address: int) -> str: + if not analysis: + return "" + for candidate in analysis.get("strings", []): + if not isinstance(candidate, Mapping): + continue + for xref in candidate.get("xrefs", []): + if isinstance(xref, Mapping) and int(xref.get("address", -1)) == address: + text = str(candidate.get("trimmed") or candidate.get("text") or "").strip() + return f"LCD text xref {h16(int(candidate['address']))} {text!r}" + return "" + + +def _instruction_sequence( + instructions: Mapping[int, Instruction] | Iterable[Instruction] | None, +) -> list[Instruction]: + if instructions is None: + return [] + values = instructions.values() if isinstance(instructions, Mapping) else instructions + return sorted(values, key=lambda ins: ins.address) + + +def _ff_terminated_candidates(rom: Rom, start: int, end: int) -> list[dict[str, object]]: + candidates: list[dict[str, object]] = [] + address = start + while address < end: + if rom.u8(address) not in DISPLAY_PRINTABLE: + address += 1 + continue + text_start = address + raw = bytearray() + while address < end and rom.u8(address) in DISPLAY_PRINTABLE: + raw.append(rom.u8(address)) + address += 1 + ff_count = 0 + cursor = address + while cursor < end and rom.u8(cursor) == 0xFF: + ff_count += 1 + cursor += 1 + if ff_count and _looks_like_lcd_text(raw): + candidates.append(_candidate(text_start, raw, "ff_terminated", ff_count=ff_count)) + address = max(cursor, address + 1) + return candidates + + +def _printable_run_candidates(rom: Rom, start: int, end: int) -> list[dict[str, object]]: + candidates: list[dict[str, object]] = [] + address = start + while address < end: + if rom.u8(address) not in DISPLAY_PRINTABLE: + address += 1 + continue + text_start = address + raw = bytearray() + while address < end and rom.u8(address) in DISPLAY_PRINTABLE: + raw.append(rom.u8(address)) + address += 1 + if _looks_like_lcd_text(raw, allow_long=True): + candidates.append(_candidate(text_start, raw, "printable_run", ff_count=0)) + address += 1 + return candidates + + +def _candidate(address: int, raw: bytearray, kind: str, *, ff_count: int) -> dict[str, object]: + text = raw.decode("ascii", errors="replace") + trimmed = text.strip() + score = _display_score(raw, kind, ff_count) + payload: dict[str, object] = { + "address": address, + "length": len(raw), + "text": text, + "trimmed": trimmed, + "kind": kind, + "score": round(score, 3), + "confidence": _confidence(score), + } + if ff_count: + payload["ff_terminators"] = ff_count + if len(raw) > 32: + payload["segments"] = _fixed_width_segments(text) + return payload + + +def _unique_candidates(candidates: list[dict[str, object]]) -> list[dict[str, object]]: + by_key: dict[tuple[int, int], dict[str, object]] = {} + for candidate in candidates: + key = (int(candidate["address"]), int(candidate["length"])) + existing = by_key.get(key) + if existing is None or float(candidate["score"]) > float(existing["score"]): + by_key[key] = candidate + return list(by_key.values()) + + +def _looks_like_lcd_text(raw: bytearray, *, allow_long: bool = False) -> bool: + if len(raw) < 4: + return False + if len(raw) > 80 and not allow_long: + return False + trimmed = bytes(raw).strip() + if len(trimmed) < 2: + return False + good = sum(1 for value in trimmed if _display_char_score(value) > 0) + return good / max(len(trimmed), 1) >= 0.78 + + +def _display_char_score(value: int) -> float: + if 0x41 <= value <= 0x5A or 0x30 <= value <= 0x39: + return 1.0 + if value == 0x20: + return 0.8 + if value in DISPLAY_PUNCTUATION: + return 0.7 + if 0x61 <= value <= 0x7A: + return 0.35 + return 0.0 + + +def _display_score(raw: bytearray, kind: str, ff_count: int) -> float: + trimmed = bytes(raw).strip() + if not trimmed: + return 0.0 + char_score = sum(_display_char_score(value) for value in trimmed) / len(trimmed) + length_bonus = 0.15 if len(raw) in {8, 10, 16, 17, 18, 19, 20} else 0.0 + terminator_bonus = min(ff_count, 3) * 0.08 + kind_bonus = 0.08 if kind == "ff_terminated" else 0.0 + long_penalty = 0.2 if len(raw) > 40 else 0.0 + return max(0.0, char_score + length_bonus + terminator_bonus + kind_bonus - long_penalty) + + +def _confidence(score: float) -> str: + if score >= 1.05: + return "high" + if score >= 0.82: + return "medium" + return "low" + + +def _fixed_width_segments(text: str) -> list[dict[str, object]]: + segments: list[dict[str, object]] = [] + for width in (10, 16, 18, 20): + if len(text) < width * 2: + continue + chunks = [text[index : index + width] for index in range(0, len(text), width)] + useful = [chunk.strip() for chunk in chunks if len(chunk.strip()) >= 2] + if len(useful) >= 2: + segments.append({"width": width, "chunks": chunks}) + return segments[:3] + + +def _xref_map( + rom: Rom, + candidates: list[dict[str, object]], + instructions: list[Instruction], +) -> dict[int, list[dict[str, object]]]: + addresses = [int(candidate["address"]) for candidate in candidates] + target_to_address: dict[int, int] = {} + for address in addresses: + for delta in range(-4, 5): + target = address + delta + if 0 <= target <= 0xFFFF: + target_to_address.setdefault(target, address) + + xrefs: dict[int, list[dict[str, object]]] = {address: [] for address in addresses} + _add_decoded_xrefs(xrefs, target_to_address, instructions) + _add_raw_mov_iw_xrefs(xrefs, target_to_address, rom) + return {address: refs for address, refs in xrefs.items() if refs} + + +def _add_decoded_xrefs( + xrefs: dict[int, list[dict[str, object]]], + target_to_address: Mapping[int, int], + instructions: list[Instruction], +) -> None: + for ins in instructions: + for target, candidate_address in target_to_address.items(): + needle = f"H'{target:04X}" + if needle in ins.operands: + xrefs[candidate_address].append( + { + "address": ins.address, + "kind": "decoded_operand", + "target": target, + "delta": target - candidate_address, + "instruction": ins.text, + }, + ) + + +def _add_raw_mov_iw_xrefs( + xrefs: dict[int, list[dict[str, object]]], + target_to_address: Mapping[int, int], + rom: Rom, +) -> None: + data = rom.data + for address in range(0, max(len(data) - 2, 0)): + opcode = data[address] + if not MOV_IW_FIRST_OPCODE <= opcode <= MOV_IW_LAST_OPCODE: + continue + target = (data[address + 1] << 8) | data[address + 2] + candidate_address = target_to_address.get(target) + if candidate_address is None: + continue + register = f"R{opcode - MOV_IW_FIRST_OPCODE}" + xref: dict[str, object] = { + "address": address, + "kind": "raw_mov_iw", + "target": target, + "delta": target - candidate_address, + "register": register, + "instruction": f"MOV:I.W #{h16(target)}, {register}", + } + bsr = _following_bsr(data, address + 3) + if bsr: + xref["following_bsr"] = bsr + xrefs[candidate_address].append(xref) + + +def _following_bsr(data: bytes, address: int) -> dict[str, object] | None: + if address + 2 >= len(data) or data[address] != 0x1E: + return None + displacement = (data[address + 1] << 8) | data[address + 2] + if displacement & 0x8000: + displacement -= 0x10000 + target = (address + 3 + displacement) & 0xFFFF + return {"address": address, "target": target, "instruction": f"BSR {h16(target)}"} + + +def _group_regions(candidates: list[dict[str, object]]) -> list[dict[str, object]]: + regions: list[dict[str, object]] = [] + current: list[dict[str, object]] = [] + previous_end: int | None = None + for candidate in candidates: + address = int(candidate["address"]) + length = int(candidate["length"]) + if current and previous_end is not None and address - previous_end > 0x80: + _append_region(regions, current) + current = [] + current.append(candidate) + previous_end = address + length + if current: + _append_region(regions, current) + return regions + + +def _append_region(regions: list[dict[str, object]], candidates: list[dict[str, object]]) -> None: + if len(candidates) < 2: + return + start = int(candidates[0]["address"]) + end = max(int(item["address"]) + int(item["length"]) for item in candidates) + regions.append( + { + "start": start, + "end": end, + "count": len(candidates), + "samples": [str(item.get("trimmed") or item.get("text")) for item in candidates[:8]], + }, + ) + + +def _search_term(rom: Rom, candidates: list[dict[str, object]], term: str) -> dict[str, object]: + raw = term.encode("ascii", errors="ignore") + literal_hits = _literal_hits(rom.data, raw) + folded = term.upper() + candidate_hits = [ + { + "address": int(candidate["address"]), + "text": candidate["text"], + "trimmed": candidate["trimmed"], + } + for candidate in candidates + if folded in str(candidate.get("text", "")).upper() + ] + near_matches = _near_matches(candidates, term) + return { + "term": term, + "literal_hits": literal_hits, + "candidate_hits": candidate_hits, + "near_matches": near_matches, + "status": "found" if literal_hits or candidate_hits else "not_found", + } + + +def _literal_hits(data: bytes, needle: bytes) -> list[int]: + if not needle: + return [] + hits: list[int] = [] + start = 0 + upper_data = data.upper() + upper_needle = needle.upper() + while True: + index = upper_data.find(upper_needle, start) + if index < 0: + return hits + hits.append(index) + start = index + 1 + + +def _near_matches(candidates: list[dict[str, object]], term: str) -> list[dict[str, object]]: + normalized_term = _normalize_text(term) + matches: list[dict[str, object]] = [] + for candidate in candidates: + normalized = _normalize_text(str(candidate.get("trimmed") or candidate.get("text") or "")) + if not normalized: + continue + ratio = SequenceMatcher(None, normalized_term, normalized).ratio() + if ratio >= 0.34: + matches.append( + { + "address": int(candidate["address"]), + "text": candidate["text"], + "trimmed": candidate["trimmed"], + "score": round(ratio, 3), + }, + ) + matches.sort(key=lambda item: (-float(item["score"]), int(item["address"]))) + return matches[:12] + + +def _normalize_text(text: str) -> str: + return "".join(char for char in text.upper() if "A" <= char <= "Z" or "0" <= char <= "9") diff --git a/h8536/pseudocode.py b/h8536/pseudocode.py index 6263cbc..4428523 100644 --- a/h8536/pseudocode.py +++ b/h8536/pseudocode.py @@ -904,6 +904,14 @@ def _metadata_comments(ins: JsonObject) -> list[str]: if isinstance(indirect, dict) and indirect.get("summary"): comments.append(str(indirect["summary"])) + lcd_text = ins.get("lcd_text") + if isinstance(lcd_text, dict) and lcd_text.get("comment"): + comments.append(str(lcd_text["comment"])) + + for lcd_item in ins.get("lcd_driver", []): + if isinstance(lcd_item, dict) and lcd_item.get("summary"): + comments.append(str(lcd_item["summary"])) + dataflow = ins.get("dataflow") if isinstance(dataflow, dict): changes = dataflow.get("changes") diff --git a/h8536/render.py b/h8536/render.py index c660615..9a918e0 100644 --- a/h8536/render.py +++ b/h8536/render.py @@ -8,6 +8,8 @@ from .dataflow import state_for_instruction from .dtc import DtcEndpointInfo, DtcRegisterInfo from .formatting import h16, label_for from .indirect import indirect_comment_for_instruction, indirect_metadata_for_instruction +from .lcd_driver import lcd_comment_for_instruction, lcd_metadata_for_instruction +from .lcd_text import lcd_text_comment_for_instruction from .memory import MEMORY_REGIONS, region_for from .model import Instruction from .peripheral_access import ( @@ -118,6 +120,103 @@ def _dataflow_comment(analysis: dict[str, object] | None, address: int) -> str: return "dataflow " + ", ".join(parts[:4]) + suffix +def _lcd_text_lines(lcd_text: dict[str, object] | None) -> list[str]: + if not lcd_text: + return [] + strings = lcd_text.get("strings", []) + regions = lcd_text.get("regions", []) + searches = lcd_text.get("searches", []) + if not strings and not regions and not searches: + return [] + + lines = ["; LCD/Text Scan"] + for search in (searches if isinstance(searches, list) else []): + if not isinstance(search, dict): + continue + hits = len(search.get("literal_hits", [])) + len(search.get("candidate_hits", [])) + status = "found" if hits else "not literal" + lines.append(f"; search {search.get('term')!r}: {status}, hits={hits}") + near = search.get("near_matches", []) + if isinstance(near, list) and near: + sample = ", ".join(f"{h16(int(item['address']))} {item['trimmed']!r}" for item in near[:4]) + lines.append(f"; near: {sample}") + + if isinstance(regions, list) and regions: + lines.append("; LCD text regions") + for region in regions[:12]: + if not isinstance(region, dict): + continue + samples = ", ".join(repr(sample) for sample in region.get("samples", [])[:4]) + lines.append( + f"; region {h16(int(region['start']))}-{h16(int(region['end']))} " + f"count={region['count']:<3} {samples}", + ) + if len(regions) > 12: + lines.append(f"; ... {len(regions) - 12} more LCD text regions") + + if isinstance(strings, list) and strings: + lines.append("; LCD text candidates") + shown = 0 + for item in strings: + if not isinstance(item, dict): + continue + if item.get("confidence") == "low" and not item.get("xref_count"): + continue + xrefs = f" xrefs={item['xref_count']}" if item.get("xref_count") else "" + lines.append( + f"; text {h16(int(item['address'])):<8} len={item['length']:<3} " + f"{item['confidence']:<6} {str(item['trimmed'])!r}{xrefs}", + ) + shown += 1 + if shown >= 48: + break + if len(strings) > shown: + lines.append(f"; ... {len(strings) - shown} more LCD text candidates") + lines.append("") + return lines + + +def _lcd_driver_lines(lcd_driver: dict[str, object] | None) -> list[str]: + if not lcd_driver: + return [] + accesses = lcd_driver.get("accesses", []) + loops = lcd_driver.get("polling_loops", []) + routines = lcd_driver.get("routines", []) + if not accesses and not loops and not routines: + return [] + + lines = ["; LCD Driver Candidates"] + for address_info in lcd_driver.get("addresses", []): + if not isinstance(address_info, dict): + continue + lines.append( + f"; {h16(int(address_info['address']))} {address_info['name']:<18} {address_info['role']}", + ) + if isinstance(routines, list) and routines: + lines.append("; LCD routines") + for routine in routines[:16]: + if not isinstance(routine, dict): + continue + roles = ", ".join(str(role) for role in routine.get("roles", [])) + lines.append( + f"; routine {h16(int(routine['start']))}-{h16(int(routine['end']))} " + f"{routine['role_hint']:<24} {roles}", + ) + if len(routines) > 16: + lines.append(f"; ... {len(routines) - 16} more LCD routines") + if isinstance(loops, list) and loops: + lines.append("; LCD busy loops") + for loop in loops[:16]: + if not isinstance(loop, dict): + continue + lines.append( + f"; loop {h16(int(loop['read_address']))}->{h16(int(loop['branch_address']))} " + f"{loop['summary']}", + ) + lines.append("") + return lines + + def format_listing( rom_path: Path, rom: Rom, @@ -135,6 +234,8 @@ def format_listing( indirect_flow: dict[str, object] | None = None, dataflow: dict[str, object] | None = None, symbols: dict[str, object] | None = None, + lcd_text: dict[str, object] | None = None, + lcd_driver: dict[str, object] | None = None, ) -> str: lines: list[str] = [] lines.append("; H8/536 ROM disassembly") @@ -149,6 +250,7 @@ def format_listing( lines.append("; - The register field is H'FE80-H'FFFF; names below come from appendix B.") lines.append("; - @aa:8 short absolute operands use BR as the upper address byte.") lines.append("; - SCI baud inference uses section 14.2.8 BRR formulas when SMR/BRR are known.") + lines.append("; - LCD inference treats E-clock H'F200/H'F201 accesses as status/control and data candidates.") if sci_analysis and sci_analysis.get("clock_hz") is None: lines.append("; - Pass --clock-hz to convert SCI BRR settings into numeric baud rates.") if show_cycles: @@ -192,6 +294,8 @@ def format_listing( lines.append("") lines.extend(_symbol_lines(symbols)) + lines.extend(_lcd_text_lines(lcd_text)) + lines.extend(_lcd_driver_lines(lcd_driver)) if timing_summary: lines.extend(format_timing_summary(timing_summary)) @@ -210,6 +314,8 @@ def format_listing( sci_comment_for_instruction(sci_analysis, address), peripheral_comment_for_instruction(peripheral_access, address), indirect_comment_for_instruction(indirect_flow, address), + lcd_text_comment_for_instruction(lcd_text, address), + lcd_comment_for_instruction(lcd_driver, address), _dataflow_comment(dataflow, address), _reference_comment(ins, symbols) if not ins.comment else "", cycle_comment(ins.cycles) if show_cycles else "", @@ -236,6 +342,8 @@ def write_json( indirect_flow: dict[str, object] | None = None, dataflow: dict[str, object] | None = None, symbols: dict[str, object] | None = None, + lcd_text: dict[str, object] | None = None, + lcd_driver: dict[str, object] | None = None, ) -> None: payload = { "vectors": [ @@ -261,8 +369,10 @@ def write_json( "indirect_flow": indirect_flow or {"sites": []}, "dataflow": _dataflow_json_payload(dataflow), "symbols": symbols or {"symbols": [], "by_address": {}}, + "lcd_text": lcd_text or {"strings": [], "regions": [], "searches": []}, + "lcd_driver": lcd_driver or {"accesses": [], "polling_loops": [], "routines": []}, "instructions": [ - _instruction_payload(ins, sci_analysis, peripheral_access, indirect_flow, dataflow, symbols) + _instruction_payload(ins, sci_analysis, peripheral_access, indirect_flow, dataflow, symbols, lcd_text, lcd_driver) for ins in (instructions[addr] for addr in sorted(instructions)) ], } @@ -319,6 +429,8 @@ def _instruction_payload( indirect_flow: dict[str, object] | None = None, dataflow: dict[str, object] | None = None, symbols: dict[str, object] | None = None, + lcd_text: dict[str, object] | None = None, + lcd_driver: dict[str, object] | None = None, ) -> dict[str, object]: payload: dict[str, object] = { "address": ins.address, @@ -355,6 +467,12 @@ def _instruction_payload( dataflow_metadata = _dataflow_instruction_payload(dataflow, ins.address) if dataflow_metadata: payload["dataflow"] = dataflow_metadata + lcd_text_comment = lcd_text_comment_for_instruction(lcd_text, ins.address) + if lcd_text_comment: + payload["lcd_text"] = {"comment": lcd_text_comment} + lcd_driver_metadata = lcd_metadata_for_instruction(lcd_driver, ins.address) + if lcd_driver_metadata: + payload["lcd_driver"] = lcd_driver_metadata return payload diff --git a/h8536/sci_protocol.py b/h8536/sci_protocol.py new file mode 100644 index 0000000..fb783ce --- /dev/null +++ b/h8536/sci_protocol.py @@ -0,0 +1,446 @@ +from __future__ import annotations + +from collections.abc import Iterable, Mapping +from dataclasses import dataclass + +from .formatting import h16, parse_int +from .model import Instruction + + +MANUAL_REFERENCES = [ + "Manual/0900766b802125d0.md:15748 SCI register map for RDR/TDR/SCR/SSR", + "Manual/0900766b802125d0.md:15794 RDR stores received data and is CPU-readable", + "Manual/0900766b802125d0.md:15823 TDR holds the next byte to transmit", + "Manual/0900766b802125d0.md:15976 SCR.TIE enables/disables TXI on TDRE", + "Manual/0900766b802125d0.md:15993 SCR.RIE enables RXI and ERI", + "Manual/0900766b802125d0.md:16008 SCR.TE enables the transmitter", + "Manual/0900766b802125d0.md:16028 SCR.RE enables the receiver", + "Manual/0900766b802125d0.md:16090 SSR flags are cleared by writing zero", + "Manual/0900766b802125d0.md:16100 SSR.TDRE means TDR can accept the next byte", + "Manual/0900766b802125d0.md:16116 SSR.RDRF means received data reached RDR", + "Manual/0900766b802125d0.md:16127 SSR.ORER reports receive overrun", + "Manual/0900766b802125d0.md:16140 SSR.FER reports framing errors", + "Manual/0900766b802125d0.md:16147 SSR.PER reports parity errors", +] + + +@dataclass(frozen=True) +class SciRegister: + channel: str + name: str + address: int + + +SCI_REGISTERS: tuple[SciRegister, ...] = ( + SciRegister("SCI1", "SCR", 0xFEDA), + SciRegister("SCI1", "TDR", 0xFEDB), + SciRegister("SCI1", "SSR", 0xFEDC), + SciRegister("SCI1", "RDR", 0xFEDD), + SciRegister("SCI2", "SCR", 0xFEF2), + SciRegister("SCI2", "TDR", 0xFEF3), + SciRegister("SCI2", "SSR", 0xFEF4), + SciRegister("SCI2", "RDR", 0xFEF5), +) + +SCI_REGISTER_BY_ADDRESS = {register.address: register for register in SCI_REGISTERS} +SCI_CHANNELS = ("SCI1", "SCI2") + +SCR_CONTROL_BITS = { + 7: ("TIE", "TX interrupt", "TXI"), + 6: ("RIE", "RX/ERI interrupts", "RXI and ERI"), + 5: ("TE", "transmitter", "TXD output"), + 4: ("RE", "receiver", "RXD input"), +} + +SSR_FLAGS = { + 7: ("TDRE", "transmit data register empty"), + 6: ("RDRF", "receive-data-full"), + 5: ("ORER", "overrun error"), + 4: ("FER", "framing error"), + 3: ("PER", "parity error"), +} + +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)"), +} + + +def analyze_sci_protocol( + instructions: Mapping[int, Instruction] | Iterable[Instruction], +) -> dict[str, object]: + """Identify SCI protocol-level reads, writes, clears, and polling waits.""" + ordered = _instruction_sequence(instructions) + annotations: dict[int, list[str]] = {} + instruction_metadata: dict[int, list[dict[str, object]]] = {} + channels: dict[str, dict[str, list[dict[str, object]]]] = { + channel: {"events": []} for channel in SCI_CHANNELS + } + events: list[dict[str, object]] = [] + + def record(event: dict[str, object]) -> None: + public = dict(event) + events.append(public) + channel = str(public["channel"]) + channels[channel]["events"].append(public) + instruction_metadata.setdefault(int(public["address"]), []).append(public) + comment = public.get("comment") + if comment: + parts = annotations.setdefault(int(public["address"]), []) + text = str(comment) + if text not in parts: + parts.append(text) + + tdre_wait_events = _tdre_wait_events_by_address(ordered) + for ins in ordered: + for event in _instruction_events(ins): + record(event) + for event in tdre_wait_events.get(ins.address, []): + record(event) + + return { + "manual_references": MANUAL_REFERENCES, + "channels": channels, + "events": events, + "annotations": { + address: "; ".join(parts) + for address, parts in sorted(annotations.items()) + }, + "instructions": instruction_metadata, + } + + +def sci_protocol_comment_for_instruction(analysis: Mapping[str, object] | None, address: int) -> str: + if not analysis: + return "" + annotations = analysis.get("annotations") + if not isinstance(annotations, Mapping): + return "" + comment = annotations.get(address) + return str(comment) if comment else "" + + +def sci_protocol_metadata_for_instruction( + analysis: Mapping[str, object] | None, + address: int, +) -> list[dict[str, object]]: + if not analysis: + return [] + instructions = analysis.get("instructions") + if not isinstance(instructions, Mapping): + return [] + metadata = instructions.get(address) + return list(metadata) if isinstance(metadata, list) else [] + + +def sci_protocol_json_payload(analysis: Mapping[str, object] | None) -> dict[str, object]: + if not analysis: + return { + "manual_references": MANUAL_REFERENCES, + "channels": {channel: {"events": []} for channel in SCI_CHANNELS}, + "events": [], + } + return { + "manual_references": analysis.get("manual_references", MANUAL_REFERENCES), + "channels": analysis.get("channels", {}), + "events": analysis.get("events", []), + } + + +def _instruction_events(ins: Instruction) -> list[dict[str, object]]: + events: list[dict[str, object]] = [] + for register in _referenced_sci_registers(ins): + if register.name == "TDR": + events.extend(_tdr_events(ins, register)) + elif register.name == "RDR": + events.extend(_rdr_events(ins, register)) + elif register.name == "SSR": + events.extend(_ssr_events(ins, register)) + elif register.name == "SCR": + events.extend(_scr_events(ins, register)) + return events + + +def _tdr_events(ins: Instruction, register: SciRegister) -> list[dict[str, object]]: + if _access_direction(ins, register.address) != "write": + return [] + return [ + _event( + ins, + register, + action="write_tdr", + comment=f"write RS232/SCI byte to {register.channel} TDR for transmission", + ), + ] + + +def _rdr_events(ins: Instruction, register: SciRegister) -> list[dict[str, object]]: + if _access_direction(ins, register.address) != "read": + return [] + return [ + _event( + ins, + register, + action="read_rdr", + comment=f"read {register.channel} received byte from RDR", + ), + ] + + +def _ssr_events(ins: Instruction, register: SciRegister) -> list[dict[str, object]]: + if _access_direction(ins, register.address) != "write": + return [] + + bit = _immediate_bit(ins.operands) + if _mnemonic_root(ins.mnemonic) == "BCLR" and bit in SSR_CLEAR_ACTIONS: + action, comment_template = SSR_CLEAR_ACTIONS[bit] + flag, description = SSR_FLAGS[bit] + return [ + _event( + ins, + register, + action=action, + bit=bit, + flag=flag, + description=description, + comment=comment_template.format(channel=register.channel), + ), + ] + + value = _written_immediate_value(ins) + if value is None: + return [] + + events: list[dict[str, object]] = [] + for clear_bit, (action, comment_template) in SSR_CLEAR_ACTIONS.items(): + if value & (1 << clear_bit): + continue + flag, description = SSR_FLAGS[clear_bit] + events.append( + _event( + ins, + register, + action=action, + bit=clear_bit, + flag=flag, + description=description, + value=value, + comment=comment_template.format(channel=register.channel), + ), + ) + return events + + +def _scr_events(ins: Instruction, register: SciRegister) -> list[dict[str, object]]: + if _access_direction(ins, register.address) != "write": + return [] + + bit = _immediate_bit(ins.operands) + root = _mnemonic_root(ins.mnemonic) + if root in {"BCLR", "BSET"} and bit in SCR_CONTROL_BITS: + return [_scr_bit_event(ins, register, bit, enabled=root == "BSET")] + + value = _written_immediate_value(ins) + if value is None: + return [] + return [ + _scr_bit_event(ins, register, bit_number, enabled=bool(value & (1 << bit_number)), value=value) + for bit_number in SCR_CONTROL_BITS + ] + + +def _scr_bit_event( + ins: Instruction, + register: SciRegister, + bit: int, + enabled: bool, + value: int | None = None, +) -> dict[str, object]: + bit_name, noun, interrupt_source = SCR_CONTROL_BITS[bit] + verb = "enable" if enabled else "disable" + action_noun = noun.replace("/", "_").replace(" ", "_").lower() + if bit == 7: + comment = f"{verb} {register.channel} TX interrupt (TIE)" + elif bit == 6: + comment = f"{verb} {register.channel} receive and receive-error interrupts (RIE)" + elif bit == 5: + comment = f"{verb} {register.channel} transmitter (TE)" + else: + comment = f"{verb} {register.channel} receiver (RE)" + return _event( + ins, + register, + action=f"{verb}_{action_noun}", + bit=bit, + bit_name=bit_name, + enabled=enabled, + interrupt_source=interrupt_source, + value=value, + comment=comment, + ) + + +def _tdre_wait_events_by_address(ordered: list[Instruction]) -> dict[int, list[dict[str, object]]]: + events_by_address: dict[int, list[dict[str, object]]] = {} + for index, ins in enumerate(ordered): + register = _single_sci_register(ins) + if register is None or register.name != "SSR": + continue + if _mnemonic_root(ins.mnemonic) != "BTST" or _immediate_bit(ins.operands) != 7: + continue + branch = _next_beq_back_to(ordered, index, ins.address) + if branch is None: + continue + events_by_address.setdefault(ins.address, []).append( + _event( + ins, + register, + action="wait_for_tdre", + bit=7, + flag="TDRE", + branch_address=branch.address, + branch_target=ins.address, + comment=f"wait for {register.channel} transmit data register empty (TDRE=1)", + ), + ) + events_by_address.setdefault(branch.address, []).append( + _event( + branch, + register, + action="tdre_wait_branch", + bit=7, + flag="TDRE", + test_address=ins.address, + branch_target=ins.address, + comment=f"repeat {register.channel} transmit-empty wait while TDRE=0", + ), + ) + return events_by_address + + +def _next_beq_back_to(ordered: list[Instruction], index: int, target: int) -> Instruction | None: + for candidate in ordered[index + 1 : index + 5]: + if _mnemonic_root(candidate.mnemonic) != "BEQ": + continue + if target in candidate.targets: + return candidate + return None + + +def _event( + ins: Instruction, + register: SciRegister, + *, + action: str, + comment: str, + **extra: object, +) -> dict[str, object]: + event: dict[str, object] = { + "address": ins.address, + "instruction": ins.text, + "action": action, + "channel": register.channel, + "register": register.name, + "register_address": register.address, + "register_address_hex": h16(register.address), + "comment": comment, + "manual": MANUAL_REFERENCES, + } + event.update({key: value for key, value in extra.items() if value is not None}) + return event + + +def _instruction_sequence( + instructions: Mapping[int, Instruction] | Iterable[Instruction], +) -> list[Instruction]: + values = instructions.values() if isinstance(instructions, Mapping) else instructions + return sorted(values, key=lambda ins: ins.address) + + +def _referenced_sci_registers(ins: Instruction) -> list[SciRegister]: + registers: list[SciRegister] = [] + seen: set[int] = set() + for address in ins.references: + register = SCI_REGISTER_BY_ADDRESS.get(address) + if register is None or register.address in seen: + continue + seen.add(register.address) + registers.append(register) + return registers + + +def _single_sci_register(ins: Instruction) -> SciRegister | None: + registers = _referenced_sci_registers(ins) + return registers[0] if len(registers) == 1 else None + + +def _access_direction(ins: Instruction, address: int) -> str | None: + root = _mnemonic_root(ins.mnemonic) + if root in {"BTST", "CMP:E", "CMP:G", "CMP:I", "MOVFPE", "TST"}: + return "read" + if root in {"BCLR", "BNOT", "BSET", "CLR", "NEG", "NOT"}: + return "write" + if root in {"ADD:Q", "ADD:G", "ADDX", "AND", "OR", "SUB", "SUBS", "SUBX", "XOR"}: + return "write" + if root in {"MOV:G", "MOV:S", "MOVTPE"}: + source, destination = _source_destination_operands(ins.operands) + if _operand_mentions_address_or_register(destination, address): + return "write" + if _operand_mentions_address_or_register(source, address): + return "read" + if root in {"MOV:L", "MOV:F"}: + return "read" + if root == "STC": + return "write" + if root == "LDC": + return "read" + return None + + +def _source_destination_operands(operands: str) -> tuple[str, str]: + if "," not in operands: + operand = operands.strip() + return "", operand + source, destination = operands.rsplit(",", 1) + return source.strip(), destination.strip() + + +def _operand_mentions_address_or_register(operand: str, address: int) -> bool: + operand_upper = operand.upper() + register = SCI_REGISTER_BY_ADDRESS.get(address) + if register and f"{register.channel}_{register.name}" in operand_upper: + return True + return f"H'{address:04X}" in operand_upper or f"0X{address:04X}" in operand_upper + + +def _immediate_bit(operands: str) -> int | None: + source, _destination = _source_destination_operands(operands) + if not source.startswith("#"): + return None + try: + bit = parse_int(source[1:]) + except ValueError: + return None + return bit if 0 <= bit <= 7 else None + + +def _written_immediate_value(ins: Instruction) -> int | None: + root = _mnemonic_root(ins.mnemonic) + if root == "CLR": + return 0 + if root not in {"MOV:G", "MOV:S"}: + return None + source, _destination = _source_destination_operands(ins.operands) + if not source.startswith("#"): + return None + try: + return parse_int(source[1:]) & 0xFF + except ValueError: + return None + + +def _mnemonic_root(mnemonic: str) -> str: + return mnemonic.rsplit(".", 1)[0].upper() diff --git a/tests/test_board_profile.py b/tests/test_board_profile.py new file mode 100644 index 0000000..1024dc6 --- /dev/null +++ b/tests/test_board_profile.py @@ -0,0 +1,74 @@ +import json +import unittest + +from h8536.board_profile import analyze_board_profile, board_comment_for_instruction +from h8536.model import Instruction + + +def ins(address: int, mnemonic: str, operands: str, references: list[int]) -> Instruction: + return Instruction(address, b"\x00", mnemonic, operands, references=references) + + +class BoardProfileTest(unittest.TestCase): + def test_profile_records_manual_pin_table_and_board_traces(self): + analysis = analyze_board_profile({}) + + self.assertEqual(analysis["board"], "sony_rcp_tx7") + self.assertIn("Manual/0900766b802125d0.md:2417", " ".join(analysis["manual_references"])) + self.assertIn("Manual/0900766b802125d0.md:2418", " ".join(analysis["manual_references"])) + traces = analysis["traces"] + self.assertEqual(traces[0]["h8_pin"], 66) + self.assertEqual(traces[0]["max202_pin"], 11) + self.assertEqual(traces[1]["h8_pin"], 67) + self.assertEqual(traces[1]["max202_pin"], 12) + json.dumps(analysis) + + def test_sci1_init_and_scr_comments_identify_rs232_max202_path(self): + instructions = { + 0x1000: ins(0x1000, "MOV:G.W", "#H'0407, @SCI1_SMR", [0xFED8]), + 0x1004: ins(0x1004, "MOV:G.B", "#H'30, @SCI1_SCR", [0xFEDA]), + } + + analysis = analyze_board_profile(instructions) + + self.assertIn("SCI1 SMR serial init for traced RS232/MAX202 path", board_comment_for_instruction(analysis, 0x1000)) + self.assertIn("SCI1 BRR serial init for traced RS232/MAX202 path", board_comment_for_instruction(analysis, 0x1000)) + scr_comment = board_comment_for_instruction(analysis, 0x1004) + self.assertIn("SCI1 SCR write TE=1 RE=1", scr_comment) + self.assertIn("P95/TXD pin 66 to MAX202 pin 11", scr_comment) + self.assertIn("P96/RXD pin 67 to MAX202 pin 12", scr_comment) + + def test_sci1_data_and_status_registers_annotate_traced_path(self): + instructions = { + 0x1010: ins(0x1010, "BTST.B", "#7, @SCI1_SSR", [0xFEDC]), + 0x1012: ins(0x1012, "MOV:G.B", "R0L, @SCI1_TDR", [0xFEDB]), + 0x1014: ins(0x1014, "MOV:G.B", "@SCI1_RDR, R0L", [0xFEDD]), + } + + analysis = analyze_board_profile(instructions) + + self.assertIn("SCI1 SSR status for traced RS232/MAX202 path", board_comment_for_instruction(analysis, 0x1010)) + self.assertIn("H8 pin 66 P95/TXD -> MAX202 pin 11", board_comment_for_instruction(analysis, 0x1012)) + self.assertIn("MAX202 pin 12 -> H8 pin 67 P96/RXD", board_comment_for_instruction(analysis, 0x1014)) + + def test_sci2_disabled_comments_say_it_is_not_traced_path(self): + instructions = { + 0x2000: ins(0x2000, "MOV:G.B", "#H'80, @SYSCR2", [0xFEFD]), + 0x2004: ins(0x2004, "MOV:G.B", "#H'30, @SCI2_SCR", [0xFEF2]), + } + + analysis = analyze_board_profile(instructions) + + syscr2_comment = board_comment_for_instruction(analysis, 0x2000) + self.assertIn("P9SCI2E=0", syscr2_comment) + self.assertIn("SCI2 is not the traced MAX202 path", syscr2_comment) + + sci2_comment = board_comment_for_instruction(analysis, 0x2004) + self.assertIn("SCI2 SCR write; not the traced MAX202 path", sci2_comment) + self.assertIn("P9SCI2E=0 disables SCI2 pins P92/P93/P94", sci2_comment) + self.assertFalse(analysis["channels"]["SCI2"]["traced_to_max202"]) + self.assertFalse(analysis["channels"]["SCI2"]["p9sci2e"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_lcd_driver.py b/tests/test_lcd_driver.py new file mode 100644 index 0000000..8c05260 --- /dev/null +++ b/tests/test_lcd_driver.py @@ -0,0 +1,44 @@ +import unittest + +from h8536.lcd_driver import analyze_lcd_driver, lcd_comment_for_instruction +from h8536.model import Instruction + + +class LcdDriverTest(unittest.TestCase): + def test_detects_e_clock_lcd_accesses_and_busy_poll_loop(self): + instructions = { + 0x3F4A: Instruction( + 0x3F4A, + b"\x15\xF2\x00\x00\x80", + "MOVFPE.B", + "@H'F200, R0", + references=[0xF200], + ), + 0x3F4F: Instruction(0x3F4F, b"\xA0\xF7", "BTST.B", "#7, R0"), + 0x3F51: Instruction(0x3F51, b"\x26\xF7", "BNE", "loc_3F4A", kind="branch", targets=[0x3F4A]), + 0x3F53: Instruction(0x3F53, b"\x15\xF2\x00\x00\x94", "MOVTPE.B", "R4, @H'F200", references=[0xF200]), + 0x3F58: Instruction(0x3F58, b"\x15\xF2\x01\x00\x94", "MOVTPE.B", "R4, @H'F201", references=[0xF201]), + 0x3F5D: Instruction(0x3F5D, b"\x19", "RTS", kind="return", fallthrough=False), + } + + analysis = analyze_lcd_driver(instructions) + + self.assertEqual(len(analysis["accesses"]), 3) + self.assertEqual(analysis["polling_loops"][0]["read_address"], 0x3F4A) + self.assertEqual(analysis["routines"][0]["role_hint"], "lcd_wait_and_transfer") + self.assertIn("LCD busy-flag poll", lcd_comment_for_instruction(analysis, 0x3F51)) + self.assertIn("LCD data write", lcd_comment_for_instruction(analysis, 0x3F58)) + + def test_regex_fallback_detects_operands_without_references(self): + instructions = { + 0x0100: Instruction(0x0100, b"", "MOVTPE.B", "R1, @H'F201"), + } + + analysis = analyze_lcd_driver(instructions) + + self.assertEqual(analysis["accesses"][0]["lcd_address"], 0xF201) + self.assertEqual(analysis["accesses"][0]["role"], "lcd_data_write") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_lcd_text.py b/tests/test_lcd_text.py new file mode 100644 index 0000000..bc0ea3a --- /dev/null +++ b/tests/test_lcd_text.py @@ -0,0 +1,55 @@ +import unittest + +from h8536.lcd_text import analyze_lcd_text, lcd_text_comment_for_instruction +from h8536.model import Instruction +from h8536.rom import Rom + + +class LcdTextTest(unittest.TestCase): + def test_finds_ff_terminated_menu_strings_and_raw_mov_xrefs(self): + data = bytearray([0x00] * 0x2200) + data[0x1000:0x100D] = b"OPERATION " + b"\xFF\xFF\xFF" + data[0x100D:0x1013] = bytes.fromhex("58 0F FD 1E 00 1D") + data[0x1030:0x103D] = b" PAINT " + b"\xFF\xFF\xFF" + data[0x103D:0x1040] = bytes.fromhex("58 10 30") + + analysis = analyze_lcd_text(Rom(bytes(data)), search_terms=("CONNECT",)) + by_text = {item["trimmed"]: item for item in analysis["strings"]} + + self.assertIn("OPERATION", by_text) + self.assertIn("PAINT", by_text) + operation = by_text["OPERATION"] + self.assertEqual(operation["kind"], "ff_terminated") + self.assertEqual(operation["ff_terminators"], 3) + self.assertEqual(operation["xrefs"][0]["kind"], "raw_mov_iw") + self.assertEqual(operation["xrefs"][0]["target"], 0x0FFD) + self.assertEqual(operation["xrefs"][0]["delta"], -3) + self.assertEqual(operation["xrefs"][0]["following_bsr"]["target"], 0x1030) + self.assertEqual(analysis["searches"][0]["status"], "not_found") + + def test_groups_nearby_strings_into_regions(self): + data = bytearray([0x00] * 0x1400) + data[0x1200:0x120D] = b" LOCK " + b"\xFF\xFF\xFF" + data[0x1240:0x124D] = b"IRIS/M.BLK" + b"\xFF\xFF\xFF" + + analysis = analyze_lcd_text(Rom(bytes(data))) + + self.assertEqual(len(analysis["regions"]), 1) + self.assertEqual(analysis["regions"][0]["count"], 2) + self.assertIn("LOCK", analysis["regions"][0]["samples"]) + + def test_decoded_operand_xref_comment(self): + data = bytearray([0x00] * 0x1300) + data[0x1100:0x110D] = b"CONNECT? " + b"\xFF\xFF\xFF" + instructions = { + 0x0100: Instruction(0x0100, b"\x58\x11\x00", "MOV:I.W", "#H'1100, R0"), + } + + analysis = analyze_lcd_text(Rom(bytes(data)), instructions, search_terms=("CONNECT",)) + + self.assertEqual(analysis["searches"][0]["status"], "found") + self.assertIn("LCD text xref", lcd_text_comment_for_instruction(analysis, 0x0100)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_sci_protocol.py b/tests/test_sci_protocol.py new file mode 100644 index 0000000..fc9c005 --- /dev/null +++ b/tests/test_sci_protocol.py @@ -0,0 +1,148 @@ +import unittest + +from h8536.model import Instruction +from h8536.sci_protocol import ( + analyze_sci_protocol, + sci_protocol_comment_for_instruction, + sci_protocol_json_payload, + sci_protocol_metadata_for_instruction, +) + + +def ins( + address: int, + mnemonic: str, + operands: str = "", + references: list[int] | None = None, + kind: str = "normal", + targets: list[int] | None = None, +) -> Instruction: + return Instruction( + address, + b"", + mnemonic, + operands, + kind=kind, + targets=targets or [], + references=references or [], + ) + + +class SciProtocolTest(unittest.TestCase): + def test_tdre_polling_loop_is_wait_for_transmit_data_register_empty(self): + instructions = { + 0x2000: ins(0x2000, "BTST.B", "#7, @SCI1_SSR", references=[0xFEDC]), + 0x2004: ins(0x2004, "BEQ", "loc_2000", kind="branch", targets=[0x2000]), + } + + analysis = analyze_sci_protocol(instructions) + + self.assertIn( + "wait for SCI1 transmit data register empty (TDRE=1)", + sci_protocol_comment_for_instruction(analysis, 0x2000), + ) + self.assertIn( + "repeat SCI1 transmit-empty wait while TDRE=0", + sci_protocol_comment_for_instruction(analysis, 0x2004), + ) + metadata = sci_protocol_metadata_for_instruction(analysis, 0x2000)[0] + self.assertEqual(metadata["action"], "wait_for_tdre") + self.assertEqual(metadata["branch_address"], 0x2004) + + def test_write_to_tdr_is_rs232_sci_transmit_byte(self): + instructions = { + 0x2100: ins(0x2100, "MOV:G.B", "R0, @SCI1_TDR", references=[0xFEDB]), + } + + analysis = analyze_sci_protocol(instructions) + + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0x2100), + "write RS232/SCI byte to SCI1 TDR for transmission", + ) + self.assertEqual(analysis["channels"]["SCI1"]["events"][0]["register"], "TDR") + + def test_scr_tie_bit_set_and_clear_enable_disable_tx_interrupt(self): + instructions = { + 0x2200: ins(0x2200, "BSET.B", "#7, @SCI1_SCR", references=[0xFEDA]), + 0x2204: ins(0x2204, "BCLR.B", "#7, @SCI1_SCR", references=[0xFEDA]), + } + + analysis = analyze_sci_protocol(instructions) + + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0x2200), + "enable SCI1 TX interrupt (TIE)", + ) + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0x2204), + "disable SCI1 TX interrupt (TIE)", + ) + + def test_receive_path_clears_rdrf_then_reads_received_byte(self): + instructions = { + 0x2300: ins(0x2300, "BCLR.B", "#6, @SCI1_SSR", references=[0xFEDC]), + 0x2304: ins(0x2304, "MOV:G.B", "@SCI1_RDR, R0", references=[0xFEDD]), + } + + analysis = analyze_sci_protocol(instructions) + + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0x2300), + "clear SCI1 receive-data-full flag (RDRF)", + ) + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0x2304), + "read SCI1 received byte from RDR", + ) + + def test_receive_error_handler_clears_overrun_framing_and_parity_errors(self): + instructions = { + 0x2400: ins(0x2400, "BCLR.B", "#5, @SCI1_SSR", references=[0xFEDC]), + 0x2404: ins(0x2404, "BCLR.B", "#4, @SCI1_SSR", references=[0xFEDC]), + 0x2408: ins(0x2408, "BCLR.B", "#3, @SCI1_SSR", references=[0xFEDC]), + } + + analysis = analyze_sci_protocol(instructions) + + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0x2400), + "clear SCI1 overrun error flag (ORER)", + ) + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0x2404), + "clear SCI1 framing error flag (FER)", + ) + self.assertEqual( + sci_protocol_comment_for_instruction(analysis, 0x2408), + "clear SCI1 parity error flag (PER)", + ) + + def test_immediate_scr_write_reports_protocol_control_bits(self): + instructions = { + 0x2500: ins(0x2500, "MOV:G.B", "#H'B0, @SCI2_SCR", references=[0xFEF2]), + } + + analysis = analyze_sci_protocol(instructions) + comment = sci_protocol_comment_for_instruction(analysis, 0x2500) + + self.assertIn("enable SCI2 TX interrupt (TIE)", 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) + + def test_json_payload_keeps_events_without_instruction_index(self): + instructions = { + 0x2600: ins(0x2600, "MOV:G.B", "R0, @SCI2_TDR", references=[0xFEF3]), + } + analysis = analyze_sci_protocol(instructions) + + payload = sci_protocol_json_payload(analysis) + + self.assertIn("manual_references", payload) + self.assertEqual(payload["events"][0]["action"], "write_tdr") + self.assertEqual(payload["channels"]["SCI2"]["events"][0]["register"], "TDR") + + +if __name__ == "__main__": + unittest.main()