The DSP Effect and Parameter Name Tables

Everything the KN5000 shows you on the effect-editor page — the effect’s name, the eight parameter labels down the left, the unit suffix next to each value — comes from four tables in the Main CPU ROM. The algorithms those names label live on the other side of the inter-CPU link, in the Sub-CPU payload (DSP Effect Data Zone).

The tables’ ROM addresses have been known for a long time (see Sound Parameter Protocol). What was missing until commit 8c9b66d (2026-08-08) was their presence in the reconstruction’s source: they sat inside a C-compiled blob as several hundred anonymous uint16_t members, so nothing in the repository said what they were.

What this page is not. Naming a table is not the same as decoding it. The four tables below are exact and their consumers are traced, but they are the labelling layer only — they carry no DSP semantics. The surrounding 146 KB of widget-descriptor material in the same blob is still largely anonymous, and the repository’s build gate proves byte-identity of the rebuild, nothing about any interpretation on this page.

1. Where they live

The whole zone is inside one binary include. v10/maincpu/ui_widgets/widget_descriptors.s contains a single directive:

NakaData_WidgetDescriptors:
	.incbin "includes/generated/naka_widget_descriptors.bin"

That 150,888-byte file (ROM 0xE30E60-0xE55BC7) is a build product, not a dump slice: the Makefile compiles v10/maincpu/ui_widgets/naka_widget_descriptors.c with clang -target tlcs900, links it with naka_widget_descriptors_link.ld and extracts .text with llvm-objcopy. The C file is one large packed struct auto-generated by scripts/naka_struct_decode.py, hand-annotated where a region has been identified.

The DSP naming zone occupies blob offsets +0x15B8 through +0x2719 — ROM 0xE32418-0xE33579, 4,450 bytes:

Symbol ROM address v10 ROM file offset Blob offset Shape
DspParamUnit_Table 0xE32418 0x032418 +0x15B8 86 × 2 bytes
DspParamName_Table 0xE324C4 0x0324C4 +0x1664 86 × 17 bytes
DspEffectName_PtrTable 0xE32A7A 0x032A7A +0x1C1A 128 × u32
DspEffectName_Strings 0xE32C7A 0x032C7A +0x1E1A 128 × 18 bytes

172 + 1462 + 512 + 2304 = 4450 — the four tables tile the zone exactly, with no padding between them. (The Main CPU program ROM maps at 0xE00000, so the file offsets above are simply the ROM address minus 0xE00000.)

In assembly the four names are .equ aliases relative to NakaData_WidgetDescriptors; in the C source they are struct members of the same name. The 128 effect-name strings keep their pre-existing assembler labels NakaInst_<EFFECT> (e.g. NakaInst_NO_OPERATION, NakaInst_CHORUS); the EffectName_EffNNN_<NAME> spellings are C struct members inside naka_widget_descriptors.c and are not linker symbols.

2. Why a grep never found them

The effect-name strings were already in the C source as ALIGNED_STRING(...) members — but they were called str_0 … str_127, with no indication that str_0 is effect 127 and str_127 is effect 0. Their index array was ptrs_0[128].

The parameter name and unit tables were worse: 817 contiguous anonymous uint16_t members, field_15b8 through field_1c18, initialised with hex word constants. Because the name records are 17 bytes long, every other name starts at an odd offset and each 16-bit member holds a byte-swapped fragment of two different characters. “VOLUME” in slot 1 was stored as:

    .field_1674 = 0x5620,      /* ' ' 'V' */
    .field_1676 = 0x4C4F,      /* 'O' 'L' */
    .field_1678 = 0x4D55,      /* 'U' 'M' */

No grep of the checked-in text sources could turn up a parameter name in this table — naka_widget_descriptors.c contains no readable copy of one. That is why the disassembly plan carried “carve the maincpu effect/name tables” as an open item long after outside tooling had already read the same bytes straight out of the ROM dump.

The 817 members split 86 + 731: 86 words for the unit table (86 × 2 = 172 B) and 731 words for the name table (86 × 17 = 1,462 B). Both counts, and the fact that the removed members form one unbroken 2-byte-stride run from +0x15B8 to +0x1C18, are mechanically checkable in the commit diff.

3. Parameter names and units

