mirror of
https://github.com/holub/mame
synced 2025-04-20 23:42:22 +03:00
(MESS) gb.c: many updates to cart handling [Fabio Priuli]
- updated carts to be slot devices - simplified loading and bankswitch mechanism - fixed MMM01 emulation - removed need for "mapper" feature from xml softlist, since the new "slot" feature is enough
This commit is contained in:
parent
095eaa68e8
commit
312abbed4e
6
.gitattributes
vendored
6
.gitattributes
vendored
@ -7124,6 +7124,12 @@ src/mess/machine/galaxy.c svneol=native#text/plain
|
||||
src/mess/machine/gamecom.c svneol=native#text/plain
|
||||
src/mess/machine/gamepock.c svneol=native#text/plain
|
||||
src/mess/machine/gb.c svneol=native#text/plain
|
||||
src/mess/machine/gb_mbc.c svneol=native#text/plain
|
||||
src/mess/machine/gb_mbc.h svneol=native#text/plain
|
||||
src/mess/machine/gb_rom.c svneol=native#text/plain
|
||||
src/mess/machine/gb_rom.h svneol=native#text/plain
|
||||
src/mess/machine/gb_slot.c svneol=native#text/plain
|
||||
src/mess/machine/gb_slot.h svneol=native#text/plain
|
||||
src/mess/machine/genpc.c svneol=native#text/plain
|
||||
src/mess/machine/hd63450.c svneol=native#text/plain
|
||||
src/mess/machine/hd63450.h svneol=native#text/plain
|
||||
|
1515
hash/gameboy.xml
1515
hash/gameboy.xml
File diff suppressed because it is too large
Load Diff
1501
hash/gbcolor.xml
1501
hash/gbcolor.xml
File diff suppressed because it is too large
Load Diff
@ -447,6 +447,9 @@ space. This mapper uses 32KB sized banks.
|
||||
#include "rendlay.h"
|
||||
#include "audio/gb.h"
|
||||
#include "includes/gb.h"
|
||||
#include "machine/gb_slot.h"
|
||||
#include "machine/gb_rom.h"
|
||||
#include "machine/gb_mbc.h"
|
||||
|
||||
|
||||
/* Initial value of the cpu registers (hacks until we get bios dumps) */
|
||||
@ -474,16 +477,113 @@ static ADDRESS_MAP_START(gb_map, AS_PROGRAM, 8, gb_state )
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w ) /* Interrupt enable register */
|
||||
ADDRESS_MAP_END
|
||||
|
||||
READ8_MEMBER(gb_state::gb_cart_r)
|
||||
{
|
||||
if (m_bios_disable && m_cartslot->m_cart)
|
||||
return m_cartslot->m_cart->read_rom(space, offset);
|
||||
else
|
||||
{
|
||||
if (offset < 0x100)
|
||||
{
|
||||
UINT8 *ROM = space.machine().root_device().memregion("maincpu")->base();
|
||||
return ROM[offset];
|
||||
}
|
||||
else if (m_cartslot->m_cart)
|
||||
{
|
||||
return m_cartslot->m_cart->read_rom(space, offset);
|
||||
}
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_state::gbc_cart_r)
|
||||
{
|
||||
if (m_bios_disable && m_cartslot->m_cart)
|
||||
return m_cartslot->m_cart->read_rom(space, offset);
|
||||
else
|
||||
{
|
||||
if (offset < 0x100)
|
||||
{
|
||||
UINT8 *ROM = space.machine().root_device().memregion("maincpu")->base();
|
||||
return ROM[offset];
|
||||
}
|
||||
else if (offset >= 0x200 && offset < 0x900)
|
||||
{
|
||||
UINT8 *ROM = space.machine().root_device().memregion("maincpu")->base();
|
||||
return ROM[offset - 0x100];
|
||||
}
|
||||
else if (m_cartslot->m_cart)
|
||||
{
|
||||
return m_cartslot->m_cart->read_rom(space, offset);
|
||||
}
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_state::gb_bank_w)
|
||||
{
|
||||
if (m_cartslot->m_cart)
|
||||
m_cartslot->m_cart->write_bank(space, offset, data);
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_state::gb_ram_r)
|
||||
{
|
||||
if (m_cartslot->m_cart)
|
||||
return m_cartslot->m_cart->read_ram(space, offset);
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_state::gb_ram_w)
|
||||
{
|
||||
if (m_cartslot->m_cart)
|
||||
m_cartslot->m_cart->write_ram(space, offset, data);
|
||||
}
|
||||
|
||||
READ8_MEMBER(megaduck_state::cart_r)
|
||||
{
|
||||
if (m_cartslot && m_cartslot->m_cart)
|
||||
return m_cartslot->m_cart->read_rom(space, offset);
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(megaduck_state::bank1_w)
|
||||
{
|
||||
if (m_cartslot->m_cart)
|
||||
m_cartslot->m_cart->write_bank(space, offset, data);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(megaduck_state::bank2_w)
|
||||
{
|
||||
if (m_cartslot->m_cart)
|
||||
m_cartslot->m_cart->write_ram(space, offset, data); /* used for bankswitch, but we re-use GB name */
|
||||
}
|
||||
|
||||
|
||||
static ADDRESS_MAP_START(gameboy_map, AS_PROGRAM, 8, gb_state )
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gb_cart_r, gb_bank_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_READWRITE(gb_vram_r, gb_vram_w ) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w ) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xfdff) AM_RAM /* 8k low RAM, echo RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_READWRITE(gb_oam_r, gb_oam_w ) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w ) /* I/O */
|
||||
AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE_LEGACY("custom", gb_sound_r, gb_sound_w ) /* sound registers */
|
||||
AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */
|
||||
AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE_LEGACY("custom", gb_wave_r, gb_wave_w ) /* Wave ram */
|
||||
AM_RANGE(0xff40, 0xff7f) AM_READWRITE(gb_video_r, gb_io2_w) /* Video controller & BIOS flip-flop */
|
||||
AM_RANGE(0xff80, 0xfffe) AM_RAM /* High RAM */
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w ) /* Interrupt enable register */
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(sgb_map, AS_PROGRAM, 8, gb_state )
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x00ff) AM_ROMBANK("bank5") /* BIOS or ROM */
|
||||
AM_RANGE(0x0100, 0x01ff) AM_ROMBANK("bank10") /* ROM bank */
|
||||
AM_RANGE(0x0200, 0x08ff) AM_ROMBANK("bank6")
|
||||
AM_RANGE(0x0900, 0x3fff) AM_ROMBANK("bank11")
|
||||
AM_RANGE(0x4000, 0x5fff) AM_ROMBANK("bank1") /* 8KB/16KB switched ROM bank */
|
||||
AM_RANGE(0x6000, 0x7fff) AM_ROMBANK("bank4") /* 8KB/16KB switched ROM bank */
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gb_cart_r, gb_bank_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_READWRITE(gb_vram_r, gb_vram_w ) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("bank2") /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w ) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xfdff) AM_RAM /* 8k low RAM, echo RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_READWRITE(gb_oam_r, gb_oam_w ) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, sgb_io_w ) /* I/O */
|
||||
@ -497,16 +597,11 @@ ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(gbc_map, AS_PROGRAM, 8, gb_state )
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x00ff) AM_ROMBANK("bank5") /* 16k fixed ROM bank */
|
||||
AM_RANGE(0x0100, 0x01ff) AM_ROMBANK("bank10") /* ROM bank */
|
||||
AM_RANGE(0x0200, 0x08ff) AM_ROMBANK("bank6")
|
||||
AM_RANGE(0x0900, 0x3fff) AM_ROMBANK("bank11")
|
||||
AM_RANGE(0x4000, 0x5fff) AM_ROMBANK("bank1") /* 8KB/16KB switched ROM bank */
|
||||
AM_RANGE(0x6000, 0x7fff) AM_ROMBANK("bank4") /* 8KB/16KB switched ROM bank */
|
||||
AM_RANGE(0x8000, 0x9fff) AM_READWRITE(gb_vram_r, gb_vram_w ) /* 8k switched VRAM bank */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("bank2") /* 8k switched RAM bank (on cartridge) */
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gbc_cart_r, gb_bank_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_READWRITE(gb_vram_r, gb_vram_w ) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w ) /* 8k switched RAM bank (cartridge) */
|
||||
AM_RANGE(0xc000, 0xcfff) AM_RAM /* 4k fixed RAM bank */
|
||||
AM_RANGE(0xd000, 0xdfff) AM_RAMBANK("bank3") /* 4k switched RAM bank */
|
||||
AM_RANGE(0xd000, 0xdfff) AM_RAMBANK("cgb_ram") /* 4k switched RAM bank */
|
||||
AM_RANGE(0xe000, 0xfdff) AM_RAM /* echo RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_READWRITE(gb_oam_r, gb_oam_w ) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w ) /* I/O */
|
||||
@ -518,12 +613,13 @@ static ADDRESS_MAP_START(gbc_map, AS_PROGRAM, 8, gb_state )
|
||||
AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w ) /* Interrupt enable register */
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(megaduck_map, AS_PROGRAM, 8, gb_state )
|
||||
static ADDRESS_MAP_START(megaduck_map, AS_PROGRAM, 8, megaduck_state )
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
AM_RANGE(0x0000, 0x3fff) AM_ROMBANK("bank10") /* 16k switched ROM bank */
|
||||
AM_RANGE(0x4000, 0x7fff) AM_ROMBANK("bank1") /* 16k switched ROM bank */
|
||||
AM_RANGE(0x0000, 0x7fff) AM_READWRITE(cart_r, bank1_w)
|
||||
AM_RANGE(0x8000, 0x9fff) AM_READWRITE(gb_vram_r, gb_vram_w ) /* 8k VRAM */
|
||||
AM_RANGE(0xa000, 0xbfff) AM_NOP /* unused? */
|
||||
AM_RANGE(0xa000, 0xafff) AM_NOP /* unused? */
|
||||
AM_RANGE(0xb000, 0xb000) AM_WRITE(bank2_w)
|
||||
AM_RANGE(0xb001, 0xbfff) AM_NOP /* unused? */
|
||||
AM_RANGE(0xc000, 0xfe9f) AM_RAM /* 8k low RAM, echo RAM */
|
||||
AM_RANGE(0xfe00, 0xfeff) AM_READWRITE(gb_oam_r, gb_oam_w ) /* OAM RAM */
|
||||
AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w ) /* I/O */
|
||||
@ -584,13 +680,36 @@ static MACHINE_CONFIG_START( gb_common, gb_state )
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_DERIVED( gameboy, gb_common )
|
||||
static SLOT_INTERFACE_START(gb_cart)
|
||||
SLOT_INTERFACE_INTERNAL("rom", GB_STD_ROM)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mbc1", GB_ROM_MBC1)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mbc1k", GB_ROM_MBC1K)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mbc2", GB_ROM_MBC2)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mbc3", GB_ROM_MBC3)
|
||||
SLOT_INTERFACE_INTERNAL("rom_huc1", GB_ROM_MBC3)
|
||||
SLOT_INTERFACE_INTERNAL("rom_huc3", GB_ROM_MBC3)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mbc5", GB_ROM_MBC5)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mbc6", GB_ROM_MBC6)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mbc7", GB_ROM_MBC7)
|
||||
SLOT_INTERFACE_INTERNAL("rom_tama5", GB_ROM_TAMA5)
|
||||
SLOT_INTERFACE_INTERNAL("rom_mmm01", GB_ROM_MMM01)
|
||||
SLOT_INTERFACE_INTERNAL("rom_wisdom", GB_ROM_WISDOM)
|
||||
SLOT_INTERFACE_INTERNAL("rom_yong", GB_ROM_YONG)
|
||||
SLOT_INTERFACE_INTERNAL("rom_lasama", GB_ROM_LASAMA)
|
||||
SLOT_INTERFACE_INTERNAL("rom_atvrac", GB_ROM_ATVRAC)
|
||||
SLOT_INTERFACE_INTERNAL("rom_camera", GB_STD_ROM)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
static SLOT_INTERFACE_START(megaduck_cart)
|
||||
SLOT_INTERFACE_INTERNAL("rom", MEGADUCK_ROM)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
static MACHINE_CONFIG_DERIVED( gameboy, gb_common )
|
||||
MCFG_CPU_REPLACE("maincpu", LR35902, 4194304) /* 4.194304 MHz */
|
||||
MCFG_CPU_PROGRAM_MAP(gameboy_map)
|
||||
|
||||
MCFG_GB_CARTRIDGE_ADD("gbslot", gb_cart, NULL, NULL)
|
||||
|
||||
MCFG_CARTSLOT_ADD("cart")
|
||||
MCFG_CARTSLOT_EXTENSION_LIST("gb,gmb,cgb,gbc,sgb,bin")
|
||||
MCFG_CARTSLOT_NOT_MANDATORY
|
||||
MCFG_CARTSLOT_INTERFACE("gameboy_cart")
|
||||
MCFG_CARTSLOT_LOAD(gb_state,gb_cart)
|
||||
MCFG_SOFTWARE_LIST_ADD("cart_list","gameboy")
|
||||
MCFG_SOFTWARE_LIST_COMPATIBLE_ADD("gbc_list","gbcolor")
|
||||
MACHINE_CONFIG_END
|
||||
@ -621,14 +740,11 @@ static MACHINE_CONFIG_DERIVED( gbpocket, gameboy )
|
||||
MCFG_LR35902_HALT_BUG
|
||||
MCFG_LR35902_RESET_VALUES(mgb_cpu_regs)
|
||||
|
||||
MCFG_MACHINE_RESET_OVERRIDE(gb_state, gbpocket )
|
||||
MCFG_MACHINE_RESET_OVERRIDE(gb_state, gbpocket)
|
||||
MCFG_PALETTE_INIT_OVERRIDE(gb_state,gbp)
|
||||
|
||||
MCFG_CARTSLOT_MODIFY("cart")
|
||||
MCFG_CARTSLOT_MANDATORY
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_DERIVED( gbcolor, gb_common )
|
||||
static MACHINE_CONFIG_DERIVED( gbcolor, gameboy )
|
||||
MCFG_CPU_MODIFY("maincpu")
|
||||
MCFG_CPU_PROGRAM_MAP( gbc_map)
|
||||
MCFG_LR35902_TIMER_CB( WRITE8( gb_state, gb_timer_callback ) )
|
||||
@ -643,16 +759,13 @@ static MACHINE_CONFIG_DERIVED( gbcolor, gb_common )
|
||||
MCFG_RAM_ADD(RAM_TAG)
|
||||
MCFG_RAM_DEFAULT_SIZE("48K") /* 2 pages of 8KB VRAM, 8 pages of 4KB RAM */
|
||||
|
||||
MCFG_CARTSLOT_ADD("cart")
|
||||
MCFG_CARTSLOT_EXTENSION_LIST("gb,gmb,cgb,gbc,sgb,bin")
|
||||
MCFG_CARTSLOT_NOT_MANDATORY
|
||||
MCFG_CARTSLOT_INTERFACE("gameboy_cart")
|
||||
MCFG_CARTSLOT_LOAD(gb_state,gb_cart)
|
||||
MCFG_DEVICE_REMOVE("cart_list")
|
||||
MCFG_DEVICE_REMOVE("gbc_list")
|
||||
MCFG_SOFTWARE_LIST_ADD("cart_list","gbcolor")
|
||||
MCFG_SOFTWARE_LIST_COMPATIBLE_ADD("gb_list","gameboy")
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_START( megaduck, gb_state )
|
||||
static MACHINE_CONFIG_START( megaduck, megaduck_state )
|
||||
/* basic machine hardware */
|
||||
MCFG_CPU_ADD("maincpu", LR35902, 4194304) /* 4.194304 MHz */
|
||||
MCFG_CPU_PROGRAM_MAP( megaduck_map)
|
||||
@ -666,8 +779,8 @@ static MACHINE_CONFIG_START( megaduck, gb_state )
|
||||
MCFG_SCREEN_VBLANK_TIME(0)
|
||||
MCFG_QUANTUM_TIME(attotime::from_hz(60))
|
||||
|
||||
MCFG_MACHINE_START_OVERRIDE(gb_state, megaduck )
|
||||
MCFG_MACHINE_RESET_OVERRIDE(gb_state, megaduck )
|
||||
MCFG_MACHINE_START_OVERRIDE(megaduck_state, megaduck )
|
||||
MCFG_MACHINE_RESET_OVERRIDE(megaduck_state, megaduck )
|
||||
|
||||
MCFG_SCREEN_UPDATE_DRIVER(gb_state, screen_update)
|
||||
MCFG_SCREEN_SIZE(20*8, 18*8)
|
||||
@ -676,19 +789,14 @@ static MACHINE_CONFIG_START( megaduck, gb_state )
|
||||
MCFG_DEFAULT_LAYOUT(layout_lcd)
|
||||
MCFG_GFXDECODE(gb)
|
||||
MCFG_PALETTE_LENGTH(4)
|
||||
MCFG_PALETTE_INIT_OVERRIDE(gb_state,megaduck)
|
||||
MCFG_PALETTE_INIT_OVERRIDE(megaduck_state,megaduck)
|
||||
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
MCFG_SOUND_ADD("custom", GAMEBOY, 0)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 0.50)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
|
||||
|
||||
MCFG_CARTSLOT_ADD("cart")
|
||||
MCFG_CARTSLOT_EXTENSION_LIST("bin")
|
||||
MCFG_CARTSLOT_MANDATORY
|
||||
MCFG_CARTSLOT_INTERFACE("megaduck_cart")
|
||||
MCFG_CARTSLOT_LOAD(gb_state,megaduck_cart)
|
||||
MCFG_SOFTWARE_LIST_ADD("cart_list","megaduck")
|
||||
MCFG_MEGADUCK_CARTRIDGE_ADD("duckslot", megaduck_cart, NULL, NULL)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/***************************************************************************
|
||||
@ -729,13 +837,13 @@ ROM_START( megaduck )
|
||||
ROM_END
|
||||
|
||||
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
|
||||
CONS( 1990, gameboy, 0, 0, gameboy, gameboy, gb_state, gb, "Nintendo", "Game Boy", 0)
|
||||
CONS( 1994, supergb, gameboy, 0, supergb, gameboy, gb_state, gb, "Nintendo", "Super Game Boy", 0)
|
||||
CONS( 1996, gbpocket, gameboy, 0, gbpocket, gameboy, gb_state, gb, "Nintendo", "Game Boy Pocket", 0)
|
||||
CONS( 1997, gblight, gameboy, 0, gbpocket, gameboy, gb_state, gb, "Nintendo", "Game Boy Light", 0)
|
||||
CONS( 1998, gbcolor, gameboy, 0, gbcolor, gameboy, gb_state, gb, "Nintendo", "Game Boy Color", GAME_IMPERFECT_GRAPHICS)
|
||||
CONS( 1990, gameboy, 0, 0, gameboy, gameboy, driver_device, 0, "Nintendo", "Game Boy", 0)
|
||||
CONS( 1994, supergb, gameboy, 0, supergb, gameboy, driver_device, 0, "Nintendo", "Super Game Boy", 0)
|
||||
CONS( 1996, gbpocket, gameboy, 0, gbpocket, gameboy, driver_device, 0, "Nintendo", "Game Boy Pocket", 0)
|
||||
CONS( 1997, gblight, gameboy, 0, gbpocket, gameboy, driver_device, 0, "Nintendo", "Game Boy Light", 0)
|
||||
CONS( 1998, gbcolor, gameboy, 0, gbcolor, gameboy, driver_device, 0, "Nintendo", "Game Boy Color", GAME_IMPERFECT_GRAPHICS)
|
||||
|
||||
/* Sound is not 100% yet, it generates some sounds which could be ok. Since we're lacking a real
|
||||
system there's no way to verify. Same goes for the colors of the LCD. We are no using the default
|
||||
Game Boy green colors */
|
||||
CONS( 1993, megaduck, 0, 0, megaduck, gameboy, gb_state, gb, "Creatronic/Videojet/Timlex/Cougar", "MegaDuck/Cougar Boy" , 0)
|
||||
CONS( 1993, megaduck, 0, 0, megaduck, gameboy, driver_device, 0, "Creatronic/Videojet/Timlex/Cougar", "MegaDuck/Cougar Boy" , 0)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef GB_H_
|
||||
#define GB_H_
|
||||
|
||||
#include "machine/gb_slot.h"
|
||||
|
||||
|
||||
/* Interrupts */
|
||||
@ -110,15 +111,9 @@ class gb_state : public driver_device
|
||||
public:
|
||||
gb_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_cartslot(*this, "gbslot")
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_bank1(*this, "bank1")
|
||||
, m_bank2(*this, "bank2")
|
||||
, m_bank3(*this, "bank3")
|
||||
, m_bank4(*this, "bank4")
|
||||
, m_bank5(*this, "bank5")
|
||||
, m_bank6(*this, "bank6")
|
||||
, m_bank10(*this, "bank10")
|
||||
, m_bank11(*this, "bank11")
|
||||
, m_rambank(*this, "cgb_ram")
|
||||
, m_inputs(*this, "INPUTS")
|
||||
{ }
|
||||
|
||||
@ -157,70 +152,16 @@ public:
|
||||
UINT8 m_sgb_data[0x100];
|
||||
UINT32 m_sgb_atf;
|
||||
|
||||
/* Cartridge/mapper */
|
||||
UINT16 m_MBCType; /* MBC type: 0 for none */
|
||||
UINT8 m_CartType; /* Cartridge type (battery, ram, rtc, etc) */
|
||||
UINT8 *m_ROMMap[MAX_ROMBANK]; /* Addresses of ROM banks */
|
||||
UINT16 m_ROMBank; /* Index of ROM bank currently used at 4000-7fff */
|
||||
UINT16 m_ROMBank00; /* Index of ROM bank currently used at 0000-3fff */
|
||||
UINT8 m_ROMMask; /* Mask for the ROM bank number */
|
||||
UINT16 m_ROMBanks; /* Total number of ROM banks */
|
||||
UINT8 *m_RAMMap[MAX_RAMBANK]; /* Addresses of RAM banks */
|
||||
UINT8 m_RAMBank; /* Number of RAM bank currently used */
|
||||
UINT8 m_RAMMask; /* Mask for the RAM bank number */
|
||||
UINT8 m_RAMBanks; /* Total number of RAM banks */
|
||||
UINT8 m_MBC1Mode; /* MBC1 ROM/RAM mode */
|
||||
UINT8 *m_MBC3RTCData; /* MBC3 RTC data */
|
||||
UINT8 m_MBC3RTCMap[5]; /* MBC3 RTC banks */
|
||||
UINT8 m_MBC3RTCBank; /* MBC3 RTC bank */
|
||||
/* CGB variables */
|
||||
UINT8 *m_GBC_RAMMap[8]; /* (CGB) Addresses of internal RAM banks */
|
||||
UINT8 m_GBC_RAMBank; /* (CGB) Current CGB RAM bank */
|
||||
UINT8 m_gbTama5Memory[32];
|
||||
UINT8 m_gbTama5Byte;
|
||||
UINT8 m_gbTama5Address;
|
||||
UINT8 m_gbLastTama5Command;
|
||||
UINT8 *m_gb_cart;
|
||||
UINT8 *m_gb_cart_ram;
|
||||
UINT8 *m_gb_dummy_rom_bank;
|
||||
UINT8 *m_gb_dummy_ram_bank;
|
||||
|
||||
UINT8 m_mmm01_bank_offset;
|
||||
UINT8 m_mmm01_reg1;
|
||||
UINT8 m_mmm01_bank;
|
||||
UINT8 m_mmm01_bank_mask;
|
||||
|
||||
gb_lcd_t m_lcd;
|
||||
void (gb_state::*update_scanline) ();
|
||||
bool m_bios_disable;
|
||||
|
||||
bitmap_ind16 m_bitmap;
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_mbc1);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_mbc2);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_mbc3);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_mbc5);
|
||||
DECLARE_WRITE8_MEMBER(gb_ram_bank_select_mbc6);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_mbc6_1);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_mbc6_2);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_mbc7);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_unknown_mbc7);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_wisdom);
|
||||
DECLARE_WRITE8_MEMBER(gb_ram_bank_select_mbc1);
|
||||
DECLARE_WRITE8_MEMBER(gb_ram_bank_select_mbc3);
|
||||
DECLARE_WRITE8_MEMBER(gb_ram_bank_select_mbc5);
|
||||
DECLARE_WRITE8_MEMBER(gb_ram_enable);
|
||||
DECLARE_WRITE8_MEMBER(gb_mem_mode_select_mbc1);
|
||||
DECLARE_WRITE8_MEMBER(gb_mem_mode_select_mbc3);
|
||||
DECLARE_WRITE8_MEMBER(gb_ram_tama5);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_mmm01_0000_w);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_mmm01_2000_w);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_mmm01_4000_w);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_mmm01_6000_w);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_select_mbc1_kor);
|
||||
DECLARE_WRITE8_MEMBER(gb_ram_bank_select_mbc1_kor);
|
||||
DECLARE_WRITE8_MEMBER(gb_mem_mode_select_mbc1_kor);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_yongyong_2000);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_lasama_6000);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_lasama_2080);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_atvracin_3f00);
|
||||
DECLARE_WRITE8_MEMBER(gb_rom_bank_atvracin_3fc0);
|
||||
DECLARE_WRITE8_MEMBER(gb_io_w);
|
||||
DECLARE_WRITE8_MEMBER(gb_io2_w);
|
||||
DECLARE_WRITE8_MEMBER(sgb_io_w);
|
||||
@ -229,14 +170,6 @@ public:
|
||||
DECLARE_READ8_MEMBER(gb_io_r);
|
||||
DECLARE_WRITE8_MEMBER(gbc_io2_w);
|
||||
DECLARE_READ8_MEMBER(gbc_io2_r);
|
||||
DECLARE_READ8_MEMBER(megaduck_video_r);
|
||||
DECLARE_WRITE8_MEMBER(megaduck_video_w);
|
||||
DECLARE_WRITE8_MEMBER(megaduck_sound_w1);
|
||||
DECLARE_READ8_MEMBER(megaduck_sound_r1);
|
||||
DECLARE_WRITE8_MEMBER(megaduck_sound_w2);
|
||||
DECLARE_READ8_MEMBER(megaduck_sound_r2);
|
||||
DECLARE_WRITE8_MEMBER(megaduck_rom_bank_select_type1);
|
||||
DECLARE_WRITE8_MEMBER(megaduck_rom_bank_select_type2);
|
||||
DECLARE_READ8_MEMBER(gb_video_r);
|
||||
DECLARE_READ8_MEMBER(gb_vram_r);
|
||||
DECLARE_WRITE8_MEMBER(gb_vram_w);
|
||||
@ -248,9 +181,6 @@ public:
|
||||
DECLARE_MACHINE_START(gb);
|
||||
DECLARE_MACHINE_RESET(gb);
|
||||
DECLARE_PALETTE_INIT(gb);
|
||||
DECLARE_MACHINE_START(megaduck);
|
||||
DECLARE_MACHINE_RESET(megaduck);
|
||||
DECLARE_PALETTE_INIT(megaduck);
|
||||
DECLARE_MACHINE_START(sgb);
|
||||
DECLARE_MACHINE_RESET(sgb);
|
||||
DECLARE_PALETTE_INIT(sgb);
|
||||
@ -267,32 +197,23 @@ public:
|
||||
TIMER_CALLBACK_MEMBER(gb_lcd_timer_proc);
|
||||
TIMER_CALLBACK_MEMBER(gbc_lcd_timer_proc);
|
||||
DECLARE_WRITE8_MEMBER(gb_timer_callback);
|
||||
DECLARE_DRIVER_INIT(gb);
|
||||
DECLARE_DEVICE_IMAGE_LOAD_MEMBER(gb_cart);
|
||||
DECLARE_DEVICE_IMAGE_LOAD_MEMBER(megaduck_cart);
|
||||
|
||||
DECLARE_READ8_MEMBER(gb_cart_r);
|
||||
DECLARE_READ8_MEMBER(gbc_cart_r);
|
||||
DECLARE_WRITE8_MEMBER(gb_bank_w);
|
||||
DECLARE_READ8_MEMBER(gb_ram_r);
|
||||
DECLARE_WRITE8_MEMBER(gb_ram_w);
|
||||
optional_device<gb_cart_slot_device> m_cartslot;
|
||||
|
||||
protected:
|
||||
required_device<lr35902_cpu_device> m_maincpu;
|
||||
required_memory_bank m_bank1; // all
|
||||
optional_memory_bank m_bank2; // dmg, sgb, cgb
|
||||
optional_memory_bank m_bank3; // cgb
|
||||
optional_memory_bank m_bank4; // dmg, sgb, cgb
|
||||
optional_memory_bank m_bank5; // dmg, sgb, cgb
|
||||
optional_memory_bank m_bank6; // dmg, sgb, cgb
|
||||
required_memory_bank m_bank10; // all
|
||||
optional_memory_bank m_bank11; // dmg, sgb, cgb
|
||||
optional_memory_bank m_rambank; // cgb
|
||||
required_ioport m_inputs;
|
||||
|
||||
void gb_timer_increment();
|
||||
void gb_timer_check_irq();
|
||||
void gb_init_regs();
|
||||
void gb_rom16_0000( UINT8 *addr );
|
||||
void gb_rom16_4000( UINT8 *addr );
|
||||
void gb_rom8_4000( UINT8 *addr );
|
||||
void gb_rom8_6000( UINT8 *addr );
|
||||
void gb_init();
|
||||
void gb_set_mbc1_banks();
|
||||
void gb_set_mbc1_kor_banks();
|
||||
void gb_init_regs();
|
||||
void gb_select_sprites();
|
||||
void gb_update_sprites();
|
||||
void gb_update_scanline();
|
||||
@ -305,7 +226,37 @@ protected:
|
||||
void gbc_hdma(UINT16 length);
|
||||
void gb_increment_scanline();
|
||||
void gb_lcd_switch_on();
|
||||
void gb_machine_stop();
|
||||
};
|
||||
|
||||
|
||||
class megaduck_state : public gb_state
|
||||
{
|
||||
public:
|
||||
megaduck_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: gb_state(mconfig, type, tag)
|
||||
, m_cartslot(*this, "duckslot")
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_inputs(*this, "INPUTS")
|
||||
{ }
|
||||
|
||||
DECLARE_READ8_MEMBER(megaduck_video_r);
|
||||
DECLARE_WRITE8_MEMBER(megaduck_video_w);
|
||||
DECLARE_WRITE8_MEMBER(megaduck_sound_w1);
|
||||
DECLARE_READ8_MEMBER(megaduck_sound_r1);
|
||||
DECLARE_WRITE8_MEMBER(megaduck_sound_w2);
|
||||
DECLARE_READ8_MEMBER(megaduck_sound_r2);
|
||||
DECLARE_MACHINE_START(megaduck);
|
||||
DECLARE_MACHINE_RESET(megaduck);
|
||||
DECLARE_PALETTE_INIT(megaduck);
|
||||
|
||||
DECLARE_READ8_MEMBER(cart_r);
|
||||
DECLARE_WRITE8_MEMBER(bank1_w);
|
||||
DECLARE_WRITE8_MEMBER(bank2_w);
|
||||
optional_device<megaduck_cart_slot_device> m_cartslot;
|
||||
|
||||
protected:
|
||||
required_device<lr35902_cpu_device> m_maincpu;
|
||||
required_ioport m_inputs;
|
||||
};
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
692
src/mess/machine/gb_mbc.c
Normal file
692
src/mess/machine/gb_mbc.c
Normal file
@ -0,0 +1,692 @@
|
||||
/***********************************************************************************************************
|
||||
|
||||
Game Boy carts with MBC (Memory Bank Controller)
|
||||
|
||||
|
||||
TODO: add proper RTC and Rumble support
|
||||
|
||||
***********************************************************************************************************/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "machine/gb_mbc.h"
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// gb_rom_mbc*_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
const device_type GB_ROM_MBC1 = &device_creator<gb_rom_mbc1_device>;
|
||||
const device_type GB_ROM_MBC1K = &device_creator<gb_rom_mbc1k_device>;
|
||||
const device_type GB_ROM_MBC2 = &device_creator<gb_rom_mbc2_device>;
|
||||
const device_type GB_ROM_MBC3 = &device_creator<gb_rom_mbc3_device>;
|
||||
const device_type GB_ROM_MBC5 = &device_creator<gb_rom_mbc5_device>;
|
||||
const device_type GB_ROM_MBC6 = &device_creator<gb_rom_mbc6_device>;
|
||||
const device_type GB_ROM_MBC7 = &device_creator<gb_rom_mbc7_device>;
|
||||
const device_type GB_ROM_MMM01 = &device_creator<gb_rom_mmm01_device>;
|
||||
|
||||
|
||||
gb_rom_mbc_device::gb_rom_mbc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, type, name, tag, owner, clock),
|
||||
device_gb_cart_interface( mconfig, *this )
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_mbc1_device::gb_rom_mbc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_mbc_device(mconfig, GB_ROM_MBC1, "GB MBC1 Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_mbc1k_device::gb_rom_mbc1k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_mbc_device(mconfig, GB_ROM_MBC1K, "GB MBC1 Korean Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_mbc2_device::gb_rom_mbc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_mbc_device(mconfig, GB_ROM_MBC2, "GB MBC2 Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_mbc3_device::gb_rom_mbc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_mbc_device(mconfig, GB_ROM_MBC3, "GB MBC3 Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_mbc5_device::gb_rom_mbc5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_mbc_device(mconfig, GB_ROM_MBC5, "GB MBC5 Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_mbc6_device::gb_rom_mbc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_mbc_device(mconfig, GB_ROM_MBC6, "GB MBC6 Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_mbc7_device::gb_rom_mbc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_mbc_device(mconfig, GB_ROM_MBC7, "GB MBC7 Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_mmm01_device::gb_rom_mmm01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_mbc_device(mconfig, GB_ROM_MMM01, "GB MMM01 Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void gb_rom_mbc_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = FALSE;
|
||||
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_enable = 0;
|
||||
m_ram_bank = 0;
|
||||
m_mode = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_ram_enable));
|
||||
save_item(NAME(m_mode));
|
||||
}
|
||||
|
||||
void gb_rom_mbc1_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = FALSE;
|
||||
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
m_ram_enable = 0;
|
||||
m_mode = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_ram_enable));
|
||||
save_item(NAME(m_mode));
|
||||
}
|
||||
|
||||
void gb_rom_mbc1k_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = FALSE;
|
||||
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
m_ram_enable = 0;
|
||||
m_mode = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_ram_enable));
|
||||
save_item(NAME(m_mode));
|
||||
}
|
||||
|
||||
void gb_rom_mbc2_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = FALSE;
|
||||
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
m_ram_enable = 0;
|
||||
m_mode = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_ram_enable));
|
||||
save_item(NAME(m_mode));
|
||||
}
|
||||
|
||||
void gb_rom_mbc3_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = FALSE;
|
||||
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
m_ram_enable = 0;
|
||||
m_mode = 0;
|
||||
memset(m_rtc_map, 0, sizeof(m_rtc_map));
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_ram_enable));
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_rtc_map));
|
||||
}
|
||||
|
||||
void gb_rom_mbc5_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = FALSE;
|
||||
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
m_ram_enable = 0;
|
||||
m_mode = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_ram_enable));
|
||||
save_item(NAME(m_mode));
|
||||
}
|
||||
|
||||
void gb_rom_mbc6_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = FALSE;
|
||||
|
||||
m_bank_4000 = 2; // correct default?
|
||||
m_bank_6000 = 3; // correct default?
|
||||
m_latch1 = 0; // correct default?
|
||||
m_latch2 = 0; // correct default?
|
||||
|
||||
m_latch_bank = 2; // correct default?
|
||||
m_latch_bank2 = 3; // correct default?
|
||||
m_ram_bank = 0;
|
||||
m_ram_enable = 0;
|
||||
m_mode = 0;
|
||||
|
||||
save_item(NAME(m_bank_4000));
|
||||
save_item(NAME(m_bank_6000));
|
||||
save_item(NAME(m_latch1));
|
||||
save_item(NAME(m_latch2));
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_ram_enable));
|
||||
save_item(NAME(m_mode));
|
||||
}
|
||||
|
||||
void gb_rom_mbc7_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = TRUE;
|
||||
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
m_ram_enable = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_ram_enable));
|
||||
}
|
||||
|
||||
void gb_rom_mmm01_device::device_start()
|
||||
{
|
||||
has_timer = FALSE;
|
||||
has_rumble = TRUE;
|
||||
|
||||
m_latch_bank = 0x200 - 2;
|
||||
m_latch_bank2 = 0x200 - 1;
|
||||
m_ram_bank = 0;
|
||||
m_bank_mask = 0xff;
|
||||
m_bank = 0;
|
||||
m_reg = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
save_item(NAME(m_bank_mask));
|
||||
save_item(NAME(m_bank));
|
||||
save_item(NAME(m_reg));
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
mapper specific handlers
|
||||
-------------------------------------------------*/
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc_device::read_rom)
|
||||
{
|
||||
return m_rom[rom_bank_map[m_latch_bank] + offset];
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc_device::read_ram)
|
||||
{
|
||||
if (m_ram)
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset];
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc_device::write_ram)
|
||||
{
|
||||
if (m_ram)
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset] = data;
|
||||
}
|
||||
|
||||
|
||||
// MBC1
|
||||
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc1_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc1_device::write_bank)
|
||||
{
|
||||
if (offset < 0x2000)
|
||||
m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0;
|
||||
else if (offset < 0x4000)
|
||||
{
|
||||
// 5bits only
|
||||
data &= 0x1f;
|
||||
// bank = 0 => bank = 1
|
||||
if (data == 0)
|
||||
data = 1;
|
||||
|
||||
m_latch_bank2 = (m_latch_bank2 & 0x01e0) | data;
|
||||
}
|
||||
else if (offset < 0x6000)
|
||||
{
|
||||
// 2bits only
|
||||
data &= 0x3;
|
||||
m_latch_bank2 = (m_latch_bank2 & 0x001f) | (data << 5);
|
||||
}
|
||||
else
|
||||
m_mode = data & 0x1;
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc1_device::read_ram)
|
||||
{
|
||||
if (m_ram && m_ram_enable)
|
||||
{
|
||||
m_ram_bank = m_mode ? (m_latch_bank2 >> 5) : 0;
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset];
|
||||
}
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc1_device::write_ram)
|
||||
{
|
||||
if (m_ram && m_ram_enable)
|
||||
{
|
||||
m_ram_bank = m_mode ? (m_latch_bank2 >> 5) : 0;
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset] = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MBC1 Korean variant (used by Bomberman Selection)
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc1k_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc1k_device::write_bank)
|
||||
{
|
||||
if (offset < 0x2000)
|
||||
m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0;
|
||||
else if (offset < 0x4000)
|
||||
{
|
||||
// 4bits only?
|
||||
data &= 0x0f;
|
||||
// bank = 0 => bank = 1
|
||||
if (data == 0)
|
||||
data = 1;
|
||||
|
||||
m_latch_bank2 = (m_latch_bank2 & 0x01f0) | data;
|
||||
}
|
||||
else if (offset < 0x6000)
|
||||
{
|
||||
// 2bits only
|
||||
data &= 0x3;
|
||||
m_latch_bank2 = (m_latch_bank2 & 0x000f) | (data << 4);
|
||||
m_latch_bank = m_latch_bank2 & 0x30;
|
||||
}
|
||||
else
|
||||
m_mode = data & 0x1;
|
||||
}
|
||||
|
||||
// RAM access is the same as usual MBC1
|
||||
READ8_MEMBER(gb_rom_mbc1k_device::read_ram)
|
||||
{
|
||||
if (m_ram && m_ram_enable)
|
||||
{
|
||||
m_ram_bank = m_mode ? (m_latch_bank2 >> 5) : 0;
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset];
|
||||
}
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc1k_device::write_ram)
|
||||
{
|
||||
if (m_ram && m_ram_enable)
|
||||
{
|
||||
m_ram_bank = m_mode ? (m_latch_bank2 >> 5) : 0;
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset] = data;
|
||||
}
|
||||
}
|
||||
|
||||
// MBC2
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc2_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc2_device::write_bank)
|
||||
{
|
||||
if (offset < 0x2000)
|
||||
m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0;
|
||||
else if (offset < 0x4000)
|
||||
{
|
||||
// 4bits only
|
||||
data &= 0x0f;
|
||||
// bank = 0 => bank = 1
|
||||
if (data == 0)
|
||||
data = 1;
|
||||
|
||||
// The least significant bit of the upper address byte must be 1
|
||||
if (offset & 0x0100)
|
||||
m_latch_bank2 = (m_latch_bank2 & 0x100) | data;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 bank only??
|
||||
READ8_MEMBER(gb_rom_mbc2_device::read_ram)
|
||||
{
|
||||
if (m_ram && m_ram_enable)
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)];
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc2_device::write_ram)
|
||||
{
|
||||
if (m_ram && m_ram_enable)
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data;
|
||||
}
|
||||
|
||||
|
||||
// MBC3
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc3_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc3_device::write_bank)
|
||||
{
|
||||
if (offset < 0x2000)
|
||||
m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0;
|
||||
else if (offset < 0x4000)
|
||||
{
|
||||
// 7bits
|
||||
data &= 0x7f;
|
||||
/* Selecting bank 0 == selecting bank 1 */
|
||||
if (data == 0)
|
||||
data = 1;
|
||||
|
||||
m_latch_bank2 = data;
|
||||
}
|
||||
else if (offset < 0x6000)
|
||||
{
|
||||
m_ram_bank = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_timer)
|
||||
{
|
||||
/* FIXME: RTC Latch goes here */
|
||||
m_rtc_map[0] = 50; /* Seconds */
|
||||
m_rtc_map[1] = 40; /* Minutes */
|
||||
m_rtc_map[2] = 15; /* Hours */
|
||||
m_rtc_map[3] = 25; /* Day counter lowest 8 bits */
|
||||
m_rtc_map[4] = 0x01; /* Day counter upper bit, timer off, no day overflow occurred (bit7) */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc3_device::read_ram)
|
||||
{
|
||||
if (m_ram_bank < 4 && m_ram_enable)
|
||||
{ // RAM
|
||||
if (m_ram)
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)];
|
||||
}
|
||||
if (m_ram_bank >= 0x8 && m_ram_bank <= 0xc)
|
||||
{ // RAM
|
||||
if (has_timer)
|
||||
return m_rtc_map[m_ram_bank - 8];
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc3_device::write_ram)
|
||||
{
|
||||
if (m_ram_bank < 4 && m_ram_enable)
|
||||
{ // RAM
|
||||
if (m_ram)
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data;
|
||||
}
|
||||
if (m_ram_bank >= 0x8 && m_ram_bank <= 0xc)
|
||||
{ // RAM
|
||||
if (has_timer)
|
||||
{
|
||||
// what to do here?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MBC5
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc5_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc5_device::write_bank)
|
||||
{
|
||||
if (offset < 0x2000)
|
||||
m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0;
|
||||
else if (offset < 0x4000)
|
||||
{
|
||||
// MBC5 has a 9 bit bank select
|
||||
// Writing into 2000-2fff sets the lower 8 bits
|
||||
// Writing into 3000-3fff sets the 9th bit
|
||||
if (offset & 0x1000)
|
||||
m_latch_bank2 = (m_latch_bank2 & 0xff) | ((data & 0x01) << 8);
|
||||
else
|
||||
m_latch_bank2 = (m_latch_bank2 & 0x100) | data;
|
||||
}
|
||||
else if (offset < 0x6000)
|
||||
{
|
||||
data &= 0x0f;
|
||||
if (has_rumble)
|
||||
data &= 0x7;
|
||||
m_ram_bank = data;
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc5_device::read_ram)
|
||||
{
|
||||
if (m_ram && m_ram_enable)
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)];
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc5_device::write_ram)
|
||||
{
|
||||
if (m_ram && m_ram_enable)
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data;
|
||||
}
|
||||
|
||||
// MBC6
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc6_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else if (offset < 0x6000)
|
||||
return m_rom[rom_bank_map[m_bank_4000 >> 1] * 0x4000 + (m_bank_4000 & 0x01) * 0x2000 + (offset & 0x1fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_bank_6000 >> 1] * 0x4000 + (m_bank_6000 & 0x01) * 0x2000 + (offset & 0x1fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc6_device::write_bank)
|
||||
{
|
||||
if (offset < 0x2000)
|
||||
{
|
||||
logerror( "0x%04X: write to mbc6 ram enable area: %04X <- 0x%02X\n", space.device().safe_pc(), offset, data );
|
||||
}
|
||||
else if (offset < 0x3000)
|
||||
{
|
||||
if (!(offset & 0x0800))
|
||||
m_latch1 = data;
|
||||
else if (data == 0x00)
|
||||
m_bank_4000 = m_latch1;
|
||||
}
|
||||
else if (offset < 0x4000)
|
||||
{
|
||||
if (!(offset & 0x0800))
|
||||
m_latch2 = data;
|
||||
else if (data == 0x00)
|
||||
m_bank_6000 = m_latch2;
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc6_device::read_ram)
|
||||
{
|
||||
if (m_ram)
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)];
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc6_device::write_ram)
|
||||
{
|
||||
if (m_ram)
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data;
|
||||
}
|
||||
|
||||
// MBC7
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc7_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc7_device::write_bank)
|
||||
{
|
||||
if (offset < 0x2000)
|
||||
{
|
||||
// FIXME: Add RAM enable support
|
||||
logerror("0x%04X: Write to ram enable register 0x%04X <- 0x%02X\n", space.device().safe_pc( ), offset, data);
|
||||
}
|
||||
else if (offset < 0x3000)
|
||||
{
|
||||
logerror( "0x%04X: write to mbc7 rom select register: 0x%04X <- 0x%02X\n", space.device() .safe_pc( ), 0x2000 + offset, data );
|
||||
/* Bit 12 must be set for writing to the mbc register */
|
||||
if (offset & 0x0100)
|
||||
m_latch_bank2 = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror( "0x%04X: write to mbc7 rom area: 0x%04X <- 0x%02X\n", space.device() .safe_pc( ), 0x3000 + offset, data );
|
||||
/* Bit 12 must be set for writing to the mbc register */
|
||||
if (offset & 0x0100)
|
||||
{
|
||||
switch (offset & 0x7000)
|
||||
{
|
||||
case 0x3000: /* 0x3000-0x3fff */
|
||||
case 0x4000: /* 0x4000-0x4fff */
|
||||
case 0x5000: /* 0x5000-0x5fff */
|
||||
case 0x6000: /* 0x6000-0x6fff */
|
||||
case 0x7000: /* 0x7000-0x7fff */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_rom_mbc7_device::read_ram)
|
||||
{
|
||||
if (m_ram)
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)];
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mbc7_device::write_ram)
|
||||
{
|
||||
if (m_ram)
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data;
|
||||
}
|
||||
|
||||
|
||||
// MMM01
|
||||
// This mmm01 implementation is mostly guess work, no clue how correct it all is
|
||||
|
||||
READ8_MEMBER(gb_rom_mmm01_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + offset];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_mmm01_device::write_bank)
|
||||
{
|
||||
if (offset < 0x2000)
|
||||
{
|
||||
if (data & 0x40)
|
||||
{
|
||||
m_latch_bank = m_reg;
|
||||
m_latch_bank2 = m_latch_bank + m_bank;
|
||||
}
|
||||
}
|
||||
else if (offset < 0x4000)
|
||||
{
|
||||
m_reg = data & ((m_rom_size / 0x4000) - 1);
|
||||
m_bank = m_reg & m_bank_mask;
|
||||
if (m_bank == 0)
|
||||
m_bank = 1;
|
||||
m_latch_bank2 = m_latch_bank + m_bank;
|
||||
}
|
||||
else if (offset < 0x6000)
|
||||
logerror("0x%04X: write 0x%02X to 0x%04X\n", space.device().safe_pc(), data, offset);
|
||||
else
|
||||
{
|
||||
logerror( "0x%04X: write 0x%02X to 0x%04X\n", space.device().safe_pc(), data, offset);
|
||||
/* Not sure if this is correct, Taito Variety Pack sets these values */
|
||||
/* Momotarou Collection 2 writes 01 and 21 here */
|
||||
switch (data)
|
||||
{
|
||||
case 0x30: m_bank_mask = 0x07; break;
|
||||
case 0x38: m_bank_mask = 0x03; break;
|
||||
default: m_bank_mask = 0xff; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
187
src/mess/machine/gb_mbc.h
Normal file
187
src/mess/machine/gb_mbc.h
Normal file
@ -0,0 +1,187 @@
|
||||
#ifndef __GB_MBC_H
|
||||
#define __GB_MBC_H
|
||||
|
||||
#include "machine/gb_slot.h"
|
||||
|
||||
|
||||
// ======================> gb_rom_mbc_device
|
||||
|
||||
class gb_rom_mbc_device : public device_t,
|
||||
public device_gb_cart_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mbc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mbc_base"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
|
||||
UINT8 m_ram_enable;
|
||||
UINT8 m_mode;
|
||||
};
|
||||
|
||||
// ======================> gb_rom_mbc1_device
|
||||
|
||||
class gb_rom_mbc1_device : public gb_rom_mbc_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mbc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mbc1"; }
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_mbc1k_device
|
||||
|
||||
class gb_rom_mbc1k_device : public gb_rom_mbc_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mbc1k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mbc1k"; }
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_mbc2_device
|
||||
|
||||
class gb_rom_mbc2_device : public gb_rom_mbc_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mbc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mbc2"; }
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_mbc3_device
|
||||
|
||||
class gb_rom_mbc3_device : public gb_rom_mbc_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mbc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mbc3"; }
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
UINT8 m_rtc_map[5];
|
||||
};
|
||||
|
||||
// ======================> gb_rom_mbc5_device
|
||||
|
||||
class gb_rom_mbc5_device : public gb_rom_mbc_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mbc5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mbc5"; }
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_mbc6_device
|
||||
|
||||
class gb_rom_mbc6_device : public gb_rom_mbc_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mbc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mbc6"; }
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
UINT16 m_latch1, m_latch2;
|
||||
UINT8 m_bank_4000, m_bank_6000;
|
||||
};
|
||||
|
||||
// ======================> gb_rom_mbc7_device
|
||||
|
||||
class gb_rom_mbc7_device : public gb_rom_mbc_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mbc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mbc7"; }
|
||||
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_mmm01_device
|
||||
class gb_rom_mmm01_device : public gb_rom_mbc_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_mmm01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_mmm01"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
UINT8 m_bank_mask, m_bank, m_reg;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type GB_ROM_MBC1;
|
||||
extern const device_type GB_ROM_MBC1K;
|
||||
extern const device_type GB_ROM_MBC2;
|
||||
extern const device_type GB_ROM_MBC3;
|
||||
extern const device_type GB_ROM_MBC4;
|
||||
extern const device_type GB_ROM_MBC5;
|
||||
extern const device_type GB_ROM_MBC6;
|
||||
extern const device_type GB_ROM_MBC7;
|
||||
extern const device_type GB_ROM_MMM01;
|
||||
|
||||
#endif
|
369
src/mess/machine/gb_rom.c
Normal file
369
src/mess/machine/gb_rom.c
Normal file
@ -0,0 +1,369 @@
|
||||
/***********************************************************************************************************
|
||||
|
||||
Game Boy cart emulation
|
||||
|
||||
|
||||
Here we emulate carts with no RAM and simple bankswitch
|
||||
|
||||
|
||||
***********************************************************************************************************/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "machine/gb_rom.h"
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// gb_rom_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
const device_type GB_STD_ROM = &device_creator<gb_rom_device>;
|
||||
const device_type GB_ROM_TAMA5 = &device_creator<gb_rom_tama5_device>;
|
||||
const device_type GB_ROM_WISDOM = &device_creator<gb_rom_wisdom_device>;
|
||||
const device_type GB_ROM_YONG = &device_creator<gb_rom_yong_device>;
|
||||
const device_type GB_ROM_ATVRAC = &device_creator<gb_rom_atvrac_device>;
|
||||
const device_type GB_ROM_LASAMA = &device_creator<gb_rom_lasama_device>;
|
||||
|
||||
const device_type MEGADUCK_ROM = &device_creator<megaduck_rom_device>;
|
||||
|
||||
|
||||
gb_rom_device::gb_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, type, name, tag, owner, clock),
|
||||
device_gb_cart_interface( mconfig, *this )
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_device::gb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, GB_STD_ROM, "GB Carts", tag, owner, clock),
|
||||
device_gb_cart_interface( mconfig, *this )
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_tama5_device::gb_rom_tama5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_device(mconfig, GB_ROM_TAMA5, "GB Tamagotchi", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_wisdom_device::gb_rom_wisdom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_device(mconfig, GB_ROM_WISDOM, "GB Wisdom Tree Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_yong_device::gb_rom_yong_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_device(mconfig, GB_ROM_YONG, "GB Yong Yong Carts", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_atvrac_device::gb_rom_atvrac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_device(mconfig, GB_ROM_ATVRAC, "GB ATV Racin'", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gb_rom_lasama_device::gb_rom_lasama_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: gb_rom_device(mconfig, GB_ROM_LASAMA, "GB LaSaMa", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
megaduck_rom_device::megaduck_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, type, name, tag, owner, clock),
|
||||
device_gb_cart_interface( mconfig, *this )
|
||||
{
|
||||
}
|
||||
|
||||
megaduck_rom_device::megaduck_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, MEGADUCK_ROM, "MegaDuck Carts", tag, owner, clock),
|
||||
device_gb_cart_interface( mconfig, *this )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void gb_rom_device::device_start()
|
||||
{
|
||||
// these actually never change for base carts, so no need to save them
|
||||
m_latch_bank = 0;
|
||||
m_ram_bank = 0;
|
||||
}
|
||||
|
||||
void megaduck_rom_device::device_start()
|
||||
{
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
}
|
||||
|
||||
void gb_rom_tama5_device::device_start()
|
||||
{
|
||||
m_tama5_data = 0;
|
||||
m_tama5_addr= 0;
|
||||
m_tama5_cmd = 0;
|
||||
memset(m_regs, 0xff, sizeof(m_regs));
|
||||
m_rtc_reg = 0xff;
|
||||
m_ram_bank = 0;
|
||||
save_item(NAME(m_tama5_data));
|
||||
save_item(NAME(m_tama5_addr));
|
||||
save_item(NAME(m_tama5_cmd));
|
||||
save_item(NAME(m_regs));
|
||||
save_item(NAME(m_rtc_reg));
|
||||
save_item(NAME(m_ram_bank));
|
||||
}
|
||||
|
||||
void gb_rom_wisdom_device::device_start()
|
||||
{
|
||||
m_latch_bank = 0;
|
||||
m_ram_bank = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_ram_bank));
|
||||
}
|
||||
|
||||
void gb_rom_yong_device::device_start()
|
||||
{
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
}
|
||||
|
||||
void gb_rom_atvrac_device::device_start()
|
||||
{
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
}
|
||||
|
||||
void gb_rom_lasama_device::device_start()
|
||||
{
|
||||
m_latch_bank = 0;
|
||||
m_latch_bank2 = 1;
|
||||
m_ram_bank = 0;
|
||||
save_item(NAME(m_latch_bank));
|
||||
save_item(NAME(m_latch_bank2));
|
||||
save_item(NAME(m_ram_bank));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
mapper specific handlers
|
||||
-------------------------------------------------*/
|
||||
|
||||
READ8_MEMBER(gb_rom_device::read_rom)
|
||||
{
|
||||
m_latch_bank = offset / 0x4000;
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_rom_device::read_ram)
|
||||
{
|
||||
if (m_ram)
|
||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset];
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_device::write_ram)
|
||||
{
|
||||
if (m_ram)
|
||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset] = data;
|
||||
}
|
||||
|
||||
|
||||
// Tamagotchi
|
||||
|
||||
READ8_MEMBER(gb_rom_tama5_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
READ8_MEMBER(gb_rom_tama5_device::read_ram)
|
||||
{
|
||||
return m_rtc_reg;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_tama5_device::write_ram)
|
||||
{
|
||||
switch (offset & 0x0001)
|
||||
{
|
||||
case 0x0000: /* Write to data register */
|
||||
switch (m_tama5_cmd)
|
||||
{
|
||||
case 0x00: /* Bits 0-3 for rom bank selection */
|
||||
m_latch_bank2 = (m_latch_bank2 & 0xf0) | (data & 0x0f);
|
||||
break;
|
||||
case 0x01: /* Bit 4(-7?) for rom bank selection */
|
||||
m_latch_bank2 = (m_latch_bank2 & 0x0f) | ((data & 0x0f) << 4);
|
||||
break;
|
||||
case 0x04: /* Data to write lo */
|
||||
m_tama5_data = (m_tama5_data & 0xf0) | (data & 0x0f);
|
||||
break;
|
||||
case 0x05: /* Data to write hi */
|
||||
m_tama5_data = (m_tama5_data & 0x0f) | ((data & 0x0f) << 4);
|
||||
break;
|
||||
case 0x06: /* Address selection hi */
|
||||
m_tama5_addr = (m_tama5_addr & 0x0f) | ((data & 0x0f) << 4);
|
||||
break;
|
||||
case 0x07: /* Address selection lo */
|
||||
/* This address always seems to written last, so we'll just
|
||||
execute the command here */
|
||||
m_tama5_addr = (m_tama5_addr & 0xf0) | (data & 0x0f);
|
||||
switch (m_tama5_addr & 0xe0)
|
||||
{
|
||||
case 0x00: /* Write memory */
|
||||
//logerror( "Write tama5 memory 0x%02X <- 0x%02X\n", m_tama5_addr & 0x1f, m_tama5_data);
|
||||
m_regs[m_tama5_addr & 0x1f] = m_tama5_data;
|
||||
break;
|
||||
case 0x20: /* Read memory */
|
||||
//logerror( "Read tama5 memory 0x%02X\n", m_tama5_addr & 0x1f);
|
||||
m_tama5_data = m_regs[m_tama5_addr & 0x1f];
|
||||
break;
|
||||
case 0x40: /* Unknown, some kind of read */
|
||||
if ((m_tama5_addr & 0x1f) == 0x12)
|
||||
m_tama5_data = 0xff;
|
||||
case 0x80: /* Unknown, some kind of read (when 07=01)/write (when 07=00/02) */
|
||||
default:
|
||||
logerror( "0x%04X: Unknown addressing mode\n", space.device() .safe_pc( ) );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0001: /* Write to control register */
|
||||
switch (data)
|
||||
{
|
||||
case 0x00: /* Bits 0-3 for rom bank selection */
|
||||
case 0x01: /* Bits 4-7 for rom bank selection */
|
||||
case 0x04: /* Data write register lo */
|
||||
case 0x05: /* Data write register hi */
|
||||
case 0x06: /* Address register hi */
|
||||
case 0x07: /* Address register lo */
|
||||
break;
|
||||
case 0x0a: /* Are we ready for the next command? */
|
||||
m_rtc_reg = 0x01;
|
||||
break;
|
||||
case 0x0c: /* Data read register lo */
|
||||
m_rtc_reg = m_tama5_data & 0x0f;
|
||||
break;
|
||||
case 0x0d: /* Data read register hi */
|
||||
m_rtc_reg = (m_tama5_data & 0xf0) >> 4;
|
||||
break;
|
||||
default:
|
||||
logerror( "0x%04X: Unknown tama5 command 0x%02X\n", space.device() .safe_pc( ), data );
|
||||
break;
|
||||
}
|
||||
m_tama5_cmd = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Wisdom Tree
|
||||
|
||||
READ8_MEMBER(gb_rom_wisdom_device::read_rom)
|
||||
{
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + offset];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_wisdom_device::write_bank)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
m_latch_bank = (offset << 1) & 0x1ff;
|
||||
}
|
||||
|
||||
|
||||
// Yong Yong pirate
|
||||
|
||||
READ8_MEMBER(gb_rom_yong_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_yong_device::write_bank)
|
||||
{
|
||||
if (offset == 0x2000)
|
||||
m_latch_bank2 = data;
|
||||
}
|
||||
|
||||
|
||||
// ATV Racin pirate (incomplete)
|
||||
|
||||
READ8_MEMBER(gb_rom_atvrac_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_atvrac_device::write_bank)
|
||||
{
|
||||
if (offset == 0x3f00)
|
||||
{
|
||||
if (data == 0)
|
||||
data = 1;
|
||||
m_latch_bank2 = m_latch_bank | data;
|
||||
}
|
||||
if (offset == 0x3fc0)
|
||||
m_latch_bank = data * 16;
|
||||
}
|
||||
|
||||
// La Sa Ma pirate (incomplete)
|
||||
|
||||
READ8_MEMBER(gb_rom_lasama_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(gb_rom_lasama_device::write_bank)
|
||||
{
|
||||
if (offset == 0x2080)
|
||||
{
|
||||
// Actual banking?
|
||||
m_latch_bank2 = m_latch_bank | (data & 0x03);
|
||||
}
|
||||
if (offset == 0x6000)
|
||||
{
|
||||
// On boot the following two get written right after each other:
|
||||
// 02
|
||||
// BE
|
||||
// Disable logo switching?
|
||||
if (!(data & 0x80))
|
||||
m_latch_bank = (data & 0x02) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MegaDuck carts
|
||||
|
||||
READ8_MEMBER(megaduck_rom_device::read_rom)
|
||||
{
|
||||
if (offset < 0x4000)
|
||||
return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)];
|
||||
else
|
||||
return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(megaduck_rom_device::write_bank)
|
||||
{
|
||||
if (offset == 0x0001)
|
||||
m_latch_bank2 = data;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(megaduck_rom_device::write_ram)
|
||||
{
|
||||
m_latch_bank = data * 2;
|
||||
m_latch_bank2 = data * 2 + 1;
|
||||
}
|
||||
|
143
src/mess/machine/gb_rom.h
Normal file
143
src/mess/machine/gb_rom.h
Normal file
@ -0,0 +1,143 @@
|
||||
#ifndef __GB_ROM_H
|
||||
#define __GB_ROM_H
|
||||
|
||||
#include "machine/gb_slot.h"
|
||||
|
||||
|
||||
// ======================> gb_rom_device
|
||||
|
||||
class gb_rom_device : public device_t,
|
||||
public device_gb_cart_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
|
||||
gb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_tama5_device
|
||||
class gb_rom_tama5_device : public gb_rom_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_tama5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_tama5"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
UINT16 m_tama5_data, m_tama5_addr, m_tama5_cmd;
|
||||
UINT8 m_regs[32];
|
||||
UINT8 m_rtc_reg;
|
||||
};
|
||||
|
||||
// ======================> gb_rom_wisdom_device
|
||||
class gb_rom_wisdom_device : public gb_rom_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_wisdom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_wisdom"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_yong_device
|
||||
class gb_rom_yong_device : public gb_rom_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_yong_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_yong"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_atvrac_device
|
||||
class gb_rom_atvrac_device : public gb_rom_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_atvrac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_atvrac"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
// ======================> gb_rom_lasama_device
|
||||
class gb_rom_lasama_device : public gb_rom_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_rom_lasama_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "gb_rom_lasama"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// ======================> megaduck_rom_device
|
||||
class megaduck_rom_device :public device_t,
|
||||
public device_gb_cart_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
megaduck_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
|
||||
megaduck_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete() { m_shortname = "megaduck_rom"; }
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type GB_STD_ROM;
|
||||
extern const device_type GB_ROM_TAMA5;
|
||||
extern const device_type GB_ROM_WISDOM;
|
||||
extern const device_type GB_ROM_YONG;
|
||||
extern const device_type GB_ROM_ATVRAC;
|
||||
extern const device_type GB_ROM_LASAMA;
|
||||
|
||||
extern const device_type MEGADUCK_ROM;
|
||||
|
||||
#endif
|
771
src/mess/machine/gb_slot.c
Normal file
771
src/mess/machine/gb_slot.c
Normal file
@ -0,0 +1,771 @@
|
||||
/***********************************************************************************************************
|
||||
|
||||
|
||||
Game Boy cart emulation
|
||||
(through slot devices)
|
||||
|
||||
|
||||
The driver exposes address ranges
|
||||
0x0000-0x7fff to read_rom/write_bank
|
||||
0xa000-0xbfff to read_ram/write_ram (typically RAM/NVRAM accesses, but megaduck uses the write for bankswitch)
|
||||
|
||||
currently available slot devices:
|
||||
gb_rom: standard carts + TAMA5 mapper + pirate carts with protection & bankswitch
|
||||
gb_mbc: MBC1-MBC7 carts (more complex bankswitch + RAM + possibly RTC/Rumble/etc.)
|
||||
|
||||
***********************************************************************************************************/
|
||||
|
||||
|
||||
#include "emu.h"
|
||||
#include "machine/gb_slot.h"
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
const device_type GB_CART_SLOT = &device_creator<gb_cart_slot_device>;
|
||||
const device_type MEGADUCK_CART_SLOT = &device_creator<megaduck_cart_slot_device>;
|
||||
|
||||
//**************************************************************************
|
||||
// MD cartridges Interface
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_gb_cart_interface - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_gb_cart_interface::device_gb_cart_interface(const machine_config &mconfig, device_t &device)
|
||||
: device_slot_card_interface(mconfig, device),
|
||||
m_rom(NULL),
|
||||
m_ram(NULL),
|
||||
m_rom_size(0),
|
||||
m_ram_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ~device_gb_cart_interface - destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_gb_cart_interface::~device_gb_cart_interface()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// rom_alloc - alloc the space for the cart
|
||||
//-------------------------------------------------
|
||||
|
||||
void device_gb_cart_interface::rom_alloc(running_machine &machine, UINT32 size)
|
||||
{
|
||||
if (m_rom == NULL)
|
||||
{
|
||||
m_rom = auto_alloc_array_clear(machine, UINT8, size);
|
||||
m_rom_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ram_alloc - alloc the space for the ram
|
||||
//-------------------------------------------------
|
||||
|
||||
void device_gb_cart_interface::ram_alloc(running_machine &machine, UINT32 size)
|
||||
{
|
||||
if (m_ram == NULL)
|
||||
{
|
||||
m_ram = auto_alloc_array_clear(machine, UINT8, size);
|
||||
m_ram_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// rom_map_setup - setup map of rom banks in 16K
|
||||
// blocks, so to simplify ROM access
|
||||
//-------------------------------------------------
|
||||
|
||||
void device_gb_cart_interface::rom_map_setup(UINT32 size)
|
||||
{
|
||||
int i;
|
||||
// setup the rom_bank_map array to faster ROM read
|
||||
for (i = 0; i < size / 0x4000; i++)
|
||||
rom_bank_map[i] = i;
|
||||
|
||||
// fill up remaining blocks with mirrors
|
||||
while (i % 512)
|
||||
{
|
||||
int j = 0, repeat_banks;
|
||||
while ((i % (512 >> j)) && j < 9)
|
||||
j++;
|
||||
repeat_banks = i % (512 >> (j - 1));
|
||||
for (int k = 0; k < repeat_banks; k++)
|
||||
rom_bank_map[i + k] = rom_bank_map[i + k - repeat_banks];
|
||||
i += repeat_banks;
|
||||
}
|
||||
|
||||
// check bank map!
|
||||
// for (i = 0; i < 256; i++)
|
||||
// {
|
||||
// printf("bank %3d = %3d\t", i, rom_bank_map[i]);
|
||||
// if ((i%8) == 7)
|
||||
// printf("\n");
|
||||
// }
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// ram_map_setup - setup map of ram banks in 16K
|
||||
// blocks, so to simplify ROM access
|
||||
//-------------------------------------------------
|
||||
|
||||
void device_gb_cart_interface::ram_map_setup(UINT8 banks)
|
||||
{
|
||||
int mask = banks - 1;
|
||||
|
||||
for (int i = 0; i < banks; i++)
|
||||
ram_bank_map[i] = i;
|
||||
|
||||
// Set up rest of the (mirrored) RAM pages
|
||||
for (int i = banks; i < 256; i++)
|
||||
ram_bank_map[i] = i & mask;
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// base_gb_cart_slot_device - constructor
|
||||
//-------------------------------------------------
|
||||
base_gb_cart_slot_device::base_gb_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, type, name, tag, owner, clock),
|
||||
device_image_interface(mconfig, *this),
|
||||
device_slot_interface(mconfig, *this),
|
||||
m_type(GB_MBC_UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
gb_cart_slot_device::gb_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
base_gb_cart_slot_device(mconfig, GB_CART_SLOT, "Game Boy Cartridge Slot", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
megaduck_cart_slot_device::megaduck_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
base_gb_cart_slot_device(mconfig, MEGADUCK_CART_SLOT, "Megaduck Cartridge Slot", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// base_gb_cart_slot_device - destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
base_gb_cart_slot_device::~base_gb_cart_slot_device()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void base_gb_cart_slot_device::device_start()
|
||||
{
|
||||
m_cart = dynamic_cast<device_gb_cart_interface *>(get_card_device());
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_config_complete - perform any
|
||||
// operations now that the configuration is
|
||||
// complete
|
||||
//-------------------------------------------------
|
||||
|
||||
void base_gb_cart_slot_device::device_config_complete()
|
||||
{
|
||||
// set brief and instance name
|
||||
update_names();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// MD PCB
|
||||
//-------------------------------------------------
|
||||
|
||||
|
||||
struct gb_slot
|
||||
{
|
||||
int pcb_id;
|
||||
const char *slot_option;
|
||||
};
|
||||
|
||||
// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
|
||||
static const gb_slot slot_list[] =
|
||||
{
|
||||
{ GB_MBC_MBC1, "rom_mbc1" },
|
||||
{ GB_MBC_MBC1_KOR, "rom_mbc1k" },
|
||||
{ GB_MBC_MBC2, "rom_mbc2" },
|
||||
{ GB_MBC_MBC3, "rom_mbc3" },
|
||||
{ GB_MBC_MBC5, "rom_mbc5" },
|
||||
{ GB_MBC_MBC6, "rom_mbc6" },
|
||||
{ GB_MBC_MBC7, "rom_mbc7" },
|
||||
{ GB_MBC_TAMA5, "rom_tama5" },
|
||||
{ GB_MBC_MMM01, "rom_mmm01" },
|
||||
{ GB_MBC_MBC3, "rom_huc1" }, // for now treat this as alias for MBC3
|
||||
{ GB_MBC_MBC3, "rom_huc3" }, // for now treat this as alias for MBC3
|
||||
{ GB_MBC_WISDOM, "rom_wisdom" },
|
||||
{ GB_MBC_YONGYONG, "rom_yong" },
|
||||
{ GB_MBC_LASAMA, "rom_lasama" },
|
||||
{ GB_MBC_ATVRACIN, "rom_atvrac" },
|
||||
{ GB_MBC_CAMERA, "rom_camera" }
|
||||
};
|
||||
|
||||
static int gb_get_pcb_id(const char *slot)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_LENGTH(slot_list); i++)
|
||||
{
|
||||
if (!mame_stricmp(slot_list[i].slot_option, slot))
|
||||
return slot_list[i].pcb_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *gb_get_slot(int type)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_LENGTH(slot_list); i++)
|
||||
{
|
||||
if (slot_list[i].pcb_id == type)
|
||||
return slot_list[i].slot_option;
|
||||
}
|
||||
|
||||
return "rom";
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
call load
|
||||
-------------------------------------------------*/
|
||||
|
||||
|
||||
bool base_gb_cart_slot_device::call_load()
|
||||
{
|
||||
if (m_cart)
|
||||
{
|
||||
UINT32 offset = 0;
|
||||
UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom");
|
||||
UINT8 *ROM;
|
||||
|
||||
// From fullpath, check for presence of a header and skip it + check filesize is valid
|
||||
if (software_entry() == NULL)
|
||||
{
|
||||
if ((len % 0x4000) == 512)
|
||||
{
|
||||
logerror("Rom-header found, skipping\n");
|
||||
offset = 512;
|
||||
len -= offset;
|
||||
fseek(offset, SEEK_SET);
|
||||
}
|
||||
/* Verify that the file contains 16kb blocks */
|
||||
if ((len == 0) || ((len % 0x4000) != 0))
|
||||
{
|
||||
seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid rom file size\n");
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
m_cart->rom_alloc(machine(), len);
|
||||
ROM = m_cart->get_rom_base();
|
||||
|
||||
if (software_entry() == NULL)
|
||||
fread(ROM, len);
|
||||
else
|
||||
memcpy(ROM, get_software_region("rom"), len);
|
||||
|
||||
// determine cart type
|
||||
offset = 0;
|
||||
if (get_mmm01_candidate(ROM, len))
|
||||
offset = len - 0x8000;
|
||||
int type;
|
||||
|
||||
if (software_entry() != NULL)
|
||||
type = gb_get_pcb_id(get_feature("slot") ? get_feature("slot") : "rom");
|
||||
else
|
||||
type = get_cart_type(ROM + offset, len - offset);
|
||||
|
||||
if (software_entry() != NULL)
|
||||
{
|
||||
const char *rumble = get_feature("rumble");
|
||||
const char *battery_backed = get_feature("battery_backed");
|
||||
|
||||
if (rumble != NULL)
|
||||
{
|
||||
if (!mame_stricmp(rumble, "yes"))
|
||||
m_cart->set_has_rumble(TRUE);
|
||||
}
|
||||
|
||||
if (battery_backed != NULL)
|
||||
{
|
||||
if (!mame_stricmp(battery_backed, "yes"))
|
||||
m_cart->set_has_battery(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
switch (ROM[0x0147 + offset])
|
||||
{
|
||||
case 0x03: case 0x06: case 0x09: case 0x0d: case 0x13: case 0x17: case 0x1b: case 0x22:
|
||||
m_cart->set_has_battery(TRUE);
|
||||
break;
|
||||
|
||||
case 0x0f: case 0x10:
|
||||
m_cart->set_has_battery(TRUE);
|
||||
m_cart->set_has_timer(TRUE);
|
||||
break;
|
||||
|
||||
case 0x1c: case 0x1d:
|
||||
m_cart->set_has_rumble(TRUE);
|
||||
break;
|
||||
|
||||
case 0x1e:
|
||||
m_cart->set_has_battery(TRUE);
|
||||
m_cart->set_has_rumble(TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
int rombanks, rambanks;
|
||||
|
||||
switch (ROM[0x0148 + offset])
|
||||
{
|
||||
case 0x52:
|
||||
rombanks = 72;
|
||||
break;
|
||||
case 0x53:
|
||||
rombanks = 80;
|
||||
break;
|
||||
case 0x54:
|
||||
rombanks = 96;
|
||||
break;
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x04: case 0x05: case 0x06: case 0x07:
|
||||
rombanks = 2 << ROM[0x0148];
|
||||
break;
|
||||
default:
|
||||
rombanks = 256;
|
||||
break;
|
||||
}
|
||||
|
||||
// setup rom bank map based on real length, not header value
|
||||
m_cart->rom_map_setup(len);
|
||||
|
||||
switch (ROM[0x0149 + offset] & 0x07)
|
||||
{
|
||||
case 0x00: case 0x06: case 0x07:
|
||||
rambanks = 0;
|
||||
break;
|
||||
case 0x01: case 0x02:
|
||||
rambanks = 1;
|
||||
break;
|
||||
case 0x03:
|
||||
rambanks = 4;
|
||||
break;
|
||||
case 0x04:
|
||||
rambanks = 16;
|
||||
break;
|
||||
case 0x05:
|
||||
default:
|
||||
rambanks = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == GB_MBC_MBC2 || type == GB_MBC_MBC7)
|
||||
rambanks = 1;
|
||||
|
||||
if (rambanks)
|
||||
setup_ram(rambanks);
|
||||
|
||||
if (m_cart->get_ram_size() && m_cart->get_has_battery())
|
||||
battery_load(m_cart->get_ram_base(), m_cart->get_ram_size(), 0xff);
|
||||
|
||||
//printf("Type: %s\n", gb_get_slot(type));
|
||||
|
||||
internal_header_logging(ROM, len, rombanks);
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
bool megaduck_cart_slot_device::call_load()
|
||||
{
|
||||
if (m_cart)
|
||||
{
|
||||
UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom");
|
||||
UINT8 *ROM;
|
||||
|
||||
m_cart->rom_alloc(machine(), len);
|
||||
ROM = m_cart->get_rom_base();
|
||||
|
||||
if (software_entry() == NULL)
|
||||
fread(ROM, len);
|
||||
else
|
||||
memcpy(ROM, get_software_region("rom"), len);
|
||||
|
||||
// setup rom bank map based on real length, not header value
|
||||
m_cart->rom_map_setup(len);
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
call_unloadload
|
||||
-------------------------------------------------*/
|
||||
|
||||
void base_gb_cart_slot_device::call_unload()
|
||||
{
|
||||
if (m_cart->get_ram_size() && m_cart->get_has_battery())
|
||||
battery_save(m_cart->get_ram_base(), m_cart->get_ram_size());
|
||||
}
|
||||
|
||||
void base_gb_cart_slot_device::setup_ram(UINT8 banks)
|
||||
{
|
||||
m_cart->ram_alloc(machine(), banks * 0x2000);
|
||||
memset(m_cart->get_ram_base(), 0xff, m_cart->get_ram_size());
|
||||
m_cart->ram_map_setup(banks);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
call softlist load
|
||||
-------------------------------------------------*/
|
||||
|
||||
bool base_gb_cart_slot_device::call_softlist_load(char *swlist, char *swname, rom_entry *start_entry)
|
||||
{
|
||||
load_software_part_region(this, swlist, swname, start_entry );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// This fails to catch Mani 4-in-1 carts... even when they match this, then they have MBC1/3 in the internal header instead of MMM01...
|
||||
bool base_gb_cart_slot_device::get_mmm01_candidate(UINT8 *ROM, UINT32 len)
|
||||
{
|
||||
if (len < 0x8147)
|
||||
return FALSE;
|
||||
|
||||
static const UINT8 nintendo_logo[0x18] = {
|
||||
0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B,
|
||||
0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D,
|
||||
0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E
|
||||
};
|
||||
int bytes_matched = 0;
|
||||
for (int i = 0; i < 0x18; i++)
|
||||
{
|
||||
if (ROM[(len - 0x8000) + 0x104 + i] == nintendo_logo[i])
|
||||
bytes_matched++;
|
||||
}
|
||||
|
||||
if (bytes_matched == 0x18 && ROM[(len - 0x8000) + 0x147] >= 0x0b && ROM[(len - 0x8000) + 0x147] <= 0x0d)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int base_gb_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len)
|
||||
{
|
||||
int type = GB_MBC_NONE;
|
||||
|
||||
if (len < 0x014c)
|
||||
fatalerror("Checking header of a corrupted image!\n");
|
||||
|
||||
switch(ROM[0x0147])
|
||||
{
|
||||
case 0x00: type = GB_MBC_NONE; break;
|
||||
case 0x01: type = GB_MBC_MBC1; break;
|
||||
case 0x02: type = GB_MBC_MBC1; break;
|
||||
case 0x03: type = GB_MBC_MBC1; break;
|
||||
case 0x05: type = GB_MBC_MBC2; break;
|
||||
case 0x06: type = GB_MBC_MBC2; break;
|
||||
case 0x08: type = GB_MBC_NONE; break;
|
||||
case 0x09: type = GB_MBC_NONE; break;
|
||||
case 0x0b: type = GB_MBC_MMM01; break;
|
||||
case 0x0c: type = GB_MBC_MMM01; break;
|
||||
case 0x0d: type = GB_MBC_MMM01; break;
|
||||
case 0x0f: type = GB_MBC_MBC3; break;
|
||||
case 0x10: type = GB_MBC_MBC3; break;
|
||||
case 0x11: type = GB_MBC_MBC3; break;
|
||||
case 0x12: type = GB_MBC_MBC3; break;
|
||||
case 0x13: type = GB_MBC_MBC3; break;
|
||||
case 0x15: type = GB_MBC_MBC4; break;
|
||||
case 0x16: type = GB_MBC_MBC4; break;
|
||||
case 0x17: type = GB_MBC_MBC4; break;
|
||||
case 0x19: type = GB_MBC_MBC5; break;
|
||||
case 0x1a: type = GB_MBC_MBC5; break;
|
||||
case 0x1b: type = GB_MBC_MBC5; break;
|
||||
case 0x1c: type = GB_MBC_MBC5; break;
|
||||
case 0x1d: type = GB_MBC_MBC5; break;
|
||||
case 0x1e: type = GB_MBC_MBC5; break;
|
||||
case 0x20: type = GB_MBC_MBC6; break;
|
||||
case 0x22: type = GB_MBC_MBC7; break;
|
||||
case 0xbe: type = GB_MBC_NONE; break; /* used in Flash2Advance GB Bridge boot program */
|
||||
case 0xea: type = GB_MBC_YONGYONG; break; /* Found in Sonic 3D Blast 5 pirate */
|
||||
case 0xfc: type = GB_MBC_CAMERA; break;
|
||||
case 0xfd: type = GB_MBC_TAMA5; break;
|
||||
case 0xfe: type = GB_MBC_HUC3; break;
|
||||
case 0xff: type = GB_MBC_HUC1; break;
|
||||
}
|
||||
|
||||
// Check for special mappers
|
||||
if (type == GB_MBC_NONE)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0x0134; i <= 0x014c; i++)
|
||||
{
|
||||
count += ROM[i];
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
type = GB_MBC_WISDOM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we're dealing with a Korean variant of the MBC1 mapper */
|
||||
if (type == GB_MBC_MBC1)
|
||||
{
|
||||
if (ROM[0x13f] == 0x42 && ROM[0x140] == 0x32 && ROM[0x141] == 0x43 && ROM[0x142] == 0x4B)
|
||||
type = GB_MBC_MBC1_KOR;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
/*-------------------------------------------------
|
||||
get default card software
|
||||
-------------------------------------------------*/
|
||||
|
||||
const char * base_gb_cart_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
|
||||
{
|
||||
|
||||
if (open_image_file(options))
|
||||
{
|
||||
const char *slot_string = "rom";
|
||||
UINT32 len = core_fsize(m_file), offset = 0;
|
||||
UINT8 *ROM = global_alloc_array(UINT8, len);
|
||||
int type;
|
||||
|
||||
core_fread(m_file, ROM, len);
|
||||
|
||||
if ((len % 0x4000) == 512)
|
||||
offset = 512;
|
||||
|
||||
if (get_mmm01_candidate(ROM + offset, len - offset))
|
||||
offset += (len - 0x8000);
|
||||
|
||||
type = get_cart_type(ROM + offset, len - offset);
|
||||
slot_string = gb_get_slot(type);
|
||||
|
||||
//printf("type: %s\n", slot_string);
|
||||
global_free(ROM);
|
||||
clear();
|
||||
|
||||
return slot_string;
|
||||
}
|
||||
|
||||
return software_get_default_slot(config, options, this, "rom");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
read
|
||||
-------------------------------------------------*/
|
||||
|
||||
READ8_MEMBER(base_gb_cart_slot_device::read_rom)
|
||||
{
|
||||
if (m_cart)
|
||||
return m_cart->read_rom(space, offset);
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
READ8_MEMBER(base_gb_cart_slot_device::read_ram)
|
||||
{
|
||||
if (m_cart)
|
||||
return m_cart->read_ram(space, offset);
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
write
|
||||
-------------------------------------------------*/
|
||||
|
||||
WRITE8_MEMBER(base_gb_cart_slot_device::write_bank)
|
||||
{
|
||||
if (m_cart)
|
||||
m_cart->write_bank(space, offset, data);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(base_gb_cart_slot_device::write_ram)
|
||||
{
|
||||
if (m_cart)
|
||||
m_cart->write_ram(space, offset, data);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
Internal header logging
|
||||
-------------------------------------------------*/
|
||||
|
||||
void base_gb_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 len, UINT16 rom_banks)
|
||||
{
|
||||
static const char *const cart_types[] =
|
||||
{
|
||||
"ROM ONLY", "ROM+MBC1", "ROM+MBC1+RAM",
|
||||
"ROM+MBC1+RAM+BATTERY", "UNKNOWN", "ROM+MBC2",
|
||||
"ROM+MBC2+BATTERY", "UNKNOWN", "ROM+RAM",
|
||||
"ROM+RAM+BATTERY", "UNKNOWN", "ROM+MMM01",
|
||||
"ROM+MMM01+SRAM", "ROM+MMM01+SRAM+BATTERY", "UNKNOWN",
|
||||
"ROM+MBC3+TIMER+BATTERY", "ROM+MBC3+TIMER+RAM+BATTERY", "ROM+MBC3",
|
||||
"ROM+MBC3+RAM", "ROM+MBC3+RAM+BATTERY", "UNKNOWN",
|
||||
"UNKNOWN", "UNKNOWN", "UNKNOWN",
|
||||
"UNKNOWN", "ROM+MBC5", "ROM+MBC5+RAM",
|
||||
"ROM+MBC5+RAM+BATTERY", "ROM+MBC5+RUMBLE", "ROM+MBC5+RUMBLE+SRAM",
|
||||
"ROM+MBC5+RUMBLE+SRAM+BATTERY", "Pocket Camera", "Bandai TAMA5",
|
||||
/* Need heaps of unknowns here */
|
||||
"Hudson HuC-3", "Hudson HuC-1"
|
||||
};
|
||||
|
||||
// some company codes
|
||||
static const struct
|
||||
{
|
||||
UINT16 code;
|
||||
const char *name;
|
||||
}
|
||||
companies[] =
|
||||
{
|
||||
{0x3301, "Nintendo"},
|
||||
{0x7901, "Accolade"},
|
||||
{0xA400, "Konami"},
|
||||
{0x6701, "Ocean"},
|
||||
{0x5601, "LJN"},
|
||||
{0x9900, "ARC?"},
|
||||
{0x0101, "Nintendo"},
|
||||
{0x0801, "Capcom"},
|
||||
{0x0100, "Nintendo"},
|
||||
{0xBB01, "SunSoft"},
|
||||
{0xA401, "Konami"},
|
||||
{0xAF01, "Namcot?"},
|
||||
{0x4901, "Irem"},
|
||||
{0x9C01, "Imagineer"},
|
||||
{0xA600, "Kawada?"},
|
||||
{0xB101, "Nexoft"},
|
||||
{0x5101, "Acclaim"},
|
||||
{0x6001, "Titus"},
|
||||
{0xB601, "HAL"},
|
||||
{0x3300, "Nintendo"},
|
||||
{0x0B00, "Coconuts?"},
|
||||
{0x5401, "Gametek"},
|
||||
{0x7F01, "Kemco?"},
|
||||
{0xC001, "Taito"},
|
||||
{0xEB01, "Atlus"},
|
||||
{0xE800, "Asmik?"},
|
||||
{0xDA00, "Tomy?"},
|
||||
{0xB100, "ASCII?"},
|
||||
{0xEB00, "Atlus"},
|
||||
{0xC000, "Taito"},
|
||||
{0x9C00, "Imagineer"},
|
||||
{0xC201, "Kemco?"},
|
||||
{0xD101, "Sofel?"},
|
||||
{0x6101, "Virgin"},
|
||||
{0xBB00, "SunSoft"},
|
||||
{0xCE01, "FCI?"},
|
||||
{0xB400, "Enix?"},
|
||||
{0xBD01, "Imagesoft"},
|
||||
{0x0A01, "Jaleco?"},
|
||||
{0xDF00, "Altron?"},
|
||||
{0xA700, "Takara?"},
|
||||
{0xEE00, "IGS?"},
|
||||
{0x8300, "Lozc?"},
|
||||
{0x5001, "Absolute?"},
|
||||
{0xDD00, "NCS?"},
|
||||
{0xE500, "Epoch?"},
|
||||
{0xCB00, "VAP?"},
|
||||
{0x8C00, "Vic Tokai"},
|
||||
{0xC200, "Kemco?"},
|
||||
{0xBF00, "Sammy?"},
|
||||
{0x1800, "Hudson Soft"},
|
||||
{0xCA01, "Palcom/Ultra"},
|
||||
{0xCA00, "Palcom/Ultra"},
|
||||
{0xC500, "Data East?"},
|
||||
{0xA900, "Technos Japan?"},
|
||||
{0xD900, "Banpresto?"},
|
||||
{0x7201, "Broderbund?"},
|
||||
{0x7A01, "Triffix Entertainment?"},
|
||||
{0xE100, "Towachiki?"},
|
||||
{0x9300, "Tsuburava?"},
|
||||
{0xC600, "Tonkin House?"},
|
||||
{0xCE00, "Pony Canyon"},
|
||||
{0x7001, "Infogrames?"},
|
||||
{0x8B01, "Bullet-Proof Software?"},
|
||||
{0x5501, "Park Place?"},
|
||||
{0xEA00, "King Records?"},
|
||||
{0x5D01, "Tradewest?"},
|
||||
{0x6F01, "ElectroBrain?"},
|
||||
{0xAA01, "Broderbund?"},
|
||||
{0xC301, "SquareSoft"},
|
||||
{0x5201, "Activision?"},
|
||||
{0x5A01, "Bitmap Brothers/Mindscape"},
|
||||
{0x5301, "American Sammy"},
|
||||
{0x4701, "Spectrum Holobyte"},
|
||||
{0x1801, "Hudson Soft"},
|
||||
{0x0000, NULL}
|
||||
};
|
||||
static const int ramsize[8] = { 0, 2, 8, 32, 128, 64, 0, 0 };
|
||||
|
||||
// const char *prod;
|
||||
char soft[17];
|
||||
UINT32 tmp = 0;
|
||||
int csum = 0, i = 0;
|
||||
|
||||
strncpy(soft, (char *)&ROM[0x0134], 16);
|
||||
soft[16] = '\0';
|
||||
logerror("Cart Information\n");
|
||||
logerror("\tName: %s\n", soft);
|
||||
logerror("\tType: %s [0x%2X]\n", (ROM[0x0147] <= 32) ? cart_types[ROM[0x0147]] : "", ROM[0x0147] );
|
||||
logerror("\tGame Boy: %s\n", (ROM[0x0143] == 0xc0) ? "No" : "Yes" );
|
||||
logerror("\tSuper GB: %s [0x%2X]\n", (ROM[0x0146] == 0x03) ? "Yes" : "No", ROM[0x0146] );
|
||||
logerror("\tColor GB: %s [0x%2X]\n", (ROM[0x0143] == 0x80 || ROM[0x0143] == 0xc0) ? "Yes" : "No", ROM[0x0143] );
|
||||
logerror("\tROM Size: %d 16kB Banks [0x%2X]\n", rom_banks, ROM[0x0148]);
|
||||
logerror("\tRAM Size: %d kB [0x%2X]\n", ramsize[ROM[0x0149] & 0x07], ROM[0x0149]);
|
||||
logerror("\tLicense code: 0x%2X%2X\n", ROM[0x0145], ROM[0x0144] );
|
||||
tmp = (ROM[0x014b] << 8) + ROM[0x014a];
|
||||
for (i = 0; i < ARRAY_LENGTH(companies); i++)
|
||||
if (tmp == companies[i].code)
|
||||
break;
|
||||
logerror("\tManufacturer ID: 0x%2X", tmp);
|
||||
logerror(" [%s]\n", (companies[i].name) ? companies[i].name : "?");
|
||||
logerror("\tVersion Number: 0x%2X\n", ROM[0x014c]);
|
||||
logerror("\tComplement Check: 0x%2X\n", ROM[0x014d]);
|
||||
logerror("\tChecksum: 0x%2X\n", ((ROM[0x014e] << 8) + ROM[0x014f]));
|
||||
tmp = (ROM[0x0103] << 8) + ROM[0x0102];
|
||||
logerror("\tStart Address: 0x%2X\n", tmp);
|
||||
|
||||
// Additional checks
|
||||
if (rom_banks == 256)
|
||||
logerror("\nWarning loading cartridge: Unknown ROM size in header [0x%x].\n", ROM[0x0148]);
|
||||
|
||||
if ((len / 0x4000) != rom_banks)
|
||||
logerror("\nWarning loading cartridge: Filesize (0x%x) and reported ROM banks (0x%x) don't match.\n",
|
||||
len, rom_banks * 0x4000);
|
||||
/* Calculate and check checksum */
|
||||
tmp = (ROM[0x014e] << 8) + ROM[0x014f];
|
||||
for (int i = 0; i < len; i++)
|
||||
csum += ROM[i];
|
||||
csum -= (ROM[0x014e] + ROM[0x014f]);
|
||||
csum &= 0xffff;
|
||||
|
||||
if (csum != tmp)
|
||||
logerror("\nWarning loading cartridge: Checksum is wrong (Actual %x vs Internal %x)\n", csum, tmp);
|
||||
|
||||
}
|
195
src/mess/machine/gb_slot.h
Normal file
195
src/mess/machine/gb_slot.h
Normal file
@ -0,0 +1,195 @@
|
||||
#ifndef __GB_SLOT_H
|
||||
#define __GB_SLOT_H
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
/* PCB */
|
||||
enum
|
||||
{
|
||||
GB_MBC_NONE = 0, /* 32KB ROM - No memory bank controller */
|
||||
GB_MBC_MBC1, /* ~2MB ROM, 8KB RAM -or- 512KB ROM, 32KB RAM */
|
||||
GB_MBC_MBC2, /* 256KB ROM, 32KB RAM */
|
||||
GB_MBC_MMM01, /* ?? ROM, ?? RAM */
|
||||
GB_MBC_MBC3, /* 2MB ROM, 32KB RAM, RTC */
|
||||
GB_MBC_MBC4, /* ?? ROM, ?? RAM */
|
||||
GB_MBC_MBC5, /* 8MB ROM, 128KB RAM (32KB w/ Rumble) */
|
||||
GB_MBC_TAMA5, /* ?? ROM ?? RAM - What is this? */
|
||||
GB_MBC_HUC1, /* ?? ROM, ?? RAM - Hudson Soft Controller */
|
||||
GB_MBC_HUC3, /* ?? ROM, ?? RAM - Hudson Soft Controller */
|
||||
GB_MBC_MBC6, /* ?? ROM, 32KB SRAM */
|
||||
GB_MBC_MBC7, /* ?? ROM, ?? RAM */
|
||||
GB_MBC_WISDOM, /* ?? ROM, ?? RAM - Wisdom tree controller */
|
||||
GB_MBC_MBC1_KOR, /* 1MB ROM, ?? RAM - Korean MBC1 variant */
|
||||
GB_MBC_YONGYONG, /* ?? ROM, ?? RAM - Appears in Sonic 3D Blast 5 pirate */
|
||||
GB_MBC_LASAMA, /* ?? ROM, ?? RAM - Appears in La Sa Ma */
|
||||
GB_MBC_ATVRACIN,
|
||||
GB_MBC_CAMERA,
|
||||
GB_MBC_MEGADUCK, /* MEGADUCK style banking */
|
||||
GB_MBC_UNKNOWN /* Unknown mapper */
|
||||
};
|
||||
|
||||
|
||||
// ======================> gb_cart_interface
|
||||
|
||||
struct gb_cart_interface
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
// ======================> device_gb_cart_interface
|
||||
|
||||
class device_gb_cart_interface : public device_slot_card_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
device_gb_cart_interface(const machine_config &mconfig, device_t &device);
|
||||
virtual ~device_gb_cart_interface();
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; }
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank) {}
|
||||
virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; }
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram) {}
|
||||
|
||||
virtual void rom_alloc(running_machine &machine, UINT32 size);
|
||||
virtual void ram_alloc(running_machine &machine, UINT32 size);
|
||||
virtual UINT8* get_rom_base() { return m_rom; }
|
||||
virtual UINT8* get_ram_base() { return m_ram; }
|
||||
virtual UINT32 get_rom_size() { return m_rom_size; }
|
||||
virtual UINT32 get_ram_size() { return m_ram_size; }
|
||||
|
||||
virtual void rom_map_setup(UINT32 size);
|
||||
virtual void ram_map_setup(UINT8 banks);
|
||||
|
||||
virtual void set_has_timer(bool val) { has_timer = val; }
|
||||
virtual void set_has_rumble(bool val) { has_rumble = val; }
|
||||
virtual void set_has_battery(bool val) { has_battery = val; }
|
||||
virtual bool get_has_battery() { return has_battery; }
|
||||
|
||||
// internal state
|
||||
UINT8 *m_rom;
|
||||
UINT8 *m_ram;
|
||||
UINT32 m_rom_size;
|
||||
UINT32 m_ram_size;
|
||||
|
||||
// bankswitch variables
|
||||
// we access ROM/RAM banks through these bank maps
|
||||
// default accesses are:
|
||||
// 0x0000-0x3fff = rom_bank_map[m_latch_bank] (generally defaults to m_latch_bank = 0)
|
||||
// 0x4000-0x7fff = rom_bank_map[m_latch_bank2] (generally defaults to m_latch_bank2 = 1)
|
||||
// 0xa000-0xbfff = ram_bank_map[m_ram_bank] (generally defaults to m_ram_bank = 0)
|
||||
// suitable writes to 0x0000-0x7fff can then modify m_latch_bank/m_latch_bank2
|
||||
UINT8 rom_bank_map[512]; // 16K chunks of ROM
|
||||
UINT8 ram_bank_map[256]; // 16K chunks of RAM
|
||||
UINT8 m_ram_bank;
|
||||
UINT16 m_latch_bank, m_latch_bank2;
|
||||
|
||||
bool has_rumble, has_timer, has_battery;
|
||||
};
|
||||
|
||||
|
||||
// ======================> base_gb_cart_slot_device
|
||||
|
||||
class base_gb_cart_slot_device : public device_t,
|
||||
public gb_cart_interface,
|
||||
public device_image_interface,
|
||||
public device_slot_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
base_gb_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
|
||||
virtual ~base_gb_cart_slot_device();
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_config_complete();
|
||||
|
||||
// image-level overrides
|
||||
virtual bool call_load();
|
||||
virtual void call_unload();
|
||||
virtual bool call_softlist_load(char *swlist, char *swname, rom_entry *start_entry);
|
||||
|
||||
virtual int get_type() { return m_type; }
|
||||
virtual int get_cart_type(UINT8 *ROM, UINT32 len);
|
||||
virtual bool get_mmm01_candidate(UINT8 *ROM, UINT32 len);
|
||||
|
||||
virtual void setup_ram(UINT8 banks);
|
||||
virtual void internal_header_logging(UINT8 *ROM, UINT32 len, UINT16 report_rom_banks);
|
||||
|
||||
virtual iodevice_t image_type() const { return IO_CARTSLOT; }
|
||||
virtual bool is_readable() const { return 1; }
|
||||
virtual bool is_writeable() const { return 0; }
|
||||
virtual bool is_creatable() const { return 0; }
|
||||
virtual bool must_be_loaded() const { return 0; }
|
||||
virtual bool is_reset_on_load() const { return 0; }
|
||||
virtual const option_guide *create_option_guide() const { return NULL; }
|
||||
virtual const char *image_interface() const { return "gameboy_cart"; }
|
||||
virtual const char *file_extensions() const { return "bin,gb,gbc"; }
|
||||
|
||||
// slot interface overrides
|
||||
virtual const char * get_default_card_software(const machine_config &config, emu_options &options);
|
||||
|
||||
// reading and writing
|
||||
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_bank);
|
||||
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||
|
||||
// FIXME:
|
||||
// this should be private, but then there is some problem installing delegates in the driver...
|
||||
//private:
|
||||
|
||||
device_gb_cart_interface* m_cart;
|
||||
|
||||
int m_type;
|
||||
};
|
||||
|
||||
// ======================> gb_cart_slot_device
|
||||
|
||||
class gb_cart_slot_device : public base_gb_cart_slot_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
gb_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
};
|
||||
|
||||
|
||||
// ======================> megaduck_cart_slot_device
|
||||
|
||||
class megaduck_cart_slot_device : public base_gb_cart_slot_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
megaduck_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// image-level overrides
|
||||
virtual bool call_load();
|
||||
virtual const char *image_interface() const { return "megaduck_cart"; }
|
||||
virtual const char *file_extensions() const { return "bin"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type GB_CART_SLOT;
|
||||
extern const device_type MEGADUCK_CART_SLOT;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_GB_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot,_def_inp) \
|
||||
MCFG_DEVICE_ADD(_tag, GB_CART_SLOT, 0) \
|
||||
MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
|
||||
|
||||
#define MCFG_MEGADUCK_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot,_def_inp) \
|
||||
MCFG_DEVICE_ADD(_tag, MEGADUCK_CART_SLOT, 0) \
|
||||
MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
|
||||
|
||||
|
||||
#endif
|
@ -1421,6 +1421,9 @@ $(MESSOBJ)/nintendo.a: \
|
||||
$(MESS_AUDIO)/gb.o \
|
||||
$(MESS_VIDEO)/gb.o \
|
||||
$(MESS_MACHINE)/gb.o \
|
||||
$(MESS_MACHINE)/gb_slot.o \
|
||||
$(MESS_MACHINE)/gb_rom.o \
|
||||
$(MESS_MACHINE)/gb_mbc.o \
|
||||
$(MESS_DRIVERS)/gb.o \
|
||||
$(MESS_MACHINE)/pokemini.o \
|
||||
$(MESS_DRIVERS)/pokemini.o \
|
||||
@ -1627,12 +1630,12 @@ $(MESSOBJ)/sanyo.a: \
|
||||
$(MESSOBJ)/sega.a: \
|
||||
$(MESS_DRIVERS)/sg1000.o \
|
||||
$(MESS_MACHINE)/md_slot.o \
|
||||
$(MESS_MACHINE)/md_rom.o \
|
||||
$(MESS_MACHINE)/md_sk.o \
|
||||
$(MESS_MACHINE)/md_eeprom.o \
|
||||
$(MESS_MACHINE)/md_jcart.o \
|
||||
$(MESS_MACHINE)/md_stm95.o \
|
||||
$(MESS_MACHINE)/megasvp.o \
|
||||
$(MESS_MACHINE)/md_rom.o \
|
||||
$(MESS_MACHINE)/md_sk.o \
|
||||
$(MESS_MACHINE)/md_eeprom.o \
|
||||
$(MESS_MACHINE)/md_jcart.o \
|
||||
$(MESS_MACHINE)/md_stm95.o \
|
||||
$(MESS_MACHINE)/megasvp.o \
|
||||
$(MESS_DRIVERS)/megadriv.o \
|
||||
$(MESS_DRIVERS)/dccons.o \
|
||||
$(MAME_MACHINE)/gdrom.o \
|
||||
|
@ -132,7 +132,7 @@ PALETTE_INIT_MEMBER(gb_state,gbc)
|
||||
m_lcd.cgb_spal[ii] = 0;
|
||||
}
|
||||
|
||||
PALETTE_INIT_MEMBER(gb_state,megaduck)
|
||||
PALETTE_INIT_MEMBER(megaduck_state,megaduck)
|
||||
{
|
||||
int ii;
|
||||
for( ii = 0; ii < 4; ii++)
|
||||
|
Loading…
Reference in New Issue
Block a user