summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/mmc3.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes/mmc3.cpp')
-rw-r--r--src/devices/bus/nes/mmc3.cpp185
1 files changed, 90 insertions, 95 deletions
diff --git a/src/devices/bus/nes/mmc3.cpp b/src/devices/bus/nes/mmc3.cpp
index d6f7f37dc4a..79b6c7deefa 100644
--- a/src/devices/bus/nes/mmc3.cpp
+++ b/src/devices/bus/nes/mmc3.cpp
@@ -20,7 +20,6 @@
* 004 Mendel Palace has never worked properly
* 004 Ninja Gaiden 2 has flashing bg graphics in the second level
- * 119 Pin Bot has glitches when the ball is in the upper half of the screen
***********************************************************************************************************/
@@ -29,16 +28,15 @@
#include "mmc3.h"
#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access ppu2c0x_device::BOTTOM_VISIBLE_SCANLINE
-#include "screen.h"
+#define LOG_UNHANDLED (1U << 1)
#ifdef NES_PCB_DEBUG
-#define VERBOSE 1
+#define VERBOSE (LOG_UNHANDLED | LOG_GENERAL)
#else
-#define VERBOSE 0
+#define VERBOSE (LOG_UNHANDLED)
#endif
-
-#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+#include "logmacro.h"
//-------------------------------------------------
@@ -54,7 +52,7 @@ DEFINE_DEVICE_TYPE(NES_ZZ_PCB, nes_zz_device, "nes_zz", "NES Cart PAL-ZZ
nes_txrom_device::nes_txrom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : nes_nrom_device(mconfig, type, tag, owner, clock), m_prg_base(0), m_prg_mask(0), m_chr_base(0), m_chr_mask(0)
+ : nes_nrom_device(mconfig, type, tag, owner, clock), m_mmc_mirror(0), m_prg_base(0), m_prg_mask(0), m_chr_base(0), m_chr_mask(0)
, m_latch(0), m_wram_protect(0), m_alt_irq(0), m_irq_count(0), m_irq_count_latch(0), m_irq_clear(0), m_irq_enable(0)
{
}
@@ -69,22 +67,32 @@ nes_hkrom_device::nes_hkrom_device(const machine_config &mconfig, const char *ta
{
}
-nes_txsrom_device::nes_txsrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : nes_txrom_device(mconfig, NES_TXSROM, tag, owner, clock)
+nes_txsrom_device::nes_txsrom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : nes_txrom_device(mconfig, type, tag, owner, clock)
+{
+}
+
+nes_txsrom_device::nes_txsrom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_txsrom_device(mconfig, NES_TXSROM, tag, owner, clock)
+{
+}
+
+nes_tqrom_device::nes_tqrom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : nes_txrom_device(mconfig, type, tag, owner, clock)
{
}
-nes_tqrom_device::nes_tqrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : nes_txrom_device(mconfig, NES_TQROM, tag, owner, clock)
+nes_tqrom_device::nes_tqrom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_tqrom_device(mconfig, NES_TQROM, tag, owner, clock)
{
}
-nes_qj_device::nes_qj_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+nes_qj_device::nes_qj_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: nes_txrom_device(mconfig, NES_QJ_PCB, tag, owner, clock)
{
}
-nes_zz_device::nes_zz_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+nes_zz_device::nes_zz_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: nes_txrom_device(mconfig, NES_ZZ_PCB, tag, owner, clock)
{
}
@@ -96,6 +104,7 @@ void nes_txrom_device::mmc3_start()
common_start();
save_item(NAME(m_mmc_prg_bank));
save_item(NAME(m_mmc_vrom_bank));
+ save_item(NAME(m_mmc_mirror));
save_item(NAME(m_latch));
save_item(NAME(m_wram_protect));
save_item(NAME(m_prg_base));
@@ -113,8 +122,19 @@ void nes_txrom_device::mmc3_common_initialize( int prg_mask, int chr_mask, int i
{
m_mmc_prg_bank[0] = m_mmc_prg_bank[2] = 0xffe; // m_mmc_prg_bank[2] & m_mmc_prg_bank[3] remain always the same in most MMC3 variants
m_mmc_prg_bank[1] = m_mmc_prg_bank[3] = 0xfff; // but some pirate clone mappers change them after writing certain registers
- memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+ // Point CHR banks to the first 8K of memory. This is needed for a few unlicensed carts that use VRAM and don't init banks properly.
+ // This includes at least some Waixing games, EverQuest and Sanguozhi, and some multicarts, New Star 6 in 1 and Famicom Yarou Vol 1.
+ m_mmc_vrom_bank[0] = 0;
+ m_mmc_vrom_bank[1] = 2;
+ m_mmc_vrom_bank[2] = 4;
+ m_mmc_vrom_bank[3] = 5;
+ m_mmc_vrom_bank[4] = 6;
+ m_mmc_vrom_bank[5] = 7;
+ m_mmc_vrom_bank[6] = 0; // extension reg used by clone boards
+ m_mmc_vrom_bank[7] = 0; // extension reg used by clone boards
+
+ m_mmc_mirror = 0;
m_latch = 0;
m_wram_protect = 0x80;
@@ -134,7 +154,6 @@ void nes_txrom_device::mmc3_common_initialize( int prg_mask, int chr_mask, int i
void nes_txrom_device::pcb_reset()
{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
// 4-screen mirroring is taken care in pcb_start, if needed...
mmc3_common_initialize(0xff, 0xff, 0);
}
@@ -154,7 +173,6 @@ void nes_hkrom_device::device_start()
void nes_hkrom_device::pcb_reset()
{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
mmc3_common_initialize(0xff, 0xff, 1);
m_mmc6_reg = 0xf0;
m_wram_enable = 0;
@@ -163,14 +181,12 @@ void nes_hkrom_device::pcb_reset()
void nes_qj_device::pcb_reset()
{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
mmc3_common_initialize(0x0f, 0x7f, 0);
}
void nes_zz_device::pcb_reset()
{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
mmc3_common_initialize(0x07, 0x7f, 0);
}
@@ -188,7 +204,7 @@ void nes_zz_device::pcb_reset()
-------------------------------------------------*/
/* Here, IRQ counter decrements every scanline. */
-void nes_txrom_device::hblank_irq(int scanline, int vblank, int blanked)
+void nes_txrom_device::hblank_irq(int scanline, bool vblank, bool blanked)
{
if (scanline < ppu2c0x_device::BOTTOM_VISIBLE_SCANLINE)
{
@@ -200,7 +216,7 @@ void nes_txrom_device::hblank_irq(int scanline, int vblank, int blanked)
if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear /*|| !m_mmc3_alt_irq*/)) // according to blargg the latter should be present as well, but it breaks Rampart and Joe & Mac US: they probably use the alt irq!
{
- LOG_MMC(("irq fired, scanline: %d\n", scanline));
+ LOG("irq fired, scanline: %d\n", scanline);
set_irq_line(ASSERT_LINE);
}
}
@@ -248,7 +264,7 @@ void nes_txrom_device::txrom_write(offs_t offset, uint8_t data)
{
uint8_t mmc_helper, cmd;
- LOG_MMC(("txrom_write, offset: %04x, data: %02x\n", offset, data));
+ LOG("txrom_write, offset: %04x, data: %02x\n", offset, data);
switch (offset & 0x6001)
{
@@ -283,7 +299,9 @@ void nes_txrom_device::txrom_write(offs_t offset, uint8_t data)
break;
case 0x2000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ m_mmc_mirror = data;
+ if (m_mirroring != PPU_MIRROR_4SCREEN)
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
break;
case 0x2001:
@@ -308,27 +326,27 @@ void nes_txrom_device::txrom_write(offs_t offset, uint8_t data)
break;
default:
- logerror("txrom_write uncaught: %04x value: %02x\n", offset + 0x8000, data);
+ LOGMASKED(LOG_UNHANDLED, "txrom_write uncaught: %04x value: %02x\n", offset + 0x8000, data);
break;
}
}
void nes_txrom_device::write_m(offs_t offset, uint8_t data)
{
- LOG_MMC(("txrom write_m, offset: %04x, data: %02x\n", offset, data));
+ LOG("txrom write_m, offset: %04x, data: %02x\n", offset, data);
if (BIT(m_wram_protect, 7) && !BIT(m_wram_protect, 6))
{
if (!m_battery.empty())
m_battery[offset & (m_battery.size() - 1)] = data;
- if (!m_prgram.empty())
+ else if (!m_prgram.empty())
m_prgram[offset & (m_prgram.size() - 1)] = data;
}
}
uint8_t nes_txrom_device::read_m(offs_t offset)
{
- LOG_MMC(("txrom read_m, offset: %04x\n", offset));
+ LOG("txrom read_m, offset: %04x\n", offset);
if (BIT(m_wram_protect, 7))
{
@@ -338,7 +356,7 @@ uint8_t nes_txrom_device::read_m(offs_t offset)
return m_prgram[offset & (m_prgram.size() - 1)];
}
- return get_open_bus(); // open bus
+ return get_open_bus();
}
@@ -353,7 +371,7 @@ uint8_t nes_txrom_device::read_m(offs_t offset)
void nes_hkrom_device::write_m(offs_t offset, uint8_t data)
{
uint8_t write_hi, write_lo;
- LOG_MMC(("hkrom write_m, offset: %04x, data: %02x\n", offset, data));
+ LOG("hkrom write_m, offset: %04x, data: %02x\n", offset, data);
if (offset < 0x1000)
return;
@@ -371,13 +389,13 @@ void nes_hkrom_device::write_m(offs_t offset, uint8_t data)
uint8_t nes_hkrom_device::read_m(offs_t offset)
{
- LOG_MMC(("hkrom read_m, offset: %04x\n", offset));
+ LOG("hkrom read_m, offset: %04x\n", offset);
if (offset < 0x1000)
- return get_open_bus(); // open bus
+ return get_open_bus();
if (!(m_mmc6_reg & 0xa0))
- return get_open_bus(); // open bus
+ return get_open_bus();
if (BIT(offset, 9) && BIT(m_mmc6_reg, 7)) // access to upper half of 1k when upper read is enabled
return m_mmc6_ram[offset & 0x3ff];
@@ -392,7 +410,7 @@ uint8_t nes_hkrom_device::read_m(offs_t offset)
void nes_hkrom_device::write_h(offs_t offset, uint8_t data)
{
uint8_t mmc6_helper;
- LOG_MMC(("hkrom write_h, offset: %04x, data: %02x\n", offset, data));
+ LOG("hkrom write_h, offset: %04x, data: %02x\n", offset, data);
switch (offset & 0x6001)
{
@@ -437,43 +455,30 @@ void nes_hkrom_device::write_h(offs_t offset, uint8_t data)
iNES: mapper 118
- In MESS: Supported. It also uses mmc3_irq.
+ In MAME: Supported. It also uses mmc3_irq.
-------------------------------------------------*/
-void nes_txsrom_device::set_mirror()
+void nes_txsrom_device::set_chr(u8 chr, int chr_base, int chr_mask)
{
- if (m_latch & 0x80)
- {
- set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1);
- set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1);
- set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1);
- set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1);
- }
- else
- {
- set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1);
- set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1);
- set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1);
- set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1);
- }
-}
+ nes_txrom_device::set_chr(chr, chr_base, chr_mask);
-void nes_txsrom_device::chr_cb( int start, int bank, int source )
-{
- set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code
- chr1_x(start, bank, source);
+ // do nametables
+ static constexpr u8 bank[8] = { 0, 0, 1, 1, 2, 3, 4, 5 };
+ int start = (m_latch & 0x80) >> 5;
+
+ for (int i = 0; i < 4; i++)
+ set_nt_page(i, CIRAM, BIT(m_mmc_vrom_bank[bank[start + i]], 7), 1);
}
-void nes_txsrom_device::write_h(offs_t offset, uint8_t data)
+void nes_txsrom_device::write_h(offs_t offset, u8 data)
{
- LOG_MMC(("txsrom write_h, offset: %04x, data: %02x\n", offset, data));
+ LOG("txsrom write_h, offset: %04x, data: %02x\n", offset, data);
switch (offset & 0x6001)
{
case 0x2000:
break;
-
default:
txrom_write(offset, data);
break;
@@ -488,33 +493,18 @@ void nes_txsrom_device::write_h(offs_t offset, uint8_t data)
iNES: mapper 119
- In MESS: Supported. It also uses mmc3_irq.
+ In MAME: Supported. It also uses mmc3_irq.
-------------------------------------------------*/
-void nes_tqrom_device::set_chr( uint8_t chr, int chr_base, int chr_mask )
+void nes_tqrom_device::chr_cb(int start, int bank, int source)
{
- uint8_t chr_page = (m_latch & 0x80) >> 5;
- uint8_t src[6], mask[6];
-
- // TQROM ignores the source, base and mask set by the MMC3 and determines them based on vrom bank bits
- for (int i = 0; i < 6; i++)
- {
- src[i] = (m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM;
- mask[i] = (m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f;
- }
-
- chr1_x(chr_page ^ 0, ((m_mmc_vrom_bank[0] & ~0x01) & mask[0]), src[0]);
- chr1_x(chr_page ^ 1, ((m_mmc_vrom_bank[0] | 0x01) & mask[0]), src[0]);
- chr1_x(chr_page ^ 2, ((m_mmc_vrom_bank[1] & ~0x01) & mask[1]), src[1]);
- chr1_x(chr_page ^ 3, ((m_mmc_vrom_bank[1] | 0x01) & mask[1]), src[1]);
- chr1_x(chr_page ^ 4, (m_mmc_vrom_bank[2] & mask[2]), src[2]);
- chr1_x(chr_page ^ 5, (m_mmc_vrom_bank[3] & mask[3]), src[3]);
- chr1_x(chr_page ^ 6, (m_mmc_vrom_bank[4] & mask[4]), src[4]);
- chr1_x(chr_page ^ 7, (m_mmc_vrom_bank[5] & mask[5]), src[5]);
+ if (BIT(bank, 6))
+ chr1_x(start, bank & 0x07, CHRRAM);
+ else
+ chr1_x(start, bank & 0x3f, CHRROM);
}
-
/*-------------------------------------------------
NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart
@@ -524,19 +514,19 @@ void nes_tqrom_device::set_chr( uint8_t chr, int chr_base, int chr_mask )
-------------------------------------------------*/
-void nes_qj_device::write_m(offs_t offset, uint8_t data)
+void nes_qj_device::write_m(offs_t offset, u8 data)
{
- LOG_MMC(("qj write_m, offset: %04x, data: %02x\n", offset, data));
+ LOG("qj write_m, offset: %04x, data: %02x\n", offset, data);
- m_prg_base = BIT(data, 0) << 4;
- m_prg_mask = 0x0f;
- m_chr_base = BIT(data, 0) << 7;
- m_chr_mask = 0x7f;
- set_prg(m_prg_base, m_prg_mask);
- set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ if (BIT(m_wram_protect, 7) && !BIT(m_wram_protect, 6))
+ {
+ m_prg_base = BIT(data, 0) << 4;
+ m_chr_base = BIT(data, 0) << 7;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
}
-
/*-------------------------------------------------
PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart
@@ -544,17 +534,22 @@ void nes_qj_device::write_m(offs_t offset, uint8_t data)
iNES: mapper 37
+ TODO: this board apparently only resets to the menu
+ screen on systems with a CIC (the outer PRG lines
+ are somehow tied to the CIC's reset line).
+
-------------------------------------------------*/
-void nes_zz_device::write_m(offs_t offset, uint8_t data)
+void nes_zz_device::write_m(offs_t offset, u8 data)
{
- uint8_t mmc_helper = data & 0x07;
- LOG_MMC(("zz write_m, offset: %04x, data: %02x\n", offset, data));
+ LOG("zz write_m, offset: %04x, data: %02x\n", offset, data);
- m_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0);
- m_prg_mask = (mmc_helper << 1) | 0x07;
- m_chr_base = BIT(mmc_helper, 2) << 7;
- m_chr_mask = 0x7f;
- set_prg(m_prg_base, m_prg_mask);
- set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ if (BIT(m_wram_protect, 7) && !BIT(m_wram_protect, 6))
+ {
+ m_prg_base = ((data & 0x04) | (data & (data << 1) & 0x02)) << 2;
+ m_prg_mask = (m_prg_mask == 0x10) ? 0x0f : 0x07;
+ m_chr_base = BIT(data, 2) << 7;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
}