diff options
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 |
commit | d131f7fa0cd0255b1a33778d1b51d1bb967fb53a (patch) | |
tree | 3021094c998780a9c4b442173889a2dbc46a20e4 /src/emu/bus/gba/gba_slot.c | |
parent | fe36f872390885a181844708e6459d4d85f1c2fc (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.c | 483 |
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()); + } +} |