One index — the parameter-id byte — selects a row of both tables, so slot i of the name table and slot i of the unit table always describe the same UI control.

  • Name record: 17 bytes = 16 display characters + a : separator. It is not NUL-terminated; the firmware copies exactly 17 bytes with Strncpy.
  • Unit record: 2 characters, no terminator. Only four values occur in the whole table: two spaces (55 slots), Hz (13), ms (11) and s followed by a space (7).
  • Slots 0 and 85 are blank spares: 17 spaces, no colon. Slots 1 and 2 are both VOLUME, so the 86 slots hold 84 distinct records.

Four records — slots 15, 16, 17 and 73, marked † below — begin with seven leading spaces: SLOW, WIND UP, WIND DOWN and FAST. They read as indented continuation rows under the label above them on screen; which label each one hangs from has not been confirmed against a screenshot.

# Name Unit # Name Unit
0 (blank spare) — 43 RELEASE SENS. s
1 VOLUME — 44 ATTACK RATE s
2 VOLUME — 45 RELEASE RATE s
3 REV SEND — 46 GATE TIME ms
4 DRIVE — 47 MASK TIME ms
5 ADJUST — 48 HARS TIME —
6 EMPHASIS GAIN — 49 LFO WAVEFORM —
7 DEPTH — 50 OSC WAVEFORM —
8 LFO SPEED Hz 51 BAND EMPHASIS FC Hz
9 SLOW LFO SPEED Hz 52 BAND EMPHASIS Q —
10 FAST LFO BALANCE — 53 BAND EMPHASIS G —
11 RESONANCE — 54 LOW MIX —
12 MANUAL — 55 HIGH MIX —
13 SLOW/FAST — 56 PHASE —
14 TREBLE FAST Hz 57 FEEDBACK —
15 SLOW † Hz 58 SWEEP RANGE —
16 WIND UP † s 59 WAH CENTER FC —
17 WIND DOWN † s 60 HARS TIME L ms
18 BASS FAST Hz 61 HARS TIME R ms
19 BASS SLOW Hz 62 BALANCE L —
20 VOLUME ADJUST — 63 BALANCE R —
21 OSC SPEED Hz 64 FAST LFO SPEED L Hz
22 DELAY L ms 65 FAST LFO SPEED R Hz
23 DELAY R ms 66 MODULATION DEPTH —
24 FEEDBACK L — 67 DELAY1 DRY/WET —
25 FEEDBACK R — 68 DELAY2 DRY/WET —
26 DELAY DRY/WET — 69 VIBRATO DRY/WET —
27 CHORUS DRY/WET — 70 WAH DRY/WET —
28 FLANGER DRY/WET — 71 FAST LFO SPEED Hz
29 PHASER DRY/WET — 72 TREBLE DEPTH —
30 LOW EMPHASIS FC — 73 FAST † Hz
31 LOW EMPHASIS G — 74 BASS DEPTH —
32 HIGH EMPHASIS FC Hz 75 DELAY 1 ms
33 HIGH EMPHASIS G — 76 DELAY 2 ms
34 REVERB TIME s 77 DELAY 3 ms
35 PRE DELAY ms 78 DELAY 4 ms
36 HIGH DAMP GAIN — 79 PAN 1 —
37 ER.LEVEL — 80 PAN 2 —
38 PITCH L — 81 PAN 3 —
39 PITCH R — 82 PAN 4 —
40 THRESHOLD — 83 INTENSITY —
41 RATIO — 84 EXCITE —
42 ATTACK SENS. s 85 (blank spare) —

Trailing spaces are stripped in this table for readability; every record is exactly 16 characters wide in the ROM.

4. The effect-name table runs backwards

DspEffectName_PtrTable is a plain 128-entry u32 array indexed by effect number 0-127. Its entries are not in address order:

DspEffectName_PtrTable[n] == 0xE33568 - 18 * n

That formula holds for all 128 entries — effect 0’s name sits at the highest address (0xE33568) and effect 127’s at the lowest (0xE32C7A). The string block is therefore laid out in descending effect order, which is why the pre-existing NakaInst_* label run in widget_descriptors.s starts with the reserved slots and ends with NakaInst_NO_OPERATION. The source states the inverse mapping explicitly: for any label in that run, the effect number is (0x02708 - blob_offset) / 18.

Each record is 18 bytes: 16 display characters, 0x00, then 0xFF filler. Effect numbers stop at 99 — all 28 slots from 100 to 127 hold the placeholder ---------- centred in its 16-character field, as do 29 of the slots below 100, leaving 71 named effects.

5. Who reads them

