diff --git a/src/sound/snd_opl_ymfm.cpp b/src/sound/snd_opl_ymfm.cpp index 6acbf79f3..28ea7a621 100644 --- a/src/sound/snd_opl_ymfm.cpp +++ b/src/sound/snd_opl_ymfm.cpp @@ -21,6 +21,7 @@ #include "ymfm/ymfm_opl.h" extern "C" { +#include <86box/86box.h> #include <86box/timer.h> #include <86box/device.h> #include <86box/sound.h> @@ -81,6 +82,9 @@ public: memset(m_oldsamples, 0, sizeof(m_oldsamples)); m_rateratio = (samplerate << RSM_FRAC) / m_chip.sample_rate(m_clock); m_clock_us = 1000000 / (double) m_clock; + m_subtract[0] = 80.0; + m_subtract[1] = 320.0; + m_type = type; timer_add(&m_timers[0], YMFMChip::timer1, this, 0); timer_add(&m_timers[1], YMFMChip::timer2, this, 0); @@ -97,11 +101,14 @@ public: return; pc_timer_t *timer = &m_timers[tnum]; - if (duration_in_clocks < 0) { + if (duration_in_clocks < 0) timer_stop(timer); - } else { + else { double period = m_clock_us * duration_in_clocks; - timer_on_auto(timer, period); + if (period < m_subtract[tnum]) + m_engine->engine_timer_expired(tnum); + else + timer_on_auto(timer, period); } } @@ -172,6 +179,11 @@ virtual void generate_resampled(int32_t *data, uint32_t num_samples) override return m_chip.read(addr); } + virtual uint32_t get_special_flags(void) override + { + return ((m_type == FM_YMF262) || (m_type == FM_YMF289B)) ? 0x8000 : 0x0000; + } + static void timer1(void *priv) { YMFMChip *drv = (YMFMChip *) priv; @@ -187,7 +199,7 @@ virtual void generate_resampled(int32_t *data, uint32_t num_samples) override private: ChipType m_chip; uint32_t m_clock; - double m_clock_us; + double m_clock_us, m_subtract[2]; typename ChipType::output_data m_output; pc_timer_t m_timers[2]; diff --git a/src/sound/ymfm/ymfm.h b/src/sound/ymfm/ymfm.h index d9c3bca3b..ae13faedd 100644 --- a/src/sound/ymfm/ymfm.h +++ b/src/sound/ymfm/ymfm.h @@ -543,6 +543,8 @@ public: // noted busy end time and return true if we haven't yet passed it virtual bool ymfm_is_busy() { return false; } + virtual uint32_t get_special_flags(void) { return 0x0000; } + // // I/O functions // diff --git a/src/sound/ymfm/ymfm_fm.ipp b/src/sound/ymfm/ymfm_fm.ipp index 17bbc9150..7e5109d59 100644 --- a/src/sound/ymfm/ymfm_fm.ipp +++ b/src/sound/ymfm/ymfm_fm.ipp @@ -1472,11 +1472,14 @@ void fm_engine_base::assign_operators() template void fm_engine_base::update_timer(uint32_t tnum, uint32_t enable, int32_t delta_clocks) { + uint32_t subtract = !!(tnum >> 15); + tnum &= 0x7fff; + // if the timer is live, but not currently enabled, set the timer if (enable && !m_timer_running[tnum]) { // period comes from the registers, and is different for each - uint32_t period = (tnum == 0) ? (1024 - m_regs.timer_a_value()) : 16 * (256 - m_regs.timer_b_value()); + uint32_t period = (tnum == 0) ? (1024 - subtract - m_regs.timer_a_value()) : 16 * (256 - subtract - m_regs.timer_b_value()); // caller can also specify a delta to account for other effects period += delta_clocks; @@ -1581,8 +1584,11 @@ void fm_engine_base::engine_mode_write(uint8_t data) // load timers; note that timer B gets a small negative adjustment because // the *16 multiplier is free-running, so the first tick of the clock // is a bit shorter - update_timer(1, m_regs.load_timer_b(), -(m_total_clocks & 15)); - update_timer(0, m_regs.load_timer_a(), 0); + // OPL3 begins counting immediately instead of after the first period is over. + // We use bit 15 of the timer number on those chips to inform that this was a + // control register write, and to therefore, subtract 1 counting cycle. + update_timer(1 | m_intf.get_special_flags(), m_regs.load_timer_b(), -(m_total_clocks & 15)); + update_timer(0 | m_intf.get_special_flags(), m_regs.load_timer_a(), 0); } }