diff options
Diffstat (limited to 'src/devices/cpu/m6502/m50734.cpp')
-rw-r--r-- | src/devices/cpu/m6502/m50734.cpp | 97 |
1 files changed, 93 insertions, 4 deletions
diff --git a/src/devices/cpu/m6502/m50734.cpp b/src/devices/cpu/m6502/m50734.cpp index dda9a6c8969..b4e31f003c7 100644 --- a/src/devices/cpu/m6502/m50734.cpp +++ b/src/devices/cpu/m6502/m50734.cpp @@ -15,6 +15,11 @@ #include "emu.h" #include "m50734.h" +#define LOG_INIT (1 << 1U) +#define LOG_TIMER (1 << 2U) +#define VERBOSE (0) +#include "logmacro.h" + // device type definition DEFINE_DEVICE_TYPE(M50734, m50734_device, "m50734", "Mitsubishi M50734") @@ -28,6 +33,8 @@ m50734_device::m50734_device(const machine_config &mconfig, const char *tag, dev , m_port_3state{0, 0, 0, 0} , m_ad_control(0) , m_ad_register(0) + , m_prescaler_reload{0xff, 0xff, 0xff} + , m_timer_reload{0xff, 0xff, 0xff} { program_config.m_internal_map = address_map_constructor(FUNC(m50734_device::internal_map), this); } @@ -49,6 +56,23 @@ void m50734_device::device_resolve_objects() m_analog_in_cb.resolve_all_safe(0); } +template <int N> +TIMER_CALLBACK_MEMBER(m50734_device::timer_interrupt) +{ + if (!BIT(m_interrupt_control[1], N * 2 + 1)) + { + m_interrupt_control[1] |= 1 << (N * 2 + 1); + if (BIT(m_interrupt_control[1], N * 2)) + { + LOGMASKED(LOG_TIMER, "Timer %d interrupt asserted at %s\n", N + 1, machine().time().to_string()); + set_input_line(M740_INT2_LINE, ASSERT_LINE); + } + } + + // Reload timer and prescaler + m_timer[N]->adjust(clocks_to_attotime(16 * u32(m_prescaler_reload[N] + 1) * (m_timer_reload[N] + 1))); +} + void m50734_device::device_start() { m740_device::device_start(); @@ -56,6 +80,9 @@ void m50734_device::device_start() space(has_space(AS_DATA) ? AS_DATA : AS_PROGRAM).specific(m_data); m_ad_timer = timer_alloc(FUNC(m50734_device::ad_complete), this); + m_timer[0] = timer_alloc(FUNC(m50734_device::timer_interrupt<0>), this); + m_timer[1] = timer_alloc(FUNC(m50734_device::timer_interrupt<1>), this); + m_timer[2] = timer_alloc(FUNC(m50734_device::timer_interrupt<2>), this); save_item(NAME(m_port_latch)); save_item(NAME(m_port_direction)); @@ -63,6 +90,9 @@ void m50734_device::device_start() save_item(NAME(m_p2_p3_function)); save_item(NAME(m_ad_control)); save_item(NAME(m_ad_register)); + save_item(NAME(m_prescaler_reload)); + save_item(NAME(m_timer_reload)); + save_item(NAME(m_interrupt_control)); } void m50734_device::device_reset() @@ -77,6 +107,10 @@ void m50734_device::device_reset() m_p2_p3_function = 0x00; m_ad_control |= 0x04; m_ad_timer->adjust(attotime::never); + + // Reset interrupts + std::fill(std::begin(m_interrupt_control), std::end(m_interrupt_control), 0x00); + set_input_line(M740_INT2_LINE, CLEAR_LINE); } void m50734_device::read_dummy(u16 adr) @@ -100,6 +134,28 @@ void m50734_device::write_data(u16 adr, u8 val) m740_device::write(adr, val); } +u8 m50734_device::interrupt_control_r(offs_t offset) +{ + return m_interrupt_control[2 - offset]; +} + +void m50734_device::interrupt_control_w(offs_t offset, u8 data) +{ + if (offset == 1) + data &= 0x3f; + u8 old_control = std::exchange(m_interrupt_control[2 - offset], data); + if (offset == 1) + { + bool timer_interrupt = (data & (data >> 1) & 0x15) != 0; + bool old_interrupt = (old_control & (old_control >> 1) & 0x15) != 0; + if (timer_interrupt != old_interrupt) + { + LOGMASKED(LOG_TIMER, "%s: Timer interrupt %sactivated by write to interrupt control register 2 ($%02X -> $%02X)\n", machine().describe_context(), timer_interrupt ? "": "de", old_control, data); + set_input_line(M740_INT2_LINE, timer_interrupt ? ASSERT_LINE : CLEAR_LINE); + } + } +} + template <int N> u8 m50734_device::port_r(offs_t offset) { @@ -118,7 +174,7 @@ void m50734_device::port_w(offs_t offset, u8 data) { if (m_port_direction[N] != data) { - logerror("%s: Port P%d direction = $%02X\n", machine().describe_context(), N, data); + LOGMASKED(LOG_INIT, "%s: Port P%d direction = $%02X\n", machine().describe_context(), N, data); m_port_direction[N] = data; m_port_out_cb[N]((data & m_port_latch[N]) | (m_port_3state[N] & ~m_port_direction[N])); } @@ -140,7 +196,7 @@ u8 m50734_device::p0_function_r() void m50734_device::p0_function_w(u8 data) { - logerror("%s: Port P0 function = $%02X\n", machine().describe_context(), data); + LOGMASKED(LOG_INIT, "%s: Port P0 function = $%02X\n", machine().describe_context(), data); m_p0_function = data; } @@ -151,7 +207,7 @@ u8 m50734_device::p2_p3_function_r() void m50734_device::p2_p3_function_w(u8 data) { - logerror("%s: Port P2/P3 function = $%02X\n", machine().describe_context(), data); + LOGMASKED(LOG_INIT, "%s: Port P2/P3 function = $%02X\n", machine().describe_context(), data); m_p2_p3_function = data & 0xc7; } @@ -177,9 +233,41 @@ u8 m50734_device::ad_r() return m_ad_register; } +u8 m50734_device::timer_r(offs_t offset) +{ + if (!m_timer[offset >> 1]->enabled()) + return 0; + + u32 ticks = attotime_to_clocks(m_timer[offset >> 1]->remaining()) / 16; + u8 pre = m_prescaler_reload[offset >> 1]; + if (BIT(offset, 0)) + return std::min<u32>(ticks / (pre + 1), 0xff); + else + return ticks % (pre + 1); +} + +void m50734_device::timer_w(offs_t offset, u8 data) +{ + u32 ticks = m_timer[offset >> 1]->enabled() ? attotime_to_clocks(m_timer[offset >> 1]->remaining()) / 16 : 0x10000; + u8 pre = m_prescaler_reload[offset >> 1]; + if (BIT(offset, 0)) + { + LOGMASKED(LOG_INIT, "%s: Reload timer %d latch = %d\n", machine().describe_context(), (offset >> 1) + 1, data); + m_timer_reload[offset >> 1] = data; + m_timer[offset >> 1]->adjust(clocks_to_attotime(16 * (data * pre + (ticks % (pre + 1)) + 1))); + } + else + { + LOGMASKED(LOG_INIT, "%s: Reload prescaler %d latch = %d\n", machine().describe_context(), (offset >> 1) + 1, data); + m_prescaler_reload[offset >> 1] = data; + m_timer[offset >> 1]->adjust(clocks_to_attotime(16 * (data + 1) * (std::min<u32>(ticks / (pre + 1), 0xff) + 1))); + } +} + void m50734_device::internal_map(address_map &map) { - // TODO: timers, etc. + // TODO: other timers, UART, etc. + map(0x00dc, 0x00e1).rw(FUNC(m50734_device::timer_r), FUNC(m50734_device::timer_w)); map(0x00e9, 0x00e9).rw(FUNC(m50734_device::ad_control_r), FUNC(m50734_device::ad_control_w)); map(0x00ea, 0x00ea).r(FUNC(m50734_device::ad_r)); map(0x00eb, 0x00eb).r(FUNC(m50734_device::p4_r)); @@ -189,4 +277,5 @@ void m50734_device::internal_map(address_map &map) map(0x00f3, 0x00f4).rw(FUNC(m50734_device::port_r<1>), FUNC(m50734_device::port_w<1>)); map(0x00f5, 0x00f5).rw(FUNC(m50734_device::p0_function_r), FUNC(m50734_device::p0_function_w)); map(0x00f6, 0x00f7).rw(FUNC(m50734_device::port_r<0>), FUNC(m50734_device::port_w<0>)); + map(0x00fd, 0x00ff).rw(FUNC(m50734_device::interrupt_control_r), FUNC(m50734_device::interrupt_control_w)); } |