Audio Subsystem

The KN5000 audio subsystem handles all sound generation, processing, and output. The Sub CPU runs dedicated audio firmware that processes MIDI-like commands from the Main CPU and drives the DSP and DAC hardware.

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                      MAIN CPU (TMP94C241F)                          │
│                                                                     │
│  Audio_Lock_Acquire ──> Audio_DMA_Transfer ──> Audio_Lock_Release   │
│                                 │                                   │
│              Latch @ 0x120000 (Inter-CPU Communication)             │
└─────────────────────────────────┬───────────────────────────────────┘
                                  │
                                  v
┌───────────────────────────────────────────────────────────────────────┐
│                       SUB CPU (TMP94C241F)                            │
│                                                                       │
│  Boot ROM: 128KB @ 0xFE0000      Payload: 192KB (from Main CPU)       │
│                                                                       │
│  ┌────────────────────────────────────────────────────────────────┐   │
│  │                  AUDIO PROCESSING LOOP                         │   │
│  │                                                                │   │
│  │  ToneGen_Process_Notes ──> MIDI_Dispatch ──> Audio_Process_DSP │   │
│  │         │                       │                    │         │   │
│  │         v                       v                    v         │   │
│  │   [Keyboard Input]        [Ring Buffer]         [DSP State]    │   │
│  │      @ 0x110000             @ 0x2B0D             @ 0x3B60      │   │
│  └────────────────────────────────────────────────────────────────┘   │
└──────────┬─────────────────────┬─────────────────────┬────────────────┘
           │                     │                     │
      [0x100000]             [Serial1]            [0x130000]
       Register                UART                   DSP
        Config                Control               Config
           │                     │                     │
           v                     v                     v
  ┌─────────────────┐   ┌─────────────────┐   ┌──────────────────┐
  │  TONE GENERATOR │   │   DAC (IC313)   │   │   DUAL DSP       │
  │  IC303          │   │   PCM69AU       │   │   IC310 + IC311  │
  │                 │   │                 │   │                  │
  │  64 voices      │   │  18-bit stereo  │   │  4 channels      │
  │  32 regs each   │   │  (via serial)   │   │  0x20 bytes/ch   │
  └────────┬────────┘   └────────┬────────┘   └──────────────────┘
           │                     │
       [0x110000]          [BCK/SDOR/SDOF]
     Keyboard Input        Serial Audio Bus

Hardware Addresses

Component Address Description
Tone Gen Registers 0x100000/0x100002 Register-indirect config (64 voices, addr/data)
Tone Gen Keyboard 0x110000/0x110002 Voice events (status + note/velocity data)
Inter-CPU Latch 0x120000 Bidirectional data register
DSP Registers 0x130000/0x130002 Register-indirect config (4 channels, addr/data)
HDAE5000 PPI 0x160000 Parallel port interface (expansion)

See Tone Generator for the complete register map and chip inventory.

DSP Port I/O Control (Sub CPU Internal Ports)

The dual DSP chips are controlled via the Sub CPU’s internal I/O ports. DSP1 (IC311, DS3613GF-3BA) uses a parallel bus protocol with Port PZ/P7 for command/data handshake. DSP2 (IC310, MN19413) uses GPIO bit-bang serial on Port F. Both share chip-select lines:

Port Bit Signal Function
0x1C (P7) 6 DSPCD Command/Data select (0=command, 1=data)
0x1C (P7) 5 DSP1_CS DSP1 chip select (active low)
0x1C (P7) 4 RD Read strobe (active low)
0x1C (P7) 3 WR Write strobe (active low)
0x38 (PE) 6 DSP2_CS DSP2 chip select (active low)
0x38 (PE) 0 MUTE Audio mute control
0x44 (PH) 2 DSP2_RST DSP2 reset (active low)
0x44 (PH) 1 DSP1_RST DSP1 reset (active low)
0x44 (PH) 0 DSP_RDY DSP ready/status (read)
0x68 (PZ) 7:0 DATA 8-bit data port (command/data bytes)

Write Protocol (command or data byte):

1. Deassert RD and WR (both high)
2. Select chip: assert DSP1_CS or DSP2_CS (drive low)
3. Poll DSP_RDY until ready (timeout: 8000 iterations)
4. Set DSPCD: 0 for command byte, 1 for data byte
5. Assert WR (drive low)
6. Write byte to PZ (port 0x68)
7. Deassert WR (drive high)
8. Deselect chip: deassert CS
9. Set DSPCD back to data mode (1)

Key Low-Level Functions:

Function Address Description
DSP1_Assert_Reset 0x038396 Reset DSP1 (clear PH.1)
DSP1_Deassert_Reset 0x03839A Release DSP1 reset (set PH.1)
DSP2_Assert_Reset 0x03839E Reset DSP2 (clear PH.2)
DSP2_Deassert_Reset 0x0383A2 Release DSP2 reset (set PH.2)
DSP_Set_Command_Mode 0x0383A7 DSPCD=0 (command register)
DSP_Set_Data_Mode 0x0383AB DSPCD=1 (data register)
DSP_Select_Chip 0x0383BF Assert CS for chip 0 or 1
DSP_Deselect_Chip 0x0383DB Deassert CS
DSP_Read_Status 0x0383F7 Read ready bit from PH.0
DSP_Send_Command 0x036331 Full command byte write (with polling)
DSP_Send_Data 0x0367EE Full data byte write (with polling)
DSP2_Send_Command 0x036599 DSP2-specific command write
DSP2_Send_Data 0x036855 DSP2-specific data write
DSP_DispatchCommand 0x03C0D4 Route command to DSP1 or DSP2
DSP_DispatchData 0x03C0F3 Route data to DSP1 or DSP2
DSP_WriteParamWord 0x03C112 Write 16-bit parameter (high byte, low byte)

DSP Channel Register Map (Memory-Mapped at 0x130000)

The memory-mapped interface at 0x130000 provides a second access path to DSP registers, used for channel initialization:

Channel register address = channel_number × 0x20 + 0x10

Channel 0: registers 0x10-0x17 (8 bytes)
Channel 1: registers 0x30-0x37
Channel 2: registers 0x50-0x57
Channel 3: registers 0x70-0x77

Write sequence:
  (0x130000) ← register address byte
  (0x130002) ← register data byte

Initialization writes test pattern 0x5A5A5A5A to all 4 channels, then sets initial config value 0x101001F with 0x20 channel spacing.

Sub CPU Audio Processing

Main Loop

The Sub CPU runs a continuous audio processing loop in the payload firmware:

Audio_System_Init:
    CALL InterCPU_Latch_Setup     ; Configure DMA channels
    CALL DSP_System_Init          ; Clear DSP state buffers
    CALL DSP2_Init                ; Initialize second DSP
    CALL DSP_Init_Channels        ; Configure 4 DSP channels
    CALL ToneGen_Init             ; Set tone generator mode

Main_Loop:
    CALL ToneGen_Process_Notes    ; Read keyboard input
    CALL MIDI_Dispatch            ; Process MIDI commands
    CALL Audio_Process_DSP        ; Update DSP state
    CALL Audio_Process_Final      ; Final audio update
    JR Main_Loop

Command Dispatch Table

Commands from the Main CPU are dispatched based on the upper 3 bits:

Cmd Range Handler Purpose
0x00-0x1F Audio_CmdHandler_00_1F DSP/audio control - writes to ring buffer
0x20-0x3F Audio_CmdHandler_20_3F Extended audio control
0x40-0x5F Audio_CmdHandler_40_5F Audio parameters
0x60-0x7F Audio_CmdHandler_60_7F Voice/DSP configuration
0x80-0x9F (Serial port setup) 38400 baud configuration
0xA0-0xBF Audio_CmdHandler_A0_BF System audio commands
0xC0-0xFF Audio_CmdHandler_C0_FF Extended system commands

Ring Buffer

Audio commands use a 4KB circular ring buffer:

Variable Address Description
Write Pointer 0x2B0D 12-bit circular index
Read Pointer 0x2B0F Current read position
Byte Count 0x2B11 Bytes available
Base Address 0x2B13 Buffer start

Key Routines:

  • RingBuf_ReadByte - Read single byte (returns 0xFFFF if empty)
  • RingBuf_SkipToEnd - Skip remaining bytes in current message

MIDI Message Processing

The MIDI_Dispatch routine parses MIDI-like status bytes and routes to handlers:

Status Handler Voice Handler Description
0x80/0x90 MIDI_Status_NoteOn Voice_NoteOn Note On/Off (velocity 0 = off)
0xB0 MIDI_Status_CtrlChange Voice_CtrlChange Control Change
0xC0 MIDI_Status_ProgChange Voice_ProgChange Program Change
0xD0 MIDI_Status_ChanPressure Voice_ChanPressure Channel Aftertouch
0xE0 MIDI_Status_PitchBend Voice_PitchBend Pitch Bend
0xF0 MIDI_Status_System Voice_SystemMsg System messages

Control Change Sub-handlers

The Voice_CtrlChange handler supports these controllers:

CC# Handler Parameter
0x01 Voice_CC_ModWheel Modulation Wheel
0x07 Voice_CC_Volume Main Volume
0x0A Voice_CC_Pan Pan/Balance
0x0B Voice_CC_Expression Expression
0x40 Voice_CC_Sustain Sustain Pedal
0x5B Voice_CC_Sostenuto Sostenuto Pedal
0x5D Voice_CC_Soft Soft Pedal
0x5E Voice_CC_Portamento Portamento
0x91 Voice_CC_91 Reverb Depth
0x95 Voice_CC_95 Chorus Depth
0x97-0x9D Voice_CC_97-Voice_CC_9D Proprietary effects

DSP Configuration

Dual DSP Architecture

The Sub CPU controls two DSP chips:

  • DSP1: Primary sound synthesis (initialized by DSP_System_Init)
  • DSP2: Additional processing (initialized by DSP2_Init)

DSP State Buffers

Buffer Address Size Purpose
DSP State 1 0x041342 38 bytes Primary DSP state
DSP State 2 0x041368 7462 bytes Extended DSP state
DSP Config 0x045310-18 12 bytes Configuration parameters
DSP Ring Buffer 0x3B60-64 6 bytes Command ring buffer for DSP
EFF Mute Flags 0x493A 10 bytes Per-DSP/EFF mute status (5 words)
EFF State 0x4940 variable Per-EFF dirty/change flags
EFF Params 0x4944 variable Per-EFF parameter dirty flags
Argo Change Flag 0x493E 2 bytes Algorithm/routing change pending
EFF Type Table 0x1ED6D 5 bytes Current effect type per EFF slot

DSP Channel Configuration

Each of the 4 DSP channels has 0x20 bytes of register space at 0x130000:

Channel 0: 0x130000 - 0x13001F
Channel 1: 0x130020 - 0x13003F
Channel 2: 0x130040 - 0x13005F
Channel 3: 0x130060 - 0x13007F

Key Routines:

  • DSP_Init_Channels - Initialize all 4 channels with test pattern
  • DSP_Write_Channel - Write 8 bytes of config to a channel (loop)
  • DSP_WriteAllChannelRegs - Write register data to all 4 channels
  • DSP_WriteChannelRegs_Inner - Write 8 sequential registers to one channel
  • DSP_Send_Command - Send command byte to DSP
  • DSP_Send_Data - Send data byte to DSP

DSP Voice Coefficient Routing

The Sub CPU firmware includes a coefficient routing subsystem that maps voice parameters to DSP coefficient buffers. This system sits between the voice parameter tables and the DSP hardware, computing which coefficient set to apply based on voice allocation and routing type.

Memory Layout:

Address Size Purpose
0x041368 7462 bytes Voice allocation table (26 channels × 287 bytes/channel)
0x045210 variable DSP coefficient output buffer (written by routing functions)
0x045310 4 bytes Base pointer for routing table computation
0x045314 4 bytes Pointer to routing configuration structure

The routing configuration structure (pointed to by 0x045314) contains pointers to coefficient source tables at various offsets:

Offset Purpose
+0x44 Type-A coefficient table (group 0, default)
+0x48 Type-A coefficient table (group 2, 128-191)
+0x4C Type-A coefficient table (group 1, 64-127)
+0x50 Type-A output pointer table
+0x54 Algorithm coefficient table (default)
+0x58 Type-B coefficient table (group 0, default)
+0x5C Type-B coefficient table (group 2)
+0x60 Type-B coefficient table (group 1)
+0x64 Type-B output pointer table
+0x70 Algorithm table (type 1)
+0x7C Algorithm table (type 2)
+0x80-0x98 Extended algorithm tables (types 3-4)

Routing Algorithm:

The routing functions share a common pattern:

  1. Extract parameters: Mask voice number to 7 bits, extract channel (low 4 bits of BC) and type (bits 6-7 of BC)
  2. Type dispatch: 4-way branch based on type bits (0/64/128/192) to select coefficient source table
  3. Compute index: index = (channel << 7 + voice) × 2, used as offset into the selected table
  4. Load source pointer: Read 32-bit pointer from table_base + index + (0x45310)
  5. Copy coefficients: Copy 13 bytes from source to DSP coefficient buffer at 0x45210

