Skip to content

Commit

Permalink
sega/segapico.cpp: Initial external interrupt support for Copera
Browse files Browse the repository at this point in the history
  • Loading branch information
qufb committed Nov 10, 2023
1 parent 98e0f52 commit 48e56b7
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 9 deletions.
19 changes: 17 additions & 2 deletions hash/copera.xml
Expand Up @@ -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)
-->

Expand Down Expand Up @@ -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="コペラのちきゅうだいすき"/>
Expand Down
88 changes: 81 additions & 7 deletions src/mame/sega/segapico.cpp
Expand Up @@ -126,6 +126,8 @@ C = MB3514 / 9325 M36
#include "softlist_dev.h"
#include "speaker.h"

#define VERBOSE (0)
#include "logmacro.h"

namespace {

Expand Down Expand Up @@ -585,29 +587,49 @@ class copera_state : public pico_base_state
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);
Expand All @@ -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)
Expand All @@ -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 )
Expand Down

0 comments on commit 48e56b7

Please sign in to comment.