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