openMSX
YMF278.cc
Go to the documentation of this file.
1// Based on ymf278b.c written by R. Belmont and O. Galibert
2
3// Improved by Valley Bell, 2018
4// Thanks to niekniek and l_oliveira for providing recordings from OPL4 hardware.
5// Thanks to superctr and wouterv for discussing changes.
6//
7// Improvements:
8// - added TL interpolation, recordings show that internal TL levels are 0x00..0xff
9// - fixed ADSR speeds, attack rate 15 is now instant
10// - correct clamping of intermediate Rate Correction values
11// - emulation of "loop glitch" (going out-of-bounds by playing a sample faster than it the loop is long)
12// - made calculation of sample position cleaner and closer to how the HW works
13// - increased output resolution from TL (0.375dB) to envelope (0.09375dB)
14// - fixed volume table -6dB steps are done using bit shifts, steps in between are multiplicators
15// - made octave -8 freeze the sample
16// - verified that TL and envelope levels are applied separately, both go silent at -60dB
17// - implemented pseudo-reverb and damping according to manual
18// - made pseudo-reverb ignore Rate Correction (real hardware ignores it)
19// - reimplemented LFO, speed exactly matches the formulas that were probably used when creating the manual
20// - fixed LFO (tremolo) amplitude modulation
21// - made LFO vibrato and tremolo accurate to hardware
22//
23// Known issues:
24// - Octave -8 was only tested with fnum 0. Other fnum values might behave differently.
25
26// This class doesn't model a full YMF278b chip. Instead it only models the
27// wave part. The FM part in modeled in YMF262 (it's almost 100% compatible,
28// the small differences are handled in YMF262). The status register and
29// interaction with the FM registers (e.g. the NEW2 bit) is currently handled
30// in the MSXMoonSound class.
31
32#include "YMF278.hh"
33
34#include "DeviceConfig.hh"
35#include "MSXException.hh"
36#include "MSXMotherBoard.hh"
37#include "serialize.hh"
38
39#include "enumerate.hh"
40#include "narrow.hh"
41#include "one_of.hh"
42#include "outer.hh"
43#include "ranges.hh"
44#include "xrange.hh"
45
46#include <algorithm>
47
48namespace openmsx {
49
50// envelope output entries
51// fixed to match recordings from actual OPL4 -Valley Bell
52static constexpr int MAX_ATT_INDEX = 0x280; // makes attack phase right and also goes well with "envelope stops at -60dB"
53static constexpr int MIN_ATT_INDEX = 0;
54static constexpr int TL_SHIFT = 2; // envelope values are 4x as fine as TL levels
55
56static constexpr unsigned LFO_SHIFT = 18; // LFO period of up to 0x40000 sample
57static constexpr unsigned LFO_PERIOD = 1 << LFO_SHIFT;
58
59// Envelope Generator phases
60static constexpr int EG_ATT = 4;
61static constexpr int EG_DEC = 3;
62static constexpr int EG_SUS = 2;
63static constexpr int EG_REL = 1;
64static constexpr int EG_OFF = 0;
65// these 2 are only used in old savestates (and are converted to EG_REL on load)
66static constexpr int EG_REV = 5; // pseudo reverb
67static constexpr int EG_DMP = 6; // damp
68
69// Pan values, units are -3dB, i.e. 8.
70static constexpr std::array<uint8_t, 16> pan_left = {
71 0, 8, 16, 24, 32, 40, 48, 255, 255, 0, 0, 0, 0, 0, 0, 0
72};
73static constexpr std::array<uint8_t, 16> pan_right = {
74 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 48, 40, 32, 24, 16, 8
75};
76
77// decay level table (3dB per step)
78// 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)
79static constexpr int16_t SC(int dB) { return int16_t(dB / 3 * 0x20); }
80static constexpr std::array<int16_t, 16> dl_tab = {
81 SC( 0), SC( 3), SC( 6), SC( 9), SC(12), SC(15), SC(18), SC(21),
82 SC(24), SC(27), SC(30), SC(33), SC(36), SC(39), SC(42), SC(93)
83};
84
85static constexpr uint8_t RATE_STEPS = 8;
86static constexpr std::array<uint8_t, 15 * RATE_STEPS> eg_inc = {
87//cycle:0 1 2 3 4 5 6 7
88 0, 1, 0, 1, 0, 1, 0, 1, // 0 rates 00..12 0 (increment by 0 or 1)
89 0, 1, 0, 1, 1, 1, 0, 1, // 1 rates 00..12 1
90 0, 1, 1, 1, 0, 1, 1, 1, // 2 rates 00..12 2
91 0, 1, 1, 1, 1, 1, 1, 1, // 3 rates 00..12 3
92
93 1, 1, 1, 1, 1, 1, 1, 1, // 4 rate 13 0 (increment by 1)
94 1, 1, 1, 2, 1, 1, 1, 2, // 5 rate 13 1
95 1, 2, 1, 2, 1, 2, 1, 2, // 6 rate 13 2
96 1, 2, 2, 2, 1, 2, 2, 2, // 7 rate 13 3
97
98 2, 2, 2, 2, 2, 2, 2, 2, // 8 rate 14 0 (increment by 2)
99 2, 2, 2, 4, 2, 2, 2, 4, // 9 rate 14 1
100 2, 4, 2, 4, 2, 4, 2, 4, // 10 rate 14 2
101 2, 4, 4, 4, 2, 4, 4, 4, // 11 rate 14 3
102
103 4, 4, 4, 4, 4, 4, 4, 4, // 12 rates 15 0, 15 1, 15 2, 15 3 for decay
104 8, 8, 8, 8, 8, 8, 8, 8, // 13 rates 15 0, 15 1, 15 2, 15 3 for attack (zero time)
105 0, 0, 0, 0, 0, 0, 0, 0, // 14 infinity rates for attack and decay(s)
106};
107
108[[nodiscard]] static constexpr uint8_t O(int a) { return narrow<uint8_t>(a * RATE_STEPS); }
109static constexpr std::array<uint8_t, 64> eg_rate_select = {
110 O(14),O(14),O(14),O(14), // inf rate
111 O( 0),O( 1),O( 2),O( 3),
112 O( 0),O( 1),O( 2),O( 3),
113 O( 0),O( 1),O( 2),O( 3),
114 O( 0),O( 1),O( 2),O( 3),
115 O( 0),O( 1),O( 2),O( 3),
116 O( 0),O( 1),O( 2),O( 3),
117 O( 0),O( 1),O( 2),O( 3),
118 O( 0),O( 1),O( 2),O( 3),
119 O( 0),O( 1),O( 2),O( 3),
120 O( 0),O( 1),O( 2),O( 3),
121 O( 0),O( 1),O( 2),O( 3),
122 O( 0),O( 1),O( 2),O( 3),
123 O( 4),O( 5),O( 6),O( 7),
124 O( 8),O( 9),O(10),O(11),
125 O(12),O(12),O(12),O(12),
126};
127
128// rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
129// shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0
130// mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0
131static constexpr std::array<uint8_t, 64> eg_rate_shift = {
132 12, 12, 12, 12,
133 11, 11, 11, 11,
134 10, 10, 10, 10,
135 9, 9, 9, 9,
136 8, 8, 8, 8,
137 7, 7, 7, 7,
138 6, 6, 6, 6,
139 5, 5, 5, 5,
140 4, 4, 4, 4,
141 3, 3, 3, 3,
142 2, 2, 2, 2,
143 1, 1, 1, 1,
144 0, 0, 0, 0,
145 0, 0, 0, 0,
146 0, 0, 0, 0,
147 0, 0, 0, 0,
148};
149
150
151// number of steps the LFO counter advances per sample
152// LFO frequency (Hz) -> LFO counter steps per sample
153[[nodiscard]] static constexpr int L(double a) { return int((LFO_PERIOD * a) / 44100.0 + 0.5); }
154static constexpr std::array<int, 8> lfo_period = {
155 L(0.168), // step: 1, period: 262144 samples
156 L(2.019), // step: 12, period: 21845 samples
157 L(3.196), // step: 19, period: 13797 samples
158 L(4.206), // step: 25, period: 10486 samples
159 L(5.215), // step: 31, period: 8456 samples
160 L(5.888), // step: 35, period: 7490 samples
161 L(6.224), // step: 37, period: 7085 samples
162 L(7.066), // step: 42, period: 6242 samples
163};
164
165
166// formula used by Yamaha docs:
167// vib_depth_cents(x) = (log2(0x400 + x) - 10) * 1200
168static constexpr std::array<int16_t, 8> vib_depth = {
169 0, // 0.000 cents
170 2, // 3.378 cents
171 3, // 5.065 cents
172 4, // 6.750 cents
173 6, // 10.114 cents
174 12, // 20.170 cents
175 24, // 40.106 cents
176 48, // 79.307 cents
177};
178
179
180// formula used by Yamaha docs:
181// am_depth_db(x) = (x-1) / 0x40 * 6.0
182// They use (x-1), because the depth is multiplied with the AM counter, which has a range of 0..0x7F.
183// Thus the maximum attenuation with x=0x80 is (0x7F * 0x80) >> 7 = 0x7F.
184// reversed formula:
185// am_depth(dB) = round(dB / 6.0 * 0x40) + 1
186static constexpr std::array<uint8_t, 8> am_depth = {
187 0x00, // 0.000 dB
188 0x14, // 1.781 dB
189 0x20, // 2.906 dB
190 0x28, // 3.656 dB
191 0x30, // 4.406 dB
192 0x40, // 5.906 dB
193 0x50, // 7.406 dB
194 0x80, // 11.910 dB
195};
196
197
198YMF278::Slot::Slot()
199{
200 reset();
201}
202
203// Sign extend a 4-bit value to int8_t
204// require: x in range [0..15]
205[[nodiscard]] static constexpr int8_t sign_extend_4(int x)
206{
207 return narrow<int8_t>((x ^ 8) - 8);
208}
209
210// Params: oct in [-8 .. +7]
211// fn in [ 0 .. 1023]
212// We want to interpret oct as a signed 4-bit number and calculate
213// ((fn | 1024) + vib) << (5 + sign_extend_4(oct))
214// Though in this formula the shift can go over a negative distance (in that
215// case we should shift in the other direction).
216[[nodiscard]] static constexpr unsigned calcStep(int8_t oct, uint16_t fn, int16_t vib = 0)
217{
218 if (oct == -8) return 0;
219 unsigned t = (fn + 1024 + vib) << (8 + oct); // use '+' iso '|' (generates slightly better code)
220 return t >> 3; // was shifted 3 positions too far
221}
222
223void YMF278::Slot::reset()
224{
225 wave = FN = TLdest = TL = pan = vib = AM = 0;
226 OCT = 0;
227 DL = 0;
228 AR = D1R = D2R = RC = RR = 0;
229 PRVB = keyon = DAMP = false;
230 stepPtr = 0;
231 step = calcStep(OCT, FN);
232 bits = 0;
233 startAddr = 0;
234 loopAddr = endAddr = 0;
235 env_vol = MAX_ATT_INDEX;
236
237 lfo_active = false;
238 lfo_cnt = 0;
239 lfo = 0;
240
241 state = EG_OFF;
242
243 // not strictly needed, but avoid UMR on savestate
244 pos = 0;
245}
246
247uint8_t YMF278::Slot::compute_rate(int val) const
248{
249 if (val == 0) {
250 return 0;
251 } else if (val == 15) {
252 return 63;
253 }
254 int res = val * 4;
255 if (RC != 15) {
256 // clamping verified with HW tests -Valley Bell
257 res += 2 * std::clamp(OCT + RC, 0, 15);
258 res += (FN & 0x200) ? 1 : 0;
259 }
260 return narrow<uint8_t>(std::clamp(res, 0, 63));
261}
262
263uint8_t YMF278::Slot::compute_decay_rate(int val) const
264{
265 if (DAMP) {
266 // damping
267 // The manual lists these values for time and attenuation: (44100 samples/second)
268 // -12dB at 5.8ms, sample 256
269 // -48dB at 8.0ms, sample 352
270 // -72dB at 9.4ms, sample 416
271 // -96dB at 10.9ms, sample 480
272 // This results in these durations and rate values for the respective phases:
273 // 0dB .. -12dB: 256 samples (5.80ms) -> 128 samples per -6dB = rate 48
274 // -12dB .. -48dB: 96 samples (2.18ms) -> 16 samples per -6dB = rate 63
275 // -48dB .. -72dB: 64 samples (1.45ms) -> 16 samples per -6dB = rate 63
276 // -72dB .. -96dB: 64 samples (1.45ms) -> 16 samples per -6dB = rate 63
277 // Damping was verified to ignore rate correction.
278 if (env_vol < dl_tab[4]) {
279 return 48; // 0dB .. -12dB
280 } else {
281 return 63; // -12dB .. -96dB
282 }
283 }
284 if (PRVB) {
285 // pseudo reverb
286 // activated when reaching -18dB, overrides D1R/D2R/RR with reverb rate 5
287 //
288 // The manual is actually a bit unclear and just says "RATE=5",
289 // referring to the D1R/D2R/RR register value. However, later
290 // pages use "RATE" to refer to the "internal" rate, which is
291 // (register * 4) + rate correction. HW recordings prove that
292 // Rate Correction is ignored, so pseudo reverb just sets the
293 // "internal" rate to a value of 4*5 = 20.
294 if (env_vol >= dl_tab[6]) {
295 return 20;
296 }
297 }
298 return compute_rate(val);
299}
300
301int16_t YMF278::Slot::compute_vib() const
302{
303 // verified via hardware recording:
304 // With LFO speed 0 (period 262144 samples), each vibrato step takes
305 // 4096 samples.
306 // -> 64 steps total
307 // Also, with vibrato depth 7 (80 cents) and an F-Num of 0x400, the
308 // final F-Nums are: 0x400 .. 0x43C, 0x43C .. 0x400, 0x400 .. 0x3C4,
309 // 0x3C4 .. 0x400
310 auto lfo_fm = narrow<int16_t>(lfo_cnt / (LFO_PERIOD / 0x40));
311 // results in +0x00..+0x0F, +0x0F..+0x00, -0x00..-0x0F, -0x0F..-0x00
312 if (lfo_fm & 0x10) lfo_fm ^= 0x1F;
313 if (lfo_fm & 0x20) lfo_fm = narrow<int16_t>(-(lfo_fm & 0x0F));
314
315 return narrow<int16_t>((lfo_fm * vib_depth[vib]) / 12);
316}
317
318uint16_t YMF278::Slot::compute_am() const
319{
320 // verified via hardware recording:
321 // With LFO speed 0 (period 262144 samples), each tremolo step takes
322 // 1024 samples.
323 // -> 256 steps total
324 auto lfo_am = narrow<uint16_t>(lfo_cnt / (LFO_PERIOD / 0x100));
325 // results in 0x00..0x7F, 0x7F..0x00
326 if (lfo_am >= 0x80) lfo_am ^= 0xFF;
327
328 return narrow<uint16_t>((lfo_am * am_depth[AM]) >> 7);
329}
330
331
332void YMF278::advance()
333{
334 eg_cnt++;
335
336 // modulo counters for volume interpolation
337 auto tl_int_cnt = eg_cnt % 9; // 0 .. 8
338 auto tl_int_step = (eg_cnt / 9) % 3; // 0 .. 2
339
340 for (auto& op : slots) {
341 // volume interpolation
342 if (tl_int_cnt == 0) {
343 if (tl_int_step == 0) {
344 // decrease volume by one step every 27 samples
345 if (op.TL < op.TLdest) ++op.TL;
346 } else {
347 // increase volume by one step every 13.5 samples
348 if (op.TL > op.TLdest) --op.TL;
349 }
350 }
351
352 if (op.lfo_active) {
353 op.lfo_cnt = (op.lfo_cnt + lfo_period[op.lfo]) & (LFO_PERIOD - 1);
354 }
355
356 // Envelope Generator
357 switch (op.state) {
358 case EG_ATT: { // attack phase
359 uint8_t rate = op.compute_rate(op.AR);
360 // Verified by HW recording (and matches Nemesis' tests of the YM2612):
361 // AR = 0xF during KeyOn results in instant switch to EG_DEC. (see keyOnHelper)
362 // Setting AR = 0xF while the attack phase is in progress freezes the envelope.
363 if (rate >= 63) {
364 break;
365 }
366 uint8_t shift = eg_rate_shift[rate];
367 if (!(eg_cnt & ((1 << shift) - 1))) {
368 uint8_t select = eg_rate_select[rate];
369 // >>4 makes the attack phase's shape match the actual chip -Valley Bell
370 op.env_vol = narrow<int16_t>(op.env_vol + ((~op.env_vol * eg_inc[select + ((eg_cnt >> shift) & 7)]) >> 4));
371 if (op.env_vol <= MIN_ATT_INDEX) {
372 op.env_vol = MIN_ATT_INDEX;
373 // TODO does the real HW skip EG_DEC completely,
374 // or is it active for 1 sample?
375 op.state = op.DL ? EG_DEC : EG_SUS;
376 }
377 }
378 break;
379 }
380 case EG_DEC: { // decay phase
381 uint8_t rate = op.compute_decay_rate(op.D1R);
382 uint8_t shift = eg_rate_shift[rate];
383 if (!(eg_cnt & ((1 << shift) - 1))) {
384 uint8_t select = eg_rate_select[rate];
385 op.env_vol = narrow<int16_t>(op.env_vol + eg_inc[select + ((eg_cnt >> shift) & 7)]);
386 if (op.env_vol >= op.DL) {
387 op.state = (op.env_vol < MAX_ATT_INDEX) ? EG_SUS : EG_OFF;
388 }
389 }
390 break;
391 }
392 case EG_SUS: { // sustain phase
393 uint8_t rate = op.compute_decay_rate(op.D2R);
394 uint8_t shift = eg_rate_shift[rate];
395 if (!(eg_cnt & ((1 << shift) - 1))) {
396 uint8_t select = eg_rate_select[rate];
397 op.env_vol = narrow<int16_t>(op.env_vol + eg_inc[select + ((eg_cnt >> shift) & 7)]);
398 if (op.env_vol >= MAX_ATT_INDEX) {
399 op.env_vol = MAX_ATT_INDEX;
400 op.state = EG_OFF;
401 }
402 }
403 break;
404 }
405 case EG_REL: { // release phase
406 uint8_t rate = op.compute_decay_rate(op.RR);
407 uint8_t shift = eg_rate_shift[rate];
408 if (!(eg_cnt & ((1 << shift) - 1))) {
409 uint8_t select = eg_rate_select[rate];
410 op.env_vol = narrow<int16_t>(op.env_vol + eg_inc[select + ((eg_cnt >> shift) & 7)]);
411 if (op.env_vol >= MAX_ATT_INDEX) {
412 op.env_vol = MAX_ATT_INDEX;
413 op.state = EG_OFF;
414 }
415 }
416 break;
417 }
418 case EG_OFF:
419 // nothing
420 break;
421
422 default:
424 }
425 }
426}
427
428int16_t YMF278::getSample(const Slot& slot, uint16_t pos) const
429{
430 // TODO How does this behave when R#2 bit 0 = 1?
431 // As-if read returns 0xff? (Like for CPU memory reads.) Or is
432 // sound generation blocked at some higher level?
433 switch (slot.bits) {
434 case 0: {
435 // 8 bit
436 return narrow_cast<int16_t>(readMem(slot.startAddr + pos) << 8);
437 }
438 case 1: {
439 // 12 bit
440 unsigned addr = slot.startAddr + ((pos / 2) * 3);
441 if (pos & 1) {
442 return narrow_cast<int16_t>(
443 (readMem(addr + 2) << 8) |
444 (readMem(addr + 1) & 0xF0));
445 } else {
446 return narrow_cast<int16_t>(
447 (readMem(addr + 0) << 8) |
448 ((readMem(addr + 1) << 4) & 0xF0));
449 }
450 }
451 case 2: {
452 // 16 bit
453 unsigned addr = slot.startAddr + (pos * 2);
454 return narrow_cast<int16_t>(
455 (readMem(addr + 0) << 8) |
456 (readMem(addr + 1) << 0));
457 }
458 default:
459 // TODO unspecified
460 return 0;
461 }
462}
463
464uint16_t YMF278::nextPos(const Slot& slot, uint16_t pos, uint16_t increment)
465{
466 // If there is a 4-sample loop and you advance 12 samples per step,
467 // it may exceed the end offset.
468 // This is abused by the "Lizard Star" song to generate noise at 0:52. -Valley Bell
469 pos += increment;
470 if ((uint32_t(pos) + slot.endAddr) >= 0x10000) // check position >= (negated) end address
471 pos += narrow_cast<uint16_t>(slot.endAddr + slot.loopAddr); // This is how the actual chip does it.
472 return pos;
473}
474
475bool YMF278::anyActive()
476{
477 return ranges::any_of(slots, [](auto& op) { return op.state != EG_OFF; });
478}
479
480// In: 'envVol', 0=max volume, others -> -3/32 = -0.09375 dB/step
481// Out: 'x' attenuated by the corresponding factor.
482// Note: microbenchmarks have shown that re-doing this calculation is about the
483// same speed as using a 4kB lookup table.
484static constexpr int vol_factor(int x, unsigned envVol)
485{
486 if (envVol >= MAX_ATT_INDEX) return 0; // hardware clips to silence below -60dB
487 int vol_mul = 0x80 - narrow<int>(envVol & 0x3F); // 0x40 values per 6dB
488 int vol_shift = 7 + narrow<int>(envVol >> 6);
489 return (x * ((0x8000 * vol_mul) >> vol_shift)) >> 15;
490}
491
492void YMF278::setMixLevel(uint8_t x, EmuTime::param time)
493{
494 static constexpr std::array<float, 8> level = {
495 (1.00f / 1), // 0dB
496 (0.75f / 1), // -3dB (approx)
497 (1.00f / 2), // -6dB
498 (0.75f / 2), // -9dB (approx)
499 (1.00f / 4), // -12dB
500 (0.75f / 4), // -15dB (approx)
501 (1.00f / 8), // -18dB
502 0.00f // -inf dB
503 };
504 setSoftwareVolume(level[x & 7], level[(x >> 3) & 7], time);
505}
506
507void YMF278::generateChannels(std::span<float*> bufs, unsigned num)
508{
509 if (!anyActive()) {
510 // TODO update internal state, even if muted
511 // TODO also mute individual channels
512 ranges::fill(bufs, nullptr);
513 return;
514 }
515
516 for (auto j : xrange(num)) {
517 for (auto i : xrange(24)) {
518 auto& sl = slots[i];
519 if (sl.state == EG_OFF) {
520 //bufs[i][2 * j + 0] += 0;
521 //bufs[i][2 * j + 1] += 0;
522 continue;
523 }
524
525 auto sample = narrow_cast<int16_t>(
526 (getSample(sl, sl.pos) * (0x10000 - sl.stepPtr) +
527 getSample(sl, nextPos(sl, sl.pos, 1)) * sl.stepPtr) >> 16);
528 // TL levels are 00..FF internally (TL register value 7F is mapped to TL level FF)
529 // Envelope levels have 4x the resolution (000..3FF)
530 // Volume levels are approximate logarithmic. -6dB result in half volume. Steps in between use linear interpolation.
531 // A volume of -60dB or lower results in silence. (value 0x280..0x3FF).
532 // Recordings from actual hardware indicate that TL level and envelope level are applied separately.
533 // Each of them is clipped to silence below -60dB, but TL+envelope might result in a lower volume. -Valley Bell
534 auto envVol = narrow_cast<uint16_t>(
535 std::min(sl.env_vol + ((sl.lfo_active && sl.AM) ? sl.compute_am() : 0),
536 MAX_ATT_INDEX));
537 int smplOut = vol_factor(vol_factor(sample, envVol), sl.TL << TL_SHIFT);
538
539 // Panning is also done separately. (low-volume TL + low-volume panning goes below -60dB)
540 // I'll be taking wild guess and assume that -3dB is approximated with 75%. (same as with TL and envelope levels)
541 // The same applies to the PCM mix level.
542 int32_t volLeft = pan_left [sl.pan]; // note: register 0xF9 is handled externally
543 int32_t volRight = pan_right[sl.pan];
544 // 0 -> 0x20, 8 -> 0x18, 16 -> 0x10, 24 -> 0x0C, etc. (not using vol_factor here saves array boundary checks)
545 volLeft = (0x20 - (volLeft & 0x0f)) >> (volLeft >> 4);
546 volRight = (0x20 - (volRight & 0x0f)) >> (volRight >> 4);
547
548 bufs[i][2 * j + 0] += narrow_cast<float>((smplOut * volLeft ) >> 5);
549 bufs[i][2 * j + 1] += narrow_cast<float>((smplOut * volRight) >> 5);
550
551 unsigned step = (sl.lfo_active && sl.vib)
552 ? calcStep(sl.OCT, sl.FN, sl.compute_vib())
553 : sl.step;
554 sl.stepPtr += step;
555
556 if (sl.stepPtr >= 0x10000) {
557 sl.pos = nextPos(sl, sl.pos, narrow<uint16_t>(sl.stepPtr >> 16));
558 sl.stepPtr &= 0xffff;
559 }
560 }
561 advance();
562 }
563}
564
565void YMF278::keyOnHelper(YMF278::Slot& slot) const
566{
567 // Unlike FM, the envelope level is reset. (And it makes sense, because you restart the sample.)
568 slot.env_vol = MAX_ATT_INDEX;
569 if (slot.compute_rate(slot.AR) < 63) {
570 slot.state = EG_ATT;
571 } else {
572 // Nuke.YKT verified that the FM part does it exactly this way,
573 // and the OPL4 manual says it's instant as well.
574 slot.env_vol = MIN_ATT_INDEX;
575 // see comment in 'case EG_ATT' in YMF278::advance()
576 slot.state = slot.DL ? EG_DEC : EG_SUS;
577 }
578 slot.stepPtr = 0;
579 slot.pos = 0;
580}
581
582void YMF278::writeReg(uint8_t reg, uint8_t data, EmuTime::param time)
583{
584 updateStream(time); // TODO optimize only for regs that directly influence sound
585 writeRegDirect(reg, data, time);
586}
587
588void YMF278::writeRegDirect(uint8_t reg, uint8_t data, EmuTime::param time)
589{
590 // Handle slot registers specifically
591 if (reg >= 0x08 && reg <= 0xF7) {
592 int sNum = (reg - 8) % 24;
593 auto& slot = slots[sNum];
594 switch ((reg - 8) / 24) {
595 case 0: {
596 slot.wave = (slot.wave & 0x100) | data;
597 int waveTblHdr = (regs[2] >> 2) & 0x7;
598 int base = (slot.wave < 384 || !waveTblHdr) ?
599 (slot.wave * 12) :
600 (waveTblHdr * 0x80000 + ((slot.wave - 384) * 12));
601 std::array<uint8_t, 12> buf;
602 for (auto i : xrange(12)) {
603 // TODO What if R#2 bit 0 = 1?
604 // See also getSample()
605 buf[i] = readMem(base + i);
606 }
607 slot.bits = (buf[0] & 0xC0) >> 6;
608 slot.startAddr = buf[2] | (buf[1] << 8) | ((buf[0] & 0x3F) << 16);
609 slot.loopAddr = uint16_t(buf[4] | (buf[3] << 8));
610 slot.endAddr = uint16_t(buf[6] | (buf[5] << 8));
611 for (auto i : xrange(7, 12)) {
612 // Verified on real YMF278:
613 // After tone loading, if you read these
614 // registers, their value actually has changed.
615 writeRegDirect(narrow<uint8_t>(8 + sNum + (i - 2) * 24), buf[i], time);
616 }
617 if (slot.keyon) {
618 keyOnHelper(slot);
619 } else {
620 slot.stepPtr = 0;
621 slot.pos = 0;
622 }
623 break;
624 }
625 case 1: {
626 slot.wave = uint16_t((slot.wave & 0xFF) | ((data & 0x1) << 8));
627 slot.FN = (slot.FN & 0x380) | (data >> 1);
628 slot.step = calcStep(slot.OCT, slot.FN);
629 break;
630 }
631 case 2: {
632 slot.FN = uint16_t((slot.FN & 0x07F) | ((data & 0x07) << 7));
633 slot.PRVB = (data & 0x08) != 0;
634 slot.OCT = sign_extend_4((data & 0xF0) >> 4);
635 slot.step = calcStep(slot.OCT, slot.FN);
636 break;
637 }
638 case 3: {
639 uint8_t t = data >> 1;
640 slot.TLdest = (t != 0x7f) ? t : 0xff; // verified on HW via volume interpolation
641 if (data & 1) {
642 // directly change volume
643 slot.TL = slot.TLdest;
644 } else {
645 // interpolate volume
646 }
647 break;
648 }
649 case 4:
650 if (data & 0x10) {
651 // output to DO1 pin:
652 // this pin is not used in MoonSound
653 // we emulate this by muting the sound
654 slot.pan = 8; // both left/right -inf dB
655 } else {
656 slot.pan = data & 0x0F;
657 }
658
659 if (data & 0x20) {
660 // LFO reset
661 slot.lfo_active = false;
662 slot.lfo_cnt = 0;
663 } else {
664 // LFO activate
665 slot.lfo_active = true;
666 }
667
668 slot.DAMP = (data & 0x40) != 0;
669
670 if (data & 0x80) {
671 if (!slot.keyon) {
672 slot.keyon = true;
673 keyOnHelper(slot);
674 }
675 } else {
676 if (slot.keyon) {
677 slot.keyon = false;
678 slot.state = EG_REL;
679 }
680 }
681 break;
682 case 5:
683 slot.lfo = (data >> 3) & 0x7;
684 slot.vib = data & 0x7;
685 break;
686 case 6:
687 slot.AR = data >> 4;
688 slot.D1R = data & 0xF;
689 break;
690 case 7:
691 slot.DL = dl_tab[data >> 4];
692 slot.D2R = data & 0xF;
693 break;
694 case 8:
695 slot.RC = data >> 4;
696 slot.RR = data & 0xF;
697 break;
698 case 9:
699 slot.AM = data & 0x7;
700 break;
701 }
702 } else {
703 // All non-slot registers
704 switch (reg) {
705 case 0x00: // TEST
706 case 0x01:
707 break;
708
709 case 0x02:
710 // wave-table-header / memory-type / memory-access-mode
711 // Simply store in regs[2]
712 break;
713
714 case 0x03:
715 // Verified on real YMF278:
716 // * Don't update the 'memAdr' variable on writes to
717 // reg 3 and 4. Only store the value in the 'regs'
718 // array for later use.
719 // * The upper 2 bits are not used to address the
720 // external memories (so from a HW pov they don't
721 // matter). But if you read back this register, the
722 // upper 2 bits always read as '0' (even if you wrote
723 // '1'). So we mask the bits here already.
724 data &= 0x3F;
725 break;
726
727 case 0x04:
728 // See reg 3.
729 break;
730
731 case 0x05:
732 // Verified on real YMF278: (see above)
733 // Only writes to reg 5 change the (full) 'memAdr'.
734 memAdr = (regs[3] << 16) | (regs[4] << 8) | data;
735 break;
736
737 case 0x06: // memory data
738 if (regs[2] & 1) {
739 writeMem(memAdr, data);
740 ++memAdr; // no need to mask (again) here
741 } else {
742 // Verified on real YMF278:
743 // - writes are ignored
744 // - memAdr is NOT increased
745 }
746 break;
747
748 case 0xf8: // These are implemented in MSXMoonSound.cc
749 case 0xf9:
750 break;
751 }
752 }
753
754 regs[reg] = data;
755}
756
757uint8_t YMF278::readReg(uint8_t reg)
758{
759 // no need to call updateStream(time)
760 uint8_t result = peekReg(reg);
761 if (reg == 6) {
762 // Memory Data Register
763 if (regs[2] & 1) {
764 // Verified on real YMF278:
765 // memAdr is only increased when 'regs[2] & 1'
766 ++memAdr; // no need to mask (again) here
767 }
768 }
769 return result;
770}
771
772uint8_t YMF278::peekReg(uint8_t reg) const
773{
774 switch (reg) {
775 case 2: // 3 upper bits are device ID
776 return (regs[2] & 0x1F) | 0x20;
777
778 case 6: // Memory Data Register
779 if (regs[2] & 1) {
780 return readMem(memAdr);
781 } else {
782 // Verified on real YMF278
783 return 0xff;
784 }
785
786 default:
787 return regs[reg];
788 }
789}
790
791static constexpr unsigned INPUT_RATE = 44100;
792
793static size_t getRamSize(int ramSizeInKb)
794{
795 if ((ramSizeInKb != 0) && // - -
796 (ramSizeInKb != 128) && // 128kB -
797 (ramSizeInKb != 256) && // 128kB 128kB
798 (ramSizeInKb != 512) && // 512kB -
799 (ramSizeInKb != 640) && // 512kB 128kB
800 (ramSizeInKb != 1024) && // 512kB 512kB
801 (ramSizeInKb != 2048)) { // 512kB 512kB 512kB 512kB
802 throw MSXException(
803 "Wrong sample ram size for MoonSound (YMF278). "
804 "Got ", ramSizeInKb, ", but must be one of "
805 "0, 128, 256, 512, 640, 1024 or 2048.");
806 }
807 return size_t(ramSizeInKb) * 1024; // kilo-bytes -> bytes
808}
809
810YMF278::YMF278(const std::string& name_, int ramSizeInKb,
811 const DeviceConfig& config)
812 : ResampledSoundDevice(config.getMotherBoard(), name_, "MoonSound wave-part",
813 24, INPUT_RATE, true)
814 , motherBoard(config.getMotherBoard())
815 , debugRegisters(motherBoard, getName())
816 , debugMemory (motherBoard, getName())
817 , rom(getName() + " ROM", "rom", config)
818 , ram(config, getName() + " RAM", "YMF278 sample RAM",
819 getRamSize(ramSizeInKb)) // check size before allocating
820{
821 if (rom.size() != 0x200000) { // 2MB
822 throw MSXException(
823 "Wrong ROM for MoonSound (YMF278). The ROM (usually "
824 "called yrw801.rom) should have a size of exactly 2MB.");
825 }
826
827 memAdr = 0; // avoid UMR
828 ranges::fill(regs, 0);
829
830 registerSound(config);
831 reset(motherBoard.getCurrentTime()); // must come after registerSound() because of call to setSoftwareVolume() via setMixLevel()
832}
833
838
840{
841 ram.clear(0);
842}
843
844void YMF278::reset(EmuTime::param time)
845{
846 updateStream(time);
847
848 eg_cnt = 0;
849
850 for (auto& op : slots) {
851 op.reset();
852 }
853 regs[2] = 0; // avoid UMR
854 for (int i = 0xf7; i >= 0; --i) { // reverse order to avoid UMR
855 writeRegDirect(narrow<uint8_t>(i), 0, time);
856 }
857 memAdr = 0;
858 setMixLevel(0, time);
859}
860
861// This routine translates an address from the (upper) MoonSound address space
862// to an address inside the (linearized) SRAM address space.
863//
864// The following info is based on measurements on a real MoonSound (v2.0)
865// PCB. This PCB can have several possible SRAM configurations:
866// 128kB:
867// 1 SRAM chip of 128kB, chip enable (/CE) of this SRAM chip is connected to
868// the 1Y0 output of a 74LS139 (2-to-4 decoder). The enable input of the
869// 74LS139 is connected to YMF278 pin /MCS6 and the 74LS139 1B:1A inputs are
870// connected to YMF278 pins MA18:MA17. So the SRAM is selected when /MC6 is
871// active and MA18:MA17 == 0:0.
872// 256kB:
873// 2 SRAM chips of 128kB. First one connected as above. Second one has /CE
874// connected to 74LS139 pin 1Y1. So SRAM2 is selected when /MSC6 is active
875// and MA18:MA17 == 0:1.
876// 512kB:
877// 1 SRAM chip of 512kB, /CE connected to /MCS6
878// 640kB:
879// 1 SRAM chip of 512kB, /CE connected to /MCS6
880// 1 SRAM chip of 128kB, /CE connected to /MCS7.
881// (This means SRAM2 is potentially mirrored over a 512kB region)
882// 1024kB:
883// 1 SRAM chip of 512kB, /CE connected to /MCS6
884// 1 SRAM chip of 512kB, /CE connected to /MCS7
885// 2048kB:
886// 1 SRAM chip of 512kB, /CE connected to /MCS6
887// 1 SRAM chip of 512kB, /CE connected to /MCS7
888// 1 SRAM chip of 512kB, /CE connected to /MCS8
889// 1 SRAM chip of 512kB, /CE connected to /MCS9
890// This configuration is not so easy to create on the v2.0 PCB. So it's
891// very rare.
892//
893// So the /MCS6 and /MCS7 (and /MCS8 and /MCS9 in case of 2048kB) signals are
894// used to select the different SRAM chips. The meaning of these signals
895// depends on the 'memory access mode'. This mode can be changed at run-time
896// via bit 1 in register 2. The following table indicates for which regions
897// these signals are active (normally MoonSound should be used with mode=0):
898// mode=0 mode=1
899// /MCS6 0x200000-0x27FFFF 0x380000-0x39FFFF
900// /MCS7 0x280000-0x2FFFFF 0x3A0000-0x3BFFFF
901// /MCS8 0x300000-0x37FFFF 0x3C0000-0x3DFFFF
902// /MCS9 0x380000-0x3FFFFF 0x3E0000-0x3FFFFF
903//
904// (For completeness) MoonSound also has 2MB ROM (YRW801), /CE of this ROM is
905// connected to YMF278 /MCS0. In both mode=0 and mode=1 this signal is active
906// for the region 0x000000-0x1FFFFF. (But this routine does not handle ROM).
907unsigned YMF278::getRamAddress(unsigned addr) const
908{
909 addr -= 0x200000; // RAM starts at 0x200000
910 if (regs[2] & 2) [[unlikely]] {
911 // Normally MoonSound is used in 'memory access mode = 0'. But
912 // in the rare case that mode=1 we adjust the address.
913 if ((0x180000 <= addr) && (addr <= 0x1FFFFF)) {
914 addr -= 0x180000;
915 switch (addr & 0x060000) {
916 case 0x000000: // [0x380000-0x39FFFF]
917 // 1st 128kB of SRAM1
918 break;
919 case 0x020000: // [0x3A0000-0x3BFFFF]
920 if (ram.size() == 256 * 1024) {
921 // 2nd 128kB SRAM chip
922 } else {
923 // 2nd block of 128kB in SRAM2
924 // In case of 512+128, we use mirroring
925 addr += 0x080000;
926 }
927 break;
928 case 0x040000: // [0x3C0000-0x3DFFFF]
929 // 3rd 128kB block in SRAM3
930 addr += 0x100000;
931 break;
932 case 0x060000: // [0x3EFFFF-0x3FFFFF]
933 // 4th 128kB block in SRAM4
934 addr += 0x180000;
935 break;
936 }
937 } else {
938 addr = unsigned(-1); // unmapped
939 }
940 }
941 if (ram.size() == 640 * 1024) {
942 // Verified on real MoonSound cartridge (v2.0): In case of
943 // 640kB (1x512kB + 1x128kB), the 128kB SRAM chip is 4 times
944 // visible. None of the other SRAM configurations show similar
945 // mirroring (because the others are powers of two).
946 if (addr > 0x080000) {
947 addr &= ~0x060000;
948 }
949 }
950 return addr;
951}
952
953uint8_t YMF278::readMem(unsigned address) const
954{
955 // Verified on real YMF278: address space wraps at 4MB.
956 address &= 0x3FFFFF;
957 if (address < 0x200000) {
958 // ROM connected to /MCS0
959 return rom[address];
960 } else {
961 unsigned ramAddr = getRamAddress(address);
962 if (ramAddr < ram.size()) {
963 return ram[ramAddr];
964 } else {
965 // unmapped region
966 return 255; // TODO check
967 }
968 }
969}
970
971void YMF278::writeMem(unsigned address, uint8_t value)
972{
973 address &= 0x3FFFFF;
974 if (address < 0x200000) {
975 // can't write to ROM
976 } else {
977 unsigned ramAddr = getRamAddress(address);
978 if (ramAddr < ram.size()) {
979 ram.write(ramAddr, value);
980 } else {
981 // can't write to unmapped memory
982 }
983 }
984}
985
986// version 1: initial version, some variables were saved as char
987// version 2: serialization framework was fixed to save/load chars as numbers
988// but for backwards compatibility we still load old savestates as
989// characters
990// version 3: 'step' is no longer stored (it is recalculated)
991// version 4:
992// - removed members: 'lfo', 'LD', 'active'
993// - new members 'TLdest', 'keyon', 'DAMP' restored from registers instead of serialized
994// - store 'OCT' sign-extended
995// - store 'endAddr' as 2s complement
996// - removed EG_DMP and EG_REV enum values from 'state'
997// version 5:
998// - re-added 'lfo' member. This is not stored in the savestate, instead it's
999// restored from register values in YMF278::serialize()
1000// - removed members 'lfo_step' and ' 'lfo_max'
1001// - 'lfo_cnt' has changed meaning (but we don't try to translate old to new meaning)
1002// version 6:
1003// - removed members: 'sample1', 'sample2'
1004template<typename Archive>
1005void YMF278::Slot::serialize(Archive& ar, unsigned version)
1006{
1007 // TODO restore more state from registers
1008 ar.serialize("startaddr", startAddr,
1009 "loopaddr", loopAddr,
1010 "stepptr", stepPtr,
1011 "pos", pos,
1012 "env_vol", env_vol,
1013 "lfo_cnt", lfo_cnt,
1014 "DL", DL,
1015 "wave", wave,
1016 "FN", FN);
1017 if (ar.versionAtLeast(version, 4)) {
1018 ar.serialize("endaddr", endAddr,
1019 "OCT", OCT);
1020 } else {
1021 unsigned e = 0; ar.serialize("endaddr", e); endAddr = uint16_t((e ^ 0xffff) + 1);
1022
1023 char O = 0;
1024 if (ar.versionAtLeast(version, 2)) {
1025 ar.serialize("OCT", O);
1026 } else {
1027 ar.serializeChar("OCT", O);
1028 }
1029 OCT = sign_extend_4(O);
1030 }
1031
1032 if (ar.versionAtLeast(version, 2)) {
1033 ar.serialize("PRVB", PRVB,
1034 "TL", TL,
1035 "pan", pan,
1036 "vib", vib,
1037 "AM", AM,
1038 "AR", AR,
1039 "D1R", D1R,
1040 "D2R", D2R,
1041 "RC", RC,
1042 "RR", RR);
1043 } else {
1044 // for backwards compatibility with old savestates
1045 char PRVB_ = 0; ar.serializeChar("PRVB", PRVB_); PRVB = PRVB_;
1046 char TL_ = 0; ar.serializeChar("TL", TL_ ); TL = TL_;
1047 char pan_ = 0; ar.serializeChar("pan", pan_); pan = pan_;
1048 char vib_ = 0; ar.serializeChar("vib", vib_); vib = vib_;
1049 char AM_ = 0; ar.serializeChar("AM", AM_ ); AM = AM_;
1050 char AR_ = 0; ar.serializeChar("AR", AR_ ); AR = AR_;
1051 char D1R_ = 0; ar.serializeChar("D1R", D1R_); D1R = D1R_;
1052 char D2R_ = 0; ar.serializeChar("D2R", D2R_); D2R = D2R_;
1053 char RC_ = 0; ar.serializeChar("RC", RC_ ); RC = RC_;
1054 char RR_ = 0; ar.serializeChar("RR", RR_ ); RR = RR_;
1055 }
1056 ar.serialize("bits", bits,
1057 "lfo_active", lfo_active);
1058
1059 ar.serialize("state", state);
1060 if (ar.versionBelow(version, 4)) {
1061 assert(Archive::IS_LOADER);
1062 if (state == one_of(EG_REV, EG_DMP)) {
1063 state = EG_REL;
1064 }
1065 }
1066
1067 // Recalculate redundant state
1068 if constexpr (Archive::IS_LOADER) {
1069 step = calcStep(OCT, FN);
1070 }
1071
1072 // This old comment is NOT completely true:
1073 // Older version also had "env_vol_step" and "env_vol_lim" but those
1074 // members were nowhere used, so removed those in the current
1075 // version (it's ok to remove members from the savestate without
1076 // updating the version number).
1077 // When you remove member variables without increasing the version
1078 // number, new openMSX executables can still read old savestates. And
1079 // if you try to load a new savestate in an old openMSX version you do
1080 // get a (cryptic) error message. But if the version number is
1081 // increased the error message is much clearer.
1082}
1083
1084// version 1: initial version
1085// version 2: loadTime and busyTime moved to MSXMoonSound class
1086// version 3: memAdr cannot be restored from register values
1087// version 4: implement ram via Ram class
1088template<typename Archive>
1089void YMF278::serialize(Archive& ar, unsigned version)
1090{
1091 ar.serialize("slots", slots,
1092 "eg_cnt", eg_cnt);
1093 if (ar.versionAtLeast(version, 4)) {
1094 ar.serialize("ram", ram);
1095 } else {
1096 ar.serialize_blob("ram", ram.getWriteBackdoor());
1097 }
1098 ar.serialize_blob("registers", regs);
1099 if (ar.versionAtLeast(version, 3)) { // must come after 'regs'
1100 ar.serialize("memadr", memAdr);
1101 } else {
1102 assert(Archive::IS_LOADER);
1103 // Old formats didn't store 'memAdr' so we also can't magically
1104 // restore the correct value. The best we can do is restore the
1105 // last set address.
1106 regs[3] &= 0x3F; // mask upper two bits
1107 memAdr = (regs[3] << 16) | (regs[4] << 8) | regs[5];
1108 }
1109
1110 // TODO restore more state from registers
1111 if constexpr (Archive::IS_LOADER) {
1112 for (auto [i, sl] : enumerate(slots)) {
1113 uint8_t t = regs[0x50 + i] >> 1;
1114 sl.TLdest = (t != 0x7f) ? t : 0xff;
1115
1116 sl.keyon = (regs[0x68 + i] & 0x80) != 0;
1117 sl.DAMP = (regs[0x68 + i] & 0x40) != 0;
1118 sl.lfo = (regs[0x80 + i] >> 3) & 7;
1119 }
1120 }
1121}
1123
1124
1125// class DebugRegisters
1126
1127YMF278::DebugRegisters::DebugRegisters(MSXMotherBoard& motherBoard_,
1128 const std::string& name_)
1129 : SimpleDebuggable(motherBoard_, name_ + " regs",
1130 "OPL4 registers", 0x100)
1131{
1132}
1133
1134uint8_t YMF278::DebugRegisters::read(unsigned address)
1135{
1136 auto& ymf278 = OUTER(YMF278, debugRegisters);
1137 return ymf278.peekReg(narrow<uint8_t>(address));
1138}
1139
1140void YMF278::DebugRegisters::write(unsigned address, uint8_t value, EmuTime::param time)
1141{
1142 auto& ymf278 = OUTER(YMF278, debugRegisters);
1143 ymf278.writeReg(narrow<uint8_t>(address), value, time);
1144}
1145
1146
1147// class DebugMemory
1148
1149YMF278::DebugMemory::DebugMemory(MSXMotherBoard& motherBoard_,
1150 const std::string& name_)
1151 : SimpleDebuggable(motherBoard_, name_ + " mem",
1152 "OPL4 memory (includes both ROM and RAM)", 0x400000) // 4MB
1153{
1154}
1155
1156uint8_t YMF278::DebugMemory::read(unsigned address)
1157{
1158 auto& ymf278 = OUTER(YMF278, debugMemory);
1159 return ymf278.readMem(address);
1160}
1161
1162void YMF278::DebugMemory::write(unsigned address, uint8_t value)
1163{
1164 auto& ymf278 = OUTER(YMF278, debugMemory);
1165 ymf278.writeMem(address, value);
1166}
1167
1168} // namespace openmsx
TclObject t
EmuTime::param getCurrentTime() const
Convenience method: This is the same as getScheduler().getCurrentTime().
auto size() const
Definition Rom.hh:36
void updateStream(EmuTime::param time)
void setSoftwareVolume(float volume, EmuTime::param time)
Change the 'software volume' of this sound device.
void unregisterSound()
Unregisters this sound device with the Mixer.
void registerSound(const DeviceConfig &config)
Registers this sound device with the Mixer.
void clear(byte c=0xff)
Definition TrackedRam.hh:46
void write(size_t addr, byte value)
Definition TrackedRam.hh:41
std::span< byte > getWriteBackdoor()
Definition TrackedRam.hh:55
size_t size() const
Definition TrackedRam.hh:20
uint8_t readReg(uint8_t reg)
Definition YMF278.cc:757
void writeReg(uint8_t reg, uint8_t data, EmuTime::param time)
Definition YMF278.cc:582
void setMixLevel(uint8_t x, EmuTime::param time)
Definition YMF278.cc:492
void reset(EmuTime::param time)
Definition YMF278.cc:844
void writeMem(unsigned address, uint8_t value)
Definition YMF278.cc:971
uint8_t readMem(unsigned address) const
Definition YMF278.cc:953
void clearRam()
Definition YMF278.cc:839
void serialize(Archive &ar, unsigned version)
Definition YMF278.cc:1089
uint8_t peekReg(uint8_t reg) const
Definition YMF278.cc:772
YMF278(const std::string &name, int ramSizeInKb, const DeviceConfig &config)
Definition YMF278.cc:810
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition enumerate.hh:28
This file implemented 3 utility functions:
Definition Autofire.cc:11
bool any_of(InputRange &&range, UnaryPredicate pred)
Definition ranges.hh:198
constexpr void fill(ForwardRange &&range, const T &value)
Definition ranges.hh:305
#define OUTER(type, member)
Definition outer.hh:42
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define UNREACHABLE
constexpr auto xrange(T e)
Definition xrange.hh:132