Voice-specific routing (DSP_VoiceCoeffRoute) adds a nested lookup:

  1. Compute voice allocation index: voice × 287 + channel × 37 + 110
  2. Read routing type from allocation entry at 0x41368 + index
  3. Use routing type bits to select coefficient source
  4. Copy 13 coefficient bytes plus 3 extra configuration bytes

Routing Functions (Sub CPU):

Function Purpose
DSP_RouteCoeffs_TypeA Route coefficients via type-A tables (offsets 0x44-0x50)
DSP_RouteCoeffs_TypeB Route coefficients via type-B tables (offsets 0x58-0x64)
DSP_CopyCoeffs_TypeA Direct coefficient copy (offset 0x50, no type dispatch)
DSP_CopyCoeffs_TypeB Direct coefficient copy (offset 0x64, no type dispatch)
DSP_VoiceCoeffRoute Voice-specific routing with allocation table lookup
DSP_VoiceCoeffRoute2 Extended voice routing with filter/vibrato coefficients
DSP_AlgoCoeffLookup Algorithm-based coefficient selection (5-way dispatch, algo 0-4)

DSP Register Write Protocol

The DSP_WriteChannelRegs_Inner function reveals the register-level protocol for writing to DSP channels via 0x130000:

Register address = channel_number × 32 + 0x10

For each of 8 registers (sequential):
  1. Write register address byte to (0x130000)   ; select register
  2. Write data byte to (0x130002)               ; write value
  3. Increment register address

