Skip to content

sega/megadriv.cpp: replace irq_callback with vpa_after / vpa_sync cpu_space_map #14038

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 5 additions & 14 deletions hash/megadriv.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3055,14 +3055,11 @@ No [VDP] sprites


<!-- This was marked as rev. A on the EA sticker, but its header (and ROM markings) uses the Jpn title... weird situation :-) -->
<software name="fatalrewa" cloneof="fatalrew" supported="no">
<software name="fatalrewa" cloneof="fatalrew" supported="yes">
<!-- Originally marked as Fatal Rewind, boots as The Killing Game Show -->
<description>The Killing Game Show (Europe)</description>
<year>1991</year>
<publisher>Electronic Arts</publisher>
<notes><![CDATA[
Crashes after EA logo, requires better [VDP] irq handling
]]></notes>
<part name="cart" interface="megadriv_cart">
<feature name="pcb" value="PWB SC40X1 REV B"/>
<feature name="u1" value="KILLING GAME SHOW KIL03"/> <!-- location not really marked on PCB, using u1 for consistency -->
Expand All @@ -3074,13 +3071,10 @@ Crashes after EA logo, requires better [VDP] irq handling


<!-- Only Euro is confirmed -->
<software name="fatalrew" supported="no">
<software name="fatalrew" supported="yes">
<description>Fatal Rewind (Europe, USA, rev. A)</description>
<year>1991</year>
<publisher>Electronic Arts</publisher>
<notes><![CDATA[
Crashes after EA logo, requires better [VDP] irq handling
]]></notes>
<part name="cart" interface="megadriv_cart">
<feature name="pcb" value="PWB SC40X1 REV B"/>
<feature name="u1" value="FATAL REWIND FAT04"/> <!-- location not really marked on PCB, using u1 for consistency -->
Expand Down Expand Up @@ -17742,12 +17736,12 @@ https://segaretro.org/Elitserien_96
</part>
</software>

<software name="killshow" cloneof="fatalrew" supported="no">
<software name="killshow" cloneof="fatalrew" supported="partial">
<description>The Killing Game Show (Japan)</description>
<year>1993</year>
<publisher>Electronic Arts Victor</publisher>
<notes><![CDATA[
Crashes after EA logo, requires better [VDP] irq handling
No sound in intro opening (verify)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't find a reference for this specific version, may be related to MT09222 anyway.

]]></notes>
<info name="serial" value="EM20021"/>
<info name="release" value="19930820"/>
Expand Down Expand Up @@ -27237,13 +27231,10 @@ Throws "this game is [...] european megadrive system" even with megadriv system
</part>
</software>

<software name="sesame" supported="no">
<software name="sesame" supported="yes">
<description>Sesame Street Counting Cafe (USA)</description>
<year>1994</year>
<publisher>Electronic Arts</publisher>
<notes><![CDATA[
Black screen, requires better [VDP] irq handling
]]></notes>
<part name="cart" interface="megadriv_cart">
<dataarea name="rom" width="16" endianness="big" size="1048576">
<rom name="sesame street counting cafe (usa).bin" size="1048576" crc="0a4f48c3" sha1="d5ef2b50cf1a22e07401f6a14c7946df66d8b605"/>
Expand Down
46 changes: 26 additions & 20 deletions src/devices/video/315_5313.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,30 +585,37 @@ void sega315_5313_device::vdp_set_register(int regnum, u8 value)
{
//osd_printf_debug("setting reg 0, irq enable is now %d\n", MEGADRIVE_REG0_IRQ4_ENABLE);

// fatalrew and sesame are very fussy about pending interrupts.
// Former in particular will quickly enable both after the EA logo (cfr. killshow at PC=0x2267a),
// and irq 6 will jump to illegal addresses because the correlated routine isn't set in stack
// but delayed a bit.
// Note that irq 6 is masked for about 5 frames, leaving the assumption that it mustn't
// be left on during all this time.
if (m_irq4_pending)
// fatalrew/killshow and sesame are very fussy about pending interrupts.
// https://jsgroth.dev/blog/posts/emulator-bugs-fatal-rewind/
// https://gendev.spritesmind.net/forum/viewtopic.php?t=2202
// this gets 1 cycle delay on both HINT and VINT for gen_test_int_delay.bin
// TODO: first time around said test prints HINT=20, pressing start gives the correct value
if (m_irq4_pending && MEGADRIVE_REG0_IRQ4_ENABLE)
{
if (MEGADRIVE_REG0_IRQ4_ENABLE)
m_lv4irqline_callback(true);
else
m_lv4irqline_callback(false);
m_irq4_on_timer->adjust(attotime::from_ticks(16, clock() / 4));
// if (MEGADRIVE_REG0_IRQ4_ENABLE)
// m_lv4irqline_callback(true);
// else
// m_lv4irqline_callback(false);
}
else
m_lv4irqline_callback(false);

}

