summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/bus/gba/gba_slot.c
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2014-03-10 14:00:01 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2014-03-10 14:00:01 +0000
commitd131f7fa0cd0255b1a33778d1b51d1bb967fb53a (patch)
tree3021094c998780a9c4b442173889a2dbc46a20e4 /src/emu/bus/gba/gba_slot.c
parentfe36f872390885a181844708e6459d4d85f1c2fc (diff)
Moved rest of console slot devices to bus folder (nw)
Diffstat (limited to 'src/emu/bus/gba/gba_slot.c')
-rw-r--r--src/emu/bus/gba/gba_slot.c483
1 files changed, 483 insertions, 0 deletions
diff --git a/src/emu/bus/gba/gba_slot.c b/src/emu/bus/gba/gba_slot.c
new file mode 100644
index 00000000000..05c64325686
--- /dev/null
+++ b/src/emu/bus/gba/gba_slot.c
@@ -0,0 +1,483 @@
+/***********************************************************************************************************
+
+
+ Game Boy Advance cart emulation
+ (through slot devices)
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "gba_slot.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type GBA_CART_SLOT = &device_creator<gba_cart_slot_device>;
+
+//**************************************************************************
+// GBA cartridges Interface
+//**************************************************************************
+
+//-------------------------------------------------
+// device_gba_cart_interface - constructor
+//-------------------------------------------------
+
+device_gba_cart_interface::device_gba_cart_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device),
+ m_rom(NULL),
+ m_nvram(NULL),
+ m_rom_size(0),
+ m_nvram_size(0)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_gba_cart_interface - destructor
+//-------------------------------------------------
+
+device_gba_cart_interface::~device_gba_cart_interface()
+{
+}
+
+//-------------------------------------------------
+// nvram_alloc - alloc the space for the ram
+//-------------------------------------------------
+
+void device_gba_cart_interface::nvram_alloc(running_machine &machine, UINT32 size)
+{
+ if (m_nvram == NULL)
+ {
+ m_nvram = auto_alloc_array_clear(machine, UINT32, size/sizeof(UINT32));
+ m_nvram_size = size;
+ state_save_register_item_pointer(machine, "GBA_CART", this->device().tag(), 0, m_nvram, m_nvram_size/sizeof(UINT32));
+ }
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// gba_cart_slot_device - constructor
+//-------------------------------------------------
+gba_cart_slot_device::gba_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, GBA_CART_SLOT, "Game Boy Advance Cartridge Slot", tag, owner, clock, "gba_cart_slot", __FILE__),
+ device_image_interface(mconfig, *this),
+ device_slot_interface(mconfig, *this),
+ m_type(GBA_STD)
+{
+}
+
+
+//-------------------------------------------------
+// gba_cart_slot_device - destructor
+//-------------------------------------------------
+
+gba_cart_slot_device::~gba_cart_slot_device()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void gba_cart_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_gba_cart_interface *>(get_card_device());
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void gba_cart_slot_device::device_config_complete()
+{
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// GBA PCB
+//-------------------------------------------------
+
+struct gba_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 gba_slot slot_list[] =
+{
+ { GBA_STD, "gba_rom" },
+ { GBA_SRAM, "gba_sram" },
+ { GBA_EEPROM, "gba_eeprom" },
+ { GBA_EEPROM4, "gba_eeprom_4k" },
+ { GBA_EEPROM64, "gba_eeprom_64k" },
+ { GBA_FLASH, "gba_flash" },
+ { GBA_FLASH512, "gba_flash_512" },
+ { GBA_FLASH1M, "gba_flash_1m" },
+};
+
+static int gba_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 *gba_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 "gba_rom";
+}
+
+
+/*-------------------------------------------------
+ call load
+ -------------------------------------------------*/
+
+bool gba_cart_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ UINT8 *ROM = (UINT8 *)m_cart->get_rom_base();
+ UINT32 cart_size;
+
+ if (software_entry() == NULL)
+ {
+ cart_size = length();
+ if (cart_size > 0x2000000)
+ {
+ seterror(IMAGE_ERROR_UNSPECIFIED, "Attempted loading a cart larger than 32MB");
+ return IMAGE_INIT_FAIL;
+ }
+ fread(ROM, cart_size);
+ m_cart->set_rom_size(cart_size); // we store the actual game size...
+
+ m_type = get_cart_type(ROM, cart_size);
+ }
+ else
+ {
+ const char *pcb_name = get_feature("slot");
+
+ cart_size = get_software_region_length("rom");
+ if (cart_size > 0x2000000)
+ {
+ seterror(IMAGE_ERROR_UNSPECIFIED, "Attempted loading a cart larger than 32MB");
+ return IMAGE_INIT_FAIL;
+ }
+ memcpy(ROM, get_software_region("rom"), cart_size);
+ m_cart->set_rom_size(cart_size); // we store the actual game size...
+
+ if (pcb_name)
+ m_type = gba_get_pcb_id(pcb_name);
+
+ //printf("Type: %s\n", gba_get_slot(m_type));
+
+ mame_printf_info("GBA: Detected (XML) %s\n", pcb_name ? pcb_name : "NONE");
+ }
+
+ if (m_type == GBA_SRAM)
+ m_cart->nvram_alloc(machine(), 0x10000);
+
+ // mirror the ROM
+ switch (cart_size)
+ {
+ case 2 * 1024 * 1024:
+ memcpy(ROM + 0x200000, ROM, 0x200000);
+ // intentional fall-through
+ case 4 * 1024 * 1024:
+ memcpy(ROM + 0x400000, ROM, 0x400000);
+ // intentional fall-through
+ case 8 * 1024 * 1024:
+ memcpy(ROM + 0x800000, ROM, 0x800000);
+ // intentional fall-through
+ case 16 * 1024 * 1024:
+ memcpy(ROM + 0x1000000, ROM, 0x1000000);
+ break;
+ }
+
+ if (m_cart->get_nvram_size())
+ battery_load(m_cart->get_nvram_base(), m_cart->get_nvram_size(), 0x00);
+
+ return IMAGE_INIT_PASS;
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/*-------------------------------------------------
+ call_unload
+ -------------------------------------------------*/
+
+void gba_cart_slot_device::call_unload()
+{
+ if (m_cart && m_cart->get_nvram_size())
+ battery_save(m_cart->get_nvram_base(), m_cart->get_nvram_size());
+}
+
+
+
+/*-------------------------------------------------
+ call softlist load
+ -------------------------------------------------*/
+
+bool gba_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;
+}
+
+
+
+/*-------------------------------------------------
+ get_cart_type - code to detect NVRAM type from
+ fullpath
+ -------------------------------------------------*/
+
+INLINE astring gba_chip_string( UINT32 chip )
+{
+ astring str;
+ if (chip == 0) str += "NONE ";
+ if (chip & GBA_CHIP_EEPROM) str += "EEPROM ";
+ if (chip & GBA_CHIP_EEPROM_64K) str += "EEPROM_64K ";
+ if (chip & GBA_CHIP_EEPROM_4K) str += "EEPROM_4K ";
+ if (chip & GBA_CHIP_FLASH) str += "FLASH ";
+ if (chip & GBA_CHIP_FLASH_1M) str += "FLASH_1M ";
+ if (chip & GBA_CHIP_FLASH_512) str += "FLASH_512 ";
+ if (chip & GBA_CHIP_SRAM) str += "SRAM ";
+ if (chip & GBA_CHIP_RTC) str += "RTC ";
+ return str.trimspace();
+}
+
+
+INLINE int gba_chip_has_conflict( UINT32 chip )
+{
+ int count1 = 0, count2 = 0;
+ if (chip & GBA_CHIP_EEPROM) count1++;
+ if (chip & GBA_CHIP_EEPROM_4K) count1++;
+ if (chip & GBA_CHIP_EEPROM_64K) count1++;
+ if (chip & GBA_CHIP_FLASH) count2++;
+ if (chip & GBA_CHIP_FLASH_1M) count2++;
+ if (chip & GBA_CHIP_FLASH_512) count2++;
+ if (chip & GBA_CHIP_SRAM) count2++;
+ return (count1 + count2) > 1; // if EEPROM + FLASH or EEPROM + SRAM carts exist, change to "(count1 > 1) || (count2 > 1)"
+}
+
+
+int gba_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len)
+{
+ UINT32 chip = 0;
+ int type = GBA_STD;
+
+ // first detect nvram type based on strings inside the file
+ for (int i = 0; i < len; i++)
+ {
+ if (!memcmp(&ROM[i], "EEPROM_V", 8))
+ chip |= GBA_CHIP_EEPROM; // should be either GBA_CHIP_EEPROM_4K or GBA_CHIP_EEPROM_64K, but it is not yet possible to automatically detect which one
+ else if ((!memcmp(&ROM[i], "SRAM_V", 6)) || (!memcmp(&ROM[i], "SRAM_F_V", 8))) // || (!memcmp(&data[i], "ADVANCEWARS", 11))) //advance wars 1 & 2 has SRAM, but no "SRAM_" string can be found inside the ROM space
+ chip |= GBA_CHIP_SRAM;
+ else if (!memcmp(&ROM[i], "FLASH1M_V", 9))
+ chip |= GBA_CHIP_FLASH_1M;
+ else if (!memcmp(&ROM[i], "FLASH512_V", 10))
+ chip |= GBA_CHIP_FLASH_512;
+ else if (!memcmp(&ROM[i], "FLASH_V", 7))
+ chip |= GBA_CHIP_FLASH;
+ else if (!memcmp(&ROM[i], "SIIRTC_V", 8))
+ chip |= GBA_CHIP_RTC;
+ }
+ mame_printf_info("GBA: Detected (ROM) %s\n", gba_chip_string(chip).cstr());
+
+ // fix for games which return more than one kind of chip: either it is one of the known titles, or we default to no battery
+ if (gba_chip_has_conflict(chip))
+ {
+ char game_code[5] = { 0 };
+ bool resolved = FALSE;
+
+ if (len >= 0xac + 4)
+ memcpy(game_code, ROM + 0xac, 4);
+
+ mame_printf_info("GBA: Game Code \"%s\"\n", game_code);
+
+ chip &= ~(GBA_CHIP_EEPROM | GBA_CHIP_EEPROM_4K | GBA_CHIP_EEPROM_64K | GBA_CHIP_FLASH | GBA_CHIP_FLASH_1M | GBA_CHIP_FLASH_512 | GBA_CHIP_SRAM);
+
+ // search if it is one of the known titles with NVRAM conflicts
+ for (int i = 0; i < sizeof(gba_chip_fix_conflict_list) / sizeof(gba_chip_fix_conflict_item); i++)
+ {
+ const gba_chip_fix_conflict_item *item = &gba_chip_fix_conflict_list[i];
+ if (!strcmp(game_code, item->game_code))
+ {
+ chip |= item->chip;
+ resolved = TRUE;
+ break;
+ }
+ }
+ if (!resolved)
+ mame_printf_warning("GBA: NVRAM is disabled because multiple NVRAM chips were detected!\n");
+ }
+
+ // fix for games which are known to require an eeprom with 14-bit addressing (64 kbit)
+ if (chip & GBA_CHIP_EEPROM)
+ {
+ char game_code[5] = { 0 };
+
+ if (len >= 0xac + 4)
+ memcpy(game_code, ROM + 0xac, 4);
+
+ mame_printf_info("GBA: Game Code \"%s\"\n", game_code);
+
+ for (int i = 0; i < sizeof(gba_chip_fix_eeprom_list) / sizeof(gba_chip_fix_eeprom_item); i++)
+ {
+ const gba_chip_fix_eeprom_item *item = &gba_chip_fix_eeprom_list[i];
+ if (!strcmp(game_code, item->game_code))
+ {
+ chip = (chip & ~GBA_CHIP_EEPROM) | GBA_CHIP_EEPROM_64K;
+ break;
+ }
+ }
+ }
+
+ if (type & GBA_CHIP_RTC)
+ {
+ mame_printf_verbose("game has RTC - not emulated at the moment\n");
+ chip &= ~GBA_CHIP_RTC;
+ }
+
+ mame_printf_info("GBA: Emulate %s\n", gba_chip_string(chip).cstr());
+
+ switch (chip)
+ {
+ case GBA_CHIP_SRAM:
+ type = GBA_SRAM;
+ break;
+ case GBA_CHIP_EEPROM:
+ type = GBA_EEPROM;
+ break;
+ case GBA_CHIP_EEPROM_4K:
+ type = GBA_EEPROM4;
+ break;
+ case GBA_CHIP_EEPROM_64K:
+ type = GBA_EEPROM64;
+ break;
+ case GBA_CHIP_FLASH:
+ type = GBA_FLASH;
+ break;
+ case GBA_CHIP_FLASH_512:
+ type = GBA_FLASH512;
+ break;
+ case GBA_CHIP_FLASH_1M:
+ type = GBA_FLASH1M;
+ break;
+ default:
+ break;
+ }
+
+ return type;
+}
+/*-------------------------------------------------
+ get default card software
+ -------------------------------------------------*/
+
+const char * gba_cart_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ if (open_image_file(options))
+ {
+ const char *slot_string = "gba_rom";
+ UINT32 len = core_fsize(m_file);
+ UINT8 *ROM = global_alloc_array(UINT8, len);
+ int type;
+
+ core_fread(m_file, ROM, len);
+
+ type = get_cart_type(ROM, len);
+ slot_string = gba_get_slot(type);
+
+ //printf("type: %s\n", slot_string);
+ global_free(ROM);
+ clear();
+
+ return slot_string;
+ }
+
+ return software_get_default_slot(config, options, this, "gba_rom");
+}
+
+/*-------------------------------------------------
+ read
+ -------------------------------------------------*/
+
+READ32_MEMBER(gba_cart_slot_device::read_rom)
+{
+ if (m_cart)
+ return m_cart->read_rom(space, offset, mem_mask);
+ else
+ return 0xffffffff;
+}
+
+READ32_MEMBER(gba_cart_slot_device::read_ram)
+{
+ if (m_cart)
+ return m_cart->read_ram(space, offset, mem_mask);
+ else
+ return 0xffffffff;
+}
+
+
+/*-------------------------------------------------
+ write
+ -------------------------------------------------*/
+
+WRITE32_MEMBER(gba_cart_slot_device::write_ram)
+{
+ if (m_cart)
+ m_cart->write_ram(space, offset, data, mem_mask);
+}
+
+
+/*-------------------------------------------------
+ Internal header logging
+ -------------------------------------------------*/
+
+void gba_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 len)
+{
+}
+
+
+/*-------------------------------------------------
+ Install ROM - directly point system address map
+ to the cart ROM region so to avoid the memory
+ system additional load
+ -------------------------------------------------*/
+
+void gba_cart_slot_device::install_rom()
+{
+ if (m_cart)
+ {
+ astring tempstring;
+ address_space &space = machine().device<cpu_device>("maincpu")->space(AS_PROGRAM);
+ space.install_read_bank(0x08000000, 0x09ffffff, 0, 0, "rom1");
+ space.install_read_bank(0x0a000000, 0x0bffffff, 0, 0, "rom2");
+ space.install_read_bank(0x0c000000, 0x0cffffff, 0, 0, "rom3");
+ machine().root_device().membank("rom1")->set_base(machine().root_device().memregion(m_cart->device().subtag(tempstring, "cartridge"))->base());
+ machine().root_device().membank("rom2")->set_base(machine().root_device().memregion(m_cart->device().subtag(tempstring, "cartridge"))->base());
+ machine().root_device().membank("rom3")->set_base(machine().root_device().memregion(m_cart->device().subtag(tempstring, "cartridge"))->base());
+ }
+}