Data sources for 8 registers:
  Reg 0-1: From BC (caller's direct parameters)
  Reg 2-3: From prevbank QBC (alternate register bank)
  Reg 4-5: From DE (caller's direct parameters)
  Reg 6-7: From prevbank QDE (alternate register bank)

The prevbank register usage allows passing 8 bytes of data using only 4 register pairs, by using the TLCS-900/H2’s alternate register bank.

Utility Functions (Sub CPU):

Function Purpose
DSP_BlockCopyWords Block copy words via ldirw instruction
DSP_FillMemWords Fill memory with repeated word value
DSP_ChecksumRange Compute one’s complement checksum of 32-bit word range

DSP State Dispatcher Architecture

The Sub CPU firmware contains a master DSP state dispatcher at DSP_State_Dispatcher that orchestrates all DSP configuration changes. It is called via this chain:

Audio_System_Init (0x01FACB)        -- on boot
  -> DSP_System_Init (0x034C45)
    -> DSP_Reset (0x0360A3)
      -> DSP_State_LoadAndApplyAll               -- full DSP reconfigure
        -> DSP_State_ApplyAll              -- DSP state apply orchestrator
          -> DSP_State_Dispatcher    -- master DSP state dispatcher

Audio_Main_Loop (0x01FAEB)          -- at runtime
  -> Audio_Process_DSP (0x035A7D)   -- reads ring buffer at 0x3B60
    -> command 0x2D dispatch
      -> DSP_CmdHandler_2D                -- sub-command router
        -> ... -> DSP_State_ApplyAll -> DSP_State_Dispatcher (same chain)

The master dispatcher (DSP_State_Dispatcher) takes a pointer to a state structure in XWA:

State structure (at RAM, passed via XWA → XIZ):
  +0: (base)
  +2: algorithm change flag (1 = needs algorithm change)
  +4: mode flag (1 = reset/disconnect mode, other = normal)
  +6: algorithm number

The dispatcher follows a conditional 11-step pipeline:

Step Routine Condition Description
1a DSP_ResetLoop mode == 1 Reset both DSP chips (assert/deassert reset lines)
1b EFF_MuteLoop mode != 1 Mute all 5 EFF channels via DSP_WriteEFFConfig
2 DSP_MuteLoop always Mute DSP hardware chips 0-1 via DSP_WriteGlobalConfig
3 DSP_AlgorithmChangeCheck always If global algo-change flag set, call DSP_AlgorithmChange
4a EFF_WriteHeader mode==1 or algo_change Write EFF header config for channel 0
4b EFF_DisconnectLoop mode==1 or algo_change Disconnect all effect slots (iterate 4→0)
5 DSP_UnmuteLoop always Unmute DSP hardware chips 0-1 via DSP_WriteGlobalConfig
6 EFF_HeaderChangeDataLoop always Process per-slot header changes + parameter changes (5 slots)
7 EFF_LinkLoop always Re-link connected effect slots (iterate 4→0)
8 EFF_VolumeLoop always Update volume parameters for all effect slots (iterate 4→0)
9 EFF_SecondaryLinkPath always Two-pass: compute max delay, then re-link secondary paths
10 Algo state update loop always Iterate slots 4→0, update algorithm state at 0x12226

EFF_MuteLoop Detail (Step 1b): Iterates EFF slots 0-4. For each slot with its mute flag set (at RAM 18736 + slot×2), sends mute config from pointer table at 0x1F3BC via DSP_WriteEFFConfig. If any slot was muted, schedules a 20-unit delay via DSP_ScheduleDelay.

DSP_AlgorithmChange Detail (Step 3): When the DSP algorithm changes, loads 7 configuration blocks sequentially from ROM:

Order ROM Address Channel Purpose
1 0x01E63C 0 Initial global config
2 0x01E6BE 0 Channel 0 config
3 0x01E996 1 Channel 1 config A
4 0x01EA12 1 Channel 1 config B
(1-unit delay) Wait for DSP to settle
5 0x01E7C5 1 Channel 1 post-delay A
6 0x01E8A7 1 Channel 1 post-delay B
7 0x01E891 1 Channel 1 post-delay C
8 0x01E947 1 Channel 1 post-delay D

If mode == 1, de-asserts DSP2 reset before loading channel configs.

EFF_HeaderChangeDataLoop Detail (Step 6): Calls EFF_Change_Handler for each dirty slot. The handler dispatches by slot number:

  • Slots 0-1: Standard EFF change path → EFF_Change_WithDebug
  • Slots 2-4: Algorithm-dependent path (mode==1 uses EFF_Change_WithDebug, otherwise EFF_DataChange_WithDebug)

EFF_Change_WithDebug writes two config blocks per change: a primary config from table at 0x1ED7C and a secondary from 0x1EF0C, both indexed by the change type. Special handling for channel 1 with types 0x9 and 0xA (hardcoded reverb/chorus ROM addresses).

All 13 diagnostic format strings (at ROM 0x0122CC-0x012397) are triggered through this dispatcher. The strings are output via Debug_Print_String (0x038365) which sends characters through boot ROM serial output at 0xFFFEA1.

Inter-CPU Command Protocol (Command 0x2D — DSP Configuration)

The Main CPU sends DSP effect configuration changes to the Sub CPU via a layered protocol:

Layer 1 — Latch Protocol:

The Main CPU writes bytes to the inter-CPU latch at 0x120000. The first byte is a header:

Bits Meaning
7-5 Handler index (0-7 into CMD_DISPATCH_TABLE at 0xF428)
4-0 Payload length minus 1 (DMA count = value + 1)

For DSP config changes, header byte 0x7F is used:

  • Handler index = 3 → Audio_CmdHandler_60_7F (line 39422)
  • Payload = 32 bytes (0x1F + 1)

The INT0_HANDLER (line 11247) reads the header byte directly, then sets up HDMA channel 0 to transfer the payload to buffer at 0x10F0. After DMA completion, MICRODMA_CH0_HANDLER (line 11338) dispatches to the handler.

Handler Range Routine Purpose
0 0x00-0x1F Audio_CmdHandler_00_1F MIDI/note commands → ring buffer at 0x2B0D
1 0x20-0x3F Audio_CmdHandler_20_3F Stub (unused)
2 0x40-0x5F Audio_CmdHandler_40_5F (function at line 9619)
3 0x60-0x7F Audio_CmdHandler_60_7F Audio/DSP commands → ring buffer at 0x3B60
4 0x80-0x9F Serial1_DataTransmit_Loop Serial port 1 data
5 0xA0-0xBF Audio_CmdHandler_A0_BF (function at line 51502)
6 0xC0-0xDF Audio_CmdHandler_C0_FF (function at line 10951)
7 0xE0-0xFF Audio_CmdHandler_C0_FF Same as handler 6

Layer 2 — Ring Buffer:

Audio_CmdHandler_60_7F copies the 32-byte payload into a ring buffer at 0x3B60:

  • Write pointer: (3B60h) — 11-bit, wraps at 0x800 (2KB)
  • Available count: (3B64h) — number of bytes queued
  • Buffer base: (3B66h) — pointer to actual data area

Two consecutive 32-byte payloads give 64 bytes in the ring buffer for a single DSP config command.

Layer 3 — Command Processing:

Audio_Process_DSP (called from main loop) reads from the ring buffer. DSP_Cmd_DequeueHeader reads 7 header bytes into RAM 4369h-436Fh, plus the command byte at 4368h.

For command 0x2D (DSP configuration), the 8-byte header is:

Byte RAM Address Description
0 4368h Command byte = 0x2D
1 4369h Sub-command (0 = normal config)
2 436Ah EFF slot selector (0x0A-0x0E → slot 0-4)
3 436Bh Reserved
4 436Ch Reserved
5 436Dh Reserved
6 436Eh Data length (0x38 = 56 bytes)
7 436Fh Update mode (0x00 = partial, 0xFF = full)

Then DSP_RingBuf_ReadAndCompare (at 0x035A7E) reads 56 data bytes from the ring buffer into 4370h-43A7h, comparing each byte with the existing slot buffer and counting changes.

Layer 4 — EFF Slot Storage:

The 56-byte parameter block is compared against the current slot buffer at 4496h + slot × 0x38:

EFF Slot Buffer Address
0 0x4496
1 0x44CE
2 0x4506
3 0x453E
4 0x4576

Each slot contains 28 word-sized parameters. Word[0] is the algorithm ID (e.g., 0x0014 = algorithm 20 = CONCERT REVERB 1). The remaining words are effect-type-specific parameter values.

If any parameters changed, DSP_ApplyConfig (at 0x03616A) copies the full 290-byte DSP state (8-byte header + 5 × 56-byte slots) from 0x448E to an allocated work buffer via DSP_State_ApplyBuf (at 0x038E31), which marks it as dirty and triggers processing by the DSP state dispatcher.

DSP Data Tables

The Sub CPU uses several lookup tables for DSP configuration:

Address Size Description
0x1E496 variable EFF header config table
0x1ED6D 5 bytes Per-EFF-slot DSP channel byte
0x1ED72 5 bytes Per-EFF-slot parameter count limit
0x1ED7C variable EFF change config table (per sub-change)
0x1EF0C variable EFF data change config table
0x1F09C N × 4 bytes Per-algorithm register address table (pointers to register maps)
0x1F22C N × 4 bytes Per-algorithm parameter mapping table (pointers to param data)
0x1F3BC variable EFF mute config table
0x1F3D0 variable DSP mute config table
0x1F3E0 variable DSP unmute config table
0x1F3F0 variable EFF disconnect config table
0x1F404 variable EFF link config table
0x122A6 2 × 11 bytes Sparse parameter update sequences (for algorithms 0x0F and 0x35)
0x12226 variable Per-algorithm byte (DSP channel assignment lookup)

Parameter Translation Chain:

DSP_WriteParameter (at 0x03C190) translates a parameter index + algorithm ID into DSP register writes:

  1. Look up 0x1F22C[algo_id] → pointer to parameter mapping data (XDE)
  2. Look up 0x1F09C[algo_id] → pointer to register address data (XBC)
  3. Call DSP_ParameterWriteEngine (at 0x03C9E6) which uses 12-byte stride tables at those pointers
  4. The inner loop reads 3 words per parameter from the mapping data
  5. Final DSP register writes go through tone generator at 0x130000

Special cases: algorithms 9 and 10 for EFF slot 1 use hardcoded tables at 0x1E17F/0x1E19E and 0x1E40A/0x1E42D respectively.

The DSP write routines used by the dispatcher:

Routine Address Description
DSP_WriteEFFConfig 0x03C161 Per-EFF DSP write (uses EFF-specific bytecode tables)
DSP_WriteGlobalConfig 0x03C181 Global DSP write (direct bytecode config)
DSP_WriteParameter 0x03C190 Parameter-specific DSP write (algo-indexed tables)
DSP_ParameterWriteEngine 0x03C9E6 Core DSP parameter write engine
DSP_BytecodeInterpreter_Init 0x03C266 Bytecode interpreter entry point

DSP Bytecode Interpreter

The Sub CPU uses a bytecode interpreter to batch-write DSP register configurations. This is not DSP microcode — it’s a Sub CPU-side interpreter that translates compact ROM-resident programs into sequences of hardware register writes to the DSP chips.

Entry Points:

Routine Address Config Table Purpose
DSP_WriteEFFConfig 0x03C161 0x14777 Per-effect channel writes (looks up DSP chip from channel mapping at 0x1ED6D)
DSP_WriteGlobalConfig 0x03C181 0x147B3 Global DSP writes (always targets DSP chip 0)

Both call DSP_BytecodeInterpreter_Init (0x03C266) which loads a 12-byte config entry from the table and begins execution.

Config Entry Format (12 bytes per entry, indexed by channel/slot):

Offset  Size  Description
+0      word  Config parameter 0 (passed to handlers via stack)
+2      word  Config parameter 1
+4      word  Config parameter 2
+6      word  Config parameter 3
+8      long  Pointer to bytecode program data in ROM

Entries are indexed by channel number: entry address = table_base + channel × 12.

Bytecode Format:

Each instruction has a 2-byte header followed by data bytes:

Byte 0: [opcode:4][count_high:4]
Byte 1: [count_low:8]

count = (count_high << 8) | count_low - 2

The count field gives the number of data bytes following the header (after subtracting 2 for the header itself).

Opcode Set:

Opcode Name Description
0x0 DSP Write Type 0 Basic DSP register write (offset 0x000 in handler table)
0x1 DSP Write Type 1 Extended parameter write (offset 0x23A)
0x2 DSP Write Type 2 Multi-register write variant (offset 0x333)
0x3 DSP Write Type 3 Complex routing write (offset 0x3DA)
0x4 DSP Write Type 4 Short parameter write (offset 0x473)
0x5 DSP Write Type 5 Short config write (offset 0x48D)
0x6-0xC Invalid (skipped)
0xD State Change Yields to task scheduler (TaskSched_PreemptiveYield_INT), then continues
0xE Send Command Sends command byte + data bytes directly to DSP hardware
0xF End Terminates bytecode execution

Opcode 0xE Detail (Send Command):

[0xE | count] [cmd_byte] [data_byte_1] ... [data_byte_N]
  1. First data byte sent via DSP_DispatchCommand (sets command register)
  2. Remaining bytes sent via DSP_DispatchData (writes data to selected register)
  3. DSP_DispatchCommand/DSP_DispatchData route to DSP1 or DSP2 based on the channel parameter

Opcodes 0-5 Detail (Native Code Handlers):

Opcodes 0-5 dispatch to native TLCS-900 machine code subroutines within the DSP_Bytecode_Programs block at 0x03C32E. The dispatch table at OFFSETS_14739 (0x014739) contains 16-bit offsets from 0x03C32E:

Opcode Offset Handler Address Approximate Size
0 0x000 0x03C32E 570 bytes
1 0x23A 0x03C568 249 bytes
2 0x333 0x03C661 167 bytes
3 0x3DA 0x03C708 153 bytes
4 0x473 0x03C7A1 26 bytes
5 0x48D 0x03C7BB 448 bytes

Total native handler code: 1,613 bytes. These handlers use prevbank registers (D7 prefix), auto-increment addressing ld C,(XWA+), and register-indirect compact forms to efficiently read data from the bytecode stream and route it to the DSP hardware via the parallel bus protocol. After completing, each handler jumps to DSP_BytecodeInterpreter_CheckEnd to continue the interpreter loop.

Common Handler Idiom:

All opcode 0-5 handlers share this recurring 13-byte “read-and-send” pattern:

ld XWA,(XSP+0x1a)     ; load bytecode stream pointer
ld C,(XWA+)            ; read next byte (auto-increment pointer)
ld (XSP+0x1a),XWA     ; store updated pointer
ld A,C                 ; copy byte to A
extz WA                ; zero-extend to 16-bit
ld BC,(XSP+0x14)       ; load DSP chip_id from stack (0=DSP1, 1=DSP2)
call DSP_DispatchCommand ; or DSP_DispatchData
ld QIZ,HL              ; save return status to prevbank register

Stack Frame Layout (set up by DSP_BytecodeInterpreter_Init):

Offset Size Contents
+0x04 word Loop counter
+0x06 word Data count (from bytecode header, 12-bit)
+0x08 word Accumulator (handler 1)
+0x0A word Accumulator (handler 0)
+0x0C word Accumulator (handler 5)
+0x0E word Accumulator (handler 3)
+0x10 long Runtime parameter value (32-bit, from caller)
+0x14 word DSP chip_id (BC register)
+0x1A long Bytecode stream pointer (XWA register)

Handler 4 — Simple Command (26 bytes):

Reads 1 byte from stream, sends as DSP command. No data follows. Used for standalone operations like algorithm select or mode switch.

Handler 3 — Command + 16-bit Address + Raw Data (153 bytes):

  1. Read 1 byte → send as DSP command
  2. Read 2-byte field → compute 16-bit DSP coefficient address:
    • addr = (byte0 << 8) | byte1 + accumulator[0x0E]
    • Send (addr >> 8) & 0xFF as data (address high byte)
    • Send addr & 0xFF as data (address low byte)
  3. Advance stream by 2
  4. Loop: read and send 1 raw data byte per iteration, for remaining (count - 3) bytes

Used for coefficient writes that need a full 16-bit address prefix.

Handler 2 — Command + 2 Preamble + Groups of 3 (167 bytes):

  1. Read 1 byte → send as DSP command
  2. Read 2 bytes → send as 2 data values
  3. Loop: (count - 3) / 3 iterations, each reads 3 bytes and sends as 3 data values

Used for bulk writes of 3-byte coefficient entries (e.g., 24-bit parameters or address+value pairs).

Handler 1 — Command + 2 Preamble + Groups of 5 with 4-bit Address (249 bytes):

  1. Read 1 byte → send as DSP command
  2. Read 2 bytes → send as 2 preamble data values
  3. Loop: (count - 3) / 5 iterations, each processing 5 stream bytes: a. Read 2 raw bytes → send as data b. Read 2-byte field → compute 12-bit coefficient address:
    • addr = (byte0 << 4) | (byte1 >> 4) + accumulator[0x08]
    • Send (addr >> 4) & 0xFF as data (address high nibble)
    • Send ((addr << 4) & 0xFF) | 1 as data (address low nibble + flag) c. Advance stream by 2, read 1 more raw byte → send as data

Used for interleaved coefficient/address writes with 12-bit packed addresses.

Handler 0 — Command + 2 Preamble + Groups of 5 with 3-way Branching (570 bytes):

Most complex handler. Processes data in groups of 5 bytes but branches based on the first byte of each group:

  1. Read 1 byte → send as DSP command
  2. Read 2 bytes → send as 2 preamble data values
  3. Loop: (count - 3) / 5 iterations, with 3-way branch per group:

    Branch A (first byte == 0x00 — static coefficient):

    • Read 2 raw bytes → send as data
    • Read 2-byte field → compute 12-bit address (4-bit shift), send as 2 data bytes
    • Advance stream by 2, read 1 more raw byte → send

    Branch B (first byte == 0x0A — raw passthrough):

    • Read and send 5 raw bytes directly as data (no computation)

    Branch C (any other value — parameter-modified coefficient):

    • Read 1 raw byte → send as data
    • Use 32-bit runtime parameter from (XSP+0x10) to compute 4 data bytes:
      • data0 = stream[0] + ((param >> 1) & 0x7F)
      • data1 = stream[1] + ((param >> 9) & 0xFF)
      • data2 = stream[2] + ((param >> 1) & 0xFF)
      • data3 = stream[3] + ((param << 7) & 0x80)
    • Send 4 computed data bytes, advance stream by 4

This is the key handler for real-time parameter control: bytecode programs contain template coefficient data, and the Branch C path mixes in the runtime parameter value to create dynamically-adjusted coefficients. Branch A handles static coefficients (address writes), Branch B handles raw data, and Branch C applies the parameter offset.

Handler 5 — Command + 2 Preamble + Groups of 5, Variant (448 bytes):

Very similar to Handler 0 but with different branching logic:

  1. Read 1 byte → send as DSP command
  2. Read 2 bytes → send as 2 preamble data values
  3. Loop: (count - 3) / 5 iterations, with 2-way branch:

    Branch A (first byte == 0x08 — 12-bit address with mask):

    • Same as Handler 0 Branch A, but additionally masks IZ high byte to 0
    • Uses ld IZH, 0 to ensure address stays within 8-bit range

    Branch B (any other value — parameter-modified):

    • Same computation as Handler 0 Branch C

Handler 5 is used for DSP programs that need both address-masked coefficient writes and parameter-modified coefficients.

Parameter Packing Summary:

Opcode Address Width Shift Group Size Loop Divisor Accumulator
0 12-bit 4 5 bytes 5 stack[0x0A]
1 12-bit 4 5 bytes 5 stack[0x08]
2 — (raw) 3 bytes 3
3 16-bit 8 1 byte 1 stack[0x0E]
4
5 12-bit 4 5 bytes 5 stack[0x0C]

For 12-bit parameters, the value is packed across 2 bytecode bytes as byte0[7:0] << 4 | byte1[7:4]. This is split into two DSP data writes: high byte (value >> 4) and low byte ((value << 4) & 0xFF). This indicates DSP registers use 12-bit parameter values for most effect parameters.

For 16-bit parameters (opcode 3), the full 16-bit value is packed as byte0[7:0] << 8 | byte1[7:0], split into high byte and low byte data writes.

Execution Flow Example:

When DSP_WriteGlobalConfig is called to mute DSP chip 0:

1. DSP_WriteGlobalConfig called with WA=0 (channel 0), XBC=pointer to mute config
2. Sets DE=0 (fixed for global writes)
3. Pushes XBC (config pointer), loads bytecode table pointer 0x147B3
4. Calls DSP_BytecodeInterpreter_Init:
   a. Loads 12-byte entry from 0x147B3 + 0*12 (channel 0)
   b. Copies 4 config words + 1 program pointer to stack frame
   c. Falls through to BytecodeInterpreter_CheckEnd
5. Interpreter reads first bytecode header from program pointer
6. Dispatches on opcode:
   - 0xE → sends command+data to DSP hardware
   - 0x0-0x5 → jumps to native handler for bulk register writes
   - 0xD → yields to scheduler, then continues
   - 0xF → terminates
7. Repeats until 0xF terminator encountered

Real-Time Parameter Modification:

The DSP_ParameterWriteEngine (0x03C673) enables real-time control of DSP effects. When a MIDI parameter changes (e.g., reverb depth, chorus rate), the engine:

  1. Looks up the parameter index in a translation table at 0x1ED6D
  2. Walks through algorithm-specific bytecode programs (table at 0x1F22C for program pointers, 0x1F09C for register addresses)
  3. Calls DSP_PerParameterTranslator to map the MIDI value to a 32-bit DSP parameter
  4. Re-runs the bytecode program with the new parameter value in (XSP+0x10)
  5. Handler 0/5 Branch C applies the parameter offset to template coefficients during write

This allows a single MIDI parameter change to update multiple DSP registers simultaneously, with the bytecode program encoding which registers to modify and how to transform the parameter value for each one.

Effect Type Bytecode Programs

Each of the 16 effect types has two bytecode programs: an algorithm program (Primary Table at 0x1ED7C) that loads the DSP algorithm, and a parameter program (Secondary Table at 0x1EF0C) that writes tunable coefficients.

Algorithm Programs (Primary Table): All use a single Handler 3 instruction with CMD=0x01 and DSP address 0x0054 (generic channels) or 0x00C8 (channel 1 reverb/chorus). The Handler 3 data size varies by algorithm complexity:

Type Algorithm Program Size Shared With Notes
0 0x017263 250B 7, 11-14 Default/base algorithm
1 0x0153C1 355B  
2 0x015664 430B  
3 0x015986 500B  
4 0x015D43 330B  
5 0x015FFE 535B Largest generic algorithm
6 0x0177C3 485B  
8 0x01743B 515B  
9 0x017F1F 245B  
10 0x018141 345B  
15 0x016ACF 435B  

Types 0, 7, 11, 12, 13, and 14 share the same algorithm (0x017263). This indicates 10 distinct algorithms and 6 aliases.

Channel 1 Special Programs: Reverb (type 0x9) and Chorus (type 0xA) have hardcoded programs bypassing the table lookup, using DSP address 0x00C8 instead of 0x0054:

Effect Algorithm Param Program Algorithm Size
Reverb (P1) 0x1DFA5 275B
Reverb (P2) 0x1E0B9 197B
Chorus (P1) 0x1E1DE 355B
Chorus (P2) 0x1E342 199B

Parameter Program Structure: All 16 types follow the same template:

H0 (9-31 groups × 5B)     ← Static/parameter-modified coefficients
H4 CMD=0x03               ← Section separator
H5 (3-21 groups × 5B)     ← Runtime-adjustable coefficients
H4 CMD=0x03               ← Section separator
H1 (8B)                   ← Address computation block
H2 (12-31 groups × 3B)    ← Bulk coefficient data
H4 CMD=0x03               ← Section separator
END

The number of H0/H5/H2 groups varies by effect type (more complex effects have more parameters). Type 5 (Flanger?) and types 3/15 have an extra H0 block before H5, suggesting additional parameter stages.

EFF Chip Mapping (0x1ED6D): Maps effect channels to DSP hardware:

Channel DSP Chip Max Params Notes
0 DSP1 (DS3613GF-3BA) 28  
1 DSP1 24 Hardcoded reverb/chorus programs
2 DSP2 (MN19413) 46 Most parameters
3 DSP2 20  
4 DSP2 20  
5-9 (invalid) Channel IDs > 4 not used for DSP

Parameter count limits are stored at 0x1ED72 (5 bytes, one per channel).

Algorithm and Parameter ROM Tables

The SubCPU ROM contains 6 key tables for DSP effect configuration:

Table Address Format Entries Purpose
Chip Mapping 0x1ED6D 1B × 5 5 Channel → DSP chip (0=DSP1, 1=DSP2)
Param Limits 0x1ED72 1B × 5 5 Max parameters per channel (20-46)
Algorithm Programs 0x1ED7C 4B × 100 100 Pointers to algorithm bytecode (indexed by full algo ID 0-99)
Parameter Programs 0x1EF0C 4B × 100 100 Pointers to parameter bytecode (47 unique programs)
Register Addresses 0x1F09C 4B × 12 12 Per-algo-type register address bytecode pointers
Parameter Mapping 0x1F22C 4B × 12 12 Per-algo-type parameter mapping bytecode pointers
Algo Type Lookup 0x1F596 1B × 40 40 Effect index (0-39) → algorithm type (2-11)

Algorithm Program Table (0x1ED7C): 100 entries indexed by full algorithm ID. Unique programs for types 2-6, 8-10, 15 (Rotary). Types 0, 7, 11 share a common program at 0x017263. Extended IDs 16-27 (reverb subtypes) share algorithm programs with their base type but have unique parameter programs.

Parameter Program Table (0x1EF0C): 47 unique parameter programs covering:

  • 10 base algorithm types
  • 12 individual reverb subtypes (IDs 16-27)
  • 6 distortion/dynamics variants (IDs 32-36, 39)
  • 6 extended effects (auto pan, pitch shifter, pedal wah, rotary, ring mod, HARS)
  • Combination effects, presets, GEQ

Register and Parameter Mapping Tables (0x1F09C, 0x1F22C): Both are indexed by algorithm type (0-11). Types 0, 7, 11 have NULL register pointers (they use extended-ID-specific programs instead). The parameter mapping table has a fallback at 0x017425 for these types. Both tables point to variable-length bytecode programs with opcodes like 0x21 (interpolation), 0x40 (pan scaling), 0x61-0x78 (dispatch), terminated by 0x7A/0xF0.

Parameter Translation Opcodes (Level 2 Bytecodes)

The DSP_PerParameterTranslator at SubCPU 0x03CB8E dispatches parameter translation opcodes that convert MIDI parameter values (0-127) into DSP chip coefficient writes. Each opcode implements a different mathematical transformation:

Special Opcodes:

Opcode Name Description
0x21 Interp2Point 2-point linear interpolation (same as 0x66)
0x24 InterpMultiStep Multi-step interpolation with breakpoints
0x40 PanScale Pan/balance simple scaling
0x7A EndSection End of parameter section
0xF0 Terminate End of entire table

Regular Opcodes (0x61-0x78), dispatched via jump table at SubCPU 0x014745:

Opcode Transform Output Description
0x61 SingleTableFetch OscParam Direct LUT lookup
0x62 AlgoTypeTableFetch FreqParam Algorithm-specific LUT
0x63 AlgoParamDecode OscParam Effect type/variant selection
0x64 PitchScale FreqParam Frequency domain scaling
0x65 VolumeScale OscParam Amplitude domain scaling
0x66 Interp2Point OscParam 2-point coefficient blend
0x67 InterpFPScale OscParam+Offset Fixed-point scaling with offset
0x68 InterpDiv0xB4 FreqParam Time constant ÷ 0xB4
0x69 VolumeCurveFP OscParam Fixed-point volume curve
0x6A FreqCurveFP FreqParam Fixed-point frequency curve
0x6B FreqInterp2Point FreqParam Frequency 2-point interpolation
0x6C Interp3PointOffset FreqParam 3-point interpolation with offset
0x6D ReverbCurveFP OscParam Reverb decay time curve
0x6E InterpFPComplex OscParam Complex fixed-point interpolation
0x6F PanPiecewiseLin OscParam Piecewise-linear pan curve
0x70 BiquadCoeff (direct) Biquad filter coefficient computation
0x71 DetuneSigned OscParam Signed detune curve
0x72 BiquadWarp (direct) Biquad frequency warping
0x73 InterpDiv0xC6 OscParam Time constant ÷ 0xC6
0x74 LUTParamSet (direct) Multi-parameter LUT write
0x75 ParamEQCurve OscParam Parametric EQ curve
0x76 SOSCoeff (direct) Second-order section coefficients
0x77 Interp2PointB OscParam 2-point variant B
0x78 VolScaleB OscParam Volume scale variant B

Output targets: OscParam writes oscillator/amplitude registers, FreqParam writes frequency/timing registers, (direct) writes multiple registers directly.

Named Effect Parameters

The MainCPU ROM at 0xE324C4 contains 86 parameter name entries (17 bytes each: 16-char name + ‘:’ separator). Key named parameters:

Index Name Index Name
0x01 VOLUME 0x22 REVERB TIME
0x03 REV SEND 0x23 PRE DELAY
0x04 DRIVE 0x24 HIGH DAMP GAIN
0x05 ADJUST 0x25 ER.LEVEL
0x06 EMPHASIS GAIN 0x26 PITCH L
0x07 DEPTH 0x27 PITCH R
0x08 LFO SPEED 0x28 THRESHOLD
0x09 SLOW LFO SPEED 0x29 RATIO
0x0A FAST LFO BALANCE 0x33 BAND EMPHASIS FC
0x0B RESONANCE 0x34 BAND EMPHASIS Q
0x0C MANUAL 0x35 BAND EMPHASIS G
0x0D SLOW/FAST 0x38 FEEDBACK
0x1D PHASER DRY/WET 0x3B WAH CENTER FC
0x52 INTENSITY

Effect Algorithm Type Summary

40 effect indices map to 10 algorithm types (2-11). Each algorithm defines which named parameters control the DSP, and which translation opcodes transform MIDI values.

Parameter Mapping Bytecode Format: Each entry is [flags:1] [total_length:1] [opcode:1] [data:length-3]. The first data byte is the primary parameter index. Additional data bytes may be secondary parameter indices or coefficient data. Programs terminate with 0xF0.

Complete Parameter→Transform Mappings (decoded from ROM tables at 0x1EF0C):

Algo Effects Parameter Mappings (ordered)
0,7,11 PERCUSSIVE, STANDARD, MIX UP, HARS, SLOW ATTACKER, COMPRESSOR, EXCITER Interp2Point(DRIVE) → InterpFPScale(PITCH L) → InterpFPComplex(ADJUST,EMPHASIS GAIN) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE)
1 (base type 1) Interp2Point(SLOW LFO SPEED,FAST LFO BAL) → VolumeScale(VOLUME) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE) → LUTParamSet(DRY/WET)
2 STAGE, BATH ROOM, KARAOKE, ROOM… Interp2Point(RESONANCE,MANUAL,SLOW/FAST,+2more) → VolumeScale(VOLUME) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE) → LUTParamSet(DRY/WET)
3 PEQ+COMPRESSOR, PEQ+VIBRATO, PEQ+FLANGER AlgoTypeTableFetch(LFO SPEED,SLOW LFO,+2more) → PitchScale(RESONANCE,MANUAL) → SOSCoeff(VOLUME,DRIVE,SLOW/FAST,+1) → FreqInterp2Point(+2) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE) → LUTParamSet(DRY/WET)
4 PEQ+S.DELAY, PEQ+CHORUS, AUTO WAH+S.DELAY Interp2Point(LFO SPEED,MANUAL) → VolumeScale(ADJUST,SLOW LFO) → Interp3PointOffset(PARAM_50,INTENSITY) → InterpDiv0xB4(LFO SPEED,SLOW LFO) → InterpDiv0xC6(VOLUME,+3) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE) → LUTParamSet(DRY/WET)
5 S.DELAY+PHASER/VIBRATO/FLANGER Interp2Point(ADJUST,EMPHASIS GAIN,LFO SPEED,SLOW LFO) → VolumeScale(VOLUME,MANUAL) → InterpDiv0xB4(+2) → InterpDiv0xC6(+2) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE) → LUTParamSet(DRY/WET)
6 STRING, DEEP SPACE, SYMPHONIC VolumeScale(VOLUME) → Interp2PointB(REV RETURN,DRIVE,EMPHASIS GAIN,SLOW LFO,RESONANCE,SLOW/FAST) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE) → LUTParamSet(DRY/WET)
8 RING MOD, ROTARY, AUTO WAH, PEDAL WAH Interp2Point(+1) → ParamEQCurve(REV SEND) → SOSCoeff(DEPTH,+1) → PanPiecewiseLin(+2) → ReverbCurveFP(+2) → InterpFPScale(PITCH L) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE)
9 VIBRATO, PITCH SHIFTER, AUTO PAN InterpFPScale(PITCH L,THRESHOLD) → SOSCoeff(REV SEND,EMPHASIS GAIN,MANUAL,+1) → InterpDiv0xC6(VOLUME,+3) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE) → LUTParamSet(DRY/WET)
10 CELM, CEL, PARAMETRIC EQ, NOISE FLANGER Interp2Point(REV SEND,DRIVE,ADJUST,EMPHASIS GAIN) → InterpFPScale(PITCH L,THRESHOLD,RATIO,+1) → SOSCoeff(LFO SPEED,RESONANCE) → InterpDiv0xC6(DEPTH) → AlgoParamDecode(EMPHASIS GAIN) → Interp2Point(GLOBAL_SCALE) → LUTParamSet(DRY/WET)

