summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/mmc1.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes/mmc1.cpp')
-rw-r--r--src/devices/bus/nes/mmc1.cpp244
1 files changed, 107 insertions, 137 deletions
diff --git a/src/devices/bus/nes/mmc1.cpp b/src/devices/bus/nes/mmc1.cpp
index 9a27c601b4c..c2cbccf77e9 100644
--- a/src/devices/bus/nes/mmc1.cpp
+++ b/src/devices/bus/nes/mmc1.cpp
@@ -13,6 +13,13 @@
* 001 Yoshi flashes in-game.
* 001 Back to the Future have heavily corrupted graphics (since forever).
+ TODO:
+ - Combine 2 versions of set_prg in SxROM base class. This means dealing with
+ variant boards SNROM, SUROM, etc which repurpose bits in the MMC1 regs.
+ - Determine if "MMC1" marked chips, the earliest version, ignores WRAM
+ enable/disable bit like its first revision, MMC1A. Also determine if MMC1C
+ really exists. It's described by kevtris, but it's not in BootGod's DB.
+
***********************************************************************************************************/
@@ -20,47 +27,40 @@
#include "mmc1.h"
#ifdef NES_PCB_DEBUG
-#define VERBOSE 1
+#define VERBOSE (LOG_GENERAL)
#else
-#define VERBOSE 0
+#define VERBOSE (0)
#endif
-
-#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+#include "logmacro.h"
//-------------------------------------------------
// constructor
//-------------------------------------------------
-DEFINE_DEVICE_TYPE(NES_SXROM, nes_sxrom_device, "nes_sxrom", "NES Cart SxROM (MMC-1) PCB")
-DEFINE_DEVICE_TYPE(NES_SOROM, nes_sorom_device, "nes_sorom", "NES Cart SOROM (MMC-1) PCB")
-DEFINE_DEVICE_TYPE(NES_SXROM_A, nes_sxrom_a_device, "nes_sxrom_a", "NES Cart SxROM (MMC-1A) PCB")
-DEFINE_DEVICE_TYPE(NES_SOROM_A, nes_sorom_a_device, "nes_sorom_a", "NES Cart SOROM (MMC-1A) PCB")
+DEFINE_DEVICE_TYPE(NES_SXROM, nes_sxrom_device, "nes_sxrom", "NES Cart SxROM (MMC-1) PCB")
+DEFINE_DEVICE_TYPE(NES_SOROM, nes_sorom_device, "nes_sorom", "NES Cart SOROM (MMC-1) PCB")
+DEFINE_DEVICE_TYPE(NES_SZROM, nes_szrom_device, "nes_szrom", "NES Cart SZROM (MMC-1) PCB")
-nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: nes_nrom_device(mconfig, type, tag, owner, clock), m_reg_write_enable(0), m_latch(0), m_count(0)
{
}
-nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: nes_sxrom_device(mconfig, NES_SXROM, tag, owner, clock)
{
}
-nes_sorom_device::nes_sorom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+nes_sorom_device::nes_sorom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: nes_sxrom_device(mconfig, NES_SOROM, tag, owner, clock)
{
}
-nes_sxrom_a_device::nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : nes_sxrom_device(mconfig, NES_SXROM_A, tag, owner, clock)
-{
-}
-
-nes_sorom_a_device::nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : nes_sxrom_device(mconfig, NES_SOROM_A, tag, owner, clock)
+nes_szrom_device::nes_szrom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_sxrom_device(mconfig, NES_SZROM, tag, owner, clock)
{
}
@@ -77,48 +77,19 @@ void nes_sxrom_device::device_start()
void nes_sxrom_device::pcb_reset()
{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
-
- m_latch = 0;
- m_count = 0;
- m_reg[0] = 0x0f;
- m_reg[1] = m_reg[2] = m_reg[3] = 0;
- m_reg_write_enable = 1;
-
- set_nt_mirroring(PPU_MIRROR_HORZ);
- set_chr();
- set_prg();
-}
-
-void nes_sorom_device::pcb_reset()
-{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
-
m_latch = 0;
m_count = 0;
m_reg[0] = 0x0f;
- m_reg[1] = m_reg[2] = m_reg[3] = 0;
+ m_reg[1] = 0;
+ m_reg[2] = 0;
+ m_reg[3] = 0;
m_reg_write_enable = 1;
- set_nt_mirroring(PPU_MIRROR_HORZ);
set_chr();
set_prg();
+ set_mirror();
}
-void nes_sorom_a_device::pcb_reset()
-{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
-
- m_latch = 0;
- m_count = 0;
- m_reg[0] = 0x0f;
- m_reg[1] = m_reg[2] = m_reg[3] = 0;
- m_reg_write_enable = 1;
-
- set_nt_mirroring(PPU_MIRROR_HORZ);
- set_chr();
- set_prg();
-}
@@ -142,9 +113,31 @@ TIMER_CALLBACK_MEMBER( nes_sxrom_device::resync_callback )
}
+// Standard MMC1 PRG banking with base and mask (to support multicarts, etc)
+void nes_sxrom_device::set_prg(int prg_base, int prg_mask)
+{
+ u8 bank = prg_base | (m_reg[3] & prg_mask);
+
+ switch (BIT(m_reg[0], 2, 2))
+ {
+ case 0:
+ case 1:
+ prg32(bank >> 1);
+ break;
+ case 2:
+ prg16_89ab(prg_base);
+ prg16_cdef(bank);
+ break;
+ case 3:
+ prg16_89ab(bank);
+ prg16_cdef(prg_base | prg_mask);
+ break;
+ }
+}
+
void nes_sxrom_device::set_prg()
{
- uint8_t prg_mode, prg_offset;
+ u8 prg_mode, prg_offset;
prg_mode = m_reg[0] & 0x0c;
/* prg_mode&0x8 determines bank size: 32k (if 0) or 16k (if 1)? when in 16k mode,
@@ -177,34 +170,34 @@ void nes_sxrom_device::set_prg()
}
}
-void nes_sxrom_device::set_chr()
+// Standard MMC1 CHR banking with base and mask (to support multicarts, etc)
+void nes_sxrom_device::set_chr(int chr_base, int chr_mask)
{
- uint8_t chr_mode = BIT(m_reg[0], 4);
-
- if (chr_mode)
+ if (BIT(m_reg[0], 4))
{
- chr4_0(m_reg[1] & 0x1f, m_chr_source);
- chr4_4(m_reg[2] & 0x1f, m_chr_source);
+ chr4_0(chr_base | (m_reg[1] & chr_mask), m_chr_source);
+ chr4_4(chr_base | (m_reg[2] & chr_mask), m_chr_source);
}
else
- chr8((m_reg[1] & 0x1f) >> 1, m_chr_source);
+ chr8((chr_base | (m_reg[1] & chr_mask)) >> 1, m_chr_source);
}
-// this allows for easier implementation of the NES-EVENT board used for Nintento World Championships
+void nes_sxrom_device::set_mirror()
+{
+ static constexpr u8 mirr[4] = { PPU_MIRROR_LOW, PPU_MIRROR_HIGH, PPU_MIRROR_VERT, PPU_MIRROR_HORZ };
+
+ set_nt_mirroring(mirr[m_reg[0] & 0x03]);
+}
+
+// this allows for easier implementation of MMC1 subclasses
void nes_sxrom_device::update_regs(int reg)
{
switch (reg)
{
case 0:
- switch (m_reg[0] & 0x03)
- {
- case 0: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- case 2: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- }
set_chr();
set_prg();
+ set_mirror();
break;
case 1:
set_chr();
@@ -219,9 +212,9 @@ void nes_sxrom_device::update_regs(int reg)
}
}
-void nes_sxrom_device::write_h(offs_t offset, uint8_t data)
+void nes_sxrom_device::write_h(offs_t offset, u8 data)
{
- LOG_MMC(("sxrom write_h, offset: %04x, data: %02x\n", offset, data));
+ LOG("sxrom write_h, offset: %04x, data: %02x\n", offset, data);
// There is only one latch and shift counter, shared amongst the 4 regs (testcase: Space Shuttle)
@@ -241,7 +234,6 @@ void nes_sxrom_device::write_h(offs_t offset, uint8_t data)
if (data & 0x80)
{
m_count = 0;
- m_latch = 0;
// Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars
m_reg[0] |= 0x0c;
@@ -249,28 +241,24 @@ void nes_sxrom_device::write_h(offs_t offset, uint8_t data)
return;
}
- if (m_count < 5)
- {
- if (m_count == 0) m_latch = 0;
- m_latch >>= 1;
- m_latch |= (data & 0x01) ? 0x10 : 0x00;
- m_count++;
- }
+ m_latch >>= 1;
+ m_latch |= (data & 1) << 4;
+ m_count = (m_count + 1) % 5;
- if (m_count == 5)
+ if (!m_count)
{
- m_reg[(offset & 0x6000) >> 13] = m_latch;
- update_regs((offset & 0x6000) >> 13);
- m_count = 0;
+ int reg = BIT(offset, 13, 2);
+ m_reg[reg] = m_latch;
+ update_regs(reg);
}
}
-void nes_sxrom_device::write_m(offs_t offset, uint8_t data)
+void nes_sxrom_device::write_m(offs_t offset, u8 data)
{
- uint8_t bank = (m_reg[1] >> 2) & 3;
- LOG_MMC(("sxrom write_m, offset: %04x, data: %02x\n", offset, data));
+ u8 bank = BIT(m_reg[1], 2, 2);
+ LOG("sxrom write_m, offset: %04x, data: %02x\n", offset, data);
- if (!BIT(m_reg[3], 4)) // WRAM enabled
+ if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled
{
if (!m_battery.empty())
m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data;
@@ -279,12 +267,12 @@ void nes_sxrom_device::write_m(offs_t offset, uint8_t data)
}
}
-uint8_t nes_sxrom_device::read_m(offs_t offset)
+u8 nes_sxrom_device::read_m(offs_t offset)
{
- uint8_t bank = (m_reg[1] >> 2) & 3;
- LOG_MMC(("sxrom read_m, offset: %04x\n", offset));
+ u8 bank = BIT(m_reg[1], 2, 2);
+ LOG("sxrom read_m, offset: %04x\n", offset);
- if (!BIT(m_reg[3], 4)) // WRAM enabled
+ if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled
{
if (!m_battery.empty())
return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)];
@@ -292,16 +280,16 @@ uint8_t nes_sxrom_device::read_m(offs_t offset)
return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)];
}
- return get_open_bus(); // open bus
+ return get_open_bus();
}
// SOROM has two RAM banks, the first is not battery backed up, the second is.
-void nes_sorom_device::write_m(offs_t offset, uint8_t data)
+void nes_sorom_device::write_m(offs_t offset, u8 data)
{
- uint8_t type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
- LOG_MMC(("sorom write_m, offset: %04x, data: %02x\n", offset, data));
+ u8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
+ LOG("sorom write_m, offset: %04x, data: %02x\n", offset, data);
- if (!BIT(m_reg[3], 4)) // WRAM enabled
+ if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled
{
if (type)
m_battery[offset & (m_battery.size() - 1)] = data;
@@ -310,12 +298,12 @@ void nes_sorom_device::write_m(offs_t offset, uint8_t data)
}
}
-uint8_t nes_sorom_device::read_m(offs_t offset)
+u8 nes_sorom_device::read_m(offs_t offset)
{
- uint8_t type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
- LOG_MMC(("sorom read_m, offset: %04x\n", offset));
+ u8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
+ LOG("sorom read_m, offset: %04x\n", offset);
- if (!BIT(m_reg[3], 4)) // WRAM enabled
+ if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled
{
if (type)
return m_battery[offset & (m_battery.size() - 1)];
@@ -323,52 +311,34 @@ uint8_t nes_sorom_device::read_m(offs_t offset)
return m_prgram[offset & (m_prgram.size() - 1)];
}
- return get_open_bus(); // open bus
-}
-
-// MMC1A boards have no wram enable/disable bit
-void nes_sxrom_a_device::write_m(offs_t offset, uint8_t data)
-{
- uint8_t bank = (m_reg[1] >> 2) & 3;
- LOG_MMC(("sxrom_a write_m, offset: %04x, data: %02x\n", offset, data));
-
- if (!m_battery.empty())
- m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data;
- if (!m_prgram.empty())
- m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data;
+ return get_open_bus();
}
-uint8_t nes_sxrom_a_device::read_m(offs_t offset)
+// SZROM has two RAM banks, the first is not battery backed up, the second is.
+void nes_szrom_device::write_m(offs_t offset, u8 data)
{
- uint8_t bank = (m_reg[1] >> 2) & 3;
- LOG_MMC(("sxrom_a read_m, offset: %04x\n", offset));
-
- if (!m_battery.empty())
- return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)];
- if (!m_prgram.empty())
- return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)];
+ LOG("szrom write_m, offset: %04x, data: %02x\n", offset, data);
- return get_open_bus(); // open bus
+ if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled
+ {
+ if (BIT(m_reg[BIT(m_reg[0], 4) + 1], 4))
+ m_battery[offset & (m_battery.size() - 1)] = data;
+ else
+ m_prgram[offset & (m_prgram.size() - 1)] = data;
+ }
}
-void nes_sorom_a_device::write_m(offs_t offset, uint8_t data)
+u8 nes_szrom_device::read_m(offs_t offset)
{
- uint8_t type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
- LOG_MMC(("sorom_a write_m, offset: %04x, data: %02x\n", offset, data));
+ LOG("szrom read_m, offset: %04x\n", offset);
- if (type)
- m_battery[offset & (m_battery.size() - 1)] = data;
- else
- m_prgram[offset & (m_prgram.size() - 1)] = data;
-}
-
-uint8_t nes_sorom_a_device::read_m(offs_t offset)
-{
- uint8_t type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
- LOG_MMC(("sorom_a read_m, offset: %04x\n", offset));
+ if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled
+ {
+ if (BIT(m_reg[BIT(m_reg[0], 4) + 1], 4))
+ return m_battery[offset & (m_battery.size() - 1)];
+ else
+ return m_prgram[offset & (m_prgram.size() - 1)];
+ }
- if (type)
- return m_battery[offset & (m_battery.size() - 1)];
- else
- return m_prgram[offset & (m_prgram.size() - 1)];
+ return get_open_bus();
}