From 12501a8f4e08d772e5f59c5029d9e926d9ded3c1 Mon Sep 17 00:00:00 2001 From: mooglyguy Date: Thu, 2 Jan 2020 18:43:30 +0100 Subject: [PATCH] -psion5: Added basic support for timers. [Ninji, Ryan Holtz] --- src/mame/drivers/psion5.cpp | 151 +++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 1 deletion(-) diff --git a/src/mame/drivers/psion5.cpp b/src/mame/drivers/psion5.cpp index 15884f76400..ad3155128e3 100644 --- a/src/mame/drivers/psion5.cpp +++ b/src/mame/drivers/psion5.cpp @@ -17,6 +17,7 @@ #include "emu.h" #include "cpu/arm7/arm7.h" +#include "cpu/arm7/arm7core.h" #include "screen.h" @@ -35,10 +36,21 @@ protected: virtual void machine_start() override; virtual void machine_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + private: + DECLARE_READ32_MEMBER(periphs_r); DECLARE_WRITE32_MEMBER(periphs_w); + void set_timer_reload(int timer, uint32_t value); + void set_timer_ctrl(int timer, uint32_t value); + void check_timer(int timer); + void check_interrupts(); + + static constexpr device_timer_id TID_TIMER1 = 0; + static constexpr device_timer_id TID_TIMER2 = 1; + enum { REG_MEMCFG1 = 0x0000, @@ -115,19 +127,139 @@ private: REG_LCDMUX = 0x0e2c }; + enum + { + IRQ_EXTFIQ = 0, // FiqExternal + IRQ_BLINT = 1, // FiqBatLow + IRQ_WEINT = 2, // FiqWatchDog + IRQ_MCINT = 3, // FiqMediaChg + IRQ_CSINT = 4, // IrqCodec + IRQ_EINT1 = 5, // IrqExt1 + IRQ_EINT2 = 6, // IrqExt2 + IRQ_EINT3 = 7, // IrqExt3 + IRQ_TC1OI = 8, // IrqTimer1 + IRQ_TC2OI = 9, // IrqTimer2 + IRQ_RTCMI = 10, // IrqRtcMatch + IRQ_TINT = 11, // IrqTick + IRQ_UART1 = 12, // IrqUart1 + IRQ_UART2 = 13, // IrqUart2 + IRQ_LCDINT = 14, // IrqLcd + IRQ_SSEOTI = 15, // IrqSpi + IRQ_FIQ_MASK = 0x000f, + IRQ_IRQ_MASK = 0xfff0 + }; + void main_map(address_map &map); uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); required_device m_maincpu; + emu_timer *m_timers[2]; + uint32_t m_timer_reload[2]; + uint32_t m_timer_ctrl[2]; + uint32_t m_pending_ints; + uint32_t m_int_mask; }; void psion5_state::machine_start() { + m_timers[0] = timer_alloc(TID_TIMER1); + m_timers[1] = timer_alloc(TID_TIMER2); + save_item(NAME(m_timer_reload[0])); + save_item(NAME(m_timer_reload[1])); + save_item(NAME(m_timer_ctrl[0])); + save_item(NAME(m_timer_ctrl[1])); + save_item(NAME(m_pending_ints)); + save_item(NAME(m_int_mask)); } void psion5_state::machine_reset() { + m_timers[0]->adjust(attotime::never); + m_timers[1]->adjust(attotime::never); + m_timer_reload[0] = m_timer_reload[1] = 0; + m_timer_ctrl[0] = m_timer_ctrl[1] = 0; + m_pending_ints = 0; + m_int_mask = 0; +} + +void psion5_state::check_interrupts() +{ + m_maincpu->set_input_line(ARM7_FIRQ_LINE, m_pending_ints & m_int_mask & IRQ_FIQ_MASK); + m_maincpu->set_input_line(ARM7_IRQ_LINE, m_pending_ints & m_int_mask & IRQ_IRQ_MASK); +} + +void psion5_state::check_timer(int timer) +{ + logerror("Checking Timer %d\n", timer + 1); + if (BIT(m_timer_ctrl[timer], 7)) + { + logerror("Bit 7 is set, in %d * %08x\n", BIT(m_timer_ctrl[timer], 3) ? 1 : m_timer_reload[timer], BIT(m_timer_ctrl[timer], 3) ? 512000 : 36000000); + attotime interval = BIT(m_timer_ctrl[timer], 3) ? attotime::from_ticks(1, 512000) : attotime::from_ticks(m_timer_reload[timer], 36000000); + if (BIT(m_timer_ctrl[timer], 6)) + { + logerror("Adjusting periodic\n"); + m_timers[timer]->adjust(interval, 0, interval); + } + else + { + logerror("Adjusting non-periodic\n"); + m_timers[timer]->adjust(interval, 0); + } + } + else + { + logerror("Cancelling\n"); + m_timers[timer]->adjust(attotime::never); + } +} + +void psion5_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TID_TIMER1) + { + logerror("Triggering 1\n"); + m_pending_ints |= (1 << IRQ_TC1OI); + } + else if (id == TID_TIMER2) + { + logerror("Triggering 2\n"); + m_pending_ints |= (1 << IRQ_TC2OI); + } + check_interrupts(); +} + +void psion5_state::set_timer_reload(int timer, uint32_t value) +{ + const uint32_t old = m_timer_reload[timer]; + m_timer_reload[timer] = value; + logerror("%s: Timer %d reload = %08x\n", machine().describe_context(), timer + 1, value); + if (old != value) + { + m_timer_reload[timer] = value; + check_timer(timer); + } +} + +void psion5_state::set_timer_ctrl(int timer, uint32_t value) +{ + const uint32_t old = m_timer_ctrl[timer]; + const uint32_t changed = old ^ value; + m_timer_ctrl[timer] = value; + if (changed != 0) + { + attotime interval = BIT(m_timer_ctrl[timer], 3) ? attotime::from_ticks(1, 512000) : attotime::from_ticks(m_timer_reload[timer], 36000000); + if (BIT(changed, 6)) + { + logerror("Timer %d, adjusting to an interval\n", timer + 1); + m_timers[timer]->adjust(m_timers[timer]->remaining(), 0, interval); + } + if (BIT(changed, 7)) + { + logerror("Timer %d, just checking timer\n", timer + 1); + check_timer(timer); + } + } } READ32_MEMBER(psion5_state::periphs_r) @@ -195,12 +327,15 @@ READ32_MEMBER(psion5_state::periphs_r) break; case REG_INTSR: + data = m_pending_ints; logerror("%s: peripheral read, INTSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_INTRSR: + data = m_pending_ints; logerror("%s: peripheral read, INTRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_INTENS: + data = m_int_mask; logerror("%s: peripheral read, INTENS = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_INTENC: @@ -247,24 +382,28 @@ READ32_MEMBER(psion5_state::periphs_r) break; case REG_TC1LOAD: + data = m_timer_reload[0]; logerror("%s: peripheral read, TC1LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC1VAL: logerror("%s: peripheral read, TC1VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC1CTRL: + data = m_timer_ctrl[0]; logerror("%s: peripheral read, TC1CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC1EOI: logerror("%s: peripheral read, TC1EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC2LOAD: + data = m_timer_reload[1]; logerror("%s: peripheral read, TC2LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC2VAL: logerror("%s: peripheral read, TC2VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC2CTRL: + data = m_timer_ctrl[1]; logerror("%s: peripheral read, TC2CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC2EOI: @@ -333,7 +472,7 @@ READ32_MEMBER(psion5_state::periphs_r) logerror("%s: peripheral read, Unknown = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; } - return 0; + return data; } WRITE32_MEMBER(psion5_state::periphs_w) @@ -406,9 +545,11 @@ WRITE32_MEMBER(psion5_state::periphs_w) logerror("%s: peripheral write, INTRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_INTENS: + m_int_mask |= data & mem_mask; logerror("%s: peripheral write, INTENS = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_INTENC: + m_int_mask &= ~(data & mem_mask); logerror("%s: peripheral write, INTENC = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_INTTEST1: @@ -453,27 +594,35 @@ WRITE32_MEMBER(psion5_state::periphs_w) case REG_TC1LOAD: logerror("%s: peripheral write, TC1LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); + set_timer_reload(0, data); break; case REG_TC1VAL: logerror("%s: peripheral write, TC1VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC1CTRL: logerror("%s: peripheral write, TC1CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + set_timer_ctrl(0, data); break; case REG_TC1EOI: logerror("%s: peripheral write, TC1EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_TC1OI); + check_interrupts(); break; case REG_TC2LOAD: logerror("%s: peripheral write, TC2LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); + set_timer_reload(1, data); break; case REG_TC2VAL: logerror("%s: peripheral write, TC2VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_TC2CTRL: logerror("%s: peripheral write, TC2CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + set_timer_ctrl(1, data); break; case REG_TC2EOI: logerror("%s: peripheral write, TC2EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_TC2OI); + check_interrupts(); break; case REG_BZCONT: