diff options
Diffstat (limited to 'src/devices/cpu/m6502/m5074x.cpp')
-rw-r--r-- | src/devices/cpu/m6502/m5074x.cpp | 342 |
1 files changed, 246 insertions, 96 deletions
diff --git a/src/devices/cpu/m6502/m5074x.cpp b/src/devices/cpu/m6502/m5074x.cpp index 9626dc0d9ad..3295f2d28a9 100644 --- a/src/devices/cpu/m6502/m5074x.cpp +++ b/src/devices/cpu/m6502/m5074x.cpp @@ -1,29 +1,36 @@ // license:BSD-3-Clause // copyright-holders:R. Belmont, Olivier Galibert /* - Mitsubishi M5074x 8-bit microcontroller family + Mitsubishi M5074x/5075x 8-bit microcontroller family */ #include "emu.h" #include "m5074x.h" +#define LOG_ADC (1U << 1) +#define LOG_PORTS (1U << 2) +#define LOG_TIMER (1U << 3) + +#define VERBOSE (0) +#include "logmacro.h" + //************************************************************************** // MACROS / CONSTANTS //************************************************************************** -#define IRQ_CNTRREQ (0x80) -#define IRQ_CNTRENA (0x40) -#define IRQ_TMR1REQ (0x20) -#define IRQ_TMR1ENA (0x10) -#define IRQ_TMR2REQ (0x08) -#define IRQ_TMR2ENA (0x04) -#define IRQ_INTREQ (0x02) -#define IRQ_INTENA (0x01) +static constexpr u8 IRQ_CNTRREQ = 0x80; +static constexpr u8 IRQ_CNTRENA = 0x40; +static constexpr u8 IRQ_TMR1REQ = 0x20; +static constexpr u8 IRQ_TMR1ENA = 0x10; +static constexpr u8 IRQ_TMR2REQ = 0x08; +static constexpr u8 IRQ_TMR2ENA = 0x04; +static constexpr u8 IRQ_INTREQ = 0x02; +static constexpr u8 IRQ_INTENA = 0x01; -#define TMRC_TMRXREQ (0x80) -#define TMRC_TMRXENA (0x40) -#define TMRC_TMRXHLT (0x20) -#define TMRC_TMRXMDE (0x0c) +static constexpr u8 TMRC_TMRXREQ = 0x80; +static constexpr u8 TMRC_TMRXENA = 0x40; +static constexpr u8 TMRC_TMRXHLT = 0x20; +static constexpr u8 TMRC_TMRXMDE = 0x0c; //************************************************************************** // DEVICE DEFINITIONS @@ -31,6 +38,7 @@ DEFINE_DEVICE_TYPE(M50740, m50740_device, "m50740", "Mitsubishi M50740") DEFINE_DEVICE_TYPE(M50741, m50741_device, "m50741", "Mitsubishi M50741") +DEFINE_DEVICE_TYPE(M50753, m50753_device, "m50753", "Mitsubishi M50753") //************************************************************************** // LIVE DEVICE @@ -39,11 +47,11 @@ DEFINE_DEVICE_TYPE(M50741, m50741_device, "m50741", "Mitsubishi M50741") //------------------------------------------------- // m5074x_device - constructor //------------------------------------------------- -m5074x_device::m5074x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal_map) : +m5074x_device::m5074x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int addrbits, address_map_constructor internal_map) : m740_device(mconfig, type, tag, owner, clock), - m_program_config("program", ENDIANNESS_LITTLE, 8, 13, 0, internal_map), - m_read_p{{*this}, {*this}, {*this}, {*this}}, - m_write_p{{*this}, {*this}, {*this}, {*this}}, + m_program_config("program", ENDIANNESS_LITTLE, 8, addrbits, 0, internal_map), + m_read_p(*this, 0), + m_write_p(*this), m_intctrl(0), m_tmrctrl(0), m_tmr12pre(0), @@ -56,6 +64,7 @@ m5074x_device::m5074x_device(const machine_config &mconfig, device_type type, co m_tmrxlatch(0), m_last_all_ints(0) { + std::fill(std::begin(m_pullups), std::end(m_pullups), 0); } //------------------------------------------------- @@ -64,16 +73,10 @@ m5074x_device::m5074x_device(const machine_config &mconfig, device_type type, co void m5074x_device::device_start() { - for (int i = 0; i < 4; i++) - { - m_read_p[i].resolve_safe(0); - m_write_p[i].resolve_safe(); - } - - for (int i = 0; i < NUM_TIMERS; i++) - { - m_timers[i] = timer_alloc(i, nullptr); - } + m_timers[TIMER_1] = timer_alloc(FUNC(m5074x_device::timer1_tick), this); + m_timers[TIMER_2] = timer_alloc(FUNC(m5074x_device::timer2_tick), this); + m_timers[TIMER_X] = timer_alloc(FUNC(m5074x_device::timerx_tick), this); + m_timers[TIMER_ADC] = timer_alloc(FUNC(m5074x_device::adc_complete), this); m740_device::device_start(); @@ -123,42 +126,39 @@ void m5074x_device::device_reset() m_tmr1 = m_tmr2 = m_tmrx = 0; } -void m5074x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(m5074x_device::timer1_tick) { - switch (id) - { - case TIMER_1: - m_tmr1--; + m_tmr1--; - if (m_tmr1 <= 0) - { - m_intctrl |= IRQ_TMR1REQ; - m_tmr1 = m_tmr1latch; - recalc_irqs(); - } - break; + if (m_tmr1 <= 0) + { + m_intctrl |= IRQ_TMR1REQ; + m_tmr1 = m_tmr1latch; + recalc_irqs(); + } +} - case TIMER_2: - m_tmr2--; +TIMER_CALLBACK_MEMBER(m5074x_device::timer2_tick) +{ + m_tmr2--; - if (m_tmr2 <= 0) - { - m_intctrl |= IRQ_TMR2REQ; - m_tmr2 = m_tmr2latch; - recalc_irqs(); - } - break; + if (m_tmr2 <= 0) + { + m_intctrl |= IRQ_TMR2REQ; + m_tmr2 = m_tmr2latch; + recalc_irqs(); + } +} - case TIMER_X: - m_tmrx--; +TIMER_CALLBACK_MEMBER(m5074x_device::timerx_tick) +{ + m_tmrx--; - if (m_tmrx <= 0) - { - m_tmrctrl |= TMRC_TMRXREQ; - m_tmrx = m_tmrxlatch; - recalc_irqs(); - } - break; + if (m_tmrx == 0) + { + m_tmrctrl |= TMRC_TMRXREQ; + m_tmrx = m_tmrxlatch; + recalc_irqs(); } } @@ -166,20 +166,13 @@ void m5074x_device::execute_set_input(int inputnum, int state) { switch (inputnum) { - case M5074X_INT1_LINE: - if (state == ASSERT_LINE) - { - m_intctrl |= IRQ_INTREQ; - } - else - { - m_intctrl &= ~IRQ_INTREQ; - } - break; - - case M5074X_SET_OVERFLOW: // the base 740 class can handle this - m740_device::execute_set_input(M740_SET_OVERFLOW, state); - break; + case M5074X_INT1_LINE: + // FIXME: edge-triggered + if (state == ASSERT_LINE) + { + m_intctrl |= IRQ_INTREQ; + } + break; } recalc_irqs(); @@ -244,12 +237,14 @@ void m5074x_device::recalc_timer(int timer) case 0: hz = clock() / 16; hz /= (m_tmr12pre + 2); + LOGMASKED(LOG_TIMER, "%s: timer 1, prescale %02x, fire at %d Hz\n", machine().describe_context(), m_tmr12pre, hz); m_timers[TIMER_1]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); break; case 1: hz = clock() / 16; hz /= (m_tmr12pre + 2); + LOGMASKED(LOG_TIMER, "%s: timer 2, prescale %02x, fire at %d Hz\n", machine().describe_context(), m_tmr12pre, hz); m_timers[TIMER_2]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); break; @@ -261,12 +256,14 @@ void m5074x_device::recalc_timer(int timer) // stop bit? if (m_tmrctrl & TMRC_TMRXHLT) { + LOGMASKED(LOG_TIMER, "%s: timer X halted\n", machine().describe_context()); m_timers[TIMER_X]->adjust(attotime::never, 0, attotime::never); } else { hz = clock() / 16; hz /= (m_tmrxpre + 2); + LOGMASKED(LOG_TIMER, "%s: timer X, prescale %02x, fire at %d Hz\n", machine().describe_context(), m_tmrxpre, hz); m_timers[TIMER_X]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); } } @@ -278,8 +275,11 @@ void m5074x_device::recalc_timer(int timer) } } -void m5074x_device::send_port(address_space &space, uint8_t offset, uint8_t data) +void m5074x_device::send_port(uint8_t offset, uint8_t data) { + LOGMASKED(LOG_PORTS, "%s: Write port %d, data %02x DDR %02x pull-ups %02x\n", machine().describe_context(), offset, + data, m_ddrs[offset], m_pullups[offset]); + m_write_p[offset](data); } @@ -292,10 +292,13 @@ uint8_t m5074x_device::read_port(uint8_t offset) // OR in ddr-masked version of port writes incoming |= (m_ports[offset] & m_ddrs[offset]); + LOGMASKED(LOG_PORTS, "%s: Read port %d, incoming %02x DDR %02x output latch %02x\n", machine().describe_context(), offset, + m_read_p[offset](), m_ddrs[offset], m_ports[offset]); + return incoming; } -READ8_MEMBER(m5074x_device::ports_r) +uint8_t m5074x_device::ports_r(offs_t offset) { switch (offset) { @@ -322,58 +325,74 @@ READ8_MEMBER(m5074x_device::ports_r) case 9: return m_ddrs[3]; + + case 0xa: + return read_port(4) & 0x0f; + + case 0xb: + return m_ddrs[4]; } return 0xff; } -WRITE8_MEMBER(m5074x_device::ports_w) +void m5074x_device::ports_w(offs_t offset, uint8_t data) { switch (offset) { case 0: // p0 - send_port(space, 0, data & m_ddrs[0]); + send_port(0, (data & m_ddrs[0]) | (m_pullups[0] & ~m_ddrs[0])); m_ports[0] = data; break; case 1: // p0 ddr - send_port(space, 0, m_ports[0] & data); + send_port(0, (m_ports[0] & data) | (m_pullups[0] & ~data)); m_ddrs[0] = data; break; case 2: // p1 - send_port(space, 1, data & m_ddrs[1]); + send_port(1, (data & m_ddrs[1]) | (m_pullups[1] & ~m_ddrs[1])); m_ports[1] = data; break; case 3: // p1 ddr - send_port(space, 1, m_ports[1] & data); + send_port(1, (m_ports[1] & data) | (m_pullups[1] & ~data)); m_ddrs[1] = data; break; case 4: // p2 - send_port(space, 2, data & m_ddrs[2]); + send_port(2, (data & m_ddrs[2]) | (m_pullups[2] & ~m_ddrs[2])); m_ports[2] = data; break; case 5: // p2 ddr - send_port(space, 2, m_ports[2] & data); + send_port(2, (m_ports[2] & data) | (m_pullups[2] & ~data)); m_ddrs[2] = data; break; case 8: // p3 - send_port(space, 3, data & m_ddrs[3]); + send_port(3, (data & m_ddrs[3]) | (m_pullups[3] & ~m_ddrs[3])); m_ports[3] = data; break; case 9: // p3 ddr - send_port(space, 3, m_ports[3] & data); + send_port(3, (m_ports[3] & data) | (m_pullups[3] & ~data)); m_ddrs[3] = data; break; + + case 0xa: // p4 (4-bit open drain) + send_port(4, (data & m_ddrs[4] & 0x0f) | (m_pullups[4] & ~m_ddrs[4])); + m_ports[4] = data & 0x0f; + break; + + case 0xb: // p4 ddr + send_port(4, (m_ports[4] & data & 0x0f) | (m_pullups[4] & ~data)); + m_ddrs[4] = data & 0x0f; + break; } } -READ8_MEMBER(m5074x_device::tmrirq_r) +uint8_t m5074x_device::tmrirq_r(offs_t offset) { switch (offset) { @@ -402,54 +421,58 @@ READ8_MEMBER(m5074x_device::tmrirq_r) return 0xff; } -WRITE8_MEMBER(m5074x_device::tmrirq_w) +void m5074x_device::tmrirq_w(offs_t offset, uint8_t data) { -// printf("%02x to tmrirq @ %d\n", data, offset); - switch (offset) { case 0: m_tmr12pre = data; + LOGMASKED(LOG_TIMER, "%s: timer 1/2 prescale %02x\n", machine().describe_context(), data); recalc_timer(0); recalc_timer(1); break; case 1: m_tmr1 = m_tmr1latch = data; + LOGMASKED(LOG_TIMER, "%s: timer 1 latch %02x\n", machine().describe_context(), data); break; case 2: m_tmr2 = m_tmr2latch = data; + LOGMASKED(LOG_TIMER, "%s: timer 2 latch %02x\n", machine().describe_context(), data); break; case 3: - m_tmrxpre = m_tmrxlatch = data; + m_tmrxpre = data; + LOGMASKED(LOG_TIMER, "%s: timer X prescale %02x\n", machine().describe_context(), data); recalc_timer(2); break; case 4: - m_tmrx = data; + m_tmrx = m_tmrxlatch = data; + LOGMASKED(LOG_TIMER, "%s: timer X latch %02x\n", machine().describe_context(), data); break; case 5: - m_intctrl = data; + // Interrupt request bits can only be reset + m_intctrl = data & (m_intctrl | ~(IRQ_CNTRREQ | IRQ_INTREQ)); recalc_irqs(); break; case 6: - m_tmrctrl = data; + m_tmrctrl = data & (m_tmrctrl | ~TMRC_TMRXREQ); recalc_irqs(); break; } } -/* M50740 - baseline for this familiy */ +// M50740 - baseline for this family void m50740_device::m50740_map(address_map &map) { map(0x0000, 0x005f).ram(); map(0x00e0, 0x00e9).rw(FUNC(m50740_device::ports_r), FUNC(m50740_device::ports_w)); map(0x00f9, 0x00ff).rw(FUNC(m50740_device::tmrirq_r), FUNC(m50740_device::tmrirq_w)); - map(0x1400, 0x1fff).rom().region(M5074X_INTERNAL_ROM_REGION, 0); + map(0x1400, 0x1fff).rom().region(DEVICE_SELF, 0); } m50740_device::m50740_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : @@ -458,17 +481,17 @@ m50740_device::m50740_device(const machine_config &mconfig, const char *tag, dev } m50740_device::m50740_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : - m5074x_device(mconfig, type, tag, owner, clock, address_map_constructor(FUNC(m50740_device::m50740_map), this)) + m5074x_device(mconfig, type, tag, owner, clock, 13, address_map_constructor(FUNC(m50740_device::m50740_map), this)) { } -/* M50741 - 50740 with a larger internal ROM */ +// M50741 - 50740 with a larger internal ROM void m50741_device::m50741_map(address_map &map) { map(0x0000, 0x005f).ram(); map(0x00e0, 0x00e9).rw(FUNC(m50741_device::ports_r), FUNC(m50741_device::ports_w)); map(0x00f9, 0x00ff).rw(FUNC(m50741_device::tmrirq_r), FUNC(m50741_device::tmrirq_w)); - map(0x1000, 0x1fff).rom().region("internal", 0); + map(0x1000, 0x1fff).rom().region(DEVICE_SELF, 0); } m50741_device::m50741_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : @@ -477,6 +500,133 @@ m50741_device::m50741_device(const machine_config &mconfig, const char *tag, dev } m50741_device::m50741_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : - m5074x_device(mconfig, type, tag, owner, clock, address_map_constructor(FUNC(m50741_device::m50741_map), this)) + m5074x_device(mconfig, type, tag, owner, clock, 13, address_map_constructor(FUNC(m50741_device::m50741_map), this)) +{ +} + +// M50753 - M5074X with more pins, more RAM, more ROM, A-D, PWM, serial I/O (TODO) +void m50753_device::m50753_map(address_map &map) +{ + map(0x0000, 0x00bf).ram(); + map(0x00e0, 0x00eb).rw(FUNC(m50753_device::ports_r), FUNC(m50753_device::ports_w)); + map(0x00ee, 0x00ee).r(FUNC(m50753_device::in_r)); + map(0x00ef, 0x00ef).r(FUNC(m50753_device::ad_r)); + map(0x00f2, 0x00f2).nopr().w(FUNC(m50753_device::ad_start_w)); + map(0x00f3, 0x00f3).rw(FUNC(m50753_device::ad_control_r), FUNC(m50753_device::ad_control_w)); + map(0x00f5, 0x00f5).rw(FUNC(m50753_device::pwm_control_r), FUNC(m50753_device::pwm_control_w)); + map(0x00f9, 0x00ff).rw(FUNC(m50753_device::tmrirq_r), FUNC(m50753_device::tmrirq_w)); + map(0xe800, 0xffff).rom().region(DEVICE_SELF, 0); +} + +// interrupt bits on 50753 are slightly different from the 740/741. +static constexpr u8 IRQ_50753_INT1REQ = 0x80; +static constexpr u8 IRQ_50753_INTADC = 0x20; +static constexpr u8 IRQ_50753_INT2REQ = 0x02; + +m50753_device::m50753_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + m50753_device(mconfig, M50753, tag, owner, clock) +{ +} + +m50753_device::m50753_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + m5074x_device(mconfig, type, tag, owner, clock, 16, address_map_constructor(FUNC(m50753_device::m50753_map), this)), + m_ad_in(*this, 0), + m_in_p(*this, 0), + m_ad_control(0), + m_pwm_enabled(false) +{ +} + +void m50753_device::device_start() +{ + m5074x_device::device_start(); + + save_item(NAME(m_ad_control)); + save_item(NAME(m_pwm_enabled)); +} + +void m50753_device::device_reset() { + m5074x_device::device_reset(); + + m_ad_control = 0; + m_pwm_enabled = false; +} + +uint8_t m50753_device::in_r() +{ + return m_in_p(); +} + +uint8_t m50753_device::ad_r() +{ + m_intctrl &= ~IRQ_50753_INTADC; + recalc_irqs(); + + return m_ad_in[m_ad_control & 0x07](); +} + +void m50753_device::ad_start_w(uint8_t data) +{ + LOGMASKED(LOG_ADC, "%s: A-D start (IN%d)\n", machine().describe_context(), m_ad_control & 0x07); + + // starting a conversion. M50753 documentation says conversion time is 72 microseconds. + m_timers[TIMER_ADC]->adjust(attotime::from_usec(72)); +} + +uint8_t m50753_device::ad_control_r() +{ + return m_ad_control; +} + +void m50753_device::ad_control_w(uint8_t data) +{ + LOGMASKED(LOG_ADC, "%s: %02x to A-D control\n", machine().describe_context(), data); + m_ad_control = data & 0x0f; +} + +uint8_t m50753_device::pwm_control_r() +{ + return m_pwm_enabled ? 0x01 : 0x00; +} + +void m50753_device::pwm_control_w(uint8_t data) +{ + m_pwm_enabled = BIT(data, 0); +} + +void m50753_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case M50753_INT1_LINE: + // FIXME: edge-triggered + if (state == ASSERT_LINE) + { + m_intctrl |= IRQ_50753_INT1REQ; + } + break; + + case M50753_INT2_LINE: + // FIXME: edge-triggered + if (state == ASSERT_LINE) + { + m_intctrl |= IRQ_50753_INT2REQ; + } + break; + } + + recalc_irqs(); +} + +TIMER_CALLBACK_MEMBER(m50753_device::adc_complete) +{ + m_timers[TIMER_ADC]->adjust(attotime::never); + + // if interrupt source is the ADC, do it. + if (m_ad_control & 4) + { + m_intctrl |= IRQ_50753_INTADC; + recalc_irqs(); + } } |