diff options
Diffstat (limited to 'src/devices/machine/6522via.cpp')
-rw-r--r-- | src/devices/machine/6522via.cpp | 331 |
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) { |