vsnes.cpp: working sound + "improved" graphics in Vs. SMB bootleg sets (#7360)

* vsnes.cpp: Improvements to Vs SMB bootleg sets based on kevtris' schematics/video.
* video/ppu2c0x.cpp: Add 2C04 PPU clone device and use the real palette ROMs for the bootlegs.
* video/ppu2c0x.cpp: Implement most PPU behavior differences for VS System bootlegs.
* video/ppu2c0x.cpp: add the 2c04 clone's delayed sprite rendering.
This commit is contained in:
Devin Acker 2020-10-22 08:56:02 -04:00 committed by GitHub
parent 0ff27cf174
commit 58ef849d18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 311 additions and 105 deletions

View File

@ -35,15 +35,16 @@
//**************************************************************************
// devices
DEFINE_DEVICE_TYPE(PPU_2C02, ppu2c02_device, "ppu2c02", "2C02 PPU")
DEFINE_DEVICE_TYPE(PPU_2C03B, ppu2c03b_device, "ppu2c03b", "2C03B PPC")
DEFINE_DEVICE_TYPE(PPU_2C04, ppu2c04_device, "ppu2c04", "2C04 PPU")
DEFINE_DEVICE_TYPE(PPU_2C07, ppu2c07_device, "ppu2c07", "2C07 PPU")
DEFINE_DEVICE_TYPE(PPU_PALC, ppupalc_device, "ppupalc", "Generic PAL Clone PPU")
DEFINE_DEVICE_TYPE(PPU_2C05_01, ppu2c05_01_device, "ppu2c05_01", "2C05_01 PPU")
DEFINE_DEVICE_TYPE(PPU_2C05_02, ppu2c05_02_device, "ppu2c05_02", "2C05_02 PPU")
DEFINE_DEVICE_TYPE(PPU_2C05_03, ppu2c05_03_device, "ppu2c05_03", "2C05_03 PPU")
DEFINE_DEVICE_TYPE(PPU_2C05_04, ppu2c05_04_device, "ppu2c05_04", "2C05_04 PPU")
DEFINE_DEVICE_TYPE(PPU_2C02, ppu2c02_device, "ppu2c02", "2C02 PPU")
DEFINE_DEVICE_TYPE(PPU_2C03B, ppu2c03b_device, "ppu2c03b", "2C03B PPC")
DEFINE_DEVICE_TYPE(PPU_2C04, ppu2c04_device, "ppu2c04", "2C04 PPU")
DEFINE_DEVICE_TYPE(PPU_2C07, ppu2c07_device, "ppu2c07", "2C07 PPU")
DEFINE_DEVICE_TYPE(PPU_PALC, ppupalc_device, "ppupalc", "Generic PAL Clone PPU")
DEFINE_DEVICE_TYPE(PPU_2C05_01, ppu2c05_01_device, "ppu2c05_01", "2C05_01 PPU")
DEFINE_DEVICE_TYPE(PPU_2C05_02, ppu2c05_02_device, "ppu2c05_02", "2C05_02 PPU")
DEFINE_DEVICE_TYPE(PPU_2C05_03, ppu2c05_03_device, "ppu2c05_03", "2C05_03 PPU")
DEFINE_DEVICE_TYPE(PPU_2C05_04, ppu2c05_04_device, "ppu2c05_04", "2C05_04 PPU")
DEFINE_DEVICE_TYPE(PPU_2C04C, ppu2c04_clone_device, "ppu2c04c", "2C04 Clone PPU")
// default address map
@ -99,6 +100,7 @@ ppu2c0x_device::ppu2c0x_device(const machine_config& mconfig, device_type type,
m_back_color(0),
m_refresh_data(0),
m_x_fine(0),
m_toggle(0),
m_tilecount(0),
m_latch(*this),
m_scanline_callback_proc(*this),
@ -106,7 +108,6 @@ ppu2c0x_device::ppu2c0x_device(const machine_config& mconfig, device_type type,
m_vidaccess_callback_proc(*this),
m_int_callback(*this),
m_refresh_latch(0),
m_toggle(0),
m_add(1),
m_videomem_addr(0),
m_data_latch(0),
@ -197,6 +198,17 @@ ppu2c05_04_device::ppu2c05_04_device(const machine_config& mconfig, const char*
m_security_value = 0x1b;
}
// Vs. Unisystem (Super Mario Bros. bootlegs)
ppu2c04_clone_device::ppu2c04_clone_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) :
ppu2c0x_device(mconfig, PPU_2C04C, tag, owner, clock),
m_palette_data(*this, "palette", 0x100)
{
m_scanlines_per_frame = VS_CLONE_SCANLINES_PER_FRAME;
m_vblank_first_scanline = VBLANK_FIRST_SCANLINE_VS_CLONE;
// background and sprites are always enabled; monochrome and color emphasis aren't supported
m_regs[PPU_CONTROL1] = ~(PPU_CONTROL1_COLOR_EMPHASIS | PPU_CONTROL1_DISPLAY_MONO);
}
//-------------------------------------------------
// device_start - device-specific startup
@ -259,6 +271,26 @@ void ppu2c0x_device::device_start()
save_item(NAME(m_palette_ram));
}
void ppu2c04_clone_device::device_start()
{
ppu2c0x_device::device_start();
/* this PPU clone draws sprites into a frame buffer before displaying them,
causing sprite rendering to be one frame behind tile/background rendering
(mainly noticeable during scrolling)
to simulate that, we can just have a secondary OAM buffer and swap them
at the end of each frame.
(theoretically this can cause the wrong sprite tiles to be drawn for
one frame after changing CHR banks, but the Vs. SMB bootlegs that use
this clone hardware don't actually have CHR bank switching anyway.
also generally affects PPU-side read timings involving the OAM, but
this still doesn't seem to matter for Vs. SMB specifically)
*/
m_spritebuf = make_unique_clear<uint8_t[]>(SPRITERAM_SIZE);
save_pointer(NAME(m_spritebuf), SPRITERAM_SIZE);
}
//**************************************************************************
// INLINE HELPERS
//**************************************************************************
@ -445,6 +477,24 @@ void ppu2c0x_rgb_device::init_palette_tables()
}
}
void ppu2c04_clone_device::init_palette_tables()
{
/* clone HW doesn't use color emphasis bits.
however, it does have two separate palettes: colors 0-63 for background, and 64-127 for sprites
(although the tile and sprite colors are identical in the Vs. SMB bootleg ROMs)
*/
for (int color_num = 0; color_num < 64*2; color_num++)
{
/* A7 line on palette ROMs is always high, color bits are in reverse order */
u8 color = m_palette_data[color_num | 0x80];
int R = bitswap<3>(color, 0, 1, 2);
int G = bitswap<3>(color, 3, 4, 5);
int B = bitswap<2>(color, 6, 7);
m_nespens[color_num] = (pal3bit(R) << 16) | (pal3bit(G) << 8) | pal2bit(B);
}
}
/*************************************
*
* PPU Initialization and Disposal
@ -704,6 +754,15 @@ void ppu2c0x_device::draw_background(uint8_t* line_priority)
}
}
void ppu2c04_clone_device::draw_background(uint8_t* line_priority)
{
// nametable selection is ignored below the hardwired scroll split position
if (m_scanline < 31)
m_refresh_data &= ~0x0c00;
ppu2c0x_device::draw_background(line_priority);
}
void ppu2c0x_device::draw_back_pen(uint32_t* dst, int back_pen)
{
*dst = m_nespens[back_pen];
@ -757,6 +816,17 @@ void ppu2c0x_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, ui
bitmap.pix(m_scanline, sprite_xpos + pixel) = pix;
}
void ppu2c04_clone_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32 &bitmap)
{
/* clone PPU clips sprites at the screen edges */
if ((sprite_xpos + pixel < 8) || (sprite_xpos + pixel) >= (VISIBLE_SCREEN_WIDTH - 6))
return;
uint16_t palval = m_palette_ram[((4 * color) | pixel_data) & 0x1f];
uint32_t pix = m_nespens[palval | 0x40];
bitmap.pix(m_scanline, sprite_xpos + pixel) = pix;
}
void ppu2c0x_device::read_extra_sprite_bits(int sprite_index)
{
// needed for some clones
@ -953,6 +1023,19 @@ void ppu2c0x_device::draw_sprites(uint8_t* line_priority)
}
}
void ppu2c04_clone_device::draw_sprites(uint8_t *line_priority)
{
ppu2c0x_device::draw_sprites(line_priority);
if (m_scanline == BOTTOM_VISIBLE_SCANLINE)
{
/* this frame's sprite buffer is cleared after being displayed
and the other one that was filled this frame will be displayed next frame */
m_spriteram.swap(m_spritebuf);
memset(m_spritebuf.get(), 0, SPRITERAM_SIZE);
}
}
/*************************************
*
* Scanline Rendering and Update
@ -1185,6 +1268,23 @@ uint8_t ppu2c0x_device::read(offs_t offset)
return m_data_latch;
}
uint8_t ppu2c04_clone_device::read(offs_t offset)
{
switch (offset & 7)
{
case PPU_STATUS: /* 2 */
// $2002 on this clone only contains the sprite 0 hit flag,
// and it's hardwired to trigger after a specific scanline, not based on actual sprite positions
if (m_scanline < 31 || m_scanline >= (m_vblank_first_scanline - 1))
return ~PPU_STATUS_SPRITE0_HIT;
return 0xff;
case PPU_SPRITE_DATA: /* 4 */
return m_spritebuf[m_regs[PPU_SPRITE_ADDRESS]];
}
return ppu2c0x_device::read(offset);
}
/*************************************
*
@ -1324,6 +1424,49 @@ void ppu2c0x_device::write(offs_t offset, uint8_t data)
m_data_latch = data;
}
void ppu2c04_clone_device::write(offs_t offset, uint8_t data)
{
switch (offset & 7)
{
case PPU_CONTROL0: /* 0 */
data &= (0x01 | PPU_CONTROL0_INC | PPU_CONTROL0_NMI); /* other bits of $2000 are ignored by this clone */
data |= PPU_CONTROL0_CHR_SELECT;
break;
case PPU_CONTROL1: /* 1 */
case PPU_SPRITE_ADDRESS: /* 3 */
return; /* $2001 and $2003 do nothing on this clone */
case PPU_SPRITE_DATA: /* 4 */
m_spritebuf[m_regs[PPU_SPRITE_ADDRESS]] = data;
m_regs[PPU_SPRITE_ADDRESS] = (m_regs[PPU_SPRITE_ADDRESS] + 1) & 0xff;
return;
case PPU_SCROLL: /* 5 */
if (m_toggle)
data = 0; /* no vertical scroll */
break;
case PPU_ADDRESS: /* 6 */
/* $2006 doesn't affect scroll latching */
if (m_toggle)
{
/* second write */
set_vram_dest((get_vram_dest() & 0xff00) | data);
}
else
{
/* first write */
set_vram_dest((get_vram_dest() & 0x00ff) | (data << 8));
}
m_toggle ^= 1;
return;
}
ppu2c0x_device::write(offset, data);
}
uint16_t ppu2c0x_device::get_vram_dest()
{
return m_videomem_addr;

View File

@ -53,14 +53,17 @@ public:
enum
{
NTSC_SCANLINES_PER_FRAME = 262,
PAL_SCANLINES_PER_FRAME = 312,
NTSC_SCANLINES_PER_FRAME = 262,
PAL_SCANLINES_PER_FRAME = 312,
VS_CLONE_SCANLINES_PER_FRAME = 280,
BOTTOM_VISIBLE_SCANLINE = 239,
VBLANK_FIRST_SCANLINE = 241,
VBLANK_FIRST_SCANLINE_PALC = 291,
VBLANK_LAST_SCANLINE_NTSC = 260,
VBLANK_LAST_SCANLINE_PAL = 310
BOTTOM_VISIBLE_SCANLINE = 239,
VBLANK_FIRST_SCANLINE = 241,
VBLANK_FIRST_SCANLINE_PALC = 291,
VBLANK_FIRST_SCANLINE_VS_CLONE = 240,
VBLANK_LAST_SCANLINE_NTSC = 260,
VBLANK_LAST_SCANLINE_PAL = 310,
VBLANK_LAST_SCANLINE_VS_CLONE = 279
// Both the scanline immediately before and immediately after VBLANK
// are non-rendering and non-vblank.
@ -207,6 +210,7 @@ protected:
int m_back_color; /* background color */
int m_refresh_data; /* refresh-related */
int m_x_fine; /* refresh-related */
int m_toggle; /* used to latch hi-lo scroll */
int m_tilecount; /* MMC5 can change attributes to subsets of the 34 visible tiles */
latch_delegate m_latch;
@ -228,7 +232,6 @@ private:
devcb_write_line m_int_callback; /* nmi access callback from interface */
int m_refresh_latch; /* refresh-related */
int m_toggle; /* used to latch hi-lo scroll */
int m_add; /* vram increment amount */
int m_videomem_addr; /* videomem address pointer */
int m_data_latch; /* latched videomem data */
@ -300,17 +303,39 @@ public:
ppu2c05_04_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
};
class ppu2c04_clone_device : public ppu2c0x_device {
public:
ppu2c04_clone_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual uint8_t read(offs_t offset) override;
virtual void write(offs_t offset, uint8_t data) override;
virtual void draw_background(uint8_t *line_priority) override;
virtual void draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32 &bitmap) override;
virtual void draw_sprites(uint8_t *line_priority) override;
virtual void init_palette_tables() override;
protected:
virtual void device_start() override;
private:
required_region_ptr<uint8_t> m_palette_data;
std::unique_ptr<uint8_t[]> m_spritebuf; /* buffered sprite ram for next frame */
};
// device type definition
//extern const device_type PPU_2C0X;
DECLARE_DEVICE_TYPE(PPU_2C02, ppu2c02_device) // NTSC NES
DECLARE_DEVICE_TYPE(PPU_2C03B, ppu2c03b_device) // Playchoice 10
DECLARE_DEVICE_TYPE(PPU_2C04, ppu2c04_device) // Vs. Unisystem
DECLARE_DEVICE_TYPE(PPU_2C07, ppu2c07_device) // PAL NES
DECLARE_DEVICE_TYPE(PPU_PALC, ppupalc_device) // PAL Clones
DECLARE_DEVICE_TYPE(PPU_2C05_01, ppu2c05_01_device) // Vs. Unisystem (Ninja Jajamaru Kun)
DECLARE_DEVICE_TYPE(PPU_2C05_02, ppu2c05_02_device) // Vs. Unisystem (Mighty Bomb Jack)
DECLARE_DEVICE_TYPE(PPU_2C05_03, ppu2c05_03_device) // Vs. Unisystem (Gumshoe)
DECLARE_DEVICE_TYPE(PPU_2C05_04, ppu2c05_04_device) // Vs. Unisystem (Top Gun)
DECLARE_DEVICE_TYPE(PPU_2C02, ppu2c02_device) // NTSC NES
DECLARE_DEVICE_TYPE(PPU_2C03B, ppu2c03b_device) // Playchoice 10
DECLARE_DEVICE_TYPE(PPU_2C04, ppu2c04_device) // Vs. Unisystem
DECLARE_DEVICE_TYPE(PPU_2C07, ppu2c07_device) // PAL NES
DECLARE_DEVICE_TYPE(PPU_PALC, ppupalc_device) // PAL Clones
DECLARE_DEVICE_TYPE(PPU_2C05_01, ppu2c05_01_device) // Vs. Unisystem (Ninja Jajamaru Kun)
DECLARE_DEVICE_TYPE(PPU_2C05_02, ppu2c05_02_device) // Vs. Unisystem (Mighty Bomb Jack)
DECLARE_DEVICE_TYPE(PPU_2C05_03, ppu2c05_03_device) // Vs. Unisystem (Gumshoe)
DECLARE_DEVICE_TYPE(PPU_2C05_04, ppu2c05_04_device) // Vs. Unisystem (Top Gun)
DECLARE_DEVICE_TYPE(PPU_2C04C, ppu2c04_clone_device) // Vs. Unisystem (Super Mario Bros. bootlegs)
#endif // MAME_VIDEO_PPU2C0X_H

