From b09ea4008927f93d1605a48921eb5e18838c979d Mon Sep 17 00:00:00 2001 From: AJR Date: Mon, 10 Oct 2022 17:18:57 -0400 Subject: m50734: Emulate some on-chip timers * r100: Add LCD unit --- src/devices/cpu/m6502/m50734.cpp | 97 ++++++++++++++++++++++++++++++++++++++-- src/devices/cpu/m6502/m50734.h | 13 +++++- src/mame/kawai/kawai_r100.cpp | 52 +++++++++++++++++++++ 3 files changed, 157 insertions(+), 5 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 +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 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(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(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)); } diff --git a/src/devices/cpu/m6502/m50734.h b/src/devices/cpu/m6502/m50734.h index 425b6a34e34..0c98f86aa31 100644 --- a/src/devices/cpu/m6502/m50734.h +++ b/src/devices/cpu/m6502/m50734.h @@ -96,6 +96,9 @@ protected: virtual void write_data(u16 adr, u8 val) override; private: + u8 interrupt_control_r(offs_t offset); + void interrupt_control_w(offs_t offset, u8 data); + template u8 port_r(offs_t offset); template void port_w(offs_t offset, u8 data); u8 p4_r(); @@ -103,12 +106,16 @@ private: void p0_function_w(u8 data); u8 p2_p3_function_r(); void p2_p3_function_w(u8 data); + u8 ad_control_r(); void ad_control_w(u8 data); u8 ad_r(); - TIMER_CALLBACK_MEMBER(ad_complete); + u8 timer_r(offs_t offset); + void timer_w(offs_t offset, u8 data); + template TIMER_CALLBACK_MEMBER(timer_interrupt); + void internal_map(address_map &map); const address_space_config m_data_config; @@ -119,6 +126,7 @@ private: devcb_read8::array<4> m_analog_in_cb; emu_timer *m_ad_timer; + emu_timer *m_timer[3]; u8 m_port_latch[4]; u8 m_port_direction[4]; @@ -127,6 +135,9 @@ private: u8 m_p2_p3_function; u8 m_ad_control; u8 m_ad_register; + u8 m_prescaler_reload[3]; + u8 m_timer_reload[3]; + u8 m_interrupt_control[3]; }; DECLARE_DEVICE_TYPE(M50734, m50734_device) diff --git a/src/mame/kawai/kawai_r100.cpp b/src/mame/kawai/kawai_r100.cpp index 8d9b73f8869..c98fc17366c 100644 --- a/src/mame/kawai/kawai_r100.cpp +++ b/src/mame/kawai/kawai_r100.cpp @@ -9,6 +9,9 @@ #include "emu.h" #include "cpu/m6502/m50734.h" #include "machine/nvram.h" +#include "video/hd44780.h" +#include "emupal.h" +#include "screen.h" class kawai_r100_state : public driver_device { @@ -16,26 +19,48 @@ public: kawai_r100_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_lcdc(*this, "lcdc") { } void r100(machine_config &config); +protected: + virtual void machine_start() override; + private: + HD44780_PIXEL_UPDATE(pixel_update); + void p0_w(u8 data); void p1_w(u8 data); void p2_w(u8 data); void p3_w(u8 data); + u8 sensor_lsi_r(offs_t offset); + void buffer_w(u8 data); void main_map(address_map &map); void data_map(address_map &map); required_device m_maincpu; + required_device m_lcdc; }; +void kawai_r100_state::machine_start() +{ + m_lcdc->rw_w(0); // write only +} + +HD44780_PIXEL_UPDATE(kawai_r100_state::pixel_update) +{ + if (x < 5 && y < 8 && line < 2 && pos < 16) + bitmap.pix(line * 8 + y, pos * 6 + x) = state; +} + void kawai_r100_state::p0_w(u8 data) { + m_lcdc->rs_w(BIT(data, 3)); + m_lcdc->e_w(BIT(data, 4)); } void kawai_r100_state::p1_w(u8 data) @@ -50,10 +75,22 @@ void kawai_r100_state::p3_w(u8 data) { } +u8 kawai_r100_state::sensor_lsi_r(offs_t offset) +{ + return 0; +} + +void kawai_r100_state::buffer_w(u8 data) +{ +} + void kawai_r100_state::main_map(address_map &map) { map(0x0000, 0x1fff).ram().share("nvram1"); map(0x2000, 0x3fff).ram().share("nvram2"); + map(0x4100, 0x41ff).r(FUNC(kawai_r100_state::sensor_lsi_r)); + map(0x4200, 0x4200).mirror(0xff).w(m_lcdc, FUNC(hd44780_device::db_w)); + map(0x4300, 0x4300).mirror(0xff).w(FUNC(kawai_r100_state::buffer_w)); map(0x4400, 0xffff).rom().region("program", 0x4400); } @@ -83,6 +120,21 @@ void kawai_r100_state::r100(machine_config &config) NVRAM(config, "nvram2", nvram_device::DEFAULT_ALL_0); // MB8464-15LL-SK + battery //M60009_AGU_DGU(config, "pcm", 5_MHz_XTAL); + + // LCD unit + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD)); + screen.set_refresh_hz(60); + screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */ + screen.set_screen_update("lcdc", FUNC(hd44780_device::screen_update)); + screen.set_size(6*16, 8*2); + screen.set_visarea_full(); + screen.set_palette("palette"); + + PALETTE(config, "palette", palette_device::MONOCHROME_INVERTED); + + HD44780(config, m_lcdc, 0); + m_lcdc->set_lcd_size(2, 16); + m_lcdc->set_pixel_update_cb(FUNC(kawai_r100_state::pixel_update)); } ROM_START(r100) -- cgit v1.2.3