sega/segapico.cpp: Initial external interrupt support for Copera (#11722)

This commit is contained in:
qufb 2023-11-11 15:15:56 +00:00 committed by GitHub
parent 68c73d6144
commit 77a3e13a96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 98 additions and 9 deletions

View File

@ -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
</part>
</software>
<software name="aliceosh">
<description>Alice in Oshare-Land</description>
<year>1994?</year> <!-- PCB date -->
<publisher>Yamaha</publisher>
<info name="serial" value="MMGS-8"/>
<info name="alt_title" value="おしゃれの国のアリス"/>
<part name="cart" interface="copera_cart">
<feature name="pcb" value="171-6882A" />
<feature name="ic1" value="MPR-17989-H" />
<dataarea name="rom" size="524288">
<rom name="mpr-17989-h.ic1" size="524288" crc="e330151a" sha1="20b9f4624188b90fdc0122cb80896c809e1b324b" loadflag="load16_word_swap" />
</dataarea>
</part>
</software>
<software name="copechik">
<description>Copera no Chikyuu Daisuki</description>
<year>1994?</year>
<year>1994?</year> <!-- PCB date -->
<publisher>Yamaha</publisher>
<info name="serial" value="MMGS-9"/>
<info name="alt_title" value="コペラのちきゅうだいすき"/>

View File

@ -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<copera_cart_slot_device> m_picocart;
std::unique_ptr<uint16_t[]> 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<uint16_t[]>(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 )