openMSX
YM2413NukeYKT.cc
Go to the documentation of this file.
1/*
2* Original copyright:
3* -------------------------------------------------------------------
4* Copyright (C) 2019 Nuke.YKT
5*
6* This program is free software; you can redistribute it and/or
7* modify it under the terms of the GNU General Public License
8* as published by the Free Software Foundation; either version 2
9* of the License, or (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16*
17* Yamaha YM2413 emulator
18* Thanks:
19* siliconpr0n.org(digshadow, John McMaster):
20* VRC VII decap and die shot.
21*
22* version: 0.9
23* -------------------------------------------------------------------
24*
25* See YM2413NukeYKT.hh for more info.
26*/
27
28#include "YM2413NukeYKT.hh"
29#include "serialize.hh"
30#include "cstd.hh"
31#include "enumerate.hh"
32#include "Math.hh"
33#include "narrow.hh"
34#include "one_of.hh"
35#include "ranges.hh"
36#include "unreachable.hh"
37#include "xrange.hh"
38#include <algorithm>
39#include <array>
40#include <cstring>
41
42namespace openmsx {
43namespace YM2413NukeYKT {
44
45enum RmNum : uint8_t {
46 rm_num_bd0 = 0, // cycles == 11
47 rm_num_hh = 1, // 12
48 rm_num_tom = 2, // 13
49 rm_num_bd1 = 3, // 14
50 rm_num_sd = 4, // 15
51 rm_num_tc = 5, // 16
52};
53[[nodiscard]] constexpr bool is_rm_cycle(int cycle)
54{
55 return (11 <= cycle) && (cycle <= 16);
56}
57[[nodiscard]] constexpr RmNum rm_for_cycle(int cycle)
58{
59 return RmNum(cycle - 11);
60}
61
62static constexpr auto logSinTab = [] {
63 std::array<uint16_t, 256> result = {};
64 //for (auto [i, r] : enumerate(result)) { msvc bug
65 for (int i = 0; i < 256; ++i) {
66 result[i] = narrow_cast<uint16_t>(cstd::round(-cstd::log2<8, 3>(cstd::sin<2>((double(i) + 0.5) * Math::pi / 256.0 / 2.0)) * 256.0));
67 }
68 return result;
69}();
70static constexpr auto expTab = [] {
71 std::array<uint16_t, 256> result = {};
72 //for (auto [i, r] : enumerate(result)) { msvc bug
73 for (int i = 0; i < 256; ++i) {
74 result[i] = narrow_cast<uint16_t>(cstd::round((cstd::exp2<6>(double(255 - i) / 256.0)) * 1024.0));
75 }
76 return result;
77}();
78
79constexpr std::array<YM2413::Patch, 15> YM2413::m_patches = {
80 YM2413::Patch{0x1e, 2, 7, {0, 0}, {1, 1}, {1, 1}, {1, 0}, {0x1, 0x1}, {0, 0}, {0xd, 0x7}, {0x0, 0x8}, {0x0, 0x1}, {0x0, 0x7}},
81 YM2413::Patch{0x1a, 1, 5, {0, 0}, {0, 1}, {0, 0}, {1, 0}, {0x3, 0x1}, {0, 0}, {0xd, 0xf}, {0x8, 0x7}, {0x2, 0x1}, {0x3, 0x3}},
82 YM2413::Patch{0x19, 0, 0, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0x3, 0x1}, {2, 0}, {0xf, 0xc}, {0x2, 0x4}, {0x1, 0x2}, {0x1, 0x3}},
83 YM2413::Patch{0x0e, 0, 7, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0x1, 0x1}, {0, 0}, {0xa, 0x6}, {0x8, 0x4}, {0x7, 0x2}, {0x0, 0x7}},
84 YM2413::Patch{0x1e, 0, 6, {0, 0}, {0, 0}, {1, 1}, {1, 0}, {0x2, 0x1}, {0, 0}, {0xe, 0x7}, {0x0, 0x6}, {0x0, 0x2}, {0x0, 0x8}},
85 YM2413::Patch{0x16, 0, 5, {0, 0}, {0, 0}, {1, 1}, {1, 0}, {0x1, 0x2}, {0, 0}, {0xe, 0x7}, {0x0, 0x1}, {0x0, 0x1}, {0x0, 0x8}},
86 YM2413::Patch{0x1d, 0, 7, {0, 0}, {0, 1}, {1, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x8, 0x8}, {0x2, 0x1}, {0x1, 0x0}, {0x0, 0x7}},
87 YM2413::Patch{0x2d, 2, 4, {0, 0}, {0, 0}, {1, 1}, {0, 0}, {0x3, 0x1}, {0, 0}, {0xa, 0x7}, {0x2, 0x2}, {0x0, 0x0}, {0x0, 0x7}},
88 YM2413::Patch{0x1b, 0, 6, {0, 0}, {1, 1}, {1, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x6, 0x6}, {0x4, 0x5}, {0x1, 0x1}, {0x0, 0x7}},
89 YM2413::Patch{0x0b, 3, 0, {0, 0}, {1, 1}, {0, 1}, {0, 0}, {0x1, 0x1}, {0, 0}, {0x8, 0xf}, {0x5, 0x7}, {0x7, 0x0}, {0x1, 0x7}},
90 YM2413::Patch{0x03, 2, 1, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0x3, 0x1}, {2, 0}, {0xf, 0xe}, {0xa, 0x4}, {0x1, 0x0}, {0x0, 0x4}},
91 YM2413::Patch{0x24, 0, 7, {0, 1}, {0, 1}, {0, 0}, {1, 0}, {0x7, 0x1}, {0, 0}, {0xf, 0xf}, {0x8, 0x8}, {0x2, 0x1}, {0x2, 0x2}},
92 YM2413::Patch{0x0c, 0, 5, {0, 0}, {1, 1}, {1, 0}, {0, 1}, {0x1, 0x0}, {0, 0}, {0xc, 0xf}, {0x2, 0x5}, {0x2, 0x4}, {0x0, 0x2}},
93 YM2413::Patch{0x15, 0, 3, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x1}, {1, 0}, {0xc, 0x9}, {0x9, 0x5}, {0x0, 0x0}, {0x3, 0x2}},
94 YM2413::Patch{0x09, 0, 3, {0, 0}, {1, 1}, {1, 0}, {0, 0}, {0x1, 0x1}, {2, 0}, {0xf, 0xe}, {0x1, 0x4}, {0x4, 0x1}, {0x0, 0x3}},
95};
96
97constexpr std::array<YM2413::Patch, 6> YM2413::r_patches = {
98 YM2413::Patch{0x18, 1, 7, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x0}, {0, 0}, {0xd, 0x0}, {0xf, 0x0}, {0x6, 0x0}, {0xa, 0x0}},
99 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x1, 0x0}, {0, 0}, {0xc, 0x0}, {0x8, 0x0}, {0xa, 0x0}, {0x7, 0x0}},
100 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x5, 0x0}, {0, 0}, {0xf, 0x0}, {0x8, 0x0}, {0x5, 0x0}, {0x9, 0x0}},
101 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xf}, {0x0, 0x8}, {0x0, 0x6}, {0x0, 0xd}},
102 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xd}, {0x0, 0x8}, {0x0, 0x4}, {0x0, 0x8}},
103 YM2413::Patch{0x00, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0x0, 0x1}, {0, 0}, {0x0, 0xa}, {0x0, 0xa}, {0x0, 0x5}, {0x0, 0x5}},
104};
105
106static constexpr std::array<uint8_t, 18> CH_OFFSET = {
107 1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 8, 6, 7, 8, 0
108};
109
110static constexpr std::array<int8_t, 8> VIB_TAB = {0, 1, 2, 1, 0, -1, -2, -1};
111
112// Define the tables
113// constexpr uint8_t attack[14][4][64] = { ... };
114// constexpr uint8_t releaseIndex[14][4][4] = { ... };
115// constexpr uint8_t releaseData[64][64] = { ... };
116// Theoretically these could all be initialized via some constexpr functions.
117// The calculation isn't difficult, but it's a bit long. 'clang' can handle it,
118// but 'gcc' cannot. So instead, for now, we pre-calculate these tables and
119// #include them. See 'generateNukeYktTables.cpp' for the generator code.
120#include "YM2413NukeYktTables.ii"
121
122
124 : attackPtr (/*dummy*/attack[0][0])
125 , releasePtr(/*dummy*/releaseData[0])
126{
127 // copy ROM patches to array (for faster lookup)
128 ranges::copy(m_patches, subspan(patches, 1));
129 reset();
130}
131
133{
134 for (auto& w : writes) w.port = uint8_t(-1);
135 write_fm_cycle = uint8_t(-1);
136 write_data = fm_data = write_address = 0;
137 fast_fm_rewrite = test_mode_active = false;
138
139 eg_counter_state = 3;
140 eg_timer = eg_timer_shift = eg_timer_shift_lock = eg_timer_lock = 0;
141 attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
142 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
143 releasePtr = releaseData[idx];
145 ranges::fill(eg_level, 0x7f);
146 ranges::fill(eg_dokon, false);
147 eg_rate[0] = eg_rate[1] = 0;
148 eg_sl[0] = eg_sl[1] = eg_out[0] = eg_out[1] = 0;
149 eg_timer_shift_stop = false;
150 eg_kon[0] = eg_kon[1] = eg_off[0] = eg_off[1] = false;
151
152 ranges::fill(pg_phase, 0);
153 ranges::fill(op_fb1, 0);
154 ranges::fill(op_fb2, 0);
155
156 op_mod = 0;
157 op_phase[0] = op_phase[1] = 0;
158
159 lfo_counter = lfo_am_counter = 0;
160 lfo_vib_counter = lfo_am_out = 0;
161 lfo_vib = VIB_TAB[lfo_vib_counter];
162 lfo_am_step = lfo_am_dir = false;
163
164 ranges::fill(fnum, 0);
165 ranges::fill(block, 0);
166 ranges::fill(vol8, 0);
167 ranges::fill(inst, 0);
168 ranges::fill(sk_on, 0);
169 for (auto i : xrange(9)) {
170 p_inst[i] = &patches[inst[i]];
171 changeFnumBlock(i);
172 }
173 rhythm = testMode = 0;
174 patches[0] = Patch(); // reset user patch, leave ROM patches alone
175 c_dcm[0] = c_dcm[1] = c_dcm[2] = 0;
176
177 rm_noise = 1; // any value except 0 (1 keeps the output the same as the original code)
178 rm_tc_bits = 0;
179
180 delay6 = delay7 = delay10 = delay11 = delay12 = 0;
181
182 ranges::fill(regs, 0);
183 latch = 0;
184}
185
186template<uint32_t CYCLES> ALWAYS_INLINE const YM2413::Patch& YM2413::preparePatch1(bool use_rm_patches) const
187{
188 return (is_rm_cycle(CYCLES) && use_rm_patches)
189 ? r_patches[rm_for_cycle(CYCLES)]
190 : *p_inst[CH_OFFSET[CYCLES]];
191}
192
193template<uint32_t CYCLES> ALWAYS_INLINE uint32_t YM2413::envelopeKSLTL(const Patch& patch1, bool use_rm_patches) const
194{
195 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
196 constexpr uint32_t ch = CH_OFFSET[CYCLES];
197
198 auto ksl = uint32_t(p_ksl[ch]) >> patch1.ksl_t[mcsel];
199 auto tl2 = [&]() -> uint32_t {
200 if ((rm_for_cycle(CYCLES) == one_of(rm_num_hh, rm_num_tom)) && use_rm_patches) {
201 return inst[ch] << (2 + 1);
202 } else if /*constexpr*/ (mcsel == 1) { // constexpr triggers compile error on visual studio
203 return vol8[ch];
204 } else {
205 return patch1.tl2;
206 }
207 }();
208 return ksl + tl2;
209}
210
211template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::envelopeTimer1()
212{
213 if constexpr (CYCLES == 0) {
214 eg_counter_state = (eg_counter_state + 1) & 3;
215 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
216 releasePtr = releaseData[idx];
217 }
218}
219
220template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void YM2413::envelopeTimer2(bool& eg_timer_carry)
221{
222 if constexpr (TEST_MODE) {
223 if (CYCLES == 0 && (eg_counter_state & 1) == 0) {
224 eg_timer_lock = eg_timer & 3;
225 eg_timer_shift_lock = /*likely*/(eg_timer_shift <= 13) ? eg_timer_shift : 0;
226 eg_timer_shift = 0;
227
228 attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
229 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
230 releasePtr = releaseData[idx];
231 }
232 { // EG timer
233 bool timer_inc = (eg_counter_state != 3) ? false
234 : (CYCLES == 0) ? true
235 : eg_timer_carry;
236 auto timer_bit = (eg_timer & 1) + timer_inc;
237 eg_timer_carry = timer_bit & 2;
238 eg_timer = ((timer_bit & 1) << 17) | (eg_timer >> 1);
239 if (testMode & 8) {
240 const auto& write = writes[CYCLES];
241 auto data = (write.port != uint8_t(-1)) ? write.value : write_data;
242 eg_timer &= 0x2ffff;
243 eg_timer |= (data << (16 - 2)) & 0x10000;
244 }
245 }
246 if constexpr (CYCLES == 0) {
247 eg_timer_shift_stop = false;
248 } else if (!eg_timer_shift_stop && ((eg_timer >> 16) & 1)) {
249 eg_timer_shift = CYCLES;
250 eg_timer_shift_stop = true;
251 }
252 } else {
253 if constexpr (CYCLES == 0) {
254 if ((eg_counter_state & 1) == 0) {
255 eg_timer_lock = eg_timer & 3;
256 eg_timer_shift_lock = (eg_timer_shift > 13) ? 0 : eg_timer_shift;
257
258 attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
259 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
260 releasePtr = releaseData[idx];
261 }
262 if (eg_counter_state == 3) {
263 eg_timer = (eg_timer + 1) & 0x3ffff;
264 eg_timer_shift = narrow_cast<uint8_t>(Math::findFirstSet(eg_timer));
265 }
266 }
267 }
268}
269
270template<uint32_t CYCLES> ALWAYS_INLINE bool YM2413::envelopeGenerate1()
271{
272 int32_t level = eg_level[(CYCLES + 16) % 18];
273 bool prev2_eg_off = eg_off[(CYCLES + 16) & 1];
274 bool prev2_eg_kon = eg_kon[(CYCLES + 16) & 1];
275 bool prev2_eg_dokon = eg_dokon[(CYCLES + 16) % 18];
276
277 auto state = eg_state[(CYCLES + 16) % 18];
278 if (prev2_eg_dokon) [[unlikely]] {
279 eg_state[(CYCLES + 16) % 18] = EgState::attack;
280 } else if (!prev2_eg_kon) {
281 eg_state[(CYCLES + 16) % 18] = EgState::release;
282 } else if ((state == EgState::attack) && (level == 0)) [[unlikely]] {
283 eg_state[(CYCLES + 16) % 18] = EgState::decay;
284 } else if ((state == EgState::decay) && ((level >> 3) == eg_sl[CYCLES & 1])) [[unlikely]] {
285 eg_state[(CYCLES + 16) % 18] = EgState::sustain;
286 }
287
288 auto prev2_rate = eg_rate[(CYCLES + 16) & 1];
289 int32_t next_level
290 = (state != EgState::attack && prev2_eg_off && !prev2_eg_dokon) ? 0x7f
291 : ((prev2_rate >= 60) && prev2_eg_dokon) ? 0x00
292 : level;
293 auto step = [&]() -> int {
294 switch (state) {
295 case EgState::attack:
296 if (prev2_eg_kon && (level != 0)) [[likely]] {
297 return (level ^ 0xfff) >> attackPtr[prev2_rate];
298 }
299 break;
300 case EgState::decay:
301 if ((level >> 3) == eg_sl[CYCLES & 1]) return 0;
302 [[fallthrough]];
303 case EgState::sustain:
304 case EgState::release:
305 if (!prev2_eg_off && !prev2_eg_dokon) {
306 return releasePtr[prev2_rate];
307 }
308 break;
309 default:
311 }
312 return 0;
313 }();
314 eg_level[(CYCLES + 16) % 18] = narrow_cast<uint8_t>(next_level + step);
315
316 return level == 0x7f; // eg_silent
317}
318
319template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::envelopeGenerate2(const Patch& patch1, bool use_rm_patches)
320{
321 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
322 constexpr uint32_t ch = CH_OFFSET[CYCLES];
323
324 bool new_eg_off = eg_level[CYCLES] >= 124; // (eg_level[CYCLES] >> 2) == 0x1f;
325 eg_off[CYCLES & 1] = new_eg_off;
326
327 auto sk = sk_on[CH_OFFSET[CYCLES]];
328 bool new_eg_kon = [&]() {
329 bool result = sk & 1;
330 if (is_rm_cycle(CYCLES) && use_rm_patches) {
331 switch (rm_for_cycle(CYCLES)) {
332 case rm_num_bd0:
333 case rm_num_bd1:
334 result |= bool(rhythm & 0x10);
335 break;
336 case rm_num_sd:
337 result |= bool(rhythm & 0x08);
338 break;
339 case rm_num_tom:
340 result |= bool(rhythm & 0x04);
341 break;
342 case rm_num_tc:
343 result |= bool(rhythm & 0x02);
344 break;
345 case rm_num_hh:
346 result |= bool(rhythm & 0x01);
347 break;
348 default:
349 break; // suppress warning
350 }
351 }
352 return result;
353 }();
354 eg_kon[CYCLES & 1] = new_eg_kon;
355
356 // Calculate rate
357 auto state_rate = eg_state[CYCLES];
358 if (state_rate == EgState::release && new_eg_kon && new_eg_off) [[unlikely]] {
359 state_rate = EgState::attack;
360 eg_dokon[CYCLES] = true;
361 } else {
362 eg_dokon[CYCLES] = false;
363 }
364
365 auto rate4 = [&]() {
366 if (!new_eg_kon && !(sk & 2) && mcsel == 1 && !patch1.et[mcsel]) {
367 return 7 * 4;
368 }
369 if (new_eg_kon && eg_state[CYCLES] == EgState::release && !new_eg_off) {
370 return 12 * 4;
371 }
372 bool tom_or_hh = (rm_for_cycle(CYCLES) == one_of(rm_num_tom, rm_num_hh)) && use_rm_patches;
373 if (!new_eg_kon && !mcsel && !tom_or_hh) {
374 return 0 * 4;
375 }
376 return (state_rate == EgState::attack ) ? patch1.ar4[mcsel]
377 : (state_rate == EgState::decay ) ? patch1.dr4[mcsel]
378 : (state_rate == EgState::sustain) ? (patch1.et[mcsel] ? (0 * 4) : patch1.rr4[mcsel])
379 : /*(state_rate == EgState::release) ?*/ ((sk & 2) ? (5 * 4) : patch1.rr4[mcsel]);
380 }();
381
382 eg_rate[CYCLES & 1] = narrow_cast<uint8_t>([&]() {
383 if (rate4 == 0) return 0;
384 auto tmp = rate4 + (p_ksr_freq[ch] >> patch1.ksr_t[mcsel]);
385 return (tmp < 0x40) ? tmp
386 : (0x3c | (tmp & 3));
387 }());
388}
389
390template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void YM2413::doLFO(bool& lfo_am_car)
391{
392 if constexpr (TEST_MODE) {
393 // Update counter
394 if constexpr (CYCLES == 17) {
395 lfo_counter++;
396 if (((lfo_counter & 0x3ff) == 0) || (testMode & 8)) {
397 lfo_vib_counter = (lfo_vib_counter + 1) & 7;
398 lfo_vib = VIB_TAB[lfo_vib_counter];
399 }
400 lfo_am_step = (lfo_counter & 0x3f) == 0;
401 }
402
403 // LFO AM
404 auto am_inc = ((lfo_am_step || (testMode & 8)) && CYCLES < 9)
405 ? (lfo_am_dir | (CYCLES == 0))
406 : 0;
407
408 if constexpr (CYCLES == 0) {
409 if (lfo_am_dir && (lfo_am_counter & 0x7f) == 0) {
410 lfo_am_dir = false;
411 } else if (!lfo_am_dir && (lfo_am_counter & 0x69) == 0x69) {
412 lfo_am_dir = true;
413 }
414 }
415
416 auto am_bit = (lfo_am_counter & 1) + am_inc + ((CYCLES < 9) ? lfo_am_car : false);
417 if constexpr (CYCLES < 8) {
418 lfo_am_car = am_bit & 2;
419 }
420 lfo_am_counter = uint16_t(((am_bit & 1) << 8) | (lfo_am_counter >> 1));
421
422 // Reset LFO
423 if (testMode & 2) {
424 lfo_vib_counter = 0;
425 lfo_vib = VIB_TAB[lfo_vib_counter];
426 lfo_counter = 0;
427 lfo_am_dir = false;
428 lfo_am_counter &= 0xff;
429 }
430 } else {
431 if constexpr (CYCLES == 17) {
432 int delta = lfo_am_dir ? -1 : 1;
433
434 if (lfo_am_dir && (lfo_am_counter & 0x7f) == 0) {
435 lfo_am_dir = false;
436 } else if (!lfo_am_dir && (lfo_am_counter & 0x69) == 0x69) {
437 lfo_am_dir = true;
438 }
439
440 if (lfo_am_step) {
441 lfo_am_counter = (lfo_am_counter + delta) & 0x1ff;
442 }
443
444 lfo_counter++;
445 if (((lfo_counter & 0x3ff) == 0)) {
446 lfo_vib_counter = (lfo_vib_counter + 1) & 7;
447 lfo_vib = VIB_TAB[lfo_vib_counter];
448 }
449 lfo_am_step = (lfo_counter & 0x3f) == 0;
450 }
451 }
452 if constexpr (CYCLES == 17) {
453 lfo_am_out = (lfo_am_counter >> 3) & 0x0f;
454 }
455}
456
457template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void YM2413::doRhythm()
458{
459 if constexpr (TEST_MODE) {
460 bool nbit = (rm_noise ^ (rm_noise >> 14)) & 1;
461 nbit |= bool(testMode & 2);
462 rm_noise = (nbit << 22) | (rm_noise >> 1);
463 } else {
464 // When test-mode does not interfere, the formula for a single step is:
465 // x = ((x & 1) << 22) ^ ((x & 0x4000) << 8) ^ (x >> 1);
466 // From this we can easily derive the value of the noise bit (bit 0)
467 // 13 and 16 steps in the future (see getPhase()). We can also
468 // derive a formula that takes 18 steps at once.
469 if constexpr (CYCLES == 17) {
470 rm_noise = ((rm_noise & 0x1ff) << 14)
471 ^ ((rm_noise & 0x3ffff) << 5)
472 ^ (rm_noise & 0x7fc000)
473 ^ ((rm_noise >> 9) & 0x3fe0)
474 ^ (rm_noise >> 18);
475 }
476 }
477}
478
479template<uint32_t CYCLES> ALWAYS_INLINE uint32_t YM2413::getPhaseMod(uint8_t fb_t)
480{
481 bool ismod2 = ((rhythm & 0x20) && (CYCLES == one_of(12u, 13u)))
482 ? false
483 : (((CYCLES + 4) / 3) & 1);
484 bool ismod3 = ((rhythm & 0x20) && (CYCLES == one_of(15u, 16u)))
485 ? false
486 : (((CYCLES + 1) / 3) & 1);
487
488 if (ismod3) return op_mod << 1;
489 if (ismod2) {
490 constexpr uint32_t cycles9 = (CYCLES + 3) % 9;
491 uint32_t op_fbsum = (op_fb1[cycles9] + op_fb2[cycles9]) & 0x7fffffff;
492 return op_fbsum >> fb_t;
493 }
494 return 0;
495}
496
497template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::doRegWrite()
498{
499 if (write_fm_cycle == CYCLES) [[unlikely]] {
500 doRegWrite(CYCLES % 9);
501 }
502}
503
504void YM2413::changeFnumBlock(uint32_t ch)
505{
506 static constexpr std::array<uint8_t, 16> KSL_TABLE = {
507 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64
508 };
509 p_ksl[ch] = narrow_cast<uint8_t>(std::max(0, KSL_TABLE[fnum[ch] >> 5] - ((8 - block[ch]) << 3)) << 1);
510 p_incr[ch] = narrow_cast<uint16_t>(fnum[ch] << block[ch]);
511 p_ksr_freq[ch] = uint8_t((block[ch] << 1) | (fnum[ch] >> 8));
512}
513
514NEVER_INLINE void YM2413::doRegWrite(uint8_t channel)
515{
516 if (write_address < 0x40) {
517 write_fm_cycle = uint8_t(-1);
518 doRegWrite(write_address & 0xf0, channel, fm_data);
519 } else {
520 write_address -= 0x40; // try again in 18 steps
521 }
522}
523
524void YM2413::doRegWrite(uint8_t regBlock, uint8_t channel, uint8_t data)
525{
526 switch (regBlock) {
527 case 0x10:
528 fnum[channel] = uint16_t((fnum[channel] & 0x100) | data);
529 changeFnumBlock(channel);
530 break;
531 case 0x20:
532 fnum[channel] = uint16_t((fnum[channel] & 0xff) | ((data & 1) << 8));
533 block[channel] = (data >> 1) & 7;
534 changeFnumBlock(channel);
535 sk_on[channel] = (data >> 4) & 3;
536 break;
537 case 0x30:
538 vol8[channel] = uint8_t((data & 0x0f) << (2 + 1)); // pre-multiply by 8
539 inst[channel] = (data >> 4) & 0x0f;
540 p_inst[channel] = &patches[inst[channel]];
541 break;
542 }
543}
544
545template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::doIO()
546{
547 if (writes[CYCLES].port != uint8_t(-1)) [[unlikely]] {
548 doIO((CYCLES + 1) % 18, writes[CYCLES]);
549 }
550}
551
552NEVER_INLINE void YM2413::doIO(uint32_t cycles_plus_1, Write& write)
553{
554 write_data = write.value;
555 if (write.port) {
556 // data
557 if (write_address < 0x10) {
558 doModeWrite(write_address, write.value);
559 } else if (write_address < 0x40) {
560 write_fm_cycle = write_address & 0xf;
561 fm_data = write.value;
562 if (!fast_fm_rewrite && (write_fm_cycle == cycles_plus_1)) {
563 write_address += 0x40; // postpone for 18 steps
564 }
565 // First fm-register write takes one cycle longer than
566 // subsequent writes to the same register. When the address
567 // is changed (even if to the same value) then there's again
568 // one cycle penalty.
569 fast_fm_rewrite = true;
570 }
571 } else {
572 // address
573 write_address = write.value;
574 write_fm_cycle = uint8_t(-1); // cancel pending fm write
575 fast_fm_rewrite = false;
576 }
577
578 write.port = uint8_t(-1);
579}
580
581void YM2413::doModeWrite(uint8_t address, uint8_t value)
582{
583 auto slot = address & 1;
584 switch (address) {
585 case 0x00:
586 case 0x01:
587 patches[0].setMulti(slot, value & 0x0f);
588 patches[0].setKSR(slot, (value >> 4) & 1);
589 patches[0].et[slot] = (value >> 5) & 1;
590 patches[0].vib[slot] = (value >> 6) & 1;
591 patches[0].setAM(slot, (value >> 7) & 1);
592 break;
593
594 case 0x02:
595 patches[0].setKSL(0, (value >> 6) & 3);
596 patches[0].setTL(value & 0x3f);
597 break;
598
599 case 0x03:
600 patches[0].setKSL(1, (value >> 6) & 3);
601 patches[0].dcm = (value >> 3) & 3;
602 patches[0].setFB(value & 7);
603 break;
604
605 case 0x04:
606 case 0x05:
607 patches[0].setDR(slot, value & 0x0f);
608 patches[0].setAR(slot, (value >> 4) & 0x0f);
609 break;
610
611 case 0x06:
612 case 0x07:
613 patches[0].setRR(slot, value & 0x0f);
614 patches[0].sl[slot] = (value >> 4) & 0x0f;
615 break;
616
617 case 0x0e:
618 rhythm = value & 0x3f;
619 break;
620
621 case 0x0f:
622 testMode = value & 0x0f;
623 break;
624 }
625}
626
627template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::doOperator(std::span<float*, 9 + 5> out, bool eg_silent)
628{
629 bool ismod1 = ((rhythm & 0x20) && (CYCLES == one_of(14u, 15u)))
630 ? false
631 : (((CYCLES + 2) / 3) & 1);
632 constexpr bool is_next_mod3 = ((CYCLES + 2) / 3) & 1; // approximate: will 'ismod3' possibly be true next step
633
634 auto output = [&]() -> int32_t {
635 if (eg_silent) return 0;
636 auto prev2_phase = op_phase[(CYCLES - 2) & 1];
637 uint8_t quarter = narrow_cast<uint8_t>((prev2_phase & 0x100) ? ~prev2_phase : prev2_phase);
638 auto logSin = logSinTab[quarter];
639 auto op_level = std::min(4095, logSin + (eg_out[(CYCLES - 2) & 1] << 4));
640 uint32_t op_exp_m = expTab[op_level & 0xff];
641 auto op_exp_s = op_level >> 8;
642 if (prev2_phase & 0x200) {
643 return /*unlikely*/(c_dcm[(CYCLES + 16) % 3] & (ismod1 ? 1 : 2))
644 ? ~0
645 : ~(op_exp_m >> op_exp_s);
646 } else {
647 return narrow<int32_t>(op_exp_m >> op_exp_s);
648 }
649 }();
650
651 if (ismod1) {
652 constexpr uint32_t cycles9 = (CYCLES + 1) % 9;
653 op_fb2[cycles9] = op_fb1[cycles9];
654 op_fb1[cycles9] = narrow_cast<int16_t>(output);
655 }
656 channelOutput<CYCLES>(out, output >> 3);
657
658 if (is_next_mod3) {
659 op_mod = output & 0x1ff;
660 }
661}
662
663template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE uint32_t YM2413::getPhase(uint8_t& rm_hh_bits)
664{
665 uint32_t phase = pg_phase[CYCLES];
666
667 // Rhythm mode
668 if constexpr (CYCLES == 12) {
669 rm_hh_bits = narrow_cast<uint8_t>(phase >> (2 + 9));
670 } else if (CYCLES == 16 && (rhythm & 0x20)) {
671 rm_tc_bits = narrow_cast<uint8_t>(phase >> 8);
672 }
673
674 if (rhythm & 0x20) {
675 auto rm_bit = [&]() {
676 bool rm_hh_bit2 = (rm_hh_bits >> (2 - 2)) & 1;
677 bool rm_hh_bit3 = (rm_hh_bits >> (3 - 2)) & 1;
678 bool rm_hh_bit7 = (rm_hh_bits >> (7 - 2)) & 1;
679 bool rm_tc_bit3 = (rm_tc_bits >> (3 + 9 - 8)) & 1;
680 bool rm_tc_bit5 = (rm_tc_bits >> (5 + 9 - 8)) & 1;
681 return (rm_hh_bit2 ^ rm_hh_bit7)
682 | (rm_hh_bit3 ^ rm_tc_bit5)
683 | (rm_tc_bit3 ^ rm_tc_bit5);
684 };
685 auto noise_bit = [&]() {
686 // see comments in doRhythm()
687 return (rm_noise >> (TEST_MODE ? 0 : (CYCLES + 1))) & 1;
688 };
689 switch (CYCLES) {
690 case 12: { // HH
691 auto b = rm_bit();
692 return (b << 9) | ((b ^ noise_bit()) ? 0xd0 : 0x34);
693 }
694 case 15: { // SD
695 auto rm_hh_bit8 = (rm_hh_bits >> (8 - 2)) & 1;
696 return (rm_hh_bit8 << 9) | ((rm_hh_bit8 ^ noise_bit()) << 8);
697 }
698 case 16: // TC
699 return (rm_bit() << 9) | 0x100;
700 default:
701 break; // suppress warning
702 }
703 }
704 return phase >> 9;
705}
706
707template<uint32_t CYCLES> ALWAYS_INLINE uint32_t YM2413::phaseCalcIncrement(const Patch& patch1) const
708{
709 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
710 constexpr uint32_t ch = CH_OFFSET[CYCLES];
711
712 uint32_t incr = [&]() {
713 // Apply vibrato?
714 if (patch1.vib[mcsel]) {
715 // note: _must_ be '/ 256' rather than '>> 8' because of
716 // round-to-zero for negative values.
717 uint32_t freq = fnum[ch] << 1;
718 freq += (int(freq) * lfo_vib) / 256;
719 return (freq << block[ch]) >> 1;
720 } else {
721 return uint32_t(p_incr[ch]);
722 }
723 }();
724 return (incr * patch1.multi_t[mcsel]) >> 1;
725}
726
727template<uint32_t CYCLES> ALWAYS_INLINE bool YM2413::keyOnEvent() const
728{
729 bool ismod = ((rhythm & 0x20) && (CYCLES == one_of(12u, 13u)))
730 ? false
731 : (((CYCLES + 4) / 3) & 1);
732 return ismod ? eg_dokon[(CYCLES + 3) % 18]
733 : eg_dokon[CYCLES];
734}
735
736template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void YM2413::incrementPhase(uint32_t phase_incr, bool key_on_event)
737{
738 uint32_t pg_phase_next = ((TEST_MODE && (testMode & 4)) || key_on_event)
739 ? 0
740 : pg_phase[CYCLES];
741 pg_phase[CYCLES] = pg_phase_next + phase_incr;
742}
743
744template<uint32_t CYCLES> ALWAYS_INLINE void YM2413::channelOutput(std::span<float*, 9 + 5> out, int32_t ch_out)
745{
746 auto outF = narrow_cast<float>(ch_out);
747 switch (CYCLES) {
748 case 4: *out[ 0]++ += outF; break;
749 case 5: *out[ 1]++ += outF; break;
750 case 6: *out[ 2]++ += outF; break;
751 case 10: *out[ 3]++ += outF; break;
752 case 11: *out[ 4]++ += outF; break;
753 case 12: *out[ 5]++ += outF; break;
754 case 14: *out[ 9]++ += (rhythm & 0x20) ? 2.0f * outF : 0.0f; break;
755 case 15: *out[10]++ += narrow_cast<float>(delay10);
756 delay10 = (rhythm & 0x20) ? 2 * ch_out : 0; break;
757 case 16: *out[ 6]++ += narrow_cast<float>(delay6);
758 *out[11]++ += narrow_cast<float>(delay11);
759 delay6 = (rhythm & 0x20) ? 0 : ch_out;
760 delay11 = (rhythm & 0x20) ? 2 * ch_out : 0; break;
761 case 17: *out[ 7]++ += narrow_cast<float>(delay7);
762 *out[12]++ += narrow_cast<float>(delay12);
763 delay7 = (rhythm & 0x20) ? 0 : ch_out;
764 delay12 = (rhythm & 0x20) ? 2 * ch_out : 0; break;
765 case 0: *out[ 8]++ += (rhythm & 0x20) ? 0.0f : outF;
766 *out[13]++ += (rhythm & 0x20) ? 2.0f * outF : 0.0f; break;
767 default:
768 break; // suppress warning
769 }
770}
771
772template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE uint8_t YM2413::envelopeOutput(uint32_t ksltl, int8_t am_t) const
773{
774 if (TEST_MODE && (testMode & 1)) {
775 return 0;
776 }
777 int32_t level = eg_level[CYCLES] + ksltl + (am_t & lfo_am_out);
778 return narrow_cast<uint8_t>(std::min(127, level));
779}
780
781template<uint32_t CYCLES, bool TEST_MODE>
782ALWAYS_INLINE void YM2413::step(Locals& l)
783{
784 if constexpr (CYCLES == 11) {
785 // the value for 'use_rm_patches' is only meaningful in cycles 11..16
786 // and it remains constant during that time.
787 l.use_rm_patches = rhythm & 0x20;
788 }
789 const Patch& patch1 = preparePatch1<CYCLES>(l.use_rm_patches);
790 uint32_t ksltl = envelopeKSLTL<CYCLES>(patch1, l.use_rm_patches);
791 envelopeTimer1<CYCLES>();
792 bool eg_silent = envelopeGenerate1<CYCLES>();
793 envelopeTimer2<CYCLES, TEST_MODE>(l.eg_timer_carry);
794 envelopeGenerate2<CYCLES>(patch1, l.use_rm_patches);
795 bool key_on_event = keyOnEvent<CYCLES>();
796
797 doLFO<CYCLES, TEST_MODE>(l.lfo_am_car);
798 doRhythm<CYCLES, TEST_MODE>();
799 uint32_t phaseMod = getPhaseMod<CYCLES>(patch1.fb_t);
800
801 constexpr uint32_t mcsel = ((CYCLES + 1) / 3) & 1;
802 eg_sl[CYCLES & 1] = patch1.sl[mcsel];
803 auto patch2_am_t = patch1.am_t[mcsel];
804
805 uint32_t phase_incr = phaseCalcIncrement<CYCLES>(patch1);
806 c_dcm[CYCLES % 3] = patch1.dcm;
807
808 doRegWrite<CYCLES>();
809 doIO<CYCLES>();
810
811 doOperator<CYCLES>(l.out, eg_silent);
812
813 uint32_t pg_out = getPhase<CYCLES, TEST_MODE>(l.rm_hh_bits);
814 op_phase[CYCLES & 1] = narrow_cast<uint16_t>(phaseMod + pg_out);
815 incrementPhase<CYCLES, TEST_MODE>(phase_incr, key_on_event);
816
817 eg_out[CYCLES & 1] = envelopeOutput<CYCLES, TEST_MODE>(ksltl, patch2_am_t);
818}
819
820void YM2413::generateChannels(std::span<float*, 9 + 5> out_, uint32_t n)
821{
822 std::array<float*, 9 + 5> out;
823 ranges::copy(out_, out);
824
825 // Loop here (instead of in step18) seems faster. (why?)
826 if (test_mode_active) [[unlikely]] {
827 repeat(n, [&] { step18<true >(out); });
828 } else {
829 repeat(n, [&] { step18<false>(out); });
830 }
831 test_mode_active = testMode;
832}
833
834template<bool TEST_MODE>
835NEVER_INLINE void YM2413::step18(std::span<float*, 9 + 5> out)
836{
837 Locals l(out);
838 l.use_rm_patches = false; // avoid warning
839 l.lfo_am_car = false; // between cycle 17 and 0 'lfo_am_car' is always =0
840
841 step< 0, TEST_MODE>(l);
842 step< 1, TEST_MODE>(l);
843 step< 2, TEST_MODE>(l);
844 step< 3, TEST_MODE>(l);
845 step< 4, TEST_MODE>(l);
846 step< 5, TEST_MODE>(l);
847 step< 6, TEST_MODE>(l);
848 step< 7, TEST_MODE>(l);
849 step< 8, TEST_MODE>(l);
850 step< 9, TEST_MODE>(l);
851 step<10, TEST_MODE>(l);
852 step<11, TEST_MODE>(l);
853 step<12, TEST_MODE>(l);
854 step<13, TEST_MODE>(l);
855 step<14, TEST_MODE>(l);
856 step<15, TEST_MODE>(l);
857 step<16, TEST_MODE>(l);
858 step<17, TEST_MODE>(l);
859
860 allowed_offset = std::max<int>(0, allowed_offset - 18); // see writePort()
861}
862
863void YM2413::writePort(bool port, uint8_t value, int cycle_offset)
864{
865 // Hack: detect too-fast access and workaround that.
866 // Ideally we'd just pass this too-fast-access to the NukeYKY code,
867 // because it handles it 'fine' (as in "the same as the real
868 // hardware"). Possibly with a warning.
869 // Though currently in openMSX, when running at 'speed > 100%' we keep
870 // emulate the sound devices at 100% speed, but because CPU runs
871 // faster this can result in artificial too-fast-access. We need to
872 // solve this properly, but for now this hack should suffice.
873
874 if (speedUpHack) [[unlikely]] {
875 while (cycle_offset < allowed_offset) [[unlikely]] {
876 float d = 0.0f;
877 std::array<float*, 9 + 5> dummy = {
878 &d, &d, &d, &d, &d, &d, &d, &d, &d,
879 &d, &d, &d, &d, &d,
880 };
881 step18<false>(dummy); // discard result
882 }
883 // Need 12 cycles (@3.57MHz) wait after address-port access, 84 cycles
884 // after data-port access. Divide by 4 to translate to our 18-step
885 // timescale.
886 allowed_offset = ((port ? 84 : 12) / 4) + cycle_offset;
887 }
888
889 writes[cycle_offset] = {port, value};
890 if (port && (write_address == 0xf)) {
891 test_mode_active = true;
892 }
893
894 // only needed for peekReg()
895 if (port == 0) {
896 latch = value & 63;
897 } else {
898 regs[latch] = value;
899 }
900}
901
902void YM2413::pokeReg(uint8_t reg, uint8_t value)
903{
904 regs[reg] = value;
905 if (reg < 0x10) {
906 doModeWrite(reg, value);
907 } else {
908 if (uint8_t ch = reg & 0xf; ch < 9) {
909 doRegWrite(reg & 0xf0, ch, value);
910 }
911 }
912}
913
914uint8_t YM2413::peekReg(uint8_t reg) const
915{
916 return regs[reg & 63];
917}
918
920{
921 return 1.0f / 256.0f;
922}
923
924void YM2413::setSpeed(double speed)
925{
926 speedUpHack = speed > 1.0;
927}
928
929} // namespace YM2413NukeYKT
930
931
932static constexpr std::initializer_list<enum_string<YM2413NukeYKT::YM2413::EgState>> egStateInfo = {
937};
939
940namespace YM2413NukeYKT {
941
942template<typename Archive>
943void YM2413::Write::serialize(Archive& ar, unsigned /*version*/)
944{
945 ar.serialize("port", port,
946 "value", value);
947}
948
949template<typename Archive>
950void YM2413::serialize(Archive& ar, unsigned /*version*/)
951{
952 ar.serialize("writes", writes,
953 "write_data", write_data,
954 "fm_data", fm_data,
955 "write_address", write_address,
956 "write_fm_cycle", write_fm_cycle,
957 "fast_fm_rewrite", fast_fm_rewrite,
958 "test_mode_active", test_mode_active);
959
960 ar.serialize("eg_timer", eg_timer,
961 "eg_sl", eg_sl,
962 "eg_out", eg_out,
963 "eg_counter_state", eg_counter_state,
964 "eg_timer_shift", eg_timer_shift,
965 "eg_timer_shift_lock", eg_timer_shift_lock,
966 "eg_timer_lock", eg_timer_lock,
967 "eg_state", eg_state,
968 "eg_level", eg_level,
969 "eg_rate", eg_rate,
970 "eg_dokon", eg_dokon,
971 "eg_kon", eg_kon,
972 "eg_off", eg_off,
973 "eg_timer_shift_stop", eg_timer_shift_stop,
974 "pg_phase", pg_phase);
975
976 ar.serialize("op_fb1", op_fb1,
977 "op_fb2", op_fb2,
978 "op_mod", op_mod,
979 "op_phase", op_phase,
980 "lfo_counter", lfo_counter,
981 "lfo_am_counter", lfo_am_counter,
982 "lfo_vib_counter", lfo_vib_counter,
983 "lfo_am_out", lfo_am_out,
984 "lfo_am_step", lfo_am_step,
985 "lfo_am_dir", lfo_am_dir);
986
987 ar.serialize("rm_noise", rm_noise,
988 "rm_tc_bits", rm_tc_bits,
989 "c_dcm", c_dcm,
990 "regs", regs,
991 "latch", latch);
992
993 if constexpr (Archive::IS_LOADER) {
994 // restore redundant state
995 attackPtr = attack[eg_timer_shift_lock][eg_timer_lock];
996 auto idx = releaseIndex[eg_timer_shift_lock][eg_timer_lock][eg_counter_state];
997 releasePtr = releaseData[idx];
998
999 lfo_vib = VIB_TAB[lfo_vib_counter];
1000
1001 delay6 = delay7 = delay10 = delay11 = delay12 = 0;
1002
1003 // Restore these from register values:
1004 // fnum, block, p_ksl, p_incr, p_ksr_freq, sk_on, vol8,
1005 // inst, p_inst, rhythm, testMode, patches[0]
1006 for (auto i : xrange(uint8_t(64))) {
1007 pokeReg(i, regs[i]);
1008 }
1009 }
1010}
1011
1012} // namespace YM2413NukeYKT
1013
1017
1018} // namespace openmsx
Abstract interface for the YM2413 core.
Definition YM2413Core.hh:28
uint8_t peekReg(uint8_t reg) const override
Read from a YM2413 register (for debug).
void writePort(bool port, uint8_t value, int cycle_offset) override
Write to the YM2413 register/data port.
void setSpeed(double speed) override
Sets real-time speed factor (aka the openMSX 'speed' setting).
float getAmplificationFactor() const override
Returns normalization factor.
void pokeReg(uint8_t reg, uint8_t value) override
Write to a YM2413 register (for debug).
void serialize(Archive &ar, unsigned version)
void generateChannels(std::span< float *, 9+5 > out, uint32_t n) override
void reset() override
Reset this YM2413 core.
#define NEVER_INLINE
Definition inline.hh:17
#define ALWAYS_INLINE
Definition inline.hh:16
unsigned findFirstSet(uint32_t x)
Find the least significant bit that is set.
Definition Math.hh:149
constexpr double pi
Definition Math.hh:24
constexpr double round(double x)
Definition cstd.hh:247
constexpr bool is_rm_cycle(int cycle)
constexpr RmNum rm_for_cycle(int cycle)
This file implemented 3 utility functions:
Definition Autofire.cc:9
constexpr void fill(ForwardRange &&range, const T &value)
Definition ranges.hh:305
auto copy(InputRange &&range, OutputIter out)
Definition ranges.hh:250
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
Definition ranges.hh:471
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define SERIALIZE_ENUM(TYPE, INFO)
#define REGISTER_POLYMORPHIC_INITIALIZER(BASE, CLASS, NAME)
#define UNREACHABLE
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
Definition xrange.hh:147
constexpr auto xrange(T e)
Definition xrange.hh:132