summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/event.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes/event.c')
-rw-r--r--src/devices/bus/nes/event.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/src/devices/bus/nes/event.c b/src/devices/bus/nes/event.c
new file mode 100644
index 00000000000..4059b107a24
--- /dev/null
+++ b/src/devices/bus/nes/event.c
@@ -0,0 +1,239 @@
+// license:BSD-3-Clause
+// copyright-holders:Fabio Priuli
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Nintendo NES-EVENT PCB
+
+
+ Here we emulate the following PCBs
+
+ * Nintendo NES-EVENT [mapper 105]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "event.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_EVENT = &device_creator<nes_event_device>;
+
+
+nes_event_device::nes_event_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sxrom_device(mconfig, NES_EVENT, "NES Cart Event PCB", tag, owner, clock, "nes_event", __FILE__),
+ m_dsw(*this, "DIPSW")
+{
+}
+
+
+void nes_event_device::device_start()
+{
+ common_start();
+ event_timer = timer_alloc(TIMER_EVENT);
+ event_timer->adjust(attotime::never);
+ timer_freq = machine().device<cpu_device>("maincpu")->cycles_to_attotime(1);
+
+ save_item(NAME(m_latch));
+ save_item(NAME(m_count));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_reg_write_enable));
+ save_item(NAME(m_nwc_init));
+
+ save_item(NAME(m_timer_count));
+ save_item(NAME(m_timer_on));
+ save_item(NAME(m_timer_enabled));
+}
+
+void nes_event_device::pcb_reset()
+{
+ 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;
+ m_nwc_init = 2;
+
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ chr8(0, CHRRAM);
+ prg32(0);
+ m_timer_count = 0;
+ m_timer_enabled = 0;
+ m_timer_on = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Event PCB
+
+ Games: Nintento World Championships
+
+ MMC-1 variant with repurposed register at $a000 and a
+ lot of discrete components
+
+ iNES: mapper 105
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_event_device::set_chr()
+{
+ // no CHR switching, there are only 8KB VRAM from the cart
+}
+
+void nes_event_device::set_prg()
+{
+// printf("enter with %d and reg1 0x%x - reg3 0x%x\n", m_nwc_init, m_reg[1], m_reg[3]);
+ // reg[1] is different from base MMC-1!
+ // bit 0 is ignored, bit1/bit3 are used for PRG switch, bit4 is used for the timer
+ UINT8 temp = (m_reg[1] >> 1) & 7;
+
+ // initially PRG is fixed, until bit4 of reg1 is set to 1 and then to 0
+ switch (m_nwc_init)
+ {
+ case 2:
+ if (m_reg[1] & 0x10) m_nwc_init--;
+ return;
+ case 1:
+ if (~m_reg[1] & 0x10) m_nwc_init--;
+ return;
+ }
+
+ if (temp < 4)
+ prg32(temp);
+ else
+ {
+ // else PRG works similarly to base MMC-1, but only acts on the higher 128KB (2nd PRG ROM)
+ switch (m_reg[0] & 0x0c)
+ {
+ case 0x00:
+ case 0x04:
+ prg32(0x04 | ((m_reg[3] >> 1) & 0x03));
+ break;
+ case 0x08:
+ prg16_89ab(0x08 | 0x00);
+ prg16_cdef(0x08 | (m_reg[3] & 0x07));
+ break;
+ case 0x0c:
+ prg16_89ab(0x08 | (m_reg[3] & 0x07));
+ prg16_cdef(0x08 | 0x07);
+ break;
+ }
+ }
+
+ // after the init procedure above, bit4 of m_reg[1] is used to init IRQ, by setting and then clearing the bit
+ // however, there are (bankswitch related?) writes with bit4 cleared before the one 'enabling' the timer, so
+ // we need the additional m_timer_enabled variable, to avoid starting the timer before its time...
+ if (m_reg[1] & 0x10)
+ {
+ m_timer_enabled = 1;
+ m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
+ }
+ else
+ {
+ if (!m_timer_on && m_timer_enabled)
+ {
+ m_timer_count = 0x20000000 | ((m_dsw->read() & 0x0f) << 25);
+ event_timer->adjust(attotime::zero, 0, timer_freq);
+ m_timer_on = 1;
+ }
+ }
+}
+
+void nes_event_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_prg();
+ break;
+ case 1:
+ set_prg();
+ break;
+ case 2:
+ set_chr();
+ break;
+ case 3:
+ set_prg();
+ break;
+ }
+}
+
+//-------------------------------------------------
+// Dipswicth
+//-------------------------------------------------
+
+static INPUT_PORTS_START( nwc_dsw )
+ PORT_START("DIPSW")
+ PORT_DIPNAME( 0x0f, 0x04, "Timer" ) PORT_DIPLOCATION("SW:!1,!2,!3,!4")
+ PORT_DIPSETTING( 0x00, "5:00.4" )
+ PORT_DIPSETTING( 0x01, "5:19.2" )
+ PORT_DIPSETTING( 0x02, "5:38.0" )
+ PORT_DIPSETTING( 0x03, "5:56.7" )
+ PORT_DIPSETTING( 0x04, "6:15.5" )
+ PORT_DIPSETTING( 0x05, "6:34.3" )
+ PORT_DIPSETTING( 0x06, "6:53.1" )
+ PORT_DIPSETTING( 0x07, "7:11.9" )
+ PORT_DIPSETTING( 0x08, "7:30.6" )
+ PORT_DIPSETTING( 0x09, "7:49.4" )
+ PORT_DIPSETTING( 0x0a, "8:08.2" )
+ PORT_DIPSETTING( 0x0b, "8:27.0" )
+ PORT_DIPSETTING( 0x0c, "8:45.8" )
+ PORT_DIPSETTING( 0x0d, "9:04.5" )
+ PORT_DIPSETTING( 0x0e, "9:23.3" )
+ PORT_DIPSETTING( 0x0f, "9:42.1" )
+INPUT_PORTS_END
+
+
+
+ioport_constructor nes_event_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( nwc_dsw );
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void nes_event_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_EVENT)
+ {
+ m_timer_count--;
+ if (!m_timer_count)
+ {
+ m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ event_timer->reset();
+ }
+ }
+}