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