diff options
Diffstat (limited to 'src/devices/bus/nes/mmc3.cpp')
-rw-r--r-- | src/devices/bus/nes/mmc3.cpp | 185 |
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); + } } |