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