nintendo/vsnes.cpp: A few minor changes. (#10205)

* Added watchdog timer (currently only active on DualSystem games).
* Set perfect quantum for vsmahjng, just like all the other DualSystem games.
* Switched vssoccera from bnglngby's init, which installs a fake IRQ hack, to standard init.
* Switched suprmriobl to empty_init and gave it more consistent function naming.
This commit is contained in:
0kmg 2022-08-11 08:06:13 -08:00 committed by GitHub
parent dec2c8e8b7
commit 40137c52eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -144,6 +144,7 @@ Changes:
#include "cpu/m6502/n2a03.h"
#include "cpu/z80/z80.h"
#include "machine/nvram.h"
#include "machine/watchdog.h"
#include "sound/sn76496.h"
#include "video/ppu2c0x.h"
@ -166,6 +167,7 @@ protected:
, m_ppu2(*this, "ppu2")
, m_sensor(*this, "sensor")
, m_nvram(*this, "nvram")
, m_watchdog(*this, "watchdog")
, m_gfx1_rom(*this, "gfx1")
, m_prg_banks(*this, "prg%u", 0U)
, m_prg_view(*this, "prg_view")
@ -207,6 +209,7 @@ protected:
optional_device<nes_zapper_sensor_device> m_sensor;
optional_device<nvram_device> m_nvram;
optional_device<watchdog_timer_device> m_watchdog;
optional_memory_region m_gfx1_rom;
@ -301,7 +304,6 @@ public:
}
void vsdual(machine_config &config);
void vsdual_pi(machine_config &config);
void init_vsdual();
protected:
@ -322,21 +324,21 @@ public:
}
void vs_smbbl(machine_config &config);
void init_smbbl();
protected:
virtual void machine_start() override;
private:
void bootleg_sound_write(offs_t offset, u8 data);
u8 vsnes_bootleg_z80_data_r();
u8 vsnes_bootleg_z80_address_r(offs_t offset);
void vsnes_bootleg_scanline(int scanline, bool vblank, bool blanked);
u8 vsnes_bootleg_ppudata();
void vsnes_bootleg_z80_map(address_map &map);
void vsnes_cpu1_bootleg_map(address_map &map);
void vsnes_ppu_bootleg_map(address_map &map);
void vssmbbl_sn_w(offs_t offset, u8 data);
void smbbl_6502_sn_w(offs_t offset, u8 data);
void smbbl_z80_sn_w(offs_t offset, u8 data);
u8 smbbl_z80_data_r();
u8 smbbl_z80_address_r(offs_t offset);
void smbbl_scanline_cb(int scanline, bool vblank, bool blanked);
u8 smbbl_ppu_data_r();
void smbbl_6502_map(address_map &map);
void smbbl_z80_map(address_map &map);
void smbbl_ppu_map(address_map &map);
required_device<sn76489_device> m_sn1;
required_device<sn76489_device> m_sn2;
@ -416,6 +418,7 @@ u8 vs_base_state::vsnes_in0_r()
ret |= m_coins[Side]->read(); // merge coins, etc
ret |= (m_dsw[Side]->read() & 3) << 3; // merge 2 dipswitches
ret |= Side << 7; // CPU indicator bit
return ret;
}
@ -423,6 +426,11 @@ u8 vs_base_state::vsnes_in0_r()
template <u8 Side>
u8 vs_base_state::vsnes_in1_r()
{
// Only the SUB side CPU can kick the watchdog, which it must do by periodically reading $4017.
// This is one reason UniSystem games too must be installed on the SUB side.
if (m_watchdog && Side == SUB)
m_watchdog->watchdog_reset();
int p2 = 2 * Side + 1;
if (m_input_strobe[Side] & 1)
@ -539,6 +547,8 @@ void vs_dual_state::machine_start()
void vs_smbbl_state::machine_start()
{
m_ppu1->set_scanline_callback(*this, FUNC(vs_smbbl_state::smbbl_scanline_cb));
u8 *base = m_gfx1_rom->base();
int entries = m_gfx1_rom->bytes() / 0x2000;
m_chr_banks[0]->configure_entries(0, entries, base, 0x2000);
@ -927,7 +937,7 @@ void vs_uni_state::init_bnglngby()
}
//**********************************************************************************
// VS Dualsystem
// VS DualSystem
template <u8 Side>
void vs_dual_state::vsdual_vrom_banking(u8 data)
@ -953,18 +963,18 @@ void vs_dual_state::init_vsdual()
//**********************************************************************************
// Vs. Super Mario Bros (Bootleg)
void vs_smbbl_state::vsnes_bootleg_scanline(int scanline, bool vblank, bool blanked)
void vs_smbbl_state::smbbl_scanline_cb(int scanline, bool vblank, bool blanked)
{
// Z80 IRQ is controlled by two factors:
// - bit 6 of current (next) scanline number
// - bit 6 of latched scanline number from Z80 reading $4000
if (!(m_bootleg_latched_scanline & 0x40))
if (!BIT(m_bootleg_latched_scanline, 6))
{
m_subcpu->set_input_line(INPUT_LINE_IRQ0, ((scanline + 1) & 0x40) ? ASSERT_LINE : CLEAR_LINE);
m_subcpu->set_input_line(INPUT_LINE_IRQ0, BIT(scanline + 1, 6) ? ASSERT_LINE : CLEAR_LINE);
}
}
u8 vs_smbbl_state::vsnes_bootleg_ppudata()
u8 vs_smbbl_state::smbbl_ppu_data_r()
{
// CPU always reads higher CHR ROM banks from $2007, PPU always reads lower ones
m_chr_banks[0]->set_entry(1);
@ -974,17 +984,6 @@ u8 vs_smbbl_state::vsnes_bootleg_ppudata()
return data;
}
void vs_smbbl_state::init_smbbl()
{
m_bootleg_sound_offset = 0;
m_bootleg_sound_data = 0;
m_bootleg_latched_scanline = 0;
m_ppu1->set_scanline_callback(*this, FUNC(vs_smbbl_state::vsnes_bootleg_scanline));
m_maincpu->space(AS_PROGRAM).install_read_handler(0x2007, 0x2007, read8smo_delegate(*this, FUNC(vs_smbbl_state::vsnes_bootleg_ppudata)));
}
//******************************************************************************
@ -1038,7 +1037,7 @@ void vs_base_state::vsnes_ppu2_map(address_map &map)
u8 vs_smbbl_state::vsnes_bootleg_z80_address_r(offs_t offset)
u8 vs_smbbl_state::smbbl_z80_address_r(offs_t offset)
{
// NMI routine uses the value read here as the low part of an offset from 0x2000 to store a value read at 0x4000
// before reading 0x6000 and returning
@ -1051,7 +1050,7 @@ u8 vs_smbbl_state::vsnes_bootleg_z80_address_r(offs_t offset)
return 0xf0 | m_bootleg_sound_offset;
}
void vs_smbbl_state::bootleg_sound_write(offs_t offset, u8 data)
void vs_smbbl_state::smbbl_6502_sn_w(offs_t offset, u8 data)
{
m_bootleg_sound_offset = offset & 0xf;
m_bootleg_sound_data = data;
@ -1059,7 +1058,7 @@ void vs_smbbl_state::bootleg_sound_write(offs_t offset, u8 data)
m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
}
u8 vs_smbbl_state::vsnes_bootleg_z80_data_r()
u8 vs_smbbl_state::smbbl_z80_data_r()
{
//printf("Z80 read data %02x\n", m_bootleg_sound_data);
m_bootleg_latched_scanline = m_ppu1->get_current_scanline();
@ -1069,7 +1068,7 @@ u8 vs_smbbl_state::vsnes_bootleg_z80_data_r()
}
// A0 = SN #1 enable, A1 = SN #2 enable, A2 = SN write enables (both) on edge
void vs_smbbl_state::vssmbbl_sn_w(offs_t offset, u8 data)
void vs_smbbl_state::smbbl_z80_sn_w(offs_t offset, u8 data)
{
// printf("sn_w: ofs %x\n", offset & 7);
if (!(offset & 4))
@ -1088,11 +1087,12 @@ void vs_smbbl_state::vssmbbl_sn_w(offs_t offset, u8 data)
// the bootleg still makes writes to the PSG addresses, it seems the Z80 should interpret them to play the sounds
void vs_smbbl_state::vsnes_cpu1_bootleg_map(address_map &map)
void vs_smbbl_state::smbbl_6502_map(address_map &map)
{
map(0x0000, 0x07ff).mirror(0x0800).ram();
map(0x2000, 0x3fff).rw(m_ppu1, FUNC(ppu2c0x_device::read), FUNC(ppu2c0x_device::write));
map(0x4000, 0x400f).w(FUNC(vs_smbbl_state::bootleg_sound_write));
map(0x2007, 0x2007).r(FUNC(vs_smbbl_state::smbbl_ppu_data_r));
map(0x4000, 0x400f).w(FUNC(vs_smbbl_state::smbbl_6502_sn_w));
map(0x4016, 0x4016).rw(FUNC(vs_smbbl_state::vsnes_in0_r<MAIN>), FUNC(vs_smbbl_state::vsnes_in0_w<MAIN>));
map(0x4017, 0x4017).r(FUNC(vs_smbbl_state::vsnes_in1_r<MAIN>)); // IN1 - input port 2 / PSG second control register
map(0x4020, 0x4020).w(FUNC(vs_smbbl_state::vsnes_coin_counter_w<MAIN>));
@ -1113,16 +1113,15 @@ void vs_smbbl_state::vsnes_cpu1_bootleg_map(address_map &map)
// x11x xxxx xxxx xxxx = 6502 address (6000) (read)
// x11x xxxx xxxx xW21 = SN76489s (6000) (write)
void vs_smbbl_state::vsnes_bootleg_z80_map(address_map &map)
void vs_smbbl_state::smbbl_z80_map(address_map &map)
{
map(0x0000, 0x1fff).rom().region("sub", 0);
map(0x2000, 0x27ff).ram();
map(0x4000, 0x5fff).r(FUNC(vs_smbbl_state::vsnes_bootleg_z80_data_r)); // read in IRQ & NMI
map(0x6000, 0x7fff).rw(FUNC(vs_smbbl_state::vsnes_bootleg_z80_address_r), FUNC(vs_smbbl_state::vssmbbl_sn_w));
map(0x2000, 0x27ff).mirror(0x1800).ram();
map(0x4000, 0x5fff).r(FUNC(vs_smbbl_state::smbbl_z80_data_r)); // read in IRQ & NMI
map(0x6000, 0x7fff).rw(FUNC(vs_smbbl_state::smbbl_z80_address_r), FUNC(vs_smbbl_state::smbbl_z80_sn_w));
}
void vs_smbbl_state::vsnes_ppu_bootleg_map(address_map &map)
void vs_smbbl_state::smbbl_ppu_map(address_map &map)
{
map(0x0000, 0x1fff).bankr(m_chr_banks[0]);
map(0x2000, 0x27ff).mirror(0x1800).ram();
@ -2573,6 +2572,9 @@ void vs_uni_state::vsnes(machine_config &config)
// sound hardware
SPEAKER(config, "mono").front_center();
maincpu.add_route(ALL_OUTPUTS, "mono", 0.50);
// watchdog resets system between 1.23s and 1.33s in hardware tests, exact timing unknown
WATCHDOG_TIMER(config, m_watchdog); // .set_time(attotime::from_msec(1300)); // FIXME: this won't work yet since the UniSystem emulation uses the wrong side of the PCB
}
void vs_uni_state::jajamaru(machine_config &config)
@ -2625,6 +2627,9 @@ void vs_dual_state::vsdual(machine_config &config)
n2a03_device &subcpu(N2A03(config, m_subcpu, NTSC_APU_CLOCK));
subcpu.set_addrmap(AS_PROGRAM, &vs_dual_state::vsnes_cpu2_map);
// need high level of interleave to keep screens in sync in Balloon Fight.
config.set_perfect_quantum(m_maincpu);
config.set_default_layout(layout_dualhsxs);
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
@ -2654,25 +2659,19 @@ void vs_dual_state::vsdual(machine_config &config)
SPEAKER(config, "rspeaker").front_right();
maincpu.add_route(ALL_OUTPUTS, "lspeaker", 0.50);
subcpu.add_route(ALL_OUTPUTS, "rspeaker", 0.50);
}
void vs_dual_state::vsdual_pi(machine_config &config)
{
vsdual(config);
config.set_perfect_quantum(m_maincpu);
// need high level of interleave to keep screens in sync in Balloon Fight.
// however vsmahjng doesn't like perfect interleave? you end up needing to reset it to boot? maybe something in a bad default state? watchdog?
// as the board would always be running in 'perfect interleave' the fact the Mahjong game doesn't work like this needs investigating.
// watchdog resets system between 1.23s and 1.33s in hardware tests, exact timing unknown
WATCHDOG_TIMER(config, m_watchdog).set_time(attotime::from_msec(1300));
}
void vs_smbbl_state::vs_smbbl(machine_config &config)
{
// basic machine hardware
M6502(config, m_maincpu, XTAL(16'000'000)/8);
m_maincpu->set_addrmap(AS_PROGRAM, &vs_smbbl_state::vsnes_cpu1_bootleg_map);
m_maincpu->set_addrmap(AS_PROGRAM, &vs_smbbl_state::smbbl_6502_map);
Z80(config, m_subcpu, XTAL(16'000'000)/8); // Z8400APS-Z80CPU
m_subcpu->set_addrmap(AS_PROGRAM, &vs_smbbl_state::vsnes_bootleg_z80_map);
m_subcpu->set_addrmap(AS_PROGRAM, &vs_smbbl_state::smbbl_z80_map);
// video hardware
screen_device &screen1(SCREEN(config, "screen1", SCREEN_TYPE_RASTER));
@ -2682,7 +2681,7 @@ void vs_smbbl_state::vs_smbbl(machine_config &config)
screen1.set_screen_update("ppu1", FUNC(ppu2c0x_device::screen_update));
PPU_2C04C(config, m_ppu1);
m_ppu1->set_addrmap(0, &vs_smbbl_state::vsnes_ppu_bootleg_map);
m_ppu1->set_addrmap(0, &vs_smbbl_state::smbbl_ppu_map);
m_ppu1->set_cpu_tag(m_maincpu);
m_ppu1->set_screen("screen1");
m_ppu1->int_callback().set_inputline(m_maincpu, INPUT_LINE_NMI);
@ -3678,8 +3677,8 @@ GAME( 1986, rbibb, 0, vsnes, rbibb, vs_uni_state
GAME( 1986, rbibba, rbibb, vsnes, rbibb, vs_uni_state, init_rbibb, ROT0, "Namco", "Vs. Atari R.B.I. Baseball (set 2)", 0 )
GAME( 1986, suprmrio, 0, vsnes, suprmrio, vs_uni_state, init_vsnormal, ROT0, "Nintendo", "Vs. Super Mario Bros. (set SM4-4 E)", 0 )
GAME( 1986, suprmrioa, suprmrio, vsnes, suprmrio, vs_uni_state, init_vsnormal, ROT0, "Nintendo", "Vs. Super Mario Bros. (set ?, harder)", 0 )
GAME( 1986, suprmriobl, suprmrio, vs_smbbl, suprmrio, vs_smbbl_state, init_smbbl, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 1)", 0 ) // timer starts at 200(!)
GAME( 1986, suprmriobl2, suprmrio, vs_smbbl, suprmrio, vs_smbbl_state, init_smbbl, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 2)", 0 ) // timer starts at 300
GAME( 1986, suprmriobl, suprmrio, vs_smbbl, suprmrio, vs_smbbl_state, empty_init, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 1)", 0 ) // timer starts at 200(!)
GAME( 1986, suprmriobl2, suprmrio, vs_smbbl, suprmrio, vs_smbbl_state, empty_init, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 2)", 0 ) // timer starts at 300
GAME( 1988, skatekds, suprmrio, vsnes, suprmrio, vs_uni_state, init_vsnormal, ROT0, "hack (Two-Bit Score)", "Vs. Skate Kids. (Graphic hack of Super Mario Bros.)", 0 )
GAME( 1985, vsskykid, 0, vsnes, vsskykid, vs_uni_state, init_vs108, ROT0, "Namco", "Vs. Super SkyKid", 0 )
GAME( 1987, tkoboxng, 0, vsnes, tkoboxng, vs_uni_state, init_tkoboxng, ROT0, "Namco / Data East USA", "Vs. T.K.O. Boxing", 0 )
@ -3692,7 +3691,7 @@ GAME( 1984, vspinbal, 0, vsnes, vspinbal, vs_uni_state
GAME( 1984, vspinbalj, vspinbal, vsnes, vspinblj, vs_uni_state, init_vsnormal, ROT0, "Nintendo Co., Ltd.", "Vs. Pinball (Japan, set PN3 B)", 0 )
GAME( 1986, vsslalom, 0, vsnes, vsslalom, vs_uni_state, init_vsnormal, ROT0, "Rare Coin-It Inc.", "Vs. Slalom", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1985, vssoccer, 0, vsnes, vssoccer, vs_uni_state, init_vsnormal, ROT0, "Nintendo", "Vs. Soccer (set SC4-2 A)", 0 )
GAME( 1985, vssoccera, vssoccer, vsnes, vssoccer, vs_uni_state, init_bnglngby, ROT0, "Nintendo", "Vs. Soccer (set SC4-3 ?)", 0 )
GAME( 1985, vssoccera, vssoccer, vsnes, vssoccer, vs_uni_state, init_vsnormal, ROT0, "Nintendo", "Vs. Soccer (set SC4-3 ?)", 0 )
GAME( 1986, vsgradus, 0, vsnes, vsgradus, vs_uni_state, init_vskonami, ROT0, "Konami", "Vs. Gradius (US, set GR E)", 0 )
GAME( 1987, nvs_platoon, 0, vsnes, platoon, vs_uni_state, init_platoon, ROT0, "Ocean Software Limited", "Vs. Platoon", 0 )
GAME( 1987, vstetris, 0, vsnes, vstetris, vs_uni_state, init_vsnormal, ROT0, "Academysoft-Elorg", "Vs. Tetris" , 0 )
@ -3709,14 +3708,14 @@ GAME( 1986, vsgshoe, 0, vsgshoe, vsgshoe, vs_uni_state
GAME( 1988, vsfdf, 0, vsnes, vsfdf, vs_uni_state, init_vsfdf, ROT0, "Sunsoft", "Vs. Freedom Force", 0 )
// Dual games
GAME( 1984, vstennis, 0, vsdual_pi, vstennis, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Tennis (Japan/USA, set TE A-3)" , 0 )
GAME( 1984, vstennisa, vstennis, vsdual_pi, vstennis, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Tennis (Japan/USA, set 2)", 0 )
GAME( 1984, vstennisb, vstennis, vsdual_pi, vstennis, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Tennis (Japan/USA, set 3)", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1984, wrecking, 0, vsdual_pi, wrecking, vs_dual_state, init_vsdual, ROT0, "Nintendo", "Vs. Wrecking Crew", 0 )
GAME( 1984, balonfgt, 0, vsdual_pi, balonfgt, vs_dual_state, init_vsdual, ROT0, "Nintendo", "Vs. Balloon Fight (set BF4 A-3)", 0 )
GAME( 1984, vstennis, 0, vsdual, vstennis, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Tennis (Japan/USA, set TE A-3)" , 0 )
GAME( 1984, vstennisa, vstennis, vsdual, vstennis, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Tennis (Japan/USA, set 2)", 0 )
GAME( 1984, vstennisb, vstennis, vsdual, vstennis, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Tennis (Japan/USA, set 3)", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1984, wrecking, 0, vsdual, wrecking, vs_dual_state, init_vsdual, ROT0, "Nintendo", "Vs. Wrecking Crew", 0 )
GAME( 1984, balonfgt, 0, vsdual, balonfgt, vs_dual_state, init_vsdual, ROT0, "Nintendo", "Vs. Balloon Fight (set BF4 A-3)", 0 )
GAME( 1984, vsmahjng, 0, vsdual, vsmahjng, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Mahjong (Japan)", 0 )
GAME( 1984, vsbball, 0, vsdual_pi, vsbball, vs_dual_state, init_vsdual, ROT0, "Nintendo of America", "Vs. Baseball (US, set BA E-1)", 0 )
GAME( 1984, vsbballj, vsbball, vsdual_pi, vsbballj, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Baseball (Japan, set BA A-3)", 0 )
GAME( 1984, vsbballja, vsbball, vsdual_pi, vsbballj, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Baseball (Japan, set BA A-2)", 0 )
GAME( 1984, vsbballjb, vsbball, vsdual_pi, vsbballj, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Baseball (Japan, set BA A-1)", 0 )
GAME( 1984, iceclmrd, 0, vsdual_pi, iceclmrj, vs_dual_state, init_vsdual, ROT0, "Nintendo", "Vs. Ice Climber Dual (set IC4-4 A-1)", 0 )
GAME( 1984, vsbball, 0, vsdual, vsbball, vs_dual_state, init_vsdual, ROT0, "Nintendo of America", "Vs. Baseball (US, set BA E-1)", 0 )
GAME( 1984, vsbballj, vsbball, vsdual, vsbballj, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Baseball (Japan, set BA A-3)", 0 )
GAME( 1984, vsbballja, vsbball, vsdual, vsbballj, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Baseball (Japan, set BA A-2)", 0 )
GAME( 1984, vsbballjb, vsbball, vsdual, vsbballj, vs_dual_state, init_vsdual, ROT0, "Nintendo Co., Ltd.", "Vs. Baseball (Japan, set BA A-1)", 0 )
GAME( 1984, iceclmrd, 0, vsdual, iceclmrj, vs_dual_state, init_vsdual, ROT0, "Nintendo", "Vs. Ice Climber Dual (set IC4-4 A-1)", 0 )