Shared kernel — per-frame control flow
Shared kernel — per-frame control flow
The 60-word common header (../disasm/kernel.dsm) is uploaded once at boot and runs every sample frame. It is the backbone every effect shares: it sets up each unit’s data pointers, CALLs the two effect bodies in turn, and closes with the output epilogue. This control flow is PROVEN BY CONSTRUCTION (notes/kn5000-dsp-headerdecode.md): the header loads the same three pointer registers twice, so a body must run and return between the two loads.
flowchart TD
N0["Fs edge → hardware PC restart (PC := 0)<br/>one pass per sample @ 44,100 Hz"]
N1["Header preamble, I-RAM 0..48<br/>input stage, LFOs, mixes; load unit-0 pointers<br/>0x821/0x827/0x825 ← 0x70/0x6C/0x25"]
N0 --> N1
N2["CALL unit-0 body @ I-RAM 84<br/>(END-OF-BLOCK word 49, unit tag 0x0E)"]
N1 --> N2
N3["unit-0 effect body runs<br/>straight-line, HAND-UNROLLED (no loop, no branch)"]
N2 --> N3
N4["RETURN to I-RAM 50"]
N3 --> N4
N5["unit-1 pointer setup, I-RAM 50..58<br/>0x821/0x827/0x825 ← 0x50/0x64/0x25"]
N4 --> N5
N6["CALL unit-1 body @ I-RAM 200<br/>(END-OF-BLOCK word 59, unit tag 0x0F)"]
N5 --> N6
N7["unit-1 effect body runs (the reverb tank)<br/>straight-line, HAND-UNROLLED"]
N6 --> N7
N8["RETURN to I-RAM 60"]
N7 --> N8
N9["Frame epilogue, I-RAM 60..82<br/>effect-return / wet-level words @ 64 & 71 (host-patched)<br/>output stage"]
N8 --> N9
N10["Wait for Fs @ I-RAM 82 (C00.A.47.407)<br/>halt until the next sample clock"]
N9 --> N10
N11["2-level call/return stack; call & return share one encoding<br/>(class4==1, addr8 = unit tag 0x0E/0x0F)"]
N9 -.-> N11
classDef io fill:#e8eef7,stroke:#33475b,stroke-width:1px,color:#111;
classDef proven fill:#d7f0d7,stroke:#2e7d32,stroke-width:2px,color:#111;
classDef measured fill:#dbe9fb,stroke:#1565c0,stroke-width:1.5px,color:#111;
classDef inferred fill:#fdf0d5,stroke:#b8860b,stroke-width:1.5px,color:#111;
classDef open fill:#eeeeee,stroke:#888,stroke-width:1px,color:#333,stroke-dasharray:5 5;
classDef ctrl fill:#f3e8fb,stroke:#6a1b9a,stroke-width:1px,color:#111;
class N0,N1,N2,N4,N5,N6,N8 proven;
class N3,N7,N10,N11 measured;
class N9 inferred;
Key facts (all from notes/kn5000-dsp-headerdecode.md):
- Per-frame hardware PC restart — the
Fs-RST/PC-RSTpins restart the PC every sample; there is no software frame loop. The last word,C00.A.47.407at I-RAM 82, waits for the next Fs (thathi12=0xC00occurs zero times in 2974 body words). (MEASURED) - Call & return share one encoding — the transfer rides on the unit tag
class4==1 && addr8 ∈ {0x0E, 0x0F}, not on the END-OF-BLOCK bit; the default action after an END-OF-BLOCK word is fall-through. (PROVEN) - A 2-level stack — unit 0 is called at word 49 and returns to 50; unit 1 at word 59 returns to 60. Both units are resident at once but run time-multiplexed. (PROVEN)
- Bodies are branchless, hand-unrolled — no word carries the entry addresses 84/200 and two exhaustive branch-field scans are negative; there is no loop to branch back to. (MEASURED)
- The epilogue (I-RAM 60..82) is the output stage — the only two words the host patches per effect, I-RAM 64 and 71, carry the unit tags in their default form and a per-slot-invariant
lo12(0x445/0x446): the effect-return / wet-level words. (INFERRED, strong)
Legend and method: README.md. Narrative: the MAME development blog, KN5000 effects-DSP series (Parts 78-84).