Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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