Common suffix: Every algorithm ends with AlgoParamDecode(EMPHASIS GAIN) for effect variant selection, Interp2Point(GLOBAL_SCALE) for output level, and (most) LUTParamSet(PHASER DRY/WET) for dry/wet mix control.

Register Address Programs (ROM table at 0x1F09C): Each algorithm type also has a register address program that specifies which DSP register addresses each parameter writes to. The register programs use the same bytecode format as the parameter mapping but contain DSP coefficient addresses (12-bit or 16-bit) and fixed-point default values. Algo types 0, 7, 11 share a fallback that doesn’t have register address programs (NULL pointers).

DSP Coefficient Setup Pipeline

The coefficient setup subsystem configures DSP processing parameters through a multi-stage pipeline. Eight functions handle different aspects of coefficient configuration:

Function Size Purpose
DSP_SetCoeff_CopyDirect 69B Direct coefficient copy from routing tables
DSP_SetCoeff_CopyDirect2 69B Direct copy variant 2
DSP_SetCoeff_RouteComplex 344B Complex routing with multi-table lookup
DSP_SetCoeff_RouteWithCallback 291B Routing with callback (calls 0x032AE0)
DSP_SetCoeff_FullPipeline 384B Multi-stage processing (0x032AE0 + 0x032682)
DSP_SetCoeff_WithDispatch 135B Type-dispatched coefficient selection
DSP_SetCoeff_WriteParams 90B Individual parameter writes to 0x045216/17
DSP_SetCoeff_MasterConfig 706B Master configuration (calls 0x02B014)

Voice-to-DSP Output Configuration

The voice output configuration functions map synthesized voices to DSP effect channels:

Function Size Purpose
Voice_DSP_OutputConfig 237B Configure voice→DSP routing (type 1)
Voice_DSP_OutputConfig2 237B Configure voice→DSP routing (type 2)
Voice_DSP_SimpleCopy 91B Simple voice parameter copy to DSP
Voice_DSP_SimpleCopy2 91B Simple copy variant 2
DSP_VoiceParam_Dispatch 155B Voice parameter dispatch with bit-5 routing

These functions implement the voice→DSP routing pipeline:

  1. Call DSP_AlgoType_Dispatch1 to determine the algorithm type for the voice
  2. Store result to DSP state (0x04520E or 0x04520C)
  3. Call Voice_BuildOutputList to enumerate active voice outputs
  4. Iterate the output list, configuring each via ToneGen_ExtParams56b_DataTable
  5. Loop until all voices processed (up to 128 for full config, 64 for simple copy)

Synthesis Architecture

The KN5000 implements a hardware wavetable synthesis architecture: the Sub CPU firmware handles MIDI event processing, voice allocation, and parameter management, while the actual sound generation is performed entirely by the tone generator hardware (IC303, TC183C230002).

Polyphony and Voice Management

Parameter Value
MIDI Channels 26 (channels 0-25)
Hardware Voices 64 simultaneous
Voice Parameter Size 287 bytes per MIDI channel (0x11F)
Hardware Voice Size 71 bytes per voice (0x47)
Voice Template 68 bytes at ROM 0xF8D5 (34 × 16-bit words)
Channel Parameter Base 0x04136E (Sub CPU RAM)
Hardware Voice Pool 0x04308E (Sub CPU RAM, 64 × 71 = 4544 bytes)
Voice Slot Table 0x4A4C (16 active voice tracking slots)

Channel address formula: 0x04136E + (channel_number × 0x11F)

The firmware implements dynamic voice allocation: any of the 26 MIDI channels can be assigned to any of the 64 hardware voices on demand. When a Note On arrives, Voice_Allocate (0x02C9DF) acquires a free voice from a pool-based allocator at 0x2A4E with voice stealing for polyphony overflow.

Voice Parameter Structure (287 bytes per MIDI channel)

Each MIDI channel maintains a 287-byte parameter block:

