summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/6522via.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/6522via.cpp')
-rw-r--r--src/devices/machine/6522via.cpp331
1 files changed, 167 insertions, 164 deletions
diff --git a/src/devices/machine/6522via.cpp b/src/devices/machine/6522via.cpp
index f37666b519a..1b1d0ea0766 100644
--- a/src/devices/machine/6522via.cpp
+++ b/src/devices/machine/6522via.cpp
@@ -11,17 +11,6 @@
**********************************************************************/
-/*
- 1999-Dec-22 PeT
- vc20 random number generation only partly working
- (reads (uninitialized) timer 1 and timer 2 counter)
- timer init, reset, read changed
-
- 2017-Feb-15 Edstrom
- Fixed shift registers to be more accurate, eg 50/50 duty cycle, latching
- on correct edges and leading and trailing edges added + logging.
- */
-
#include "emu.h"
#include "6522via.h"
@@ -29,10 +18,10 @@
PARAMETERS
***************************************************************************/
-#define LOG_SETUP (1U << 1)
-#define LOG_SHIFT (1U << 2)
-#define LOG_READ (1U << 3)
-#define LOG_INT (1U << 4)
+#define LOG_SETUP (1U << 1)
+#define LOG_SHIFT (1U << 2)
+#define LOG_READ (1U << 3)
+#define LOG_INT (1U << 4)
//#define VERBOSE (LOG_SHIFT|LOG_INT|LOG_SETUP)
//#define LOG_OUTPUT_FUNC printf
@@ -180,27 +169,24 @@ void via6522_device::map(address_map &map)
// via6522_device - constructor
//-------------------------------------------------
-via6522_device::via6522_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_a_handler(*this),
- m_in_b_handler(*this),
- m_out_a_handler(*this),
- m_out_b_handler(*this),
- m_ca2_handler(*this),
- m_cb1_handler(*this),
- m_cb2_handler(*this),
- m_irq_handler(*this),
- m_in_a(0xff),
- m_in_ca1(0),
- m_in_ca2(0),
- m_out_ca2(0),
- m_in_b(0xff),
- m_in_cb1(0),
- m_in_cb2(0),
- m_pcr(0),
- m_acr(0),
- m_ier(0),
- m_ifr(0)
+via6522_device::via6522_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_a_handler(*this, 0xff),
+ m_in_b_handler(*this, 0xff),
+ m_out_a_handler(*this),
+ m_out_b_handler(*this),
+ m_ca2_handler(*this),
+ m_cb1_handler(*this),
+ m_cb2_handler(*this),
+ m_irq_handler(*this),
+ m_in_a(0xff),
+ m_in_ca1(0),
+ m_in_ca2(0),
+ m_in_b(0xff),
+ m_in_cb1(0),
+ m_in_cb2(0),
+ m_pcr(0),
+ m_acr(0)
{
}
@@ -209,8 +195,8 @@ via6522_device::via6522_device(const machine_config &mconfig, device_type type,
// mos6522_device - constructor
//-------------------------------------------------
-mos6522_device::mos6522_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : via6522_device(mconfig, MOS6522, tag, owner, clock)
+mos6522_device::mos6522_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ via6522_device(mconfig, MOS6522, tag, owner, clock)
{
}
@@ -219,8 +205,8 @@ mos6522_device::mos6522_device(const machine_config &mconfig, const char *tag, d
// r65c22_device - constructor
//-------------------------------------------------
-r65c22_device::r65c22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : via6522_device(mconfig, R65C22, tag, owner, clock)
+r65c22_device::r65c22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ via6522_device(mconfig, R65C22, tag, owner, clock)
{
}
@@ -229,8 +215,8 @@ r65c22_device::r65c22_device(const machine_config &mconfig, const char *tag, dev
// r65c22_device - constructor
//-------------------------------------------------
-r65nc22_device::r65nc22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : via6522_device(mconfig, R65NC22, tag, owner, clock)
+r65nc22_device::r65nc22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ via6522_device(mconfig, R65NC22, tag, owner, clock)
{
}
@@ -239,8 +225,8 @@ r65nc22_device::r65nc22_device(const machine_config &mconfig, const char *tag, d
// w65c22s_device - constructor
//-------------------------------------------------
-w65c22s_device::w65c22s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : via6522_device(mconfig, W65C22S, tag, owner, clock)
+w65c22s_device::w65c22s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ via6522_device(mconfig, W65C22S, tag, owner, clock)
{
}
@@ -251,30 +237,49 @@ w65c22s_device::w65c22s_device(const machine_config &mconfig, const char *tag, d
void via6522_device::device_start()
{
- m_in_a_handler.resolve();
- m_in_b_handler.resolve();
- m_out_a_handler.resolve_safe();
- m_out_b_handler.resolve_safe();
- m_cb1_handler.resolve_safe();
- m_ca2_handler.resolve_safe();
- m_cb2_handler.resolve_safe();
- m_irq_handler.resolve_safe();
-
m_t1ll = 0xf3; /* via at 0x9110 in vic20 show these values */
m_t1lh = 0xb5; /* ports are not written by kernel! */
m_t2ll = 0xff; /* taken from vice */
m_t2lh = 0xff;
+
+ m_time1 = machine().time();
+ m_time2 = machine().time();
+
+ m_t1 = timer_alloc(FUNC(via6522_device::t1_tick), this);
+ m_t2 = timer_alloc(FUNC(via6522_device::t2_tick), this);
+ m_ca2_timer = timer_alloc(FUNC(via6522_device::ca2_tick), this);
+ m_cb2_timer = machine().scheduler().timer_alloc(timer_expired_delegate());
+ m_shift_timer = timer_alloc(FUNC(via6522_device::shift_tick), this);
+ m_shift_irq_timer = timer_alloc(FUNC(via6522_device::shift_irq_tick), this);
+
+ // zerofill other
+ m_out_a = 0;
+ m_out_ca2 = 0;
+ m_ddr_a = 0;
+ m_latch_a = 0;
+ m_out_b = 0;
+ m_out_cb1 = 0;
+ m_out_cb2 = 0;
+ m_ddr_b = 0;
+ m_latch_b = 0;
+
+ m_t1cl = 0;
+ m_t1ch = 0;
+ m_t2cl = 0;
+ m_t2ch = 0;
+
m_sr = 0;
+ m_pcr = 0;
+ m_acr = 0;
+ m_ier = 0;
+ m_ifr = 0;
- m_time2 = m_time1 = machine().time();
- m_t1 = timer_alloc(TIMER_T1);
- m_t2 = timer_alloc(TIMER_T2);
- m_ca2_timer = timer_alloc(TIMER_CA2);
- m_cb2_timer = timer_alloc(TIMER_CB2);
- m_shift_timer = timer_alloc(TIMER_SHIFT);
- m_shift_irq_timer = timer_alloc(TIMER_SHIFT_IRQ);
+ m_t1_active = 0;
+ m_t1_pb7 = 0;
+ m_t2_active = 0;
+ m_shift_counter = 0;
- /* save state register */
+ // save state register
save_item(NAME(m_in_a));
save_item(NAME(m_in_ca1));
save_item(NAME(m_in_ca2));
@@ -282,6 +287,7 @@ void via6522_device::device_start()
save_item(NAME(m_out_ca2));
save_item(NAME(m_ddr_a));
save_item(NAME(m_latch_a));
+
save_item(NAME(m_in_b));
save_item(NAME(m_in_cb1));
save_item(NAME(m_in_cb2));
@@ -290,6 +296,7 @@ void via6522_device::device_start()
save_item(NAME(m_out_cb2));
save_item(NAME(m_ddr_b));
save_item(NAME(m_latch_b));
+
save_item(NAME(m_t1cl));
save_item(NAME(m_t1ch));
save_item(NAME(m_t1ll));
@@ -298,11 +305,13 @@ void via6522_device::device_start()
save_item(NAME(m_t2ch));
save_item(NAME(m_t2ll));
save_item(NAME(m_t2lh));
+
save_item(NAME(m_sr));
save_item(NAME(m_pcr));
save_item(NAME(m_acr));
save_item(NAME(m_ier));
save_item(NAME(m_ifr));
+
save_item(NAME(m_time1));
save_item(NAME(m_t1_active));
save_item(NAME(m_t1_pb7));
@@ -426,7 +435,7 @@ void via6522_device::clear_int(int data)
/*-------------------------------------------------
- via_shift
+ shift_out
-------------------------------------------------*/
void via6522_device::shift_out()
@@ -449,7 +458,7 @@ void via6522_device::shift_out()
}
else // Check for INT condition, eg the last and raising edge of the 15-0 falling/raising edges
{
- if (!SO_T2_RATE(m_acr)) // The T2 continous shifter doesn't do interrupts (mode 4)
+ if (!SO_T2_RATE(m_acr)) // The T2 continuous shifter doesn't do interrupts (mode 4)
{
if (m_shift_counter == 0 && (SO_O2_CONTROL(m_acr) || SO_T2_CONTROL(m_acr)))
{
@@ -464,13 +473,13 @@ void via6522_device::shift_out()
void via6522_device::shift_in()
{
// Only shift in data on raising edge
- if ( !(m_shift_counter & 1) )
+ if (!(m_shift_counter & 1))
{
LOGSHIFT("%s shift In SR: %02x->", tag(), m_sr);
m_sr = (m_sr << 1) | (m_in_cb2 & 1);
LOGSHIFT("%02x\n", m_sr);
- if (m_shift_counter == 0)
+ if (m_shift_counter == 0 && !SR_DISABLED(m_acr))
{
LOGINT("SHIFT in INT request ");
// set_int(INT_SR);// TODO: this interrupt is 1-2 clock cycles too early
@@ -480,94 +489,92 @@ void via6522_device::shift_in()
m_shift_counter = (m_shift_counter - 1) & 0x0f; // Count all edges
}
-void via6522_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(via6522_device::shift_irq_tick)
{
- switch (id)
- {
- case TIMER_SHIFT_IRQ: // This timer event is a delayed IRQ for improved cycle accuracy
- set_int(INT_SR); // triggered from shift_in or shift_out on the last rising edge
- m_shift_irq_timer->adjust(attotime::never); // Not needed really...
- break;
- case TIMER_SHIFT:
- LOGSHIFT("SHIFT timer event CB1 %s edge, %d\n", m_out_cb1 & 1 ? "falling" : "raising", m_shift_counter);
- m_out_cb1 ^= 1;
- m_cb1_handler(m_out_cb1);
-
- // we call shift methods for all edges
- if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
- {
- shift_out();
- }
- else if (SI_T2_CONTROL(m_acr) || SI_O2_CONTROL(m_acr))
- {
- shift_in();
- }
-
- // If in continous mode or the shifter is still shifting we re-arm the timer
- if (SO_T2_RATE(m_acr) || (m_shift_counter < 0x0f))
- {
- if (SI_O2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
- {
- m_shift_timer->adjust(clocks_to_attotime(1));
- }
- else if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SI_T2_CONTROL(m_acr))
- {
- m_shift_timer->adjust(clocks_to_attotime(m_t2ll + 2) / 2);
- }
- else // otherwise we stop it
- {
- m_shift_timer->adjust(attotime::never);
- }
- }
- break;
- case TIMER_T1:
- if (T1_CONTINUOUS (m_acr))
- {
- m_t1_pb7 = !m_t1_pb7;
- m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY));
- }
- else
- {
- m_t1_pb7 = 1;
- m_t1_active = 0;
- m_time1 = machine().time();
- }
+ // This timer event is a delayed IRQ for improved cycle accuracy
+ set_int(INT_SR); // triggered from shift_in or shift_out on the last rising edge
+ m_shift_irq_timer->adjust(attotime::never); // Not needed really...
+}
- if (T1_SET_PB7(m_acr))
- {
- output_pb();
- }
+TIMER_CALLBACK_MEMBER(via6522_device::shift_tick)
+{
+ LOGSHIFT("SHIFT timer event CB1 %s edge, %d\n", m_out_cb1 & 1 ? "falling" : "raising", m_shift_counter);
+ m_out_cb1 ^= 1;
+ m_cb1_handler(m_out_cb1);
- LOGINT("T1 INT request ");
- set_int(INT_T1);
- break;
+ // we call shift methods for all edges
+ if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
+ {
+ shift_out();
+ }
+ else if (SI_T2_CONTROL(m_acr) || SI_O2_CONTROL(m_acr))
+ {
+ shift_in();
+ }
- case TIMER_T2:
- m_t2_active = 0;
- m_time2 = machine().time();
+ // If in continuous mode or the shifter is still shifting we re-arm the timer
+ if (SO_T2_RATE(m_acr) || (m_shift_counter < 0x0f))
+ {
+ if (SI_O2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
+ {
+ m_shift_timer->adjust(clocks_to_attotime(1));
+ }
+ else if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SI_T2_CONTROL(m_acr))
+ {
+ m_shift_timer->adjust(clocks_to_attotime(m_t2ll + 2) / 2);
+ }
+ else // otherwise we stop it
+ {
+ m_shift_timer->adjust(attotime::never);
+ }
+ }
+}
- LOGINT("T2 INT request ");
- set_int(INT_T2);
- break;
+TIMER_CALLBACK_MEMBER(via6522_device::t1_tick)
+{
+ if (T1_CONTINUOUS (m_acr))
+ {
+ m_t1_pb7 = !m_t1_pb7;
+ m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY));
+ }
+ else
+ {
+ m_t1_pb7 = 1;
+ m_t1_active = 0;
+ m_time1 = machine().time();
+ }
- case TIMER_CA2:
- m_out_ca2 = 1;
- m_ca2_handler(m_out_ca2);
- break;
+ if (T1_SET_PB7(m_acr))
+ {
+ output_pb();
}
+
+ LOGINT("T1 INT request ");
+ set_int(INT_T1);
}
-uint8_t via6522_device::input_pa()
+TIMER_CALLBACK_MEMBER(via6522_device::t2_tick)
{
- uint8_t pa = m_in_a & ~m_ddr_a;
+ m_t2_active = 0;
+ m_time2 = machine().time();
- /// TODO: REMOVE THIS
- if (m_ddr_a != 0xff && !m_in_a_handler.isnull())
- pa &= m_in_a_handler();
+ LOGINT("T2 INT request ");
+ set_int(INT_T2);
+}
- pa |= m_out_a & m_ddr_a;
+TIMER_CALLBACK_MEMBER(via6522_device::ca2_tick)
+{
+ m_out_ca2 = 1;
+ m_ca2_handler(m_out_ca2);
+}
- return pa;
+uint8_t via6522_device::input_pa()
+{
+ // HACK: port a in the real 6522 does not mask off the output pins, but you can't trust handlers.
+ if (!m_in_a_handler.isunset())
+ return (m_in_a & ~m_ddr_a & m_in_a_handler()) | (m_out_a & m_ddr_a);
+ else
+ return (m_out_a | ~m_ddr_a) & m_in_a;
}
void via6522_device::output_pa()
@@ -586,7 +593,7 @@ uint8_t via6522_device::input_pb()
uint8_t pb = m_in_b & ~m_ddr_b;
/// TODO: REMOVE THIS
- if (m_ddr_b != 0xff && !m_in_b_handler.isnull())
+ if (m_ddr_b != 0xff && !m_in_b_handler.isunset())
{
pb &= m_in_b_handler();
}
@@ -632,13 +639,13 @@ u8 via6522_device::read(offs_t offset)
{
case VIA_PB:
/* update the input */
- if (PB_LATCH_ENABLE(m_acr) == 0)
+ if ((PB_LATCH_ENABLE(m_acr) != 0) && ((m_ifr & INT_CB1) != 0))
{
- val = input_pb();
+ val = m_latch_b;
}
else
{
- val = m_latch_b;
+ val = input_pb();
}
if (!machine().side_effects_disabled())
@@ -650,13 +657,13 @@ u8 via6522_device::read(offs_t offset)
case VIA_PA:
/* update the input */
- if (PA_LATCH_ENABLE(m_acr) == 0)
+ if ((PA_LATCH_ENABLE(m_acr) != 0) && ((m_ifr & INT_CA1) != 0))
{
- val = input_pa();
+ val = m_latch_a;
}
else
{
- val = m_latch_a;
+ val = input_pa();
}
if (!machine().side_effects_disabled())
@@ -678,13 +685,13 @@ u8 via6522_device::read(offs_t offset)
case VIA_PANH:
/* update the input */
- if (PA_LATCH_ENABLE(m_acr) == 0)
+ if ((PA_LATCH_ENABLE(m_acr) != 0) && ((m_ifr & INT_CA1) != 0))
{
- val = input_pa();
+ val = m_latch_a;
}
else
{
- val = m_latch_a;
+ val = input_pa();
}
break;
@@ -885,7 +892,7 @@ void via6522_device::write(offs_t offset, u8 data)
break;
case VIA_DDRB:
- if ( data != m_ddr_b )
+ if (data != m_ddr_b)
{
m_ddr_b = data;
@@ -1019,7 +1026,7 @@ void via6522_device::write(offs_t offset, u8 data)
if (SI_T2_CONTROL(m_acr)) LOGSHIFT("IN on T2");
if (SI_O2_CONTROL(m_acr)) LOGSHIFT("IN on O2");
if (SI_EXT_CONTROL(m_acr)) LOGSHIFT("IN on EXT");
- if (SO_T2_RATE(m_acr)) LOGSHIFT("OUT on continous T2");
+ if (SO_T2_RATE(m_acr)) LOGSHIFT("OUT on continuous T2");
if (SO_T2_CONTROL(m_acr)) LOGSHIFT("OUT on T2");
if (SO_O2_CONTROL(m_acr)) LOGSHIFT("OUT on O2");
if (SO_EXT_CONTROL(m_acr)) LOGSHIFT("OUT on EXT");
@@ -1060,12 +1067,8 @@ void via6522_device::write(offs_t offset, u8 data)
break;
case VIA_IFR:
- if (data & INT_ANY)
- {
- data = 0x7f;
- }
LOGINT("IFR INT ");
- clear_int(data);
+ clear_int(data & 0x7f);
break;
}
}
@@ -1078,7 +1081,7 @@ void via6522_device::set_pa_line(int line, int state)
m_in_a &= ~(1 << line);
}
-void via6522_device::write_pa( u8 data )
+void via6522_device::write_pa(u8 data)
{
m_in_a = data;
}
@@ -1087,7 +1090,7 @@ void via6522_device::write_pa( u8 data )
ca1_w - interface setting VIA port CA1 input
-------------------------------------------------*/
-WRITE_LINE_MEMBER( via6522_device::write_ca1 )
+void via6522_device::write_ca1(int state)
{
if (m_in_ca1 != state)
{
@@ -1119,7 +1122,7 @@ WRITE_LINE_MEMBER( via6522_device::write_ca1 )
ca2_w - interface setting VIA port CA2 input
-------------------------------------------------*/
-WRITE_LINE_MEMBER( via6522_device::write_ca2 )
+void via6522_device::write_ca2(int state)
{
if (m_in_ca2 != state)
{
@@ -1149,7 +1152,7 @@ void via6522_device::set_pb_line(int line, int state)
}
}
-void via6522_device::write_pb( u8 data )
+void via6522_device::write_pb(u8 data)
{
if (!BIT(data, 6) && BIT(m_in_b, 6))
counter2_decrement();
@@ -1161,7 +1164,7 @@ void via6522_device::write_pb( u8 data )
write_cb1 - interface setting VIA port CB1 input
-------------------------------------------------*/
-WRITE_LINE_MEMBER( via6522_device::write_cb1 )
+void via6522_device::write_cb1(int state)
{
if (m_in_cb1 != state)
{
@@ -1189,7 +1192,7 @@ WRITE_LINE_MEMBER( via6522_device::write_cb1 )
LOGSHIFT("SHIFT OUT EXT/CB1 falling edge, %d\n", m_shift_counter);
shift_out();
}
- else if (SI_EXT_CONTROL(m_acr))
+ else if (SI_EXT_CONTROL(m_acr) || SR_DISABLED(m_acr))
{
LOGSHIFT("SHIFT IN EXT/CB1 raising edge, %d\n", m_shift_counter);
shift_in();
@@ -1202,7 +1205,7 @@ WRITE_LINE_MEMBER( via6522_device::write_cb1 )
write_cb2 - interface setting VIA port CB2 input
-------------------------------------------------*/
-WRITE_LINE_MEMBER( via6522_device::write_cb2 )
+void via6522_device::write_cb2(int state)
{
if (m_in_cb2 != state)
{