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