summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/tengen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes/tengen.cpp')
-rw-r--r--src/devices/bus/nes/tengen.cpp194
1 files changed, 70 insertions, 124 deletions
diff --git a/src/devices/bus/nes/tengen.cpp b/src/devices/bus/nes/tengen.cpp
index f6228685796..2304ee9a201 100644
--- a/src/devices/bus/nes/tengen.cpp
+++ b/src/devices/bus/nes/tengen.cpp
@@ -8,12 +8,10 @@
Here we emulate the following PCBs
- * Tengen 800008
* Tengen 800032 [mapper 64]
* Tengen 800037 [mapper 158]
- TODO:
- - emulated the IRQ delay in 800032 (possibly reason of Skull & Crossbones not working?)
+ Note, Tetris' Tengen 800008 [mapper 148] is implemented in sachen.cpp.
***********************************************************************************************************/
@@ -25,39 +23,32 @@
#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_TENGEN_800008, nes_tengen008_device, "nes_tengen008", "NES Cart Tengen 800008 PCB")
DEFINE_DEVICE_TYPE(NES_TENGEN_800032, nes_tengen032_device, "nes_tengen032", "NES Cart Tengen 800032 PCB")
DEFINE_DEVICE_TYPE(NES_TENGEN_800037, nes_tengen037_device, "nes_tengen037", "NES Cart Tengen 800037 PCB")
-nes_tengen008_device::nes_tengen008_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : nes_nrom_device(mconfig, NES_TENGEN_800008, tag, owner, clock)
-{
-}
-
-nes_tengen032_device::nes_tengen032_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_irq_count(0), m_irq_count_latch(0), m_irq_mode(0), m_irq_reset(0), m_irq_enable(0), m_latch(0), irq_timer(nullptr)
+nes_tengen032_device::nes_tengen032_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_latch(0), m_irq_count(0), m_irq_count_latch(0), m_irq_mode(0), m_irq_reset(0), m_irq_enable(0), m_irq_pending(0), irq_timer(nullptr)
{
}
-nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: nes_tengen032_device(mconfig, NES_TENGEN_800032, tag, owner, clock)
{
}
-nes_tengen037_device::nes_tengen037_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+nes_tengen037_device::nes_tengen037_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: nes_tengen032_device(mconfig, NES_TENGEN_800037, tag, owner, clock)
{
}
@@ -65,24 +56,12 @@ nes_tengen037_device::nes_tengen037_device(const machine_config &mconfig, const
-void nes_tengen008_device::device_start()
-{
- common_start();
-}
-
-void nes_tengen008_device::pcb_reset()
-{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
- prg32(0);
- chr8(0, m_chr_source);
-}
-
void nes_tengen032_device::device_start()
{
common_start();
- irq_timer = timer_alloc(TIMER_IRQ);
- irq_timer->reset();
+ irq_timer = timer_alloc(FUNC(nes_tengen032_device::irq_timer_tick), this);
timer_freq = clocks_to_attotime(4);
+ irq_timer->adjust(attotime::zero, 0, timer_freq);
save_item(NAME(m_mmc_prg_bank));
save_item(NAME(m_mmc_vrom_bank));
@@ -91,24 +70,27 @@ void nes_tengen032_device::device_start()
save_item(NAME(m_irq_mode));
save_item(NAME(m_irq_reset));
save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_pending));
save_item(NAME(m_irq_count));
save_item(NAME(m_irq_count_latch));
}
void nes_tengen032_device::pcb_reset()
{
- m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
- prg16_89ab(m_prg_chunks - 1);
+ prg16_89ab(0);
prg16_cdef(m_prg_chunks - 1);
chr8(0, m_chr_source);
- memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank));
- memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+
+ std::fill(std::begin(m_mmc_prg_bank), std::end(m_mmc_prg_bank), 0x00);
+ std::fill(std::begin(m_mmc_vrom_bank), std::end(m_mmc_vrom_bank), 0x00);
m_latch = 0;
m_irq_mode = 0;
m_irq_reset = 0;
m_irq_enable = 0;
- m_irq_count = m_irq_count_latch = 0;
+ m_irq_pending = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0xff;
}
@@ -118,27 +100,6 @@ void nes_tengen032_device::pcb_reset()
/*-------------------------------------------------
- Tengen 800008 Board
-
- iNES: mapper 3?
-
- In MESS: Supported.
-
- -------------------------------------------------*/
-
-void nes_tengen008_device::write_h(offs_t offset, uint8_t data)
-{
- LOG_MMC(("tengen008 write_h, offset: %04x, data: %02x\n", offset, data));
-
- // this pcb is subject to bus conflict
- data = account_bus_conflict(offset, data);
-
- prg32(data >> 3);
- chr8(data, CHRROM);
-}
-
-/*-------------------------------------------------
-
Tengen 800032 Board
Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls
@@ -150,10 +111,12 @@ void nes_tengen008_device::write_h(offs_t offset, uint8_t data)
iNES: mapper 64
- In MESS: Partially Supported (there should be a small
- delay between the IRQ and its execution, but that is not
- emulated yet: this is possibly the problem with Skulls
- & Crossbones)
+ In MAME: Partially supported.
+
+ TODO: There are issues with IRQ. Skull & Crossbones
+ probably doesn't work because of this? It alone uses
+ the cycle-based IRQ (and it constantly switches
+ between IRQ modes).
-------------------------------------------------*/
@@ -168,33 +131,38 @@ inline void nes_tengen032_device::irq_clock(int blanked)
if (m_irq_reset)
{
m_irq_reset = 0;
- m_irq_count = m_irq_count_latch + 1;
+ m_irq_count = m_irq_count_latch | (m_irq_count_latch ? 1 : 0);
}
else if (!m_irq_count)
m_irq_count = m_irq_count_latch;
+ else
+ m_irq_count--;
- m_irq_count--;
if (m_irq_enable && !blanked && !m_irq_count)
- set_irq_line(ASSERT_LINE);
+ m_irq_pending = 1;
}
// we use the HBLANK IRQ latch from PPU for the scanline based IRQ mode
// and a timer for the cycle based IRQ mode, which both call irq_clock
-void nes_tengen032_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(nes_tengen032_device::irq_timer_tick)
{
- if (id == TIMER_IRQ)
+ if (m_irq_pending)
{
- irq_clock(0);
+ set_irq_line(ASSERT_LINE);
+ m_irq_pending = 0;
}
+
+ if (m_irq_mode)
+ irq_clock(0);
}
-void nes_tengen032_device::hblank_irq(int scanline, int vblank, int blanked)
+void nes_tengen032_device::hblank_irq(int scanline, bool vblank, bool blanked)
{
if (!m_irq_mode) // we are in scanline mode!
{
- if (scanline < ppu2c0x_device::BOTTOM_VISIBLE_SCANLINE)
+ if (scanline <= ppu2c0x_device::BOTTOM_VISIBLE_SCANLINE)
{
irq_clock(blanked);
}
@@ -203,47 +171,40 @@ void nes_tengen032_device::hblank_irq(int scanline, int vblank, int blanked)
void nes_tengen032_device::set_prg()
{
- uint8_t prg_mode = m_latch & 0x40;
-
- prg8_89(m_mmc_prg_bank[prg_mode ? 2: 0]);
- prg8_ab(m_mmc_prg_bank[prg_mode ? 0: 1]);
- prg8_cd(m_mmc_prg_bank[prg_mode ? 1: 2]);
-}
+ u8 prg_flip = (m_latch & 0x40) >> 5;
-void nes_tengen032_device::chr_cb(int start, int bank, int source)
-{
- chr1_x(start, bank, source);
+ prg8_89(m_mmc_prg_bank[0 ^ prg_flip]);
+ prg8_ab(m_mmc_prg_bank[1]);
+ prg8_cd(m_mmc_prg_bank[2 ^ prg_flip]);
}
void nes_tengen032_device::set_chr()
{
- uint8_t chr_page = (m_latch & 0x80) >> 5;
+ u8 chr_flip = (m_latch & 0x80) >> 5;
if (m_latch & 0x20)
{
- chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0], CHRROM);
- chr_cb(1 ^ chr_page, m_mmc_vrom_bank[6], CHRROM);
- chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1], CHRROM);
- chr_cb(3 ^ chr_page, m_mmc_vrom_bank[7], CHRROM);
+ chr1_x(0 ^ chr_flip, m_mmc_vrom_bank[0], CHRROM);
+ chr1_x(1 ^ chr_flip, m_mmc_vrom_bank[6], CHRROM);
+ chr1_x(2 ^ chr_flip, m_mmc_vrom_bank[1], CHRROM);
+ chr1_x(3 ^ chr_flip, m_mmc_vrom_bank[7], CHRROM);
}
else
{
- chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0] & ~0x01, CHRROM);
- chr_cb(1 ^ chr_page, m_mmc_vrom_bank[0] | 0x01, CHRROM);
- chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1] & ~0x01, CHRROM);
- chr_cb(3 ^ chr_page, m_mmc_vrom_bank[1] | 0x01, CHRROM);
+ chr2_x(0 ^ chr_flip, m_mmc_vrom_bank[0] >> 1, CHRROM);
+ chr2_x(2 ^ chr_flip, m_mmc_vrom_bank[1] >> 1, CHRROM);
}
- chr_cb(4 ^ chr_page, m_mmc_vrom_bank[2], CHRROM);
- chr_cb(5 ^ chr_page, m_mmc_vrom_bank[3], CHRROM);
- chr_cb(6 ^ chr_page, m_mmc_vrom_bank[4], CHRROM);
- chr_cb(7 ^ chr_page, m_mmc_vrom_bank[5], CHRROM);
+ chr1_x(4 ^ chr_flip, m_mmc_vrom_bank[2], CHRROM);
+ chr1_x(5 ^ chr_flip, m_mmc_vrom_bank[3], CHRROM);
+ chr1_x(6 ^ chr_flip, m_mmc_vrom_bank[4], CHRROM);
+ chr1_x(7 ^ chr_flip, m_mmc_vrom_bank[5], CHRROM);
}
-void nes_tengen032_device::tengen032_write(offs_t offset, uint8_t data)
+void nes_tengen032_device::write_h(offs_t offset, u8 data)
{
- uint8_t helper, cmd;
- LOG_MMC(("tengen032_write, offset: %04x, data: %02x\n", offset, data));
+ u8 helper, cmd;
+ LOG("tengen032 write_h, offset: %04x, data: %02x\n", offset, data);
switch (offset & 0x6001)
{
@@ -293,17 +254,16 @@ void nes_tengen032_device::tengen032_write(offs_t offset, uint8_t data)
m_irq_count_latch = data;
break;
- case 0x4001: /* $c001 - IRQ scanline latch */
+ case 0x4001: // $c001 - IRQ scanline latch
m_irq_mode = data & 0x01;
if (m_irq_mode)
irq_timer->adjust(attotime::zero, 0, timer_freq);
- else
- irq_timer->adjust(attotime::never);
m_irq_reset = 1;
break;
case 0x6000:
m_irq_enable = 0;
+ m_irq_pending = 0;
set_irq_line(CLEAR_LINE);
break;
@@ -312,7 +272,7 @@ void nes_tengen032_device::tengen032_write(offs_t offset, uint8_t data)
break;
default:
- LOG_MMC(("Tengen 800032 write. addr: %04x value: %02x\n", offset + 0x8000, data));
+ LOG("Tengen 800032 write. addr: %04x value: %02x\n", offset + 0x8000, data);
break;
}
}
@@ -330,46 +290,32 @@ void nes_tengen032_device::tengen032_write(offs_t offset, uint8_t data)
iNES: mapper 158
- In MESS: Supported.
+ In MAME: Supported.
-------------------------------------------------*/
-void nes_tengen037_device::set_mirror()
+void nes_tengen037_device::set_chr()
{
- 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_tengen032_device::set_chr();
-void nes_tengen037_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_tengen037_device::write_h(offs_t offset, uint8_t data)
+void nes_tengen037_device::write_h(offs_t offset, u8 data)
{
- LOG_MMC(("tengen037 write_h, offset: %04x, data: %02x\n", offset, data));
+ LOG("tengen037 write_h, offset: %04x, data: %02x\n", offset, data);
switch (offset & 0x6001)
{
case 0x2000:
break;
-
default:
- tengen032_write(offset, data);
+ nes_tengen032_device::write_h(offset, data);
break;
}
}