M3745x: Preliminary support for the Mitsubishi M37450 microcontroller [R. Belmont]

This commit is contained in:
R. Belmont 2013-03-18 01:12:44 +00:00
parent 6172ebc94e
commit f89b0d6d3c
4 changed files with 661 additions and 1 deletions

2
.gitattributes vendored
View File

@ -559,6 +559,8 @@ src/emu/cpu/m6502/dm65ce02.lst svneol=native#text/plain
src/emu/cpu/m6502/dm740.lst svneol=native#text/plain
src/emu/cpu/m6502/dn2a03.lst svneol=native#text/plain
src/emu/cpu/m6502/dr65c02.lst svneol=native#text/plain
src/emu/cpu/m6502/m3745x.c svneol=native#text/plain
src/emu/cpu/m6502/m3745x.h svneol=native#text/plain
src/emu/cpu/m6502/m4510.c svneol=native#text/plain
src/emu/cpu/m6502/m4510.h svneol=native#text/plain
src/emu/cpu/m6502/m6502.c svneol=native#text/plain

View File

@ -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...

498
src/emu/cpu/m6502/m3745x.c Normal file
View File

@ -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))
{
}

156
src/emu/cpu/m6502/m3745x.h Normal file
View File

@ -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