summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/i8155.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/i8155.cpp')
-rw-r--r--src/devices/machine/i8155.cpp160
1 files changed, 83 insertions, 77 deletions
diff --git a/src/devices/machine/i8155.cpp b/src/devices/machine/i8155.cpp
index c8cb11f0216..7fad5016760 100644
--- a/src/devices/machine/i8155.cpp
+++ b/src/devices/machine/i8155.cpp
@@ -38,8 +38,8 @@ DEFINE_DEVICE_TYPE(I8156, i8156_device, "i8156", "Intel 8156 RAM, I/O & Timer")
// MACROS / CONSTANTS
//**************************************************************************
-#define LOG_PORT (1U << 0)
-#define LOG_TIMER (1U << 1)
+#define LOG_PORT (1U << 1)
+#define LOG_TIMER (1U << 2)
#define VERBOSE (0)
#include "logmacro.h"
@@ -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())
@@ -230,10 +245,10 @@ inline uint8_t i8155_device::read_port(int port)
inline void i8155_device::write_port(int port, uint8_t data)
{
+ m_output[port] = data;
switch (get_port_mode(port))
{
case PORT_MODE_OUTPUT:
- m_output[port] = data;
if (port == PORT_A)
m_out_pa_cb((offs_t)0, m_output[port]);
else if (port == PORT_B)
@@ -253,27 +268,26 @@ inline void i8155_device::write_port(int port, uint8_t data)
// i8155_device - constructor
//-------------------------------------------------
-i8155_device::i8155_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : i8155_device(mconfig, I8155, tag, owner, clock)
+i8155_device::i8155_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i8155_device(mconfig, I8155, tag, owner, clock)
{
}
-i8155_device::i8155_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- m_in_pa_cb(*this),
- m_in_pb_cb(*this),
- m_in_pc_cb(*this),
- m_out_pa_cb(*this),
- m_out_pb_cb(*this),
- m_out_pc_cb(*this),
- m_out_to_cb(*this),
- m_command(0),
- m_status(0),
- m_count_length(0),
- m_count_loaded(0),
- m_counter(0),
- m_count_extra(false),
- m_to(0)
+i8155_device::i8155_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_in_pa_cb(*this, 0),
+ m_in_pb_cb(*this, 0),
+ m_in_pc_cb(*this, 0),
+ m_out_pa_cb(*this),
+ m_out_pb_cb(*this),
+ m_out_pc_cb(*this),
+ m_out_to_cb(*this),
+ m_command(0),
+ m_status(0),
+ m_count_length(0),
+ m_count_loaded(0),
+ m_to(0),
+ m_count_even_phase(false)
{
}
@@ -282,8 +296,8 @@ i8155_device::i8155_device(const machine_config &mconfig, device_type type, cons
// i8156_device - constructor
//-------------------------------------------------
-i8156_device::i8156_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : i8155_device(mconfig, I8156, tag, owner, clock)
+i8156_device::i8156_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i8155_device(mconfig, I8156, tag, owner, clock)
{
}
@@ -294,20 +308,12 @@ i8156_device::i8156_device(const machine_config &mconfig, const char *tag, devic
void i8155_device::device_start()
{
- // resolve callbacks
- m_in_pa_cb.resolve_safe(0);
- m_in_pb_cb.resolve_safe(0);
- m_in_pc_cb.resolve_safe(0);
- m_out_pa_cb.resolve_safe();
- m_out_pb_cb.resolve_safe();
- m_out_pc_cb.resolve_safe();
- m_out_to_cb.resolve_safe();
-
// allocate RAM
m_ram = make_unique_clear<uint8_t[]>(256);
// allocate timers
- m_timer = timer_alloc();
+ m_timer = timer_alloc(FUNC(i8155_device::timer_half_counted), this);
+ m_timer_tc = timer_alloc(FUNC(i8155_device::timer_tc), this);
// register for state saving
save_item(NAME(m_io_m));
@@ -318,8 +324,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 +351,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 +373,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 +421,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 +438,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;
}