Enhancer — HLE + bytecode
Enhancer — HLE reconstruction and DSP bytecode
DSPHLE selector 0x10 · program image prog03_enhancer · Preview (topology decoded and reconstructed; most panel→cell role mappings are position-decoded).
high-shelf emphasis + all-pass phase + decoded 350 ms slap (DELAY=0x0B proven); roles INFERRED.
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/prog03_enhancer.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 -- ENHANCER
; image rep algo 3 | slots 3 | unit 0 (I-RAM load 84)
; family filter | confidence medium | 99 words, 26 class-A multiplies (18 named)
; role: enhancer: phase/emphasis shaping
; 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 088013000B ?word 0x088013000B ; 880.1.30.00B hi12{ESC ?7 res=080} [external delay-DRAM READ (FORCED, adjudication-round5 sect. 3 -- addr8 bit 6 is the direction field and 0x60 is the WRITE; this REVERSES R1 F1, which bounded the read latency to one repetition when the descriptors need twenty words); this end moves with the user's DELAY (ms) knob, and the delay is READ_CELL - WRITE_CELL; addr8 0x30 also marks the FIRST DRAM access of a body, 37 of 38 distinct images (R3 sect. 6.2). external delay-DRAM access; address = DESCRIPTOR_CELL[k] + G, from the host bank behind pointer ...825 / tag 0x4C (R3, PROVEN BY CONSTRUCTION) -- the k-th class-1 escape word of a body takes the k-th cell of that body's own descriptor block (the IDENTITY map, FORCED in adjudication-round5 sect. 1), so the address is NOT in this word]
w1 000020B1CD ld (p),(p)+11
w2 000020040E ld acc,(p)+0
w3 0212200000 mac.b (p)0,(p)+0 ; mem[p]<-acc, acc=0
w4 002A240000 ?word 0x002A240000 ; 02A.2.40.000 hi12{f31=5 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w5 0000A001D5 ld (p),c+,(p)+0
; C-RAM[0x00] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x00] = damping filter tap 0 (role damping, PROVEN)
w6 0292A01412 mac acc,c+,(p)+1 ; store SUPPRESSED (bit7)
; C-RAM[0x01] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x01] = damping filter tap 1 (role damping, PROVEN)
w7 0282ABF1D5 mac (p),c+,(p)-65
; C-RAM[0x02] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x02] = damping filter tap 2 (role damping, PROVEN)
w8 0282241407 mac.st acc,(p)+65
w9 00122C1447 ?word 0x00122C1447 ; 012.2.C1.447 hi12{ST f31=1} [SPECULATIVE (prospective, not measured): SRC 0x11 = ACCB (2nd accumulator)]
w10 00002401C8 ?word 0x00002401C8 ; 000.2.40.1C8 hi12{-} [SPECULATIVE (prospective, not measured): ACT 0x08 = table-port multiply]
w11 00002C21D5 ld (p),(p)-62
w12 010223E1CD mac (p),(p)+62
w13 0212201412 mac acc,(p)+1 ; mem[p]<-acc, acc=0
w14 01042C11D5 post (p),(p)-63
w15 010223F1CD mac (p),(p)+63
w16 0212ABE412 mac acc,c+,(p)-66 ; mem[p]<-acc, acc=0
; C-RAM[0x03] (coeff, base 0x00 MEASURED)
w17 0104200000 post.b (p)0,(p)+0
w18 0026200000 ?word 0x0026200000 ; 026.2.00.000 hi12{f31=3 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w19 0880130407 dly.r dsc[k],p+48
w20 00002FF000 nop
w21 00122441C0 mac.b (p),(p)+68 ; mem[p]<-acc, acc=0
w22 0104A001D5 post (p),c+,(p)+0
; C-RAM[0x04] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x04] = damping filter tap 0 (role damping, PROVEN)
w23 0292A01412 mac acc,c+,(p)+1 ; store SUPPRESSED (bit7)
; C-RAM[0x05] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x05] = damping filter tap 1 (role damping, PROVEN)
w24 0282ABB1D5 mac (p),c+,(p)-69
; C-RAM[0x06] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x06] = damping filter tap 2 (role damping, PROVEN)
w25 0282245000 mac.b (p)0,(p)+69
w26 00122BD447 ?word 0x00122BD447 ; 012.2.BD.447 hi12{ST f31=1} [SPECULATIVE (prospective, not measured): SRC 0x11 = ACCB (2nd accumulator)]
w27 00002441C8 ?word 0x00002441C8 ; 000.2.44.1C8 hi12{-} [SPECULATIVE (prospective, not measured): ACT 0x08 = table-port multiply]
w28 00002BE1D5 ld (p),(p)-66
w29 01022421CD mac (p),(p)+66
w30 0212201412 mac acc,(p)+1 ; mem[p]<-acc, acc=0
w31 01042BD1D5 post (p),(p)-67
w32 01022431CD mac (p),(p)+67
w33 0212ABA412 mac acc,c+,(p)-70 ; mem[p]<-acc, acc=0
; C-RAM[0x07] (coeff, base 0x00 MEASURED)
w34 0104200000 post.b (p)0,(p)+0
w35 0026200000 ?word 0x0026200000 ; 026.2.00.000 hi12{f31=3 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w36 0880130000 dly.r dsc[k],p+48
w37 0000A00415 ld acc,c+,(p)+0
; C-RAM[0x08] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x08] = op0x62[0] (role output-level, INFERRED)
w38 0212AFF1D5 mac (p),c+,(p)-1 ; mem[p]<-acc, acc=0
; C-RAM[0x09] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x09] = op0x62[1] (role output-level, INFERRED)
w39 0202AFB1D5 mac (p),c+,(p)-5
; C-RAM[0x0A] (coeff, base 0x00 MEASURED)
w40 0202200000 mac.b (p)0,(p)+0
w41 09001601D5 dly.w dsc[k],p+96
w42 0192A4D000 mac.b (p)0,c+,(p)+77 ; store SUPPRESSED (bit7)
; C-RAM[0x0B] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x0B] = op0x64[0] (role coeff, INFERRED)
w43 00822001C0 mac.b (p),(p)+0
w44 0C4032044C ldreg r4C,#25 ; immediate -> the register lo12 selects
w45 0A00000041 ?word 0x0A00000041 ; A00.0.00.041 hi12{ESC f98=2} [head of a fixed 3-word template (S-5); operands SRC 0x01/ACT 0x01 dark]
w46 08801202C7 dly.r dsc[k],p+32
w47 0102AB54C8 ?word 0x0102AB54C8 ; 102.A.B5.4C8 hi12{f98=1 f31=1} cur+ [gain multiply (same op in phaser all-pass and reverb diffuser)]
; C-RAM[0x0C] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x0C] = op0x64[1] (role coeff, INFERRED)
w48 00002F7000 nop
w49 002820A1CD ?word 0x002820A1CD ; 028.2.0A.1CD hi12{f31=4 ?5 res=020} [SPECULATIVE (prospective, not measured): ACT 0x0D = delay/state MIXING: mem onto bus (universal; pair w/ 0x0E)]
w50 00002FF1CE ld (p),(p)-1
w51 0212202407 mac.st acc,(p)+2 ; mem[p]<-acc, acc=0
w52 002A24A000 ?word 0x002A24A000 ; 02A.2.4A.000 hi12{f31=5 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w53 0000A001D5 ld (p),c+,(p)+0
; C-RAM[0x0D] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x0D] = damping filter tap 0 (role damping, PROVEN)
w54 0292A01412 mac acc,c+,(p)+1 ; store SUPPRESSED (bit7)
; C-RAM[0x0E] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x0E] = damping filter tap 1 (role damping, PROVEN)
w55 0282AB51D5 mac (p),c+,(p)-75
; C-RAM[0x0F] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x0F] = damping filter tap 2 (role damping, PROVEN)
w56 028224B407 mac.st acc,(p)+75
w57 00122AF447 ?word 0x00122AF447 ; 012.2.AF.447 hi12{ST f31=1} [SPECULATIVE (prospective, not measured): SRC 0x11 = ACCB (2nd accumulator)]
w58 00002521C8 ?word 0x00002521C8 ; 000.2.52.1C8 hi12{-} [SPECULATIVE (prospective, not measured): ACT 0x08 = table-port multiply]
w59 00002B81D5 ld (p),(p)-72
w60 01022481CD mac (p),(p)+72
w61 0212201412 mac acc,(p)+1 ; mem[p]<-acc, acc=0
w62 01042B71D5 post (p),(p)-73
w63 01022491CD mac (p),(p)+73
w64 0212AB4412 mac acc,c+,(p)-76 ; mem[p]<-acc, acc=0
; C-RAM[0x10] (coeff, base 0x00 MEASURED)
w65 0104200000 post.b (p)0,(p)+0
w66 0026200000 ?word 0x0026200000 ; 026.2.00.000 hi12{f31=3 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w67 00002FF407 ld.st acc,(p)-1
w68 001224E1C0 mac.b (p),(p)+78 ; mem[p]<-acc, acc=0
w69 0104A001D5 post (p),c+,(p)+0
; C-RAM[0x11] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x11] = damping filter tap 0 (role damping, PROVEN)
w70 0292A01412 mac acc,c+,(p)+1 ; store SUPPRESSED (bit7)
; C-RAM[0x12] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x12] = damping filter tap 1 (role damping, PROVEN)
w71 0282AB11D5 mac (p),c+,(p)-79
; C-RAM[0x13] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x13] = damping filter tap 2 (role damping, PROVEN)
w72 028224F000 mac.b (p)0,(p)+79
w73 00122AB447 ?word 0x00122AB447 ; 012.2.AB.447 hi12{ST f31=1} [SPECULATIVE (prospective, not measured): SRC 0x11 = ACCB (2nd accumulator)]
w74 00002561C8 ?word 0x00002561C8 ; 000.2.56.1C8 hi12{-} [SPECULATIVE (prospective, not measured): ACT 0x08 = table-port multiply]
w75 00002B41D5 ld (p),(p)-76
w76 010224C1CD mac (p),(p)+76
w77 0212201412 mac acc,(p)+1 ; mem[p]<-acc, acc=0
w78 01042B31D5 post (p),(p)-77
w79 010224D1CD mac (p),(p)+77
w80 0212AB0412 mac acc,c+,(p)-80 ; mem[p]<-acc, acc=0
; C-RAM[0x14] (coeff, base 0x00 MEASURED)
w81 0104200000 post.b (p)0,(p)+0
w82 0026200000 ?word 0x0026200000 ; 026.2.00.000 hi12{f31=3 ?5 res=020} [SPECULATIVE (prospective, not measured): SRC 0x00 = mem[ptr]/delay-RAM read]
w83 0000A00415 ld acc,c+,(p)+0
; C-RAM[0x15] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x15] = op0x62[2] (role output-level, INFERRED)
w84 0212AFF1D5 mac (p),c+,(p)-1 ; mem[p]<-acc, acc=0
; C-RAM[0x16] (coeff, base 0x00 MEASURED)
; coeff C-RAM[0x16] = op0x62[3] (role output-level, INFERRED)
w85 0202AFC1D5 mac (p),c+,(p)-4
; C-RAM[0x17] (coeff, base 0x00 MEASURED)
w86 0202200000 mac.b (p)0,(p)+0
w87 09001601D5 dly.w dsc[k],p+96
w88 0192A56000 mac.b (p)0,c+,(p)+86 ; store SUPPRESSED (bit7)
; C-RAM[0x18] (coeff, base 0x00 MEASURED)
w89 00822001C0 mac.b (p),(p)+0
w90 0C4032044C ldreg r4C,#25 ; immediate -> the register lo12 selects
w91 0A00000041 ?word 0x0A00000041 ; A00.0.00.041 hi12{ESC f98=2} [head of a fixed 3-word template (S-5); operands SRC 0x01/ACT 0x01 dark]
w92 08801202C7 dly.r dsc[k],p+32
w93 0102A9D4C8 ?word 0x0102A9D4C8 ; 102.A.9D.4C8 hi12{f98=1 f31=1} cur+ [gain multiply (same op in phaser all-pass and reverb diffuser)]
; C-RAM[0x19] (coeff, base 0x00 MEASURED)
w94 0000200000 nop
w95 0000200000 nop
w96 0000200000 nop
w97 0880160000 dly.w dsc[k],p+96
w98 042810E000 ?word 0x042810E000 ; 428.1.0E.000 hi12{END f31=4 ?5 res=020} [END OF BLOCK, unit 0 -- CALL/RETURN -- and still performs the rest of the word]
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 enh_hle = (dsphle == 0x10);
int enh_dN = 0; double enh_hi = 0.0, enh_wet = 0.0;
if (enh_hle)
{
enh_dN = std::clamp(int(double(m_dsp1->cram_read(0x0B) & 0xffffff) * x_cs * sr48 + 0.5), 1, 34999);
enh_hi = std::clamp(0.5 + 2.0 * std::fabs(q22x(m_dsp1->cram_read(0x09)) * x_cs), 0.5, 3.0); // HIGH MIX boost
enh_wet = 0.25; // modest slap blend (DELAY is the anchor)
m_enh_lp_l.set_damping(0.64); m_enh_lp_r.set_damping(0.64);
m_enh_ap_l.set_a(0.6); m_enh_ap_r.set_a(0.6);
}
Per-sample insert (the reconstructed signal path):
if (enh_hle) // ENHANCER: high-shelf emphasis + all-pass phase + decoded ~350 ms slap
{
const double xl = double(mix_l) / 32768.0, xr = double(mix_r) / 32768.0;
const double ehl = xl + (enh_hi - 1.0) * (xl - m_enh_lp_l.process_one(xl));
const double ehr = xr + (enh_hi - 1.0) * (xr - m_enh_lp_r.process_one(xr));
const double phl = m_enh_ap_l.process_one(ehl), phr = m_enh_ap_r.process_one(ehr);
const double dl = m_enh_l.read(double(enh_dN)), dr = m_enh_r.read(double(enh_dN));
m_enh_l.write(phl); m_enh_r.write(phr);
mix_l = int32_t(std::clamp(phl + enh_wet * dl, -1.0, 1.0) * 32767.0);
mix_r = int32_t(std::clamp(phr + enh_wet * dr, -1.0, 1.0) * 32767.0);
}