All four consumers are in sequencer/sequencer_ui.s. Addresses are from the linked v10 ELF:

Routine Address Reads Mechanism
DspItem0_DisplayEffectName 0xF355F3 DspEffectName_PtrTable effect no. from RAM word 0x2976, sll xwa,2, index, Strcpy
DspItem0_DisplayParamNames 0xF3561F DspParamName_Table param id × 0x11, Strncpy 17 bytes, 8 rows per page
DspItem0_DisplayParamValues 0xF3566C DspParamUnit_Table same param id × 2, Strncpy 2 bytes
EntertainerGridCheck 0xF30326 DspEffectName_PtrTable takes the table address into a stack slot

Both parameter routines get their id the same way: the per-effect ordered id list is a byte array whose base address is taken with lda_d16 xbc, (0x29ac), and the row index of the first line on the current page is the byte at 0x021098. The loop paints eight rows (cpw (xsp + 18), 0x8), so a screen is a sliding window into that id list.

6. Cross-reference to the Sub-CPU algorithms

Every effect-name member in naka_widget_descriptors.c now carries a comment naming the DSP_EffNN_* / DSP2_EffNN_* blocks it labels in v142/subcpu/subcpu_data_tables.s. Counting those comments over the 128 slots:

Class Count
Own at least one Sub-CPU block 60
Marked STUB — nothing of their own 40
Effect numbers 100-127, no Sub-CPU slot at all 28

That reconciles with the figure already on the DSP Effect Data Zone page — 42 effect numbers point all three of algorithm / coefficient / descriptor at the shared NO OPERATION trio. The 42 are the 40 stubs plus two special cases: effect 0 itself, which owns the trio, and effect 37 SLOW ATTACKER, which owns a parameter-value table (0x0173F2) but runs the pass-through program. Nine of the 60 owners are DSP2_* (IC310 / MN19413) programs.

The zone bytes are identical in the v7, v9 and v10 program dumps — none of the 348 bytes that differ between the v7 blob and the v9/v10 blob falls inside +0x15B8-+0x2719; the differences are relocated code pointers elsewhere in the descriptor material.

7. Caveats and open items

  • The blob is still one .incbin. Only the naming zone has been identified; most of the 150,888-byte struct is still field_XXXX / ptr_XXXX members with no meaning attached. Naming 4,450 bytes does not make the widget-descriptor format understood.
  • The rename landed in v9 and v10 only. v7/maincpu/sequencer/sequencer_ui.s still loads the table through the positional alias NakaData_WidgetDescriptors_0x1C1A. The three aliases remain defined in shared/positional_labels.s in all three trees.
  • v7 does not compile this blob from its C source. The v7 program build runs a second pass (scripts/build/extract_v7_bins.py) that re-extracts generated .bin files from the original v7 ROM whenever the compiled v9 version matches ≥50 % at the same address, and naka_widget_descriptors.bin is one of them — the committed v7/.../naka_widget_descriptors_link.ld is a copy of v9’s and carries v9 symbol addresses. The disassembly plan tracks this as its largest open item (v7-cdata, ~703 KB across 23 shared-named bins) and flags the 50 % heuristic as a silent-corruption risk. The v7 tree’s 100 % byte-match for this region is therefore not evidence that the C source reproduces v7.
  • The UI parameter order is not in these tables. Which ids an effect shows, and in what order, comes from the Sub-CPU side; the ordered lists quoted in the per-effect banners of subcpu_data_tables.s were captured live in emulation, not read from a table.

Provenance

  • Carve + labels: commit 8c9b66d in kn5000-roms-disasm — v10/maincpu/ui_widgets/widget_descriptors.s, v10/maincpu/ui_widgets/naka_widget_descriptors.c (and the v7/v9 copies), v9,v10/maincpu/sequencer/sequencer_ui.s.
  • Table contents, shapes, blank slots, unit distribution and the 0xE33568 - 18n pointer formula: read directly out of original_ROMs/kn5000_v10_program.rom.
  • Routine addresses: llvm-nm on rebuilt_ROMs/kn5000_v10_program.llvm.elf.
  • Stub/owner counts: the 100-entry pointer arrays at Sub-CPU 0x01ED7C / 0x01EF0C / 0x01F09C / 0x01F22C in original_ROMs/kn5000_subprogram_v142.rom.
  • Open v7 item: analysis/binclude-audit-2026-08-07/PLAN.md, package v7-cdata.