(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:
Fabio Priuli 2013-02-07 20:41:05 +00:00
parent 095eaa68e8
commit 312abbed4e
14 changed files with 5629 additions and 1384 deletions

6
.gitattributes vendored
View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -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 \

View File

@ -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++)