Annotate the USB-MIDI router and the USB-1->CV patch in the disassembly
Add a comment-injection mechanism to roundtrip.py (COMMENTS / PATCH_COMMENTS
address-keyed dicts) so annotations survive regeneration -- they live in the
script, not the generated file.
Annotated in firmware.asm:
* The router at 0xA57B: register-bank switch, event-buffer save, the
CV-source-locked early-out, the cable-number switch (cable 0 -> 0x70,
cable 1 -> 0xc3, cable 2 -> 0x82 = CV ring), the descriptor write via
0x551e, and the single common routing pass at 0xA5C0.
* The dispatcher at 0xDF05 / dispatch call at 0xDF28.
* The usb1_cv_stub at 0x8126 (each instruction) and the retargeted call.
The router's structure clarifies why re-injection is used rather than a
router patch: 0x551e only writes a 3-byte destination descriptor, and the
actual routing pass (0xA5C0+) runs once per invocation, wrapped by a
PSW push/pop -- so two destinations require two full router calls.
This commit is contained in:
@@ -14034,18 +14034,30 @@ movx @r0, a
|
||||
jc L_817D
|
||||
rr a
|
||||
xch a, r5
|
||||
; usb1_cv_stub: mirror cable-0 (USB-1) events into the CV ring (dest 0x82); first run the original router unchanged
|
||||
L_8126:
|
||||
lcall 0xa57b
|
||||
; USB-MIDI 4-byte event buffer at 0x0F9B
|
||||
mov dptr, #0x0f9b
|
||||
; load event[0] (cable nibble in top 4 bits)
|
||||
movx a, @dptr
|
||||
; isolate cable number (top nibble of event[0])
|
||||
anl a, #0xf0
|
||||
; not cable 0 -> done (no mirror needed)
|
||||
jnz L_813C
|
||||
; reload event[0]
|
||||
movx a, @dptr
|
||||
; retag cable 0 as cable 2 (set bit 0x20)
|
||||
orl a, #0x20
|
||||
; store back
|
||||
movx @dptr, a
|
||||
; DPTR high = 0x0F (buffer page)
|
||||
mov r6, #0x0f
|
||||
; DPTR low = 0x9B (buffer addr)
|
||||
mov r7, #0x9b
|
||||
; route again -> USB-3 / CV ring (dest 0x82)
|
||||
lcall 0xa57b
|
||||
; done
|
||||
L_813C:
|
||||
ret
|
||||
mov r7, a
|
||||
@@ -19577,17 +19589,22 @@ mov dptr, #0x0e1c
|
||||
mov a, #0x04
|
||||
movx @dptr, a
|
||||
ret
|
||||
; USB-MIDI router (fcn.0000a57b): route the 4-byte event at @r6:r7 to a per-cable destination ring (called from 0xdf28)
|
||||
push 0xd0
|
||||
; switch to register bank 1 (PSW.RS0 = 1)
|
||||
mov 0xd0, #0x08
|
||||
; save event-buffer pointer r6:r7 -> 0x0d3b/0x0d3c
|
||||
mov dptr, #0x0d3b
|
||||
mov a, r6
|
||||
movx @dptr, a
|
||||
inc dptr
|
||||
mov a, r7
|
||||
movx @dptr, a
|
||||
; if CV-source-locked flag (bit 0x22.2) set, early-out (r7 = 1)
|
||||
jnb 0x12, L_A590
|
||||
mov r7, #0x01
|
||||
ljmp 0xa660
|
||||
; read event[0]; extract cable number (high nibble) -> r7
|
||||
L_A590:
|
||||
mov dptr, #0x0d3b
|
||||
lcall 0xcb9c
|
||||
@@ -19595,10 +19612,12 @@ swap a
|
||||
anl a, #0x0f
|
||||
mov r7, a
|
||||
jnz L_A5A4
|
||||
; cable 0 (USB-1 / Control Surface) -> dest 0x70
|
||||
mov r3, #0x01
|
||||
mov r2, #0x03
|
||||
mov r1, #0x70
|
||||
sjmp L_A5BA
|
||||
; cable 1 -> dest 0xc3
|
||||
L_A5A4:
|
||||
mov a, r7
|
||||
cjne a, #0x01, L_A5B0
|
||||
@@ -19606,15 +19625,18 @@ mov r3, #0x01
|
||||
mov r2, #0x01
|
||||
mov r1, #0xc3
|
||||
sjmp L_A5BA
|
||||
; cable 2 (USB-3) -> dest 0x82 (CV ring)
|
||||
L_A5B0:
|
||||
mov a, r7
|
||||
cjne a, #0x02, L_A5C0
|
||||
mov r3, #0x01
|
||||
mov r2, #0x03
|
||||
mov r1, #0x82
|
||||
; write destination descriptor (r3,r2,r1) -> 0x0d3d/e/f (fcn.0000551e)
|
||||
L_A5BA:
|
||||
mov dptr, #0x0d3d
|
||||
lcall 0x551e
|
||||
; common routing pass: copy MIDI bytes from the event buffer to the selected destination ring (runs ONCE per router invocation)
|
||||
L_A5C0:
|
||||
lcall 0xcba6
|
||||
lcall 0x52ca
|
||||
@@ -19706,6 +19728,7 @@ xch a, r7
|
||||
mov 0xf0, r7
|
||||
lcall 0x532d
|
||||
mov r7, #0x01
|
||||
; restore PSW; return (r7 = status)
|
||||
pop 0xd0
|
||||
ret
|
||||
push 0xd0
|
||||
@@ -28348,6 +28371,7 @@ movx @dptr, a
|
||||
mov r6, 0x04
|
||||
mov r7, 0x05
|
||||
ret
|
||||
; USB-MIDI event dispatcher (fcn.0000df05)
|
||||
push 0xd0
|
||||
mov 0xd0, #0x08
|
||||
mov dptr, #0x0f9b
|
||||
@@ -28369,6 +28393,7 @@ sjmp L_DF34
|
||||
L_DF24:
|
||||
mov r6, #0x0f
|
||||
mov r7, #0x9b
|
||||
; dispatch call -> usb1_cv_stub (was: router 0xa57b)
|
||||
lcall L_8126
|
||||
mov a, r7
|
||||
jz L_DF32
|
||||
|
||||
@@ -51,6 +51,44 @@ ABS_OPS = {"ljmp", "lcall", "ajmp", "acall"}
|
||||
LINE_RE = re.compile(
|
||||
r'^\s*[\\|/]?\s*0x([0-9a-fA-F]{8})\s+([0-9a-fA-F]+)\s+(\S.*)$')
|
||||
|
||||
# Annotated addresses. Emitted as `;` comment lines before the instruction,
|
||||
# so the disassembly reads as a narrative. These survive regeneration (they
|
||||
# live in this script, not in the generated file). Patch-mode comments
|
||||
# (PATCH_COMMENTS) override COMMENTS at the same address.
|
||||
COMMENTS = {
|
||||
0xa57b: "USB-MIDI router (fcn.0000a57b): route the 4-byte event at @r6:r7 to a per-cable destination ring (called from 0xdf28)",
|
||||
0xa57d: "switch to register bank 1 (PSW.RS0 = 1)",
|
||||
0xa580: "save event-buffer pointer r6:r7 -> 0x0d3b/0x0d3c",
|
||||
0xa588: "if CV-source-locked flag (bit 0x22.2) set, early-out (r7 = 1)",
|
||||
0xa590: "read event[0]; extract cable number (high nibble) -> r7",
|
||||
0xa59c: "cable 0 (USB-1 / Control Surface) -> dest 0x70",
|
||||
0xa5a4: "cable 1 -> dest 0xc3",
|
||||
0xa5b0: "cable 2 (USB-3) -> dest 0x82 (CV ring)",
|
||||
0xa5ba: "write destination descriptor (r3,r2,r1) -> 0x0d3d/e/f (fcn.0000551e)",
|
||||
0xa5c0: "common routing pass: copy MIDI bytes from the event buffer to the selected destination ring (runs ONCE per router invocation)",
|
||||
0xa660: "restore PSW; return (r7 = status)",
|
||||
0xdf05: "USB-MIDI event dispatcher (fcn.0000df05)",
|
||||
0xdf28: "dispatch call -> router 0xa57b",
|
||||
}
|
||||
|
||||
# Patch-mode-only annotations (the stub + retargeted call site).
|
||||
# Each comment describes the instruction AT that address.
|
||||
PATCH_COMMENTS = {
|
||||
0x8126: "usb1_cv_stub: mirror cable-0 (USB-1) events into the CV ring (dest 0x82); first run the original router unchanged",
|
||||
0x8129: "USB-MIDI 4-byte event buffer at 0x0F9B",
|
||||
0x812c: "load event[0] (cable nibble in top 4 bits)",
|
||||
0x812d: "isolate cable number (top nibble of event[0])",
|
||||
0x812f: "not cable 0 -> done (no mirror needed)",
|
||||
0x8131: "reload event[0]",
|
||||
0x8132: "retag cable 0 as cable 2 (set bit 0x20)",
|
||||
0x8134: "store back",
|
||||
0x8135: "DPTR high = 0x0F (buffer page)",
|
||||
0x8137: "DPTR low = 0x9B (buffer addr)",
|
||||
0x8139: "route again -> USB-3 / CV ring (dest 0x82)",
|
||||
0x813c: "done",
|
||||
0xdf28: "dispatch call -> usb1_cv_stub (was: router 0xa57b)",
|
||||
}
|
||||
|
||||
|
||||
def signed(b):
|
||||
return b - 0x100 if b >= 0x80 else b
|
||||
@@ -181,8 +219,13 @@ def emit_source(items, labels, pinned, patch=False):
|
||||
lines.append(".area CODE (ABS)")
|
||||
lines.append(".org 0x%04x" % BASE)
|
||||
item_line = {}
|
||||
cmt = dict(COMMENTS)
|
||||
if patch:
|
||||
cmt.update(PATCH_COMMENTS)
|
||||
for idx, it in enumerate(items):
|
||||
a = it["addr"]
|
||||
if a in cmt:
|
||||
lines.append("; " + cmt[a])
|
||||
if a in labels:
|
||||
lines.append("L_%04X:" % a)
|
||||
if it["is_gap"] or it["force_db"] or a in pinned:
|
||||
|
||||
Reference in New Issue
Block a user