if (regnum == 0x01)
{
if (m_irq6_pending)
if (m_irq6_pending && MEGADRIVE_REG01_IRQ6_ENABLE)
{
if (MEGADRIVE_REG01_IRQ6_ENABLE)
m_lv6irqline_callback(true);
else
m_lv6irqline_callback(false);
m_irq6_on_timer->adjust(attotime::from_ticks(16, clock() / 4));

// if (MEGADRIVE_REG01_IRQ6_ENABLE)
// m_lv6irqline_callback(true);
// else
// m_lv6irqline_callback(false);
}
else
m_lv6irqline_callback(false);
}

// if (regnum == 0x0a)
Expand Down Expand Up @@ -2254,7 +2261,7 @@ void sega315_5313_device::vdp_handle_scanline_callback(int scanline)
if (get_scanline_counter() == m_irq6_scanline)
{
// osd_printf_debug("x %d", get_scanline_counter());
m_irq6_on_timer->adjust(attotime::from_usec(6));
m_irq6_on_timer->adjust(attotime::from_ticks(16, clock() / 4));
m_irq6_pending = 1;
m_vblank_flag = 1;

Expand All @@ -2276,8 +2283,7 @@ void sega315_5313_device::vdp_handle_scanline_callback(int scanline)

if (MEGADRIVE_REG0_IRQ4_ENABLE)
{
// TODO: arbitrary timing
m_irq4_on_timer->adjust(attotime::from_usec(1));
m_irq4_on_timer->adjust(attotime::from_ticks(16, clock() / 4));
//osd_printf_debug("irq4 on scanline %d reload %d\n", get_scanline_counter(), MEGADRIVE_REG0A_HINT_VALUE);
}
else
Expand Down Expand Up @@ -2320,7 +2326,7 @@ void sega315_5313_device::vdp_handle_eof()

m_vblank_flag = 0;
// Not here, breaks warlock
//m_irq6_pending = 0;
// m_irq6_pending = 0;

/* Set it to -1 here, so it becomes 0 when the first timer kicks in */
if (!m_use_alt_timing) m_scanline_counter = -1;
Expand Down
19 changes: 15 additions & 4 deletions src/devices/video/315_5313.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class sega315_5313_device : public sega315_5313_mode4_device, public device_gfx_
typedef device_delegate<void (int scanline)> md_32x_scanline_helper_delegate;

auto snd_irq() { return m_sndirqline_callback.bind(); }
auto lv6_irq() { return m_lv6irqline_callback.bind(); }
auto lv4_irq() { return m_lv4irqline_callback.bind(); }
auto vint_cb() { return m_lv6irqline_callback.bind(); }
auto hint_cb() { return m_lv4irqline_callback.bind(); }

void set_lcm_scaling(bool lcm_scaling) { m_lcm_scaling = lcm_scaling; }
void set_alt_timing(int use_alt_timing) { m_use_alt_timing = use_alt_timing; }
Expand Down Expand Up @@ -73,8 +73,19 @@ class sega315_5313_device : public sega315_5313_mode4_device, public device_gfx_
TIMER_CALLBACK_MEMBER(irq4_on_timer_callback);
void vdp_handle_eof();
void device_reset_old();
void vdp_clear_irq6_pending() { m_irq6_pending = 0; }
void vdp_clear_irq4_pending() { m_irq4_pending = 0; }
void irq_ack()
{
if (m_irq6_pending)
{
m_irq6_pending = 0;
m_lv6irqline_callback(false);
}
else if (m_irq4_pending)
{
m_irq4_pending = 0;
m_lv4irqline_callback(false);
}
}

// set some VDP variables at start (shall be moved to a device interface?)
void set_scanline_counter(int scanline) { m_scanline_counter = scanline; }
Expand Down
61 changes: 28 additions & 33 deletions src/mame/sega/calcune.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ class calcune_state : public driver_device
int m_vdp_state = 0;

void vdp_sndirqline_callback_genesis_z80(int state);
void vdp_lv6irqline_callback_genesis_68k(int state);
void vdp_lv4irqline_callback_genesis_68k(int state);
void vdp_vint_cb(int state);
void vdp_hint_cb(int state);

IRQ_CALLBACK_MEMBER(genesis_int_callback);
void cpu_space_map(address_map &map);

uint16_t cal_700000_r();
void cal_770000_w(uint16_t data);
Expand Down Expand Up @@ -206,42 +206,37 @@ void calcune_state::machine_reset()
m_vdp[1]->device_reset_old();
}


