summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2013-03-18 01:12:44 +0000
committer R. Belmont <rb6502@users.noreply.github.com>2013-03-18 01:12:44 +0000
commitf89b0d6d3c32a47d8d3dcb2b464a75fc795aedb5 (patch)
treed64f6ad22f7c2823c89af376c70c8abfa3d32616 /src
parent6172ebc94e1799a485952b7ce9fd5931acf55d1a (diff)
M3745x: Preliminary support for the Mitsubishi M37450 microcontroller [R. Belmont]
Diffstat (limited to 'src')
-rw-r--r--src/emu/cpu/cpu.mak6
-rw-r--r--src/emu/cpu/m6502/m3745x.c498
-rw-r--r--src/emu/cpu/m6502/m3745x.h156
3 files changed, 659 insertions, 1 deletions
diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak
index d0a24e31041..53cfe7a72bc 100644
--- a/src/emu/cpu/cpu.mak
+++ b/src/emu/cpu/cpu.mak
@@ -1034,7 +1034,8 @@ CPUOBJS += $(CPUOBJ)/m6502/deco16.o \
$(CPUOBJ)/m6502/m8502.o \
$(CPUOBJ)/m6502/n2a03.o \
$(CPUOBJ)/m6502/r65c02.o \
- $(CPUOBJ)/m6502/m740.o
+ $(CPUOBJ)/m6502/m740.o \
+ $(CPUOBJ)/m6502/m3745x.o \
DASMOBJS +=
endif
@@ -1116,6 +1117,9 @@ $(CPUOBJ)/m6502/m740.o: $(CPUSRC)/m6502/m740.c \
$(CPUSRC)/m6502/m740.h \
$(CPUSRC)/m6502/m6502.h
+$(CPUOBJ)/m6502/m3745x.o: $(CPUSRC)/m6502/m3745x.c \
+ $(CPUSRC)/m6502/m3745x.h
+
# rule to generate the C files
$(CPUOBJ)/m6502/deco16.inc: $(CPUSRC)/m6502/m6502make.py $(CPUSRC)/m6502/odeco16.lst $(CPUSRC)/m6502/ddeco16.lst
@echo Generating DECO16 source file...
diff --git a/src/emu/cpu/m6502/m3745x.c b/src/emu/cpu/m6502/m3745x.c
new file mode 100644
index 00000000000..87ecd7b5b25
--- /dev/null
+++ b/src/emu/cpu/m6502/m3745x.c
@@ -0,0 +1,498 @@
+/*
+ Mitsubishi M3745x 8-bit microcontroller family
+*/
+
+#include "emu.h"
+#include "m3745x.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+// Interrupt control bits (interpolated from C68 program; need 7450 Group manual badly)
+
+#define IRQ1_INT1 (0x04)
+#define IRQ1_INT2 (0x08) // guess, not used in C68
+#define IRQ1_INT3 (0x10) // guess, not used in C68
+
+#define IRQ2_SERIALRX (0x08)
+#define IRQ2_SERIALTX (0x10)
+#define IRQ2_ADC (0x20)
+
+#define ADCTRL_CH_MASK (0x07) // AD ctrl reg. channel mask
+#define ADCTRL_COMPLETE (0x08) // AD ctrl "start"/"complete" bit
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type M37450 = &device_creator<m37450_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// m3745x_device - constructor
+//-------------------------------------------------
+m3745x_device::m3745x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map) :
+ m740_device(mconfig, type, name, tag, owner, clock),
+ m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0, internal_map),
+ read_p3(*this),
+ read_p4(*this),
+ read_p5(*this),
+ read_p6(*this),
+ write_p3(*this),
+ write_p4(*this),
+ write_p5(*this),
+ write_p6(*this),
+ read_ad_0(*this),
+ read_ad_1(*this),
+ read_ad_2(*this),
+ read_ad_3(*this),
+ read_ad_4(*this),
+ read_ad_5(*this),
+ read_ad_6(*this),
+ read_ad_7(*this)
+{
+}
+
+void m3745x_device::device_config_complete()
+{
+ m_shortname = "m3745x";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m3745x_device::device_start()
+{
+ read_p3.resolve_safe(0);
+ read_p4.resolve_safe(0);
+ read_p5.resolve_safe(0);
+ read_p6.resolve_safe(0);
+ write_p3.resolve_safe();
+ write_p4.resolve_safe();
+ write_p5.resolve_safe();
+ write_p6.resolve_safe();
+ read_ad_0.resolve_safe(0);
+ read_ad_1.resolve_safe(0);
+ read_ad_2.resolve_safe(0);
+ read_ad_3.resolve_safe(0);
+ read_ad_4.resolve_safe(0);
+ read_ad_5.resolve_safe(0);
+ read_ad_6.resolve_safe(0);
+ read_ad_7.resolve_safe(0);
+
+ for (int i = 0; i < NUM_TIMERS; i++)
+ {
+ m_timers[i] = timer_alloc(i, NULL);
+ }
+
+ m740_device::device_start();
+
+ // all ports reset to input on startup
+ memset(m_ddrs, 0, sizeof(m_ddrs));
+ memset(m_ports, 0, sizeof(m_ports));
+ m_intreq1 = m_intreq2 = m_intctrl1 = m_intctrl2 = 0;
+ m_adctrl = 0;
+ m_last_all_ints = 0;
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m3745x_device::device_reset()
+{
+ m740_device::device_reset();
+
+ SP = 0x01ff; // we have the "traditional" stack in page 1, not 0 like some M740 derivatives
+
+ for (int i = 0; i < NUM_TIMERS; i++)
+ {
+ m_timers[i]->adjust(attotime::never);
+ }
+
+ // all ports reset to input on startup
+ memset(m_ddrs, 0, sizeof(m_ddrs));
+ memset(m_ports, 0, sizeof(m_ports));
+ m_intreq1 = m_intreq2 = m_intctrl1 = m_intctrl2 = 0;
+ m_adctrl = 0;
+ m_last_all_ints = 0;
+}
+
+void m3745x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_ADC:
+ m_timers[TIMER_ADC]->adjust(attotime::never);
+
+ m_adctrl |= ADCTRL_COMPLETE;
+ m_intreq2 |= IRQ2_ADC;
+ recalc_irqs();
+ break;
+
+ default:
+ printf("M3775x: unknown timer expire %d\n", id);
+ break;
+ }
+}
+
+void m3745x_device::execute_set_input(int inputnum, int state)
+{
+ switch (inputnum)
+ {
+ case M3745X_INT1_LINE:
+ if (state == ASSERT_LINE)
+ {
+ m_intreq1 |= IRQ1_INT1;
+ }
+ else
+ {
+ m_intreq1 &= ~IRQ1_INT1;
+ }
+ break;
+
+ case M3745X_INT2_LINE:
+ if (state == ASSERT_LINE)
+ {
+ m_intreq1 |= IRQ1_INT2;
+ }
+ else
+ {
+ m_intreq1 &= ~IRQ1_INT2;
+ }
+ break;
+
+ case M3745X_INT3_LINE:
+ if (state == ASSERT_LINE)
+ {
+ m_intreq1 |= IRQ1_INT3;
+ }
+ else
+ {
+ m_intreq1 &= ~IRQ1_INT3;
+ }
+ break;
+
+ case M3745X_SET_OVERFLOW: // the base 740 class can handle this
+ m740_device::execute_set_input(M740_SET_OVERFLOW, state);
+ break;
+ }
+
+ recalc_irqs();
+}
+
+void m3745x_device::recalc_irqs()
+{
+ UINT16 all_ints = 0;
+ int static const irq_lines[16] =
+ {
+ -1, -1, -1, M740_INT11_LINE, M740_INT12_LINE, M740_INT13_LINE, -1, -1,
+ -1, -1, M740_INT2_LINE, M740_INT3_LINE, M740_INT4_LINE, -1, -1, -1
+ };
+
+ all_ints = (m_intreq1 & m_intctrl1) << 8;
+ all_ints |= (m_intreq2 & m_intctrl2);
+
+// printf("recalc_irqs: last_all_ints = %04x last_ints = %04x (req1 %02x ctrl1 %02x req2 %02x ctrl2 %02x)\n", all_ints, m_last_all_ints, m_intreq1, m_intctrl1, m_intreq2, m_intctrl2);
+
+ // check all 16 IRQ bits for changes
+ for (int i = 0; i < 16; i++)
+ {
+ // if bit is set now
+ if (all_ints & (1 << i))
+ {
+ // and wasn't last time
+ if (!(m_last_all_ints & (1 << i)))
+ {
+// printf(" asserting irq %d (%d)\n", i, irq_lines[i]);
+ if (irq_lines[i] != -1)
+ {
+ m740_device::execute_set_input(irq_lines[i], ASSERT_LINE);
+ }
+ }
+ }
+ else // bit is clear now
+ {
+ // ...and wasn't clear last time
+ if (m_last_all_ints & (1 << i))
+ {
+// printf(" clearing irq %d (%d)\n", i, irq_lines[i]);
+ if (irq_lines[i] != -1)
+ {
+ m740_device::execute_set_input(irq_lines[i], CLEAR_LINE);
+ }
+ }
+ }
+ }
+
+ m_last_all_ints = all_ints;
+}
+
+void m3745x_device::send_port(address_space &space, UINT8 offset, UINT8 data)
+{
+ switch (offset)
+ {
+ case 0:
+ write_p3(data);
+ break;
+
+ case 1:
+ write_p4(data);
+ break;
+
+ case 2:
+ write_p5(data);
+ break;
+
+ case 3:
+ write_p6(data);
+ break;
+ }
+}
+
+UINT8 m3745x_device::read_port(UINT8 offset)
+{
+ UINT8 incoming = 0;
+
+ switch (offset)
+ {
+ case 0:
+ incoming = read_p3();
+ break;
+
+ case 1:
+ incoming = read_p4();
+ break;
+
+ case 2:
+ incoming = read_p5();
+ break;
+
+ case 3:
+ incoming = read_p6();
+ break;
+ }
+
+ // apply data direction registers
+ incoming &= (m_ddrs[offset] ^ 0xff);
+ // OR in ddr-masked version of port writes
+ incoming |= (m_ports[offset] & m_ddrs[offset]);
+
+ return incoming;
+}
+
+READ8_MEMBER(m3745x_device::ports_r)
+{
+ switch (offset)
+ {
+ case 0:
+ return read_port(0);
+
+ case 1:
+ return m_ddrs[0];
+
+ case 2:
+ return read_port(1);
+
+ case 4:
+ return read_port(2);
+
+ case 5:
+ return m_ddrs[2];
+
+ case 6:
+ return read_port(3);
+
+ case 7:
+ return m_ddrs[3];
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(m3745x_device::ports_w)
+{
+ switch (offset)
+ {
+ case 0: // p3
+ send_port(space, 0, data & m_ddrs[0]);
+ m_ports[0] = data;
+ break;
+
+ case 1: // p3 ddr
+ send_port(space, 0, m_ports[0] & data);
+ m_ddrs[0] = data;
+ break;
+
+ case 2: // p4
+ send_port(space, 1, data & m_ddrs[1]);
+ m_ports[1] = data;
+ break;
+
+ case 4: // p5
+ send_port(space, 2, data & m_ddrs[2]);
+ m_ports[2] = data;
+ break;
+
+ case 5: // p5 ddr
+ send_port(space, 2, m_ports[2] & data);
+ m_ddrs[2] = data;
+ break;
+
+ case 6: // p6
+ send_port(space, 3, data & m_ddrs[3]);
+ m_ports[3] = data;
+ break;
+
+ case 7: // p6 ddr
+ send_port(space, 3, m_ports[3] & data);
+ m_ddrs[3] = data;
+ break;
+ }
+}
+
+READ8_MEMBER(m3745x_device::intregs_r)
+{
+ switch (offset)
+ {
+ case 0:
+ return m_intreq1;
+
+ case 1:
+ return m_intreq2;
+
+ case 2:
+ return m_intctrl1;
+
+ case 3:
+ return m_intctrl2;
+ }
+
+ // this should never happen
+ assert(0);
+ return 0;
+}
+
+WRITE8_MEMBER(m3745x_device::intregs_w)
+{
+ switch (offset)
+ {
+ case 0:
+ m_intreq1 = data;
+ break;
+
+ case 1:
+ m_intreq2 = data;
+ break;
+
+ case 2:
+ m_intctrl1 = data;
+ break;
+
+ case 3:
+ m_intctrl2 = data;
+ break;
+ }
+
+ recalc_irqs();
+}
+
+READ8_MEMBER(m3745x_device::adc_r)
+{
+ UINT8 rv = 0;
+
+ switch (offset)
+ {
+ case 0:
+ m_intreq2 &= ~IRQ2_ADC;
+ recalc_irqs();
+
+ switch (m_adctrl & 7)
+ {
+ case 0:
+ rv = read_ad_0();
+ break;
+
+ case 1:
+ rv = read_ad_1();
+ break;
+
+ case 2:
+ rv = read_ad_2();
+ break;
+
+ case 3:
+ rv = read_ad_3();
+ break;
+
+ case 4:
+ rv = read_ad_4();
+ break;
+
+ case 5:
+ rv = read_ad_5();
+ break;
+
+ case 6:
+ rv = read_ad_6();
+ break;
+
+ case 7:
+ rv = read_ad_7();
+ break;
+ }
+ return rv;
+
+ case 1:
+ return m_adctrl;
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(m3745x_device::adc_w)
+{
+ switch (offset)
+ {
+ case 0:
+ printf("M3745x: Write %02x to ADC output?!\n", data);
+ break;
+
+ case 1:
+ m_adctrl = data;
+
+ // starting a conversion? this takes 50 cycles.
+ if (!(m_adctrl & ADCTRL_COMPLETE))
+ {
+ double hz = (double)clock() / 50.0f;
+ m_timers[TIMER_ADC]->adjust(attotime::from_hz(hz));
+ }
+ break;
+ }
+}
+
+/* M37450 - baseline for this familiy */
+static ADDRESS_MAP_START( m37450_map, AS_PROGRAM, 8, m37450_device )
+ AM_RANGE(0x0000, 0x00bf) AM_RAM
+ AM_RANGE(0x00d6, 0x00dd) AM_READWRITE(ports_r, ports_w)
+ AM_RANGE(0x00e2, 0x00e3) AM_READWRITE(adc_r, adc_w)
+ AM_RANGE(0x00fc, 0x00ff) AM_READWRITE(intregs_r, intregs_w)
+ AM_RANGE(0x0100, 0x01ff) AM_RAM
+ADDRESS_MAP_END
+
+m37450_device::m37450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ m3745x_device(mconfig, M37450, "Mitsubishi M37450", tag, owner, clock, ADDRESS_MAP_NAME(m37450_map))
+{
+}
+
+m37450_device::m37450_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
+ m3745x_device(mconfig, type, name, tag, owner, clock, ADDRESS_MAP_NAME(m37450_map))
+{
+}
+
diff --git a/src/emu/cpu/m6502/m3745x.h b/src/emu/cpu/m6502/m3745x.h
new file mode 100644
index 00000000000..43798a5b83a
--- /dev/null
+++ b/src/emu/cpu/m6502/m3745x.h
@@ -0,0 +1,156 @@
+#pragma once
+
+#ifndef __M3745X_H__
+#define __M3745X_H__
+
+#include "m740.h"
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_M3745X_ADC14_CALLBACKS(_ad0, _ad1, _ad2, _ad3) \
+ downcast<m3745x_device *>(device)->set_ad14_callbacks(DEVCB2_##_ad0, DEVCB2_##_ad1, DEVCB2_##_ad2, DEVCB2_##_ad3);
+
+#define MCFG_M3745X_ADC58_CALLBACKS(_ad0, _ad1, _ad2, _ad3) \
+ downcast<m3745x_device *>(device)->set_ad58_callbacks(DEVCB2_##_ad0, DEVCB2_##_ad1, DEVCB2_##_ad2, DEVCB2_##_ad3);
+
+#define MCFG_M3745X_PORT3_CALLBACKS(_read, _write) \
+ downcast<m3745x_device *>(device)->set_p3_callbacks(DEVCB2_##_read, DEVCB2_##_write);
+
+#define MCFG_M3745X_PORT4_CALLBACKS(_read, _write) \
+ downcast<m3745x_device *>(device)->set_p4_callbacks(DEVCB2_##_read, DEVCB2_##_write);
+
+#define MCFG_M3745X_PORT5_CALLBACKS(_read, _write) \
+ downcast<m3745x_device *>(device)->set_p5_callbacks(DEVCB2_##_read, DEVCB2_##_write);
+
+#define MCFG_M3745X_PORT6_CALLBACKS(_read, _write) \
+ downcast<m3745x_device *>(device)->set_p6_callbacks(DEVCB2_##_read, DEVCB2_##_write);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> m3745x_device
+
+class m3745x_device : public m740_device
+{
+ friend class m37450_device;
+
+ enum
+ {
+ TIMER_1 = 0,
+ TIMER_2,
+ TIMER_3,
+
+ TIMER_ADC,
+
+ NUM_TIMERS
+ };
+
+public:
+ enum
+ {
+ M3745X_INT1_LINE = INPUT_LINE_IRQ0,
+ M3745X_INT2_LINE,
+ M3745X_INT3_LINE,
+
+ M3745X_SET_OVERFLOW = M740_SET_OVERFLOW
+ };
+
+ // construction/destruction
+ m3745x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map);
+
+ const address_space_config m_program_config;
+
+ template<class _read, class _write> void set_p3_callbacks(_read rd, _write wr)
+ {
+ read_p3.set_callback(rd);
+ write_p3.set_callback(wr);
+ }
+
+ template<class _read, class _write> void set_p4_callbacks(_read rd, _write wr)
+ {
+ read_p4.set_callback(rd);
+ write_p4.set_callback(wr);
+ }
+
+ template<class _read, class _write> void set_p5_callbacks(_read rd, _write wr)
+ {
+ read_p5.set_callback(rd);
+ write_p5.set_callback(wr);
+ }
+
+ template<class _read, class _write> void set_p6_callbacks(_read rd, _write wr)
+ {
+ read_p6.set_callback(rd);
+ write_p6.set_callback(wr);
+ }
+
+ template<class _read, class _read2, class _read3, class _read4> void set_ad14_callbacks(_read rd, _read2 rd2, _read3 rd3, _read4 rd4)
+ {
+ read_ad_0.set_callback(rd);
+ read_ad_1.set_callback(rd2);
+ read_ad_2.set_callback(rd3);
+ read_ad_3.set_callback(rd4);
+ }
+
+ template<class _read, class _read2, class _read3, class _read4> void set_ad58_callbacks(_read rd, _read2 rd2, _read3 rd3, _read4 rd4)
+ {
+ read_ad_4.set_callback(rd);
+ read_ad_5.set_callback(rd2);
+ read_ad_6.set_callback(rd3);
+ read_ad_7.set_callback(rd4);
+ }
+
+ devcb2_read8 read_p3, read_p4, read_p5, read_p6;
+ devcb2_write8 write_p3, write_p4, write_p5, write_p6;
+ devcb2_read8 read_ad_0, read_ad_1, read_ad_2, read_ad_3;
+ devcb2_read8 read_ad_4, read_ad_5, read_ad_6, read_ad_7;
+
+ DECLARE_READ8_MEMBER(ports_r);
+ DECLARE_WRITE8_MEMBER(ports_w);
+ DECLARE_READ8_MEMBER(adc_r);
+ DECLARE_WRITE8_MEMBER(adc_w);
+ DECLARE_READ8_MEMBER(intregs_r);
+ DECLARE_WRITE8_MEMBER(intregs_w);
+
+ bool are_port_bits_output(UINT8 port, UINT8 mask) { return ((m_ddrs[port] & mask) == mask) ? true : false; }
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_config_complete();
+ virtual void execute_set_input(int inputnum, int state);
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; }
+
+ void send_port(address_space &space, UINT8 offset, UINT8 data);
+ UINT8 read_port(UINT8 offset);
+
+ void recalc_irqs();
+
+ UINT8 m_ports[6], m_ddrs[6];
+ UINT8 m_intreq1, m_intreq2, m_intctrl1, m_intctrl2;
+ UINT8 m_adctrl;
+ UINT16 m_last_all_ints;
+
+private:
+ emu_timer *m_timers[NUM_TIMERS];
+};
+
+class m37450_device : public m3745x_device
+{
+public:
+ m37450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ m37450_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+
+private:
+};
+
+extern const device_type M37450;
+
+#endif