Auto Wah — HLE + bytecode
Auto Wah — HLE reconstruction and DSP bytecode
DSPHLE selector 0x12 · program image prog52_auto_wah · Preview (topology decoded and reconstructed; most panel→cell role mappings are position-decoded).
envelope-swept resonant filter (no LFO); biquad cells 0x00-0x06. Roles SPECULATIVE.
This page pairs the bytecode the effect runs on the NEC µPD6383GF with the high-level reconstruction that makes it audible in MAME. The reconstruction is not the chip’s microcode — it is a textbook DSP block built from the decoded meaning of that microcode, and reading the two together is how the bytecode is understood (and, in time, driven toward a faithful low-level emulation). See also the signal-flow flowchart.
The bytecode below is the source of truth; the HLE reconstruction is not. The HLE is our best current interpretation and may contain mistakes — where the two disagree, the bytecode wins, and a better HLE should be updated here. This page is the permanent archive of the reference HLE: it is kept here even after the code is eventually removed from the MAME sources.
DSP bytecode (reverse-engineered microprogram)
The disassembled image the chip executes for this effect. Source (regenerable):
dsp/disasm/prog52_auto_wah.dsm.
; Reverse-engineered disassembly of the KN5000 effects-DSP microcode
; (NEC uPD6383GF), recovered from the original firmware. The microcode is the
; work of its original authors; this is a disassembly for preservation and
; interoperability, and no claim of copyright is made over the disassembled program.
; KN5000 effects-DSP program -- AUTO WAH
; image rep algo 52 | slots 52 | unit 0 (I-RAM load 84)
; family filter | confidence medium | 72 words, 13 class-A multiplies (6 named)
; role: auto wah: envelope-swept resonator
; coefficient cursor base 0x00
;
; GENERATED by dsp/tools/gen_dsp_disasm.py -- DO NOT EDIT.
; Put labels/comments in the matching dsp/sym/*.sym; analysis in dsp/algorithms/.
w0 000020B1CD ld (p),(p)+11
w1 000020340E ld acc,(p)+3
w2 02122FD407 mac.st acc,(p)-3 ; mem[p]<-acc, acc=0
w3 002A200000 ?word 0x002A200000 ; 02A.2.00.000 hi12{f31=5 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w4 0022200000 mac.b (p)0,(p)+0
w5 0880130000 dly.r dsc[k],p+48
w6 0000200413 ld.ta acc,(p)+0
w7 00002401CD ld (p),(p)+64
w8 01122031CE mac (p),(p)+3 ; mem[p]<-acc, acc=0
w9 01042001CE post (p),(p)+0
w10 02022FF1D5 mac (p),(p)-1
w11 0102ABF1D4 mac.tb (p),c+,(p)-65
; C-RAM[0x00] (coeff, base 0x00 MEASURED)
w12 02042421CD post (p),(p)+66
w13 02042FE687 post.st tb,(p)-2
w14 08048161DA ?word 0x08048161DA ; 804.8.16.1DA hi12{ESC f31=2} cur [class 8: post-sum step (rescale/round/saturate?), OPERATION UNKNOWN]
w15 00002FF647 ld.st ta,(p)-1
w16 0000202687 ld.st tb,(p)+2
w17 00002BC407 ld.st acc,(p)-68
w18 0024200000 post.b (p)0,(p)+0
w19 0000205407 ld.st acc,(p)+5
w20 0010AFC1D5 ld (p),c+,(p)-4 ; mem[p]<-acc, acc=0
; C-RAM[0x01] (coeff, base 0x00 MEASURED)
w21 0202A031D5 mac (p),c+,(p)+3
; C-RAM[0x02] (coeff, base 0x00 MEASURED)
w22 0202200000 mac.b (p)0,(p)+0
w23 002A200000 ?word 0x002A200000 ; 02A.2.00.000 hi12{f31=5 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w24 0026200000 ?word 0x0026200000 ; 026.2.00.000 hi12{f31=3 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w25 0018A001D5 ?word 0x0018A001D5 ; 018.A.00.1D5 hi12{ST f31=4} cur+ [SPECULATIVE: class-A multiply (P = coef x source 0x07); the source id / accumulator-combine f31=4 / ACT 0x15 may be OPEN]
; C-RAM[0x03] (coeff, base 0x00 MEASURED)
w26 0104A001D5 post (p),c+,(p)+0
; C-RAM[0x04] (coeff, base 0x00 MEASURED)
w27 0C402C0000 ldreg r00,#22 ; immediate -> the register lo12 selects
w28 0182A00000 mac.b (p)0,c+,(p)+0
; C-RAM[0x05] (coeff, base 0x00 MEASURED)
w29 0000200447 ?word 0x0000200447 ; 000.2.00.447 hi12{-} [SPECULATIVE (prospective, not measured): SRC 0x11 = ACCB (2nd accumulator)]
w30 0010AFA1D5 ld (p),c+,(p)-6 ; mem[p]<-acc, acc=0
; C-RAM[0x06] (coeff, base 0x00 MEASURED)
w31 0202AFE1D5 mac (p),c+,(p)-2
; C-RAM[0x07] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x07] = op0x78[0] (role coeff, INFERRED)
w32 0202200000 mac.b (p)0,(p)+0
w33 0000A00415 ld acc,c+,(p)+0
; C-RAM[0x08] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x08] = op0x78[1] (role coeff, INFERRED)
w34 0212200000 mac.b (p)0,(p)+0 ; mem[p]<-acc, acc=0
w35 0000200407 ld.st acc,(p)+0
w36 00002FF1CD ld (p),(p)-1
w37 000020040E ld acc,(p)+0
w38 0212200000 mac.b (p)0,(p)+0 ; mem[p]<-acc, acc=0
w39 002A200000 ?word 0x002A200000 ; 02A.2.00.000 hi12{f31=5 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w40 0000200415 ld acc,(p)+0
w41 0212200000 mac.b (p)0,(p)+0 ; mem[p]<-acc, acc=0
w42 0000200415 ld acc,(p)+0
w43 0212200000 mac.b (p)0,(p)+0 ; mem[p]<-acc, acc=0
w44 0000A00415 ld acc,c+,(p)+0
; C-RAM[0x09] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x09] = op0x24[0] (role coeff, INFERRED)
w45 0212A081D5 mac (p),c+,(p)+8 ; mem[p]<-acc, acc=0
; C-RAM[0x0A] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x0A] = op0x24[1] (role coeff, INFERRED)
w46 0202200000 mac.b (p)0,(p)+0
w47 00002F9407 ld.st acc,(p)-7
w48 00122071D1 ?word 0x00122071D1 ; 012.2.07.1D1 hi12{ST f31=1} [SPECULATIVE: class-2 post-increment MAC (source 0x07); the accumulator-combine f31=1 and/or ACT 0x11 are OPEN]
w49 0292200000 mac.b (p)0,(p)+0 ; store SUPPRESSED (bit7)
w50 0000AFF455 ?word 0x0000AFF455 ; 000.A.FF.455 hi12{-} cur+ [SPECULATIVE (prospective, not measured): SRC 0x11 = ACCB (2nd accumulator)]
; C-RAM[0x0B] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x0B] = op0x24[2] (role coeff, INFERRED)
w51 0204200000 post.b (p)0,(p)+0
w52 0880130407 dly.r dsc[k],p+48
w53 00002F5000 nop
w54 000020A1CD ld (p),(p)+10
w55 00002011CE ld (p),(p)+1
w56 0212200000 mac.b (p)0,(p)+0 ; mem[p]<-acc, acc=0
w57 002A200000 ?word 0x002A200000 ; 02A.2.00.000 hi12{f31=5 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w58 0022200000 mac.b (p)0,(p)+0
w59 0000200413 ld.ta acc,(p)+0
w60 00002441CD ld (p),(p)+68
w61 01122031CE mac (p),(p)+3 ; mem[p]<-acc, acc=0
w62 01042001CE post (p),(p)+0
w63 02022FF1D5 mac (p),(p)-1
w64 0102ABB1D4 mac.tb (p),c+,(p)-69
; C-RAM[0x0C] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x0C] = op0x24[3] (role coeff, INFERRED)
w65 02042461CD post (p),(p)+70
w66 02042FE687 post.st tb,(p)-2
w67 08048161DA ?word 0x08048161DA ; 804.8.16.1DA hi12{ESC f31=2} cur [class 8: post-sum step (rescale/round/saturate?), OPERATION UNKNOWN]
w68 00002FF647 ld.st ta,(p)-1
w69 0000202687 ld.st tb,(p)+2
w70 00002AA407 ld.st acc,(p)-86
w71 042410E000 endblk #0E ; END OF BLOCK -- the last word of a block
HLE reconstruction (MAME, kn5000_tonegen.cpp)
The decode of the bytecode above, rebuilt as audible DSP. Two parts: the parameter refresh
(reads the decoded C-RAM coefficient cells once per update) and the per-sample insert (the
signal processing). Default OFF, behind the DSPHLE research port. Source:
src/mame/matsushita/kn5000_tonegen.cpp.
Parameter refresh (decode the C-RAM coefficients):
const bool wah_hle = (dsphle == 0x12);
double wah_q = 0.0;
if (wah_hle) { wah_q = 0.85; } // resonance (SVF feedback)
Per-sample insert (the reconstructed signal path):
if (wah_hle) // AUTO WAH: input envelope sweeps a resonant state-variable filter cutoff
{
const double xl = double(mix_l) / 32768.0, xr = double(mix_r) / 32768.0;
m_wah_env_l = std::max(std::fabs(xl), m_wah_env_l * 0.9995);
m_wah_env_r = std::max(std::fabs(xr), m_wah_env_r * 0.9995);
const double fcl = 300.0 + std::clamp(m_wah_env_l, 0.0, 1.0) * 3500.0;
const double fcr = 300.0 + std::clamp(m_wah_env_r, 0.0, 1.0) * 3500.0;
const double fl = 2.0 * std::sin(PI_C * std::min(fcl, 0.45 * STREAM_RATE) / double(STREAM_RATE));
const double fr = 2.0 * std::sin(PI_C * std::min(fcr, 0.45 * STREAM_RATE) / double(STREAM_RATE));
const double dmp = 1.0 - wah_q;
m_wah_lp_l += fl * m_wah_bp_l; const double hpl = xl - m_wah_lp_l - dmp * m_wah_bp_l; m_wah_bp_l += fl * hpl;
m_wah_lp_r += fr * m_wah_bp_r; const double hpr = xr - m_wah_lp_r - dmp * m_wah_bp_r; m_wah_bp_r += fr * hpr;
mix_l = int32_t(std::clamp(m_wah_bp_l, -1.0, 1.0) * 32767.0);
mix_r = int32_t(std::clamp(m_wah_bp_r, -1.0, 1.0) * 32767.0);
}