IRQ_CALLBACK_MEMBER(calcune_state::genesis_int_callback)
void calcune_state::cpu_space_map(address_map &map)
{
if (irqline==4)
{
m_vdp[0]->vdp_clear_irq4_pending();
}

if (irqline==6)
{
m_vdp[0]->vdp_clear_irq6_pending();
}

return (0x60+irqline*4)/4; // vector address
map(0xfffff3, 0xfffff3).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 25; }));
// IPL0, should be unused by Calcune
map(0xfffff5, 0xfffff5).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 26; }));
map(0xfffff7, 0xfffff7).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 27; }));
map(0xfffff9, 0xfffff9).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([this] () -> u8 {
m_vdp[0]->irq_ack();
return 28;
}));
map(0xfffffb, 0xfffffb).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 29; }));
map(0xfffffd, 0xfffffd).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([this] () -> u8 {
m_vdp[0]->irq_ack();
return 30;
}));
map(0xffffff, 0xffffff).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 31; }));
}

void calcune_state::vdp_sndirqline_callback_genesis_z80(int state)
{
}

void calcune_state::vdp_lv6irqline_callback_genesis_68k(int state)
// this looks odd but is the logic the Genesis code requires
void calcune_state::vdp_vint_cb(int state)
{
// this looks odd but is the logic the Genesis code requires
if (state == ASSERT_LINE)
m_maincpu->set_input_line(6, HOLD_LINE);
else
m_maincpu->set_input_line(6, CLEAR_LINE);
m_maincpu->set_input_line(6, state ? ASSERT_LINE : CLEAR_LINE);
}

void calcune_state::vdp_lv4irqline_callback_genesis_68k(int state)
void calcune_state::vdp_hint_cb(int state)
{
// this looks odd but is the logic the Genesis code requires
if (state == ASSERT_LINE)
m_maincpu->set_input_line(4, HOLD_LINE);
else
m_maincpu->set_input_line(4, CLEAR_LINE);
m_maincpu->set_input_line(4, state ? ASSERT_LINE : CLEAR_LINE);
}

