summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/nes_slot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes/nes_slot.cpp')
-rw-r--r--src/devices/bus/nes/nes_slot.cpp303
1 files changed, 75 insertions, 228 deletions
diff --git a/src/devices/bus/nes/nes_slot.cpp b/src/devices/bus/nes/nes_slot.cpp
index ec839fb1e7b..d7df07d7693 100644
--- a/src/devices/bus/nes/nes_slot.cpp
+++ b/src/devices/bus/nes/nes_slot.cpp
@@ -129,7 +129,8 @@ device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconf
, m_n163_vol(0)
, m_outer_prg_size(0)
, m_outer_chr_size(0)
- , m_mirroring(PPU_MIRROR_NONE)
+ , m_smd133_addr(0x6000)
+ , m_mirroring(PPU_MIRROR_HORZ)
, m_pcb_ctrl_mirror(false)
, m_four_screen_vram(false)
, m_has_trainer(false)
@@ -157,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)
@@ -173,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);
@@ -205,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++)
@@ -224,25 +223,21 @@ 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, const char *tag)
+void device_nes_cart_interface::misc_rom_alloc(size_t size)
{
if (m_misc_rom == nullptr)
{
- std::string tempstring(tag);
- tempstring.append(NESSLOT_MISC_ROM_REGION_TAG);
- m_misc_rom = device().machine().memory().region_alloc(tempstring.c_str(), size, 1, ENDIANNESS_LITTLE)->base();
+ m_misc_rom = device().machine().memory().region_alloc(device().subtag("^cart:misc_rom"), size, 1, ENDIANNESS_LITTLE)->base();
m_misc_rom_size = size;
}
}
@@ -270,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];
}
@@ -302,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;
@@ -318,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;
@@ -328,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;
@@ -336,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;
@@ -388,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]];
- }
- }
-}
+ assert(m_vrom != nullptr);
-void device_nes_cart_interface::chr2_x(int start, int bank, int source)
-{
- chr_sanity_check(source);
-
- 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)
- {
- 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
+ for (int i = 0; i < kbyte; i++)
{
- 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]];
}
}
@@ -501,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)
{
@@ -509,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:
@@ -522,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)
@@ -536,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;
@@ -574,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;
}
}
@@ -589,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
//-------------------------------------------------
@@ -624,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)];
}
@@ -649,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;
@@ -657,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];
}
@@ -749,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));
}
@@ -795,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_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)
{
}
@@ -845,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"
@@ -855,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"
@@ -865,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)
{
@@ -877,42 +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());
- seterror(image_error::INVALIDIMAGE, "File is neither iNES or UNIF format");
- 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());
}
@@ -951,8 +799,7 @@ std::string nes_cart_slot_device::get_default_card_software(get_default_card_sof
hook.image_file()->length(len); // FIXME: check error return, guard against excessively large files
std::vector<uint8_t> rom(len);
- size_t actual;
- hook.image_file()->read(&rom[0], len, actual); // FIXME: check error return or read returning short
+ 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'))