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