void calcune_state::machine_start()
Expand All @@ -256,7 +251,7 @@ void calcune_state::calcune(machine_config &config)
{
M68000(config, m_maincpu, OSC1_CLOCK / 7); /* 7.67 MHz */
m_maincpu->set_addrmap(AS_PROGRAM, &calcune_state::calcune_map);
m_maincpu->set_irq_acknowledge_callback(FUNC(calcune_state::genesis_int_callback));
m_maincpu->set_addrmap(m68000_base_device::AS_CPU_SPACE, &calcune_state::cpu_space_map);

Z80(config, "z80", OSC1_CLOCK / 15).set_disable(); /* 3.58 MHz, no code is ever uploaded for the Z80, so it's unused here even if it is present on the PCB */

Expand All @@ -271,8 +266,8 @@ void calcune_state::calcune(machine_config &config)
SEGA315_5313(config, m_vdp[0], OSC1_CLOCK, m_maincpu);
m_vdp[0]->set_is_pal(false);
m_vdp[0]->snd_irq().set(FUNC(calcune_state::vdp_sndirqline_callback_genesis_z80));
m_vdp[0]->lv6_irq().set(FUNC(calcune_state::vdp_lv6irqline_callback_genesis_68k));
m_vdp[0]->lv4_irq().set(FUNC(calcune_state::vdp_lv4irqline_callback_genesis_68k));
m_vdp[0]->vint_cb().set(FUNC(calcune_state::vdp_vint_cb));
m_vdp[0]->hint_cb().set(FUNC(calcune_state::vdp_hint_cb));
m_vdp[0]->set_alt_timing(1);
m_vdp[0]->add_route(ALL_OUTPUTS, "speaker", 0.25, 0);
m_vdp[0]->add_route(ALL_OUTPUTS, "speaker", 0.25, 1);
Expand All @@ -281,8 +276,8 @@ void calcune_state::calcune(machine_config &config)
m_vdp[1]->set_is_pal(false);
// are these not hooked up or should they OR with the other lines?
// m_vdp[1]->snd_irq().set(FUNC(calcune_state::vdp_sndirqline_callback_genesis_z80));
// m_vdp[1]->lv6_irq().set(FUNC(calcune_state::vdp_lv6irqline_callback_genesis_68k));
// m_vdp[1]->lv4_irq().set(FUNC(calcune_state::vdp_lv4irqline_callback_genesis_68k));
// m_vdp[1]->vint_cb().set(FUNC(calcune_state::vdp_vint_cb));
// m_vdp[1]->hint_cb().set(FUNC(calcune_state::vdp_hint_cb));
m_vdp[1]->set_alt_timing(1);
m_vdp[1]->add_route(ALL_OUTPUTS, "speaker", 0.25, 0);
m_vdp[1]->add_route(ALL_OUTPUTS, "speaker", 0.25, 1);
Expand Down
59 changes: 27 additions & 32 deletions src/mame/sega/megadriv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,41 +736,36 @@ void md_base_state::vdp_sndirqline_callback_genesis_z80(int state)
}
}

// this comes from the vdp, and is connected to 68k irq level 6 (main vbl interrupt)
void md_core_state::vdp_lv6irqline_callback_genesis_68k(int state)
// this comes from the vdp, and is connected to 68k irq level 6 (IPL2, main vbl interrupt)
void md_core_state::vdp_vint_cb(int state)
{
if (state == ASSERT_LINE)
m_maincpu->set_input_line(6, HOLD_LINE);
else
m_maincpu->set_input_line(6, CLEAR_LINE);
m_maincpu->set_input_line(6, state ? ASSERT_LINE : CLEAR_LINE);
}

// this comes from the vdp, and is connected to 68k irq level 4 (raster interrupt)
void md_core_state::vdp_lv4irqline_callback_genesis_68k(int state)
// this comes from the vdp, and is connected to 68k irq level 4 (IPL1, raster interrupt)
void md_core_state::vdp_hint_cb(int state)
{
if (state == ASSERT_LINE)
m_maincpu->set_input_line(4, HOLD_LINE);
else
m_maincpu->set_input_line(4, CLEAR_LINE);
m_maincpu->set_input_line(4, state ? ASSERT_LINE : CLEAR_LINE);
}

