summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/ggenie.cpp
diff options
context:
space:
mode:
author 0kmg <9137159+0kmg@users.noreply.github.com>2022-04-02 12:47:01 -0800
committer GitHub <noreply@github.com>2022-04-02 16:47:01 -0400
commit1039cc50df65effe584c12f3b5c12756e3ab3689 (patch)
treeeec6d65aa2b0cc125edc352dbfad08a22b9f6947 /src/devices/bus/nes/ggenie.cpp
parent8015fc79a730d9e3df4c384826d7abd687566176 (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.cpp230
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);
}