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