From 77a3e13a96dc86920e2f656b847741514807d0b0 Mon Sep 17 00:00:00 2001 From: qufb <93520295+qufb@users.noreply.github.com> Date: Sat, 11 Nov 2023 15:15:56 +0000 Subject: sega/segapico.cpp: Initial external interrupt support for Copera (#11722) --- hash/copera.xml | 19 ++++++++-- src/mame/sega/segapico.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 9 deletions(-) diff --git a/hash/copera.xml b/hash/copera.xml index 7f7a83ed70a..ec9da900dc6 100644 --- a/hash/copera.xml +++ b/hash/copera.xml @@ -5,7 +5,7 @@ license:CC0-1.0 Games for the MIXT BOOK PLAYER COPERA -* おしゃれの国のアリス - Oshare no Kuni no Alice (Yamaha - ???? - MMGS-8) +Missing / Unconfirmed: * 冒険!メロリン島 - Bouken! Merorin Shima (Yamaha - ???? - MMGS-10) --> @@ -117,9 +117,24 @@ Games for the MIXT BOOK PLAYER COPERA + + Alice in Oshare-Land + 1994? + Yamaha + + + + + + + + + + + Copera no Chikyuu Daisuki - 1994? + 1994? Yamaha diff --git a/src/mame/sega/segapico.cpp b/src/mame/sega/segapico.cpp index ff4cfc767d7..aeec0011647 100644 --- a/src/mame/sega/segapico.cpp +++ b/src/mame/sega/segapico.cpp @@ -126,6 +126,8 @@ C = MB3514 / 9325 M36 #include "softlist_dev.h" #include "speaker.h" +#define VERBOSE (0) +#include "logmacro.h" namespace { @@ -585,29 +587,49 @@ public: void copera(machine_config &config); protected: + virtual void machine_reset() override; virtual void machine_start() override; + void copera_pcm_cb(int state); + uint16_t copera_io_read(offs_t offset); + void copera_io_write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + + TIMER_CALLBACK_MEMBER(process_ext_timer); + private: void copera_mem(address_map &map); required_device m_picocart; -}; + std::unique_ptr m_ext_regs; + bool m_is_ext_requested; + emu_timer *m_ext_timer; +}; +TIMER_CALLBACK_MEMBER(copera_state::process_ext_timer) +{ + // TODO: When is it enabled? Expected even if games don't set bit 3 of VDP mode register 3... + if (m_is_ext_requested) + { + m_maincpu->set_input_line(2, HOLD_LINE); + m_is_ext_requested = false; + } + else + { + m_maincpu->set_input_line(2, CLEAR_LINE); + m_is_ext_requested = true; + } +} void copera_state::copera_mem(address_map &map) { map(0x000000, 0x3fffff).rom(); - map(0x800000, 0x80001f).rw(FUNC(copera_state::pico_68k_io_read), FUNC(copera_state::pico_68k_io_write)); - + map(0xbff800, 0xbff87f).rw(FUNC(copera_state::copera_io_read), FUNC(copera_state::copera_io_write)); // FIXME: Guessed range. map(0xc00000, 0xc0001f).rw(m_vdp, FUNC(sega315_5313_device::vdp_r), FUNC(sega315_5313_device::vdp_w)); - map(0xe00000, 0xe0ffff).ram().mirror(0x1f0000); } - - static void copera_cart(device_slot_interface &device) { device.option_add_internal("rom", MD_STD_ROM); @@ -631,6 +653,28 @@ void copera_state::machine_start() m_sega_315_5641_pcm->start_w(1); m_vdp->stop_timers(); + + m_ext_regs = make_unique_clear(0x80/2); + + // FIXME: Guessed timing. + // + // It must be less than HBLANK. Games have a busy loop where they read + // VDP status register and check if bit 7 (vertical interrupt pending) is + // set and then cleared (e.g. Copera no Chikyuu Daisuki @ 0xfb3c4). + // Too frequent EXT interrupts result in that subroutine only executing after + // scanline 224 and will never catch bit 7 set. + m_ext_timer = timer_alloc(FUNC(copera_state::process_ext_timer), this); + m_ext_timer->adjust(attotime::zero, 0, m_vdp->screen().scan_period() * 20); +} + +void copera_state::machine_reset() +{ + pico_base_state::machine_reset(); + + m_is_ext_requested = true; + m_ext_regs[0] = 0; + m_ext_regs[0x2/2] = 0xffff; + m_ext_regs[0x4/2] = 0xffff; } void copera_state::copera(machine_config &config) @@ -649,11 +693,41 @@ void copera_state::copera(machine_config &config) SPEAKER(config, "rspeaker").front_right(); SEGA_315_5641_PCM(config, m_sega_315_5641_pcm, upd7759_device::STANDARD_CLOCK); - m_sega_315_5641_pcm->fifo_cb().set(FUNC(copera_state::sound_cause_irq)); + m_sega_315_5641_pcm->fifo_cb().set(FUNC(copera_state::copera_pcm_cb)); m_sega_315_5641_pcm->add_route(ALL_OUTPUTS, "lspeaker", 0.16); m_sega_315_5641_pcm->add_route(ALL_OUTPUTS, "rspeaker", 0.16); } +void copera_state::copera_pcm_cb(int state) +{ + // TODO: Not IRQ3 (games assign an infinite loop handler), likely handled by an EXT callback. +} + +uint16_t copera_state::copera_io_read(offs_t offset) +{ + LOG("COPERA IO r @ %08x: %08x = %04x\n", m_maincpu->pc(), 0xbff800 + offset * 2, m_ext_regs[offset]); + return m_ext_regs[offset]; +} + +void copera_state::copera_io_write(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + if (ACCESSING_BITS_8_15) + { + m_ext_regs[offset] = (data & mem_mask) | (m_ext_regs[offset] & 0x00FF); + } + if (ACCESSING_BITS_0_7) + { + m_ext_regs[offset] = (data & mem_mask) | (m_ext_regs[offset] & 0xFF00); + } + + // TODO: We only enable EXT handler callback 3. + if (((m_ext_regs[0x4/2] & 0xFF) == 0xd) && ((m_ext_regs[0x2/2] & 0xff) == 0x3f)) + { + m_ext_regs[0] |= 1 << 3; + } + + LOG("COPERA IO w @ %08x: %08x = %04x (mask %08x)\n", m_maincpu->pc(), 0xbff800 + offset * 2, data, mem_mask); +} ROM_START( copera ) -- cgit v1.2.3