summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/gameboy/gb_slot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/gameboy/gb_slot.cpp')
-rw-r--r--src/devices/bus/gameboy/gb_slot.cpp834
1 files changed, 0 insertions, 834 deletions
diff --git a/src/devices/bus/gameboy/gb_slot.cpp b/src/devices/bus/gameboy/gb_slot.cpp
deleted file mode 100644
index 31d11e59dcf..00000000000
--- a/src/devices/bus/gameboy/gb_slot.cpp
+++ /dev/null
@@ -1,834 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Fabio Priuli, Wilbert Pol
-/***********************************************************************************************************
-
-
- 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 "gb_slot.h"
-
-//**************************************************************************
-// GLOBAL VARIABLES
-//**************************************************************************
-
-DEFINE_DEVICE_TYPE(GB_CART_SLOT, gb_cart_slot_device, "gb_cart_slot", "Game Boy Cartridge Slot")
-DEFINE_DEVICE_TYPE(MEGADUCK_CART_SLOT, megaduck_cart_slot_device, "megaduck_cart_slot", "Megaduck Cartridge Slot")
-
-//**************************************************************************
-// GB cartridges Interface
-//**************************************************************************
-
-//-------------------------------------------------
-// device_gb_cart_interface - constructor
-//-------------------------------------------------
-
-device_gb_cart_interface::device_gb_cart_interface(const machine_config &mconfig, device_t &device) :
- device_interface(device, "gbcart"),
- m_rom(nullptr),
- m_rom_size(0), m_ram_bank(0), m_latch_bank(0), m_latch_bank2(0),
- has_rumble(false),
- has_timer(false),
- has_battery(false)
-{
-}
-
-
-//-------------------------------------------------
-// ~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(uint32_t size, const char *tag)
-{
- if (m_rom == nullptr)
- {
- m_rom = device().machine().memory().region_alloc(std::string(tag).append(GBSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base();
- m_rom_size = size;
- }
-}
-
-
-//-------------------------------------------------
-// ram_alloc - alloc the space for the ram
-//-------------------------------------------------
-
-void device_gb_cart_interface::ram_alloc(uint32_t size)
-{
- m_ram.resize(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_t 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_t 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
-//**************************************************************************
-
-//-------------------------------------------------
-// gb_cart_slot_device_base - constructor
-//-------------------------------------------------
-gb_cart_slot_device_base::gb_cart_slot_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, type, tag, owner, clock),
- device_image_interface(mconfig, *this),
- device_single_card_slot_interface<device_gb_cart_interface>(mconfig, *this),
- m_type(GB_MBC_UNKNOWN),
- m_cart(nullptr)
-{
-}
-
-gb_cart_slot_device::gb_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- gb_cart_slot_device_base(mconfig, GB_CART_SLOT, tag, owner, clock)
-{
-}
-
-megaduck_cart_slot_device::megaduck_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- gb_cart_slot_device_base(mconfig, MEGADUCK_CART_SLOT, tag, owner, clock)
-{
-}
-
-//-------------------------------------------------
-// gb_cart_slot_device_base - destructor
-//-------------------------------------------------
-
-gb_cart_slot_device_base::~gb_cart_slot_device_base()
-{
-}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void gb_cart_slot_device_base::device_start()
-{
- m_cart = get_card_device();
-}
-
-
-//-------------------------------------------------
-// GB 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_COL, "rom_mbc1col" },
- { 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_M161, "rom_m161" },
- { 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_SACHEN1, "rom_sachen1" },
- { GB_MBC_SACHEN2, "rom_sachen2" },
- { GB_MBC_WISDOM, "rom_wisdom" },
- { GB_MBC_YONGYONG, "rom_yong" },
- { GB_MBC_LASAMA, "rom_lasama" },
- { GB_MBC_ATVRACIN, "rom_atvrac" },
- { GB_MBC_SINTAX, "rom_sintax" },
- { GB_MBC_CHONGWU, "rom_chong" },
- { GB_MBC_LICHENG, "rom_licheng" },
- { GB_MBC_DIGIMON, "rom_digimon" },
- { GB_MBC_ROCKMAN8, "rom_rock8" },
- { GB_MBC_SM3SP, "rom_sm3sp" },
- { GB_MBC_UNK01, "rom_unk01" },
- { GB_MBC_DKONG5, "rom_dkong5" },
- { GB_MBC_CAMERA, "rom_camera" },
- { GB_MBC_188IN1, "rom_188in1" }
-};
-
-static int gb_get_pcb_id(const char *slot)
-{
- for (auto & elem : slot_list)
- {
- if (!core_stricmp(elem.slot_option, slot))
- return elem.pcb_id;
- }
-
- return GB_MBC_NONE;
-}
-
-static const char *gb_get_slot(int type)
-{
- for (auto & elem : slot_list)
- {
- if (elem.pcb_id == type)
- return elem.slot_option;
- }
-
- return "rom";
-}
-
-
-/*-------------------------------------------------
- call load
- -------------------------------------------------*/
-
-
-image_init_result gb_cart_slot_device_base::call_load()
-{
- if (m_cart)
- {
- uint32_t offset;
- uint32_t len = !loaded_through_softlist() ? length() : get_software_region_length("rom");
- uint8_t *ROM;
- int rambanks = 0;
-
- // From fullpath, check for presence of a header and skip it + check filesize is valid
- if (!loaded_through_softlist())
- {
- 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_result::FAIL;
- }
- }
-
- m_cart->rom_alloc(len, tag());
- ROM = m_cart->get_rom_base();
-
- if (!loaded_through_softlist())
- 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;
-
- if (loaded_through_softlist())
- m_type = gb_get_pcb_id(get_feature("slot") ? get_feature("slot") : "rom");
- else
- m_type = get_cart_type(ROM + offset, len - offset);
-
- // setup additional mask/shift for MBC1 variants:
- // a few game collections use the same mapper with slightly
- // different lines connection with the ROM / RAM
- if (m_type == GB_MBC_MBC1 || m_type == GB_MBC_188IN1)
- m_cart->set_additional_wirings(0x1f, 0);
- if (m_type == GB_MBC_MBC1_COL)
- m_cart->set_additional_wirings(0x0f, -1);
-
- // setup RAM/NVRAM/RTC/RUMBLE
- if (loaded_through_softlist())
- {
- // from softlist we only rely on xml
- if (get_software_region("ram"))
- rambanks = get_software_region_length("ram") / 0x2000;
-
- if (get_software_region("nvram"))
- {
- m_cart->set_has_battery(true);
- rambanks = get_software_region_length("nvram") / 0x2000;
- }
-
- if (get_feature("rumble"))
- {
- if (!core_stricmp(get_feature("rumble"), "yes"))
- m_cart->set_has_rumble(true);
- }
-
- if (get_feature("rtc"))
- {
- if (!core_stricmp(get_feature("rtc"), "yes"))
- m_cart->set_has_timer(true);
- }
- }
- else
- {
- // from fullpath we rely on header
- 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;
- }
-
- 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 (m_type == GB_MBC_MBC2 || m_type == GB_MBC_MBC7)
- rambanks = 1;
- }
-
- // setup rom bank map based on real length, not header value
- m_cart->rom_map_setup(len);
-
- 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(m_type));
-
- internal_header_logging(ROM + offset, len);
-
- return image_init_result::PASS;
- }
-
- return image_init_result::PASS;
-}
-
-image_init_result megaduck_cart_slot_device::call_load()
-{
- if (m_cart)
- {
- uint32_t len = !loaded_through_softlist() ? length() : get_software_region_length("rom");
-
- m_cart->rom_alloc(len, tag());
-
- if (!loaded_through_softlist())
- fread(m_cart->get_rom_base(), len);
- else
- memcpy(m_cart->get_rom_base(), 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_result::PASS;
- }
-
- return image_init_result::PASS;
-}
-
-
-/*-------------------------------------------------
- call_unload
- -------------------------------------------------*/
-
-void gb_cart_slot_device_base::call_unload()
-{
- if (m_cart && m_cart->get_ram_base() && m_cart->get_ram_size() && m_cart->get_has_battery())
- battery_save(m_cart->get_ram_base(), m_cart->get_ram_size());
-}
-
-void gb_cart_slot_device_base::setup_ram(uint8_t banks)
-{
- m_cart->ram_alloc(banks * 0x2000);
- memset(m_cart->get_ram_base(), 0xff, m_cart->get_ram_size());
- m_cart->ram_map_setup(banks);
-}
-
-
-
-// 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 gb_cart_slot_device_base::get_mmm01_candidate(const uint8_t *ROM, uint32_t len)
-{
- if (len < 0x8147)
- return false;
-
- static const uint8_t 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;
-}
-
-bool gb_cart_slot_device_base::is_mbc1col_game(const uint8_t *ROM, uint32_t len)
-{
- const uint8_t name_length = 0x10u;
- static const uint8_t internal_names[][name_length + 1] = {
- /* Bomberman Collection */
- "BOMCOL\0\0\0\0\0\0\0\0\0\0",
- /* Bomberman Selection */
- "BOMSEL\0\0\0\0\0B2CK\xC0",
- /* Genjin Collection */
- "GENCOL\0\0\0\0\0\0\0\0\0\0",
- /* Momotarou Collection */
- "MOMOCOL\0\0\0\0\0\0\0\0\0",
- /* Mortal Kombat I & II Japan */
- "MORTALKOMBAT DUO",
- /* Mortal Kombat I & II US */
- "MORTALKOMBATI&II",
- /* Super Chinese Land 1,2,3' */
- "SUPERCHINESE 123"
- };
-
- const uint8_t rows = ARRAY_LENGTH(internal_names);
-
- for (uint8_t i = 0x00; i < rows; ++i) {
- if (0 == memcmp(&ROM[0x134], &internal_names[i][0], name_length))
- return true;
- }
-
- return false;
-}
-
-int gb_cart_slot_device_base::get_cart_type(const uint8_t *ROM, uint32_t 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 for some unlicensed games
- //if (type == GB_MBC_MBC5)
- if (len >= 0x184 + 0x30)
- {
- int count = 0;
- for (int i = 0x0184; i < 0x0184 + 0x30; i++)
- {
- count += ROM[i];
- }
-
- if (count == 4876)
- {
-// printf("Li Cheng %d\n", count);
- type = GB_MBC_LICHENG;
- }
- if ((count == 4138 || count == 4125) && len >= 2097152)
- {
- // All known sintax (raw) dumps are at least 2097152 bytes in size
- // Zhi Huan Wang uses 4138
- // most sintax use 4125
-// printf("Sintax %d!\n", count);
- type = GB_MBC_SINTAX;
- }
- }
-
- /* Check if we're dealing with the multigame variant of the MBC1 mapper */
- if (type == GB_MBC_MBC1 && is_mbc1col_game(ROM, len))
- type = GB_MBC_MBC1_COL;
-
- return type;
-}
-
-/*-------------------------------------------------
- get default card software
- -------------------------------------------------*/
-
-std::string gb_cart_slot_device_base::get_default_card_software(get_default_card_software_hook &hook) const
-{
- if (hook.image_file())
- {
- const char *slot_string;
- uint32_t len = hook.image_file()->size(), offset = 0;
- std::vector<uint8_t> rom(len);
- int type;
-
- hook.image_file()->read(&rom[0], 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);
-
- return std::string(slot_string);
- }
-
- return software_get_default_slot("rom");
-}
-
-
-std::string megaduck_cart_slot_device::get_default_card_software(get_default_card_software_hook &hook) const
-{
- if (hook.image_file())
- return std::string("rom");
-
- return software_get_default_slot("rom");
-}
-
-
-
-/*-------------------------------------------------
- read
- -------------------------------------------------*/
-
-uint8_t gb_cart_slot_device_base::read_rom(offs_t offset)
-{
- if (m_cart)
- return m_cart->read_rom(offset);
- else
- return 0xff;
-}
-
-uint8_t gb_cart_slot_device_base::read_ram(offs_t offset)
-{
- if (m_cart)
- return m_cart->read_ram(offset);
- else
- return 0xff;
-}
-
-
-/*-------------------------------------------------
- write
- -------------------------------------------------*/
-
-void gb_cart_slot_device_base::write_bank(offs_t offset, uint8_t data)
-{
- if (m_cart)
- m_cart->write_bank(offset, data);
-}
-
-void gb_cart_slot_device_base::write_ram(offs_t offset, uint8_t data)
-{
- if (m_cart)
- m_cart->write_ram(offset, data);
-}
-
-
-/*-------------------------------------------------
- Internal header logging
- -------------------------------------------------*/
-
-void gb_cart_slot_device_base::internal_header_logging(uint8_t *ROM, uint32_t len)
-{
- 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_t 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"}
- };
- static const int ramsize[8] = { 0, 2, 8, 32, 128, 64, 0, 0 };
-
- char soft[17];
- uint32_t tmp;
- int csum = 0, i = 0;
- int rom_banks;
-
- switch (ROM[0x0148])
- {
- case 0x52:
- rom_banks = 72;
- break;
- case 0x53:
- rom_banks = 80;
- break;
- case 0x54:
- rom_banks = 96;
- break;
- case 0x00: case 0x01: case 0x02: case 0x03:
- case 0x04: case 0x05: case 0x06: case 0x07:
- rom_banks = 2 << ROM[0x0148];
- break;
- default:
- rom_banks = 256;
- break;
- }
-
- strncpy(soft, (char *)&ROM[0x0134], 16);
- soft[16] = '\0';
- logerror("Cart Information\n");
- logerror("\tName: %s\n", soft);
- logerror("\tType: %s [0x%02X]\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%02X]\n", (ROM[0x0146] == 0x03) ? "Yes" : "No", ROM[0x0146] );
- logerror("\tColor GB: %s [0x%02X]\n", (ROM[0x0143] == 0x80 || ROM[0x0143] == 0xc0) ? "Yes" : "No", ROM[0x0143] );
- logerror("\tROM Size: %d 16kB Banks [0x%02X]\n", rom_banks, ROM[0x0148]);
- logerror("\tRAM Size: %d kB [0x%02X]\n", ramsize[ROM[0x0149] & 0x07], ROM[0x0149]);
- logerror("\tLicense code: 0x%02X%02X\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%02X [%s]\n", tmp, (i < ARRAY_LENGTH(companies)) ? companies[i].name : "?");
- logerror("\tVersion Number: 0x%02X\n", ROM[0x014c]);
- logerror("\tComplement Check: 0x%02X\n", ROM[0x014d]);
- logerror("\tChecksum: 0x%04X\n", ((ROM[0x014e] << 8) + ROM[0x014f]));
- tmp = (ROM[0x0103] << 8) + ROM[0x0102];
- logerror("\tStart Address: 0x%04X\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 0x%04X vs Internal 0x%04X)\n", csum, tmp);
-
-}