View File

@ -221,16 +221,17 @@ void vsnes_state::vsnes_cpu2_map(address_map &map)
uint8_t vsnes_state::vsnes_bootleg_z80_address_r()
uint8_t vsnes_state::vsnes_bootleg_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
if (!(offset & 1))
{
m_subcpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
}
// can't really see how to get sound this way tho, maybe the unused rom is acting as lookup table to convert
// PSG write offsets to addresses to offsets for use here?
//printf("Z80 read offs %x\n", m_bootleg_sound_offset);
m_subcpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
return m_bootleg_sound_offset;
return 0xf0 | m_bootleg_sound_offset;
}
void vsnes_state::bootleg_sound_write(offs_t offset, uint8_t data)
@ -238,12 +239,15 @@ void vsnes_state::bootleg_sound_write(offs_t offset, uint8_t data)
m_bootleg_sound_offset = offset & 0xf;
m_bootleg_sound_data = data;
m_subcpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
}
uint8_t vsnes_state::vsnes_bootleg_z80_data_r()
{
//printf("Z80 read data %02x\n", m_bootleg_sound_data);
m_bootleg_latched_scanline = m_ppu1->get_current_scanline();
m_subcpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
return m_bootleg_sound_data;
}
@ -271,20 +275,14 @@ void vsnes_state::vsnes_cpu1_bootleg_map(address_map &map)
{
map(0x0000, 0x07ff).mirror(0x1800).ram().share("work_ram");
map(0x2000, 0x3fff).rw(m_ppu1, FUNC(ppu2c0x_device::read), FUNC(ppu2c0x_device::write));
map(0x4000, 0x4017).w(FUNC(vsnes_state::bootleg_sound_write));
map(0x4014, 0x4014).w(FUNC(vsnes_state::sprite_dma_0_w));
map(0x4000, 0x400f).w(FUNC(vsnes_state::bootleg_sound_write));
map(0x4016, 0x4016).rw(FUNC(vsnes_state::vsnes_in0_r), FUNC(vsnes_state::vsnes_in0_w));
map(0x4017, 0x4017).r(FUNC(vsnes_state::vsnes_in1_r)); /* IN1 - input port 2 / PSG second control register */
map(0x4020, 0x4020).rw(FUNC(vsnes_state::vsnes_coin_counter_r), FUNC(vsnes_state::vsnes_coin_counter_w));
map(0x4020, 0x4020).w(FUNC(vsnes_state::vsnes_coin_counter_w));
map(0x6000, 0x7fff).bankrw("extra1");
map(0x8000, 0xffff).rom();
}
uint8_t vsnes_state::vsnes_bootleg_z80_latch_r()
{
return 0x00;
}
// from kevtris' schematics, 2 74LS139s do the Z80 address decoding.
// A13 = 0, A14 = 0 is ROM
// A13 = 1, A14 = 0 is RAM
@ -1846,36 +1844,32 @@ void vsnes_state::vsdual_pi(machine_config &config)
void vsnes_state::vsnes_bootleg(machine_config &config)
{
/* basic machine hardware */
M6502(config, m_maincpu, XTAL(16'000'000)/4); // 4mhz? seems too high but flickers badly otherwise, issue elsewhere?
M6502(config, m_maincpu, XTAL(16'000'000)/8);
m_maincpu->set_addrmap(AS_PROGRAM, &vsnes_state::vsnes_cpu1_bootleg_map);
/* some carts also trigger IRQs */
MCFG_MACHINE_RESET_OVERRIDE(vsnes_state,vsnes)
MCFG_MACHINE_START_OVERRIDE(vsnes_state,vsnes)
MCFG_MACHINE_START_OVERRIDE(vsnes_state,bootleg)
Z80(config, m_subcpu, XTAL(16'000'000)/4); /* ? MHz */ // Z8400APS-Z80CPU
Z80(config, m_subcpu, XTAL(16'000'000)/8); // Z8400APS-Z80CPU
m_subcpu->set_addrmap(AS_PROGRAM, &vsnes_state::vsnes_bootleg_z80_map);
m_subcpu->set_vblank_int("screen1", FUNC(vsnes_state::irq0_line_assert));
/* video hardware */
screen_device &screen1(SCREEN(config, "screen1", SCREEN_TYPE_RASTER));
screen1.set_refresh_hz(60);
screen1.set_size(32*8, 262);
screen1.set_refresh_hz(56.69);
screen1.set_size(32*8, 280);
screen1.set_visarea(0*8, 32*8-1, 0*8, 30*8-1);
screen1.set_screen_update("ppu1", FUNC(ppu2c0x_device::screen_update));
PPU_2C04(config, m_ppu1);
PPU_2C04C(config, m_ppu1);
m_ppu1->set_cpu_tag(m_maincpu);
m_ppu1->set_screen("screen1");
m_ppu1->int_callback().set_inputline(m_maincpu, INPUT_LINE_NMI);
m_ppu1->use_sprite_write_limitation_disable(); // bootleg seems to need this - code to set the sprite address is replaced with complete copy loops??
/* sound hardware */
SPEAKER(config, "mono").front_center();
// PCB has 2, code accesses 3? which 2 really exist?
SN76489(config, "sn1", XTAL(16'000'000)/4).add_route(ALL_OUTPUTS, "mono", 0.50);
SN76489(config, "sn1", XTAL(16'000'000)/8).add_route(ALL_OUTPUTS, "mono", 0.50); // one runs at 2 MHz, other runs at 4 MHz
SN76489(config, "sn2", XTAL(16'000'000)/4).add_route(ALL_OUTPUTS, "mono", 0.50);
SN76489(config, "sn3", XTAL(16'000'000)/4).add_route(ALL_OUTPUTS, "mono", 0.50);
}
/******************************************************************************/
@ -1961,7 +1955,7 @@ ROM_START( suprmriobl )
ROM_REGION( 0x10000, "sub", 0 ) /* Z80 memory */
ROM_LOAD( "1.bin", 0x0000, 0x2000, CRC(9e3557f2) SHA1(11a0de2c0154f7ac120d9774cb5d1051e0156822) )
ROM_REGION( 0x10000, "unk", 0 ) /* first half is some sort of table */
ROM_REGION( 0x10000, "unk", 0 ) /* Table used by clone PPU for sprite flipping, etc. */
ROM_LOAD( "3.bin", 0x0000, 0x8000, CRC(67a467f9) SHA1(61cd1db7cd52faa31153b89f6b98c9b78bf4ca4f) )
ROM_REGION( 0x4000, "gfx1", 0 ) /* PPU memory */
@ -1969,9 +1963,9 @@ ROM_START( suprmriobl )
ROM_LOAD( "5.bin", 0x2000, 0x2000, CRC(15506b86) SHA1(69ecf7a3cc8bf719c1581ec7c0d68798817d416f) )
/* this set has some extra files compared to "suprmriobl2", they probably exist on that pcb too though */
ROM_REGION( 0x200, "proms", 0 )
ROM_LOAD( "prom6301.1", 0x000, 0x100, CRC(a31dc330) SHA1(b652003f7e252bac3bdb19412839c2f03af7f8b8) )
ROM_LOAD( "prom6301.2", 0x100, 0x100, CRC(019c6141) SHA1(fdeda4dea6506807a3324fa941f0684208aa3b4b) )
ROM_REGION( 0x100, "ppu1:palette", 0 )
ROM_LOAD_NIB_HIGH( "prom6301.1", 0x000, 0x100, CRC(a31dc330) SHA1(b652003f7e252bac3bdb19412839c2f03af7f8b8) )
ROM_LOAD_NIB_LOW ( "prom6301.2", 0x000, 0x100, CRC(019c6141) SHA1(fdeda4dea6506807a3324fa941f0684208aa3b4b) )
ROM_REGION( 0x4000, "pals", 0 )
ROM_LOAD( "pal16l8.1", 0x000, 0x104, CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e) )
@ -1982,7 +1976,8 @@ ROM_START( suprmriobl )
ROM_LOAD( "pal16r8.6", 0x000, 0x104, CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e) )
ROM_LOAD( "pal16r8a.7", 0x000, 0x104, CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e) )
PALETTE_2C04_0004("ppu1:palette")
ROM_REGION(0x0100, "epld", 0)
ROM_LOAD("ep1200.bin", 0x000, 0x100, NO_DUMP) // Not dumped
ROM_END
ROM_START( suprmriobl2 )
@ -1992,48 +1987,28 @@ ROM_START( suprmriobl2 )
ROM_REGION( 0x10000, "sub", 0 ) /* Z80 memory */
ROM_LOAD( "1-2764.bin", 0x0000, 0x2000, CRC(95856e07) SHA1(c681cfdb656e687bc59080df56c9c38e13be4bb8) )
ROM_REGION( 0x10000, "unk", 0 ) /* first half is some sort of table */
ROM_REGION( 0x10000, "unk", 0 ) /* Table used by clone PPU for sprite flipping, etc. */
ROM_LOAD( "3-27256.bin", 0x0000, 0x8000, CRC(67a467f9) SHA1(61cd1db7cd52faa31153b89f6b98c9b78bf4ca4f) )
ROM_REGION( 0x4000, "gfx1", 0 ) /* PPU memory */
ROM_LOAD( "2-2764.bin", 0x0000, 0x2000, CRC(42418d40) SHA1(22ab61589742cfa4cc6856f7205d7b4b8310bc4d) )
ROM_LOAD( "5-2764.bin", 0x2000, 0x2000, CRC(15506b86) SHA1(69ecf7a3cc8bf719c1581ec7c0d68798817d416f) )
PALETTE_2C04_0004("ppu1:palette")
ROM_END
ROM_REGION(0x100, "ppu1:palette", 0)
ROM_LOAD_NIB_HIGH( "prom6301.1", 0x000, 0x100, BAD_DUMP CRC(a31dc330) SHA1(b652003f7e252bac3bdb19412839c2f03af7f8b8) ) // Not from this PCB
ROM_LOAD_NIB_LOW ( "prom6301.2", 0x000, 0x100, BAD_DUMP CRC(019c6141) SHA1(fdeda4dea6506807a3324fa941f0684208aa3b4b) ) // Not from this PCB
ROM_START( suprmriobl3 )
ROM_REGION( 0x10000, "maincpu", 0 ) // 6502 memory
ROM_LOAD( "sm_4.bin", 0x8000, 0x8000, CRC(663b1753) SHA1(b0d2057c4545f2d6534cafb16086826c8ba49f5a) )
ROM_REGION(0x4000, "pals", 0)
ROM_LOAD("pal16l8.1", 0x000, 0x104, BAD_DUMP CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e)) // Not from this PCB
ROM_LOAD("pal16r6a.2", 0x000, 0x104, NO_DUMP)
ROM_LOAD("pal16r8.3", 0x000, 0x104, BAD_DUMP CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e)) // Not from this PCB
ROM_LOAD("pal16l8.4", 0x000, 0x104, BAD_DUMP CRC(6f6de82d) SHA1(3d59b222d25457b2f89b559409721db37d6a81d8)) // Not from this PCB
ROM_LOAD("pal16r6.5", 0x000, 0x104, BAD_DUMP CRC(ceff7c7c) SHA1(52fd344c591478469369cd0862d1facfe23e12fb)) // Not from this PCB
ROM_LOAD("pal16r8.6", 0x000, 0x104, BAD_DUMP CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e)) // Not from this PCB
ROM_LOAD("pal16r8a.7", 0x000, 0x104, BAD_DUMP CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e)) // Not from this PCB
ROM_REGION( 0x10000, "sub", 0 ) // Z80 memory
ROM_LOAD( "sm_1.bin", 0x0000, 0x2000, CRC(7f6dda4a) SHA1(0e92a1255ce13ae1215b531f268cd4874e20d611) )
ROM_REGION( 0x10000, "unk", 0 ) // First half is some sort of table
ROM_LOAD( "sm_3.bin", 0x0000, 0x8000, CRC(67a467f9) SHA1(61cd1db7cd52faa31153b89f6b98c9b78bf4ca4f) )
ROM_REGION( 0x4000, "gfx1", 0 ) // PPU memory
ROM_LOAD( "sm_2.bin", 0x0000, 0x2000, CRC(a5f771d1) SHA1(b3f916700035d5556cca009ab83300fb662a868f) )
ROM_LOAD( "sm_5.bin", 0x2000, 0x2000, CRC(a08903ca) SHA1(7ecec519ac973168a84505ddede4f248b554fd85) )
/* this set has some extra files compared to "suprmriobl2", they probably exist on that pcb too though */
ROM_REGION( 0x200, "proms", 0 )
ROM_LOAD( "prom6301.1", 0x000, 0x100, BAD_DUMP CRC(a31dc330) SHA1(b652003f7e252bac3bdb19412839c2f03af7f8b8) ) // Not from this PCB
ROM_LOAD( "prom6301.2", 0x100, 0x100, BAD_DUMP CRC(019c6141) SHA1(fdeda4dea6506807a3324fa941f0684208aa3b4b) ) // Not from this PCB
ROM_REGION( 0x4000, "pals", 0 )
ROM_LOAD( "pal16l8.1", 0x000, 0x104, BAD_DUMP CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e) ) // Not from this PCB
ROM_LOAD( "pal16r6a.2", 0x000, 0x104, NO_DUMP )
ROM_LOAD( "pal16r8.3", 0x000, 0x104, BAD_DUMP CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e) ) // Not from this PCB
ROM_LOAD( "pal16l8.4", 0x000, 0x104, BAD_DUMP CRC(6f6de82d) SHA1(3d59b222d25457b2f89b559409721db37d6a81d8) ) // Not from this PCB
ROM_LOAD( "pal16r6.5", 0x000, 0x104, BAD_DUMP CRC(ceff7c7c) SHA1(52fd344c591478469369cd0862d1facfe23e12fb) ) // Not from this PCB
ROM_LOAD( "pal16r8.6", 0x000, 0x104, BAD_DUMP CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e) ) // Not from this PCB
ROM_LOAD( "pal16r8a.7", 0x000, 0x104, BAD_DUMP CRC(bd76fb53) SHA1(2d0634e8edb3289a103719466465e9777606086e) ) // Not from this PCB
ROM_REGION( 0x0100, "epld", 0 )
ROM_LOAD( "ep1200.bin", 0x000, 0x100, NO_DUMP ) // Not dumped
PALETTE_2C04_0004("ppu1:palette") // Not from this PCB
ROM_REGION(0x0100, "epld", 0)
ROM_LOAD("ep1200.bin", 0x000, 0x100, NO_DUMP) // Not dumped
ROM_END
ROM_START( skatekds )
@ -2880,9 +2855,8 @@ GAME( 1986, rbibb, 0, vsnes, rbibb, vsnes_state, init_rbib
GAME( 1986, rbibba, rbibb, vsnes, rbibb, vsnes_state, init_rbibb, ROT0, "Namco", "Vs. Atari R.B.I. Baseball (set 2)", 0 )
GAME( 1986, suprmrio, 0, vsnes, suprmrio, vsnes_state, init_vsnormal, ROT0, "Nintendo", "Vs. Super Mario Bros. (set SM4-4 E)", 0 )
GAME( 1986, suprmrioa,suprmrio, vsnes, suprmrio, vsnes_state, init_vsnormal, ROT0, "Nintendo", "Vs. Super Mario Bros. (set ?, harder)", 0 )
GAME( 1986, suprmriobl,suprmrio, vsnes_bootleg, suprmrio, vsnes_state, init_vsnormal, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 1)", MACHINE_NOT_WORKING ) // timer starts at 200(!)
GAME( 1986, suprmriobl2,suprmrio,vsnes_bootleg, suprmrio, vsnes_state, init_vsnormal, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 2)", MACHINE_NOT_WORKING ) // timer starts at 300
GAME( 1986, suprmriobl3,suprmrio,vsnes_bootleg, suprmrio, vsnes_state, init_vsnormal, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 3)", MACHINE_NOT_WORKING ) // timer starts at 300
GAME( 1986, suprmriobl,suprmrio, vsnes_bootleg, suprmrio, vsnes_state, init_bootleg, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 1)", 0) // timer starts at 200(!)
GAME( 1986, suprmriobl2,suprmrio,vsnes_bootleg, suprmrio, vsnes_state, init_bootleg, ROT0, "bootleg", "Vs. Super Mario Bros. (bootleg with Z80, set 2)", 0) // timer starts at 300
GAME( 1988, skatekds, suprmrio, vsnes, suprmrio, vsnes_state, init_vsnormal, ROT0, "hack (Two-Bit Score)", "Vs. Skate Kids. (Graphic hack of Super Mario Bros.)", 0 )
GAME( 1985, vsskykid, 0, vsnes, vsskykid, vsnes_state, init_MMC3, ROT0, "Namco", "Vs. Super SkyKid", 0 )
GAME( 1987, tkoboxng, 0, vsnes, tkoboxng, vsnes_state, init_tkoboxng, ROT0, "Namco / Data East USA", "Vs. T.K.O. Boxing", 0 )

View File

@ -44,6 +44,7 @@ public:
void init_platoon();
void init_rbibb();
void init_vsdual();
void init_bootleg();
private:
required_device<cpu_device> m_maincpu;
@ -99,15 +100,17 @@ private:
DECLARE_MACHINE_RESET(vsnes);
DECLARE_MACHINE_START(vsdual);
DECLARE_MACHINE_RESET(vsdual);
DECLARE_MACHINE_START(bootleg);
void v_set_videorom_bank( int start, int count, int vrom_start_bank );
void mapper4_set_prg( );
void mapper4_set_chr( );
void mapper4_irq( int scanline, int vblank, int blanked );
uint8_t vsnes_bootleg_z80_latch_r();
void bootleg_sound_write(offs_t offset, uint8_t data);
uint8_t vsnes_bootleg_z80_data_r();
uint8_t vsnes_bootleg_z80_address_r();
uint8_t vsnes_bootleg_z80_address_r(offs_t offset);
void vsnes_bootleg_scanline(int scanline, int vblank, int blanked);
uint8_t vsnes_bootleg_ppudata();
void vsnes_bootleg_z80_map(address_map &map);
void vsnes_cpu1_bootleg_map(address_map &map);
@ -122,6 +125,7 @@ private:
std::unique_ptr<uint8_t[]> m_vram;
uint8_t* m_vrom[2];
std::unique_ptr<uint8_t[]> m_nt_ram[2];
memory_bank* m_bank_vrom[8];
uint8_t* m_nt_page[2][4];
uint32_t m_vrom_size[2];
int m_vrom_banks;
@ -146,4 +150,5 @@ private:
uint8_t m_bootleg_sound_offset;
uint8_t m_bootleg_sound_data;
int m_bootleg_latched_scanline;
};

