]> Shamusworld >> Repos - stargem2/blobdiff - src/v6821.cpp
Finally fixed problems with demo mode.
[stargem2] / src / v6821.cpp
diff --git a/src/v6821.cpp b/src/v6821.cpp
new file mode 100644 (file)
index 0000000..0476bee
--- /dev/null
@@ -0,0 +1,165 @@
+//
+// 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);
+       }
+}