summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/c117.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/c117.cpp')
-rw-r--r--src/mame/machine/c117.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/src/mame/machine/c117.cpp b/src/mame/machine/c117.cpp
new file mode 100644
index 00000000000..de27ff06011
--- /dev/null
+++ b/src/mame/machine/c117.cpp
@@ -0,0 +1,230 @@
+// license:BSD-3-Clause
+// copyright-holders:Alex W. Jackson
+/*
+Namco Custom 117, used in System 1
+
+CUS117 is a simple MMU that provides a 23 bit virtual address space for a pair
+of M6809 CPUs. The chip outputs the various enable lines for RAM, ROM, video
+customs, etc., and bits 12-21 of the virtual address (bit 22 of the virtual
+address is handled internally: it selects between ROM and everything else)
+
+Each CPU's address space is evenly divided into eight 8KB banks, and each of
+these banks can be directed to any portion of the virtual address space
+(however, the last bank for each CPU is effectively read only, since writes to
+E000-FFFF control CUS117 itself)
+
+The main and sub CPUs share the same address and data bus, but each CPU can
+set up its own banks independently. The main CPU can also set the sub CPU's
+last bank (E000-FFFF, where the 6809 reset and interrupt vectors reside)
+
+As well as being an MMU, CUS117 serves as the interrupt controller for the
+two 6809s and as the reset generator for the entire system.
+*/
+
+#include "emu.h"
+#include "cpu/m6809/m6809.h"
+#include "machine/c117.h"
+
+
+const device_type NAMCO_C117 = &device_creator<namco_c117_device>;
+
+
+//-------------------------------------------------
+// namco_c117_device - constructor
+//-------------------------------------------------
+
+namco_c117_device::namco_c117_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, NAMCO_C117, "Namco C117 MMU", tag, owner, clock, "namco_c117", __FILE__),
+ device_memory_interface(mconfig, *this),
+ m_subres_cb(*this),
+ m_program_config("program", ENDIANNESS_BIG, 8, 23),
+ m_maincpu_tag(NULL),
+ m_subcpu_tag(NULL)
+{
+}
+
+//-------------------------------------------------
+// set_cpu_tags - set the tags of the two CPUs
+// connected to the device
+//-------------------------------------------------
+
+void namco_c117_device::set_cpu_tags(device_t &device, const char *maintag, const char *subtag)
+{
+ namco_c117_device &c117 = downcast<namco_c117_device &>(device);
+ c117.m_maincpu_tag = maintag;
+ c117.m_subcpu_tag = subtag;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void namco_c117_device::device_start()
+{
+ m_subres_cb.resolve_safe();
+
+ m_program = &space(AS_PROGRAM);
+
+ cpu_device *maincpu = siblingdevice<cpu_device>(m_maincpu_tag);
+ cpu_device *subcpu = siblingdevice<cpu_device>(m_subcpu_tag);
+
+ m_cpuexec[0] = maincpu;
+ m_cpuexec[1] = subcpu;
+ m_cpudirect[0] = &maincpu->space(AS_PROGRAM).direct();
+ m_cpudirect[1] = &subcpu->space(AS_PROGRAM).direct();
+
+ memset(&m_offsets, 0, sizeof(m_offsets));
+ m_subres = m_wdog = 0;
+ save_item(NAME(m_offsets));
+ save_item(NAME(m_subres));
+ save_item(NAME(m_wdog));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void namco_c117_device::device_reset()
+{
+ // default MMU setup for main CPU
+ m_offsets[0][0] = 0x0180 * 0x2000; // bank0 = 0x180(RAM) - evidence: wldcourt
+ m_offsets[0][1] = 0x0180 * 0x2000; // bank1 = 0x180(RAM) - evidence: berabohm
+ m_offsets[0][7] = 0x03ff * 0x2000; // bank7 = 0x3ff(PRG7)
+
+ // default MMU setup for sub CPU
+ m_offsets[1][0] = 0x0180 * 0x2000; // bank0 = 0x180(RAM) - evidence: wldcourt
+ m_offsets[1][7] = 0x03ff * 0x2000; // bank7 = 0x3ff(PRG7)
+
+ m_cpudirect[0]->force_update();
+ m_cpudirect[1]->force_update();
+
+ m_subres = m_wdog = 0;
+ m_subres_cb(ASSERT_LINE);
+
+ // reset the main CPU so it picks up the reset vector from the correct bank
+ m_cpuexec[0]->set_input_line(INPUT_LINE_RESET, PULSE_LINE);
+}
+
+
+READ8_MEMBER(namco_c117_device::main_r)
+{
+ return m_program->read_byte(remap(0, offset));
+}
+
+READ8_MEMBER(namco_c117_device::sub_r)
+{
+ return m_program->read_byte(remap(1, offset));
+}
+
+WRITE8_MEMBER(namco_c117_device::main_w)
+{
+ if (offset < 0xe000)
+ m_program->write_byte(remap(0, offset), data);
+ else
+ register_w(0, offset, data);
+}
+
+WRITE8_MEMBER(namco_c117_device::sub_w)
+{
+ if (offset < 0xe000)
+ m_program->write_byte(remap(1, offset), data);
+ else
+ register_w(1, offset, data);
+}
+
+// FIXME: the sound CPU watchdog is probably in CUS121, and definitely isn't in CUS117
+// however, until the watchdog is a device and it's possible to have two independent
+// watchdogs in a machine, it's easiest to handle it here
+WRITE8_MEMBER(namco_c117_device::sound_watchdog_w)
+{
+ kick_watchdog(2);
+}
+
+
+void namco_c117_device::register_w(int whichcpu, offs_t offset, UINT8 data)
+{
+ int reg = (offset >> 9) & 0xf;
+ bool unknown_reg = false;
+
+ switch (reg)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ bankswitch(whichcpu, reg, offset & 1, data);
+ break;
+ case 8: // F000 - SUBRES (halt/reset everything but main CPU)
+ if (whichcpu == 0)
+ {
+ m_subres = data & 1;
+ m_subres_cb(m_subres ? CLEAR_LINE : ASSERT_LINE);
+ }
+ else
+ unknown_reg = true;
+ break;
+ case 9: // F200 - kick watchdog
+ kick_watchdog(whichcpu);
+ break;
+// case 10: // F400 - unknown but used
+// break;
+ case 11: // F600 - IRQ ack
+ m_cpuexec[whichcpu]->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
+ break;
+ case 12: // F800 - FIRQ ack
+ m_cpuexec[whichcpu]->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE);
+ break;
+ case 13: // FA00 - assert FIRQ on sub CPU
+ if (whichcpu == 0)
+ m_cpuexec[1]->set_input_line(M6809_FIRQ_LINE, ASSERT_LINE);
+ else
+ unknown_reg = true;
+ break;
+ case 14: // FC00 - set initial ROM bank for sub CPU
+ if (whichcpu == 0)
+ {
+ m_offsets[1][7] = 0x600000 | (data * 0x2000);
+ m_cpudirect[1]->force_update();
+ }
+ else
+ unknown_reg = true;
+ break;
+ default:
+ unknown_reg = true;
+ }
+ if (unknown_reg)
+ logerror("'%s' writing to unknown CUS117 register %04X = %02X\n", (whichcpu ? m_subcpu_tag : m_maincpu_tag), offset, data);
+}
+
+void namco_c117_device::bankswitch(int whichcpu, int whichbank, int a0, UINT8 data)
+{
+ UINT32 &bank = m_offsets[whichcpu][whichbank];
+
+ // even writes set a22-a21; odd writes set a20-a13
+ if (a0 == 0)
+ bank = (bank & 0x1fe000) | ((data & 0x03) * 0x200000);
+ else
+ bank = (bank & 0x600000) | (data * 0x2000);
+
+ m_cpudirect[whichcpu]->force_update();
+}
+
+void namco_c117_device::kick_watchdog(int whichcpu)
+{
+ // FIXME: change to 3 once sound CPU watchdog is separated from this device
+ static const int ALL_CPU_MASK = 7;
+
+ m_wdog |= (1 << whichcpu);
+
+ if (m_wdog == ALL_CPU_MASK || !m_subres)
+ {
+ m_wdog = 0;
+ machine().watchdog_reset();
+ }
+}