/* Callback when the 68k takes an IRQ */
IRQ_CALLBACK_MEMBER(md_core_state::genesis_int_callback)
void md_core_state::cpu_space_map(address_map &map)
{
if (irqline==4)
{
m_vdp->vdp_clear_irq4_pending();
}

if (irqline==6)
{
m_vdp->vdp_clear_irq6_pending();
}

return (0x60+irqline*4)/4; // vector address
map(0xfffff3, 0xfffff3).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 25; }));
// TODO: IPL0 (external irq tied to VDP IE2)
map(0xfffff5, 0xfffff5).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 26; }));
map(0xfffff7, 0xfffff7).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 27; }));
map(0xfffff9, 0xfffff9).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([this] () -> u8 {
m_vdp->irq_ack();
return 28;
}));
map(0xfffffb, 0xfffffb).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 29; }));
map(0xfffffd, 0xfffffd).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([this] () -> u8 {
m_vdp->irq_ack();
return 30;
}));
map(0xffffff, 0xffffff).before_time(m_maincpu, FUNC(m68000_device::vpa_sync)).after_delay(m_maincpu, FUNC(m68000_device::vpa_after)).lr8(NAME([] () -> u8 { return 31; }));
}


void md_core_state::megadriv_timers(machine_config &config)
{
TIMER(config, m_scan_timer).configure_generic(m_vdp, FUNC(sega315_5313_device::megadriv_scanline_timer_callback));
Expand All @@ -779,15 +774,15 @@ void md_core_state::megadriv_timers(machine_config &config)
void md_core_state::md_core_ntsc(machine_config &config)
{
M68000(config, m_maincpu, MASTER_CLOCK_NTSC / 7); // 7.67 MHz
m_maincpu->set_irq_acknowledge_callback(FUNC(md_core_state::genesis_int_callback));
m_maincpu->set_addrmap(m68000_base_device::AS_CPU_SPACE, &md_core_state::cpu_space_map);
// IRQs are handled via the timers

megadriv_timers(config);

SEGA315_5313(config, m_vdp, MASTER_CLOCK_NTSC, m_maincpu);
m_vdp->set_is_pal(false);
m_vdp->lv6_irq().set(FUNC(md_core_state::vdp_lv6irqline_callback_genesis_68k));
m_vdp->lv4_irq().set(FUNC(md_core_state::vdp_lv4irqline_callback_genesis_68k));
m_vdp->vint_cb().set(FUNC(md_core_state::vdp_vint_cb));
m_vdp->hint_cb().set(FUNC(md_core_state::vdp_hint_cb));
m_vdp->set_screen("megadriv");

SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
Expand All @@ -803,15 +798,15 @@ void md_core_state::md_core_ntsc(machine_config &config)
void md_core_state::md_core_pal(machine_config &config)
{
M68000(config, m_maincpu, MASTER_CLOCK_PAL / 7); // 7.67 MHz
m_maincpu->set_irq_acknowledge_callback(FUNC(md_core_state::genesis_int_callback));
m_maincpu->set_addrmap(m68000_base_device::AS_CPU_SPACE, &md_core_state::cpu_space_map);
// IRQs are handled via the timers

megadriv_timers(config);

SEGA315_5313(config, m_vdp, MASTER_CLOCK_PAL, m_maincpu);
m_vdp->set_is_pal(true);
m_vdp->lv6_irq().set(FUNC(md_core_state::vdp_lv6irqline_callback_genesis_68k));
m_vdp->lv4_irq().set(FUNC(md_core_state::vdp_lv4irqline_callback_genesis_68k));
m_vdp->vint_cb().set(FUNC(md_core_state::vdp_vint_cb));
m_vdp->hint_cb().set(FUNC(md_core_state::vdp_hint_cb));
m_vdp->set_screen("megadriv");

SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
Expand Down
7 changes: 4 additions & 3 deletions src/mame/sega/megadriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ class md_core_state : public driver_device
optional_ioport m_io_reset;

private:
IRQ_CALLBACK_MEMBER(genesis_int_callback);
// IRQ_CALLBACK_MEMBER(genesis_int_callback);
void cpu_space_map(address_map &map);

void vdp_lv6irqline_callback_genesis_68k(int state);
void vdp_lv4irqline_callback_genesis_68k(int state);
void vdp_vint_cb(int state);
void vdp_hint_cb(int state);

void megadriv_timers(machine_config &config);
};
Expand Down
Loading