summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/bus/msx_cart/moonsound.h2
-rw-r--r--src/devices/sound/ymf278b.cpp983
-rw-r--r--src/devices/sound/ymf278b.h192
-rw-r--r--src/devices/sound/ymfm_mame.h21
-rw-r--r--src/devices/sound/ymopl.cpp85
-rw-r--r--src/devices/sound/ymopl.h41
-rw-r--r--src/devices/sound/ymopn.cpp59
-rw-r--r--src/devices/sound/ymopn.h8
8 files changed, 152 insertions, 1239 deletions
diff --git a/src/devices/bus/msx_cart/moonsound.h b/src/devices/bus/msx_cart/moonsound.h
index ca30dfb5c35..62f614ae729 100644
--- a/src/devices/bus/msx_cart/moonsound.h
+++ b/src/devices/bus/msx_cart/moonsound.h
@@ -6,7 +6,7 @@
#pragma once
#include "bus/msx_cart/cartridge.h"
-#include "sound/ymf278b.h"
+#include "sound/ymopl.h"
DECLARE_DEVICE_TYPE(MSX_CART_MOONSOUND, msx_cart_moonsound_device)
diff --git a/src/devices/sound/ymf278b.cpp b/src/devices/sound/ymf278b.cpp
deleted file mode 100644
index 60646fd620e..00000000000
--- a/src/devices/sound/ymf278b.cpp
+++ /dev/null
@@ -1,983 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:R. Belmont, Olivier Galibert, hap
-/*
-
- YMF278B FM + Wave table Synthesizer (OPL4)
-
- Timer and PCM YMF278B. The FM will be shared with the ymf262, eventually.
-
- This chip roughly splits the difference between the Sega 315-5560 MultiPCM
- (Multi32, Model 1/2) and YMF 292-F SCSP (later Model 2, STV, Saturn, Model 3).
-
- Features as listed in LSI-4MF2782 data sheet:
- FM Synthesis (same as YMF262)
- 1. Sound generation mode
- Two-operater mode
- Generates eighteen voices or fifteen voices plus five rhythm sounds simultaneously
- Four-operator mode
- Generates six voices in four-operator mode plus six voices in two-operator mode simultaneously,
- or generates six voices in four-operator mode plus three voices in two-operator mode plus five
- rhythm sounds simultaneously
- 2. Eight selectable waveforms
- 3. Stereo output
- Wave Table Synthesis
- 1. Generates twenty-four voices simultaneously
- 2. 44.1kHz sampling rate for output sound data
- 3. Selectable from 8-bit, 12-bit and 16-bit word lengths for wave data
- 4. Stereo output (16-stage panpot for each voice)
- Wave Data
- 1. Accepts 32M bit external memory at maximum
- 2. Up to 512 wave tables
- 3. External ROM or SRAM can be connected. With SRAM connected, the CPU can download wave data
- 4. Outputs chip select signals for 1Mbit, 4Mbit, 8Mbit or 16Mbit memory
- 5. Can be directly connected to the Yamaha YRW801 (Wave data ROM)
- Features of YRW801 as listed in LSI 4RW801A2
- Built-in wave data of tones which comply with GM system Level 1
- Melody tone ....... 128 tones
- Percussion tone ... 47 tones
- 16Mbit capacity (2,097,152word x 8)
-
- By R. Belmont and O. Galibert.
-
-
- TODO:
- - accurate timing of envelopes
- - LFO (vibrato, tremolo)
- - integrate YMF262 mixing (used by Fuuki games, not used by Psikyo and Metro games)
- - Envelope and LFO function is similar algorithm as multipcm.cpp (except Damp, Pseudo Reverb)
- Can it be merged with/ported to this?
-*/
-
-#include "emu.h"
-#include "ymf278b.h"
-
-#include <algorithm>
-
-#define VERBOSE 0
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
-
-
-// Using the nominal datasheet frequency of 33.868MHz, the output of
-// the chip will be clock/768 = 44.1kHz. However, the FM engine is
-// clocked internally at clock/(19*36), or 49.515kHz, so the FM output
-// needs to be downsampled. The calculations below produce the fractional
-// number of extra FM samples we need to consume for each output sample,
-// as a 0.24 fixed point fraction.
-static constexpr double NOMINAL_CLOCK = 33868800;
-static constexpr double NOMINAL_FM_RATE = NOMINAL_CLOCK / double(ymfm::opl4_registers::DEFAULT_PRESCALE * ymfm::opl4_registers::OPERATORS);
-static constexpr double NOMINAL_OUTPUT_RATE = NOMINAL_CLOCK / 768.0;
-static constexpr uint32_t FM_STEP = uint32_t((NOMINAL_FM_RATE / NOMINAL_OUTPUT_RATE - 1.0) * double(1 << 24));
-
-
-/**************************************************************************/
-
-int ymf278b_device::compute_rate(YMF278BSlot *slot, int val)
-{
- int res, oct;
-
- if(val == 0)
- return 0;
- if(val == 15)
- return 63;
- if(slot->RC != 15)
- {
- oct = slot->octave;
- if (oct & 8)
- oct |= -8;
-
- res = (oct+slot->RC)*2 + (slot->F_NUMBER & 0x200 ? 1 : 0) + val*4;
- }
- else
- res = val * 4;
- if(res < 0)
- res = 0;
- else if(res > 63)
- res = 63;
-
- return res;
-}
-
-uint32_t ymf278b_device::compute_decay_env_vol_step(YMF278BSlot *slot, int val)
-{
- int rate;
- uint32_t res;
-
- // rate override with damping/pseudo reverb
- if (slot->DAMP)
- rate = 56; // approximate, datasheet says it's slightly curved though
- else if (slot->preverb && slot->env_vol > ((6*8)<<23))
- {
- // pseudo reverb starts at -18dB (6 in voltab)
- slot->env_preverb = 1;
- rate = 5;
- }
- else
- rate = compute_rate(slot, val);
-
- if (rate < 4)
- res = 0;
- else
- res = (256U<<23) / m_lut_dr[rate];
-
- return res;
-}
-
-void ymf278b_device::compute_freq_step(YMF278BSlot *slot)
-{
- uint32_t step;
- int oct;
-
- oct = slot->octave;
- if(oct & 8)
- oct |= -8;
-
- step = (slot->F_NUMBER | 1024) << (oct + 8);
- slot->step = step >> 3;
-}
-
-void ymf278b_device::compute_envelope(YMF278BSlot *slot)
-{
- switch (slot->env_step)
- {
- // Attack
- case 0:
- {
- // Attack
- int rate = compute_rate(slot, slot->AR);
- slot->env_vol = 256U<<23;
- slot->env_vol_lim = (256U<<23) - 1;
-
- if (rate==63)
- {
- // immediate
- LOG(("YMF278B: Attack skipped - "));
- slot->env_vol = 0;
- slot->env_step++;
- compute_envelope(slot);
- }
- else if (rate<4)
- {
- slot->env_vol_step = 0;
- }
- else
- {
- // NOTE: attack rate is linear here, but datasheet shows a smooth curve
- LOG(("YMF278B: Attack, val = %d, rate = %d, delay = %g\n", slot->AR, rate, m_lut_ar[rate]*1000.0));
- slot->env_vol_step = ~((256U<<23) / m_lut_ar[rate]);
- }
-
- break;
- }
-
- // Decay 1
- case 1:
- if(slot->DL)
- {
- LOG(("YMF278B: Decay step 1, dl=%d, val = %d rate = %d, delay = %g, PRVB = %d, DAMP = %d\n", slot->DL, slot->D1R, compute_rate(slot, slot->D1R), m_lut_dr[compute_rate(slot, slot->D1R)]*1000.0, slot->preverb, slot->DAMP));
- slot->env_vol_step = compute_decay_env_vol_step(slot, slot->D1R);
- slot->env_vol_lim = (slot->DL*8)<<23;
- }
- else
- {
- LOG(("YMF278B: Decay 1 skipped - "));
- slot->env_step++;
- compute_envelope(slot);
- }
-
- break;
-
- // Decay 2
- case 2:
- LOG(("YMF278B: Decay step 2, val = %d, rate = %d, delay = %g, , PRVB = %d, DAMP = %d, current vol = %d\n", slot->D2R, compute_rate(slot, slot->D2R), m_lut_dr[compute_rate(slot, slot->D2R)]*1000.0, slot->preverb, slot->DAMP, slot->env_vol >> 23));
- slot->env_vol_step = compute_decay_env_vol_step(slot, slot->D2R);
- slot->env_vol_lim = 256U<<23;
- break;
-
- // Decay 2 reached -96dB
- case 3:
- LOG(("YMF278B: Voice cleared because of decay 2\n"));
- slot->env_vol = 256U<<23;
- slot->env_vol_step = 0;
- slot->env_vol_lim = 0;
- slot->active = 0;
- break;
-
- // Release
- case 4:
- LOG(("YMF278B: Release, val = %d, rate = %d, delay = %g, PRVB = %d, DAMP = %d\n", slot->RR, compute_rate(slot, slot->RR), m_lut_dr[compute_rate(slot, slot->RR)]*1000.0, slot->preverb, slot->DAMP));
- slot->env_vol_step = compute_decay_env_vol_step(slot, slot->RR);
- slot->env_vol_lim = 256U<<23;
- break;
-
- // Release reached -96dB
- case 5:
- LOG(("YMF278B: Release ends\n"));
- slot->env_vol = 256U<<23;
- slot->env_vol_step = 0;
- slot->env_vol_lim = 0;
- slot->active = 0;
- break;
-
- default: break;
- }
-}
-
-//-------------------------------------------------
-// sound_stream_update - handle a stream update
-//-------------------------------------------------
-
-void ymf278b_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
-{
- int i, j;
- YMF278BSlot *slot;
- int16_t sample = 0;
- int32_t *mixp;
-
- std::fill(m_mix_buffer.begin(), m_mix_buffer.end(), 0);
-
- for (i = 0; i < 24; i++)
- {
- slot = &m_slots[i];
-
- if (slot->active)
- {
- mixp = &m_mix_buffer[0];
-
- for (j = 0; j < outputs[0].samples(); j++)
- {
- if (slot->stepptr >= slot->endaddr)
- {
- slot->stepptr = slot->stepptr - slot->endaddr + slot->loopaddr;
-
- // NOTE: loop overflow is still possible here if (slot->stepptr >= slot->endaddr)
- // This glitch may be (ab)used to your advantage to create pseudorandom noise.
- }
-
- switch (slot->bits)
- {
- // 8 bit
- case 0:
- sample = read_byte(slot->startaddr + (slot->stepptr>>16))<<8;
- break;
-
- // 12 bit
- case 1:
- if (slot->stepptr & 0x10000)
- sample = read_byte(slot->startaddr + (slot->stepptr>>17)*3+2)<<8 |
- (read_byte(slot->startaddr + (slot->stepptr>>17)*3+1) & 0xf0);
- else
- sample = read_byte(slot->startaddr + (slot->stepptr>>17)*3)<<8 |
- ((read_byte(slot->startaddr + (slot->stepptr>>17)*3+1) << 4) & 0xf0);
- break;
-
- // 16 bit
- case 2:
- sample = read_byte(slot->startaddr + ((slot->stepptr>>16)*2))<<8 |
- read_byte(slot->startaddr + ((slot->stepptr>>16)*2)+1);
- break;
-
- // ?? bit, effect is unknown, datasheet says it's prohibited
- case 3:
- sample = 0;
- break;
- }
-
- if (slot->CH) // DO1 out
- {
- mixp++;
- mixp++;
- *mixp++ += (sample * m_volume[slot->TL+m_pan_left [slot->pan]+(slot->env_vol>>23)])>>17;
- *mixp++ += (sample * m_volume[slot->TL+m_pan_right[slot->pan]+(slot->env_vol>>23)])>>17;
- }
- else // DO2 out
- {
- *mixp++ += (sample * m_volume[slot->TL+m_pan_left [slot->pan]+(slot->env_vol>>23)])>>17;
- *mixp++ += (sample * m_volume[slot->TL+m_pan_right[slot->pan]+(slot->env_vol>>23)])>>17;
- mixp++;
- mixp++;
- }
-
- // update frequency
- slot->stepptr += slot->step;
-
- // update envelope
- slot->env_vol += slot->env_vol_step;
- if (((int32_t)(slot->env_vol - slot->env_vol_lim)) >= 0)
- {
- slot->env_step++;
- compute_envelope(slot);
- }
- else if (slot->preverb && !slot->env_preverb && slot->env_step && slot->env_vol > ((6*8)<<23))
- compute_envelope(slot);
- }
- }
- }
-
- mixp = &m_mix_buffer[0];
- stream_buffer::sample_t wtl = stream_buffer::sample_t(m_mix_level[m_pcm_l]) / (65536.0f * 32768.0f);
- stream_buffer::sample_t wtr = stream_buffer::sample_t(m_mix_level[m_pcm_r]) / (65536.0f * 32768.0f);
- stream_buffer::sample_t fml = stream_buffer::sample_t(m_mix_level[m_fm_l]) / (65536.0f * 32768.0f);
- stream_buffer::sample_t fmr = stream_buffer::sample_t(m_mix_level[m_fm_r]) / (65536.0f * 32768.0f);
- for (i = 0; i < outputs[0].samples(); i++)
- {
- // the FM_STEP value is the fractional number of extra samples consumed per
- // output sample; when this overflows, we need to clock the FM engine an
- // extra time; since the PCM side of the chip doesn't do interpolation, I'm
- // assuming this resampling stage doesn't either
- m_fm_pos += FM_STEP;
- if (BIT(m_fm_pos, 24))
- {
- m_fm.clock(fm_engine::ALL_CHANNELS);
- m_fm_pos &= 0xffffff;
- }
-
- // clock the system
- m_fm.clock(fm_engine::ALL_CHANNELS);
-
- // update the FM content; clipping is unknown
- fm_engine::output_data sums;
- m_fm.output(sums.clear(), 1, 32767, fm_engine::ALL_CHANNELS);
-
- // DO2 output: mixed FM channels 0+1 and wavetable channels 0+1
- outputs[0].put(i, stream_buffer::sample_t(*mixp++) * wtl + stream_buffer::sample_t(sums.data[0]) * fml);
- outputs[1].put(i, stream_buffer::sample_t(*mixp++) * wtr + stream_buffer::sample_t(sums.data[1]) * fmr);
-
- // DO0 output: FM channels 2+3 only
- outputs[2].put_int(i, sums.data[2], 32768);
- outputs[3].put_int(i, sums.data[3], 32768);
-
- // DO1 output: wavetable channels 2+3 only
- outputs[4].put_int(i, *mixp++, 32768);
- outputs[5].put_int(i, *mixp++, 32768);
- }
-}
-
-enum
-{
- TIMER_BUSY_CLEAR,
- TIMER_LD_CLEAR
-};
-
-void ymf278b_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch(id)
- {
- case TIMER_BUSY_CLEAR:
- m_fm.set_reset_status(0, STATUS_BUSY);
- break;
-
- case TIMER_LD_CLEAR:
- m_fm.set_reset_status(0, STATUS_LD);
- break;
- }
-}
-
-
-/**************************************************************************/
-
-void ymf278b_device::retrigger_sample(YMF278BSlot *slot)
-{
- // activate channel
- if (slot->octave != 8)
- slot->active = 1;
-
- // reset sample pos and go to attack stage
- slot->stepptr = 0;
- slot->env_step = 0;
- slot->env_preverb = 0;
-
- compute_freq_step(slot);
- compute_envelope(slot);
-}
-
-void ymf278b_device::C_w(uint8_t reg, uint8_t data)
-{
- // Handle slot registers specifically
- if (reg >= 0x08 && reg <= 0xf7)
- {
- YMF278BSlot *slot;
- int snum;
- snum = (reg-8) % 24;
- slot = &m_slots[snum];
- switch((reg-8) / 24)
- {
- case 0:
- {
- attotime period;
- uint32_t offset;
- uint8_t p[12];
- int i;
-
- slot->wave &= 0x100;
- slot->wave |= data;
-
- // load wavetable header
- if(slot->wave < 384 || !m_wavetblhdr)
- offset = slot->wave * 12;
- else
- offset = m_wavetblhdr*0x80000 + (slot->wave - 384) * 12;
- for (i = 0; i < 12; i++)
- p[i] = read_byte(offset+i);
-
- slot->bits = (p[0]&0xc0)>>6;
- slot->startaddr = (p[2] | (p[1]<<8) | ((p[0]&0x3f)<<16));
- slot->loopaddr = (p[4]<<16) | (p[3]<<24);
- slot->endaddr = (p[6]<<16) | (p[5]<<24);
- slot->endaddr -= 0x00010000U;
- slot->endaddr ^= 0xffff0000U;
-
- // copy internal registers data
- for (i = 7; i < 12; i++)
- C_w(8 + snum + (i-2) * 24, p[i]);
-
- // status register LD bit is on for approx 300us
- m_fm.set_reset_status(STATUS_LD, 0);
- period = clocks_to_attotime(10);
- m_timer_ld->adjust(period);
-
- // retrigger if key is on
- if (slot->KEY_ON)
- retrigger_sample(slot);
- else if (slot->active)
- {
- // deactivate channel
- slot->env_step = 5;
- compute_envelope(slot);
- }
-
- break;
- }
-
- case 1:
- slot->wave &= 0xff;
- slot->wave |= ((data&0x1)<<8);
- slot->F_NUMBER &= 0x380;
- slot->F_NUMBER |= (data>>1);
- if (slot->active && (data ^ m_pcmregs[reg]) & 0xfe)
- {
- compute_freq_step(slot);
- compute_envelope(slot);
- }
- break;
-
- case 2:
- slot->F_NUMBER &= 0x07f;
- slot->F_NUMBER |= ((data&0x07)<<7);
- slot->preverb = (data&0x8)>>3;
- slot->octave = (data&0xf0)>>4;
- if (data != m_pcmregs[reg])
- {
- // channel goes off if octave is set to -8 (datasheet says it's prohibited)
- // (it is ok if this activates the channel while it was off: compute_envelope will reset it again if needed)
- slot->active = (slot->octave != 8);
-
- if (slot->active)
- {
- slot->env_preverb = 0;
- compute_freq_step(slot);
- compute_envelope(slot);
- }
- }
- break;
-
- case 3:
- slot->TL = data>>1;
- slot->LD = data&0x1;
- break;
-
- case 4:
- slot->CH = (data&0x10)>>4;
- // CH bit note: output to DO1 pin (1) or DO2 pin (0), this may
- // silence the channel depending on how it's wired up on the PCB.
- // For now, it's always enabled.
- // (bit 5 (LFO reset) is also not hooked up yet)
-
- slot->pan = data&0xf;
- slot->DAMP = (data&0x40)>>6;
- if (data & 0x80)
- {
- // don't retrigger if key was already on
- if (slot->KEY_ON)
- {
- if ((data ^ m_pcmregs[reg]) & 0x40)
- compute_envelope(slot);
-
- break;
- }
-
- retrigger_sample(slot);
- }
- else if (slot->active)
- {
- // release
- slot->env_step = 4;
- compute_envelope(slot);
- }
- slot->KEY_ON = (data&0x80)>>7;
- break;
-
- case 5:
- // LFO and vibrato level, not hooked up yet
- slot->LFO = (data>>3)&0x7;
- slot->VIB = data&0x7;
- break;
-
- case 6:
- slot->AR = data>>4;
- slot->D1R = data&0xf;
- if (slot->active && data != m_pcmregs[reg])
- compute_envelope(slot);
- break;
-
- case 7:
- slot->DL = data>>4;
- slot->D2R = data&0xf;
- if (slot->active && data != m_pcmregs[reg])
- compute_envelope(slot);
- break;
-
- case 8:
- slot->RC = data>>4;
- slot->RR = data&0xf;
- if (slot->active && data != m_pcmregs[reg])
- compute_envelope(slot);
- break;
-
- case 9:
- // tremolo level, not hooked up yet
- slot->AM = data & 0x7;
- break;
- }
- }
- else
- {
- // All non-slot registers
- switch (reg)
- {
- // LSI TEST
- case 0x00:
- case 0x01:
- break;
-
- case 0x02:
- m_wavetblhdr = (data>>2)&0x7;
- m_memmode = data&3;
- break;
-
- case 0x03:
- data &= 0x3f; // !
- break;
- case 0x04:
- break;
- case 0x05:
- // set memory address
- m_memadr = m_pcmregs[3] << 16 | m_pcmregs[4] << 8 | data;
- break;
-
- case 0x06:
- // memory data
- space(0).write_byte(m_memadr, data);
- m_memadr = (m_memadr + 1) & 0x3fffff;
- break;
-
- case 0x07:
- break; // unused
-
- case 0xf8:
- m_fm_l = data & 0x7;
- m_fm_r = (data>>3)&0x7;
- break;
-
- case 0xf9:
- m_pcm_l = data & 0x7;
- m_pcm_r = (data>>3)&0x7;
- break;
-
- default:
- logerror("YMF278B: Port C write %02x, %02x\n", reg, data);
- break;
- }
- }
-
- m_pcmregs[reg] = data;
-}
-
-void ymf278b_device::timer_busy_start(int is_pcm)
-{
- // status register BUSY bit is on for 56(FM) or 88(PCM) cycles
- m_fm.set_reset_status(STATUS_BUSY, 0);
- m_timer_busy->adjust(attotime::from_hz(m_clock / (is_pcm ? 88 : 56)));
-}
-
-void ymf278b_device::write(offs_t offset, u8 data)
-{
- uint32_t old;
- switch (offset & 7)
- {
- case 0:
- case 2:
- timer_busy_start(0);
- m_port_AB = data;
- m_lastport = BIT(offset, 1);
- break;
-
- case 1:
- case 3:
- timer_busy_start(0);
- old = m_fm.regs().new2flag();
- m_fm.write(m_port_AB | (m_lastport << 8), data);
-
- // if the new2 flag is turned on, the next status read will set bit 1
- // but only for the first status read after new2 is set
- if (old == 0 && m_fm.regs().new2flag() != 0)
- m_next_status_id = true;
- break;
-
- case 4:
- timer_busy_start(1);
- m_port_C = data;
- break;
-
- case 5:
- // PCM regs are only accessible if NEW2 is set
- if (!m_fm.regs().new2flag())
- break;
-
- m_stream->update();
-
- timer_busy_start(1);
- C_w(m_port_C, data);
- break;
-
- default:
- logerror("%s: unexpected write at offset %X to ymf278b = %02X\n", machine().describe_context(), offset, data);
- break;
- }
-}
-
-
-u8 ymf278b_device::read(offs_t offset)
-{
- uint8_t ret = 0;
-
- switch (offset & 7)
- {
- // status register
- case 0:
-
- // first status read after initialization returns a chip ID, which
- // varies based on the "new" flags, indicating the mode
- if (m_next_status_id)
- {
- if (m_fm.regs().new2flag())
- ret = 0x02;
- else if (m_fm.regs().newflag())
- ret = 0x00;
- else
- ret = 0x06;
- m_next_status_id = false;
- }
- else
- {
- ret = m_fm.status();
-
- // if new2 flag is not set, we're in OPL2 or OPL3 mode
- if (!m_fm.regs().new2flag())
- ret &= ~(STATUS_BUSY | STATUS_LD);
- }
- break;
-
- // FM regs can be read too (on contrary to what the datasheet says)
- case 1:
- case 3:
- // but they're not implemented here yet
- // This may be incorrect, but it makes the mbwave moonsound detection in msx drivers pass.
- ret = m_fm.regs().read(m_port_AB | (m_lastport << 8));
- break;
-
- // PCM regs
- case 5:
- // only accessible if NEW2 is set
- if (!m_fm.regs().new2flag())
- break;
-
- switch (m_port_C)
- {
- // special cases
- case 2:
- ret = (m_pcmregs[m_port_C] & 0x1f) | 0x20; // device ID in upper bits
- break;
- case 6:
- ret = read_byte(m_memadr);
- m_memadr = (m_memadr + 1) & 0x3fffff;
- break;
-
- default:
- ret = m_pcmregs[m_port_C];
- break;
- }
- break;
-
- default:
- logerror("%s: unexpected read at offset %X from ymf278b\n", machine().describe_context(), offset);
- break;
- }
-
- return ret;
-}
-
-
-/**************************************************************************/
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void ymf278b_device::device_reset()
-{
- int i;
-
- // clear registers
- for (i = 0; i < 8; i++)
- C_w(i, 0);
- for (i = 0xff; i >= 8; i--)
- C_w(i, 0);
- C_w(0xf8, 0x1b);
-
- m_port_AB = m_port_C = 0;
- m_lastport = 0;
- m_next_status_id = true;
- m_memadr = 0;
-
- // init/silence channels
- for (i = 0; i < 24 ; i++)
- {
- YMF278BSlot *slot = &m_slots[i];
-
- slot->LFO = 0;
- slot->VIB = 0;
- slot->AR = 0;
- slot->D1R = 0;
- slot->DL = 0;
- slot->D2R = 0;
- slot->RC = 0;
- slot->RR = 0;
- slot->AM = 0;
-
- slot->startaddr = 0;
- slot->loopaddr = 0;
- slot->endaddr = 0;
-
- slot->env_step = 5;
- compute_envelope(slot);
- }
-
- m_timer_busy->reset();
- m_timer_ld->reset();
-
- m_fm.reset();
-}
-
-void ymf278b_device::device_clock_changed()
-{
- int old_rate = m_rate;
- m_clock = clock();
- m_rate = m_clock/768;
- m_fm_pos = 0;
-
- if (m_rate > old_rate)
- {
- m_mix_buffer.resize(m_rate*4,0);
- }
- m_stream->set_sample_rate(m_rate);
-}
-
-void ymf278b_device::rom_bank_updated()
-{
- m_stream->update();
-}
-
-void ymf278b_device::precompute_rate_tables()
-{
- int i;
-
- // decay rate
- for (i = 0; i < 64; i++)
- {
- if (i <= 3)
- m_lut_dr[i] = 0;
- else if (i >= 60)
- m_lut_dr[i] = 15 << 4;
- else
- m_lut_dr[i] = (15 << (21 - i / 4)) / (4 + i % 4);
- }
-
- // attack rate (manual shows curve instead of linear though, so this is not entirely accurate)
- for (i = 0; i < 64; i++)
- {
- if (i <= 3 || i == 63)
- m_lut_ar[i] = 0;
- else if (i >= 60)
- m_lut_ar[i] = 17;
- else
- m_lut_ar[i] = (67 << (15 - i / 4)) / (4 + i % 4);
- }
-}
-
-void ymf278b_device::register_save_state()
-{
- int i;
-
- save_item(NAME(m_pcmregs));
- save_item(NAME(m_wavetblhdr));
- save_item(NAME(m_memmode));
- save_item(NAME(m_memadr));
- save_item(NAME(m_fm_l));
- save_item(NAME(m_fm_r));
- save_item(NAME(m_fm_pos));
- save_item(NAME(m_pcm_l));
- save_item(NAME(m_pcm_r));
- save_item(NAME(m_port_AB));
- save_item(NAME(m_port_C));
- save_item(NAME(m_lastport));
- save_item(NAME(m_next_status_id));
-
- for (i = 0; i < 24; ++i)
- {
- save_item(NAME(m_slots[i].wave), i);
- save_item(NAME(m_slots[i].F_NUMBER), i);
- save_item(NAME(m_slots[i].octave), i);
- save_item(NAME(m_slots[i].preverb), i);
- save_item(NAME(m_slots[i].DAMP), i);
- save_item(NAME(m_slots[i].CH), i);
- save_item(NAME(m_slots[i].LD), i);
- save_item(NAME(m_slots[i].TL), i);
- save_item(NAME(m_slots[i].pan), i);
- save_item(NAME(m_slots[i].LFO), i);
- save_item(NAME(m_slots[i].VIB), i);
- save_item(NAME(m_slots[i].AM), i);
-
- save_item(NAME(m_slots[i].AR), i);
- save_item(NAME(m_slots[i].D1R), i);
- save_item(NAME(m_slots[i].DL), i);
- save_item(NAME(m_slots[i].D2R), i);
- save_item(NAME(m_slots[i].RC), i);
- save_item(NAME(m_slots[i].RR), i);
-
- save_item(NAME(m_slots[i].step), i);
- save_item(NAME(m_slots[i].stepptr), i);
-
- save_item(NAME(m_slots[i].active), i);
- save_item(NAME(m_slots[i].KEY_ON), i);
- save_item(NAME(m_slots[i].bits), i);
- save_item(NAME(m_slots[i].startaddr), i);
- save_item(NAME(m_slots[i].loopaddr), i);
- save_item(NAME(m_slots[i].endaddr), i);
-
- save_item(NAME(m_slots[i].env_step), i);
- save_item(NAME(m_slots[i].env_vol), i);
- save_item(NAME(m_slots[i].env_vol_step), i);
- save_item(NAME(m_slots[i].env_vol_lim), i);
- save_item(NAME(m_slots[i].env_preverb), i);
- }
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void ymf278b_device::device_start()
-{
- int i;
-
- m_clock = clock();
- m_rate = m_clock / 768;
- m_fm_pos = 0;
-
- m_timer_busy = timer_alloc(TIMER_BUSY_CLEAR);
- m_timer_ld = timer_alloc(TIMER_LD_CLEAR);
-
- for (i = 0; i < 24; i++)
- {
- m_slots[i].num = i;
- }
-
- m_stream = stream_alloc(0, 6, m_rate);
- m_mix_buffer.resize(m_rate*4,0);
-
- // rate tables
- precompute_rate_tables();
-
- // Volume table, 1 = -0.375dB, 8 = -3dB, 256 = -96dB
- for(i = 0; i < 256; i++)
- m_volume[i] = 65536*pow(2.0, (-0.375/6)*i);
- for(i = 256; i < 256*4; i++)
- m_volume[i] = 0;
-
- // Pan values, units are -3dB, i.e. 8.
- for(i = 0; i < 16; i++)
- {
- m_pan_left[i] = i < 7 ? i*8 : i < 9 ? 256 : 0;
- m_pan_right[i] = i < 8 ? 0 : i < 10 ? 256 : (16-i)*8;
- }
-
- // Mixing levels, units are -3dB, and add some margin to avoid clipping
- for(i=0; i<7; i++)
- m_mix_level[i] = m_volume[8*i+13];
- m_mix_level[7] = 0;
-
- // Register state for saving
- register_save_state();
-
- // YMF262 related -- cribbed from ymfm_device_base_common
- {
- // allocate our timers
- for (int tnum = 0; tnum < 2; tnum++)
- m_timer[tnum] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ymf278b_device::fm_timer_handler), this));
-
- // resolve the handlers
- m_update_irq.resolve();
-
- // compute the size of the save buffer by doing an initial save
- ymfm::ymfm_saved_state state(m_save_blob, true);
- m_fm.save_restore(state);
-
- // now register the blob for save, on the assumption the size won't change
- save_item(NAME(m_save_blob));
- }
-}
-
-
-DEFINE_DEVICE_TYPE(YMF278B, ymf278b_device, "ymf278b", "Yamaha YMF278B OPL4")
-
-ymf278b_device::ymf278b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, YMF278B, tag, owner, clock)
- , device_sound_interface(mconfig, *this)
- , device_rom_interface(mconfig, *this)
- , m_fm(*this)
- , m_update_irq(*this)
-{
-}
-
-// handle pre-saving by filling the blob
-void ymf278b_device::device_pre_save()
-{
- // remember the original blob size
- auto orig_size = m_save_blob.size();
-
- // save the state
- ymfm::ymfm_saved_state state(m_save_blob, true);
- m_fm.save_restore(state);
-
- // ensure that the size didn't change since we first allocated
- if (m_save_blob.size() != orig_size)
- throw emu_fatalerror("State size changed for ymfm chip");
-}
-
-// handle post-loading by restoring from the blob
-void ymf278b_device::device_post_load()
-{
- // populate the state from the blob
- ymfm::ymfm_saved_state state(m_save_blob, false);
- m_fm.save_restore(state);
-}
diff --git a/src/devices/sound/ymf278b.h b/src/devices/sound/ymf278b.h
deleted file mode 100644
index 07812279283..00000000000
--- a/src/devices/sound/ymf278b.h
+++ /dev/null
@@ -1,192 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:R. Belmont, Olivier Galibert, hap
-#ifndef MAME_SOUND_YMF278B_H
-#define MAME_SOUND_YMF278B_H
-
-#pragma once
-
-#include "ymfm/src/ymfm_opl.h"
-#include "dirom.h"
-
-class ymf278b_device : public device_t, public device_sound_interface, public device_rom_interface<22>, public ymfm::ymfm_interface
-{
-public:
- static constexpr u8 STATUS_BUSY = 0x01;
- static constexpr u8 STATUS_LD = 0x02;
-
- // YMF278B is OPL4
- using fm_engine = ymfm::fm_engine_base<ymfm::opl4_registers>;
-
- // constructor
- ymf278b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- // configuration helpers
- auto irq_handler() { return m_update_irq.bind(); }
-
- // read/write access
- u8 read(offs_t offset);
- void write(offs_t offset, u8 data);
-
-protected:
- // device-level overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_clock_changed() override;
- virtual void device_pre_save() override;
- virtual void device_post_load() override;
-
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
- // sound stream update overrides
- virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
-
- // device_rom_interface overrides
- virtual void rom_bank_updated() override;
-
-private:
- // timer callbacks
- void fm_timer_handler(void *ptr, int param) { m_engine->engine_timer_expired(param); }
- void fm_mode_write(void *ptr, int param) { m_engine->engine_mode_write(param); }
- void fm_check_interrupts(void *ptr, int param) { m_engine->engine_check_interrupts(); }
-
- struct YMF278BSlot
- {
- int16_t wave; /* wavetable number */
- int16_t F_NUMBER; /* frequency */
- int8_t octave; /* octave */
- int8_t preverb; /* pseudo-reverb */
- int8_t DAMP; /* damping */
- int8_t CH; /* output channel */
- int8_t LD; /* level direct */
- int8_t TL; /* total level */
- int8_t pan; /* panpot */
- int8_t LFO; /* LFO */
- int8_t VIB; /* vibrato */
- int8_t AM; /* tremolo */
-
- int8_t AR; /* attack rate */
- int8_t D1R; /* decay 1 rate */
- int8_t DL; /* decay level */
- int8_t D2R; /* decay 2 rate */
- int8_t RC; /* rate correction */
- int8_t RR; /* release rate */
-
- uint32_t step; /* fixed-point frequency step */
- uint64_t stepptr; /* fixed-point pointer into the sample */
-
- int8_t active; /* channel is playing */
- int8_t KEY_ON; /* slot keyed on */
- int8_t bits; /* width of the samples */
- uint32_t startaddr;
- uint32_t loopaddr;
- uint32_t endaddr;
-
- int env_step;
- uint32_t env_vol;
- uint32_t env_vol_step;
- uint32_t env_vol_lim;
- int8_t env_preverb;
-
- int num; /* slot number (for debug only) */
- };
-
- int compute_rate(YMF278BSlot *slot, int val);
- uint32_t compute_decay_env_vol_step(YMF278BSlot *slot, int val);
- void compute_freq_step(YMF278BSlot *slot);
- void compute_envelope(YMF278BSlot *slot);
- void irq_check();
- void retrigger_sample(YMF278BSlot *slot);
- void C_w(uint8_t reg, uint8_t data);
- void timer_busy_start(int is_pcm);
- void precompute_rate_tables();
- void register_save_state();
-
- // internal state
- uint8_t m_pcmregs[256];
- YMF278BSlot m_slots[24];
- int8_t m_wavetblhdr;
- int8_t m_memmode;
- int32_t m_memadr;
-
- emu_timer *m_timer_busy;
- emu_timer *m_timer_ld;
-
- int32_t m_fm_l, m_fm_r;
- int32_t m_pcm_l, m_pcm_r;
-
- uint32_t m_fm_pos;
-
- uint8_t m_port_C, m_port_AB, m_lastport;
- bool m_next_status_id;
-
- // precomputed tables
- uint32_t m_lut_ar[64]; // attack rate
- uint32_t m_lut_dr[64]; // decay rate
- int32_t m_volume[256*4]; // precalculated attenuation values with some margin for envelope and pan levels
- int m_pan_left[16],m_pan_right[16]; // pan volume offsets
- int32_t m_mix_level[8];
-
- int m_clock;
- int m_rate;
-
- sound_stream * m_stream;
- std::vector<int32_t> m_mix_buffer;
-
- // ymfm OPL4 -- cribbed from ymfm_device_base_common until we figure out how to
- // make a proper chip out of this hybrid
- fm_engine m_fm;
- attotime m_busy_end; // busy end time
- emu_timer *m_timer[2]; // two timers
- devcb_write_line m_update_irq; // IRQ update callback
- std::vector<uint8_t> m_save_blob;// save state blob for FM
-
- // perform a synchronized write
- virtual void ymfm_sync_mode_write(uint8_t data) override
- {
- machine().scheduler().synchronize(timer_expired_delegate(FUNC(ymf278b_device::fm_mode_write), this), data);
- }
-
- // perform a synchronized interrupt check
- virtual void ymfm_sync_check_interrupts() override
- {
- // if we're currently executing a CPU, schedule the interrupt check;
- // otherwise, do it directly
- auto &scheduler = machine().scheduler();
- if (scheduler.currently_executing())
- scheduler.synchronize(timer_expired_delegate(FUNC(ymf278b_device::fm_check_interrupts), this));
- else
- m_engine->engine_check_interrupts();
- }
-
- // set a timer
- virtual void ymfm_set_timer(uint32_t tnum, int32_t duration_in_clocks) override
- {
- if (duration_in_clocks >= 0)
- m_timer[tnum]->adjust(attotime::from_ticks(duration_in_clocks, device_t::clock()), tnum);
- else
- m_timer[tnum]->enable(false);
- }
-
- // set the time when busy will be clear
- virtual void ymfm_set_busy_end(uint32_t clocks) override
- {
- m_busy_end = machine().time() + attotime::from_ticks(clocks, device_t::clock());
- }
-
- // are we past the busy clear time?
- virtual bool ymfm_is_busy() override
- {
- return (machine().time() < m_busy_end);
- }
-
- // handle IRQ signaling
- virtual void ymfm_update_irq(bool asserted) override
- {
- if (!m_update_irq.isnull())
- m_update_irq(asserted ? ASSERT_LINE : CLEAR_LINE);
- }
-};
-
-DECLARE_DEVICE_TYPE(YMF278B, ymf278b_device)
-
-#endif // MAME_SOUND_YMF278B_H
diff --git a/src/devices/sound/ymfm_mame.h b/src/devices/sound/ymfm_mame.h
index 342e571e747..74acf718182 100644
--- a/src/devices/sound/ymfm_mame.h
+++ b/src/devices/sound/ymfm_mame.h
@@ -123,22 +123,19 @@ protected:
return (machine().time() < m_busy_end);
}
- // the chip implementation calls this whenever a new value is written to
- // one of the chip's output ports (only applies to some chip types); our
- // responsibility is to pass the written data on to any consumers
- virtual void ymfm_io_write(uint8_t port, uint8_t data) override
+ // the chip implementation calls this whenever data is read from outside
+ // of the chip; our responsibility is to provide the data requested
+ virtual uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address) override
{
- if (!m_io_write[port & 1].isnull())
- m_io_write[port & 1](data);
+ return (type != ymfm::ACCESS_IO || m_io_read[address & 1].isnull()) ? 0 : m_io_read[address & 1]();
}
- // the chip implementation calls this whenever an on-chip register is read
- // which returns data from one of the chip's input ports; our responsibility
- // is to produce the current input value so that it can be reflected by the
- // read operation
- virtual uint8_t ymfm_io_read(uint8_t port) override
+ // the chip implementation calls this whenever data is written outside
+ // of the chip; our responsibility is to pass the written data on to any consumers
+ virtual void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data) override
{
- return m_io_read[port & 1].isnull() ? 0 : m_io_read[port & 1]();
+ if (type == ymfm::ACCESS_IO && !m_io_write[address & 1].isnull())
+ m_io_write[address & 1](data);
}
// handle device start
diff --git a/src/devices/sound/ymopl.cpp b/src/devices/sound/ymopl.cpp
index 9953a5a3551..352906f40b8 100644
--- a/src/devices/sound/ymopl.cpp
+++ b/src/devices/sound/ymopl.cpp
@@ -51,26 +51,30 @@ void y8950_device::rom_bank_updated()
//-------------------------------------------------
-// ymfm_adpcm_b_read - callback to read data for
+// ymfm_external_read - callback to read data for
// the ADPCM-B engine; in this case, from our
// default address space
//-------------------------------------------------
-uint8_t y8950_device::ymfm_adpcm_b_read(uint32_t offset)
+uint8_t y8950_device::ymfm_external_read(ymfm::access_class type, uint32_t offset)
{
- return read_byte(offset);
+ if (type == ymfm::ACCESS_ADPCM_B)
+ return read_byte(offset);
+ return parent::ymfm_external_read(type, offset);
}
//-------------------------------------------------
-// ymfm_adpcm_b_write - callback to write data to
+// ymfm_external_write - callback to write data to
// the ADPCM-B engine; in this case, to our
// default address space
//-------------------------------------------------
-void y8950_device::ymfm_adpcm_b_write(uint32_t offset, uint8_t data)
+void y8950_device::ymfm_external_write(ymfm::access_class type, uint32_t offset, uint8_t data)
{
- space().write_byte(offset, data);
+ if (type == ymfm::ACCESS_ADPCM_B)
+ return space().write_byte(offset, data);
+ parent::ymfm_external_write(type, offset, data);
}
@@ -110,6 +114,75 @@ ymf262_device::ymf262_device(const machine_config &mconfig, const char *tag, dev
//*********************************************************
+// YMF278B DEVICE
+//*********************************************************
+
+DEFINE_DEVICE_TYPE(YMF278B, ymf278b_device, "ymf278b", "YMF278B OPL4")
+
+//-------------------------------------------------
+// ymf278b_device - constructor
+//-------------------------------------------------
+
+ymf278b_device::ymf278b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ ymfm_device_base<ymfm::ymf278b>(mconfig, tag, owner, clock, YMF278B),
+ device_rom_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// rom_bank_updated - refresh the stream if the
+// ROM banking changes
+//-------------------------------------------------
+
+void ymf278b_device::rom_bank_updated()
+{
+ m_stream->update();
+}
+
+
+//-------------------------------------------------
+// ymfm_external_read - callback to read data for
+// the ADPCM-B engine; in this case, from our
+// default address space
+//-------------------------------------------------
+
+uint8_t ymf278b_device::ymfm_external_read(ymfm::access_class type, uint32_t offset)
+{
+ if (type == ymfm::ACCESS_PCM)
+ return read_byte(offset);
+ return 0;
+}
+
+
+//-------------------------------------------------
+// ymfm_external_write - callback to write data to
+// the ADPCM-B engine; in this case, to our
+// default address space
+//-------------------------------------------------
+
+void ymf278b_device::ymfm_external_write(ymfm::access_class type, uint32_t offset, uint8_t data)
+{
+ if (type == ymfm::ACCESS_PCM)
+ return space().write_byte(offset, data);
+}
+
+
+//-------------------------------------------------
+// ymfm_external_write - callback to write data to
+// the ADPCM-B engine; in this case, to our
+// default address space
+//-------------------------------------------------
+
+void ymf278b_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ // rotate the outputs so that the DO2 outputs are first
+ parent::update_internal(outputs, 2);
+}
+
+
+
+//*********************************************************
// YM2413 DEVICE
//*********************************************************
diff --git a/src/devices/sound/ymopl.h b/src/devices/sound/ymopl.h
index 4d221529b4b..4ec8f605023 100644
--- a/src/devices/sound/ymopl.h
+++ b/src/devices/sound/ymopl.h
@@ -29,6 +29,8 @@ DECLARE_DEVICE_TYPE(Y8950, y8950_device);
class y8950_device : public ymfm_device_base<ymfm::y8950>, public device_rom_interface<21>
{
+ using parent = ymfm_device_base<ymfm::y8950>;
+
public:
// constructor
y8950_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -48,8 +50,8 @@ protected:
private:
// ADPCM read/write callbacks
- uint8_t ymfm_adpcm_b_read(offs_t address) override;
- void ymfm_adpcm_b_write(offs_t address, uint8_t data) override;
+ uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address) override;
+ void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data) override;
};
@@ -81,6 +83,41 @@ public:
};
+// ======================> ymf278b_device
+
+DECLARE_DEVICE_TYPE(YMF278B, ymf278b_device);
+
+class ymf278b_device : public ymfm_device_base<ymfm::ymf278b>, public device_rom_interface<22>
+{
+ using parent = ymfm_device_base<ymfm::ymf278b>;
+
+public:
+ // constructor
+ ymf278b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // additional register reads
+ uint8_t data_pcm_r() { return update_streams().read_data_pcm(); }
+
+ // additional register writes
+ void address_hi_w(u8 data) { update_streams().write_address_hi(data); }
+ void data_hi_w(u8 data) { update_streams().write_data(data); }
+ void address_pcm_w(u8 data) { update_streams().write_address_pcm(data); }
+ void data_pcm_w(u8 data) { update_streams().write_data_pcm(data); }
+
+protected:
+ // device_rom_interface overrides
+ virtual void rom_bank_updated() override;
+
+ // sound overrides
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+private:
+ // ADPCM read/write callbacks
+ uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address) override;
+ void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data) override;
+};
+
+
// ======================> ym2413_device
DECLARE_DEVICE_TYPE(YM2413, ym2413_device);
diff --git a/src/devices/sound/ymopn.cpp b/src/devices/sound/ymopn.cpp
index 8733a5115cf..2d1751ce8b0 100644
--- a/src/devices/sound/ymopn.cpp
+++ b/src/devices/sound/ymopn.cpp
@@ -109,38 +109,31 @@ void ym2608_device::rom_bank_updated()
//-------------------------------------------------
-// ymfm_adpcm_a_read - callback to read data for
-// the ADPCM-A engine; in this case, from the
-// internal ROM containing drum samples
+// ymfm_external_read - callback to read data for
+// the ADPCM-A/B engines
//-------------------------------------------------
-uint8_t ym2608_device::ymfm_adpcm_a_read(uint32_t offset)
+uint8_t ym2608_device::ymfm_external_read(ymfm::access_class type, uint32_t offset)
{
- return m_internal->as_u8(offset % m_internal->bytes());
+ if (type == ymfm::ACCESS_ADPCM_A)
+ return m_internal->as_u8(offset % m_internal->bytes());
+ else if (type == ymfm::ACCESS_ADPCM_B)
+ return space(0).read_byte(offset);
+ return parent::ymfm_external_read(type, offset);
}
//-------------------------------------------------
-// ymfm_adpcm_b_read - callback to read data for
-// the ADPCM-B engine; in this case, from our
-// default address space
-//-------------------------------------------------
-
-uint8_t ym2608_device::ymfm_adpcm_b_read(uint32_t offset)
-{
- return space(0).read_byte(offset);
-}
-
-
-//-------------------------------------------------
-// ymfm_adpcm_b_write - callback to write data to
+// ymfm_external_write - callback to write data to
// the ADPCM-B engine; in this case, to our
// default address space
//-------------------------------------------------
-void ym2608_device::ymfm_adpcm_b_write(uint32_t offset, uint8_t data)
+void ym2608_device::ymfm_external_write(ymfm::access_class type, uint32_t offset, uint8_t data)
{
- space(0).write_byte(offset, data);
+ if (type == ymfm::ACCESS_ADPCM_B)
+ return space(0).write_byte(offset, data);
+ parent::ymfm_external_write(type, offset, data);
}
@@ -208,28 +201,18 @@ void ym2610_device_base<ChipClass>::device_start()
//-------------------------------------------------
-// ymfm_adpcm_a_read - callback to read data for
-// the ADPCM-A engine; in this case, from address
-// space 0
-//-------------------------------------------------
-
-template<typename ChipClass>
-uint8_t ym2610_device_base<ChipClass>::ymfm_adpcm_a_read(uint32_t offset)
-{
- return space(0).read_byte(offset);
-}
-
-
-//-------------------------------------------------
-// ymfm_adpcm_b_read - callback to read data for
-// the ADPCM-B engine; in this case, from address
-// space 1
+// ymfm_external_read - callback to read data for
+// the ADPCM-A/B engines
//-------------------------------------------------
template<typename ChipClass>
-uint8_t ym2610_device_base<ChipClass>::ymfm_adpcm_b_read(uint32_t offset)
+uint8_t ym2610_device_base<ChipClass>::ymfm_external_read(ymfm::access_class type, uint32_t offset)
{
- return space(1).read_byte(offset);
+ if (type == ymfm::ACCESS_ADPCM_A)
+ return space(0).read_byte(offset);
+ else if (type == ymfm::ACCESS_ADPCM_B)
+ return space(1).read_byte(offset);
+ return 0;
}
diff --git a/src/devices/sound/ymopn.h b/src/devices/sound/ymopn.h
index 7bf72216aff..c65738dee07 100644
--- a/src/devices/sound/ymopn.h
+++ b/src/devices/sound/ymopn.h
@@ -75,9 +75,8 @@ protected:
private:
// ADPCM read/write callbacks
- virtual uint8_t ymfm_adpcm_a_read(uint32_t address) override;
- virtual uint8_t ymfm_adpcm_b_read(uint32_t address) override;
- virtual void ymfm_adpcm_b_write(uint32_t address, u8 data) override;
+ virtual uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address) override;
+ virtual void ymfm_external_write(ymfm::access_class type, uint32_t address, u8 data) override;
// internal state
required_memory_region m_internal; // internal memory region
@@ -115,8 +114,7 @@ protected:
private:
// ADPCM read/write callbacks
- virtual uint8_t ymfm_adpcm_a_read(offs_t address) override;
- virtual uint8_t ymfm_adpcm_b_read(offs_t address) override;
+ virtual uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address) override;
// internal state
address_space_config const m_adpcm_a_config; // address space 0 config (ADPCM-A)