summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
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
commita9e8be4d6791cfe7e957ff57b8993f5e74b1352a (patch)
treeb1d1614814f6c85abd74c5117ff40d11a00f2cea
parentb20ba46fc75fba844edc442f2af2334faba18bb8 (diff)
i8155: Make timer more efficient by not counting each cycle
-rw-r--r--src/devices/machine/i8155.cpp111
-rw-r--r--src/devices/machine/i8155.h11
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);
};