Offset Size Parameter Set By
+0x00 4 Pitch base Note On
+0x04 2 Portamento flag CC 0x95
+0x06 2 Volume (scaled) CC 0x07
+0x08 2 Pan CC 0x0A
+0x0A 2 Expression (scaled) CC 0x0B
+0x11 1 Frequency multiplier CC 0x91
+0x12 1 Fine pitch tuning CC 0x97
+0x1F 1 Vibrato depth CC 0x9B
+0x20 1 Tremolo/AM depth CC 0x9D
+0x67 var Extended parameter refs Program Change

Note-On Processing Pipeline

When a MIDI Note On arrives at Voice_NoteOn (0x02CF97):

MIDI Note On (channel, note, velocity)
  │
  ├─ velocity = 0? ──yes──> Voice_NoteOff (release voice)
  │
  ├─ Voice_Allocate (0x02C9DF)
  │     └─ Pool-based allocation from 64 hardware voices
  │     └─ Voice stealing if pool exhausted
  │
  ├─ Voice_SetVelocity
  │     └─ Scale velocity via lookup table at 0x011D16
  │     └─ Write to amplitude parameter
  │
  ├─ Voice_SetPitch / ToneGen_Calc_Pitch (0x03D11F)
  │     └─ note + 0x24 (transpose by +36 semitones)
  │     └─ Semitone-specific adjustments (A#, G#, F#, E#)
  │     └─ Mode-dependent pitch offset (tone gen mode at 0x4A48)
  │     └─ Clamp to 0-255 range
  │
  └─ ToneGen_WriteVoiceParams
        └─ Write 21 register pairs to 0x100000/0x100002
        └─ Set key-on flag (bit 15 at register offset 0x0080)

Pitch Calculation

ToneGen_Calc_Pitch (0x03D11F) converts MIDI note numbers to tone generator pitch values:

  1. Add base offset: note + 0x24 (transpose up 3 octaves)
  2. Apply semitone-specific corrections for A#, G#, F#, E# (chromatic tuning compensation)
  3. Apply mode-dependent offset from lookup tables at 0x01F420-0x01F422
  4. Clamp final pitch to 0-255 range
  5. Look up velocity curve from table at 0x01F53E

Volume and Expression

Volume (CC 0x07) and Expression (CC 0x0B) both use a shared scaling lookup table at ROM 0x011D16. The final output level is the product of volume and expression, applied to the tone generator’s volume registers (groups 0x08-0x09).

Pan (CC 0x0A) is a direct value (0-127) written to channel offset +0x08 and translated to left/right balance via EnvTranspose_UpdateLoop.

Envelope Processing

The KN5000 uses hardware envelopes in the tone generator IC303 — the Sub CPU firmware does not implement software ADSR:

  • Key-on (Note On): Sets bit 15 at tone gen register 0x0080, which triggers the hardware’s internal attack phase
  • Key-off (Note Off): Clears the enable flag, triggering hardware release
  • Sustain pedal (CC 0x40): Voice_CC_Sustain (0x028962) defers note-off processing while held — notes sustain until pedal released
  • Sostenuto (CC 0x5B): Similar hold behavior for notes already sounding
  • Soft pedal (CC 0x5D): Reduces velocity/volume scaling

Attack, decay, sustain level, and release times are determined by the tone generator hardware and the per-voice register template, not by CPU-side envelope generators.

LFO and Modulation

The Mod Wheel (CC 0x01) controls LFO modulation via Voice_ModWheel_Apply (0x024565). The modulation type is selected by bits [7:6] of voice parameter offset +16:

Bits [7:6] Mode Effect
0x00 Off No modulation
0x40 Vibrato Pitch modulation (frequency wobble)
0x80 Tremolo Amplitude modulation (volume pulse)
0xC0 Auto-pan Stereo position modulation

Additional modulation parameters via proprietary CCs:

CC Offset Parameter
0x9B +0x1F Vibrato depth
0x9C Vibrato enable/disable (bit 8 toggle)
0x9D +0x20 Tremolo/AM depth

The actual LFO oscillator runs inside the tone generator hardware; the firmware only sets depth and mode parameters.

Filter Control

No explicit filter envelope or cutoff sweep exists in the CPU firmware. The tone generator hardware likely contains internal filters controlled by:

  • CC 0x9B (offset +0x1F): May modulate filter cutoff depth in addition to vibrato
  • Tone gen registers 0x0800-0x08C0 (Volume/Level group): Likely include filter-related parameters
  • Tone gen registers 0x09C0-0x0A40 (Aux group): Extended parameters potentially including resonance

Filter behavior is fixed per voice preset — no real-time filter sweeps are implemented in firmware.

Proprietary Control Changes (0x91-0x9D)

CC Handler Channel Offset Function
0x91 Voice_CC_SetReverbDepth +0x11 Frequency multiplier (via lookup table)
0x95 Voice_CC_SetChorusEnable +0x04 Portamento enable/disable (boolean flag)
0x97 Voice_CC_SetChorusDepth +0x12 Fine pitch tuning (semitone-level adjustment)
0x9B Voice_CC_SetDelayDepth +0x1F Vibrato depth (via lookup table)
0x9C Voice_CC_SetDelayEnable Vibrato enable/disable (bit 8 toggle)
0x9D Voice_CC_SetDelayFeedback +0x20 Tremolo/AM depth (via lookup table)

All proprietary CCs use channel × 0x11F + base_offset to access per-channel data. CCs 0x91, 0x97, 0x9B, and 0x9D read values from a shared lookup table at 0x011D16. CCs 0x95 and 0x9C are boolean toggles using OR/AND bit masks.

Tone Generator

The tone generator (IC303, TC183C230002) is a custom Matsushita 64-voice wavetable synthesis LSI. It has two interfaces:

  • Register config at 0x100000/0x100002: Write voice parameters and global settings via register-indirect addressing (32 registers per voice across 8 groups × 4 banks, 13 global registers)
  • Keyboard input at 0x110000/0x110002: Read voice events (note on/off with velocity)

See Tone Generator for the complete register map, initialization sequence, and chip inventory.

Voice Slot Table

16 voice slots at 0x4A4C-0x4A5C track active notes:

  • 0xFF = note active
  • 0x00 = slot available

Key Routines

Routine Address Description
ToneGen_Config_Init 0x02DFCF Configure all 64 voices and global registers
ToneGen_Init 0x03D016 Set mode to 6, start polling
ToneGen_Poll_Init 0x03D227 Read initial voice state (16 slots)
ToneGen_Process_Notes 0x03D01E Process keyboard events in main loop
ToneGen_Read_Voice_Data 0x03D0C5 Read note/velocity from hardware
ToneGen_Calc_Pitch 0x03D11F Calculate pitch value

Hardware Access

  • P6.7 controls A23 address line for tone generator access
  • Status read: 0x110002 (bit 0 = data ready)
  • Data read: 0x110000 (16-bit: low byte = note, high byte = velocity)
  • Register write: 0x100000 (address), 0x100002 (data) with P6.7 chip-select protocol

Sound Categories

The Main CPU organizes sounds into 16 categories with pointers at 0xE023B0:

Index Category
0 PIANO
1 GUITAR
2 STRINGS & VOCAL
3 BRASS
4 FLUTE
5 SAX & REED
6 MALLET & ORCH PERC
7 WORLD PERC
8 ORGAN & ACCORDION
9 ORCHESTRAL PAD
10 SYNTH
11 BASS
12 DIGITAL DRAWBAR
13 ACCORDION REG.
14 GM SPECIAL
15 DRUM KITS

Feature Demo

The Feature Demo plays pre-recorded MIDI sequences to demonstrate the keyboard’s capabilities. Pressing the DEMO button triggers a complex initialization and playback sequence.

Demo Initialization Flow

DemoModeFunc (entry point)
  ├─ First call → DemoMode_Initialize
  │     ├─ Demo_PreSetup (general preparation)
  │     ├─ Audio_WaitForReady (poll bit 2 of 0x0420)
  │     ├─ Voice_SavePreset (save current voice state)
  │     ├─ SeqInit_PostEventSequence (post events 0xE1, 0xE2, 0xE3)
  │     └─ Seq_StartMainControlAlt (enter main control with event 0x01E1000D)
  └─ Subsequent calls → DemoMode_Main_Operation
        ├─ Voice_InitializeAll (allocates 0x1F0 bytes, inits 16 voices × 26 params)
        ├─ Audio_ConfigureDSP (DSP and hardware setup)
        ├─ Voice_LoadVoiceTable (load 16 voice presets)
        ├─ Demo_PreSetup
        ├─ Voice_CopyPreset (restore voice data)
        ├─ Timer7_DisableInterrupt
        ├─ Audio_CheckSubsystemReady
        ├─ SeqInit_PostEventSequence
        ├─ SeqInit_FinalEvent (post event 0x1B with 0xFFFFFFFF)
        └─ Seq_StartMainControl (enter main control with event 0x01E1000C)

Sequencer Event Processing

The sequencer reads song events from an internal buffer and dispatches them via inter-CPU latch:

Routine Address Purpose
Seq_ProcessEventLoop 0xEF14CA Main event processing loop
Seq_CheckSongEnd 0xEF27A5 Checks if song position (0x01F377) == end position (0x01F373)
Seq_ProcessMidiEvent 0xEF13CD Processes individual MIDI events (0x90=NoteOn, 0x80=NoteOff, 0xB0=CC)

Demo Song Data

The demo’s style/rhythm preset data is at Demo_StyleRhythmData (0xF5CFCC), which contains:

  • Rhythm/style parameter bytes (96 bytes)
  • ASCII variation names: “a-variation1” through “c-variation4” (12 variations)
  • Section names: “a-intro 1”, “a-fill in 1”, “a-ending 1”, etc. (24 sections)
  • Additional parameter data

The data loading uses LDIR block copy loops at Demo_LoadVariationData (0xF5CF8B) and Demo_LoadVariationC_Data (0xF5CFAE).

Current Emulation Behavior

When the DEMO button is pressed in MAME, the Feature Demo enters its playback loop but only sends configuration commands (Control Change, Pitch Bend, Channel Pressure, SysEx). No Note On (0x90) or Note Off (0x80) events are ever dispatched. Analysis of a test session showed:

Command Type Count Description
0xB0 (CC) 2,555 Control Change — Pan (1109), Expression (1099), Volume (73), others
0xF0 (SysEx) 36 System Exclusive messages
0xE0 (Pitch Bend) 19 Pitch Bend changes
0xD0 (Chan Pressure) 15 Channel Pressure (aftertouch)
0x90 (Note On) 0 No note events sent
0x80 (Note Off) 0 No note events sent

Diagnostic Log Analysis

Detailed MAME logging with sequencer state instrumentation reveals:

Rhythm ROM validation passes:

  • rhy_ofs=00000000 at RAM (3277h) — NOT 0xFFFFFFFF, so RhythmROM_CheckValid returns success
  • Rhythm ROM reads occur during demo mode (1800-3800 reads/second from 0x400000+ addresses)
  • First rhythm ROM read at t=5.5s from 0x400000, PC=0xF5465E (inside RhythmROM_ValidateHeader)

Sequencer state machine transitions:

Time State Event
Boot 0x00 Initial idle state
~5s 0x01 Transition during initialization
~21s 0xE0 DemoMode_Main_Operation entered
~22.6s 0xE4 DemoMode_Initialize completed

All observed states (0x00, 0x01, 0xE0, 0xE4) are outside the 0x10-0x16 skip range, confirming the sequencer dispatcher is NOT blocked by state checks.

Ring buffer never written:

  • putc_mrx=0 in every heartbeat — the function that writes MIDI events to the main sequencer ring buffer (SeqMain_WriteByte at 0xEF276D) has ZERO execution hits
  • SeqBuf wr=0000 rd=0000 — write and read positions are always equal (buffer empty)
  • Seq_CheckSongEnd always returns 0 (no events to process)

Startup flag always zero:

  • startflag=0000 at RAM (0x0251D8) — never set to a non-zero value
  • This flag controls whether Seq_StartMainControlAlt (called from DemoMode_Initialize) configures audio hardware at 0xF42EA4
  • On real hardware, something sets this flag during boot or demo initialization

Event loop rate drops 60x after demo init:

  • Before demo: ~11,500 event loop iterations/sec
  • After demo init (state=0xE4): ~168-180 iterations/sec
  • This indicates the sequencer dispatcher IS running heavier processing (rhythm ROM reads, pattern loading), consuming CPU time, but never producing MIDI events into the ring buffer

Sequencer processing PC addresses during demo:

  • PCs in range F5CFxx-F641xx confirm rhythm/sequencer processing code is executing
  • This range covers Seq_RhythmProcessor through RhythmROM_CalcPatternAddr

Root Cause Analysis

The pipeline breaks between “rhythm data loaded from ROM” and “MIDI events generated into ring buffer”:

Rhythm ROM (4MB) ──read──> Pattern Data in RAM ──???──> Ring Buffer (0x01F37B)
     ✓ working              ✓ executing                  ✗ NEVER written

Possible causes under investigation:

  1. Startup flag (0x0251D8) is never set, potentially skipping a critical initialization step
  2. A missing Timer7 tick or other timing mechanism that drives MIDI event generation
  3. An inter-CPU response or hardware register that gates the final event write stage

Code References

Main CPU (maincpu/kn5000_v10_program.asm)

Routine Address Description
Audio_Lock_Acquire 0xEF1FEE Acquire inter-CPU lock
Audio_Lock_Release 0xEF1F0F Release inter-CPU lock
Audio_DMA_Transfer 0xEF341B Core DMA transfer
Audio_InitDMAChannels 0xEF329E Initialize DMA channels
sendCOMM 0xEF32F4 Send command/audio data to Sub CPU (chunks 32-byte blocks)
InterCPU_Send_Data_Block 0xEF3350 Send 1-32 byte packet via inter-CPU latch
Audio_CheckSubsystemReady 0xFDDE6F Check if audio subsystem is ready for commands
Audio_CheckInitStatus 0xFDF08A Verify audio init state (checks 0xF19E)
Voice_InitializeAll 0xFE0E75 Initialize all 16 voices (26 params each)
Audio_ConfigureDSP 0xFDBD52 Configure DSP hardware and state
DemoMode_Initialize 0xF869E3 Feature Demo first-time initialization
DemoMode_Main_Operation 0xF8696F Feature Demo normal playback handler

Sub CPU (subcpu/kn5000_subprogram_v142.asm)

Routine Address Description
Audio_System_Init 0x01FACB Master audio initialization
MIDI_Dispatch 0x034D93 MIDI message dispatcher
Audio_CmdHandler_00_1F 0x034D5F Audio command handler
Voice_NoteOn 0x02CF97 Note On processing
Voice_CtrlChange 0x02A282 Control Change processing
DSP_System_Init 0x034C45 DSP initialization
ToneGen_Init 0x03D016 Tone generator init

Serial Port 1 Interface

The Sub CPU’s serial port 1 is used as a Computer Interface (TO HOST connector). The “SA” designation in the service manual schematics refers to “Sub Address” bus lines, not a chip name.

Parameter Value
Mode 8-bit UART (SC1MOD = 0x29)
Baud Rate ~500kHz (20MHz / 4 / 10)
Sync Byte 0xFE (sent at init and periodically)
TX Buffer 1024 bytes at 0x0A00-0x0DFF
RX Buffer 512 bytes at 0x0E16-0x1015

MIDI Active Sensing

MAME emulation confirms that the Sub CPU transmits 0xFE (MIDI Active Sensing) on this port approximately every 276ms. This is a standard MIDI heartbeat message indicating the device is alive and ready for communication. No other data has been observed on this port during normal operation or Feature Demo playback.

See Tone Generator for details.

DSP Chip Identification

The KN5000 uses two custom DSP chips for effects processing:

IC Part Number Manufacturer Notes
IC310 MN19413 Matsushita (Panasonic) Custom ASIC, no public documentation
IC311 DS3613GF-3BA Unknown origin Custom ASIC, no public documentation

Both DSPs use an identical 8-bit parallel bus protocol with shared data lines but separate chip-select signals. They are NOT general-purpose DSPs — they are dedicated effects processors with a fixed command interface.

DSP Control Pin Mapping

The Sub CPU controls both DSPs via GPIO pins:

Pin Port Function
P7.3 Port 7 bit 3 Write strobe (active low)
P7.4 Port 7 bit 4 Read strobe (active low)
P7.5 Port 7 bit 5 CS1 — DSP1 chip select (IC311, DS3613GF-3BA)
P7.6 Port 7 bit 6 Command/Data select (1=command, 0=data)
PE.6 Port E bit 6 CS2 — DSP2 chip select (IC310, MN19413)
PH.0 Port H bit 0 Status input (busy/ready)
PZ[7:0] Port Z 8-bit bidirectional data bus

DSP1 handshake sequence (parallel bus command write):

  1. Set PZ = data byte
  2. Set P7.6 = 1 (command mode) or 0 (data mode)
  3. Assert CS1 (P7.5 low)
  4. Assert write strobe (P7.3 low)
  5. Wait for PH.0 ready
  6. Deassert write/CS

DSP2 serial protocol (GPIO bit-bang):

DSP2 uses a different interface from DSP1. Instead of the parallel bus, it uses GPIO bit-bang serial on Port F:

Pin Function
PF.0 SDA — Serial data to DSP2
PF.2 SCLK — Serial clock to DSP2
PE.6 CS2 — Chip select (active low)

Each byte is transmitted MSB-first with one CS assert/deassert cycle per byte. Both DSP2_Send_Command and DSP2_Send_Data produce 9 SCLK rising edges per byte (8 data bits + 1 trailing). The command variant adds an extra ClockPulseHigh before the bit loop, but this doesn’t create an additional rising edge because the first bit loop iteration’s SCLK-high is absorbed (SCLK already high from the pulse).

Command byte: CS↓ → ClkHigh → [SDA=bit7, CLK↑(absorbed), CLK↓] → [SDA=bit6, CLK↑, CLK↓] × 7 → trailing CLK↑ → CS↑
Data byte:    CS↓ → [SDA=bit7, CLK↑, CLK↓] × 8 → trailing CLK↑ → CS↑

Transaction boundaries are marked by DSP2_SPI_BusIdle (PF.0=0, PF.2=0), called by bytecode Op0D between command groups.

Register writes use CMD 0x30 followed by 4-byte data groups: [0x00, addr, val_hi, val_lo]. Boot-time writes observed: REG[0xD0]=0x0000, REG[0xD3]=0x0000, REG[0x3C]=0x4000.

DSP Firmware / Microcode Loading

The DSP chips do NOT receive external microcode from the Sub CPU. Investigation of the SubCPU firmware reveals that no large code blocks are ever uploaded to the DSPs. Instead:

  1. DSPs are pre-programmed at manufacture — The MN19413 (IC310) and DS3613GF-3BA (IC311) contain internal ROM with their instruction set already loaded. They are dedicated effects processors with a fixed command interface, not general-purpose programmable DSPs.

  2. Sub CPU controls DSPs via register writes only — All communication uses the 8-bit parallel bus handshake protocol (Port PZ data, Port P7 control lines). The Sub CPU sends:
    • Command bytes (P7.6=1): Select DSP register or operation mode
    • Data bytes (P7.6=0): Write parameter values to selected register
  3. Configuration via bytecode interpreter — The Sub CPU has a bytecode interpreter (DSP_BytecodeInterpreter_Init at 0x03C266) that reads compact bytecode programs from ROM and translates them into sequences of DSP command+data writes. This is a Sub CPU-side interpreter, not DSP microcode.

Evidence: The DSP_WriteEFFConfig and DSP_WriteGlobalConfig routines both call DSP_BytecodeInterpreter_Init with ROM pointers to bytecode tables (at 0x14777 for EFF configs, 0x147B3 for global configs). These tables contain opcodes like:

  • 0x0-0x4: DSP register write operations
  • 0x0D: State change notification
  • 0x0E: Send command+data sequence
  • 0x0F: End of program

Implication for emulation: The DSP chips must be emulated with their internal behavior intact. Since no dumps of the DSP internal ROMs exist, the DSP behavior must be reverse-engineered from the register interface (what the SubCPU writes) and the resulting audio output. This is the primary remaining challenge for accurate sound emulation.

DSP Preset Structure

The 0x91-word (290-byte) block at SubCPU RAM address 0xF01E contains effect parameter presets, not DSP microcode. The structure is:

Offset Size Content
+0x00 20 words Header / global effect config
+0x28 5 × ~24 words Effect parameter blocks

Each effect block contains parameters:

  • Type (effect algorithm selector: 1, 3, 4, 8)
  • Level (0-99)
  • Depth (0-99)
  • Time (0-99)
  • Rate (0-99)
  • Mix (dry/wet balance, 0-99)
  • Feedback (0-99)

Effect Type Name Table

The Main CPU ROM contains a 128-entry effect type name table at address 0xE32A7A (pointer table) with 16-character padded strings at 0xE32C7A-0xE33579. 100 entries are named; the rest are unused (----------).

Modulation Effects (0-6):

Index Name
0 NO OPERATION
1 CHORUS
2 MODULATED CHORUS
3 ENHANCER
4 FLANGER
5 PHASER
6 ENSEMBLE

Delay & Gated Effects (8-11):

Index Name
8 GATED REVERB
9 SINGLE DELAY
10 MULTI TAP DELAY
11 MODULATION DELAY

Reverbs (15-27):

Index Name
15 ROCK ROTARY
16 ROOM REVERB 1
17 ROOM REVERB 2
18 PLATE REVERB 1
19 PLATE REVERB 2
20 CONCERT REVERB 1
21 CONCERT REVERB 2
22 DARK REVERB 1
23 DARK REVERB 2
24 BRIGHT REVERB 1
25 BRIGHT REVERB 2
26 WAVE REVERB 1
27 WAVE REVERB 2

Drive & Dynamics (32-39):

Index Name
32 DISTORTION
33 OVERDRIVE
34 FUZZ
35 EXCITER
36 COMPRESSOR
37 SLOW ATTACKER
38 NOISE FLANGER
39 PARAMETRIC EQ

Special Effects (44-60, 63):

Index Name
44 CEL
45 CELM
48 AUTO PAN
49 PITCH SHIFTER
50 VIBRATO
51 PEDAL WAH
52 AUTO WAH
53 ROTARY SPEAKER
54 RING MODULATOR
55 HARS EFFECT
56 MIX UP
57 STANDARD
58 PERCUSSIVE
59 SYMPHONIC
60 DEEP SPACE
63 STRING

Combination Effects (64-75, 79-81, 88-91, 96-99):

Index Name
64 S.DELAY+CHORUS
65 S.DELAY+S.DELAY
66 S.DELAY+FLANGER
67 S.DELAY+VIBRATO
68 S.DELAY+PHASER
69 PEDAL WAH+DELAY
70 AUTO WAH+S.DELAY
71 PEQ+CHORUS
72 PEQ+S.DELAY
73 PEQ+FLANGER
74 PEQ+VIBRATO
75 PEQ+COMPRESSOR
79 GEQ
80 DS_D
81 OVER_D
88 ROOM
89 KARAOKE
90 BATH ROOM
91 STAGE
96 PEQ+COMPR+DIST
97 PEQ+COMPR+OVERDR
98 PEQ+DIST+DELAY
99 PEQ+OVERDR+DELAY

Effect Parameter Names

84 effect parameter names are stored at Main CPU ROM 0xE324D0-0xE32A6A:

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

Known DSP Commands

These are the hardware command bytes sent to the DSP chips via the parallel bus (P7.6=1 for command, P7.6=0 for subsequent data). They are sent by bytecode opcode 0xE and by direct calls to DSP_DispatchCommand/DSP_DispatchData.

Command Direction Via Description
0x01 Write OP3 (16-bit) Bulk initialization — uploads full DSP state (150-350 data bytes). Used for EFF header (302B), reverb (272B), chorus (352B), algorithm init (117B).
0x03 Write OP4 (cmd only) Algorithm select — sent before coefficient data blocks (OP1/OP2). No data bytes.
0x0F Write OP4 (cmd only) Disable/flush — sent during algorithm init cleanup. No data bytes.
0x10 Write OP4 (cmd only) Enable/start — sent during algorithm init sequence. No data bytes.
0x30 Write SEND_CMD (0xE) Parameter write — sub-addressed, large data blocks (up to 190 bytes). Format: 0x30 [sub_addr] [data...]. Sub-addresses 0x00, 0x03, 0x05, 0x0D seen.
0x60 Write OP0 Bulk transfer — used in standard parameter write sequences via opcode 0 handler.

Algorithm Configuration Sequence (from DSP_AlgorithmChange):

The complete algorithm change writes 8 bytecode programs to the DSPs in order:

1. AlgoChange_Init (0x01E63C):
   - OP3: cmd=0x01, 117 bytes (16-bit packed DSP state init)
   - OP4: cmd=0x10 (enable)
   - OP4: cmd=0x10 (enable again)
   - OP4: cmd=0x0F (flush)

2. AlgoChange_Ch0 (0x01E6BE):
   - OP0: cmd=0x01, 23 bytes (12-bit packed init)
   - OP4: cmd=0x03 (select algorithm)
   - OP1: 8 bytes (algorithm header)
   - OP2: 93 bytes (coefficient data block 1)
   - OP4: cmd=0x03 (select algorithm)
   - OP1: 8 bytes (algorithm header 2)
   - OP2: 93 bytes (coefficient data block 2)

3-8. AlgoChange_Ch1 (4 programs with delay):
   - SEND_CMD: cmd=0x30 sub=0x03 + 2 data bytes (mode select)
   - STATE_CHANGE (yield to scheduler)
   - SEND_CMD: cmd=0x30 sub=0x05 + 100-189 data bytes (coefficients)
   - SEND_CMD: cmd=0x30 sub=0x00 + variable data (parameters)
   - SEND_CMD: cmd=0x30 sub=0x0D + variable data (delay line config)

Parameter Data Formats:

Reverb and chorus configs share a common 28-byte header (first 14 word pairs) starting with 0x00C8 0x0880 0x1300 0x0B00 0x0028 0x9415 0x0212..., suggesting a common DSP state initialization structure where effect-specific parameters follow.

The DSP_DispatchCommand function (0x036454) routes commands to DSP1 (DSP_Send_Command) or DSP2 (DSP2_Send_Command) based on the chip number in BC. Both use the same handshake protocol: poll PH.0 for ready, then write via Port PZ with appropriate chip-select and command/data strobes.

DSP Boot Sequence (MAME Dynamic Trace)

The following sequence was captured from MAME emulation during the first 60 seconds of boot. All DSP1 activity occurs via the parallel port (CMD 0x01); no CMD 0x30 register writes target DSP1 during boot (DSP2 receives CMD 0x30 writes for addr 0xD0, 0xD3, 0xF6, 0x3C).

Phase 1 — Hardware Init:
  DSP2: REG WRITE addr=0xD0 value=0x0000
  DSP2: REG WRITE addr=0xD3 value=0x0000
  DSP1: INIT CONFIG [0xFB 0xDA 0x3F 0xA0 0x1A]  (CMD 0x04, 5 bytes)
  DSP1: STATUS/MODE value=0x003C                  (CMD 0x09)
  DSP1: CONTROL [0x00 0x55 0x55]                  (CMD 0x0C)

Phase 2 — DSP Program Loading (CMD 0x01, bytecode):
  DSP1: PROGRAM module=0x3C (117 bytes)   — AlgoChange_Init bytecode
  DSP1: RESET × 2, SYNC
  DSP1: coefficient clear (ch1, @0x06/@0x86 = 0)
  DSP1: COEFF UPLOAD @0x50 (92 bytes) — lookup table A
  DSP1: COEFF UPLOAD @0x6E (92 bytes) — lookup table B
  DSP1: COEFF UPLOAD @0x8C (2 bytes)  — table terminator

Phase 3 — DSP2 Enable:
  DSP2: REG WRITE addr=0xD0 value=0x4000
  DSP2: REG WRITE addr=0xF6 value=0x4FB0

Phase 4 — Effect Configuration:
  DSP1: PROGRAM module=0x00 (302 bytes) — EFF header (main program)
  DSP1: PROGRAM module=0x47 (7 bytes)   — config patch A
  DSP1: PROGRAM module=0x40 (7 bytes)   — config patch B
  DSP1: second INIT CONFIG [0xFB 0xDA 0x00 0xA0 0x1A]
  DSP2: REG WRITE addr=0x3C value=0x4000
  DSP1: second STATUS/MODE value=0x003C

Phase 5 — Effect Algorithm Loading:
  DSP1: PROGRAM module=0x00 (302 bytes) — EFF header (repeated)
  DSP1: PROGRAM module=0x47 (7 bytes)
  DSP1: PROGRAM module=0xC8 (667 bytes) — reverb algorithm bytecode
    → Heavy coefficient upload: 30 blocks, many with 4-coeff groups
    → Addresses: @0xD0, @0x85, @0x94, @0x87, @0x8A (init zeros)
    → then @0x00-0x3D (26 coefficient pairs — delay line taps)
    → @0x1E (master reverb level = 32767 = 0x7FFF)
    → @0x90, @0xAE (lookup tables)
    → @0x97, @0x9E-0xB2 (reverb tail coefficients)
    → @0x1D-0x3D (groups of 4: all-pass filter stages × 8)
    → @0x90 (final gain = 103268)
  DSP1: PROGRAM module=0x00 (302 bytes) — third EFF header
  DSP1: PROGRAM module=0x40 (7 bytes)
  DSP1: PROGRAM module=0x54 (352 bytes) — chorus/modulation algorithm
    → Coefficient upload: @0x07-0x0E (zeros), @0x26 (10 delay params)
    → @0x00 table upload (62 bytes), @0x09/@0x0A (LFO rates)
    → @0x1D-0x3D (all-pass stages × 4)

Phase 6 — Final Configuration:
  DSP1: PROGRAM module=0x47 (7 bytes)   — updated config patch
  DSP1: PROGRAM module=0x40 (7 bytes)   — updated config patch
  DSP1: coefficient write @0x06 = 0, @0x86 = 101643 (dry/wet mix)
  DSP1: Memory-mapped register writes: ch0-ch3 param[0-7] = 0
  DSP1: ch0-ch3 config = 0x01 (enable all channels)

Key findings from dynamic trace:

  • The default boot effect is reverb on channel 1 with coefficients loaded at DSP internal addresses 0x00-0xB2
  • All coefficient uploads target channel 1 (base 0x60); channels 0, 2, 3 receive only parameter clears
  • The coefficient data structure matches a late-reflection reverb: 8 all-pass filter stages (addresses 0x1D-0x3D in groups of 4), 26 delay line taps (0x00+ sequence), and lookup tables (0x90, 0xAE)
  • DSP program module indices: 0x00=EFF header, 0x3C=init, 0x40/0x47=patches, 0x54=chorus, 0xC8=reverb
  • The INIT CONFIG byte[2] changes from 0x3F (init mode) to 0x00 (run mode) between phases

DSP2 Register Map (CMD 0x30 Writes)

The MN19413 (DSP2) receives register writes via CMD 0x30 + 4-byte groups [0x00, addr, val_hi, val_lo]. During the first 60 seconds of boot, 679 writes target 112 unique register addresses across the full 0x00-0xFF range.

Initialization Registers (written first):

Order Address Value Function
1 0xD0 0x0000 Reset/control (cleared on init)
2 0xD3 0x0000 Reset/control (cleared on init)
3 0xD0 0x4000 Enable (set during Phase 3)
4 0x3C 0x4000 Master enable (set during Phase 4)

REG[0xD0] and REG[0xD3] are cleared first, then 0xD0 is set to 0x4000 to enable the DSP. REG[0x3C] = 0x4000 appears to be a master configuration enable.

Channel Registers (stride 0x10, offset 0x_8 — 16 channels):

All 16 addresses at offset 0x_8 (0x08, 0x18, 0x28, … 0xF8) are written during boot. Initial values suggest delay line tap positions:

Channel Address Init Value Final Value Writes
0 0x08 0x02F6 0x02F6 1
1 0x18 0x3FC0 0x860C 3
2 0x28 0x2FD0 0x0014 3
3 0x38 0x1FE0 0x0093 9
4 0x48 0x0FF0 0x0FF0 1
5 0x58 0x0093 0x0093 1
6 0x68 0x4510 0x4510 1
7 0x78 0x00E3 0x8001 5
8 0x88 0x2530 0x0203 15
9 0x98 0x1540 0x1540 1
10 0xA8 0x8092 0x0077 3
11 0xB8 0x4A60 0xCC18 3
12 0xC8 0x3A70 0x3A70 1
13 0xD8 0x8002 0x2A80 3
14 0xE8 0x0000 0x1A90 2
15 0xF8 0x0AA0 0xD230 2

High-Traffic Registers (control/routing):

Address Writes Unique Values Function Hypothesis
0x40 107 32 Primary control/routing register
0x00 87 47 Secondary control/routing register
0x80 86 26 Tertiary control/routing register
0x89 29 4 Effect parameter A
0xA9 29 9 Effect parameter B
0x02 26 11 Algorithm/mode selector
0x81 17 4 Effect parameter C
0xA1 16 2 Effect parameter D
0x88 15 3 Channel 8 config (also 0x_8 family)
0x04 13 8 Configuration register
0x42 11 8 Routing configuration

REG[0x00], REG[0x40], and REG[0x80] are the most-written addresses, each receiving 80+ writes with dozens of unique values. These likely serve as command/data ports for a secondary register-indirect interface within the DSP.

Coefficient Registers (monotonically incrementing):

Address Values Range Avg Step
0xE6 7 0x7C13 - 0x7CCD 31.0
0xE7 8 0x7405 - 0x74E7 32.3

These registers receive steadily increasing values, consistent with filter coefficient ramp tables or LFO modulation parameters.

Common Value Patterns:

Value Registers Hit Possible Meaning
0x8002 18 registers Enable flag (type 2)
0x8001 12 registers Enable flag (type 1)
0x0093 9 registers Bypass/mute or default coefficient
0xD003 6 registers Routing/connection descriptor
0x4000 13 registers Master enable or half-scale coefficient
0x0203 6 registers Status/mode flag

The pattern of 0x80xx values written to many registers suggests a register format where bit 15 is an enable/valid flag and the lower bits encode type or parameter data.

DSP Effect Types and Algorithm Mapping

The KN5000 supports 40 effect slots (indices 0-39), mapped to 12 DSP algorithm types (0-11) via a lookup table at SubCPU ROM address 0x01F596. The algorithm type determines which DSP program module and coefficient set gets uploaded to DSP1.

Effect List and Algorithm Types:

Index Effect Name Algo Index Effect Name Algo
0 NO OPERATION 2 20 CONCERT REVERB 1 6
1 CHORUS 2 21 CONCERT REVERB 2 6
2 MODULATED CHORUS 2 22 DARK REVERB 1 7
3 ENHANCER 2 23 DARK REVERB 2 7
4 FLANGER 2 24 BRIGHT REVERB 1 7
5 PHASER 2 25 BRIGHT REVERB 2 7
6 ENSEMBLE 2 26 WAVE REVERB 1 8
7 (reserved) 2 27 WAVE REVERB 2 8
8 GATED REVERB 3 28-29 (reserved) 8-9
9 SINGLE DELAY 3 30-31 (reserved) 9
10 MULTI TAP DELAY 3 32 DISTORTION 9
11 MODULATION DELAY 4 33 OVERDRIVE 10
12-14 (reserved) 4 34 FUZZ 10
15 ROCK ROTARY 5 35 EXCITER 10
16 ROOM REVERB 1 5 36 COMPRESSOR 10
17 ROOM REVERB 2 5 37 SLOW ATTACKER 11
18 PLATE REVERB 1 5 38 NOISE FLANGER 11
19 PLATE REVERB 2 6 39 PARAMETRIC EQ 11

Algorithm Type Groups:

Algo Category Effects
2 Modulation NO OPERATION, CHORUS, MOD CHORUS, ENHANCER, FLANGER, PHASER, ENSEMBLE
3 Delay/Gate GATED REVERB, SINGLE DELAY, MULTI TAP DELAY
4 Mod Delay MODULATION DELAY
5 Reverb A ROCK ROTARY, ROOM REVERB 1/2, PLATE REVERB 1
6 Reverb B PLATE REVERB 2, CONCERT REVERB 1/2
7 Reverb C DARK REVERB 1/2, BRIGHT REVERB 1/2
8 Reverb D WAVE REVERB 1/2
9 Distortion A DISTORTION
10 Distortion B OVERDRIVE, FUZZ, EXCITER, COMPRESSOR
11 Dynamics SLOW ATTACKER, NOISE FLANGER, PARAMETRIC EQ

Algo types 0 and 1 are not used by any effect and appear to be reserved for internal routing.

Effect Parameter Names (stored at MainCPU 0xE324C4, colon-delimited 16-char fields):

Each effect has up to 8 adjustable parameters selected from a shared pool of 52 parameter names. Key parameters include: VOLUME, DEPTH, LFO SPEED, RESONANCE, MANUAL, REVERB TIME, PRE DELAY, HIGH DAMP GAIN, ER.LEVEL, FEEDBACK L/R, DELAY L/R, THRESHOLD, RATIO, ATTACK/RELEASE SENS/RATE, GATE TIME.

Algorithm Selection Mechanism:

The MainCPU sends the effect index (0-39) to the SubCPU via Audio_SendCommand (cmd 0x4D8C, category 0xE3). The SubCPU’s DSP_Cmd2B_AlgoSelect handler (sub-command 0x00) receives this index, looks up the algorithm type from the ROM table at 0x01F596, initializes the voice structure (287 bytes per slot, base 0x041368, stride 0x11F), then uploads the appropriate DSP program modules and coefficient data to DSP1.

The algo type is stored at offset 0x5D of the voice structure. The full byte encodes both the algo type (lower nibble) and additional routing state (upper nibble). For example, 0x93 = algo type 3 with upper state 9, 0x25 = algo type 5 with upper state 2.

The SubCPU maintains up to 26 voice slots. At boot, the default configuration loads reverb-type effects (algo types 3 and 5) on several slots, with DSP program modules 0xC8 (reverb) and 0x54 (chorus) uploaded to DSP1.

Effect Name Table: MainCPU ROM address 0xE32A7A contains 40 pointers to 16-character fixed-width effect name strings (padded with spaces).

DSP1 Internal Address Map

The DSP1 coefficient address space is organized by algorithm type. Each coefficient is a 17-bit value encoded as ((B4>>7)&1) | (B3<<1) | (B2<<9). Addresses are per-channel (channel base: 0x40=ch0, 0x60=ch1, 0x80=ch2, 0xA0=ch3).

Reverb Algorithm (module 0xC8, 667 bytes):

Address Function Boot Default
@0x00 Delay line tap array (26 pairs = 52 coefficients) 33268, 0, 41925, 32768, …
@0x06 Dry signal level 0 (muted)
@0x1D-0x3D All-pass filter bank (8 stages × 4 coefficients each) Stage-specific values
@0x1E Master reverb level 32767 (0x7FFF = maximum)
@0x85-0x8A Init registers 0 (cleared)
@0x86 Wet (reverb) output level 101643
@0x90 Output gain 103268
@0x94 Init register 0 (cleared)
@0x97 Reverb tail feedback coefficient 63251
@0x9E Reverb tail filter coefficients (4 blocks) 65566, 119222, 31803, 16916
@0xB2 Reverb tail final coefficient 51634
@0xD0 Init block 0 (cleared)

Chorus/Modulation Algorithm (module 0x54, 352 bytes):

Address Function Boot Default
@0x00 LFO waveform table (62 bytes via CMD 0x02) Sine/triangle LUT
@0x05-0x10 Init registers 0 (cleared)
@0x09 LFO rate A
@0x0A LFO rate B / depth
@0x1D-0x29 All-pass filter bank (4 stages × 4 coefficients) Stage-specific
@0x26 Delay parameters (10 coefficients) 400, 4161, …

Hypothesized Parameter ↔ DSP Address Mapping:

UI Parameter DSP Address(es) Notes
REVERB TIME @0x1D-0x3D All-pass filter coefficients control decay time
PRE DELAY @0x00 array Delay line tap positions set initial reflection gap
HIGH DAMP GAIN @0x9E Tail filter coefficients control high-frequency damping
ER.LEVEL @0x1E or @0x90 Early reflection / output gain level
DRY/WET @0x06 / @0x86 Dry = 0 (muted), Wet = 101643 (full reverb)
LFO SPEED @0x09, @0x0A Chorus LFO rate registers
DEPTH @0x26 Chorus delay modulation depth

DSP Voice Structure Layout

The SubCPU maintains 26 voice/effect slots starting at DRAM 0x041368, stride 0x11F (287 bytes). Each slot controls one DSP effect instance. Structure fields discovered through MAME dynamic analysis:

Offset Size Field Description
+0x00 2 flags Voice configuration flags
+0x06 3 rom_ptr ROM data pointer (24-bit)
+0x0E 2 config Configuration word
+0x13 1 unknown Always 0x02 in active slots
+0x18 1 algo_related Value matches algo type (5 for reverb)
+0x19 1 param_a First effect parameter (e.g., REVERB TIME=26, GATED=6)
+0x1A 1 param_b Second parameter (usually 0)
+0x1B 1 param_c Third parameter (default 64 = 0x40)
+0x1C 1 param_d Fourth parameter (default 64 = 0x40)
+0x1D-0x20 4 params_e-h Parameters 5-8 (usually 0)
+0x21 1 enable Enable flag (1 = active)
+0x57 1 routing Routing state (matches upper nibble of algo byte)
+0x5D 1 algo_byte Algorithm: lower nibble = type (2-11), upper nibble = routing
+0x5E 1 effect_idx Effect index (0-39, maps to algo type via ROM table at 0x01F596)
+0x6E-0x70 3 cfg_ptr_1 Configuration data pointer 1
+0x71-0x86   algo_data_1 Algorithm-specific coefficient data block 1
+0x87 1 block_flags Flags between data blocks
+0x90-0xB3   algo_data_2 Algorithm-specific coefficient data block 2
+0xB4-0xD0   algo_data_3 Algorithm-specific coefficient data block 3
+0xD1-0x100   algo_data_4 Algorithm-specific coefficient data block 4

Boot-time default voice slots (MAME 60s trace):

Slot Algo Type Routing param_a Description
2 3 (delay/gate) 9 6 Gated reverb default
16 5 (reverb A) 2 26 Room reverb 1
17 5 (reverb A) 2 29 Room reverb 1 (alt params)
18 3 (delay/gate) 9 6 Gated reverb (duplicate of slot 2)
21 3 (delay/gate) 9 6 Gated reverb (duplicate of slot 2)

Effect Routing Configuration

The routing config table at SubCPU DRAM 0x00F490 (40 bytes) assigns each effect index to a routing group. This controls how the effect is connected in the audio signal chain.

Routing Effects Group Name
0 9, 11-14, 16-28 Direct (no routing modifier)
1 0-3, 12-15, 29 Modulation group A
2 4-7, 30 Modulation group B
3 8, 10, 31 Delay/reverb group
4-11 32-39 Per-distortion/dynamics (one routing per effect)

Note: Effects 32-39 (distortion, overdrive, fuzz, exciter, compressor, slow attacker, noise flanger, parametric EQ) each have unique routing values 4-11, suggesting they require individual signal path configuration.

Keybed Architecture

The physical keyboard (keybed) connects directly to the tone generator IC303, NOT to the Sub CPU. IC303 performs hardware key scanning internally and presents note events to the Sub CPU via the keyboard input interface at 0x110000.

This means:

  • The CPU does not scan the keyboard matrix
  • IC303 handles debouncing, velocity detection, and polyphony assignment
  • The Sub CPU simply reads completed note events from IC303’s output register

See Keybed Scanning for the complete note flow, encoding format, and voice slot management.

MAME Emulation Status

The MAME driver (kn5000.cpp) includes device classes for the audio chips. The tone generator produces basic audio output (waveform playback from ROM). The DSP devices are register stubs that accept firmware writes without crashing. No DSP audio processing is emulated — the DSP internal ROMs have not been dumped.

Audio Chip Device Classes

Device Chip IC Interface MAME Class Status
Tone Generator TC183C230002 IC303 Memory-mapped (0x100000) kn5000_tonegen_device 64-voice PCM with pitch/pan/volume, keybed input, voice status readback
DSP1 DS3613GF-3BA IC311 Memory-mapped (0x130000) kn5000_dsp1_device Register stub: 4 channels × 0x20 registers, accepts writes
DSP2 MN19413 IC310 Serial (GPIO bit-bang) (port callbacks) Not yet a separate device; serial protocol handled by SubCPU GPIO

Tone Generator (kn5000_tonegen_device):

  • Register-indirect config interface (address port + data port)
  • 64-voice PCM wavetable playback at 48kHz from waveform ROMs (IC304-IC307)
  • Pitch scaling: semitone ratio (reg[1]) with octave shift (reg[8])
  • Stereo pan: left/right from group 8 regs (reg[21]/reg[22]), range 0-0x78
  • Waveform selection from reg[3] (waveform control register)
  • KEY ON (0x8100) / KEY OFF (0x7E00) voice management with per-voice hold timer (2s)
  • Voice status readback: reports KEY ON while hold timer active
  • Keyboard input interface with push_keybed_event() for MAME input port integration

DSP1 (kn5000_dsp1_device):

  • 4 channels × 0x20-byte register space (channel base = N × 0x20 + 0x10)
  • Register-indirect interface: address latch at 0x130000, data at 0x130002
  • Accepts firmware register writes; no audio processing (internal ROM not dumped)

DSP2 (MN19413 — not yet a MAME device):

  • Serial interface via SubCPU GPIO (Port PF bit 0 = SDA, bit 2 = SCLK, PE.6 = CS)
  • 9-bit serial transactions (MSB-first), bit-bang protocol
  • CMD 0x30 register writes: 4-byte groups [0x00, addr, val_hi, val_lo]
  • Boot writes: REG[0xD0]=0, REG[0xD3]=0, REG[0x3C]=0x4000
  • Future work: create separate device class for serial protocol decoding

Key Emulation Challenges

  1. No DSP internal ROM dumps — Both DSP chips contain internal ROM with their effects algorithms. Without dumps, audio processing cannot be accurately emulated.
  2. Tone generator wavetable ROM — IC303 contains internal wavetable samples. Without a dump, synthesized audio output is not possible.
  3. Serial port 1 protocol — The ~500kHz UART connection between SubCPU and the DAC/DSP control path is not yet fully decoded.

What Works Now

  • SubCPU firmware loads and executes (192KB payload transfer via HDMA)
  • All inter-CPU audio commands (0x2D DSP config, 0x2B sound name query, etc.) are dispatched correctly
  • DSP state dispatcher runs all 11 sub-routines, generating complete register write sequences
  • Effect configurations flow from MainCPU → SubCPU → DSP device stubs
  • Keybed input from MAME input ports reaches the tone generator device
  • SubCPU Serial Port 1 (Computer Interface) wired with UART byte decoder and logging
  • Feature Demo sends CC/pitch/sysex configuration commands correctly (2,625 commands observed)

Known Issues

  • Feature Demo timing — The SSF presentation runs too fast because Seq_IsMelodyActive sees voices as inactive almost immediately after KEY OFF. Root cause: the tone generator HLE’s release envelope completes in ~125ms. Fix: a 2-second hold timer was added per voice so firmware status queries still see voices as active, matching the real hardware’s longer envelope times. Needs MAME testing to verify.
  • No DSP effects audio — DSP device classes are logging stubs with register tracking. Tone generator produces sine wave output but no effects processing (reverb, chorus, etc.).

Research Needed

  • Document waveform ROM format and sample layout – Complete: IC307 analyzed. 198-entry index table, 186 unique signed 16-bit PCM waveforms, x16 byte offset addressing, key zone parameter records. See Waveform ROM Format
  • Decode per-algorithm parameter mapping tables at 0x1F22C/0x1F09C — Complete: both are 12-entry pointer tables (indexed by algo type 0-11) pointing to variable-length bytecode programs with opcodes 0x21/0x24/0x40/0x61-0x78, terminated by 0x7A/0xF0
  • Map MainCPU parameter indices to EFF block word positions — Partial: 84 named parameters extracted from MainCPU 0xE324C4. DSP2 master list at 0xE4475C maps 14 SubCPU param indices to UI names. Final register-to-parameter mapping requires runtime bytecode tracing
  • Decode DSP register semantics per channel — Partial: DSP2 112-register map from boot-time analysis (stride-0x10 channel regs at offset 0x_8, control regs 0x00/0x40/0x80, coefficient regs 0xE6/0xE7). DSP1 channel regs 0x10-0x17 still need semantic mapping.
  • Document remaining inter-CPU command types (beyond 0x2D and 0xE1/E2/E3)
  • Investigate why song engine never writes MIDI events to ring buffer (putc_mrx has zero hits) — may be resolved by voice hold timer fix
  • Determine what sets the startup flag at 0x0251D8 on real hardware
  • Trace the path from rhythm ROM pattern data to ring buffer write calls — partially addressed by Feature Demo analysis
  • Decode voice parameter template at ROM 0xF8D5 (34 words — which map to pitch, waveform select, envelope mode, etc.)
  • Investigate why Feature Demo sequencer never reaches Note On events — Ring buffer at 0x01F37B is never written; sequencer dispatcher and rhythm ROM reading work correctly but event generation stage never fires
  • Identify the timing mechanism or subcpu response that advances the sequencer — Partially resolved: Timer7, state machine, and dispatcher pipeline traced; the issue is in the song engine output stage, not the input/timing stage
  • Identify exact device on Serial Port 1 — Computer Interface (TO HOST connector), sends 0xFE Active Sensing
  • Analyze DSP1/DSP2 command sets — Partial: 4 commands identified, preset structure decoded
  • Extract effect type names from ROM — Complete: 100 named effect types at MainCPU 0xE32A7A
  • Extract effect parameter names from ROM — Complete: 84 parameter names at MainCPU 0xE324D0
  • Document DSP state dispatcher architecture — Complete: DSP_State_Dispatcher and 11 sub-routines traced
  • Trace inter-CPU command 0x2D protocol — Complete: 4-layer protocol fully documented
  • Map effect type indices to DSP register configurations — Partial: translation chain traced through DSP_WriteParameterDSP_ParameterWriteEngine, but per-algorithm ROM tables not yet decoded
  • Determine if DSP microcode is loaded from ROMNo. DSPs are pre-programmed; SubCPU only writes configuration via bytecode interpreter
  • Map remaining proprietary CC handlers (0x97-0x9D) — Complete: CC91=freq mult, CC95=portamento, CC97=fine pitch, CC9B=vibrato depth, CC9C=vibrato enable, CC9D=tremolo depth
  • Decode tone generator register semantics — Partial: voice control state machine, key-on/off flags, volume/level groups, latched parameter updates documented; pitch/envelope/filter register mapping still needs work
  • Document synthesis architecture — Complete: 64-voice wavetable, 26 MIDI channels, dynamic voice allocation, hardware ADSR, LFO modes, proprietary CCs
  • Reverse-engineer DSP register semantics by runtime bytecode tracing — static analysis decoded all table structures (7 ROM tables, 47 unique parameter programs, 100 algorithm entries) but actual register addresses are embedded in variable-length bytecode and require interpreter execution to extract
  • Analyze native code handlers within DSP_Bytecode_ProgramsFully decoded (1,613 bytes → 6 handlers). Op0/5: complex 5-byte groups with 3-way branching (static/raw/parameter-modified coefficients). Op1: 5-byte groups with 12-bit address. Op2: 3-byte raw groups. Op3: 16-bit address + raw tail. Op4: command-only. Key finding: Handlers 0/5 Branch C implement real-time parameter control by mixing a 32-bit runtime parameter into template coefficient data during DSP writes.
  • Determine if DSP internal ROM can be extracted (decapping, JTAG, etc.)
  • Document bytecode interpreter opcode set completely (opcodes 0x0-0xF) — Complete: 2-byte header format, opcodes 0-5 (native code dispatch), 0xD (yield), 0xE (send command+data), 0xF (end). Config entries are 12 bytes (4 words + 1 pointer). Handlers at DSP_Bytecode_Programs (0x3C32E) are native TLCS-900 subroutines.