2 Skelton for retropc emulator
4 Origin : MAME 0.164 Rockwell 6522 VIA
5 Author : Takeda.Toshiya
11 // license:BSD-3-Clause
12 // copyright-holders:Peter Trauner, Mathis Rosenhauer
13 /**********************************************************************
15 Rockwell 6522 VIA interface and emulation
17 This function emulates the functionality of up to 8 6522
18 versatile interface adapters.
20 This is based on the M6821 emulation in MAME.
24 T2 pulse counting mode
25 Pulse mode handshake output
28 **********************************************************************/
32 vc20 random number generation only partly working
33 (reads (uninitialized) timer 1 and timer 2 counter)
34 timer init, reset, read changed
41 /***************************************************************************
43 ***************************************************************************/
46 #define CA1_LOW_TO_HIGH(c) (c & 0x01)
47 #define CA1_HIGH_TO_LOW(c) (!(c & 0x01))
49 #define CB1_LOW_TO_HIGH(c) (c & 0x10)
50 #define CB1_HIGH_TO_LOW(c) (!(c & 0x10))
52 #define CA2_INPUT(c) (!(c & 0x08))
53 #define CA2_LOW_TO_HIGH(c) ((c & 0x0c) == 0x04)
54 #define CA2_HIGH_TO_LOW(c) ((c & 0x0c) == 0x00)
55 #define CA2_IND_IRQ(c) ((c & 0x0a) == 0x02)
57 #define CA2_OUTPUT(c) (c & 0x08)
58 #define CA2_AUTO_HS(c) ((c & 0x0c) == 0x08)
59 #define CA2_HS_OUTPUT(c) ((c & 0x0e) == 0x08)
60 #define CA2_PULSE_OUTPUT(c) ((c & 0x0e) == 0x0a)
61 #define CA2_FIX_OUTPUT(c) ((c & 0x0c) == 0x0c)
62 #define CA2_OUTPUT_LEVEL(c) ((c & 0x02) >> 1)
64 #define CB2_INPUT(c) (!(c & 0x80))
65 #define CB2_LOW_TO_HIGH(c) ((c & 0xc0) == 0x40)
66 #define CB2_HIGH_TO_LOW(c) ((c & 0xc0) == 0x00)
67 #define CB2_IND_IRQ(c) ((c & 0xa0) == 0x20)
69 #define CB2_OUTPUT(c) (c & 0x80)
70 #define CB2_AUTO_HS(c) ((c & 0xc0) == 0x80)
71 #define CB2_HS_OUTPUT(c) ((c & 0xe0) == 0x80)
72 #define CB2_PULSE_OUTPUT(c) ((c & 0xe0) == 0xa0)
73 #define CB2_FIX_OUTPUT(c) ((c & 0xc0) == 0xc0)
74 #define CB2_OUTPUT_LEVEL(c) ((c & 0x20) >> 5)
77 #define PA_LATCH_ENABLE(c) (c & 0x01)
78 #define PB_LATCH_ENABLE(c) (c & 0x02)
80 #define SR_DISABLED(c) (!(c & 0x1c))
81 #define SI_T2_CONTROL(c) ((c & 0x1c) == 0x04)
82 #define SI_O2_CONTROL(c) ((c & 0x1c) == 0x08)
83 #define SI_EXT_CONTROL(c) ((c & 0x1c) == 0x0c)
84 #define SO_T2_RATE(c) ((c & 0x1c) == 0x10)
85 #define SO_T2_CONTROL(c) ((c & 0x1c) == 0x14)
86 #define SO_O2_CONTROL(c) ((c & 0x1c) == 0x18)
87 #define SO_EXT_CONTROL(c) ((c & 0x1c) == 0x1c)
89 #define T1_SET_PB7(c) (c & 0x80)
90 #define T1_CONTINUOUS(c) (c & 0x40)
91 #define T2_COUNT_PB6(c) (c & 0x20)
103 #define CLR_PA_INT() clear_int(INT_CA1 | ((!CA2_IND_IRQ(m_pcr)) ? INT_CA2: 0))
104 #define CLR_PB_INT() clear_int(INT_CB1 | ((!CB2_IND_IRQ(m_pcr)) ? INT_CB2: 0))
108 #define TIMER1_VALUE (m_t1ll+(m_t1lh<<8))
109 #define TIMER2_VALUE (m_t2ll+(m_t2lh<<8))
111 // XXX: from 6522via.h
141 // XXX: definitions for conversion
143 #define clocks_to_attotime(c) (1000000.0 * (c) / clock)
144 #define attotime_to_clocks(u) (int)(clock * (u) / 1000000.0 + 0.5)
146 #define m_out_a_handler(v) write_signals(&outputs_a, (v))
147 #define m_out_b_handler(v) write_signals(&outputs_b, (v))
148 #define m_ca2_handler(v) write_signals(&outputs_ca2, (v) ? 0xffffffff : 0)
149 #define m_cb1_handler(v) write_signals(&outputs_cb1, (v) ? 0xffffffff : 0)
150 #define m_cb2_handler(v) write_signals(&outputs_cb2, (v) ? 0xffffffff : 0)
151 #define m_irq_handler(v) write_signals(&outputs_irq, (v) ? 0xffffffff : 0)
153 #define ASSERT_LINE 1
156 /***************************************************************************
158 ***************************************************************************/
160 uint16_t SY6522::get_counter1_value()
166 val = attotime_to_clocks(get_event_remaining_usec(m_t1)) - IFR_DELAY;
170 val = 0xffff - attotime_to_clocks(get_passed_usec(m_time1));
177 //**************************************************************************
179 //**************************************************************************
181 //-------------------------------------------------
182 // device_start - device-specific startup
183 //-------------------------------------------------
185 void SY6522::initialize()
187 DEVICE::initialize();
188 m_t1ll = 0xf3; /* via at 0x9110 in vic20 show these values */
189 m_t1lh = 0xb5; /* ports are not written by kernel! */
190 m_t2ll = 0xff; /* taken from vice */
194 m_time2 = m_time1 = 0;//machine().time();
198 //-------------------------------------------------
199 // device_reset - device-specific reset
200 //-------------------------------------------------
231 m_ca2_handler(m_out_ca2);
232 m_cb1_handler(m_out_cb1);
233 m_cb2_handler(m_out_cb2);
235 // XXX: non loop events are canceled in reset()
245 void SY6522::output_irq()
247 if (m_ier & m_ifr & 0x7f)
249 if ((m_ifr & INT_ANY) == 0)
252 m_irq_handler(ASSERT_LINE);
260 m_irq_handler(CLEAR_LINE);
266 /*-------------------------------------------------
267 via_set_int - external interrupt check
268 -------------------------------------------------*/
270 void SY6522::set_int(int data)
281 /*-------------------------------------------------
282 via_clear_int - external interrupt check
283 -------------------------------------------------*/
285 void SY6522::clear_int(int data)
296 /*-------------------------------------------------
298 -------------------------------------------------*/
300 void SY6522::shift_out()
302 m_out_cb2 = (m_sr >> 7) & 1;
303 m_sr = (m_sr << 1) | m_out_cb2;
305 m_cb2_handler(m_out_cb2);
307 if (!SO_T2_RATE(m_acr))
309 m_shift_counter = (m_shift_counter + 1) % 8;
311 if (m_shift_counter == 0)
318 void SY6522::shift_in()
320 m_sr = (m_sr << 1) | (m_in_cb2 & 1);
322 m_shift_counter = (m_shift_counter + 1) % 8;
324 if (m_shift_counter == 0)
331 void SY6522::event_callback(int id, int err)
338 m_cb1_handler(m_out_cb1);
340 if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
346 m_cb1_handler(m_out_cb1);
348 if (SI_T2_CONTROL(m_acr) || SI_O2_CONTROL(m_acr))
353 if (SO_T2_RATE(m_acr) || m_shift_counter)
355 if (SI_O2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr))
357 register_event(this, TIMER_SHIFT, clocks_to_attotime(2), false, &m_shift_timer);
361 register_event(this, TIMER_SHIFT, clocks_to_attotime((m_t2ll + 2)*2), false, &m_shift_timer);
369 if (T1_CONTINUOUS (m_acr))
371 m_t1_pb7 = !m_t1_pb7;
372 register_event(this, TIMER_T1, clocks_to_attotime(TIMER1_VALUE + IFR_DELAY), false, &m_t1);
378 m_time1 = get_current_clock();
381 if (T1_SET_PB7(m_acr))
392 m_time2 = get_current_clock();
400 m_ca2_handler(m_out_ca2);
405 uint8_t SY6522::input_pa()
407 /// TODO: REMOVE THIS
408 // if (!m_in_a_handler.isnull())
410 // if (m_ddr_a != 0xff)
411 // m_in_a = m_in_a_handler(0);
413 // return (m_out_a & m_ddr_a) + (m_in_a & ~m_ddr_a);
416 return m_in_a & (m_out_a | ~m_ddr_a);
419 void SY6522::output_pa()
421 uint8_t pa = (m_out_a & m_ddr_a) | ~m_ddr_a;
425 uint8_t SY6522::input_pb()
427 /// TODO: REMOVE THIS
428 // if (m_ddr_b != 0xff && !m_in_b_handler.isnull())
430 // m_in_b = m_in_b_handler(0);
433 uint8_t pb = (m_out_b & m_ddr_b) + (m_in_b & ~m_ddr_b);
435 if (T1_SET_PB7(m_acr))
436 pb = (pb & 0x7f) | (m_t1_pb7 << 7);
441 void SY6522::output_pb()
443 uint8_t pb = (m_out_b & m_ddr_b) | ~m_ddr_b;
445 if (T1_SET_PB7(m_acr))
446 pb = (pb & 0x7f) | (m_t1_pb7 << 7);
451 /*-------------------------------------------------
452 via_r - CPU interface for VIA read
453 -------------------------------------------------*/
455 uint32_t SY6522::read_io8(uint32_t offset)
458 // if (space.debugger_access())
466 /* update the input */
467 if (PB_LATCH_ENABLE(m_acr) == 0)
480 /* update the input */
481 if (PA_LATCH_ENABLE(m_acr) == 0)
492 if (m_out_ca2 && (CA2_PULSE_OUTPUT(m_pcr) || CA2_AUTO_HS(m_pcr)))
495 m_ca2_handler(m_out_ca2);
498 if (CA2_PULSE_OUTPUT(m_pcr))
500 if(m_ca2_timer != -1)
501 cancel_event(this, m_ca2_timer);
502 register_event(this, TIMER_CA2, clocks_to_attotime(1), false, &m_ca2_timer);
508 /* update the input */
509 if (PA_LATCH_ENABLE(m_acr) == 0)
529 val = get_counter1_value() & 0xFF;
533 val = get_counter1_value() >> 8;
548 val = attotime_to_clocks(get_event_remaining_usec(m_t2)) & 0xff;
552 if (T2_COUNT_PB6(m_acr))
558 val = (0x10000 - (attotime_to_clocks(get_passed_usec(m_time2)) & 0xffff) - 1) & 0xff;
566 val = attotime_to_clocks(get_event_remaining_usec(m_t2)) >> 8;
570 if (T2_COUNT_PB6(m_acr))
576 val = (0x10000 - (attotime_to_clocks(get_passed_usec(m_time2)) & 0xffff) - 1) >> 8;
585 if (SI_O2_CONTROL(m_acr))
587 if(m_shift_timer != -1)
588 cancel_event(this, m_shift_timer);
589 register_event(this, TIMER_SHIFT, clocks_to_attotime(2), false, &m_shift_timer);
591 if (SI_T2_CONTROL(m_acr))
593 if(m_shift_timer != -1)
594 cancel_event(this, m_shift_timer);
595 register_event(this, TIMER_SHIFT, clocks_to_attotime((m_t2ll + 2)*2), false, &m_shift_timer);
619 /*-------------------------------------------------
620 via_w - CPU interface for VIA write
621 -------------------------------------------------*/
623 void SY6522::write_io8(uint32_t offset, uint32_t data)
639 if (m_out_cb2 && CB2_AUTO_HS(m_pcr))
642 m_cb2_handler(m_out_cb2);
656 if (m_out_ca2 && (CA2_PULSE_OUTPUT(m_pcr) || CA2_AUTO_HS(m_pcr)))
659 m_ca2_handler(m_out_ca2);
662 if (CA2_PULSE_OUTPUT(m_pcr))
664 if(m_ca2_timer != -1)
665 cancel_event(this, m_ca2_timer);
666 register_event(this, TIMER_CA2, clocks_to_attotime(1), false, &m_ca2_timer);
682 if ( data != m_ddr_b )
710 m_t1ch = m_t1lh = data;
717 if (T1_SET_PB7(m_acr))
723 cancel_event(this, m_t1);
724 register_event(this, TIMER_T1, clocks_to_attotime(TIMER1_VALUE + IFR_DELAY), false, &m_t1);
733 m_t2ch = m_t2lh = data;
738 if (!T2_COUNT_PB6(m_acr))
741 cancel_event(this, m_t2);
742 register_event(this, TIMER_T2, clocks_to_attotime(TIMER2_VALUE + IFR_DELAY), false, &m_t2);
748 cancel_event(this, m_t2);
749 register_event(this, TIMER_T2, clocks_to_attotime(TIMER2_VALUE), false, &m_t2);
751 m_time2 = get_current_clock();
759 if (SO_O2_CONTROL(m_acr))
761 if(m_shift_timer != -1)
762 cancel_event(this, m_shift_timer);
763 register_event(this, TIMER_SHIFT, clocks_to_attotime(2), false, &m_shift_timer);
765 if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr))
767 if(m_shift_timer != -1)
768 cancel_event(this, m_shift_timer);
769 register_event(this, TIMER_SHIFT, clocks_to_attotime((m_t2ll + 2)*2), false, &m_shift_timer);
776 if (CA2_FIX_OUTPUT(data) && m_out_ca2 != CA2_OUTPUT_LEVEL(data))
778 m_out_ca2 = CA2_OUTPUT_LEVEL(data);
779 m_ca2_handler(m_out_ca2);
782 if (CB2_FIX_OUTPUT(data) && m_out_cb2 != CB2_OUTPUT_LEVEL(data))
784 m_out_cb2 = CB2_OUTPUT_LEVEL(data);
785 m_cb2_handler(m_out_cb2);
791 uint16_t counter1 = get_counter1_value();
796 if (T1_CONTINUOUS(data))
799 cancel_event(this, m_t1);
800 register_event(this, TIMER_T1, clocks_to_attotime(counter1 + IFR_DELAY), false, &m_t1);
809 m_ier |= data & 0x7f;
813 m_ier &= ~(data & 0x7f);
829 void SY6522::write_signal(int id, uint32_t data, uint32_t mask)
831 int state = (data & mask) ? 1 : 0;
834 case SIG_SY6522_PORT_A:
836 m_in_a |= (data & mask);
839 case SIG_SY6522_PORT_CA1:
840 /*-------------------------------------------------
841 ca1_w - interface setting VIA port CA1 input
842 -------------------------------------------------*/
843 if (m_in_ca1 != state)
847 if ((m_in_ca1 && CA1_LOW_TO_HIGH(m_pcr)) || (!m_in_ca1 && CA1_HIGH_TO_LOW(m_pcr)))
849 if (PA_LATCH_ENABLE(m_acr))
851 m_latch_a = input_pa();
856 if (!m_out_ca2 && CA2_AUTO_HS(m_pcr))
859 m_ca2_handler(m_out_ca2);
865 case SIG_SY6522_PORT_CA2:
866 /*-------------------------------------------------
867 ca2_w - interface setting VIA port CA2 input
868 -------------------------------------------------*/
869 if (m_in_ca2 != state)
873 if (CA2_INPUT(m_pcr))
875 if ((m_in_ca2 && CA2_LOW_TO_HIGH(m_pcr)) || (!m_in_ca2 && CA2_HIGH_TO_LOW(m_pcr)))
883 case SIG_SY6522_PORT_B:
885 m_in_b |= (data & mask);
888 case SIG_SY6522_PORT_CB1:
889 /*-------------------------------------------------
890 cb1_w - interface setting VIA port CB1 input
891 -------------------------------------------------*/
892 if (m_in_cb1 != state)
896 if ((m_in_cb1 && CB1_LOW_TO_HIGH(m_pcr)) || (!m_in_cb1 && CB1_HIGH_TO_LOW(m_pcr)))
898 if (PB_LATCH_ENABLE(m_acr))
900 m_latch_b = input_pb();
903 if (SO_EXT_CONTROL(m_acr))
908 if (SI_EXT_CONTROL(m_acr))
915 if (!m_out_cb2 && CB2_AUTO_HS(m_pcr))
924 case SIG_SY6522_PORT_CB2:
925 /*-------------------------------------------------
926 cb2_w - interface setting VIA port CB2 input
927 -------------------------------------------------*/
928 if (m_in_cb2 != state)
932 if (CB2_INPUT(m_pcr))
934 if ((m_in_cb2 && CB2_LOW_TO_HIGH(m_pcr)) || (!m_in_cb2 && CB2_HIGH_TO_LOW(m_pcr)))
944 #define STATE_VERSION 1
946 bool SY6522::process_state(FILEIO* state_fio, bool loading)
948 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
951 if(!state_fio->StateCheckInt32(this_device_id)) {
954 state_fio->StateValue(m_in_a);
955 state_fio->StateValue(m_in_ca1);
956 state_fio->StateValue(m_in_ca2);
957 state_fio->StateValue(m_out_a);
958 state_fio->StateValue(m_out_ca2);
959 state_fio->StateValue(m_ddr_a);
960 state_fio->StateValue(m_latch_a);
961 state_fio->StateValue(m_in_b);
962 state_fio->StateValue(m_in_cb1);
963 state_fio->StateValue(m_in_cb2);
964 state_fio->StateValue(m_out_b);
965 state_fio->StateValue(m_out_cb1);
966 state_fio->StateValue(m_out_cb2);
967 state_fio->StateValue(m_ddr_b);
968 state_fio->StateValue(m_latch_b);
969 state_fio->StateValue(m_t1cl);
970 state_fio->StateValue(m_t1ch);
971 state_fio->StateValue(m_t1ll);
972 state_fio->StateValue(m_t1lh);
973 state_fio->StateValue(m_t2cl);
974 state_fio->StateValue(m_t2ch);
975 state_fio->StateValue(m_t2ll);
976 state_fio->StateValue(m_t2lh);
977 state_fio->StateValue(m_sr);
978 state_fio->StateValue(m_pcr);
979 state_fio->StateValue(m_acr);
980 state_fio->StateValue(m_ier);
981 state_fio->StateValue(m_ifr);
982 state_fio->StateValue(m_t1);
983 state_fio->StateValue(m_time1);
984 state_fio->StateValue(m_t1_active);
985 state_fio->StateValue(m_t1_pb7);
986 state_fio->StateValue(m_t2);
987 state_fio->StateValue(m_time2);
988 state_fio->StateValue(m_t2_active);
989 state_fio->StateValue(m_ca2_timer);
990 state_fio->StateValue(m_shift_timer);
991 state_fio->StateValue(m_shift_counter);