summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/mos6530.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/mos6530.cpp')
-rw-r--r--src/devices/machine/mos6530.cpp729
1 files changed, 470 insertions, 259 deletions
diff --git a/src/devices/machine/mos6530.cpp b/src/devices/machine/mos6530.cpp
index 8cc7198b3e5..599e3962bc8 100644
--- a/src/devices/machine/mos6530.cpp
+++ b/src/devices/machine/mos6530.cpp
@@ -1,383 +1,594 @@
// license:BSD-3-Clause
// copyright-holders:Curt Coder
-/***************************************************************************
+/**********************************************************************
- MOS 6530 MIOT emulation
- Memory, I/O, Timer Array (Rockwell calls it RRIOT: ROM, RAM, I/O, Timer)
+ MOS Technology 6530 MIOT (Memory, I/O, Timer Array)
+ Rockwell calls it RRIOT: ROM, RAM, I/O, Timer
-The timer seems to follow these rules:
-- When the timer flag changes from 0 to 1 the timer continues to count
- down at a 1 cycle rate.
-- When the timer is being read or written the timer flag is reset.
-- When the timer flag is set and the timer contents are 0, the counting
- stops.
+ MOS Technology 6532 RIOT (RAM, I/O, Timer Array)
-From the operation of the KIM1 it expects the irqflag to be set whenever
-the unit is reset. This is something that is not clear from the datasheet
-and should be verified against real hardware.
-
-***************************************************************************/
+**********************************************************************/
#include "emu.h"
#include "mos6530.h"
+#define LOG_TIMER (1U << 1)
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
+//#define VERBOSE (LOG_GENERAL | LOG_TIMER)
+#include "logmacro.h"
-enum
-{
- TIMER_IDLE,
- TIMER_COUNTING,
- TIMER_FINISHING
-};
+#define LOGTIMER(...) LOGMASKED(LOG_TIMER, __VA_ARGS__)
-#define TIMER_FLAG 0x80
-/***************************************************************************
- DEVICE INTERFACE
-***************************************************************************/
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
DEFINE_DEVICE_TYPE(MOS6530, mos6530_device, "mos6530", "MOS 6530 MIOT")
+DEFINE_DEVICE_TYPE(MOS6532, mos6532_device, "mos6532", "MOS 6532 RIOT")
+
+
+void mos6530_device::rom_map(address_map &map)
+{
+ map.global_mask(0x3ff);
+ map(0x000, 0x3ff).r(FUNC(mos6530_device::rom_r));
+}
+
+void mos6530_device::ram_map(address_map &map)
+{
+ map.global_mask(0x3f);
+ map(0x00, 0x3f).rw(FUNC(mos6530_device::ram_r), FUNC(mos6530_device::ram_w));
+}
+
+void mos6530_device::io_map(address_map &map)
+{
+ map.global_mask(0xf);
+ map(0x00, 0x00).mirror(0x8).rw(FUNC(mos6530_device::pa_data_r), FUNC(mos6530_device::pa_data_w));
+ map(0x01, 0x01).mirror(0x8).rw(FUNC(mos6530_device::pa_ddr_r), FUNC(mos6530_device::pa_ddr_w));
+ map(0x02, 0x02).mirror(0x8).rw(FUNC(mos6530_device::pb_data_r), FUNC(mos6530_device::pb_data_w));
+ map(0x03, 0x03).mirror(0x8).rw(FUNC(mos6530_device::pb_ddr_r), FUNC(mos6530_device::pb_ddr_w));
+ map(0x04, 0x07).w(FUNC(mos6530_device::timer_off_w));
+ map(0x0c, 0x0f).w(FUNC(mos6530_device::timer_on_w));
+ map(0x04, 0x04).mirror(0x2).r(FUNC(mos6530_device::timer_off_r));
+ map(0x0c, 0x0c).mirror(0x2).r(FUNC(mos6530_device::timer_on_r));
+ map(0x05, 0x05).mirror(0xa).r(FUNC(mos6530_device::irq_r));
+}
-mos6530_device::mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MOS6530, tag, owner, clock),
- m_in_pa_cb(*this),
- m_out_pa_cb(*this),
- m_in_pb_cb(*this),
- m_out_pb_cb(*this)
+void mos6532_device::ram_map(address_map &map)
{
+ map.global_mask(0x7f);
+ map(0x00, 0x7f).rw(FUNC(mos6532_device::ram_r), FUNC(mos6532_device::ram_w));
}
+void mos6532_device::io_map(address_map &map)
+{
+ map.global_mask(0x1f);
+ map(0x00, 0x00).mirror(0x18).rw(FUNC(mos6532_device::pa_data_r), FUNC(mos6532_device::pa_data_w));
+ map(0x01, 0x01).mirror(0x18).rw(FUNC(mos6532_device::pa_ddr_r), FUNC(mos6532_device::pa_ddr_w));
+ map(0x02, 0x02).mirror(0x18).rw(FUNC(mos6532_device::pb_data_r), FUNC(mos6532_device::pb_data_w));
+ map(0x03, 0x03).mirror(0x18).rw(FUNC(mos6532_device::pb_ddr_r), FUNC(mos6532_device::pb_ddr_w));
+ map(0x14, 0x17).w(FUNC(mos6532_device::timer_off_w));
+ map(0x1c, 0x1f).w(FUNC(mos6532_device::timer_on_w));
+ map(0x04, 0x04).mirror(0x12).r(FUNC(mos6532_device::timer_off_r));
+ map(0x0c, 0x0c).mirror(0x12).r(FUNC(mos6532_device::timer_on_r));
+ map(0x05, 0x05).mirror(0x1a).r(FUNC(mos6532_device::irq_r));
+ map(0x04, 0x07).mirror(0x8).w(FUNC(mos6532_device::edge_w));
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
//-------------------------------------------------
-// device_start - device-specific startup
+// mos6530_device_base - constructor
//-------------------------------------------------
-void mos6530_device::device_start()
-{
- /* set static values */
- m_clock = clock();
+mos6530_device_base::mos6530_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 rsize) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_ram(*this, finder_base::DUMMY_TAG, rsize, ENDIANNESS_LITTLE),
+ m_rom(*this, DEVICE_SELF),
+ m_irq_cb(*this),
+ m_in8_pa_cb(*this, 0),
+ m_out8_pa_cb(*this),
+ m_in8_pb_cb(*this, 0),
+ m_out8_pb_cb(*this),
+ m_in_pa_cb(*this, 0),
+ m_out_pa_cb(*this),
+ m_in_pb_cb(*this, 0),
+ m_out_pb_cb(*this),
+ m_pa_in(0xff),
+ m_pa_out(0),
+ m_pa_ddr(0),
+ m_pa7(1),
+ m_pa7_dir(0),
+ m_pb_in(0xff),
+ m_pb_out(0),
+ m_pb_ddr(0),
+ m_ie_timer(false),
+ m_irq_timer(false),
+ m_ie_edge(false),
+ m_irq_edge(false)
+{ }
+
+
+//-------------------------------------------------
+// mos6530_device - constructor
+//-------------------------------------------------
+
+mos6530_device::mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ mos6530_device_base(mconfig, MOS6530, tag, owner, clock, 0x40)
+{ }
- /* resolve callbacks */
- m_in_pa_cb.resolve_safe(0);
- m_out_pa_cb.resolve_safe();
- m_in_pb_cb.resolve_safe(0);
- m_out_pb_cb.resolve_safe();
- /* allocate timers */
- m_timer = timer_alloc(TIMER_END_CALLBACK);
+//-------------------------------------------------
+// mos6532_device - constructor
+//-------------------------------------------------
- /* register for save states */
- save_item(NAME(m_port[0].m_in));
- save_item(NAME(m_port[0].m_out));
- save_item(NAME(m_port[0].m_ddr));
- save_item(NAME(m_port[1].m_in));
- save_item(NAME(m_port[1].m_out));
- save_item(NAME(m_port[1].m_ddr));
+mos6532_device::mos6532_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ mos6530_device_base(mconfig, MOS6532, tag, owner, clock, 0x80)
+{ }
- save_item(NAME(m_irqstate));
- save_item(NAME(m_irqenable));
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mos6530_device_base::device_start()
+{
+ // allocate timer
+ m_timer = timer_alloc(FUNC(mos6530_device_base::timer_end), this);
+ m_timershift = 10;
+ m_timerstate = TIMER_COUNTING;
+ m_timer->adjust(attotime::from_ticks(256 << m_timershift, clock()));
+
+ // state saving
+ save_item(NAME(m_pa_in));
+ save_item(NAME(m_pa_out));
+ save_item(NAME(m_pa_ddr));
+ save_item(NAME(m_pa7));
+ save_item(NAME(m_pa7_dir));
+
+ save_item(NAME(m_pb_in));
+ save_item(NAME(m_pb_out));
+ save_item(NAME(m_pb_ddr));
+
+ save_item(NAME(m_ie_timer));
+ save_item(NAME(m_irq_timer));
+ save_item(NAME(m_ie_edge));
+ save_item(NAME(m_irq_edge));
save_item(NAME(m_timershift));
save_item(NAME(m_timerstate));
+ save_item(NAME(m_timeout));
}
+
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
-void mos6530_device::device_reset()
+void mos6530_device_base::device_reset()
{
- /* reset I/O states */
- m_port[0].m_out = 0;
- m_port[0].m_ddr = 0;
- m_port[1].m_out = 0;
- m_port[1].m_ddr = 0;
+ m_pa_out = 0;
+ m_pa_ddr = 0;
+ m_pb_out = 0;
+ m_pb_ddr = 0;
+
+ m_ie_timer = false;
+ m_ie_edge = false;
+ m_irq_edge = false;
+ m_pa7_dir = 0;
+
+ update_pa();
+ update_pb();
+ update_irq();
+ edge_detect();
+}
- /* reset IRQ states */
- m_irqenable = 0;
- m_irqstate = TIMER_FLAG;
- update_irqstate();
- /* reset timer states */
- m_timershift = 0;
- m_timerstate = TIMER_IDLE;
- m_timer->adjust(attotime::never);
+//-------------------------------------------------
+// update_pa -
+//-------------------------------------------------
+
+void mos6530_device_base::update_pa()
+{
+ uint8_t data = (m_pa_out & m_pa_ddr) | (m_pa_ddr ^ 0xff);
+
+ if (m_out8_pa_cb.isunset())
+ {
+ for (int i = 0; i < 8; i++)
+ m_out_pa_cb[i](BIT(data, i));
+ }
+ else
+ m_out8_pa_cb(data);
}
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
+//-------------------------------------------------
+// update_pb -
+//-------------------------------------------------
+void mos6530_device_base::update_pb()
+{
+ uint8_t data = (m_pb_out & m_pb_ddr) | (m_pb_ddr ^ 0xff);
-/*-------------------------------------------------
- update_irqstate - update the IRQ state
- based on interrupt enables
--------------------------------------------------*/
+ if (m_out8_pb_cb.isunset())
+ {
+ for (int i = 0; i < 8; i++)
+ m_out_pb_cb[i](BIT(data, i));
+ }
+ else
+ m_out8_pb_cb(data);
+}
-void mos6530_device::update_irqstate()
+void mos6530_device::update_pb()
{
- uint8_t out = m_port[1].m_out;
+ uint8_t data = (m_pb_out & m_pb_ddr) | (m_pb_ddr ^ 0xff);
- if (m_irqenable)
- out = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (out & 0x7F);
+ if (!BIT(m_pb_ddr, 7))
+ {
+ // active low!
+ if (m_ie_timer && m_irq_timer)
+ data &= ~IRQ_TIMER;
+ else
+ data |= IRQ_TIMER;
+ }
+
+ if (m_out8_pb_cb.isunset())
+ {
+ for (int i = 0; i < 8; i++)
+ m_out_pb_cb[i](BIT(data, i));
+ }
+ else
+ m_out8_pb_cb(data);
- m_out_pb_cb((offs_t)0, out);
+ m_irq_cb(BIT(data, 7) ? CLEAR_LINE: ASSERT_LINE);
}
-/*-------------------------------------------------
- get_timer - return the current timer value
--------------------------------------------------*/
+//-------------------------------------------------
+// update_irq -
+//-------------------------------------------------
-uint8_t mos6530_device::get_timer()
+void mos6530_device_base::update_irq()
{
- /* if idle, return 0 */
- if (m_timerstate == TIMER_IDLE)
- return 0;
+ int state = CLEAR_LINE;
- /* if counting, return the number of ticks remaining */
- else if (m_timerstate == TIMER_COUNTING)
- return m_timer->remaining().as_ticks(m_clock) >> m_timershift;
+ if (m_ie_timer && m_irq_timer) state = ASSERT_LINE;
+ if (m_ie_edge && m_irq_edge) state = ASSERT_LINE;
- /* if finishing, return the number of ticks without the shift */
- else
- return m_timer->remaining().as_ticks(m_clock);
+ m_irq_cb(state);
}
+void mos6530_device::update_irq()
+{
+ update_pb();
+}
-/***************************************************************************
- INTERNAL FUNCTIONS
-***************************************************************************/
-/*-------------------------------------------------
- timer_end_callback - callback to process the
- timer
--------------------------------------------------*/
+//-------------------------------------------------
+// get_irq_flags -
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::get_irq_flags()
+{
+ uint8_t data = 0;
+
+ if (m_irq_timer) data |= IRQ_TIMER;
+ if (m_irq_edge) data |= IRQ_EDGE;
+
+ return data;
+}
-void mos6530_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+uint8_t mos6530_device::get_irq_flags()
{
- switch (id)
+ uint8_t data = 0;
+
+ if (m_irq_timer) data |= IRQ_TIMER;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// get_timer - return the current timer value
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::get_timer()
+{
+ // determine the number of ticks remaining
+ uint8_t shift = (m_timerstate == TIMER_COUNTING) ? m_timershift : 0;
+ int64_t remain = m_timer->remaining().as_ticks(clock());
+ uint8_t val = remain >> shift;
+
+ // timeout is at 255, so round it down
+ return (remain & ((1 << shift) - 1)) ? val : (val - 1);
+}
+
+
+//-------------------------------------------------
+// timer_start - restart timer counter
+//-------------------------------------------------
+
+void mos6530_device_base::timer_start(uint8_t data)
+{
+ m_timerstate = TIMER_COUNTING;
+ attotime curtime = machine().time();
+ int64_t target = curtime.as_ticks(clock()) + 1 + (data << m_timershift);
+ m_timer->adjust(attotime::from_ticks(target, clock()) - curtime);
+}
+
+
+//-------------------------------------------------
+// timer_end -
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(mos6530_device_base::timer_end)
+{
+ // if we finished counting, signal timer IRQ
+ if (m_timerstate == TIMER_COUNTING)
{
- // deferred reset
- case TIMER_END_CALLBACK:
- assert(m_timerstate != TIMER_IDLE);
-
- /* if we finished counting, switch to the finishing state */
- if (m_timerstate == TIMER_COUNTING)
- {
- m_timerstate = TIMER_FINISHING;
- m_timer->adjust(attotime::from_ticks(256, m_clock));
-
- /* signal timer IRQ as well */
- m_irqstate |= TIMER_FLAG;
- update_irqstate();
- }
-
- /* if we finished finishing, switch to the idle state */
- else if (m_timerstate == TIMER_FINISHING)
- {
- m_timerstate = TIMER_IDLE;
- m_timer->adjust(attotime::never);
- }
- break;
+ m_timeout = machine().time();
+ m_irq_timer = true;
+ update_irq();
}
+
+ // if we finished, keep spinning without the prescaler
+ m_timerstate = TIMER_SPINNING;
+ m_timer->adjust(attotime::from_ticks(256, clock()));
}
-/***************************************************************************
- I/O ACCESS
-***************************************************************************/
-/*-------------------------------------------------
- mos6530_w - master I/O write access
--------------------------------------------------*/
+//-------------------------------------------------
+// edge_detect -
+//-------------------------------------------------
-void mos6530_device::write(offs_t offset, uint8_t data)
+void mos6530_device_base::edge_detect()
{
- /* if A2 == 1, we are writing to the timer */
- if (offset & 0x04)
+ uint8_t data = (m_pa_out & m_pa_ddr) | (m_pa_in & ~m_pa_ddr);
+ int state = BIT(data, 7);
+
+ if ((m_pa7 ^ state) && !(m_pa7_dir ^ state) && !m_irq_edge)
{
- static const uint8_t timershift[4] = { 0, 3, 6, 10 };
- attotime curtime = machine().time();
- int64_t target;
+ LOG("%s %s edge-detect IRQ\n", machine().time().as_string(), name());
- /* A0-A1 contain the timer divisor */
- m_timershift = timershift[offset & 3];
+ m_irq_edge = true;
+ update_irq();
+ }
- /* A3 contains the timer IRQ enable */
- if (offset & 8)
- m_irqenable |= TIMER_FLAG;
- else
- m_irqenable &= ~TIMER_FLAG;
+ m_pa7 = state;
+}
- /* writes here clear the timer flag */
- if (m_timerstate != TIMER_FINISHING || get_timer() != 0xff)
- m_irqstate &= ~TIMER_FLAG;
- update_irqstate();
- /* update the timer */
- m_timerstate = TIMER_COUNTING;
- target = curtime.as_ticks(m_clock) + 1 + (data << m_timershift);
- m_timer->adjust(attotime::from_ticks(target, m_clock) - curtime);
- }
+//-------------------------------------------------
+// pa_w -
+//-------------------------------------------------
- /* if A2 == 0, we are writing to the I/O section */
- else
- {
- /* A1 selects the port */
- mos6530_port *port = &m_port[BIT(offset, 1)];
+void mos6530_device_base::pa_w(offs_t offset, uint8_t data, uint8_t mem_mask)
+{
+ LOG("%s %s %s Port A Data Write %02X Mask %02X\n", machine().time().as_string(), machine().describe_context(), name(), data, mem_mask);
- /* if A0 == 1, we are writing to the port's DDR */
- if (offset & 1)
- port->m_ddr = data;
+ m_pa_in = (m_pa_in & ~mem_mask) | (data & mem_mask);
+ edge_detect();
+}
- /* if A0 == 0, we are writing to the port's output */
- else
- {
- uint8_t olddata = port->m_out;
- port->m_out = data;
-
- if ((offset & 2) && m_irqenable)
- {
- olddata = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (olddata & 0x7F);
- data = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (data & 0x7F);
- }
-
- if (!BIT(offset, 1))
- m_out_pa_cb((offs_t)0, data);
- else
- m_out_pb_cb((offs_t)0, data);
- }
- }
+
+//-------------------------------------------------
+// pb_w -
+//-------------------------------------------------
+
+void mos6530_device_base::pb_w(offs_t offset, uint8_t data, uint8_t mem_mask)
+{
+ LOG("%s %s %s Port B Data Write %02X Mask %02X\n", machine().time().as_string(), machine().describe_context(), name(), data, mem_mask);
+
+ m_pb_in = (m_pb_in & ~mem_mask) | (data & mem_mask);
}
-/*-------------------------------------------------
- mos6530_r - master I/O read access
--------------------------------------------------*/
+//-------------------------------------------------
+// pa_data_r -
+//-------------------------------------------------
-uint8_t mos6530_device::read(offs_t offset)
+uint8_t mos6530_device_base::pa_data_r()
{
- uint8_t val;
+ uint8_t in = 0;
- /* if A2 == 1 and A0 == 1, we are reading interrupt flags */
- if ((offset & 0x05) == 0x05)
+ if (m_in8_pa_cb.isunset())
{
- val = m_irqstate;
+ for (int i = 0; i < 8; i++)
+ in |= (m_in_pa_cb[i].isunset() ? BIT(m_pa_in, i) : m_in_pa_cb[i]()) << i;
}
+ else
+ in = m_in8_pa_cb();
- /* if A2 == 1 and A0 == 0, we are reading the timer */
- else if ((offset & 0x05) == 0x04)
- {
- val = get_timer();
+ uint8_t data = (m_pa_out & m_pa_ddr) | (in & ~m_pa_ddr);
- /* A3 contains the timer IRQ enable */
- if (offset & 8)
- m_irqenable |= TIMER_FLAG;
- else
- m_irqenable &= ~TIMER_FLAG;
+ LOG("%s %s %s Port A Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
- /* implicitly clears the timer flag */
- if (m_timerstate != TIMER_FINISHING || val != 0xff)
- m_irqstate &= ~TIMER_FLAG;
- update_irqstate();
- }
+ return data;
+}
- /* if A2 == 0 and A0 == anything, we are reading from ports */
- else
- {
- /* A1 selects the port */
- mos6530_port *port = &m_port[BIT(offset, 1)];
- /* if A0 == 1, we are reading the port's DDR */
- if (offset & 1)
- val = port->m_ddr;
+//-------------------------------------------------
+// pa_data_w -
+//-------------------------------------------------
- /* if A0 == 0, we are reading the port as an input */
- else
- {
- uint8_t out = port->m_out;
+void mos6530_device_base::pa_data_w(uint8_t data)
+{
+ m_pa_out = data;
- if ((offset & 2) && m_irqenable)
- out = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (out & 0x7F);
+ LOG("%s %s %s Port A Data Out %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
- /* call the input callback if it exists */
- if (!BIT(offset, 1))
- port->m_in = m_in_pa_cb(0);
- else
- port->m_in = m_in_pb_cb(0);
+ update_pa();
+ edge_detect();
+}
- /* apply the DDR to the result */
- val = (out & port->m_ddr) | (port->m_in & ~port->m_ddr);
- }
+
+//-------------------------------------------------
+// pa_ddr_w -
+//-------------------------------------------------
+
+void mos6530_device_base::pa_ddr_w(uint8_t data)
+{
+ m_pa_ddr = data;
+
+ LOG("%s %s %s Port A DDR %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
+
+ update_pa();
+ edge_detect();
+}
+
+
+//-------------------------------------------------
+// pb_data_r -
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::pb_data_r()
+{
+ uint8_t in = 0;
+
+ if (m_in8_pb_cb.isunset())
+ {
+ for (int i = 0; i < 8; i++)
+ in |= (m_in_pb_cb[i].isunset() ? BIT(m_pb_in, i) : m_in_pb_cb[i]()) << i;
}
- return val;
+ else
+ in = m_in8_pb_cb();
+
+ uint8_t data = (m_pb_out & m_pb_ddr) | (in & ~m_pb_ddr);
+
+ LOG("%s %s %s Port B Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
+
+ return data;
}
-/*-------------------------------------------------
- mos6530_porta_in_set - set port A input
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// pb_data_w -
+//-------------------------------------------------
-void mos6530_device::porta_in_set(uint8_t data, uint8_t mask)
+void mos6530_device_base::pb_data_w(uint8_t data)
{
- m_port[0].m_in = (m_port[0].m_in & ~mask) | (data & mask);
+ m_pb_out = data;
+
+ LOG("%s %s %s Port B Data Out %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
+
+ update_pb();
}
-/*-------------------------------------------------
- mos6530_portb_in_set - set port B input
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// pb_ddr_w -
+//-------------------------------------------------
-void mos6530_device::portb_in_set(uint8_t data, uint8_t mask)
+void mos6530_device_base::pb_ddr_w(uint8_t data)
{
- m_port[1].m_in = (m_port[1].m_in & ~mask) | (data & mask);
+ m_pb_ddr = data;
+
+ LOG("%s %s %s Port B DDR %02x\n", machine().time().as_string(), machine().describe_context(), name(), data);
+
+ update_pb();
}
-/*-------------------------------------------------
- mos6530_porta_in_get - return port A input
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// timer_r -
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::timer_off_r()
+{
+ return timer_r(false);
+}
-uint8_t mos6530_device::porta_in_get()
+uint8_t mos6530_device_base::timer_on_r()
{
- return m_port[0].m_in;
+ return timer_r(true);
}
+uint8_t mos6530_device_base::timer_r(bool ie)
+{
+ uint8_t data = get_timer();
+
+ if (!machine().side_effects_disabled())
+ {
+ // IRQ is not cleared when reading at the same time IRQ is raised
+ if (m_timeout < machine().time() - attotime::from_hz(2 * clock()))
+ {
+ m_irq_timer = false;
+
+ // timer goes back to count mode
+ if (m_timerstate == TIMER_SPINNING)
+ timer_start(data);
+ }
-/*-------------------------------------------------
- mos6530_portb_in_get - return port B input
- value
--------------------------------------------------*/
+ m_ie_timer = ie;
+ update_irq();
-uint8_t mos6530_device::portb_in_get()
+ LOGTIMER("%s %s %s Timer read %02x IE %u\n", machine().time().as_string(), machine().describe_context(), name(), data, m_ie_timer ? 1 : 0);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// irq_r -
+//-------------------------------------------------
+
+uint8_t mos6530_device_base::irq_r()
{
- return m_port[1].m_in;
+ uint8_t data = get_irq_flags();
+
+ if (!machine().side_effects_disabled() && m_irq_edge)
+ {
+ m_irq_edge = false;
+ update_irq();
+ }
+
+ return data;
}
-/*-------------------------------------------------
- mos6530_porta_in_get - return port A output
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// timer_w -
+//-------------------------------------------------
+
+void mos6530_device_base::timer_off_w(offs_t offset, uint8_t data)
+{
+ timer_w(offset, data, false);
+}
+
+void mos6530_device_base::timer_on_w(offs_t offset, uint8_t data)
+{
+ timer_w(offset, data, true);
+}
-uint8_t mos6530_device::porta_out_get()
+void mos6530_device_base::timer_w(offs_t offset, uint8_t data, bool ie)
{
- return m_port[0].m_out;
+ // A0-A1 contain the prescaler
+ static const uint8_t timershift[4] = { 0, 3, 6, 10 };
+ m_timershift = timershift[offset & 3];
+ timer_start(data);
+
+ m_irq_timer = false;
+ m_ie_timer = ie;
+ update_irq();
+
+ LOGTIMER("%s %s %s Timer value %02x prescale %u IE %u\n", machine().time().as_string(), machine().describe_context(), name(), data, 1 << m_timershift, m_ie_timer ? 1 : 0);
}
-/*-------------------------------------------------
- mos6530_portb_in_get - return port B output
- value
--------------------------------------------------*/
+//-------------------------------------------------
+// edge_w -
+//-------------------------------------------------
-uint8_t mos6530_device::portb_out_get()
+void mos6530_device_base::edge_w(offs_t offset, uint8_t data)
{
- return m_port[1].m_out;
+ m_pa7_dir = BIT(offset, 0);
+ m_ie_edge = bool(BIT(offset, 1));
+ update_irq();
+
+ LOG("%s %s %s %s edge-detect, %s interrupt\n", machine().time().as_string(), machine().describe_context(), name(), m_pa7_dir ? "positive" : "negative", m_ie_edge ? "enable" : "disable");
}