diff options
author | AJR <ajrhacker@users.noreply.github.com> | 2020-02-02 00:16:03 -0500 |
---|---|---|
committer | AJR <ajrhacker@users.noreply.github.com> | 2020-02-02 09:12:32 -0500 |
commit | a9e8be4d6791cfe7e957ff57b8993f5e74b1352a (patch) | |
tree | b1d1614814f6c85abd74c5117ff40d11a00f2cea | |
parent | b20ba46fc75fba844edc442f2af2334faba18bb8 (diff) |
i8155: Make timer more efficient by not counting each cycle
-rw-r--r-- | src/devices/machine/i8155.cpp | 111 | ||||
-rw-r--r-- | src/devices/machine/i8155.h | 11 |
2 files changed, 70 insertions, 52 deletions
diff --git a/src/devices/machine/i8155.cpp b/src/devices/machine/i8155.cpp index c8cb11f0216..4703fed8990 100644 --- a/src/devices/machine/i8155.cpp +++ b/src/devices/machine/i8155.cpp @@ -109,11 +109,22 @@ enum // INLINE HELPERS //************************************************************************** -inline uint8_t i8155_device::get_timer_mode() +inline uint8_t i8155_device::get_timer_mode() const { return (m_count_loaded >> 8) & TIMER_MODE_MASK; } +inline uint16_t i8155_device::get_timer_count() const +{ + if (m_timer->enabled()) + { + // timer counts down by twos + return std::min((uint16_t(attotime_to_clocks(m_timer->remaining())) + 1) << 1, m_count_loaded & 0x3ffe) | (m_count_even_phase ? 0 : 1); + } + else + return m_count_length; +} + inline void i8155_device::timer_output(int to) { if (to == m_to) @@ -128,7 +139,12 @@ inline void i8155_device::timer_output(int to) inline void i8155_device::timer_stop_count() { // stop counting - m_timer->enable(0); + if (m_timer->enabled()) + { + m_count_loaded = (m_count_loaded & (TIMER_MODE_MASK << 8)) | get_timer_count(); + m_timer->enable(false); + } + m_timer_tc->enable(false); // clear timer output timer_output(1); @@ -146,11 +162,10 @@ inline void i8155_device::timer_reload_count() } // begin the odd half of the count, with one extra cycle if count is odd - m_counter = (m_count_loaded & 0x3ffe) | 1; - m_count_extra = BIT(m_count_loaded, 0); + m_count_even_phase = false; // set up our timer - m_timer->adjust(attotime::zero, 0, clocks_to_attotime(1)); + m_timer->adjust(clocks_to_attotime(((m_count_length & 0x3ffe) >> 1) + (m_count_length & 1))); timer_output(1); switch (get_timer_mode()) @@ -271,9 +286,8 @@ i8155_device::i8155_device(const machine_config &mconfig, device_type type, cons m_status(0), m_count_length(0), m_count_loaded(0), - m_counter(0), - m_count_extra(false), - m_to(0) + m_to(0), + m_count_even_phase(false) { } @@ -307,7 +321,8 @@ void i8155_device::device_start() m_ram = make_unique_clear<uint8_t[]>(256); // allocate timers - m_timer = timer_alloc(); + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i8155_device::timer_half_counted), this)); + m_timer_tc = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i8155_device::timer_tc), this)); // register for state saving save_item(NAME(m_io_m)); @@ -318,8 +333,6 @@ void i8155_device::device_start() save_pointer(NAME(m_ram), 256); save_item(NAME(m_count_length)); save_item(NAME(m_count_loaded)); - save_item(NAME(m_count_extra)); - save_item(NAME(m_counter)); save_item(NAME(m_to)); } @@ -347,45 +360,15 @@ void i8155_device::device_reset() //------------------------------------------------- -// device_timer - handler timer events +// timer_half_counted - handler timer events //------------------------------------------------- -void i8155_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(i8155_device::timer_half_counted) { - if (m_count_extra) - { - m_count_extra = false; - return; - } - - // count down by twos - m_counter -= 2; - - if (m_counter == 1) - { - LOGMASKED(LOG_TIMER, "Timer count half finished\n"); - - // reload the even half of the count - m_counter = m_count_loaded & 0x3ffe; - - // square wave modes produce a low output in the second half of the counting period - if ((get_timer_mode() & TIMER_MODE_TC_PULSE) == 0) - timer_output(0); - } - else if (m_counter == 2) - { - if ((get_timer_mode() & TIMER_MODE_TC_PULSE) != 0) - { - // pulse low on TC being reached - timer_output(0); - } - - // set timer flag - m_status |= STATUS_TIMER; - } - else if (m_counter == 0) + if (m_count_even_phase) { timer_output(1); + m_count_even_phase = false; if ((get_timer_mode() & TIMER_MODE_AUTO_RELOAD) == 0 || (m_command & COMMAND_TM_MASK) == COMMAND_TM_STOP_AFTER_TC) { @@ -399,6 +382,37 @@ void i8155_device::device_timer(emu_timer &timer, device_timer_id id, int param, timer_reload_count(); } } + else + { + LOGMASKED(LOG_TIMER, "Timer count half finished\n"); + + // reload the even half of the count + m_timer->adjust(clocks_to_attotime((m_count_loaded & 0x3ffe) >> 1)); + m_count_even_phase = true; + + // square wave modes produce a low output in the second half of the counting period + if ((get_timer_mode() & TIMER_MODE_TC_PULSE) == 0) + timer_output(0); + else + m_timer_tc->adjust(clocks_to_attotime((std::max(m_count_loaded & 0x3ffe, 2) - 2) >> 1)); + } +} + + +//------------------------------------------------- +// timer_tc - generate TC low pulse +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(i8155_device::timer_tc) +{ + if ((get_timer_mode() & TIMER_MODE_TC_PULSE) != 0) + { + // pulse low on TC being reached + timer_output(0); + } + + // set timer flag + m_status |= STATUS_TIMER; } @@ -416,7 +430,8 @@ uint8_t i8155_device::io_r(offs_t offset) data = m_status; // clear timer flag - m_status &= ~STATUS_TIMER; + if (!machine().side_effects_disabled()) + m_status &= ~STATUS_TIMER; break; case REGISTER_PORT_A: @@ -432,11 +447,11 @@ uint8_t i8155_device::io_r(offs_t offset) break; case REGISTER_TIMER_LOW: - data = m_counter & 0xff; + data = get_timer_count() & 0xff; break; case REGISTER_TIMER_HIGH: - data = (m_counter >> 8 & 0x3f) | get_timer_mode(); + data = (get_timer_count() >> 8 & 0x3f) | get_timer_mode(); break; } diff --git a/src/devices/machine/i8155.h b/src/devices/machine/i8155.h index a4fe5b2938f..ace27e002c9 100644 --- a/src/devices/machine/i8155.h +++ b/src/devices/machine/i8155.h @@ -71,7 +71,6 @@ protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; private: devcb_read8 m_in_pa_cb; @@ -100,16 +99,17 @@ private: // counter uint16_t m_count_length; // count length register (assigned) uint16_t m_count_loaded; // count length register (loaded) - uint16_t m_counter; // counter register - bool m_count_extra; // extra cycle when count is odd int m_to; // timer output + bool m_count_even_phase; // timers emu_timer *m_timer; // counter timer + emu_timer *m_timer_tc; // counter timer (for TC) const address_space_config m_space_config; - inline uint8_t get_timer_mode(); + inline uint8_t get_timer_mode() const; + inline uint16_t get_timer_count() const; inline void timer_output(int to); inline void timer_stop_count(); inline void timer_reload_count(); @@ -119,6 +119,9 @@ private: void write_command(uint8_t data); void register_w(int offset, uint8_t data); + + TIMER_CALLBACK_MEMBER(timer_half_counted); + TIMER_CALLBACK_MEMBER(timer_tc); }; |