/*********************************************************************************************************** NES/Famicom cartridge emulation for IREM PCBs Copyright MESS Team. Visit http://mamedev.org for licensing and usage restrictions. Here we emulate the following PCBs * IREM LROG017 [mapper 77] * IREM Holy Diver [mapper 78] * IREM TAM-S1 [mapper 97] * IREM G101 [mapper 32] * IREM H3001 [mapper 65] ***********************************************************************************************************/ #include "emu.h" #include "machine/nes_irem.h" #include "cpu/m6502/m6502.h" #ifdef NES_PCB_DEBUG #define VERBOSE 1 #else #define VERBOSE 0 #endif #define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) //------------------------------------------------- // constructor //------------------------------------------------- const device_type NES_LROG017 = &device_creator; const device_type NES_HOLYDIVR = &device_creator; const device_type NES_TAM_S1 = &device_creator; const device_type NES_G101 = &device_creator; const device_type NES_H3001 = &device_creator; nes_lrog017_device::nes_lrog017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : nes_nrom_device(mconfig, NES_LROG017, "NES Cart Irem Discrete 74*161/161/21/138 PCB", tag, owner, clock, "nes_lrog017", __FILE__) { } nes_holydivr_device::nes_holydivr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : nes_nrom_device(mconfig, NES_HOLYDIVR, "NES Cart Irem Holy Diver PCB", tag, owner, clock, "nes_holydivr", __FILE__) { } nes_tam_s1_device::nes_tam_s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : nes_nrom_device(mconfig, NES_TAM_S1, "NES Cart Irem TAM-S1 PCB", tag, owner, clock, "nes_tam_s1", __FILE__) { } nes_g101_device::nes_g101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : nes_nrom_device(mconfig, NES_G101, "NES Cart Irem G-101 PCB", tag, owner, clock, "nes_g101", __FILE__) { } nes_h3001_device::nes_h3001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : nes_nrom_device(mconfig, NES_H3001, "NES Cart Irem H-3001 PCB", tag, owner, clock, "nes_h3001", __FILE__) { } void nes_lrog017_device::device_start() { common_start(); } void nes_lrog017_device::pcb_reset() { prg32(0); chr2_0(0, CHRROM); chr2_2(0, CHRRAM); chr2_4(1, CHRRAM); chr2_6(2, CHRRAM); } void nes_holydivr_device::device_start() { common_start(); } void nes_holydivr_device::pcb_reset() { m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; prg16_89ab(0); prg16_cdef(m_prg_chunks - 1); chr8(0, m_chr_source); } void nes_tam_s1_device::device_start() { common_start(); } void nes_tam_s1_device::pcb_reset() { m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; prg16_89ab(m_prg_chunks - 1); prg16_cdef(0); chr8(0, m_chr_source); } void nes_g101_device::device_start() { common_start(); save_item(NAME(m_latch)); } void nes_g101_device::pcb_reset() { m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; prg16_89ab(0); prg16_cdef(m_prg_chunks - 1); chr8(0, m_chr_source); m_latch = 0; } void nes_h3001_device::device_start() { common_start(); irq_timer = timer_alloc(TIMER_IRQ); irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); save_item(NAME(m_irq_enable)); save_item(NAME(m_irq_count)); save_item(NAME(m_irq_count_latch)); } void nes_h3001_device::pcb_reset() { m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; prg16_89ab(0); prg16_cdef(m_prg_chunks - 1); chr8(0, m_chr_source); m_irq_enable = 0; m_irq_count = 0; m_irq_count_latch = 0; } /*------------------------------------------------- mapper specific handlers -------------------------------------------------*/ /*------------------------------------------------- Irem LROG017 - Discrete board emulation (74*161/161/21/138) Games: Napoleon Senki iNES: mapper 77 This board should use 2KB of CHRRAM as NTRAM, instead of using directly 4-screen mirroring, but for the moment we cheat in this way... -------------------------------------------------*/ WRITE8_MEMBER(nes_lrog017_device::write_h) { LOG_MMC(("lrog017 write_h, offset: %04x, data: %02x\n", offset, data)); // this pcb is subject to bus conflict data = account_bus_conflict(offset, data); prg32(data); chr2_0((data >> 4), CHRROM); } /*------------------------------------------------- Irem Holy Diver board emulation iNES: mapper 78 (shared with JF-16) -------------------------------------------------*/ WRITE8_MEMBER(nes_holydivr_device::write_h) { LOG_MMC(("holy diver write_h, offset: %04x, data: %02x\n", offset, data)); // this pcb is subject to bus conflict data = account_bus_conflict(offset, data); set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); chr8(data >> 4, CHRROM); prg16_89ab(data); } /*------------------------------------------------- Irem TAM-S1 board emulation Games: Kaiketsu Yanchamaru iNES: mapper 97 In MESS: Supported. -------------------------------------------------*/ WRITE8_MEMBER(nes_tam_s1_device::write_h) { LOG_MMC(("tam s1 write_h, offset: %04x, data: %02x\n", offset, data)); if (offset < 0x4000) { // this pcb is subject to bus conflict data = account_bus_conflict(offset, data); set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); prg16_cdef(data); } } /*------------------------------------------------- Irem G-101 board emulation Major League uses hardwired mirroring iNES: mapper 32 -------------------------------------------------*/ WRITE8_MEMBER(nes_g101_device::write_h) { LOG_MMC(("g101 write_h, offset: %04x, data: %02x\n", offset, data)); switch (offset & 0x7000) { case 0x0000: // NEStopia here differs a little bit m_latch ? prg8_cd(data) : prg8_89(data); break; case 0x1000: m_latch = BIT(data, 1); if (m_pcb_ctrl_mirror) set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); break; case 0x2000: prg8_ab(data); break; case 0x3000: chr1_x(offset & 0x07, data, CHRROM); break; } } /*------------------------------------------------- Irem H-3001 board emulation Games: Daiku no Gen San 2 - Akage no Dan no Gyakushuu, Kaiketsu Yanchamaru 3, Spartan X 2 iNES: mapper 65 In MESS: Supported. -------------------------------------------------*/ void nes_h3001_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { if (id == TIMER_IRQ) { if (m_irq_enable) { // 16bit counter, IRQ fired when the counter reaches 0 // after firing, the counter is *not* reloaded and does not wrap if (m_irq_count > 0) m_irq_count--; if (!m_irq_count) { machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, ASSERT_LINE); m_irq_enable = 0; } } } } WRITE8_MEMBER(nes_h3001_device::write_h) { LOG_MMC(("h3001 write_h, offset %04x, data: %02x\n", offset, data)); switch (offset & 0x7fff) { case 0x0000: prg8_89(data); break; case 0x1001: set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); break; case 0x1003: m_irq_enable = data & 0x80; machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, CLEAR_LINE); break; case 0x1004: m_irq_count = m_irq_count_latch; machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, CLEAR_LINE); break; case 0x1005: m_irq_count_latch = (m_irq_count_latch & 0x00ff) | (data << 8); break; case 0x1006: m_irq_count_latch = (m_irq_count_latch & 0xff00) | data; break; case 0x2000: prg8_ab(data); break; case 0x3000: case 0x3001: case 0x3002: case 0x3003: case 0x3004: case 0x3005: case 0x3006: case 0x3007: chr1_x(offset & 0x07, data, CHRROM); break; case 0x4000: prg8_cd(data); break; default: break; } }