--- /dev/null
+//
+// Virtual 6821 Peripheral Interface Adapter (PIA) Emulator v1.0
+//
+// by James Hammons
+// (C) 2022 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// WHO WHEN WHAT
+// --- ---------- ------------------------------------------------------------
+// JLH 12/27/2022 Created this file. :-)
+
+#include "v6821.h"
+
+//#include "log.h"
+//#include "v6809.h"
+
+// A "1" bit in the DDR means that line is an output
+
+V6821PIA::V6821PIA(): ddra(0), ddrb(0), pa(0), pb(0), cra(0), crb(0), ora(0), orb(0), ca1(false), ca2(false), cb1(false), cb2(false), irqa1(false), irqa2(false), irqb1(false), irqb2(false), irqaState(false), irqbState(false), IRQA(NULL), IRQB(NULL)
+{
+}
+
+V6821PIA::V6821PIA(void (* a)(bool), void (*b)(bool)): ddra(0), ddrb(0), pa(0), pb(0), cra(0), crb(0), ora(0), orb(0), ca1(false), ca2(false), cb1(false), cb2(false), irqa1(false), irqa2(false), irqb1(false), irqb2(false), irqaState(false), irqbState(false), IRQA(a), IRQB(b)
+{
+}
+
+void V6821PIA::Reset(void)
+{
+}
+
+uint8_t V6821PIA::Read(uint8_t addr)
+{
+ switch (addr & 0x03)
+ {
+ case 0:
+ if (cra & 0x04)
+ {
+ // IRQ flags are implicitly cleared by a read
+ irqa1 = irqa2 = false;
+ HandleIRQs();
+
+ return pa & ~ddra;
+ }
+
+ return ddra;
+
+ case 1:
+ return cra | (irqa1 ? 0x80 : 0x00) | (irqa2 ? 0x40 : 0x00);
+
+ case 2:
+ if (crb & 0x04)
+ {
+ // IRQ flags are implicitly cleared by a read
+ irqb1 = irqb2 = false;
+ HandleIRQs();
+
+ return pb & ~ddrb;
+ }
+
+ return ddrb;
+
+ case 3:
+ return crb | (irqb1 ? 0x80 : 0x00) | (irqb2 ? 0x40 : 0x00);
+ }
+
+ // This is only here to silence the the compiler... :-/
+ return 0xFF;
+}
+
+void V6821PIA::Write(uint8_t addr, uint8_t data)
+{
+ switch (addr & 0x03)
+ {
+ case 0:
+ if (cra & 0x04)
+ pa = data;
+ else
+ ddra = data;
+
+ break;
+
+ case 1:
+ cra = data & 0x3F; // Bits 6-7 are RO
+ HandleIRQs();
+ break;
+
+ case 2:
+ if (crb & 0x04)
+ pb = data;
+ else
+ ddrb = data;
+
+ break;
+
+ case 3:
+ crb = data & 0x3F; // Bits 6-7 are RO
+ HandleIRQs();
+ }
+}
+
+void V6821PIA::CA1(bool state)
+{
+ // Do nothing if nothing changed...
+ if (ca1 == state)
+ return;
+
+ // Check if there's been a transition (bit 1 = lo to hi transition)
+ if ((state && (cra & 0x02)) || (!state && !(cra & 0x02)))
+ {
+ irqa1 = true;
+ HandleIRQs();
+ }
+
+ ca1 = state;
+}
+
+void V6821PIA::CA2(bool state)
+{
+ ca2 = state;
+}
+
+void V6821PIA::CB1(bool state)
+{
+ // Do nothing if nothing changed...
+ if (cb1 == state)
+ return;
+
+ // Check if there's been a transition (bit 1 = lo to hi transition)
+ if ((state && (crb & 0x02)) || (!state && !(crb & 0x02)))
+ {
+ irqb1 = true;
+ HandleIRQs();
+ }
+
+ cb1 = state;
+}
+
+void V6821PIA::CB2(bool state)
+{
+ cb2 = state;
+}
+
+void V6821PIA::HandleIRQs(void)
+{
+ bool newState = (irqa1 && (cra & 0x01)) || (irqa2 && (cra & 0x08));
+
+ if (newState != irqaState)
+ {
+ irqaState = newState;
+
+ if (IRQA)
+ IRQA(irqaState);
+ }
+
+ newState = (irqb1 && (crb & 0x01)) || (irqb2 && (crb & 0x08));
+
+ if (newState != irqbState)
+ {
+ irqbState = newState;
+
+ if (IRQB)
+ IRQB(irqbState);
+ }
+}