diff options
author | 2022-04-02 12:47:01 -0800 | |
---|---|---|
committer | 2022-04-02 16:47:01 -0400 | |
commit | 1039cc50df65effe584c12f3b5c12756e3ab3689 (patch) | |
tree | eec6d65aa2b0cc125edc352dbfad08a22b9f6947 /src/devices/bus/nes/ggenie.cpp | |
parent | 8015fc79a730d9e3df4c384826d7abd687566176 (diff) |
bus/nes: Game Genie cleanup time. (#9502)
- Trimmed overdumped PRG ROM to 4K.
- Removed nonexistent CHR ROM, replaced with emulation of on-board logic.
- Removed hack from NES slot code that directly set the CPU program counter.
- Corrected reset behavior.
Diffstat (limited to 'src/devices/bus/nes/ggenie.cpp')
-rw-r--r-- | src/devices/bus/nes/ggenie.cpp | 230 |
1 files changed, 109 insertions, 121 deletions
diff --git a/src/devices/bus/nes/ggenie.cpp b/src/devices/bus/nes/ggenie.cpp index bb5866feac7..bddebcad512 100644 --- a/src/devices/bus/nes/ggenie.cpp +++ b/src/devices/bus/nes/ggenie.cpp @@ -10,6 +10,8 @@ * Galoob Game Genie, passthrough hacking cart + TODO: emulate bugs/quirks/bus conflicts. See NesDev wiki. + ***********************************************************************************************************/ @@ -33,10 +35,10 @@ DEFINE_DEVICE_TYPE(NES_GGENIE, nes_ggenie_device, "nes_ggenie", "NES Cart Game Genie PCB") -nes_ggenie_device::nes_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) +nes_ggenie_device::nes_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : nes_nrom_device(mconfig, NES_GGENIE, tag, owner, clock) , m_ggslot(*this, "gg_slot") - , m_gg_bypass(0) + , m_gg_bypass(false) { } @@ -45,26 +47,35 @@ void nes_ggenie_device::device_start() { common_start(); save_item(NAME(m_gg_bypass)); + save_item(NAME(m_gg_addr)); + save_item(NAME(m_gg_repl)); + save_item(NAME(m_gg_comp)); + save_item(NAME(m_gg_enable)); + save_item(NAME(m_gg_is_comp)); } -void nes_ggenie_device::pcb_start(running_machine &machine, uint8_t *ciram_ptr, bool cart_mounted) +void nes_ggenie_device::pcb_start(running_machine &machine, u8 *ciram_ptr, bool cart_mounted) { device_nes_cart_interface::pcb_start(machine, ciram_ptr, cart_mounted); - if (m_ggslot->m_cart) - m_ggslot->pcb_start(m_ciram); -} + m_ggslot->pcb_start(m_ciram); -void nes_ggenie_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; prg32(0); - chr8(0, m_chr_source); + m_gg_bypass = false; - set_nt_mirroring(PPU_MIRROR_LOW); - m_gg_bypass = 0; + for (int i = 0; i < 3; i++) + { + m_gg_addr[i] = 0; + m_gg_repl[i] = 0; + m_gg_comp[i] = 0; + m_gg_enable[i] = false; + m_gg_is_comp[i] = false; + } +} - if (m_ggslot->m_cart) - m_ggslot->m_cart->pcb_reset(); +void nes_ggenie_device::pcb_reset() +{ + // Game Genie does NOT reset to its interface once in game mode + m_ggslot->pcb_reset(); } @@ -80,177 +91,154 @@ void nes_ggenie_device::pcb_reset() -------------------------------------------------*/ -void nes_ggenie_device::write_h(offs_t offset, uint8_t data) +void nes_ggenie_device::write_h(offs_t offset, u8 data) { -// LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data)); - if (!m_gg_bypass) +// LOG_MMC(("ggenie write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_gg_bypass) { - // From blargg: Codes are written to $8001-800C, starting at $800C and going down to $8001. - // Next, two values are written to $8000. The first specify the kind of codes which have - // been inserted, the second write to $8000 is always zero (all 8 bits). - // This probably disables the boot ROM (the code is executing from RAM at this point). - // Once done, the code jumps to ($FFFC) to begin the game. - // All 12 bytes from $8001-800C are written regardless of how many codes are inserted. - // The value written to $8000 is the only clue as to what codes are actually valid and which - // ones have compare values. - if (offset) - { - int code; - offset -= 1; - code = (offset & 0xc) >> 2; - if (code == 3) - return; // how did we end up here? the GG is not expected to write to $800d-800f! + m_ggslot->write_h(offset, data); + return; + } - switch (offset & 3) - { - case 0: - m_gg_addr[code] |= (data & 0x7f) << 8; - break; - case 1: - m_gg_addr[code] = data; - break; - case 2: - m_gg_comp[code] = data; - break; - case 3: - m_gg_repl[code] = data; - break; - } - return; - } + // From blargg: Codes are written to $8001-800C, starting at $800C and going down to $8001. + // Next, two values are written to $8000. The first specify the kind of codes which have + // been inserted, and disables the boot ROM. The second write to $8000 is always 0x00, and + // goes to the slave cart for unknown reasons. + // Once done, the code jumps to ($FFFC) to begin the game. + // All 12 bytes from $8001-800C are written regardless of how many codes are inserted. + // The value written to $8000 is the only clue as to what codes are actually valid and which + // ones have compare values. + if (offset) + { + offset -= 1; + int code = BIT(offset, 2, 2); + if (code == 3) + return; // how did we end up here? the GG is not expected to write to $800d-800f! - if (offset == 0 && data == 0) + switch (offset & 3) + { + case 0: + m_gg_addr[code] |= (data & 0x7f) << 8; + break; + case 1: + m_gg_addr[code] = data; + break; + case 2: + m_gg_comp[code] = data; + break; + case 3: + m_gg_repl[code] = data; + break; + } + } + else // 0x8000 + { + m_gg_bypass = BIT(data, 0); + for (int i = 0; i < 3; i++) { - m_gg_bypass = 1; - reset_cpu(); + m_gg_is_comp[i] = BIT(data, i + 1); + m_gg_enable[i] = !BIT(data, i + 4); } - else + // bit 7 is unused and always zero + + logerror("Game Genie Summary:\n"); + for (int i = 0; i < 3; i++) { - // bit 0 is always set (GG enable?) - m_gg_is_comp[0] = BIT(data, 1); - m_gg_is_comp[1] = BIT(data, 2); - m_gg_is_comp[2] = BIT(data, 3); - m_gg_disable[0] = BIT(data, 4); - m_gg_disable[1] = BIT(data, 5); - m_gg_disable[2] = BIT(data, 6); - // bit 7 is always clear - logerror("Game Genie Summary:\n"); - for (int i = 0; i < 3; i++) + logerror("Code %d: %s\n", i, m_gg_enable[i] ? "Yes" : "No"); + if (m_gg_enable[i]) { - logerror("Code %d: %s\n", i, m_gg_disable[i] ? "No" : "Yes"); - if (!m_gg_disable[i]) - { - logerror("\tAddr: 0x%X\n", m_gg_addr[i]); - logerror("\tValue: 0x%X\n", m_gg_repl[i]); - if (m_gg_is_comp[i]) - logerror("\t if equals: 0x%X\n", m_gg_comp[i]); - - } + logerror("\tAddr: 0x%X\n", m_gg_addr[i]); + logerror("\tValue: 0x%X\n", m_gg_repl[i]); + if (m_gg_is_comp[i]) + logerror("\t if equals: 0x%X\n", m_gg_comp[i]); } } } - else - m_ggslot->write_h(offset, data); } -void nes_ggenie_device::write_m(offs_t offset, uint8_t data) +void nes_ggenie_device::write_m(offs_t offset, u8 data) { - if (m_gg_bypass && m_ggslot) + if (m_gg_bypass) m_ggslot->write_m(offset, data); } -void nes_ggenie_device::write_l(offs_t offset, uint8_t data) +void nes_ggenie_device::write_l(offs_t offset, u8 data) { - if (m_gg_bypass && m_ggslot) + if (m_gg_bypass) m_ggslot->write_l(offset, data); } -uint8_t nes_ggenie_device::read_h(offs_t offset) +u8 nes_ggenie_device::read_h(offs_t offset) { if (m_gg_bypass && m_ggslot->m_cart) { - uint8_t rom_value = m_ggslot->m_cart->hi_access_rom(offset); + u8 rom_value = m_ggslot->m_cart->hi_access_rom(offset); // check if GG code has to act on this address for (int i = 0; i < 3; i++) { - if (!m_gg_disable[i] && offset == m_gg_addr[i]) + if (m_gg_enable[i] && offset == m_gg_addr[i]) { - if (!m_gg_is_comp[i] || (m_gg_is_comp[i] && m_gg_comp[i] == rom_value)) + if (!m_gg_is_comp[i] || m_gg_comp[i] == rom_value) return m_gg_repl[i]; } } - return rom_value; + return rom_value; } - return hi_access_rom(offset); + return m_prg[offset & 0xfff]; // ROM is only 4K } -uint8_t nes_ggenie_device::read_m(offs_t offset) +u8 nes_ggenie_device::read_m(offs_t offset) { - if (m_gg_bypass && m_ggslot->m_cart) - return m_ggslot->m_cart->read_m(offset); + if (m_gg_bypass) + return m_ggslot->read_m(offset); return 0xff; } -uint8_t nes_ggenie_device::read_l(offs_t offset) +u8 nes_ggenie_device::read_l(offs_t offset) { - if (m_gg_bypass && m_ggslot->m_cart) - return m_ggslot->m_cart->read_l(offset); + if (m_gg_bypass) + return m_ggslot->read_l(offset); return 0xff; } -void nes_ggenie_device::chr_w(offs_t offset, uint8_t data) +void nes_ggenie_device::chr_w(offs_t offset, u8 data) { - int bank = offset >> 10; - if (m_gg_bypass && m_ggslot->m_cart) - { m_ggslot->m_cart->chr_w(offset, data); - return; - } - - if (m_chr_src[bank] == CHRRAM) - m_chr_access[bank][offset & 0x3ff] = data; } -uint8_t nes_ggenie_device::chr_r(offs_t offset) +u8 nes_ggenie_device::chr_r(offs_t offset) { - int bank = offset >> 10; - if (m_gg_bypass && m_ggslot->m_cart) - return m_ggslot->m_cart->chr_r(offset); - - return m_chr_access[bank][offset & 0x3ff]; + return m_ggslot->m_cart->chr_r(offset); + else + { + // there is no on-board CHRROM, 1 of 4 values are generated based on PPU A2, A4, A5, A6, A7, resulting in 16 tiles + static constexpr u8 chr_lut[4] = { 0x00, 0xf0, 0x0f, 0xff }; + return chr_lut[BIT(offset, BIT(offset, 2) ? 4 : 6, 2)]; + } } -void nes_ggenie_device::nt_w(offs_t offset, uint8_t data) +void nes_ggenie_device::nt_w(offs_t offset, u8 data) { - int page = ((offset & 0xc00) >> 10); - if (m_gg_bypass && m_ggslot->m_cart) - { m_ggslot->m_cart->nt_w(offset, data); - return; - } - - if (!m_nt_writable[page]) - return; - - m_nt_access[page][offset & 0x3ff] = data; + else + device_nes_cart_interface::nt_w(offset, data); } -uint8_t nes_ggenie_device::nt_r(offs_t offset) +u8 nes_ggenie_device::nt_r(offs_t offset) { - int page = ((offset & 0xc00) >> 10); - if (m_gg_bypass && m_ggslot->m_cart) return m_ggslot->m_cart->nt_r(offset); - - return m_nt_access[page][offset & 0x3ff]; + else + return device_nes_cart_interface::nt_r(offset); } |