1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles, Nathan Woods
3 /**********************************************************************
4
5 Motorola 6821 PIA interface and emulation
6
7 **********************************************************************/
8
9 #include "emu.h"
10 #include "6821pia.h"
11
12 //**************************************************************************
13 // MACROS
14 //**************************************************************************
15
16 #define LOG_GENERAL 0x01
17 #define LOG_SETUP 0x02
18 #define LOG_CA1 0x08
19
20 //#define VERBOSE (LOG_SETUP | LOG_GENERAL | LOG_CA1)
21 //#define LOG_OUTPUT_STREAM std::cout
22
23 #include "logmacro.h"
24 #define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__)
25 #define LOGCA1(...) LOGMASKED(LOG_CA1, __VA_ARGS__)
26
27 #define PIA_IRQ1 (0x80)
28 #define PIA_IRQ2 (0x40)
29
30
31 //**************************************************************************
32 // LIVE DEVICE
33 //**************************************************************************
34
35 // device type definition
36 DEFINE_DEVICE_TYPE(PIA6821, pia6821_device, "pia6821", "6821 PIA")
37
38
39 //-------------------------------------------------
40 // pia6821_device - constructor
41 //-------------------------------------------------
42
pia6821_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)43 pia6821_device::pia6821_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
44 : device_t(mconfig, PIA6821, tag, owner, clock),
45 m_in_a_handler(*this),
46 m_in_b_handler(*this),
47 m_in_ca1_handler(*this),
48 m_in_cb1_handler(*this),
49 m_in_ca2_handler(*this),
50 m_out_a_handler(*this),
51 m_out_b_handler(*this),
52 m_ca2_handler(*this),
53 m_cb2_handler(*this),
54 m_irqa_handler(*this),
55 m_irqb_handler(*this), m_in_a(0),
56 m_in_ca1(0), m_in_ca2(0), m_out_a(0), m_a_input_overrides_output_mask(0), m_out_ca2(0), m_ddr_a(0),
57 m_ctl_a(0), m_irq_a1(0), m_irq_a2(0),
58 m_irq_a_state(0), m_in_b(0),
59 m_in_cb1(0), m_in_cb2(0), m_out_b(0), m_out_cb2(0), m_last_out_cb2_z(0), m_ddr_b(0),
60 m_ctl_b(0), m_irq_b1(0), m_irq_b2(0),
61 m_irq_b_state(0), m_in_a_pushed(false), m_out_a_needs_pulled(false), m_in_ca1_pushed(false),
62 m_in_ca2_pushed(false), m_out_ca2_needs_pulled(false), m_in_b_pushed(false), m_out_b_needs_pulled(false),
63 m_in_cb1_pushed(false), m_in_cb2_pushed(false), m_out_cb2_needs_pulled(false), m_logged_port_a_not_connected(false),
64 m_logged_port_b_not_connected(false), m_logged_ca1_not_connected(false), m_logged_ca2_not_connected(false),
65 m_logged_cb1_not_connected(false), m_logged_cb2_not_connected(false)
66 {
67 }
68
69
70 //-------------------------------------------------
71 // device_start - device-specific startup
72 //-------------------------------------------------
73
device_start()74 void pia6821_device::device_start()
75 {
76 // resolve callbacks
77 m_in_a_handler.resolve();
78 m_in_b_handler.resolve();
79 m_in_ca1_handler.resolve();
80 m_in_cb1_handler.resolve();
81 m_in_ca2_handler.resolve();
82 m_out_a_handler.resolve();
83 m_out_b_handler.resolve();
84 m_ca2_handler.resolve();
85 m_cb2_handler.resolve();
86 m_irqa_handler.resolve_safe();
87 m_irqb_handler.resolve_safe();
88
89 save_item(NAME(m_in_a));
90 save_item(NAME(m_in_ca1));
91 save_item(NAME(m_in_ca2));
92 save_item(NAME(m_out_a));
93 save_item(NAME(m_out_ca2));
94 save_item(NAME(m_ddr_a));
95 save_item(NAME(m_ctl_a));
96 save_item(NAME(m_irq_a1));
97 save_item(NAME(m_irq_a2));
98 save_item(NAME(m_irq_a_state));
99 save_item(NAME(m_in_b));
100 save_item(NAME(m_in_cb1));
101 save_item(NAME(m_in_cb2));
102 save_item(NAME(m_out_b));
103 save_item(NAME(m_out_cb2));
104 save_item(NAME(m_last_out_cb2_z));
105 save_item(NAME(m_ddr_b));
106 save_item(NAME(m_ctl_b));
107 save_item(NAME(m_irq_b1));
108 save_item(NAME(m_irq_b2));
109 save_item(NAME(m_irq_b_state));
110 save_item(NAME(m_in_a_pushed));
111 save_item(NAME(m_out_a_needs_pulled));
112 save_item(NAME(m_in_ca1_pushed));
113 save_item(NAME(m_in_ca2_pushed));
114 save_item(NAME(m_out_ca2_needs_pulled));
115 save_item(NAME(m_in_b_pushed));
116 save_item(NAME(m_out_b_needs_pulled));
117 save_item(NAME(m_in_cb1_pushed));
118 save_item(NAME(m_in_cb2_pushed));
119 save_item(NAME(m_out_cb2_needs_pulled));
120 }
121
122
123 //-------------------------------------------------
124 // device_reset - device-specific reset
125 //-------------------------------------------------
126
device_reset()127 void pia6821_device::device_reset()
128 {
129 //
130 // set default read values.
131 //
132 // ports A,CA1,CA2 default to 1
133 // ports B,CB1,CB2 are three-state and undefined (set to 0)
134 //
135 m_in_a = 0xff;
136 m_in_ca1 = true;
137 m_in_ca2 = true;
138 m_out_a = 0;
139 m_out_ca2 = 0;
140 m_ddr_a = 0;
141 m_ctl_a = 0;
142 m_irq_a1 = 0;
143 m_irq_a2 = 0;
144 m_irq_a_state = 0;
145 m_in_b = 0;
146 m_in_cb1 = 0;
147 m_in_cb2 = 0;
148 m_out_b = 0;
149 m_out_cb2 = 0;
150 m_last_out_cb2_z = 0;
151 m_ddr_b = 0;
152 m_ctl_b = 0;
153 m_irq_b1 = 0;
154 m_irq_b2 = 0;
155 m_irq_b_state = 0;
156 m_in_a_pushed = false;
157 m_out_a_needs_pulled = false;
158 m_in_ca1_pushed = false;
159 m_in_ca2_pushed = false;
160 m_out_ca2_needs_pulled = false;
161 m_in_b_pushed = false;
162 m_out_b_needs_pulled = false;
163 m_in_cb1_pushed = false;
164 m_in_cb2_pushed = false;
165 m_out_cb2_needs_pulled = false;
166 m_logged_port_a_not_connected = false;
167 m_logged_port_b_not_connected = false;
168 m_logged_ca1_not_connected = false;
169 m_logged_ca2_not_connected = false;
170 m_logged_cb1_not_connected = false;
171 m_logged_cb2_not_connected = false;
172
173
174 // clear the IRQs
175 m_irqa_handler(false);
176 m_irqb_handler(false);
177 }
178
179
180 //-------------------------------------------------
181 // update_interrupts
182 //-------------------------------------------------
183
update_interrupts()184 void pia6821_device::update_interrupts()
185 {
186 // start with IRQ A
187 int new_state = (m_irq_a1 && irq1_enabled(m_ctl_a)) || (m_irq_a2 && irq2_enabled(m_ctl_a));
188
189 if (new_state != m_irq_a_state)
190 {
191 m_irq_a_state = new_state;
192 m_irqa_handler(m_irq_a_state);
193 }
194
195 // then do IRQ B
196 new_state = (m_irq_b1 && irq1_enabled(m_ctl_b)) || (m_irq_b2 && irq2_enabled(m_ctl_b));
197
198 if (new_state != m_irq_b_state)
199 {
200 m_irq_b_state = new_state;
201 m_irqb_handler(m_irq_b_state);
202 }
203 }
204
205
206 //-------------------------------------------------
207 // get_in_a_value
208 //-------------------------------------------------
209
get_in_a_value()210 uint8_t pia6821_device::get_in_a_value()
211 {
212 uint8_t port_a_data = 0;
213 uint8_t ret;
214
215 // update the input
216 if (!m_in_a_handler.isnull())
217 {
218 port_a_data = m_in_a_handler(0);
219 }
220 else
221 {
222 if (m_in_a_pushed)
223 {
224 port_a_data = m_in_a;
225 }
226 else
227 {
228 // assume pins are disconnected and simulate the internal pullups.
229 port_a_data = 0xff;
230
231 if (!m_logged_port_a_not_connected && (m_ddr_a != 0xff) &&
232 !machine().side_effects_disabled())
233 {
234 logerror("Warning! No port A read handler. Assuming pins 0x%02X not connected\n", m_ddr_a ^ 0xff);
235 m_logged_port_a_not_connected = true;
236 }
237 }
238 }
239
240 // For port A, when the port is in output mode other devices can drive the
241 // pins too. If the device pulls the voltage on the lines enough,a read of
242 // the output register will show the external device value on the driven pins.
243 ret = (~m_ddr_a & port_a_data) // input pins
244 | (m_ddr_a & m_out_a & ~m_a_input_overrides_output_mask) // normal output pins
245 | (m_ddr_a & port_a_data & m_a_input_overrides_output_mask); // overridden output pins
246
247 return ret;
248 }
249
250
251 //-------------------------------------------------
252 // get_in_b_value
253 //-------------------------------------------------
254
get_in_b_value()255 uint8_t pia6821_device::get_in_b_value()
256 {
257 uint8_t ret;
258
259 if (m_ddr_b == 0xff)
260 {
261 // all output, just return buffer
262 ret = m_out_b;
263 }
264 else
265 {
266 uint8_t port_b_data;
267
268 // update the input
269 if (!m_in_b_handler.isnull())
270 {
271 port_b_data = m_in_b_handler(0);
272 }
273 else
274 {
275 if (m_in_b_pushed)
276 {
277 port_b_data = m_in_b;
278 }
279 else
280 {
281 if (!m_logged_port_b_not_connected && (m_ddr_b != 0xff)
282 && !machine().side_effects_disabled())
283 {
284 logerror("Error! No port B read handler. Three-state pins 0x%02X are undefined\n", m_ddr_b ^ 0xff);
285 m_logged_port_b_not_connected = true;
286 }
287
288 // undefined -- need to return something
289 port_b_data = 0x00;
290 }
291 }
292
293 // the DDR determines if the pin or the output buffer is read
294 ret = (m_out_b & m_ddr_b) | (port_b_data & ~m_ddr_b);
295 }
296
297 return ret;
298 }
299
300
301 //-------------------------------------------------
302 // get_out_a_value
303 //-------------------------------------------------
304
get_out_a_value()305 uint8_t pia6821_device::get_out_a_value()
306 {
307 uint8_t ret;
308
309 if (m_ddr_a == 0xff)
310 {
311 // all output
312 ret = m_out_a;
313 }
314 else
315 {
316 // input pins don't change
317 ret = (m_out_a & m_ddr_a) | (get_in_a_value() & ~m_ddr_a);
318 }
319
320 return ret;
321 }
322
323
324 //-------------------------------------------------
325 // get_out_b_value
326 //-------------------------------------------------
327
get_out_b_value()328 uint8_t pia6821_device::get_out_b_value()
329 {
330 // input pins are high-impedance - we just send them as zeros for backwards compatibility
331 return m_out_b & m_ddr_b;
332 }
333
334
335 //-------------------------------------------------
336 // set_out_ca2
337 //-------------------------------------------------
338
set_out_ca2(int data)339 void pia6821_device::set_out_ca2(int data)
340 {
341 if (data != m_out_ca2)
342 {
343 m_out_ca2 = data;
344
345 // send to output function
346 if (!m_ca2_handler.isnull())
347 {
348 m_ca2_handler(m_out_ca2);
349 }
350 else
351 {
352 if (m_out_ca2_needs_pulled)
353 logerror("Warning! No port CA2 write handler. Previous value has been lost!\n");
354
355 m_out_ca2_needs_pulled = true;
356 }
357 }
358 }
359
360
361 //-------------------------------------------------
362 // set_out_cb2
363 //-------------------------------------------------
364
set_out_cb2(int data)365 void pia6821_device::set_out_cb2(int data)
366 {
367 int z = cb2_output_z();
368
369 if ((data != m_out_cb2) || (z != m_last_out_cb2_z))
370 {
371 m_out_cb2 = data;
372 m_last_out_cb2_z = z;
373
374 // send to output function
375 if (!m_cb2_handler.isnull())
376 {
377 m_cb2_handler(m_out_cb2);
378 }
379 else
380 {
381 if (m_out_cb2_needs_pulled)
382 logerror("Warning! No port CB2 write handler. Previous value has been lost!\n");
383
384 m_out_cb2_needs_pulled = true;
385 }
386 }
387 }
388
389
390 //-------------------------------------------------
391 // port_a_r
392 //-------------------------------------------------
393
port_a_r()394 uint8_t pia6821_device::port_a_r()
395 {
396 uint8_t ret = get_in_a_value();
397
398 if (!machine().side_effects_disabled())
399 {
400 // IRQ flags implicitly cleared by a read
401 m_irq_a1 = false;
402 m_irq_a2 = false;
403 update_interrupts();
404
405 // CA2 is configured as output and in read strobe mode
406 if (c2_output(m_ctl_a) && c2_strobe_mode(m_ctl_a))
407 {
408 // this will cause a transition low
409 set_out_ca2(false);
410
411 // if the CA2 strobe is cleared by the E, reset it right away
412 if (strobe_e_reset(m_ctl_a))
413 set_out_ca2(true);
414 }
415
416 LOG("PIA port A read = %02X\n", ret);
417 }
418
419 return ret;
420 }
421
422
423 //-------------------------------------------------
424 // ddr_a_r
425 //-------------------------------------------------
426
ddr_a_r()427 uint8_t pia6821_device::ddr_a_r()
428 {
429 const uint8_t ret = m_ddr_a;
430
431 LOG("PIA DDR A read = %02X\n", ret);
432
433 return ret;
434 }
435
436
437 //-------------------------------------------------
438 // port_b_r
439 //-------------------------------------------------
440
port_b_r()441 uint8_t pia6821_device::port_b_r()
442 {
443 const uint8_t ret = get_in_b_value();
444
445 if (!machine().side_effects_disabled())
446 {
447 // This read will implicitly clear the IRQ B1 flag. If CB2 is
448 // in write-strobe mode with CB1 restore, and a CB1 active
449 // transition set the flag, clearing it will cause CB2 to go
450 // high again. Note that this is different from what happens
451 // with port A.
452 if (m_irq_b1 && c2_strobe_mode(m_ctl_b) && strobe_c1_reset(m_ctl_b))
453 set_out_cb2(true);
454
455 // IRQ flags implicitly cleared by a read
456 m_irq_b1 = false;
457 m_irq_b2 = false;
458 update_interrupts();
459
460 LOG("PIA port B read = %02X\n", ret);
461 }
462
463 return ret;
464 }
465
466
467 //-------------------------------------------------
468 // ddr_b_r
469 //-------------------------------------------------
470
ddr_b_r()471 uint8_t pia6821_device::ddr_b_r()
472 {
473 const uint8_t ret = m_ddr_b;
474
475 LOG("PIA DDR B read = %02X\n", ret);
476
477 return ret;
478 }
479
480
481 //-------------------------------------------------
482 // control_a_r
483 //-------------------------------------------------
484
control_a_r()485 uint8_t pia6821_device::control_a_r()
486 {
487 uint8_t ret;
488
489 if (!machine().side_effects_disabled())
490 {
491 // update CA1 & CA2 if callback exists, these in turn may update IRQ's
492 if (!m_in_ca1_handler.isnull())
493 {
494 ca1_w(m_in_ca1_handler());
495 }
496 else if(!m_logged_ca1_not_connected && (!m_in_ca1_pushed))
497 {
498 logerror("Warning! No CA1 read handler. Assuming pin not connected\n");
499 m_logged_ca1_not_connected = true;
500 }
501
502 if (!m_in_ca2_handler.isnull())
503 {
504 ca2_w(m_in_ca2_handler());
505 }
506 else if ( !m_logged_ca2_not_connected && c2_input(m_ctl_a) && !m_in_ca2_pushed)
507 {
508 logerror("Warning! No CA2 read handler. Assuming pin not connected\n");
509 m_logged_ca2_not_connected = true;
510 }
511 }
512
513 // read control register
514 ret = m_ctl_a;
515
516 // set the IRQ flags if we have pending IRQs
517 if (m_irq_a1)
518 ret |= PIA_IRQ1;
519
520 if (m_irq_a2 && c2_input(m_ctl_a))
521 ret |= PIA_IRQ2;
522
523 LOG("PIA control A read = %02X\n", ret);
524
525 return ret;
526 }
527
528
529 //-------------------------------------------------
530 // control_b_r
531 //-------------------------------------------------
532
control_b_r()533 uint8_t pia6821_device::control_b_r()
534 {
535 uint8_t ret;
536
537 if (!machine().side_effects_disabled())
538 {
539 // update CB1 & CB2 if callback exists, these in turn may update IRQ's
540 if(!m_in_cb1_handler.isnull())
541 {
542 cb1_w(m_in_cb1_handler());
543 }
544 else if(!m_logged_cb1_not_connected && !m_in_cb1_pushed)
545 {
546 logerror("Error! no CB1 read handler. Three-state pin is undefined\n");
547 m_logged_cb1_not_connected = true;
548 }
549
550 if(!m_logged_cb2_not_connected && c2_input(m_ctl_b) && !m_in_cb2_pushed)
551 {
552 logerror("Error! Three-state pin is undefined\n");
553 m_logged_cb2_not_connected = true;
554 }
555 }
556
557 // read control register
558 ret = m_ctl_b;
559
560 // set the IRQ flags if we have pending IRQs
561 if (m_irq_b1)
562 ret |= PIA_IRQ1;
563
564 if (m_irq_b2 && c2_input(m_ctl_b))
565 ret |= PIA_IRQ2;
566
567 LOG("PIA control B read = %02X\n", ret);
568
569 return ret;
570 }
571
572
573 //-------------------------------------------------
574 // read
575 //-------------------------------------------------
576
read(offs_t offset)577 uint8_t pia6821_device::read(offs_t offset)
578 {
579 uint8_t ret;
580
581 switch (offset & 0x03)
582 {
583 default: // impossible
584 case 0x00:
585 ret = output_selected(m_ctl_a) ? port_a_r() : ddr_a_r();
586 break;
587
588 case 0x01:
589 ret = control_a_r();
590 break;
591
592 case 0x02:
593 ret = output_selected(m_ctl_b) ? port_b_r() : ddr_b_r();
594 break;
595
596 case 0x03:
597 ret = control_b_r();
598 break;
599 }
600
601 return ret;
602 }
603
604
605
606 //-------------------------------------------------
607 // send_to_out_a_func
608 //-------------------------------------------------
609
send_to_out_a_func(const char * message)610 void pia6821_device::send_to_out_a_func(const char* message)
611 {
612 // input pins are pulled high
613 const uint8_t data = get_out_a_value();
614
615 LOG("PIA %s = %02X DDRA=%02x\n", message, data, m_ddr_a);
616
617 if (!m_out_a_handler.isnull())
618 {
619 m_out_a_handler(offs_t(0), data);
620 }
621 else
622 {
623 if (m_out_a_needs_pulled)
624 logerror("Warning! No port A write handler. Previous value has been lost!\n");
625
626 m_out_a_needs_pulled = true;
627 }
628 }
629
630
631 //-------------------------------------------------
632 // send_to_out_b_func
633 //-------------------------------------------------
634
send_to_out_b_func(const char * message)635 void pia6821_device::send_to_out_b_func(const char* message)
636 {
637 // input pins are high-impedance - we just send them as zeros for backwards compatibility
638 const uint8_t data = get_out_b_value();
639
640 LOG("PIA %s = %02X DDRB=%02x\n", message, data, m_ddr_b);
641
642 if (!m_out_b_handler.isnull())
643 {
644 m_out_b_handler(offs_t(0), data);
645 }
646 else
647 {
648 if (m_out_b_needs_pulled)
649 logerror("Warning! No port B write handler. Previous value has been lost!\n");
650
651 m_out_b_needs_pulled = true;
652 }
653 }
654
655
656 //-------------------------------------------------
657 // port_a_w
658 //-------------------------------------------------
659
port_a_w(uint8_t data)660 void pia6821_device::port_a_w(uint8_t data)
661 {
662 // buffer the output value
663 m_out_a = data;
664
665 LOGSETUP("PIA ");
666 send_to_out_a_func("port A write");
667 }
668
669
670 //-------------------------------------------------
671 // ddr_a_w
672 //-------------------------------------------------
673
ddr_a_w(uint8_t data)674 void pia6821_device::ddr_a_w(uint8_t data)
675 {
676 LOGSETUP("PIA DDR A write = %02X (%s mode)\n", data, (0x00 == data) ? "input" : (0xff == data) ? "output" : "mixed");
677
678 if (m_ddr_a != data)
679 {
680 // DDR changed, call the callback again
681 m_ddr_a = data;
682 m_logged_port_a_not_connected = false;
683 send_to_out_a_func("port A write due to DDR change");
684 }
685 }
686
687
688 //-------------------------------------------------
689 // port_b_w
690 //-------------------------------------------------
691
port_b_w(uint8_t data)692 void pia6821_device::port_b_w(uint8_t data)
693 {
694 // buffer the output value
695 m_out_b = data;
696
697 send_to_out_b_func("port B write");
698
699 // CB2 in write strobe mode
700 if (c2_strobe_mode(m_ctl_b))
701 {
702 // this will cause a transition low
703 set_out_cb2(false);
704
705 // if the CB2 strobe is cleared by the E, reset it right away
706 if (strobe_e_reset(m_ctl_b))
707 set_out_cb2(true);
708 }
709 }
710
711
712 //-------------------------------------------------
713 // ddr_b_w
714 //-------------------------------------------------
715
ddr_b_w(uint8_t data)716 void pia6821_device::ddr_b_w(uint8_t data)
717 {
718 LOGSETUP("PIA DDR B write = %02X (%s mode)\n", data, (0x00 == data) ? "input" : (0xff == data) ? "output" : "mixed");
719
720 if (m_ddr_b != data)
721 {
722 // DDR changed, call the callback again
723 m_ddr_b = data;
724 m_logged_port_b_not_connected = false;
725 send_to_out_b_func("port B write due to DDR change");
726 }
727 }
728
729
730 //-------------------------------------------------
731 // control_a_w
732 //-------------------------------------------------
733
control_a_w(uint8_t data)734 void pia6821_device::control_a_w(uint8_t data)
735 {
736 // bit 7 and 6 are read only
737 data &= 0x3f;
738
739 LOGSETUP("PIA control A write = %02X\n", data);
740 LOGSETUP(" - CA1 interrupts %s\n", (data & 0x01) ? "enabled" : "disabled");
741 LOGSETUP(" - CA1 interrupts active on %s transition\n", (data & 0x02) ? "low-to-high" : "high-to-low");
742 LOGSETUP(" - Port A %s register selected\n", (data & 0x04) ? "Data" : "DDR");
743
744 // update the control register
745 m_ctl_a = data;
746
747 // CA2 is configured as output
748 if (c2_output(m_ctl_a))
749 {
750 bool temp;
751 if (c2_set_mode(m_ctl_a))
752 {
753 LOGSETUP(" - CA2 set/reset mode: ");
754 temp = c2_set(m_ctl_a); // set/reset mode - bit value determines the new output
755 }
756 else
757 {
758 LOGSETUP(" - CA2 strobe mode: ");
759 temp = true; // strobe mode - output is always high unless strobed
760 }
761
762 LOGSETUP("%d\n", temp);
763 set_out_ca2(temp);
764 }
765
766 // update externals
767 update_interrupts();
768 }
769
770
771 //-------------------------------------------------
772 // control_b_w
773 //-------------------------------------------------
774
control_b_w(uint8_t data)775 void pia6821_device::control_b_w(uint8_t data)
776 {
777 // bit 7 and 6 are read only
778 data &= 0x3f;
779
780 LOGSETUP("PIA control B write = %02X\n", data);
781 LOGSETUP(" - CB1 interrupts %s\n", (data & 0x01) ? "enabled" : "disabled");
782 LOGSETUP(" - CB1 interrupts active on %s transition\n", (data & 0x02) ? "low-to-high" : "high-to-low");
783 LOGSETUP(" - Port B %s register selected\n", (data & 0x04) ? "Data" : "DDR");
784
785 // update the control register
786 m_ctl_b = data;
787
788 bool temp;
789 if (c2_set_mode(m_ctl_b))
790 {
791 LOGSETUP(" - CB2 set/reset mode: ");
792 temp = c2_set(m_ctl_b); // set/reset mode - bit value determines the new output
793 }
794 else
795 {
796 LOGSETUP(" - CB2 strobe mode: ");
797 temp = true; // strobe mode - output is always high unless strobed
798 }
799
800 LOGSETUP("%d\n", temp);
801 set_out_cb2(temp);
802
803 // update externals
804 update_interrupts();
805 }
806
807
808 //-------------------------------------------------
809 // write
810 //-------------------------------------------------
811
write(offs_t offset,uint8_t data)812 void pia6821_device::write(offs_t offset, uint8_t data)
813 {
814 switch (offset & 0x03)
815 {
816 default: // impossible
817 case 0x00:
818 if (output_selected(m_ctl_a))
819 port_a_w(data);
820 else
821 ddr_a_w(data);
822 break;
823
824 case 0x01:
825 control_a_w( data);
826 break;
827
828 case 0x02:
829 if (output_selected(m_ctl_b))
830 port_b_w(data);
831 else
832 ddr_b_w(data);
833 break;
834
835 case 0x03:
836 control_b_w(data);
837 break;
838 }
839 }
840
841
842 //-------------------------------------------------
843 // set_a_input
844 //-------------------------------------------------
845
set_a_input(uint8_t data)846 void pia6821_device::set_a_input(uint8_t data)
847 {
848 if (!m_in_a_handler.isnull())
849 throw emu_fatalerror("pia6821_device::set_a_input() called when m_in_a_handler set");
850
851 LOG("Set PIA input port A = %02X\n", data);
852
853 m_in_a = data;
854 m_in_a_pushed = true;
855 }
856
857
858 //-------------------------------------------------
859 // porta_w
860 //-------------------------------------------------
861
porta_w(uint8_t data)862 void pia6821_device::porta_w(uint8_t data)
863 {
864 set_a_input(data);
865 }
866
867
868 //-------------------------------------------------
869 // write_porta_line
870 //-------------------------------------------------
871
write_porta_line(int line,bool state)872 void pia6821_device::write_porta_line(int line, bool state)
873 {
874 const uint8_t mask = 1 << line;
875 if (state)
876 set_a_input(m_in_a | mask);
877 else
878 set_a_input(m_in_a & ~mask);
879 }
880
881
882 //-------------------------------------------------
883 // a_output
884 //-------------------------------------------------
885
a_output()886 uint8_t pia6821_device::a_output()
887 {
888 m_out_a_needs_pulled = false;
889
890 return get_out_a_value();
891 }
892
893
894 //-------------------------------------------------
895 // ca1_w
896 //-------------------------------------------------
897
WRITE_LINE_MEMBER(pia6821_device::ca1_w)898 WRITE_LINE_MEMBER( pia6821_device::ca1_w )
899 {
900 LOGCA1("Set PIA input CA1 = %d\n", state);
901
902 // the new state has caused a transition
903 if ((m_in_ca1 != state) && ((state && c1_low_to_high(m_ctl_a)) || (!state && c1_high_to_low(m_ctl_a))))
904 {
905 LOGCA1("CA1 triggering\n");
906
907 // mark the IRQ
908 m_irq_a1 = true;
909
910 // update externals
911 update_interrupts();
912
913 // CA2 is configured as output and in read strobe mode and cleared by a CA1 transition
914 if (c2_output(m_ctl_a) && c2_strobe_mode(m_ctl_a) && strobe_c1_reset(m_ctl_a))
915 set_out_ca2(true);
916 }
917
918 // set the new value for CA1
919 m_in_ca1 = state;
920 m_in_ca1_pushed = true;
921 }
922
923
924 //-------------------------------------------------
925 // ca2_w
926 //-------------------------------------------------
927
WRITE_LINE_MEMBER(pia6821_device::ca2_w)928 WRITE_LINE_MEMBER( pia6821_device::ca2_w )
929 {
930 LOG("Set PIA input CA2 = %d\n", state);
931
932 // if input mode and the new state has caused a transition
933 if (c2_input(m_ctl_a) && (m_in_ca2 != state) && ((state && c2_low_to_high(m_ctl_a)) || (!state && c2_high_to_low(m_ctl_a))))
934 {
935 LOG("CA2 triggering\n");
936
937 // mark the IRQ
938 m_irq_a2 = true;
939
940 // update externals
941 update_interrupts();
942 }
943
944 // set the new value for CA2
945 m_in_ca2 = state;
946 m_in_ca2_pushed = true;
947 }
948
949
950 //-------------------------------------------------
951 // ca2_output
952 //-------------------------------------------------
953
ca2_output()954 bool pia6821_device::ca2_output()
955 {
956 m_out_ca2_needs_pulled = false;
957
958 return m_out_ca2;
959 }
960
961
962 //-------------------------------------------------
963 // ca2_output_z - version of ca2_output which
964 // takes account of internal pullup resistor
965 //-------------------------------------------------
966
ca2_output_z()967 bool pia6821_device::ca2_output_z()
968 {
969 m_out_ca2_needs_pulled = false;
970
971 // If it's an output, output the bit, if it's an input, it's pulled up
972 return m_out_ca2 | c2_input(m_ctl_a);
973 }
974
975
976 //-------------------------------------------------
977 // portb_w
978 //-------------------------------------------------
979
portb_w(uint8_t data)980 void pia6821_device::portb_w(uint8_t data)
981 {
982 if (!m_in_b_handler.isnull())
983 throw emu_fatalerror("pia6821_device::portb_w() called when in_b_func implemented");
984
985 LOG("Set PIA input port B = %02X\n", data);
986
987 m_in_b = data;
988 m_in_b_pushed = true;
989 }
990
991
992 //-------------------------------------------------
993 // write_portb_line
994 //-------------------------------------------------
995
write_portb_line(int line,bool state)996 void pia6821_device::write_portb_line(int line, bool state)
997 {
998 const uint8_t mask = 1 << line;
999
1000 if (state)
1001 portb_w(m_in_b | mask);
1002 else
1003 portb_w(m_in_b & ~mask);
1004 }
1005
1006
1007 //-------------------------------------------------
1008 // b_output
1009 //-------------------------------------------------
1010
b_output()1011 uint8_t pia6821_device::b_output()
1012 {
1013 m_out_b_needs_pulled = false;
1014
1015 return get_out_b_value();
1016 }
1017
1018
1019 //-------------------------------------------------
1020 // cb1_w
1021 //-------------------------------------------------
1022
WRITE_LINE_MEMBER(pia6821_device::cb1_w)1023 WRITE_LINE_MEMBER( pia6821_device::cb1_w )
1024 {
1025 LOG("Set PIA input CB1 = %d\n", state);
1026
1027 // the new state has caused a transition
1028 if ((m_in_cb1 != state) && ((state && c1_low_to_high(m_ctl_b)) || (!state && c1_high_to_low(m_ctl_b))))
1029 {
1030 LOG("CB1 triggering\n");
1031
1032 // mark the IRQ
1033 m_irq_b1 = 1;
1034
1035 // update externals
1036 update_interrupts();
1037
1038 // If CB2 is configured as a write-strobe output which is reset by a CB1
1039 // transition, this reset will only happen when a read from port B implicitly
1040 // clears the IRQ B1 flag. So we handle the CB2 reset there. Note that this
1041 // is different from what happens with port A.
1042 }
1043
1044 // set the new value for CB1
1045 m_in_cb1 = state;
1046 m_in_cb1_pushed = true;
1047 }
1048
1049
1050 //-------------------------------------------------
1051 // cb2_w
1052 //-------------------------------------------------
1053
WRITE_LINE_MEMBER(pia6821_device::cb2_w)1054 WRITE_LINE_MEMBER( pia6821_device::cb2_w )
1055 {
1056 LOG("Set PIA input CB2 = %d\n", state);
1057
1058 // if input mode and the new state has caused a transition
1059 if (c2_input(m_ctl_b) &&
1060 (m_in_cb2 != state) &&
1061 ((state && c2_low_to_high(m_ctl_b)) || (!state && c2_high_to_low(m_ctl_b))))
1062 {
1063 LOG("CB2 triggering\n");
1064
1065 // mark the IRQ
1066 m_irq_b2 = 1;
1067
1068 // update externals
1069 update_interrupts();
1070 }
1071
1072 // set the new value for CA2
1073 m_in_cb2 = state;
1074 m_in_cb2_pushed = true;
1075 }
1076
1077
1078 //-------------------------------------------------
1079 // output_cb2
1080 //-------------------------------------------------
1081
cb2_output()1082 bool pia6821_device::cb2_output()
1083 {
1084 m_out_cb2_needs_pulled = false;
1085
1086 return m_out_cb2;
1087 }
1088
1089
1090 //-------------------------------------------------
1091 // cb2_output_z
1092 //-------------------------------------------------
1093
cb2_output_z()1094 bool pia6821_device::cb2_output_z()
1095 {
1096 return !c2_output(m_ctl_b);
1097 }
1098
1099
1100 //-------------------------------------------------
1101 // control byte wrappers
1102 //-------------------------------------------------
1103
irq1_enabled(uint8_t c)1104 inline bool pia6821_device::irq1_enabled(uint8_t c) { return bool(BIT(c, 0)); }
c1_low_to_high(uint8_t c)1105 inline bool pia6821_device::c1_low_to_high(uint8_t c) { return bool(BIT(c, 1)); }
c1_high_to_low(uint8_t c)1106 inline bool pia6821_device::c1_high_to_low(uint8_t c) { return !bool(BIT(c, 1)); }
output_selected(uint8_t c)1107 inline bool pia6821_device::output_selected(uint8_t c) { return bool(BIT(c, 2)); }
irq2_enabled(uint8_t c)1108 inline bool pia6821_device::irq2_enabled(uint8_t c) { return bool(BIT(c, 3)); }
strobe_e_reset(uint8_t c)1109 inline bool pia6821_device::strobe_e_reset(uint8_t c) { return bool(BIT(c, 3)); }
strobe_c1_reset(uint8_t c)1110 inline bool pia6821_device::strobe_c1_reset(uint8_t c) { return !bool(BIT(c, 3)); }
c2_set(uint8_t c)1111 inline bool pia6821_device::c2_set(uint8_t c) { return bool(BIT(c, 3)); }
c2_low_to_high(uint8_t c)1112 inline bool pia6821_device::c2_low_to_high(uint8_t c) { return bool(BIT(c, 4)); }
c2_high_to_low(uint8_t c)1113 inline bool pia6821_device::c2_high_to_low(uint8_t c) { return !bool(BIT(c, 4)); }
c2_set_mode(uint8_t c)1114 inline bool pia6821_device::c2_set_mode(uint8_t c) { return bool(BIT(c, 4)); }
c2_strobe_mode(uint8_t c)1115 inline bool pia6821_device::c2_strobe_mode(uint8_t c) { return !bool(BIT(c, 4)); }
c2_output(uint8_t c)1116 inline bool pia6821_device::c2_output(uint8_t c) { return bool(BIT(c, 5)); }
c2_input(uint8_t c)1117 inline bool pia6821_device::c2_input(uint8_t c) { return !bool(BIT(c, 5)); }
1118