diff --git a/.gitattributes b/.gitattributes index a94052591b7..5a8dc7ba9c3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7332,6 +7332,8 @@ src/mess/machine/nes.c svneol=native#text/plain src/mess/machine/nes_ines.c svneol=native#text/plain src/mess/machine/nes_mmc.c svneol=native#text/plain src/mess/machine/nes_pcb.c svneol=native#text/plain +src/mess/machine/nes_slot.c svneol=native#text/plain +src/mess/machine/nes_slot.h svneol=native#text/plain src/mess/machine/nes_unif.c svneol=native#text/plain src/mess/machine/nextkbd.c svneol=native#text/plain src/mess/machine/nextkbd.h svneol=native#text/plain diff --git a/src/mess/drivers/nes.c b/src/mess/drivers/nes.c index 45763301336..647a40e9e1b 100644 --- a/src/mess/drivers/nes.c +++ b/src/mess/drivers/nes.c @@ -15,7 +15,6 @@ #include "includes/nes.h" //#include "includes/nes_mmc.h" #include "cpu/m6502/n2a03.h" -#include "imagedev/cartslot.h" #include "sound/nes_apu.h" #include "imagedev/flopdrv.h" #include "formats/nes_dsk.h" @@ -53,7 +52,9 @@ static ADDRESS_MAP_START( nes_map, AS_PROGRAM, 8, nes_state ) AM_RANGE(0x4016, 0x4016) AM_READWRITE(nes_IN0_r, nes_IN0_w) /* IN0 - input port 1 */ AM_RANGE(0x4017, 0x4017) AM_READ(nes_IN1_r) /* IN1 - input port 2 */ AM_RANGE(0x4017, 0x4017) AM_WRITE(psg_4017_w) /* PSG second control register */ - AM_RANGE(0x4100, 0x5fff) AM_READWRITE(nes_low_mapper_r, nes_low_mapper_w) /* Perform unholy acts on the machine */ + // 0x4100-0x5fff -> LOW HANDLER defined on a pcb base + // 0x6000-0x7fff -> MID HANDLER defined on a pcb base + // 0x8000-0xffff -> HIGH HANDLER defined on a pcb base ADDRESS_MAP_END @@ -442,6 +443,14 @@ static const floppy_interface nes_floppy_interface = }; +static const nes_cart_interface nes_crt_interface = +{ +}; + +static SLOT_INTERFACE_START(nes_cart) + SLOT_INTERFACE("rom", NES_ROM) +SLOT_INTERFACE_END + static MACHINE_CONFIG_START( nes, nes_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", N2A03, NTSC_CLOCK) @@ -470,12 +479,7 @@ static MACHINE_CONFIG_START( nes, nes_state ) MCFG_SOUND_CONFIG(nes_apu_interface) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.90) - MCFG_CARTSLOT_ADD("cart") - MCFG_CARTSLOT_EXTENSION_LIST("nes,unf") - MCFG_CARTSLOT_MANDATORY - MCFG_CARTSLOT_INTERFACE("nes_cart") - MCFG_CARTSLOT_LOAD(nes_state,nes_cart) - MCFG_CARTSLOT_PARTIALHASH(nes_partialhash) + MCFG_NES_CARTRIDGE_ADD("nes_slot", nes_crt_interface, nes_cart, NULL, NULL) MCFG_SOFTWARE_LIST_ADD("cart_list","nes") MACHINE_CONFIG_END @@ -522,20 +526,13 @@ static MACHINE_CONFIG_DERIVED( dendy, nes ) MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( famicom, nes ) - - MCFG_CARTSLOT_MODIFY("cart") - MCFG_CARTSLOT_EXTENSION_LIST("nes,unf") - MCFG_CARTSLOT_NOT_MANDATORY - MCFG_CARTSLOT_LOAD(nes_state,nes_cart) - MCFG_CARTSLOT_PARTIALHASH(nes_partialhash) + MCFG_DEVICE_REMOVE( "nes_slot" ) +// MCFG_FC_CARTRIDGE_ADD("nes_slot", nes_crt_interface, nes_cart, NULL, NULL) // here we need a non-mandatory cart... MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, nes_floppy_interface) MCFG_SOFTWARE_LIST_ADD("flop_list","famicom_flop") MACHINE_CONFIG_END -//static MACHINE_CONFIG_DERIVED( nes_test, nes ) -//MACHINE_CONFIG_END - /* rom regions are just place-holders: they get removed and re-allocated when a cart is loaded */ ROM_START( nes ) @@ -588,7 +585,6 @@ ROM_START( dendy ) ROM_REGION( 0x800, "ciram", ROMREGION_ERASE00 ) /* CI RAM */ ROM_END -//#define rom_nes_test rom_nes /*************************************************************************** @@ -604,5 +600,3 @@ CONS( 1986, famitwin, nes, 0, famicom, famicom, nes_state, famicom, "Sh CONS( 198?, m82, nes, 0, nes, nes, driver_device, 0, "Nintendo", "M82 Display Unit", GAME_IMPERFECT_GRAPHICS | GAME_NOT_WORKING ) CONS( 1996, drpcjr, nes, 0, famicom, famicom, nes_state, famicom, "Bung", "Doctor PC Jr", GAME_IMPERFECT_GRAPHICS ) CONS( 1992, dendy, nes, 0, dendy, nes, driver_device, 0, "Steepler", "Dendy Classic", GAME_IMPERFECT_GRAPHICS ) - -//CONS( 1985, nes_test, 0, 0, nes_test, nes, driver_device, 0, "Nintendo", "Nintendo Entertainment System (Testdriver)", GAME_IMPERFECT_GRAPHICS ) diff --git a/src/mess/includes/nes.h b/src/mess/includes/nes.h index 95f9087d09f..d11f3716305 100644 --- a/src/mess/includes/nes.h +++ b/src/mess/includes/nes.h @@ -10,6 +10,7 @@ #define NES_H_ #include "includes/nes_mmc.h" +#include "machine/nes_slot.h" /*************************************************************************** @@ -54,7 +55,9 @@ class nes_state : public nes_carts_state { public: nes_state(const machine_config &mconfig, device_type type, const char *tag) - : nes_carts_state(mconfig, type, tag) { } + : nes_carts_state(mconfig, type, tag), + m_cartslot(*this, "nes_slot") + { } /* input_related - this part has to be cleaned up (e.g. in_2 and in_3 are not really necessary here...) */ nes_input m_in_0, m_in_1, m_in_2, m_in_3; @@ -74,8 +77,6 @@ public: DECLARE_READ8_MEMBER(nes_chr_r); DECLARE_WRITE8_MEMBER(nes_nt_w); DECLARE_READ8_MEMBER(nes_nt_r); - DECLARE_WRITE8_MEMBER(nes_low_mapper_w); - DECLARE_READ8_MEMBER(nes_low_mapper_r); /* misc */ write8_delegate m_mmc_write_low; @@ -114,7 +115,6 @@ public: DECLARE_WRITE8_MEMBER(nes_vh_sprite_dma_w); DECLARE_DRIVER_INIT(famicom); virtual void machine_start(); - virtual void machine_stop(); virtual void machine_reset(); virtual void video_start(); virtual void video_reset(); @@ -126,7 +126,6 @@ public: DECLARE_WRITE8_MEMBER(psg_4015_w); DECLARE_WRITE8_MEMBER(psg_4017_w); void nes_banks_restore(); - DECLARE_DEVICE_IMAGE_LOAD_MEMBER(nes_cart); DECLARE_DEVICE_IMAGE_LOAD_MEMBER(nes_disk); DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(nes_disk); @@ -144,16 +143,18 @@ public: ioport_port *m_io_zapper2_y; ioport_port *m_io_paddle; + optional_device m_cartslot; //mandatory + private: /* devices */ // cpu_device *m_maincpu; // ppu2c0x_device *m_ppu; // device_t *m_sound; - device_t *m_cart; // emu_timer *m_irq_timer; memory_bank *m_prg_bank_mem[5]; }; + /*----------- defined in machine/nes.c -----------*/ diff --git a/src/mess/includes/nes_mmc.h b/src/mess/includes/nes_mmc.h index 9bdaff6731c..0cc28c9b4a7 100644 --- a/src/mess/includes/nes_mmc.h +++ b/src/mess/includes/nes_mmc.h @@ -1,6 +1,8 @@ #ifndef __MMC_H #define __MMC_H +#include "video/ppu2c0x.h" + /* Boards */ enum { @@ -109,7 +111,7 @@ enum // these are used to setup the proper PCB ID, for each supported type of files int nes_get_pcb_id(running_machine &machine, const char *feature); // for softlist -void unif_mapr_setup(running_machine &machine, const char *board); // for UNIF files +void unif_mapr_setup(const char *board, int *pcb_id, int *battery, int *prgram, int *vram_chunks); // for UNIF files int nes_get_mmc_id(running_machine &machine, int mapper); // for iNES files // these are used to setup handlers and callbacks necessary to the emulation (resp. at start and reset) @@ -610,6 +612,4 @@ public: }; - - #endif diff --git a/src/mess/machine/nes.c b/src/mess/machine/nes.c index 605784c6b7f..a589c70de33 100644 --- a/src/mess/machine/nes.c +++ b/src/mess/machine/nes.c @@ -42,8 +42,11 @@ void nes_state::init_nes_core() { address_space &space = machine().device("maincpu")->memory().space(AS_PROGRAM); static const char *const bank_names[] = { "bank1", "bank2", "bank3", "bank4" }; - int prg_banks = (m_prg_chunks == 1) ? (2 * 2) : (m_prg_chunks * 2); int i; + m_prg_chunks = 0; + m_chr_chunks = 0; + m_vram_chunks = 0; + m_pcb_id = NO_BOARD; m_rom = machine().root_device().memregion("maincpu")->base(); m_ciram = machine().root_device().memregion("ciram")->base(); @@ -57,6 +60,52 @@ void nes_state::init_nes_core() membank("bank10")->set_base(m_rom); + // get cart info from cartslot + if (m_cartslot && m_cartslot->m_cart) + { + m_prg_chunks = m_cartslot->m_cart->get_prg_size() / 0x4000; + m_chr_chunks = m_cartslot->m_cart->get_vrom_size() / 0x2000; + m_vram_chunks = m_cartslot->m_cart->get_vram_size() / 0x2000; +// printf("%d - %d - %d\n", m_prg_chunks, m_chr_chunks, m_vram_chunks); + m_prg = m_cartslot->m_cart->get_prg_base(); + if (m_cartslot->m_cart->get_vrom_size()) + m_vrom = m_cartslot->m_cart->get_vrom_base(); + if (m_cartslot->m_cart->get_vram_size()) + m_vram = auto_alloc_array(machine(), UINT8, m_cartslot->m_cart->get_vram_size()); + + m_pcb_id = m_cartslot->get_pcb_id(); + m_hard_mirroring = m_cartslot->m_cart->get_mirroring(); + m_four_screen_vram = m_cartslot->m_cart->get_four_screen_vram(); + + // setup memory pointers and related variables + m_prg_ram = m_cartslot->m_cart->get_battery_size() ? 1 : 0; + m_wram_size = m_cartslot->m_cart->get_prgram_size(); + m_mapper_ram_size = m_cartslot->m_cart->get_mapper_ram_size(); + m_mapper_bram_size = m_cartslot->m_cart->get_mapper_bram_size(); + m_battery = m_cartslot->m_cart->get_battery_size() ? 1 : 0; + m_battery_size = m_cartslot->m_cart->get_battery_size(); + + if (m_prg_ram) + m_wram = m_cartslot->m_cart->get_prgram_base(); + if (m_mapper_ram_size) + m_mapper_ram = m_cartslot->m_cart->get_mapper_ram_base(); + if (m_battery) + m_battery_ram = m_cartslot->m_cart->get_battery_base(); + if (m_mapper_bram_size) + m_mapper_bram = m_cartslot->m_cart->get_mapper_bram_base(); + + // setup the rest of the variables involved + m_chr_open_bus = m_cartslot->get_chr_open_bus(); + m_ce_mask = m_cartslot->get_ce_mask(); + m_ce_state = m_cartslot->get_ce_state(); + m_vrc_ls_prg_a = m_cartslot->get_vrc_ls_prg_a(); + m_vrc_ls_prg_b = m_cartslot->get_vrc_ls_prg_b(); + m_vrc_ls_chr = m_cartslot->get_vrc_ls_chr(); + m_crc_hack = m_cartslot->get_crc_hack(); + } + + int prg_banks = (m_prg_chunks == 1) ? (2 * 2) : (m_prg_chunks * 2); + /* If there is Disk Expansion and no cart has been loaded, setup memory accordingly */ if (m_disk_expansion && m_pcb_id == NO_BOARD) { @@ -83,87 +132,91 @@ void nes_state::init_nes_core() membank("bank2")->set_base(m_fds_ram); return; } - - /* Set up the mapper callbacks */ - pcb_handlers_setup(); - - /* Set up the memory handlers for the mapper */ - space.install_read_bank(0x8000, 0x9fff, "bank1"); - space.install_read_bank(0xa000, 0xbfff, "bank2"); - space.install_read_bank(0xc000, 0xdfff, "bank3"); - space.install_read_bank(0xe000, 0xffff, "bank4"); - space.install_readwrite_bank(0x6000, 0x7fff, "bank5"); - - /* configure banks 1-4 */ - for (i = 0; i < 4; i++) - { - membank(bank_names[i])->configure_entries(0, prg_banks, m_prg, 0x2000); - // some mappers (e.g. MMC5) can map PRG RAM in 0x8000-0xffff as well - if (m_prg_ram) - membank(bank_names[i])->configure_entries(prg_banks, m_wram_size / 0x2000, m_wram, 0x2000); - // however, at start we point to PRG ROM - membank(bank_names[i])->set_entry(i); - m_prg_bank[i] = i; - } - - /* bank 5 configuration is more delicate, since it can have PRG RAM, PRG ROM or SRAM mapped to it */ - /* we first map PRG ROM banks, then the battery bank (if a battery is present), and finally PRG RAM (m_wram) */ - membank("bank5")->configure_entries(0, prg_banks, m_prg, 0x2000); - m_battery_bank5_start = prg_banks; - m_prgram_bank5_start = prg_banks; - m_empty_bank5_start = prg_banks; - - /* add battery ram, but only if there's no trainer since they share overlapping memory. */ - if (m_battery && !m_trainer) - { - UINT32 bank_size = (m_battery_size > 0x2000) ? 0x2000 : m_battery_size; - int bank_num = (m_battery_size > 0x2000) ? m_battery_size / 0x2000 : 1; - membank("bank5")->configure_entries(prg_banks, bank_num, m_battery_ram, bank_size); - m_prgram_bank5_start += bank_num; - m_empty_bank5_start += bank_num; - } - /* add prg ram. */ - if (m_prg_ram) - { - membank("bank5")->configure_entries(m_prgram_bank5_start, m_wram_size / 0x2000, m_wram, 0x2000); - m_empty_bank5_start += m_wram_size / 0x2000; - } - - membank("bank5")->configure_entry(m_empty_bank5_start, m_rom + 0x6000); - - /* if we have any additional PRG RAM, point bank5 to its first bank */ - if (m_battery || m_prg_ram) - m_prg_bank[4] = m_battery_bank5_start; - else - m_prg_bank[4] = m_empty_bank5_start; // or shall we point to "maincpu" region at 0x6000? point is that we should never access this region if no sram or wram is present! - - membank("bank5")->set_entry(m_prg_bank[4]); - - if (m_four_screen_vram) - { - m_extended_ntram = auto_alloc_array_clear(machine(), UINT8, 0x2000); - save_pointer(NAME(m_extended_ntram), 0x2000); - } - - if (m_four_screen_vram) - set_nt_mirroring(PPU_MIRROR_4SCREEN); else { - switch (m_hard_mirroring) + /* Set up the mapper callbacks */ + pcb_handlers_setup(); + + /* Set up the memory handlers for the mapper */ + space.install_read_bank(0x8000, 0x9fff, "bank1"); + space.install_read_bank(0xa000, 0xbfff, "bank2"); + space.install_read_bank(0xc000, 0xdfff, "bank3"); + space.install_read_bank(0xe000, 0xffff, "bank4"); + space.install_readwrite_bank(0x6000, 0x7fff, "bank5"); + + /* configure banks 1-4 */ + for (i = 0; i < 4; i++) { - case PPU_MIRROR_HORZ: - case PPU_MIRROR_VERT: - case PPU_MIRROR_HIGH: - case PPU_MIRROR_LOW: - set_nt_mirroring(m_hard_mirroring); - break; - default: - set_nt_mirroring(PPU_MIRROR_NONE); - break; + membank(bank_names[i])->configure_entries(0, prg_banks, m_prg, 0x2000); + // some mappers (e.g. MMC5) can map PRG RAM in 0x8000-0xffff as well + if (m_prg_ram) + membank(bank_names[i])->configure_entries(prg_banks, m_wram_size / 0x2000, m_wram, 0x2000); + // however, at start we point to PRG ROM + membank(bank_names[i])->set_entry(i); + m_prg_bank[i] = i; + } + + /* bank 5 configuration is more delicate, since it can have PRG RAM, PRG ROM or SRAM mapped to it */ + /* we first map PRG ROM banks, then the battery bank (if a battery is present), and finally PRG RAM (m_wram) */ + membank("bank5")->configure_entries(0, prg_banks, m_prg, 0x2000); + m_battery_bank5_start = prg_banks; + m_prgram_bank5_start = prg_banks; + m_empty_bank5_start = prg_banks; + + /* add battery ram, but only if there's no trainer since they share overlapping memory. */ + if (m_battery && !m_trainer) + { + UINT32 bank_size = (m_battery_size > 0x2000) ? 0x2000 : m_battery_size; + int bank_num = (m_battery_size > 0x2000) ? m_battery_size / 0x2000 : 1; + membank("bank5")->configure_entries(prg_banks, bank_num, m_battery_ram, bank_size); + m_prgram_bank5_start += bank_num; + m_empty_bank5_start += bank_num; + } + /* add prg ram. */ + if (m_prg_ram) + { + membank("bank5")->configure_entries(m_prgram_bank5_start, m_wram_size / 0x2000, m_wram, 0x2000); + m_empty_bank5_start += m_wram_size / 0x2000; + } + + membank("bank5")->configure_entry(m_empty_bank5_start, m_rom + 0x6000); + + /* if we have any additional PRG RAM, point bank5 to its first bank */ + if (m_battery || m_prg_ram) + m_prg_bank[4] = m_battery_bank5_start; + else + m_prg_bank[4] = m_empty_bank5_start; // or shall we point to "maincpu" region at 0x6000? point is that we should never access this region if no sram or wram is present! + + membank("bank5")->set_entry(m_prg_bank[4]); + + if (m_four_screen_vram) + { + m_extended_ntram = auto_alloc_array_clear(machine(), UINT8, 0x2000); + save_pointer(NAME(m_extended_ntram), 0x2000); + } + + if (m_four_screen_vram) + set_nt_mirroring(PPU_MIRROR_4SCREEN); + else + { + switch (m_hard_mirroring) + { + case PPU_MIRROR_HORZ: + case PPU_MIRROR_VERT: + case PPU_MIRROR_HIGH: + case PPU_MIRROR_LOW: + set_nt_mirroring(m_hard_mirroring); + break; + default: + set_nt_mirroring(PPU_MIRROR_NONE); + break; + } } } // there are still some quirk about writes to bank5... I hope to fix them soon. (mappers 34,45,52,246 have both mid_w and WRAM-->check) + if (!m_mmc_write_low.isnull()) + space.install_write_handler(0x4100, 0x5fff, m_mmc_write_low); if (!m_mmc_write_mid.isnull()) space.install_write_handler(0x6000, 0x7fff, m_mmc_write_mid); if (!m_mmc_write.isnull()) @@ -172,6 +225,8 @@ void nes_state::init_nes_core() // In fact, we also allow single pcbs to overwrite the bank read handlers defined above, // because some pcbs (mainly pirate ones) require protection values to be read instead of // the expected ROM banks: these handlers, though, must take care of the ROM access as well + if (!m_mmc_read_low.isnull()) + space.install_read_handler(0x4100, 0x5fff, m_mmc_read_low); if (!m_mmc_read_mid.isnull()) space.install_read_handler(0x6000, 0x7fff, m_mmc_read_mid); if (!m_mmc_read.isnull()) @@ -302,7 +357,6 @@ void nes_state::machine_start() m_maincpu = machine().device("maincpu"); m_sound = machine().device("nessound"); - m_cart = machine().device("cart"); m_io_ctrlsel = ioport("CTRLSEL"); m_io_fckey[0] = ioport("FCKEY0"); m_io_fckey[1] = ioport("FCKEY1"); @@ -363,23 +417,6 @@ void nes_state::machine_start() } -//------------------------------------------------- -// machine_stop -//------------------------------------------------- - -void nes_state::machine_stop() -{ - device_image_interface *image = dynamic_cast(m_cart); - /* Write out the battery file if necessary */ - if (m_battery) - image->battery_save(m_battery_ram, m_battery_size); - - if (m_mapper_bram_size) - image->battery_save(m_mapper_bram, m_mapper_bram_size); -} - - - //------------------------------------------------- // update_prg_banks //------------------------------------------------- @@ -670,906 +707,6 @@ WRITE8_MEMBER(nes_state::nes_IN1_w) { } -struct nes_cart_lines -{ - const char *tag; - int line; -}; - -static const struct nes_cart_lines nes_cart_lines_table[] = -{ - { "PRG A0", 0 }, - { "PRG A1", 1 }, - { "PRG A2", 2 }, - { "PRG A3", 3 }, - { "PRG A4", 4 }, - { "PRG A5", 5 }, - { "PRG A6", 6 }, - { "PRG A7", 7 }, - { "CHR A10", 10 }, - { "CHR A11", 11 }, - { "CHR A12", 12 }, - { "CHR A13", 13 }, - { "CHR A14", 14 }, - { "CHR A15", 15 }, - { "CHR A16", 16 }, - { "CHR A17", 17 }, - { "NC", 127 }, - { 0 } -}; - -static int nes_cart_get_line( const char *feature ) -{ - const struct nes_cart_lines *nes_line = &nes_cart_lines_table[0]; - - if (feature == NULL) - return 128; - - while (nes_line->tag) - { - if (strcmp(nes_line->tag, feature) == 0) - break; - - nes_line++; - } - - return nes_line->line; -} - -DEVICE_IMAGE_LOAD_MEMBER( nes_state, nes_cart ) -{ - nes_state *state = image.device().machine().driver_data(); - state->m_pcb_id = NO_BOARD; // initialization - - if (image.software_entry() == NULL) - { - const char *mapinfo = NULL; - int mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0; //, goodcrcinfo = 0; - char magic[4], extend[5]; - int local_options = 0; - char m; - - /* Check first 4 bytes of the image to decide if it is UNIF or iNES */ - /* Unfortunately, many .unf files have been released as .nes, so we cannot rely on extensions only */ - memset(magic, '\0', sizeof(magic)); - image.fread(magic, 4); - - if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */ - { - UINT32 prg_size; - state->m_ines20 = 0; - state->m_battery_size = NES_BATTERY_SIZE; // with iNES we can only support 8K WRAM battery (iNES 2.0 might fix this) - state->m_prg_ram = 1; // always map state->m_wram in bank5 (eventually, this should be enabled only for some mappers) - - // check if the image is recognized by nes.hsi - mapinfo = hashfile_extrainfo(image); - - // image_extrainfo() resets the file position back to start. - // Let's skip past the magic header once again. - image.fseek(4, SEEK_SET); - - image.fread(&state->m_prg_chunks, 1); - image.fread(&state->m_chr_chunks, 1); - /* Read the first ROM option byte (offset 6) */ - image.fread(&m, 1); - - /* Interpret the iNES header flags */ - state->m_mapper = (m & 0xf0) >> 4; - local_options = m & 0x0f; - - /* Read the second ROM option byte (offset 7) */ - image.fread(&m, 1); - - switch (m & 0xc) - { - case 0x4: - case 0xc: - // probably the header got corrupted: don't trust upper bits for mapper - break; - - case 0x8: // it's iNES 2.0 format - state->m_ines20 = 1; - case 0x0: - default: - state->m_mapper = state->m_mapper | (m & 0xf0); - break; - } - - if (mapinfo /* && !state->m_ines20 */) - { - if (4 == sscanf(mapinfo,"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4)) - { - /* image is present in nes.hsi: overwrite the header settings with these */ - state->m_mapper = mapint1; - local_options = mapint2 & 0x0f; - state->m_crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below) - state->m_prg_chunks = mapint3; - state->m_chr_chunks = mapint4; - logerror("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); -// mame_printf_error("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); -// goodcrcinfo = 1; - state->m_ines20 = 0; - } - else - { - logerror("NES: [%s], Invalid mapinfo found\n", mapinfo); - } - } - else - { - logerror("NES: No extrainfo found\n"); - } - - state->m_hard_mirroring = (local_options & 0x01) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ; -// mame_printf_error("%s\n", state->m_hard_mirroring & 0x01 ? "Vertical" : "Horizontal"); - state->m_battery = local_options & 0x02; - state->m_trainer = local_options & 0x04; - state->m_four_screen_vram = local_options & 0x08; - - if (state->m_battery) - logerror("-- Battery found\n"); - - if (state->m_trainer) - logerror("-- Trainer found\n"); - - if (state->m_four_screen_vram) - logerror("-- 4-screen VRAM\n"); - - if (state->m_ines20) - { - logerror("Extended iNES format:\n"); - image.fread(&extend, 5); - state->m_mapper |= (extend[0] & 0x0f) << 8; - logerror("-- mapper: %d\n", state->m_mapper); - logerror("-- submapper: %d\n", (extend[0] & 0xf0) >> 4); - state->m_prg_chunks |= ((extend[1] & 0x0f) << 8); - state->m_chr_chunks |= ((extend[1] & 0xf0) << 4); - logerror("-- PRG chunks: %d\n", state->m_prg_chunks); - logerror("-- CHR chunks: %d\n", state->m_chr_chunks); - logerror("-- PRG NVWRAM: %d\n", extend[2] & 0x0f); - logerror("-- PRG WRAM: %d\n", (extend[2] & 0xf0) >> 4); - logerror("-- CHR NVWRAM: %d\n", extend[3] & 0x0f); - logerror("-- CHR WRAM: %d\n", (extend[3] & 0xf0) >> 4); - logerror("-- TV System: %d\n", extend[4] & 3); - } - - // Allocate class pointers for PRG/VROM/VRAM/WRAM - prg_size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000; - state->m_prg = auto_alloc_array(image.device().machine(), UINT8, prg_size); - if (state->m_chr_chunks) - state->m_vrom = auto_alloc_array(image.device().machine(), UINT8, state->m_chr_chunks * 0x2000); - - state->m_vram_chunks = 2; - state->m_vram = auto_alloc_array(image.device().machine(), UINT8, 0x4000); - - // FIXME: this should only be allocated if there is actual wram in the cart (i.e. if state->m_prg_ram = 1)! - // or if there is a trainer, I think - state->m_wram_size = 0x10000; - state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); - - /* Setup PCB type (needed to add proper handlers later) */ - state->m_pcb_id = nes_get_mmc_id(image.device().machine(), state->m_mapper); - - // a few mappers correspond to multiple PCBs, so we need a few additional checks - switch (state->m_pcb_id) - { - case STD_CNROM: - if (state->m_mapper == 185) - { - switch (state->m_crc_hack) - { - case 0x0: // pin26: CE, pin27: CE (B-Wings, Bird Week) - state->m_ce_mask = 0x03; - state->m_ce_state = 0x03; - break; - case 0x4: // pin26: CE, pin27: /CE (Mighty Bomb Jack, Spy Vs. Spy) - state->m_ce_mask = 0x03; - state->m_ce_state = 0x01; - break; - case 0x8: // pin26: /CE, pin27: CE (Sansu 1, 2, 3 Nen) - state->m_ce_mask = 0x03; - state->m_ce_state = 0x02; - break; - case 0xc: // pin26: /CE, pin27: /CE (Seicross v2.0) - state->m_ce_mask = 0x03; - state->m_ce_state = 0x00; - break; - } - } - break; - case KONAMI_VRC2: - if (state->m_mapper == 22) - { - state->m_vrc_ls_prg_a = 0; - state->m_vrc_ls_prg_b = 1; - state->m_vrc_ls_chr = 1; - } - if (state->m_mapper == 23 && !state->m_crc_hack) - { - state->m_vrc_ls_prg_a = 1; - state->m_vrc_ls_prg_b = 0; - state->m_vrc_ls_chr = 0; - } - if (state->m_mapper == 23 && state->m_crc_hack) - { - // here there are also Akumajou Special, Crisis Force, Parodius da!, Tiny Toons which are VRC-4 - state->m_vrc_ls_prg_a = 3; - state->m_vrc_ls_prg_b = 2; - state->m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset - } - break; - case KONAMI_VRC4: - if (state->m_mapper == 21) - { - // Wai Wai World 2 & Ganbare Goemon Gaiden 2 (the latter with crc_hack) - state->m_vrc_ls_prg_a = state->m_crc_hack ? 7 : 2; - state->m_vrc_ls_prg_b = state->m_crc_hack ? 6 : 1; - } - if (state->m_mapper == 25) // here there is also Ganbare Goemon Gaiden which is VRC-2 - { - state->m_vrc_ls_prg_a = state->m_crc_hack ? 2 : 0; - state->m_vrc_ls_prg_b = state->m_crc_hack ? 3 : 1; - } - break; - case KONAMI_VRC6: - if (state->m_mapper == 24) - { - state->m_vrc_ls_prg_a = 1; - state->m_vrc_ls_prg_b = 0; - } - if (state->m_mapper == 26) - { - state->m_vrc_ls_prg_a = 0; - state->m_vrc_ls_prg_b = 1; - } - break; - case IREM_G101: - if (state->m_crc_hack) - state->m_hard_mirroring = PPU_MIRROR_HIGH; // Major League has hardwired mirroring - break; - case DIS_74X161X161X32: - if (state->m_mapper == 70) - state->m_hard_mirroring = PPU_MIRROR_VERT; // only hardwired mirroring makes different mappers 70 & 152 - break; - case SUNSOFT_2: - if (state->m_mapper == 93) - state->m_hard_mirroring = PPU_MIRROR_VERT; // only hardwired mirroring makes different mappers 89 & 93 - break; - case STD_BXROM: - if (state->m_crc_hack) - state->m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards - break; - case BANDAI_LZ93: - if (state->m_crc_hack) - state->m_pcb_id = BANDAI_JUMP2; // Mapper 153 is used for 2 diff boards - break; - case IREM_HOLYDIV: - if (state->m_crc_hack) - state->m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards - break; - case CAMERICA_BF9093: - if (state->m_crc_hack) - state->m_pcb_id = CAMERICA_BF9097; // Mapper 71 is used for 2 diff boards - break; - case HES_BOARD: - if (state->m_crc_hack) - state->m_pcb_id = HES6IN1_BOARD; // Mapper 113 is used for 2 diff boards - break; - case WAIXING_ZS: - if (state->m_crc_hack) - state->m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards - break; - case BMC_GOLD_7IN1: - if (state->m_crc_hack) - state->m_pcb_id = BMC_MARIOPARTY_7IN1; // Mapper 52 is used for 2 diff boards - break; - //FIXME: we also have to fix Action 52 PRG loading somewhere... - } - - /* Allocate internal Mapper RAM for boards which require it */ - if (state->m_pcb_id == STD_EXROM) - state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 0x400); - - if (state->m_pcb_id == TAITO_X1_005 || state->m_pcb_id == TAITO_X1_005_A) - state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, 0x80); - - if (state->m_pcb_id == TAITO_X1_017) - state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, 0x1400); - - if (state->m_pcb_id == NAMCOT_163) - state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 0x2000); - - if (state->m_pcb_id == FUKUTAKE_BOARD) - state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 2816); - - /* Position past the header */ - image.fseek(16, SEEK_SET); - - /* Load the 0x200 byte trainer at 0x7000 if it exists */ - if (state->m_trainer) - image.fread(&state->m_wram[0x1000], 0x200); - - /* Read in the program chunks */ - image.fread(&state->m_prg[0], 0x4000 * state->m_prg_chunks); - if (state->m_prg_chunks == 1) - memcpy(&state->m_prg[0x4000], &state->m_prg[0], 0x4000); - -#if SPLIT_PRG - { - FILE *prgout; - char outname[255]; - - sprintf(outname, "%s.prg", image.filename()); - prgout = fopen(outname, "wb"); - if (prgout) - { - fwrite(&state->m_prg[0], 1, 0x4000 * state->m_prg_chunks, prgout); - mame_printf_error("Created PRG chunk\n"); - } - - fclose(prgout); - } -#endif - - logerror("**\n"); - logerror("Mapper: %d\n", state->m_mapper); - logerror("PRG chunks: %02x, size: %06x\n", state->m_prg_chunks, 0x4000 * state->m_prg_chunks); - // mame_printf_error("Mapper: %d\n", state->m_mapper); - // mame_printf_error("PRG chunks: %02x, size: %06x\n", state->m_prg_chunks, 0x4000 * state->m_prg_chunks); - - /* Read in any chr chunks */ - if (state->m_chr_chunks > 0) - { - image.fread(state->m_vrom, state->m_chr_chunks * 0x2000); - if (state->m_mapper == 2) - logerror("Warning: VROM has been found in VRAM-based mapper. Either the mapper is set wrong or the ROM image is incorrect.\n"); - } - -#if SPLIT_CHR - if (state->m_chr_chunks > 0) - { - FILE *chrout; - char outname[255]; - - sprintf(outname, "%s.chr", image.filename()); - chrout= fopen(outname, "wb"); - if (chrout) - { - fwrite(state->m_vrom, 1, 0x2000 * state->m_chr_chunks, chrout); - mame_printf_error("Created CHR chunk\n"); - } - fclose(chrout); - } -#endif - - logerror("CHR chunks: %02x, size: %06x\n", state->m_chr_chunks, 0x2000 * state->m_chr_chunks); - logerror("**\n"); - // mame_printf_error("CHR chunks: %02x, size: %06x\n", state->m_chr_chunks, 0x2000 * state->m_chr_chunks); - // mame_printf_error("**\n"); - } - else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */ - { - UINT32 unif_ver = 0; - char magic2[4]; - UINT8 buffer[4]; - UINT32 chunk_length = 0, read_length = 0x20; - UINT32 prg_start = 0, chr_start = 0, prg_size; - char unif_mapr[32]; // here we should store MAPR chunks - UINT32 size = image.length(); - int mapr_chunk_found = 0; - // allocate space to temporarily store PRG & CHR banks - UINT8 *temp_prg = auto_alloc_array(image.device().machine(), UINT8, 256 * 0x4000); - UINT8 *temp_chr = auto_alloc_array(image.device().machine(), UINT8, 256 * 0x2000); - UINT8 temp_byte = 0; - - /* init prg/chr chunks to 0: the exact number of chunks will be determined while reading the file */ - state->m_prg_chunks = 0; - state->m_chr_chunks = 0; - - image.fread(&buffer, 4); - unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - logerror("UNIF file found, version %d\n", unif_ver); - - if (size <= 0x20) - { - logerror("%s only contains the UNIF header and no data.\n", image.filename()); - return IMAGE_INIT_FAIL; - } - - do - { - image.fseek(read_length, SEEK_SET); - - memset(magic2, '\0', sizeof(magic2)); - image.fread(&magic2, 4); - - /* We first run through the whole image to find a [MAPR] chunk. This is needed - because, unfortunately, the MAPR chunk is not always the first chunk (see - Super 24-in-1). When such a chunk is found, we set mapr_chunk_found=1 and - we go back to load other chunks! */ - if (!mapr_chunk_found) - { - if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) - { - mapr_chunk_found = 1; - logerror("[MAPR] chunk found: "); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - if (chunk_length <= 0x20) - image.fread(&unif_mapr, chunk_length); - - // find out prg/chr size, battery, wram, etc. - unif_mapr_setup(image.device().machine(), unif_mapr); - - /* now that we found the MAPR chunk, we can go back to load other chunks */ - image.fseek(0x20, SEEK_SET); - read_length = 0x20; - } - else - { - logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - } - else - { - /* What kind of chunk do we have here? */ - if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) - { - /* The [MAPR] chunk has already been read, so we skip it */ - /* TO DO: it would be nice to check if more than one MAPR chunk is present */ - logerror("[MAPR] chunk found (in the 2nd run). Already loaded.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'R') && (magic2[1] == 'E') && (magic2[2] == 'A') && (magic2[3] == 'D')) - { - logerror("[READ] chunk found. No support yet.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'N') && (magic2[1] == 'A') && (magic2[2] == 'M') && (magic2[3] == 'E')) - { - logerror("[NAME] chunk found. No support yet.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'W') && (magic2[1] == 'R') && (magic2[2] == 'T') && (magic2[3] == 'R')) - { - logerror("[WRTR] chunk found. No support yet.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'C') && (magic2[3] == 'I')) - { - logerror("[TVCI] chunk found.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - image.fread(&temp_byte, 1); - logerror("Television Standard : %s\n", (temp_byte == 0) ? "NTSC" : (temp_byte == 1) ? "PAL" : "Does not matter"); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'S') && (magic2[3] == 'C')) // is this the same as TVCI?? - { - logerror("[TVSC] chunk found. No support yet.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'D') && (magic2[1] == 'I') && (magic2[2] == 'N') && (magic2[3] == 'F')) - { - logerror("[DINF] chunk found. No support yet.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'C') && (magic2[1] == 'T') && (magic2[2] == 'R') && (magic2[3] == 'L')) - { - logerror("[CTRL] chunk found. No support yet.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'B') && (magic2[1] == 'A') && (magic2[2] == 'T') && (magic2[3] == 'R')) - { - logerror("[BATR] chunk found. No support yet.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'V') && (magic2[1] == 'R') && (magic2[2] == 'O') && (magic2[3] == 'R')) - { - logerror("[VROR] chunk found. No support yet.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'M') && (magic2[1] == 'I') && (magic2[2] == 'R') && (magic2[3] == 'R')) - { - logerror("[MIRR] chunk found.\n"); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - image.fread(&temp_byte, 1); - switch (temp_byte) - { - case 0: // Horizontal Mirroring (Hard Wired) - state->m_hard_mirroring = PPU_MIRROR_HORZ; - break; - case 1: // Vertical Mirroring (Hard Wired) - state->m_hard_mirroring = PPU_MIRROR_VERT; - break; - case 2: // Mirror All Pages From $2000 (Hard Wired) - state->m_hard_mirroring = PPU_MIRROR_LOW; - break; - case 3: // Mirror All Pages From $2400 (Hard Wired) - state->m_hard_mirroring = PPU_MIRROR_HIGH; - break; - case 4: // Four Screens of VRAM (Hard Wired) - state->m_four_screen_vram = 1; - break; - case 5: // Mirroring Controlled By Mapper Hardware - logerror("Mirroring handled by the board hardware.\n"); - // default to horizontal at start - state->m_hard_mirroring = PPU_MIRROR_HORZ; - break; - default: - logerror("Undocumented mirroring value.\n"); - // default to horizontal - state->m_hard_mirroring = PPU_MIRROR_HORZ; - break; - } - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'P') && (magic2[1] == 'C') && (magic2[2] == 'K')) - { - logerror("[PCK%c] chunk found. No support yet.\n", magic2[3]); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'C') && (magic2[1] == 'C') && (magic2[2] == 'K')) - { - logerror("[CCK%c] chunk found. No support yet.\n", magic2[3]); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'P') && (magic2[1] == 'R') && (magic2[2] == 'G')) - { - logerror("[PRG%c] chunk found. ", magic2[3]); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - // FIXME: we currently don't support PRG chunks smaller than 16K! - state->m_prg_chunks += (chunk_length / 0x4000); - - if (chunk_length / 0x4000) - logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000); - else - logerror("This chunk is smaller than 16K: the emulation might have issues. Please report this file to the MESS forums.\n"); - - /* Read in the program chunks */ - image.fread(&temp_prg[prg_start], chunk_length); - - prg_start += chunk_length; - read_length += (chunk_length + 8); - } - else if ((magic2[0] == 'C') && (magic2[1] == 'H') && (magic2[2] == 'R')) - { - logerror("[CHR%c] chunk found. ", magic2[3]); - image.fread(&buffer, 4); - chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); - - state->m_chr_chunks += (chunk_length / 0x2000); - - logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000); - - /* Read in the vrom chunks */ - image.fread(&temp_chr[chr_start], chunk_length); - - chr_start += chunk_length; - read_length += (chunk_length + 8); - } - else - { - logerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); - read_length = size; - } - } - } while (size > read_length); - - if (!mapr_chunk_found) - { - auto_free(image.device().machine(), temp_prg); - auto_free(image.device().machine(), temp_chr); - fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted\n"); - } - - if (!prg_start) - { - auto_free(image.device().machine(), temp_prg); - auto_free(image.device().machine(), temp_chr); - fatalerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); - } - - // Allocate class pointers for PRG/VROM/VRAM/WRAM and copy data there from the temp copies - - /* Take care of PRG */ - prg_size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000; - state->m_prg = auto_alloc_array(image.device().machine(), UINT8, prg_size); - - memcpy(&state->m_prg[0], &temp_prg[0], state->m_prg_chunks * 0x4000); - /* If only a single 16K PRG chunk is present, mirror it! */ - if (state->m_prg_chunks == 1) - memcpy(&state->m_prg[0x4000], &state->m_prg[0], 0x4000); - - /* Take care of CHR ROM */ - if (state->m_chr_chunks) - { - state->m_vrom = auto_alloc_array(image.device().machine(), UINT8, state->m_chr_chunks * 0x2000); - memcpy(&state->m_vrom[0x00000], &temp_chr[0x00000], state->m_chr_chunks * 0x2000); - } - - /* Take care of CHR RAM */ - if (state->m_vram_chunks) - state->m_vram = auto_alloc_array(image.device().machine(), UINT8, state->m_vram_chunks * 0x2000); - - // FIXME: this should only be allocated if there is actual wram in the cart (i.e. if state->m_prg_ram = 1)! - state->m_wram_size = 0x10000; - state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); - -#if SPLIT_PRG - { - FILE *prgout; - char outname[255]; - - sprintf(outname, "%s.prg", image.filename()); - prgout = fopen(outname, "wb"); - if (prgout) - { - fwrite(&state->m_prg[0], 1, 0x4000 * state->m_prg_chunks, prgout); - mame_printf_error("Created PRG chunk\n"); - } - - fclose(prgout); - } -#endif - -#if SPLIT_CHR - if (state->m_chr_chunks > 0) - { - FILE *chrout; - char outname[255]; - - sprintf(outname, "%s.chr", image.filename()); - chrout= fopen(outname, "wb"); - if (chrout) - { - fwrite(state->m_vrom, 1, 0x2000 * state->m_chr_chunks, chrout); - mame_printf_error("Created CHR chunk\n"); - } - fclose(chrout); - } -#endif - // free the temporary copy of PRG/CHR - auto_free(image.device().machine(), temp_prg); - auto_free(image.device().machine(), temp_chr); - logerror("UNIF support is only very preliminary.\n"); - } - else - { - logerror("%s is NOT a file in either iNES or UNIF format.\n", image.filename()); - return IMAGE_INIT_FAIL; - } - } - else - { - UINT32 prg_size = image.get_software_region_length("prg"); - UINT32 chr_size = image.get_software_region_length("chr"); - UINT32 vram_size = image.get_software_region_length("vram"); - vram_size += image.get_software_region_length("vram2"); - - // validate the xml fields - if (!prg_size) - fatalerror("No PRG entry for this software! Please check if the xml list got corrupted\n"); - if (prg_size < 0x8000) - fatalerror("PRG entry is too small! Please check if the xml list got corrupted\n"); - - // Allocate class pointers for PRG/VROM/VRAM/WRAM and copy data there from the temp copies - state->m_prg = auto_alloc_array(image.device().machine(), UINT8, prg_size); - - if (chr_size) - state->m_vrom = auto_alloc_array(image.device().machine(), UINT8, chr_size); - - if (vram_size) - state->m_vram = auto_alloc_array(image.device().machine(), UINT8, vram_size); - - memcpy(state->m_prg, image.get_software_region("prg"), prg_size); - - if (chr_size) - memcpy(state->m_vrom, image.get_software_region("chr"), chr_size); - - state->m_prg_chunks = prg_size / 0x4000; - state->m_chr_chunks = chr_size / 0x2000; - state->m_vram_chunks = vram_size / 0x2000; - - state->m_pcb_id = nes_get_pcb_id(image.device().machine(), image.get_feature("pcb")); - - if (state->m_pcb_id == STD_TVROM || state->m_pcb_id == STD_DRROM || state->m_pcb_id == IREM_LROG017) - state->m_four_screen_vram = 1; - else - state->m_four_screen_vram = 0; - - state->m_battery = (image.get_software_region("bwram") != NULL) ? 1 : 0; - state->m_battery_size = image.get_software_region_length("bwram"); - - if (state->m_pcb_id == BANDAI_LZ93EX) - { - // allocate the 24C01 or 24C02 EEPROM - state->m_battery = 1; - state->m_battery_size += 0x2000; - } - - if (state->m_pcb_id == BANDAI_DATACH) - { - // allocate the 24C01 and 24C02 EEPROM - state->m_battery = 1; - state->m_battery_size += 0x4000; - } - - state->m_prg_ram = (image.get_software_region("wram") != NULL) ? 1 : 0; - state->m_wram_size = image.get_software_region_length("wram"); - state->m_mapper_ram_size = image.get_software_region_length("mapper_ram"); - state->m_mapper_bram_size = image.get_software_region_length("mapper_bram"); - - if (state->m_prg_ram) - state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size); - if (state->m_mapper_ram_size) - state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_mapper_ram_size); - if (state->m_mapper_bram_size) - state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, state->m_mapper_bram_size); - - /* Check for mirroring */ - if (image.get_feature("mirroring") != NULL) - { - const char *mirroring = image.get_feature("mirroring"); - if (!strcmp(mirroring, "horizontal")) - state->m_hard_mirroring = PPU_MIRROR_HORZ; - if (!strcmp(mirroring, "vertical")) - state->m_hard_mirroring = PPU_MIRROR_VERT; - if (!strcmp(mirroring, "high")) - state->m_hard_mirroring = PPU_MIRROR_HIGH; - if (!strcmp(mirroring, "low")) - state->m_hard_mirroring = PPU_MIRROR_LOW; - } - - state->m_chr_open_bus = 0; - state->m_ce_mask = 0; - state->m_ce_state = 0; - state->m_vrc_ls_prg_a = 0; - state->m_vrc_ls_prg_b = 0; - state->m_vrc_ls_chr = 0; - - /* Check for pins in specific boards which require them */ - if (state->m_pcb_id == STD_CNROM) - { - if (image.get_feature("chr-pin26") != NULL) - { - state->m_ce_mask |= 0x01; - state->m_ce_state |= !strcmp(image.get_feature("chr-pin26"), "CE") ? 0x01 : 0; - } - if (image.get_feature("chr-pin27") != NULL) - { - state->m_ce_mask |= 0x02; - state->m_ce_state |= !strcmp(image.get_feature("chr-pin27"), "CE") ? 0x02 : 0; - } - } - - if (state->m_pcb_id == TAITO_X1_005 && image.get_feature("x1-pin17") != NULL && image.get_feature("x1-pin31") != NULL) - { - if (!strcmp(image.get_feature("x1-pin17"), "CIRAM A10") && !strcmp(image.get_feature("x1-pin31"), "NC")) - state->m_pcb_id = TAITO_X1_005_A; - } - - if (state->m_pcb_id == KONAMI_VRC2) - { - state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc2-pin3")); - state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc2-pin4")); - state->m_vrc_ls_chr = (nes_cart_get_line(image.get_feature("vrc2-pin21")) != 10) ? 1 : 0; -// mame_printf_error("VRC-2, pin3: A%d, pin4: A%d, pin21: %s\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b, state->m_vrc_ls_chr ? "NC" : "A10"); - } - - if (state->m_pcb_id == KONAMI_VRC4) - { - state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc4-pin3")); - state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc4-pin4")); -// mame_printf_error("VRC-4, pin3: A%d, pin4: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b); - } - - if (state->m_pcb_id == KONAMI_VRC6) - { - state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc6-pin9")); - state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc6-pin10")); -// mame_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b); - } - - /* Check for other misc board variants */ - if (state->m_pcb_id == STD_SOROM) - { - if (image.get_feature("mmc1_type") != NULL && !strcmp(image.get_feature("mmc1_type"), "MMC1A")) - state->m_pcb_id = STD_SOROM_A; // in MMC1-A PRG RAM is always enabled - } - - if (state->m_pcb_id == STD_SXROM) - { - if (image.get_feature("mmc1_type") != NULL && !strcmp(image.get_feature("mmc1_type"), "MMC1A")) - state->m_pcb_id = STD_SXROM_A; // in MMC1-A PRG RAM is always enabled - } - - if (state->m_pcb_id == STD_NXROM || state->m_pcb_id == SUNSOFT_DCS) - { - if (image.get_software_region("minicart") != NULL) // check for dual minicart - { - state->m_pcb_id = SUNSOFT_DCS; - // we shall load somewhere the minicart, but we still do not support this - } - } - -#if 0 - if (state->m_pcb_id == UNSUPPORTED_BOARD) - mame_printf_error("This board (%s) is currently not supported by MESS\n", image.get_feature("pcb")); - mame_printf_error("PCB Feature: %s\n", image.get_feature("pcb")); - mame_printf_error("PRG chunks: %d\n", state->m_prg_chunks); - mame_printf_error("CHR chunks: %d\n", state->m_chr_chunks); - mame_printf_error("VRAM: Present %s, size: %d\n", state->m_vram_chunks ? "Yes" : "No", vram_size); - mame_printf_error("NVWRAM: Present %s, size: %d\n", state->m_battery ? "Yes" : "No", state->m_battery_size); - mame_printf_error("WRAM: Present %s, size: %d\n", state->m_prg_ram ? "Yes" : "No", state->m_wram_size); -#endif - } - - // Attempt to load a battery file for this ROM - // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.) - if (state->m_battery || state->m_mapper_bram_size) - { - UINT8 *temp_nvram = auto_alloc_array(image.device().machine(), UINT8, state->m_battery_size + state->m_mapper_bram_size); - image.battery_load(temp_nvram, state->m_battery_size + state->m_mapper_bram_size, 0x00); - if (state->m_battery) - { - state->m_battery_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_battery_size); - memcpy(state->m_battery_ram, temp_nvram, state->m_battery_size); - } - if (state->m_mapper_bram_size) - memcpy(state->m_mapper_bram, temp_nvram + state->m_battery_size, state->m_mapper_bram_size); - - auto_free(image.device().machine(), temp_nvram); - } - - return IMAGE_INIT_PASS; -} - void nes_partialhash(hash_collection &dest, const unsigned char *data, diff --git a/src/mess/machine/nes_mmc.c b/src/mess/machine/nes_mmc.c index df07e70f848..7c932bda80d 100644 --- a/src/mess/machine/nes_mmc.c +++ b/src/mess/machine/nes_mmc.c @@ -209,24 +209,6 @@ READ8_MEMBER(nes_state::nes_nt_r) return m_nt_page[page].access[offset & 0x3ff]; } -WRITE8_MEMBER(nes_state::nes_low_mapper_w) -{ - if (!m_mmc_write_low.isnull()) - (m_mmc_write_low)(space, offset, data, mem_mask); - else - logerror("Unimplemented LOW mapper write, offset: %04x, data: %02x\n", offset + 0x4100, data); -} - -READ8_MEMBER(nes_state::nes_low_mapper_r) -{ - if (!m_mmc_read_low.isnull()) - return (m_mmc_read_low)(space, offset, mem_mask); - else - logerror("Unimplemented LOW mapper read, offset: %04x\n", offset + 0x4100); - - return 0; -} - /************************************************************* Helpers to handle MMC diff --git a/src/mess/machine/nes_slot.c b/src/mess/machine/nes_slot.c new file mode 100644 index 00000000000..3ac3bfaa356 --- /dev/null +++ b/src/mess/machine/nes_slot.c @@ -0,0 +1,1231 @@ +#include "emu.h" +#include "machine/nes_slot.h" + + +#define NES_BATTERY_SIZE 0x2000 + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NES_CART_SLOT = &device_creator; +const device_type FC_CART_SLOT = &device_creator; + + +//************************************************************************** +// NES cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_nes_cart_interface - constructor +//------------------------------------------------- + +device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_prg(NULL), + m_prgram(NULL), + m_vrom(NULL), + m_vram(NULL), + m_battery(NULL), + m_mapper_ram(NULL), + m_mapper_bram(NULL), + m_prg_size(0), + m_prgram_size(0), + m_vrom_size(0), + m_vram_size(0), + m_battery_size(0), + m_mapper_ram_size(0), + m_mapper_bram_size(0) +{ +} + + +//------------------------------------------------- +// ~device_nes_cart_interface - destructor +//------------------------------------------------- + +device_nes_cart_interface::~device_nes_cart_interface() +{ +} + +//------------------------------------------------- +// pointer allocators +//------------------------------------------------- + +void device_nes_cart_interface::prg_alloc(running_machine &machine, size_t size) +{ + if (m_prg == NULL) + { + m_prg = auto_alloc_array(machine, UINT8, size); + m_prg_size = size; + } +} + +void device_nes_cart_interface::prgram_alloc(running_machine &machine, size_t size) +{ + if (m_prgram == NULL) + { + m_prgram = auto_alloc_array(machine, UINT8, size); + m_prgram_size = size; + } +} + +void device_nes_cart_interface::vrom_alloc(running_machine &machine, size_t size) +{ + if (m_vrom == NULL) + { + m_vrom = auto_alloc_array(machine, UINT8, size); + m_vrom_size = size; + } +} + +void device_nes_cart_interface::vram_alloc(running_machine &machine, size_t size) +{ + if (m_vram == NULL) + { + m_vram = auto_alloc_array(machine, UINT8, size); + m_vram_size = size; + } +} + +void device_nes_cart_interface::battery_alloc(running_machine &machine, size_t size) +{ + if (m_battery == NULL) + { + m_battery = auto_alloc_array(machine, UINT8, size); + m_battery_size = size; + } +} + +void device_nes_cart_interface::mapper_ram_alloc(running_machine &machine, size_t size) +{ + if (m_mapper_ram == NULL) + { + m_mapper_ram = auto_alloc_array(machine, UINT8, size); + m_mapper_ram_size = size; + } +} + +void device_nes_cart_interface::mapper_bram_alloc(running_machine &machine, size_t size) +{ + if (m_mapper_bram == NULL) + { + m_mapper_bram = auto_alloc_array(machine, UINT8, size); + m_mapper_bram_size = size; + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// base_nes_cart_slot_device - constructor +//------------------------------------------------- +base_nes_cart_slot_device::base_nes_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_chr_open_bus(0), + m_ce_mask(0), + m_ce_state(0), + m_vrc_ls_prg_a(0), + m_vrc_ls_prg_b(0), + m_vrc_ls_chr(0), + m_crc_hack(0) +{ +} + +nes_cart_slot_device::nes_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_nes_cart_slot_device(mconfig, NES_CART_SLOT, "NES Cartridge Slot", tag, owner, clock) +{ +} + +fc_cart_slot_device::fc_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_nes_cart_slot_device(mconfig, FC_CART_SLOT, "FC Cartridge Slot", tag, owner, clock) +{ +} + +//------------------------------------------------- +// base_nes_cart_slot_device - destructor +//------------------------------------------------- + +base_nes_cart_slot_device::~base_nes_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void base_nes_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void base_nes_cart_slot_device::device_config_complete() +{ + // inherit a copy of the static data +// const nes_cart_interface *intf = reinterpret_cast(static_config()); +// if (intf != NULL) +// { +// *static_cast(this) = *intf; +// } + + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + + +struct nes_cart_lines +{ + const char *tag; + int line; +}; + +static const struct nes_cart_lines nes_cart_lines_table[] = +{ + { "PRG A0", 0 }, + { "PRG A1", 1 }, + { "PRG A2", 2 }, + { "PRG A3", 3 }, + { "PRG A4", 4 }, + { "PRG A5", 5 }, + { "PRG A6", 6 }, + { "PRG A7", 7 }, + { "CHR A10", 10 }, + { "CHR A11", 11 }, + { "CHR A12", 12 }, + { "CHR A13", 13 }, + { "CHR A14", 14 }, + { "CHR A15", 15 }, + { "CHR A16", 16 }, + { "CHR A17", 17 }, + { "NC", 127 }, + { 0 } +}; + +static int nes_cart_get_line( const char *feature ) +{ + const struct nes_cart_lines *nes_line = &nes_cart_lines_table[0]; + + if (feature == NULL) + return 128; + + while (nes_line->tag) + { + if (strcmp(nes_line->tag, feature) == 0) + break; + + nes_line++; + } + + return nes_line->line; +} + +/* Set to generate prg & chr files when the cart is loaded */ +#define SPLIT_PRG 0 +#define SPLIT_CHR 0 + +bool base_nes_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_ram_size = 0, mapper_bram_size = 0; // helper for regions to alloc at the end + + if (software_entry() == NULL) + { + const char *mapinfo = NULL; + int mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0; + char magic[4]; + + /* Check first 4 bytes of the image to decide if it is UNIF or iNES */ + /* Unfortunately, many .unf files have been released as .nes, so we cannot rely on extensions only */ + memset(magic, '\0', sizeof(magic)); + fread(magic, 4); + + if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */ + { + UINT32 prg_size, vrom_size; + UINT8 header[0x10]; + UINT8 mapper, local_options; + bool ines20 = FALSE, has_trainer = FALSE, prg16k; + + // check if the image is recognized by nes.hsi +// mapinfo = hashfile_extrainfo(image); + + // image_extrainfo() resets the file position back to start. + fseek(0, SEEK_SET); + // read out the header + fread(&header, 0x10); + + // SETUP step 1: getting PRG, VROM, VRAM sizes + prg16k = (header[4] == 1); + prg_size = prg16k ? 2 * 0x4000 : header[4] * 0x4000; + vrom_size = header[5] * 0x2000; + vram_size = 0x4000; + + // SETUP step 2: getting PCB and other settings + mapper = (header[6] & 0xf0) >> 4; + local_options = header[6] & 0x0f; + + switch (header[7] & 0xc) + { + case 0x4: + case 0xc: + // probably the header got corrupted: don't trust upper bits for mapper + break; + + case 0x8: // it's iNES 2.0 format + ines20 = TRUE; + case 0x0: + default: + mapper |= header[7] & 0xf0; + break; + } + + // use info from nes.hsi if available! + if (mapinfo) + { + if (4 == sscanf(mapinfo,"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4)) + { + /* image is present in nes.hsi: overwrite the header settings with these */ + mapper = mapint1; + local_options = mapint2 & 0x0f; + m_crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below) + prg_size = mapint3 * 0x4000; + vrom_size = mapint4 * 0x2000; + logerror("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); +// mame_printf_error("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); + } + else + { + logerror("NES: [%s], Invalid mapinfo found\n", mapinfo); + } + } + else + { + logerror("NES: No extrainfo found\n"); + } + + // use extended iNES2.0 info if available! + if (ines20) + { + mapper |= (header[8] & 0x0f) << 8; + // header[8] & 0xf0 is used for submappers, but I haven't found any specific image to implement this + prg_size += ((header[9] & 0x0f) << 8) * 0x4000; + vrom_size += ((header[9] & 0xf0) << 4) * 0x2000; + } + + // SETUP step 3: storing the info needed for emulation + m_pcb_id = nes_get_mmc_id(machine(), mapper); + m_cart->set_mirroring(BIT(local_options, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + if (BIT(local_options, 1)) + battery_size = NES_BATTERY_SIZE; // with original iNES format we can only support 8K WRAM battery + has_trainer = BIT(local_options, 2) ? TRUE : FALSE; + m_cart->set_four_screen_vram(BIT(local_options, 3)); + + if (ines20) + { + // PRGRAM/BWRAM (not fully supported, also due to lack of 2.0 files) + if ((header[10] & 0x0f) > 0) + prgram_size = 0x80 << ((header[10] & 0x0f) - 1); + if ((header[10] & 0xf0) > 0) + battery_size = 0x80 << ((header[10] & 0xf0) - 5); + // VRAM + vram_size = 0; + if ((header[11] & 0x0f) > 0) + vram_size = 0x80 << ((header[11] & 0x0f) - 1); + // header[11] & 0xf0 is the size of battery backed VRAM, found so far in Racermate II only and not supported yet + } + else + { + // always map PRGRAM/WRAM in bank5 (eventually, this should be enabled only for some mappers) + // and save it depending on has_battery + + // PRGRAM size is 8k for most games, but pirate carts often use different sizes, + // so its size has been added recently to the iNES format spec, but almost no image uses it + prgram_size = header[8] ? header[8] * 0x2000 : 0x2000; + } + + // a few mappers correspond to multiple PCBs, so we need a few additional checks and tweaks + switch (m_pcb_id) + { + case STD_CNROM: + if (mapper == 185) + { + switch (m_crc_hack) + { + case 0x0: // pin26: CE, pin27: CE (B-Wings, Bird Week) + m_ce_mask = 0x03; + m_ce_state = 0x03; + break; + case 0x4: // pin26: CE, pin27: /CE (Mighty Bomb Jack, Spy Vs. Spy) + m_ce_mask = 0x03; + m_ce_state = 0x01; + break; + case 0x8: // pin26: /CE, pin27: CE (Sansu 1, 2, 3 Nen) + m_ce_mask = 0x03; + m_ce_state = 0x02; + break; + case 0xc: // pin26: /CE, pin27: /CE (Seicross v2.0) + m_ce_mask = 0x03; + m_ce_state = 0x00; + break; + } + } + break; + case KONAMI_VRC2: + if (mapper == 22) + { + m_vrc_ls_prg_a = 0; + m_vrc_ls_prg_b = 1; + m_vrc_ls_chr = 1; + } + if (mapper == 23 && !m_crc_hack) + { + m_vrc_ls_prg_a = 1; + m_vrc_ls_prg_b = 0; + m_vrc_ls_chr = 0; + } + if (mapper == 23 && m_crc_hack) + { + // here there are also Akumajou Special, Crisis Force, Parodius da!, Tiny Toons which are VRC-4 + m_vrc_ls_prg_a = 3; + m_vrc_ls_prg_b = 2; + m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset + } + break; + case KONAMI_VRC4: + if (mapper == 21) + { + // Wai Wai World 2 & Ganbare Goemon Gaiden 2 (the latter with crc_hack) + m_vrc_ls_prg_a = m_crc_hack ? 7 : 2; + m_vrc_ls_prg_b = m_crc_hack ? 6 : 1; + } + if (mapper == 25) // here there is also Ganbare Goemon Gaiden which is VRC-2 + { + m_vrc_ls_prg_a = m_crc_hack ? 2 : 0; + m_vrc_ls_prg_b = m_crc_hack ? 3 : 1; + } + break; + case KONAMI_VRC6: + if (mapper == 24) + { + m_vrc_ls_prg_a = 1; + m_vrc_ls_prg_b = 0; + } + if (mapper == 26) + { + m_vrc_ls_prg_a = 0; + m_vrc_ls_prg_b = 1; + } + break; + case IREM_G101: + if (m_crc_hack) + m_cart->set_mirroring(PPU_MIRROR_HIGH); // Major League has hardwired mirroring + break; + case DIS_74X161X161X32: + if (mapper == 70) + m_cart->set_mirroring(PPU_MIRROR_VERT); // only hardwired mirroring makes different mappers 70 & 152 + break; + case SUNSOFT_2: + if (mapper == 93) + m_cart->set_mirroring(PPU_MIRROR_VERT); // only hardwired mirroring makes different mappers 89 & 93 + break; + case STD_BXROM: + if (m_crc_hack) + m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards + break; + case BANDAI_LZ93: + if (m_crc_hack) + m_pcb_id = BANDAI_JUMP2; // Mapper 153 is used for 2 diff boards + break; + case IREM_HOLYDIV: + if (m_crc_hack) + m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards + break; + case CAMERICA_BF9093: + if (m_crc_hack) + m_pcb_id = CAMERICA_BF9097; // Mapper 71 is used for 2 diff boards + break; + case HES_BOARD: + if (m_crc_hack) + m_pcb_id = HES6IN1_BOARD; // Mapper 113 is used for 2 diff boards + break; + case WAIXING_ZS: + if (m_crc_hack) + m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards + break; + case BMC_GOLD_7IN1: + if (m_crc_hack) + m_pcb_id = BMC_MARIOPARTY_7IN1; // Mapper 52 is used for 2 diff boards + break; + case STD_EXROM: + mapper_ram_size = 0x400; + break; + case TAITO_X1_017: + mapper_ram_size = 0x1400; + break; + case TAITO_X1_005: + case TAITO_X1_005_A: + mapper_ram_size = 0x80; + break; + case NAMCOT_163: + mapper_ram_size = 0x2000; + break; + case FUKUTAKE_BOARD: + mapper_ram_size = 2816; + break; + //FIXME: we also have to fix Action 52 PRG loading somewhere... + } + + // SETUP step 4: logging what we have found + if (!ines20) + { + logerror("Loaded game in iNES format:\n"); + logerror("-- Mapper %d\n", mapper); + logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); + logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); + logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); + if (battery_size) + logerror("-- Battery found\n"); + if (has_trainer) + logerror("-- Trainer found\n"); + if (m_cart->get_four_screen_vram()) + logerror("-- 4-screen VRAM\n"); + logerror("-- TV System: %s\n", ((header[10] & 3) == 0) ? "NTSC" : (header[10] & 1) ? "Both NTSC and PAL" : "PAL"); + } + else + { + logerror("Loaded game in Extended iNES format:\n"); + logerror("-- Mapper: %d\n", mapper); + logerror("-- Submapper: %d\n", (header[8] & 0xf0) >> 4); + logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); + logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); + logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); + logerror("-- PRG NVWRAM: %d\n", header[10] & 0x0f); + logerror("-- PRG WRAM: %d\n", (header[10] & 0xf0) >> 4); + logerror("-- CHR NVWRAM: %d\n", header[11] & 0x0f); + logerror("-- CHR WRAM: %d\n", (header[11] & 0xf0) >> 4); + logerror("-- TV System: %s\n", (header[12] & 2) ? "Both NTSC and PAL" : (header[12] & 1) ? "PAL" : "NTSC"); + } + + // SETUP step 5: allocate pointers for PRG/VROM + if (prg_size) + m_cart->prg_alloc(machine(), prg_size); + if (vrom_size) + m_cart->vrom_alloc(machine(), vrom_size); + + if (has_trainer) + fread(&m_cart->m_prgram[0x1000], 0x200); + + + // SETUP step 6: at last load the data! + // Read in the program chunks + if (prg16k) + { + fread(m_cart->get_prg_base(), 0x4000); + memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000); + } + else + fread(m_cart->get_prg_base(), m_cart->get_prg_size()); +#if SPLIT_PRG + { + FILE *prgout; + char outname[255]; + + sprintf(outname, "%s.prg", filename()); + prgout = fopen(outname, "wb"); + if (prgout) + { + fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout); + mame_printf_error("Created PRG chunk\n"); + } + + fclose(prgout); + } +#endif + + // Read in any chr chunks + if (m_cart->get_vrom_size()) + fread(m_cart->get_vrom_base(), m_cart->get_vrom_size()); + +#if SPLIT_CHR + if (state->m_chr_chunks > 0) + { + FILE *chrout; + char outname[255]; + + sprintf(outname, "%s.chr", filename()); + chrout= fopen(outname, "wb"); + if (chrout) + { + fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout); + mame_printf_error("Created CHR chunk\n"); + } + fclose(chrout); + } +#endif + } + else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */ + { + // SETUP step 1: running through the file and getting PRG, VROM sizes + UINT32 unif_ver = 0, chunk_length = 0, read_length = 0x20; + UINT32 prg_start = 0, chr_start = 0; + UINT32 size = length(), prg_size = 0, vrom_size = 0; + UINT8 buffer[4], mirror = 0; + char magic2[4]; + char unif_mapr[32]; // here we should store MAPR chunks + bool mapr_chunk_found = FALSE, small_prg = FALSE; + + // allocate space to temporarily store PRG & CHR banks + UINT8 *temp_prg = auto_alloc_array(machine(), UINT8, 256 * 0x4000); + UINT8 *temp_chr = auto_alloc_array(machine(), UINT8, 256 * 0x2000); + UINT8 temp_byte = 0; + + fread(&buffer, 4); + unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + logerror("Loaded game in UNIF format, version %d\n", unif_ver); + + if (size <= 0x20) + { + logerror("%s only contains the UNIF header and no data.\n", filename()); + return IMAGE_INIT_FAIL; + } + + do + { + fseek(read_length, SEEK_SET); + + memset(magic2, '\0', sizeof(magic2)); + fread(&magic2, 4); + + /* We first run through the whole image to find a [MAPR] chunk. This is needed + because, unfortunately, the MAPR chunk is not always the first chunk (see + Super 24-in-1). When such a chunk is found, we set mapr_chunk_found=1 and + we go back to load other chunks! */ + if (!mapr_chunk_found) + { + if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) + { + mapr_chunk_found = TRUE; + logerror("[MAPR] chunk found: "); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + if (chunk_length <= 0x20) + fread(&unif_mapr, chunk_length); + logerror("%s\n", unif_mapr); + + /* now that we found the MAPR chunk, we can go back to load other chunks */ + fseek(0x20, SEEK_SET); + read_length = 0x20; + } + else + { + logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + } + else + { + /* What kind of chunk do we have here? */ + if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) + { + /* The [MAPR] chunk has already been read, so we skip it */ + /* TO DO: it would be nice to check if more than one MAPR chunk is present */ + logerror("[MAPR] chunk found (in the 2nd run). Already loaded.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'R') && (magic2[1] == 'E') && (magic2[2] == 'A') && (magic2[3] == 'D')) + { + logerror("[READ] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'N') && (magic2[1] == 'A') && (magic2[2] == 'M') && (magic2[3] == 'E')) + { + logerror("[NAME] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'W') && (magic2[1] == 'R') && (magic2[2] == 'T') && (magic2[3] == 'R')) + { + logerror("[WRTR] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'C') && (magic2[3] == 'I')) + { + logerror("[TVCI] chunk found.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + fread(&temp_byte, 1); + logerror("Television Standard : %s\n", (temp_byte == 0) ? "NTSC" : (temp_byte == 1) ? "PAL" : "Does not matter"); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'S') && (magic2[3] == 'C')) // is this the same as TVCI?? + { + logerror("[TVSC] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'D') && (magic2[1] == 'I') && (magic2[2] == 'N') && (magic2[3] == 'F')) + { + logerror("[DINF] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'C') && (magic2[1] == 'T') && (magic2[2] == 'R') && (magic2[3] == 'L')) + { + logerror("[CTRL] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'B') && (magic2[1] == 'A') && (magic2[2] == 'T') && (magic2[3] == 'R')) + { + logerror("[BATR] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'V') && (magic2[1] == 'R') && (magic2[2] == 'O') && (magic2[3] == 'R')) + { + logerror("[VROR] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'M') && (magic2[1] == 'I') && (magic2[2] == 'R') && (magic2[3] == 'R')) + { + logerror("[MIRR] chunk found.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + fread(&mirror, 1); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'P') && (magic2[1] == 'C') && (magic2[2] == 'K')) + { + logerror("[PCK%c] chunk found. No support yet.\n", magic2[3]); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'C') && (magic2[1] == 'C') && (magic2[2] == 'K')) + { + logerror("[CCK%c] chunk found. No support yet.\n", magic2[3]); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'P') && (magic2[1] == 'R') && (magic2[2] == 'G')) + { + logerror("[PRG%c] chunk found. ", magic2[3]); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + prg_size += chunk_length; + + if (chunk_length / 0x4000) + logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000); + else + { + small_prg = TRUE; + logerror("This chunk is smaller than 16K: the emulation might have issues. Please report this file to the MESS forums.\n"); + } + + /* Read in the program chunks */ + fread(&temp_prg[prg_start], chunk_length); + + prg_start += chunk_length; + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'C') && (magic2[1] == 'H') && (magic2[2] == 'R')) + { + logerror("[CHR%c] chunk found. ", magic2[3]); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + vrom_size += chunk_length; + + logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000); + + /* Read in the vrom chunks */ + fread(&temp_chr[chr_start], chunk_length); + + chr_start += chunk_length; + read_length += (chunk_length + 8); + } + else + { + logerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); + read_length = size; + } + } + } while (size > read_length); + + if (!mapr_chunk_found) + { + auto_free(machine(), temp_prg); + auto_free(machine(), temp_chr); + fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted\n"); + } + + if (!prg_start) + { + auto_free(machine(), temp_prg); + auto_free(machine(), temp_chr); + fatalerror("No PRG found. Please report the problem at MESS Board.\n"); + } + + // SETUP step 2: getting PCB and other settings + int pcb_id = 0, battery = 0, prgram = 0, vram_chunks = 0; + unif_mapr_setup(unif_mapr, &pcb_id, &battery, &prgram, &vram_chunks); + + // SETUP step 3: storing the info needed for emulation + m_pcb_id = pcb_id; + if (battery) + battery_size = NES_BATTERY_SIZE; // we should allow for smaller battery! + prgram_size = prgram * 0x2000; + vram_size = vram_chunks * 0x2000; + + m_cart->set_four_screen_vram(0); + switch (mirror) + { + case 0: // Horizontal Mirroring (Hard Wired) + m_cart->set_mirroring(PPU_MIRROR_HORZ); + break; + case 1: // Vertical Mirroring (Hard Wired) + m_cart->set_mirroring(PPU_MIRROR_VERT); + break; + case 2: // Mirror All Pages From $2000 (Hard Wired) + m_cart->set_mirroring(PPU_MIRROR_LOW); + break; + case 3: // Mirror All Pages From $2400 (Hard Wired) + m_cart->set_mirroring(PPU_MIRROR_HIGH); + break; + case 4: // Four Screens of VRAM (Hard Wired) + m_cart->set_four_screen_vram(1); + break; + case 5: // Mirroring Controlled By Mapper Hardware + logerror("Mirroring handled by the board hardware.\n"); + // default to horizontal at start + m_cart->set_mirroring(PPU_MIRROR_HORZ); + break; + default: + logerror("Undocumented mirroring value.\n"); + // default to horizontal + m_cart->set_mirroring(PPU_MIRROR_HORZ); + break; + } + + // SETUP step 4: logging what we have found + logerror("-- Board %s\n", unif_mapr); + logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); + logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); + logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); + + // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data! + if (prg_size == 0x4000) + { + m_cart->prg_alloc(machine(), 0x8000); + memcpy(m_cart->get_prg_base(), temp_prg, 0x4000); + memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000); + } + else + { + m_cart->prg_alloc(machine(), prg_size); + memcpy(m_cart->get_prg_base(), temp_prg, prg_size); + } + + if (small_prg) // This is not supported yet, so warn users about this + mame_printf_error("Loaded UNIF file with non-16k PRG chunk. This is not supported in MESS yet."); + + if (vrom_size) + { + m_cart->vrom_alloc(machine(), vrom_size); + memcpy(m_cart->get_vrom_base(), temp_chr, vrom_size); + } + +#if SPLIT_PRG + { + FILE *prgout; + char outname[255]; + + sprintf(outname, "%s.prg", filename()); + prgout = fopen(outname, "wb"); + if (prgout) + { + fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout); + mame_printf_error("Created PRG chunk\n"); + } + + fclose(prgout); + } +#endif + +#if SPLIT_CHR + if (state->m_chr_chunks > 0) + { + FILE *chrout; + char outname[255]; + + sprintf(outname, "%s.chr", filename()); + chrout= fopen(outname, "wb"); + if (chrout) + { + fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout); + mame_printf_error("Created CHR chunk\n"); + } + fclose(chrout); + } +#endif + // free the temporary copy of PRG/CHR + auto_free(machine(), temp_prg); + auto_free(machine(), temp_chr); + logerror("UNIF support is only very preliminary.\n"); + } + else + { + logerror("%s is NOT a file in either iNES or UNIF format.\n", filename()); + return IMAGE_INIT_FAIL; + } + } + else + { + // SETUP step 1: getting PRG, VROM, VRAM sizes + UINT32 prg_size = get_software_region_length("prg"); + UINT32 vrom_size = get_software_region_length("chr"); + UINT32 vram_size = get_software_region_length("vram"); + vram_size += get_software_region_length("vram2"); + + // validate the xml fields + if (!prg_size) + fatalerror("No PRG entry for this software! Please check if the xml list got corrupted\n"); + if (prg_size < 0x8000) + fatalerror("PRG entry is too small! Please check if the xml list got corrupted\n"); + + // SETUP step 2: getting PCB and other settings + if (get_feature("pcb")) + m_pcb_id = nes_get_pcb_id(machine(), get_feature("pcb")); + else + m_pcb_id = NO_BOARD; + + // SETUP step 3: storing the info needed for emulation + if (m_pcb_id == STD_TVROM || m_pcb_id == STD_DRROM || m_pcb_id == IREM_LROG017) + m_cart->set_four_screen_vram(1); + else + m_cart->set_four_screen_vram(0); + + if (get_software_region("bwram") != NULL) + battery_size = get_software_region_length("bwram"); + + if (m_pcb_id == BANDAI_LZ93EX) + { + // allocate the 24C01 or 24C02 EEPROM + battery_size += 0x2000; + } + + if (m_pcb_id == BANDAI_DATACH) + { + // allocate the 24C01 and 24C02 EEPROM + battery_size += 0x4000; + } + + if (get_software_region("wram") != NULL) + prgram_size = get_software_region_length("wram"); + if (get_software_region("mapper_ram") != NULL) + mapper_ram_size = get_software_region_length("mapper_ram"); + if (get_software_region("mapper_bram") != NULL) + mapper_bram_size = get_software_region_length("mapper_bram"); + + if (get_feature("mirroring")) + { + const char *mirroring = get_feature("mirroring"); + if (!strcmp(mirroring, "horizontal")) + m_cart->set_mirroring(PPU_MIRROR_HORZ); + if (!strcmp(mirroring, "vertical")) + m_cart->set_mirroring(PPU_MIRROR_VERT); + if (!strcmp(mirroring, "high")) + m_cart->set_mirroring(PPU_MIRROR_HIGH); + if (!strcmp(mirroring, "low")) + m_cart->set_mirroring(PPU_MIRROR_LOW); + } + else + m_cart->set_mirroring(PPU_MIRROR_NONE); + + /* Check for pins in specific boards which require them */ + if (m_pcb_id == STD_CNROM) + { + if (get_feature("chr-pin26") != NULL) + { + m_ce_mask |= 0x01; + m_ce_state |= !strcmp(get_feature("chr-pin26"), "CE") ? 0x01 : 0; + } + if (get_feature("chr-pin27") != NULL) + { + m_ce_mask |= 0x02; + m_ce_state |= !strcmp(get_feature("chr-pin27"), "CE") ? 0x02 : 0; + } + } + + if (m_pcb_id == TAITO_X1_005 && get_feature("x1-pin17") != NULL && get_feature("x1-pin31") != NULL) + { + if (!strcmp(get_feature("x1-pin17"), "CIRAM A10") && !strcmp(get_feature("x1-pin31"), "NC")) + m_pcb_id = TAITO_X1_005_A; + } + + if (m_pcb_id == KONAMI_VRC2) + { + m_vrc_ls_prg_a = nes_cart_get_line(get_feature("vrc2-pin3")); + m_vrc_ls_prg_b = nes_cart_get_line(get_feature("vrc2-pin4")); + m_vrc_ls_chr = (nes_cart_get_line(get_feature("vrc2-pin21")) != 10) ? 1 : 0; +// mame_printf_error("VRC-2, pin3: A%d, pin4: A%d, pin21: %s\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b, state->m_vrc_ls_chr ? "NC" : "A10"); + } + + if (m_pcb_id == KONAMI_VRC4) + { + m_vrc_ls_prg_a = nes_cart_get_line(get_feature("vrc4-pin3")); + m_vrc_ls_prg_b = nes_cart_get_line(get_feature("vrc4-pin4")); +// mame_printf_error("VRC-4, pin3: A%d, pin4: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b); + } + + if (m_pcb_id == KONAMI_VRC6) + { + m_vrc_ls_prg_a = nes_cart_get_line(get_feature("vrc6-pin9")); + m_vrc_ls_prg_b = nes_cart_get_line(get_feature("vrc6-pin10")); +// mame_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b); + } + + /* Check for other misc board variants */ + if (m_pcb_id == STD_SOROM) + { + if (get_feature("mmc1_type") != NULL && !strcmp(get_feature("mmc1_type"), "MMC1A")) + m_pcb_id = STD_SOROM_A; // in MMC1-A PRG RAM is always enabled + } + + if (m_pcb_id == STD_SXROM) + { + if (get_feature("mmc1_type") != NULL && !strcmp(get_feature("mmc1_type"), "MMC1A")) + m_pcb_id = STD_SXROM_A; // in MMC1-A PRG RAM is always enabled + } + + if (m_pcb_id == STD_NXROM || m_pcb_id == SUNSOFT_DCS) + { + if (get_software_region("minicart") != NULL) // check for dual minicart + { + m_pcb_id = SUNSOFT_DCS; + // we shall load somewhere the minicart, but we still do not support this + } + } + + // SETUP step 4: logging what we have found + logerror("Loaded game from softlist:\n"); + logerror("-- PCB: %s", get_feature("pcb")); + if (m_pcb_id == UNSUPPORTED_BOARD) + logerror(" (currently not supported by MESS)"); + logerror("\n-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); + logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); + logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); + logerror("-- PRG NVWRAM: %d\n", m_cart->get_battery_size()); + logerror("-- PRG WRAM: %d\n", m_cart->get_prgram_size()); + + // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data! + m_cart->prg_alloc(machine(), prg_size); + memcpy(m_cart->get_prg_base(), get_software_region("prg"), prg_size); + if (vrom_size) + { + m_cart->vrom_alloc(machine(), vrom_size); + memcpy(m_cart->get_vrom_base(), get_software_region("chr"), vrom_size); + } + } + + // Allocate the remaining pointer, when needed + if (vram_size) + m_cart->vram_alloc(machine(), vram_size); + if (prgram_size) + m_cart->prgram_alloc(machine(), prgram_size); + if (mapper_ram_size) + m_cart->mapper_ram_alloc(machine(), mapper_ram_size); + + // Attempt to load a battery file for this ROM + // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.) + if (battery_size || mapper_bram_size) + { + UINT32 tot_size = battery_size + mapper_bram_size; + UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size); + battery_load(temp_nvram, tot_size, 0x00); + if (battery_size) + { + m_cart->battery_alloc(machine(), battery_size); + memcpy(m_cart->get_battery_base(), temp_nvram, battery_size); + } + if (mapper_bram_size) + { + m_cart->mapper_bram_alloc(machine(), mapper_bram_size); + memcpy(m_cart->get_mapper_bram_base(), temp_nvram + battery_size, mapper_bram_size); + } + + if (temp_nvram) + auto_free(machine(), temp_nvram); + } + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unloadload + -------------------------------------------------*/ + +void base_nes_cart_slot_device::call_unload() +{ + if (m_cart->get_battery_size()) + battery_save(m_cart->get_battery_base(), m_cart->get_battery_size()); + if (m_cart->get_mapper_bram_size()) + battery_save(m_cart->get_mapper_bram_base(), m_cart->get_mapper_bram_size()); +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool base_nes_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 default card software + -------------------------------------------------*/ + +const char * base_nes_cart_slot_device::get_default_card_software(const machine_config &config, emu_options &options) +{ + return software_get_default_slot(config, options, this, "rom"); +} + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(base_nes_cart_slot_device::read_l) +{ + if (m_cart) + return m_cart->read_l(space, offset); + else + return 0xff; +} + +READ8_MEMBER(base_nes_cart_slot_device::read_m) +{ + if (m_cart) + return m_cart->read_m(space, offset); + else + return 0xff; +} + +READ8_MEMBER(base_nes_cart_slot_device::read_h) +{ + if (m_cart) + return m_cart->read_h(space, offset); + else + return 0xff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(base_nes_cart_slot_device::write_l) +{ + if (m_cart) + m_cart->write_l(space, offset, data); +} + +WRITE8_MEMBER(base_nes_cart_slot_device::write_m) +{ + if (m_cart) + m_cart->write_m(space, offset, data); +} + +WRITE8_MEMBER(base_nes_cart_slot_device::write_h) +{ + if (m_cart) + m_cart->write_h(space, offset, data); +} + + +// CART DEVICE [TO BE MOVED TO SEPARATE SOURCE LATER] + +//------------------------------------------------- +// nes_rom_device - constructor +//------------------------------------------------- + +const device_type NES_ROM = &device_creator; + +nes_rom_device::nes_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_ROM, "NES ROM", tag, owner, clock), + device_nes_cart_interface( mconfig, *this ) +{ +} + +nes_rom_device::nes_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_nes_cart_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nes_rom_device::device_start() +{ +} + diff --git a/src/mess/machine/nes_slot.h b/src/mess/machine/nes_slot.h new file mode 100644 index 00000000000..93f0d8295ec --- /dev/null +++ b/src/mess/machine/nes_slot.h @@ -0,0 +1,230 @@ +#ifndef __NES_SLOT_H__ +#define __NES_SLOT_H__ + +#include "includes/nes_mmc.h" + + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +// ======================> nes_cart_interface + +struct nes_cart_interface +{ +}; + + +// ======================> device_nes_cart_interface + +class device_nes_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_nes_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_nes_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_m) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_h) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_l) { } + virtual DECLARE_WRITE8_MEMBER(write_m) { } + virtual DECLARE_WRITE8_MEMBER(write_h) { } + + virtual void prg_alloc(running_machine &machine, size_t size); + virtual void prgram_alloc(running_machine &machine, size_t size); + virtual void vrom_alloc(running_machine &machine, size_t size); + virtual void vram_alloc(running_machine &machine, size_t size); + virtual void battery_alloc(running_machine &machine, size_t size); + virtual void mapper_ram_alloc(running_machine &machine, size_t size); + virtual void mapper_bram_alloc(running_machine &machine, size_t size); + + virtual int get_mirroring() { return m_mirroring; } + virtual void set_mirroring(int val) { m_mirroring = val; } + virtual int get_four_screen_vram() { return m_four_screen_vram; } + virtual void set_four_screen_vram(int val) { m_four_screen_vram = val; } + + virtual UINT8* get_prg_base() { return m_prg; } + virtual UINT8* get_prgram_base() { return m_prgram; } + virtual UINT8* get_vrom_base() { return m_vrom; } + virtual UINT8* get_vram_base() { return m_vram; } + virtual UINT8* get_battery_base() { return m_battery; } + virtual UINT8* get_mapper_ram_base() { return m_mapper_ram; } + virtual UINT8* get_mapper_bram_base() { return m_mapper_bram; } + + virtual UINT32 get_prg_size() { return m_prg_size; } + virtual UINT32 get_prgram_size() { return m_prgram_size; } + virtual UINT32 get_vrom_size() { return m_vrom_size; } + virtual UINT32 get_vram_size() { return m_vram_size; } + virtual UINT32 get_battery_size() { return m_battery_size; } + virtual UINT32 get_mapper_ram_size() { return m_mapper_ram_size; } + virtual UINT32 get_mapper_bram_size() { return m_mapper_bram_size; } + +//private: + + // internal state + UINT8 *m_prg; + UINT8 *m_prgram; + UINT8 *m_vrom; + UINT8 *m_vram; + UINT8 *m_battery; + UINT8 *m_mapper_ram; + UINT8 *m_mapper_bram; + + UINT32 m_prg_size; + UINT32 m_prgram_size; + UINT32 m_vrom_size; + UINT32 m_vram_size; + UINT32 m_battery_size; + UINT32 m_mapper_ram_size; + UINT32 m_mapper_bram_size; + + int m_mirroring, m_four_screen_vram; + bool m_has_battery, m_has_prgram; +}; + + +// ======================> nes_cart_slot_device + +class base_nes_cart_slot_device : public device_t, + public nes_cart_interface, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + base_nes_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + virtual ~base_nes_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 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 1; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return "nes_cart"; } + virtual const char *file_extensions() const { return "nes,unf,unif"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // 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_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + int get_pcb_id() { return m_pcb_id; }; + + // temporarily here + int m_chr_open_bus; + int m_ce_mask; + int m_ce_state; + int m_vrc_ls_prg_a; + int m_vrc_ls_prg_b; + int m_vrc_ls_chr; + int m_crc_hack; + + virtual int get_chr_open_bus() { return m_chr_open_bus; }; + virtual int get_ce_mask() { return m_ce_mask; }; + virtual int get_ce_state() { return m_ce_state; }; + virtual int get_vrc_ls_prg_a() { return m_vrc_ls_prg_a; }; + virtual int get_vrc_ls_prg_b() { return m_vrc_ls_prg_b; }; + virtual int get_vrc_ls_chr() { return m_vrc_ls_chr; }; + virtual int get_crc_hack() { return m_crc_hack; }; + + //private: + + device_nes_cart_interface* m_cart; + int m_pcb_id; +}; + +// ======================> nes_cart_slot_device + +class nes_cart_slot_device : public base_nes_cart_slot_device +{ +public: + // construction/destruction + nes_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual bool must_be_loaded() const { return 1; } +}; + + +// ======================> fc_cart_slot_device + +class fc_cart_slot_device : public base_nes_cart_slot_device +{ +public: + // construction/destruction + fc_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual bool must_be_loaded() const { return 0; } +}; + + +// device type definition +extern const device_type NES_CART_SLOT; +extern const device_type FC_CART_SLOT; // same but not mandatory + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define MCFG_NES_CARTRIDGE_ADD(_tag,_config,_slot_intf,_def_slot,_def_inp) \ + MCFG_DEVICE_ADD(_tag, NES_CART_SLOT, 0) \ + MCFG_DEVICE_CONFIG(_config) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) + +#define MCFG_FC_CARTRIDGE_ADD(_tag,_config,_slot_intf,_def_slot,_def_inp) \ + MCFG_DEVICE_ADD(_tag, FC_CART_SLOT, 0) \ + MCFG_DEVICE_CONFIG(_config) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) + + +// CART DEVICE [TO BE MOVED TO SEPARATE SOURCE LATER] + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_rom_device + +class nes_rom_device : public device_t, + public device_nes_cart_interface +{ +public: + // construction/destruction + nes_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nes_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + + //protected: + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { m_shortname = "nes_rom"; } + + // nescart_interface overrides +// virtual DECLARE_READ8_MEMBER(read_l); +// virtual DECLARE_READ8_MEMBER(read_m); +// virtual DECLARE_READ8_MEMBER(read_h); +// virtual DECLARE_WRITE8_MEMBER(write_l); +// virtual DECLARE_WRITE8_MEMBER(write_m); +// virtual DECLARE_WRITE8_MEMBER(write_h); +}; + +// device type definition +extern const device_type NES_ROM; + +#endif diff --git a/src/mess/machine/nes_unif.c b/src/mess/machine/nes_unif.c index 9492ab78637..08d963ba7fc 100644 --- a/src/mess/machine/nes_unif.c +++ b/src/mess/machine/nes_unif.c @@ -158,25 +158,20 @@ const unif *nes_unif_lookup( const char *board ) *************************************************************/ -void unif_mapr_setup( running_machine &machine, const char *board ) +void unif_mapr_setup( const char *board, int *pcb_id, int *battery, int *prgram, int *vram_chunks ) { - nes_state *state = machine.driver_data(); - const unif *unif_board = nes_unif_lookup(board); - - logerror("%s\n", board); - + const unif *unif_board = nes_unif_lookup(board); if (unif_board == NULL) fatalerror("Unknown UNIF board %s.\n", board); - - state->m_pcb_id = unif_board->board_idx; - state->m_battery = unif_board->nvwram; // we should implement battery banks based on the size of this... - state->m_battery_size = NES_BATTERY_SIZE; // FIXME: we should allow for smaller battery! - state->m_prg_ram = unif_board->wram; // we should implement WRAM banks based on the size of this... - + + *pcb_id = unif_board->board_idx; + *battery = unif_board->nvwram; // we should implement battery banks based on the size of this... + *prgram = unif_board->wram; // we should implement WRAM banks based on the size of this... + if (unif_board->chrram <= CHRRAM_8) - state->m_vram_chunks = 1; + *vram_chunks = 1; else if (unif_board->chrram == CHRRAM_16) - state->m_vram_chunks = 2; + *vram_chunks = 2; else if (unif_board->chrram == CHRRAM_32) - state->m_vram_chunks = 4; + *vram_chunks = 4; } diff --git a/src/mess/mess.mak b/src/mess/mess.mak index 1deeea114b8..ad738f3284a 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -1417,6 +1417,7 @@ $(MESSOBJ)/next.a: \ $(MESSOBJ)/nintendo.a: \ $(MESS_MACHINE)/nes_mmc.o \ + $(MESS_MACHINE)/nes_slot.o \ $(MESS_VIDEO)/nes.o \ $(MESS_MACHINE)/nes.o \ $(MESS_DRIVERS)/nes.o \