summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/m6502/m3745x.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/m6502/m3745x.c')
-rw-r--r--src/devices/cpu/m6502/m3745x.c503
1 files changed, 503 insertions, 0 deletions
diff --git a/src/devices/cpu/m6502/m3745x.c b/src/devices/cpu/m6502/m3745x.c
new file mode 100644
index 00000000000..79aa2a95a83
--- /dev/null
+++ b/src/devices/cpu/m6502/m3745x.c
@@ -0,0 +1,503 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont, Olivier Galibert
+/*
+ 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, const char *shortname, const char *source) :
+ m740_device(mconfig, type, name, tag, owner, clock, "m3745x", source),
+ 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)
+{
+}
+
+//-------------------------------------------------
+// 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();
+
+ save_item(NAME(m_ports));
+ save_item(NAME(m_ddrs));
+ save_item(NAME(m_intreq1));
+ save_item(NAME(m_intreq2));
+ save_item(NAME(m_intctrl1));
+ save_item(NAME(m_intctrl2));
+ save_item(NAME(m_adctrl));
+ save_item(NAME(m_last_all_ints));
+
+ // 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.0;
+ 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), "m3745x", __FILE__)
+{
+}
+
+m37450_device::m37450_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ m3745x_device(mconfig, type, name, tag, owner, clock, ADDRESS_MAP_NAME(m37450_map), shortname, source)
+{
+}