--- /dev/null
+//
+// Mockingboard support
+//
+// by James Hammons
+// (C) 2018 Underground Software
+//
+// NOTES:
+// bit 7 = L/R channel select (AY chip 1 versus AY chip 2)
+// 0 = Left, 1 = Right
+//
+// Reg. B is connected to BC1, BDIR, RST' (bits 0, 1, 2)
+//
+// Left VIA IRQ line is tied to 6502 IRQ line
+// Rght VIA IRQ line is tied to 6502 NMI line
+//
+
+
+#include "mockingboard.h"
+#include "apple2.h"
+#include "mmu.h"
+
+
+MOCKINGBOARD mb[2];
+
+
+void MBReset(void)
+{
+ mb[0].via[0].Reset();
+ mb[0].via[1].Reset();
+ mb[0].ay[0].Reset();
+ mb[0].ay[1].Reset();
+}
+
+
+void MBWrite(int chipNum, uint8_t reg, uint8_t byte)
+{
+ V6522VIA * chip1 = &mb[0].via[chipNum];
+ chip1->Write(reg, byte);
+
+ if (reg == 0)
+ mb[0].ay[chipNum].WriteControl(chip1->orb & chip1->ddrb);
+ else if (reg == 1)
+ mb[0].ay[chipNum].WriteData(chip1->ora & chip1->ddra);
+}
+
+
+uint8_t MBRead(int chipNum, uint8_t reg)
+{
+ return mb[0].via[chipNum].Read(reg);
+}
+
+
+void MBRun(uint16_t cycles)
+{
+ if (mb[0].via[0].Run(cycles))
+ mainCPU.cpuFlags |= V65C02_ASSERT_LINE_IRQ;
+
+ if (mb[0].via[1].Run(cycles))
+ mainCPU.cpuFlags |= V65C02_ASSERT_LINE_NMI;
+}
+
+
+void MBSaveState(FILE * file)
+{
+ fwrite(&mb[0], 1, sizeof(struct MOCKINGBOARD), file);
+ fwrite(&mb[1], 1, sizeof(struct MOCKINGBOARD), file);
+}
+
+
+void MBLoadState(FILE * file)
+{
+ fread(&mb[0], 1, sizeof(struct MOCKINGBOARD), file);
+ fread(&mb[1], 1, sizeof(struct MOCKINGBOARD), file);
+}
+
+
+static uint8_t SlotPageR(uint16_t address)
+{
+ uint8_t regNum = address & 0x0F;
+ uint8_t chipNum = (address & 0x80) >> 7;
+
+ return MBRead(chipNum, regNum);
+}
+
+
+static void SlotPageW(uint16_t address, uint8_t byte)
+{
+ uint8_t regNum = address & 0x0F;
+ uint8_t chipNum = (address & 0x80) >> 7;
+
+ MBWrite(chipNum, regNum, byte);
+}
+
+
+void InstallMockingboard(uint8_t slot)
+{
+ SlotData mbDevice = { 0, 0, SlotPageR, SlotPageW, 0, 0 };
+ InstallSlotHandler(slot, &mbDevice);
+}
+