Add recompilable sdas8051 source; round-trips to stock v2.2.1 binary
roundtrip.py converts the radare2 disassembly (qunexus_v2.2.1.asm) into a single sdas8051 assembler source (firmware.asm) and verifies it re-assembles byte-identical to the 54,279-byte stock image (base 0x2400). 31,051 of 31,346 items (99.06%) re-assemble from mnemonics; 295 are pinned to .db where r2's display syntax doesn't round-trip through sdas8051 (256 ajmp/acall that sdas8051 mis-encodes, 39 data-in-code). Converges in 3 iterations. Also adds patch_usb1_to_cv.asm (the USB-1->CV patch as a standalone sdas8051 source) and verify_patch_asm.py (proves the assembled patch matches the bytes written to the device over C2). Reproduce: python3 roundtrip.py
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
; ---------------------------------------------------------------------------
|
||||
; USB-1 -> CV routing patch for QuNexus firmware v2.2.1
|
||||
;
|
||||
; Goal: MIDI arriving on USB port 1 (Control Surface, cable 0) should also
|
||||
; reach the CV engine. The stock firmware's CV_Out_Source only offers
|
||||
; Expander / USB-3, so cable-0 events never enter the CV ring.
|
||||
;
|
||||
; Mechanism: retarget the single USB-MIDI dispatch call at 0xDF28 from the
|
||||
; stock router (0xA57B) to a small stub (0x8126). The stub first runs the
|
||||
; original router unchanged, then inspects the 4-byte USB-MIDI event buffer
|
||||
; at 0x0F9B: if the event came in on cable 0 (top nibble == 0), it retags it
|
||||
; as cable 2 (sets bit 0x20) and calls the router again so the event also
|
||||
; lands in the USB-3 / CV ring. Events on any other cable pass through
|
||||
; untouched (one router call, as stock).
|
||||
;
|
||||
; Abort-safety (matches patch_c2.py): the stub page (0x8000) is programmed
|
||||
; BEFORE the retarget page (0xDE00), so a mid-failure never leaves a call to
|
||||
; unprogrammed flash.
|
||||
;
|
||||
; This file assembles with sdas8051 (SDCC): sdas8051 -l patch_usb1_to_cv.asm
|
||||
; The resulting bytes must match exactly what patch_c2.py writes to the
|
||||
; device over C2 (see verify_patch_asm.py).
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
.area CODE (ABS)
|
||||
|
||||
; --- Stub routine (programmed into 0xFF padding at 0x8126, page 0x8000) ---
|
||||
.org 0x8126
|
||||
usb1_cv_stub:
|
||||
lcall 0xa57b ; 12 a5 7b original cable-number router
|
||||
mov dptr, #0x0f9b ; 90 0f 9b USB-MIDI 4-byte event buffer
|
||||
movx a, @dptr ; e0 load event[0] (cable nibble in top 4 bits)
|
||||
anl a, #0xf0 ; 54 f0 isolate cable number
|
||||
jnz stub_done ; 70 0b not cable 0 -> nothing to mirror
|
||||
movx a, @dptr ; e0 reload event[0]
|
||||
orl a, #0x20 ; 44 20 retag cable 0 as cable 2
|
||||
movx @dptr, a ; f0 store back
|
||||
mov r6, #0x0f ; 7e 0f DPTR high = 0x0F (buffer page)
|
||||
mov r7, #0x9b ; 7f 9b DPTR low = 0x9B (buffer addr)
|
||||
lcall 0xa57b ; 12 a5 7b route again -> USB-3 / CV ring
|
||||
stub_done:
|
||||
ret ; 22
|
||||
|
||||
; --- Retarget: the single dispatch call site (page 0xDE00) ---------------
|
||||
; Stock at 0xDF28 is `lcall 0xa57b` (12 a5 7b). Patched to call the stub.
|
||||
.org 0xdf28
|
||||
lcall 0x8126 ; 12 81 26 -> usb1_cv_stub
|
||||
Reference in New Issue
Block a user