diff options
Diffstat (limited to 'src/devices/bus/nes/nes_slot.cpp')
-rw-r--r-- | src/devices/bus/nes/nes_slot.cpp | 328 |
1 files changed, 97 insertions, 231 deletions
diff --git a/src/devices/bus/nes/nes_slot.cpp b/src/devices/bus/nes/nes_slot.cpp index ab8235ccc55..d7df07d7693 100644 --- a/src/devices/bus/nes/nes_slot.cpp +++ b/src/devices/bus/nes/nes_slot.cpp @@ -107,7 +107,7 @@ DEFINE_DEVICE_TYPE(NES_CART_SLOT, nes_cart_slot_device, "nes_cart_slot", "NES Ca //------------------------------------------------- device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconfig, device_t &device) - : device_slot_card_interface(mconfig, device) + : device_interface(device, "nescart") , m_prg(nullptr) , m_vrom(nullptr) , m_ciram(nullptr) @@ -117,13 +117,20 @@ device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconf // main NES CPU here, even if it does not belong to this device. , m_maincpu(*this, ":maincpu") , m_mapper_sram(nullptr) + , m_misc_rom(nullptr) , m_mapper_sram_size(0) + , m_misc_rom_size(0) , m_ce_mask(0) , m_ce_state(0) + , m_mmc1_type(mmc1_type::MMC1B) , m_vrc_ls_prg_a(0) , m_vrc_ls_prg_b(0) , m_vrc_ls_chr(0) - , m_mirroring(PPU_MIRROR_NONE) + , m_n163_vol(0) + , m_outer_prg_size(0) + , m_outer_chr_size(0) + , m_smd133_addr(0x6000) + , m_mirroring(PPU_MIRROR_HORZ) , m_pcb_ctrl_mirror(false) , m_four_screen_vram(false) , m_has_trainer(false) @@ -151,11 +158,11 @@ device_nes_cart_interface::~device_nes_cart_interface() // pointer allocators //------------------------------------------------- -void device_nes_cart_interface::prg_alloc(size_t size, const char *tag) +void device_nes_cart_interface::prg_alloc(size_t size) { if (m_prg == nullptr) { - m_prg = device().machine().memory().region_alloc(std::string(tag).append(NESSLOT_PRGROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_prg = device().machine().memory().region_alloc(device().subtag("^cart:prg_rom"), size, 1, ENDIANNESS_LITTLE)->base(); m_prg_size = size; m_prg_chunks = size / 0x4000; if (size % 0x2000) @@ -167,26 +174,24 @@ void device_nes_cart_interface::prg_alloc(size_t size, const char *tag) m_prg_chunks--; } - m_prg_mask = ((m_prg_chunks << 1) - 1); + m_prg_mask = (m_prg_chunks << 1) - 1; // printf("first mask %x!\n", m_prg_mask); if ((m_prg_chunks << 1) & m_prg_mask) { - int mask_bits = 0, temp = (m_prg_chunks << 1), mapsize; + int mask_bits = 0; // contrary to what happens with later systems, like e.g. SNES or MD, // only half a dozen of NES carts have PRG which is not a power of 2 // so we use this bank_map only as an exception // printf("uneven rom!\n"); // 1. redefine mask as (next power of 2)-1 - for (; temp; ) - { + for (int temp = m_prg_chunks << 1; temp; temp >>= 1) mask_bits++; - temp >>= 1; - } + m_prg_mask = (1 << mask_bits) - 1; // printf("new mask %x!\n", m_prg_mask); - mapsize = (1 << mask_bits)/2; + int mapsize = (1 << mask_bits) / 2; // 2. create a bank_map for banks in the range mask/2 -> mask m_prg_bank_map.resize(mapsize); @@ -199,7 +204,7 @@ void device_nes_cart_interface::prg_alloc(size_t size, const char *tag) while (j % mapsize) { int k = 0, repeat_banks; - while ((j % (mapsize >> k)) && k < mask_bits) + while (j % (mapsize >> k) && k < mask_bits) k++; repeat_banks = j % (mapsize >> (k - 1)); for (int l = 0; l < repeat_banks; l++) @@ -218,18 +223,25 @@ void device_nes_cart_interface::prg_alloc(size_t size, const char *tag) } } -void device_nes_cart_interface::vrom_alloc(size_t size, const char *tag) +void device_nes_cart_interface::vrom_alloc(size_t size) { if (m_vrom == nullptr) { - std::string tempstring(tag); - tempstring.append(NESSLOT_CHRROM_REGION_TAG); - m_vrom = device().machine().memory().region_alloc(tempstring.c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_vrom = device().machine().memory().region_alloc(device().subtag("^cart:chr_rom"), size, 1, ENDIANNESS_LITTLE)->base(); m_vrom_size = size; m_vrom_chunks = size / 0x2000; } } +void device_nes_cart_interface::misc_rom_alloc(size_t size) +{ + if (m_misc_rom == nullptr) + { + m_misc_rom = device().machine().memory().region_alloc(device().subtag("^cart:misc_rom"), size, 1, ENDIANNESS_LITTLE)->base(); + m_misc_rom_size = size; + } +} + void device_nes_cart_interface::prgram_alloc(size_t size) { m_prgram.resize(size); @@ -253,20 +265,20 @@ void device_nes_cart_interface::battery_alloc(size_t size) inline int device_nes_cart_interface::prg_8k_bank_num(int bank_8k) { - if (m_prg_mask == ((m_prg_chunks << 1) - 1)) + if (m_prg_mask == (m_prg_chunks << 1) - 1) return bank_8k & m_prg_mask; // only a few pirate games (less than a dozen) have PRG which is not power of 2 // so we treat it here separately, rather than forcing all games to use m_prg_bank_map // case 1: if we are accessing a bank before the end of the image, just return that bank - if (bank_8k < ((m_prg_chunks << 1) - 1)) + if (bank_8k < (m_prg_chunks << 1) - 1) return bank_8k; // case 2: otherwise return a mirror using the bank_map! // uint8_t temp = bank_8k; bank_8k &= m_prg_mask; - bank_8k -= (m_prg_mask/2 + 1); + bank_8k -= m_prg_mask / 2 + 1; // printf("bank: accessed %x (top: %x), returned %x\n", temp, (m_prg_chunks << 1) - 1, m_prg_bank_map[bank_8k]); return m_prg_bank_map[bank_8k]; } @@ -276,8 +288,8 @@ inline void device_nes_cart_interface::update_prg_banks(int prg_bank_start, int for (int prg_bank = prg_bank_start; prg_bank <= prg_bank_end; prg_bank++) { assert(prg_bank >= 0); - assert(prg_bank < ARRAY_LENGTH(m_prg_bank)); - assert(prg_bank < ARRAY_LENGTH(m_prg_bank_mem)); + assert(prg_bank < std::size(m_prg_bank)); + assert(prg_bank < std::size(m_prg_bank_mem)); m_prg_bank_mem[prg_bank]->set_entry(m_prg_bank[prg_bank]); } @@ -285,11 +297,11 @@ inline void device_nes_cart_interface::update_prg_banks(int prg_bank_start, int void device_nes_cart_interface::prg32(int bank) { - /* if there is only 16k PRG, return */ + // if there is only 16k PRG, return if (!(m_prg_chunks >> 1)) return; - /* assumes that bank references a 32k chunk */ + // assumes that bank references a 32k chunk bank = prg_8k_bank_num(bank * 4); m_prg_bank[0] = bank + 0; @@ -301,7 +313,7 @@ void device_nes_cart_interface::prg32(int bank) void device_nes_cart_interface::prg16_89ab(int bank) { - /* assumes that bank references a 16k chunk */ + // assumes that bank references a 16k chunk bank = prg_8k_bank_num(bank * 2); m_prg_bank[0] = bank + 0; @@ -311,7 +323,7 @@ void device_nes_cart_interface::prg16_89ab(int bank) void device_nes_cart_interface::prg16_cdef(int bank) { - /* assumes that bank references a 16k chunk */ + // assumes that bank references a 16k chunk bank = prg_8k_bank_num(bank * 2); m_prg_bank[2] = bank + 0; @@ -319,48 +331,12 @@ void device_nes_cart_interface::prg16_cdef(int bank) update_prg_banks(2, 3); } -void device_nes_cart_interface::prg8_89(int bank) -{ - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[0] = bank; - update_prg_banks(0, 0); -} - -void device_nes_cart_interface::prg8_ab(int bank) -{ - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[1] = bank; - update_prg_banks(1, 1); -} - -void device_nes_cart_interface::prg8_cd(int bank) -{ - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[2] = bank; - update_prg_banks(2, 2); -} - -void device_nes_cart_interface::prg8_ef(int bank) -{ - /* assumes that bank references an 8k chunk */ - bank = prg_8k_bank_num(bank); - - m_prg_bank[3] = bank; - update_prg_banks(3, 3); -} - -/* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */ +// We define a parameterized helper to map 8k PRG-ROM to one of the banks void device_nes_cart_interface::prg8_x(int start, int bank) { assert(start < 4); - /* assumes that bank references an 8k chunk */ + // assumes that bank references an 8k chunk bank = prg_8k_bank_num(bank); m_prg_bank[start] = bank; @@ -371,110 +347,36 @@ void device_nes_cart_interface::prg8_x(int start, int bank) // CHR helpers //------------------------------------------------- -inline void device_nes_cart_interface::chr_sanity_check( int source ) +void device_nes_cart_interface::bank_chr(int shift, int start, int bank, int source) { - if (source == CHRRAM && m_vram.empty()) - fatalerror("CHRRAM bankswitch with no VRAM\n"); - - if (source == CHRROM && m_vrom == nullptr) - fatalerror("CHRROM bankswitch with no VROM\n"); -} - -void device_nes_cart_interface::chr8(int bank, int source) -{ - chr_sanity_check(source); + uint8_t *base_ptr; + uint32_t chr_chunks; if (source == CHRRAM) { - bank &= (m_vram_chunks - 1); - for (int i = 0; i < 8; i++) - { - m_chr_src[i] = source; - m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses! - m_chr_access[i] = &m_vram[m_chr_orig[i]]; - } - } - else - { - bank &= (m_vrom_chunks - 1); - for (int i = 0; i < 8; i++) - { - m_chr_src[i] = source; - m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses! - m_chr_access[i] = &m_vrom[m_chr_orig[i]]; - } - } -} - -void device_nes_cart_interface::chr4_x(int start, int bank, int source) -{ - chr_sanity_check(source); + assert(!m_vram.empty()); - if (source == CHRRAM) - { - bank &= ((m_vram_chunks << 1) - 1); - for (int i = 0; i < 4; i++) - { - m_chr_src[i + start] = source; - m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses! - m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]]; - } + base_ptr = &m_vram[0]; + chr_chunks = m_vram_chunks; } - else + else // source == CHRROM { - bank &= ((m_vrom_chunks << 1) - 1); - for (int i = 0; i < 4; i++) - { - m_chr_src[i + start] = source; - m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses! - m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]]; - } - } -} - -void device_nes_cart_interface::chr2_x(int start, int bank, int source) -{ - chr_sanity_check(source); + assert(m_vrom != nullptr); - if (source == CHRRAM) - { - bank &= ((m_vram_chunks << 2) - 1); - for (int i = 0; i < 2; i++) - { - m_chr_src[i + start] = source; - m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses! - m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]]; - } + base_ptr = m_vrom; + chr_chunks = m_vrom_chunks; } - else - { - bank &= ((m_vrom_chunks << 2) - 1); - for (int i = 0; i < 2; i++) - { - m_chr_src[i + start] = source; - m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses! - m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]]; - } - } -} -void device_nes_cart_interface::chr1_x(int start, int bank, int source) -{ - chr_sanity_check(source); + bank &= (chr_chunks << (3 - shift)) - 1; + int size = 0x400 << shift; + int bank_start = bank * size; + int kbyte = 1 << shift; - if (source == CHRRAM) + for (int i = 0; i < kbyte; i++) { - bank &= ((m_vram_chunks << 3) - 1); - m_chr_src[start] = source; - m_chr_orig[start] = (bank * 0x400); // for save state uses! - m_chr_access[start] = &m_vram[m_chr_orig[start]]; - } - else - { - bank &= ((m_vrom_chunks << 3) - 1); - m_chr_src[start] = source; - m_chr_orig[start] = (bank * 0x400); // for save state uses! - m_chr_access[start] = &m_vrom[m_chr_orig[start]]; + m_chr_src[i + start] = source; + m_chr_orig[i + start] = bank_start + i * 0x400; // for save state uses! + m_chr_access[i + start] = &base_ptr[m_chr_orig[i + start]]; } } @@ -484,7 +386,7 @@ void device_nes_cart_interface::chr1_x(int start, int bank, int source) void device_nes_cart_interface::set_nt_page(int page, int source, int bank, int writable) { - uint8_t* base_ptr; + uint8_t *base_ptr; switch (source) { @@ -492,7 +394,7 @@ void device_nes_cart_interface::set_nt_page(int page, int source, int bank, int base_ptr = &m_ext_ntram[0]; break; case VROM: - bank &= ((m_vrom_chunks << 3) - 1); + bank &= (m_vrom_chunks << 3) - 1; base_ptr = m_vrom; break; case EXRAM: @@ -505,7 +407,7 @@ void device_nes_cart_interface::set_nt_page(int page, int source, int bank, int break; } - page &= 3; /* mask down to the 4 logical pages */ + page &= 3; // mask down to the 4 logical pages m_nt_src[page] = source; if (base_ptr) @@ -519,20 +421,21 @@ void device_nes_cart_interface::set_nt_page(int page, int source, int bank, int void device_nes_cart_interface::set_nt_mirroring(int mirroring) { - /* setup our videomem handlers based on mirroring */ + // setup our videomem handlers based on mirroring switch (mirroring) { - case PPU_MIRROR_VERT: + default: + case PPU_MIRROR_HORZ: set_nt_page(0, CIRAM, 0, 1); - set_nt_page(1, CIRAM, 1, 1); - set_nt_page(2, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 0, 1); + set_nt_page(2, CIRAM, 1, 1); set_nt_page(3, CIRAM, 1, 1); break; - case PPU_MIRROR_HORZ: + case PPU_MIRROR_VERT: set_nt_page(0, CIRAM, 0, 1); - set_nt_page(1, CIRAM, 0, 1); - set_nt_page(2, CIRAM, 1, 1); + set_nt_page(1, CIRAM, 1, 1); + set_nt_page(2, CIRAM, 0, 1); set_nt_page(3, CIRAM, 1, 1); break; @@ -557,14 +460,6 @@ void device_nes_cart_interface::set_nt_mirroring(int mirroring) set_nt_page(2, CART_NTRAM, 2, 1); set_nt_page(3, CART_NTRAM, 3, 1); break; - - case PPU_MIRROR_NONE: - default: - set_nt_page(0, CIRAM, 0, 1); - set_nt_page(1, CIRAM, 0, 1); - set_nt_page(2, CIRAM, 1, 1); - set_nt_page(3, CIRAM, 1, 1); - break; } } @@ -572,32 +467,13 @@ void device_nes_cart_interface::set_nt_mirroring(int mirroring) // Interrupt helpers //------------------------------------------------- -DECLARE_WRITE_LINE_MEMBER(device_nes_cart_interface::set_irq_line) +void device_nes_cart_interface::set_irq_line(int state) { - // use hold_irq_line for HOLD_LINE semantics (not recommended) assert(state == ASSERT_LINE || state == CLEAR_LINE); m_maincpu->set_input_line(m6502_device::IRQ_LINE, state); } -void device_nes_cart_interface::hold_irq_line() -{ - // hack which requires the CPU object - m_maincpu->set_input_line(m6502_device::IRQ_LINE, HOLD_LINE); -} - -void device_nes_cart_interface::reset_cpu() -{ - // another hack - m_maincpu->set_pc(0xfffc); -} - -void device_nes_cart_interface::poke(offs_t offset, uint8_t data) -{ - // even worse hack - m_maincpu->space(AS_PROGRAM).write_byte(offset, data); -} - //------------------------------------------------- // Other helpers //------------------------------------------------- @@ -607,7 +483,7 @@ void device_nes_cart_interface::poke(offs_t offset, uint8_t data) // the memory banks) uint8_t device_nes_cart_interface::hi_access_rom(uint32_t offset) { - int bank = (offset & 0x6000) >> 13; + int bank = BIT(offset, 13, 2); return m_prg[m_prg_bank[bank] * 0x2000 + (offset & 0x1fff)]; } @@ -632,7 +508,7 @@ uint8_t device_nes_cart_interface::account_bus_conflict(uint32_t offset, uint8_t void device_nes_cart_interface::chr_w(offs_t offset, uint8_t data) { - int bank = offset >> 10; + int bank = BIT(offset, 10, 3); if (m_chr_src[bank] == CHRRAM) m_chr_access[bank][offset & 0x3ff] = data; @@ -640,24 +516,22 @@ void device_nes_cart_interface::chr_w(offs_t offset, uint8_t data) uint8_t device_nes_cart_interface::chr_r(offs_t offset) { - int bank = offset >> 10; + int bank = BIT(offset, 10, 3); return m_chr_access[bank][offset & 0x3ff]; } void device_nes_cart_interface::nt_w(offs_t offset, uint8_t data) { - int page = ((offset & 0xc00) >> 10); - - if (!m_nt_writable[page]) - return; + int page = BIT(offset, 10, 2); - m_nt_access[page][offset & 0x3ff] = data; + if (m_nt_writable[page]) + m_nt_access[page][offset & 0x3ff] = data; } uint8_t device_nes_cart_interface::nt_r(offs_t offset) { - int page = ((offset & 0xc00) >> 10); + int page = BIT(offset, 10, 2); return m_nt_access[page][offset & 0x3ff]; } @@ -732,7 +606,7 @@ void device_nes_cart_interface::pcb_start(running_machine &machine, uint8_t *cir if (m_four_screen_vram) { - m_ext_ntram.resize(0x2000); + m_ext_ntram.resize(0x1000); device().save_item(NAME(m_ext_ntram)); } @@ -778,12 +652,11 @@ void device_nes_cart_interface::nes_banks_restore() //------------------------------------------------- nes_cart_slot_device::nes_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, NES_CART_SLOT, tag, owner, clock) - , device_image_interface(mconfig, *this) - , device_slot_interface(mconfig, *this) + , device_cartrom_image_interface(mconfig, *this) + , device_single_card_slot_interface<device_nes_cart_interface>(mconfig, *this) , m_crc_hack(0) , m_cart(nullptr) , m_pcb_id(NO_BOARD) - , m_must_be_loaded(1) { } @@ -801,7 +674,7 @@ nes_cart_slot_device::~nes_cart_slot_device() void nes_cart_slot_device::device_start() { - m_cart = dynamic_cast<device_nes_cart_interface *>(get_card_device()); + m_cart = get_card_device(); } @@ -828,7 +701,7 @@ void nes_cart_slot_device::pcb_reset() -------------------------------------------------*/ -/* Include emulation of NES PCBs for softlist */ +// Include emulation of NES PCBs for softlist #include "nes_pcb.hxx" @@ -838,7 +711,7 @@ void nes_cart_slot_device::pcb_reset() -------------------------------------------------*/ -/* Include emulation of UNIF Boards for .unf files */ +// Include emulation of UNIF Boards for .unf files #include "nes_unif.hxx" @@ -848,11 +721,11 @@ void nes_cart_slot_device::pcb_reset() -------------------------------------------------*/ -/* Include emulation of iNES Mappers for .nes files */ +// Include emulation of iNES Mappers for .nes files #include "nes_ines.hxx" -image_init_result nes_cart_slot_device::call_load() +std::pair<std::error_condition, std::string> nes_cart_slot_device::call_load() { if (m_cart) { @@ -860,41 +733,34 @@ image_init_result nes_cart_slot_device::call_load() { 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 */ + // 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 fread(magic, 4); - if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */ + if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) // If header starts with 'NES' it is iNES { if (length() <= 0x10) - { - logerror("%s only contains the iNES header and no data.\n", filename()); - return image_init_result::FAIL; - } + return std::make_pair(image_error::INVALIDLENGTH, "File contains iNES header with no data"); call_load_ines(); } - else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */ + else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) // If header starts with 'UNIF' it is UNIF { if (length() <= 0x20) - { - logerror("%s only contains the UNIF header and no data.\n", filename()); - return image_init_result::FAIL; - } + return std::make_pair(image_error::INVALIDLENGTH, "File contains UNIF header with no data"); call_load_unif(); } else { - logerror("%s is NOT a file in either iNES or UNIF format.\n", filename()); - return image_init_result::FAIL; + return std::make_pair(image_error::INVALIDIMAGE, "File is not an iNES or UNIF cartridge image"); } } else call_load_pcb(); } - return image_init_result::PASS; + return std::make_pair(std::error_condition(), std::string()); } @@ -929,16 +795,16 @@ std::string nes_cart_slot_device::get_default_card_software(get_default_card_sof { if (hook.image_file()) { - const char *slot_string = "nrom"; - uint32_t len = hook.image_file()->size(); + uint64_t len; + hook.image_file()->length(len); // FIXME: check error return, guard against excessively large files std::vector<uint8_t> rom(len); - hook.image_file()->read(&rom[0], len); + read(*hook.image_file(), &rom[0], len); // FIXME: check error return or read returning short + const char *slot_string = "nrom"; if ((rom[0] == 'N') && (rom[1] == 'E') && (rom[2] == 'S')) slot_string = get_default_card_ines(hook, &rom[0], len); - - if ((rom[0] == 'U') && (rom[1] == 'N') && (rom[2] == 'I') && (rom[3] == 'F')) + else if ((rom[0] == 'U') && (rom[1] == 'N') && (rom[2] == 'I') && (rom[3] == 'F')) slot_string = get_default_card_unif(&rom[0], len); return std::string(slot_string); |