View File

@ -179,7 +179,7 @@ void vsnes_state::v_set_videorom_bank( int start, int count, int vrom_start_ban
/* count determines the size of the area mapped */
for (i = 0; i < count; i++)
{
membank(chr_banknames[i + start])->set_entry(vrom_start_bank + i);
m_bank_vrom[i + start]->set_entry(vrom_start_bank + i);
}
}
@ -219,7 +219,8 @@ MACHINE_START_MEMBER(vsnes_state,vsnes)
for (i = 0; i < 8; i++)
{
ppu1_space.install_read_bank(0x0400 * i, 0x0400 * i + 0x03ff, chr_banknames[i]);
membank(chr_banknames[i])->configure_entries(0, m_vrom_banks, m_vrom[0], 0x400);
m_bank_vrom[i] = membank(chr_banknames[i]);
m_bank_vrom[i]->configure_entries(0, m_vrom_banks, m_vrom[0], 0x400);
}
v_set_videorom_bank(0, 8, 0);
}
@ -255,10 +256,34 @@ MACHINE_START_MEMBER(vsnes_state,vsdual)
m_ppu1->space(AS_PROGRAM).install_read_bank(0x0000, 0x1fff, "bank2");
// read only!
m_ppu2->space(AS_PROGRAM).install_read_bank(0x0000, 0x1fff, "bank3");
membank("bank2")->configure_entries(0, m_vrom_size[0] / 0x2000, m_vrom[0], 0x2000);
membank("bank3")->configure_entries(0, m_vrom_size[1] / 0x2000, m_vrom[1], 0x2000);
membank("bank2")->set_entry(0);
membank("bank3")->set_entry(0);
m_bank_vrom[0] = membank("bank2");
m_bank_vrom[1] = membank("bank3");
m_bank_vrom[0]->configure_entries(0, m_vrom_size[0] / 0x2000, m_vrom[0], 0x2000);
m_bank_vrom[1]->configure_entries(0, m_vrom_size[1] / 0x2000, m_vrom[1], 0x2000);
m_bank_vrom[0]->set_entry(0);
m_bank_vrom[1]->set_entry(0);
}
MACHINE_START_MEMBER(vsnes_state, bootleg)
{
address_space &ppu1_space = m_ppu1->space(AS_PROGRAM);
/* establish nametable ram */
m_nt_ram[0] = std::make_unique<uint8_t[]>(0x1000);
/* set mirroring */
v_set_mirroring(0, PPU_MIRROR_VERT);
ppu1_space.install_readwrite_handler(0x2000, 0x3eff, read8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt0_r)), write8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt0_w)));
m_vrom[0] = m_gfx1_rom->base();
m_vrom_size[0] = m_gfx1_rom->bytes();
m_vrom_banks = m_vrom_size[0] / 0x2000;
/* establish chr banks */
m_ppu1->space(AS_PROGRAM).install_read_bank(0x0000, 0x1fff, "bank2");
m_bank_vrom[0] = membank("bank2");
m_bank_vrom[0]->configure_entries(0, m_vrom_banks, m_vrom[0], 0x2000);
m_bank_vrom[0]->set_entry(0);
}
/*************************************
@ -1017,7 +1042,7 @@ void vsnes_state::init_bnglngby()
void vsnes_state::vsdual_vrom_banking_main(uint8_t data)
{
/* switch vrom */
membank("bank2")->set_entry(BIT(data, 2));
m_bank_vrom[0]->set_entry(BIT(data, 2));
/* bit 1 ( data & 2 ) triggers irq on the other cpu */
m_subcpu->set_input_line(0, (data & 2) ? CLEAR_LINE : ASSERT_LINE);
@ -1029,7 +1054,7 @@ void vsnes_state::vsdual_vrom_banking_main(uint8_t data)
void vsnes_state::vsdual_vrom_banking_sub(uint8_t data)
{
/* switch vrom */
membank("bank3")->set_entry(BIT(data, 2));
m_bank_vrom[1]->set_entry(BIT(data, 2));
/* bit 1 ( data & 2 ) triggers irq on the other cpu */
m_maincpu->set_input_line(0, (data & 2) ? CLEAR_LINE : ASSERT_LINE);
@ -1050,3 +1075,38 @@ void vsnes_state::init_vsdual()
m_maincpu->space(AS_PROGRAM).install_ram(0x6000, 0x7fff, &prg[0x6000]);
m_subcpu->space(AS_PROGRAM).install_ram(0x6000, 0x7fff, &prg[0x6000]);
}
/**********************************************************************************/
/* Vs. Super Mario Bros (Bootleg) */
void vsnes_state::vsnes_bootleg_scanline(int scanline, int vblank, int 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))
{
m_subcpu->set_input_line(INPUT_LINE_IRQ0, ((scanline + 1) & 0x40) ? ASSERT_LINE : CLEAR_LINE);
}
}
uint8_t vsnes_state::vsnes_bootleg_ppudata()
{
// CPU always reads higher CHR ROM banks from $2007, PPU always reads lower ones
m_bank_vrom[0]->set_entry(1);
uint8_t data = m_ppu1->read(0x2007);
m_bank_vrom[0]->set_entry(0);
return data;
}
void vsnes_state::init_bootleg()
{
m_bootleg_sound_offset = 0;
m_bootleg_sound_data = 0;
m_bootleg_latched_scanline = 0;
m_ppu1->set_scanline_callback(*this, FUNC(vsnes_state::vsnes_bootleg_scanline));
m_maincpu->space(AS_PROGRAM).install_read_handler(0x2007, 0x2007, read8smo_delegate(*this, FUNC(vsnes_state::vsnes_bootleg_ppudata)));
}

View File

@ -41455,7 +41455,6 @@ suprmrio // (c) 1986 Nintendo
suprmrioa // (c) 1986 Nintendo
suprmriobl // bootleg
suprmriobl2 // bootleg
suprmriobl3 // bootleg
supxevs // (c) 1986 Nintendo
tkoboxng // (c) 1987 Data East
topgun // (c) 1987 Konami