]> Shamusworld >> Repos - apple2/blobdiff - src/mmu.cpp
Added Apple II/IIe firmware, fixed HD write emulation.
[apple2] / src / mmu.cpp
index 653eac9eeb61e392da8d1255faa6e5a652b5a126..c1ca98acef77af3ae5024340de9acc746cb8f198 100644 (file)
 
 #include "mmu.h"
 #include "apple2.h"
-#include "ay8910.h"
-#include "firmware.h"
+#include "firmware/firmware.h"
 #include "log.h"
-#include "mos6522via.h"
+#include "mockingboard.h"
 #include "sound.h"
 #include "video.h"
 
 // Address Map enumeration
 enum { AM_RAM, AM_ROM, AM_BANKED, AM_READ, AM_WRITE, AM_READ_WRITE, AM_END_OF_LIST };
 
-// Macros for function pointers
-#define READFUNC(x) uint8_t (* x)(uint16_t)
-#define WRITEFUNC(x) void (* x)(uint16_t, uint8_t)
-
 // Internal vars
 uint8_t ** addrPtrRead[0x10000];
 uint8_t ** addrPtrWrite[0x10000];
@@ -39,6 +34,14 @@ uint16_t addrOffset[0x10000];
 READFUNC(funcMapRead[0x10000]);
 WRITEFUNC(funcMapWrite[0x10000]);
 
+READFUNC(slotHandlerR[8]);
+WRITEFUNC(slotHandlerW[8]);
+
+READFUNC(slotHandler2KR[8]);
+WRITEFUNC(slotHandler2KW[8]);
+
+uint8_t enabledSlot;
+
 struct AddressMap
 {
        uint16_t start;
@@ -69,7 +72,8 @@ uint8_t * mainMemoryTextW = &ram[0x0400];     // $0400 - $07FF (write)
 uint8_t * mainMemoryHGRR  = &ram[0x2000];      // $2000 - $3FFF (read)
 uint8_t * mainMemoryHGRW  = &ram[0x2000];      // $2000 - $3FFF (write)
 
-uint8_t * slotMemory      = &rom[0xC100];      // $C100 - $CFFF
+uint8_t * slotMemory      = &rom[0xC100];      // $C100 - $C7FF
+uint8_t * peripheralMemory= &rom[0xC800];      // $C800 - $CFFF
 uint8_t * slot3Memory     = &rom[0xC300];      // $C300 - $C3FF
 uint8_t * slot4Memory     = &rom[0xC400];      // $C400 - $C4FF
 uint8_t * slot6Memory     = &diskROM[0];       // $C600 - $C6FF
@@ -84,6 +88,10 @@ uint8_t ReadNOP(uint16_t);
 void WriteNOP(uint16_t, uint8_t);
 uint8_t ReadMemory(uint16_t);
 void WriteMemory(uint16_t, uint8_t);
+uint8_t SlotR(uint16_t address);
+void SlotW(uint16_t address, uint8_t byte);
+uint8_t Slot2KR(uint16_t address);
+void Slot2KW(uint16_t address, uint8_t byte);
 uint8_t ReadKeyboard(uint16_t);
 void Switch80STORE(uint16_t, uint8_t);
 void SwitchRAMRD(uint16_t, uint8_t);
@@ -91,6 +99,8 @@ void SwitchRAMWRT(uint16_t, uint8_t);
 void SwitchSLOTCXROM(uint16_t, uint8_t);
 void SwitchALTZP(uint16_t, uint8_t);
 void SwitchSLOTC3ROM(uint16_t, uint8_t);
+uint8_t SwitchINTC8ROMR(uint16_t);
+void SwitchINTC8ROMW(uint16_t, uint8_t);
 void Switch80COL(uint16_t, uint8_t);
 void SwitchALTCHARSET(uint16_t, uint8_t);
 uint8_t ReadKeyStrobe(uint16_t);
@@ -126,19 +136,11 @@ void SwitchHIRESW(uint16_t, uint8_t);
 uint8_t SwitchDHIRESR(uint16_t);
 void SwitchDHIRESW(uint16_t, uint8_t);
 void SwitchIOUDIS(uint16_t, uint8_t);
-uint8_t Slot6R(uint16_t);
-void Slot6W(uint16_t, uint8_t);
-void HandleSlot6(uint16_t, uint8_t);
-uint8_t MBRead(uint16_t);
-void MBWrite(uint16_t, uint8_t);
 uint8_t ReadButton0(uint16_t);
 uint8_t ReadButton1(uint16_t);
 uint8_t ReadPaddle0(uint16_t);
 uint8_t ReadIOUDIS(uint16_t);
 uint8_t ReadDHIRES(uint16_t);
-uint8_t ReadFloatingBus(uint16_t);
-//uint8_t SwitchR(uint16_t);
-//void SwitchW(uint16_t, uint8_t);
 
 
 // The main Apple //e memory map
@@ -191,22 +193,42 @@ AddressMap memoryMap[] = {
        { 0xC061, 0xC061, AM_READ, 0, 0, ReadButton0, 0 },
        { 0xC062, 0xC062, AM_READ, 0, 0, ReadButton1, 0 },
        { 0xC064, 0xC067, AM_READ, 0, 0, ReadPaddle0, 0 },
-//     { 0xC07E, 0xC07F, AM_READ_WRITE, 0, 0, SwitchIOUDISR, SwitchIOUDISW },
        { 0xC07E, 0xC07E, AM_READ_WRITE, 0, 0, ReadIOUDIS, SwitchIOUDIS },
        { 0xC07F, 0xC07F, AM_READ_WRITE, 0, 0, ReadDHIRES, SwitchIOUDIS },
        { 0xC080, 0xC08F, AM_READ_WRITE, 0, 0, SwitchLCR, SwitchLCW },
-       { 0xC0E0, 0xC0EF, AM_READ_WRITE, 0, 0, Slot6R, Slot6W },
-       { 0xC100, 0xCFFF, AM_ROM, &slotMemory, 0, 0, 0 },
 
-       // This will overlay the slotMemory accessors for slot 6 ROM
-       { 0xC300, 0xC3FF, AM_ROM, &slot3Memory, 0, 0, 0 },
-       { 0xC600, 0xC6FF, AM_ROM, &slot6Memory, 0, 0, 0 },
-       { 0xC400, 0xC4FF, AM_READ_WRITE, 0, 0, MBRead, MBWrite },
+       { 0xC100, 0xC7FF, AM_READ_WRITE, 0, 0, SlotR, SlotW },
+       { 0xC800, 0xCFFE, AM_READ_WRITE, 0, 0, Slot2KR, Slot2KW },
+       { 0xCFFF, 0xCFFF, AM_READ_WRITE, 0, 0, SwitchINTC8ROMR, SwitchINTC8ROMW },
 
        { 0xD000, 0xDFFF, AM_BANKED, &lcBankMemoryR, &lcBankMemoryW, 0, 0 },
        { 0xE000, 0xFFFF, AM_BANKED, &upperMemoryR, &upperMemoryW, 0, 0 },
        ADDRESS_MAP_END
 };
+/*
+Some stuff that may be useful:
+
+N.B.: Page 5-22 of UTA2E has INTC8ROM ON/OFF backwards
+INTC8ROM is turned OFF by R/W access to $CFFF
+INTC8ROM is turned ON by $C3xx access and SLOTC3ROM' (off)
+WRONG: (INTC8ROM on puts card's slot ROM/RAM(?) access in $C800-$CFFF)
+
+OK, so it's slightly more complex than that.  Basically, when there is an access to $CFFF, all peripheral cards must *stop* responding to  I/O STROBE'.  Only when a card gets an I/O SELECT' signal, can it respond to I/O STROBE'.
+
+INTC8ROM inhibits I/O STROBE' and activates the MB ROM in $C800-$CFFF
+INTC8ROM is 1 by access to $C3xx when SLOTC3ROM is 0
+INTC8ROM is 0 by access to $CFFF
+
+ICX = INTCXROM (aka SLOTCXROM), SC3 = SLOTC3ROM
+
+             ICX=0,SC3=0  ICX=0,SC3=1  ICX=1,SC3=0  ICX=1,SC3=1
+$C100-$C2FF   slot         slot         internal     internal
+$C300-$C3FF   internal     slot         internal     internal
+$C400-$CFFF   slot         slot         internal     internal
+
+Read from $C800-$CFFF causes I/O STROBE to go low (and INTCXROM and INTC8ROM are not set)
+
+*/
 
 
 void SetupAddressMap(void)
@@ -220,6 +242,14 @@ void SetupAddressMap(void)
                addrOffset[i] = 0;
        }
 
+       for(uint32_t i=0; i<8; i++)
+       {
+               slotHandlerR[i] = ReadNOP;
+               slotHandlerW[i] = WriteNOP;
+               slotHandler2KR[i] = ReadNOP;
+               slotHandler2KW[i] = WriteNOP;
+       }
+
        uint32_t i=0;
 
        while (memoryMap[i].type != AM_END_OF_LIST)
@@ -310,10 +340,79 @@ void ResetMMUPointers(void)
        mainMemoryW = (ramwrt ?  &ram2[0x0200] : &ram[0x0200]);
        mainMemoryHGRW = (ramwrt ? &ram2[0x2000] : &ram[0x2000]);
 
-       slot6Memory = (slotCXROM ? &diskROM[0] : &rom[0xC600]);
-       slot3Memory = (slotC3ROM ? &rom[0] : &rom[0xC300]);
+//     slot6Memory = (intCXROM ? &rom[0xC600] : &diskROM[0]);
+//     slot3Memory = (slotC3ROM ? &rom[0] : &rom[0xC300]);
        pageZeroMemory = (altzp ? &ram2[0x0000] : &ram[0x0000]);
        SwitchLC();
+#if 1
+WriteLog("RAMWRT = %s\n", (ramwrt ? "ON" : "off"));
+WriteLog("RAMRD = %s\n", (ramrd ? "ON" : "off"));
+WriteLog("SLOTCXROM = %s\n", (intCXROM ? "ON" : "off"));
+WriteLog("SLOTC3ROM = %s\n", (slotC3ROM ? "ON" : "off"));
+WriteLog("ALTZP = %s\n", (altzp ? "ON" : "off"));
+#endif
+}
+
+
+//
+// Set up slot access
+//
+void InstallSlotHandler(uint8_t slot, SlotData * slotData)
+{
+       // Sanity check
+       if (slot > 7)
+       {
+               WriteLog("InstallSlotHanlder: Caller attempted to put device into slot #%u...\n", slot);
+               return;
+       }
+
+       // Set up I/O read & write functions
+       for(uint32_t i=0; i<16; i++)
+       {
+               if (slotData->ioR)
+                       funcMapRead[0xC080 + (slot * 16) + i] = slotData->ioR;
+
+               if (slotData->ioW)
+                       funcMapWrite[0xC080 + (slot * 16) + i] = slotData->ioW;
+       }
+
+       // Set up memory access read/write functions
+       if (slotData->pageR)
+               slotHandlerR[slot] = slotData->pageR;
+
+       if (slotData->pageW)
+               slotHandlerW[slot] = slotData->pageW;
+
+       if (slotData->extraR)
+               slotHandler2KR[slot] = slotData->extraR;
+
+       if (slotData->extraW)
+               slotHandler2KW[slot] = slotData->extraW;
+/*
+Was thinking about how to make these things more self-contained, so that the management overhead would be less.  IOW, you should be able to make an object (struct) that holds everything needed to interface the MMU with itself--InstallSlotHandler *almost* does this, but not quite.  A consequence of this approach is that we would have to add generic slot I/O handlers into the mix, but that shouldn't be too horrible.  So it could be something like so:
+
+struct Card
+{
+       void * object;
+       uint16_t type;  // Probably an enum so we can figure out what 'object' is
+       READFUNC(slotIOR);
+       WRITEFUNC(slotIOW);
+       READFUNC(slotPageR);
+       WRITEFUNC(slotPageW);
+       READFUNC(slot2KR);
+       WRITEFUNC(slot2KW);
+}
+
+So instead of a bunch of crappy shit that sucks in here, we would have a simple thing like:
+
+Card * slots[8];
+
+to encapsulate slots.  This also makes it easier to move them around and makes things less error prone.
+
+So maybe...
+
+
+*/
 }
 
 
@@ -322,7 +421,13 @@ void ResetMMUPointers(void)
 //
 uint8_t ReadNOP(uint16_t)
 {
-       return 0;
+       // This is for unconnected reads, and some software looks at addresses like
+       // these.  In particular, Mr. Robot and His Robot Factory failed in that it
+       // was looking at the first byte of each slots 256 byte driver space and
+       // failing if it saw a zero there.  Now I have no idea what happens in the
+       // real hardware, but I suspect it would return something that looks like
+       // ReadFloatingBus().
+       return 0xFF;
 }
 
 
@@ -357,16 +462,130 @@ void WriteMemory(uint16_t address, uint8_t byte)
 //
 uint8_t AppleReadMem(uint16_t address)
 {
+#if 0
+if (address == 0xD4 || address == 0xAC20)
+       WriteLog("Reading $%X...\n", address);
+#endif
+#if 0
+       uint8_t memRead = (*(funcMapRead[address]))(address);
+static uint16_t lastAddr = 0;
+static uint32_t lastCount = 0;
+if ((address > 0xC000 && address < 0xC100) || address == 0xC601)
+{
+       if (lastAddr == address)
+               lastCount++;
+       else
+       {
+               if (lastCount > 1)
+                       WriteLog("%d times...\n", lastCount);
+
+               WriteLog("Reading $%02X from $%X ($%02X, $%02X)\n", memRead, address, diskROM[1], rom[0xC601]);
+               lastCount = 1;
+               lastAddr = address;
+       }
+}
+       return memRead;
+#else
        return (*(funcMapRead[address]))(address);
+#endif
 }
 
 
 void AppleWriteMem(uint16_t address, uint8_t byte)
 {
+#if 0
+static uint16_t lastAddr = 0;
+static uint32_t lastCount = 0;
+if ((address > 0xC000 && address < 0xC100) || address == 0xC601)
+{
+       if (lastAddr == address)
+               lastCount++;
+       else
+       {
+               if (lastCount > 1)
+                       WriteLog("%d times...\n", lastCount);
+
+               WriteLog("Writing to $%X\n", address);
+               lastCount = 1;
+               lastAddr = address;
+       }
+}
+#endif
+#if 0
+if (address == 0xD4 || address == 0xAC20)
+       WriteLog("Writing $%02X @ $%X...\n", byte, address);
+#endif
+#if 0
+//if (address >= 0x0827 && address <= 0x082A)
+if (address == 0x000D)
+       WriteLog("Writing $%02X @ $%X (PC=$%04X)...\n", byte, address, mainCPU.pc);
+#endif
        (*(funcMapWrite[address]))(address, byte);
 }
 
 
+//
+// Generic slot handlers.  These are set up here so that we can catch INTCXROM,
+// INTC8ROM & SLOTC3ROM here instead of having to catch them in each slot handler.
+//
+uint8_t SlotR(uint16_t address)
+{
+//WriteLog("SlotR: address=$%04X, intCXROM=%d, slotC3ROM=%d, intC8ROM=%d\n", address, intCXROM, slotC3ROM, intC8ROM);
+       if (intCXROM)
+               return rom[address];
+
+       uint8_t slot = (address & 0xF00) >> 8;
+       enabledSlot = slot;
+
+       if ((slotC3ROM == 0) && (slot == 3))
+       {
+               intC8ROM = 1;
+               return rom[address];
+       }
+
+       return (*(slotHandlerR[slot]))(address & 0xFF);
+}
+
+
+void SlotW(uint16_t address, uint8_t byte)
+{
+       if (intCXROM)
+               return;
+
+       uint8_t slot = (address & 0xF00) >> 8;
+       enabledSlot = slot;
+
+       if ((slotC3ROM == 0) && (slot == 3))
+       {
+               intC8ROM = 1;
+               return;
+       }
+
+       (*(slotHandlerW[slot]))(address & 0xFF, byte);
+}
+
+
+//
+// Slot handling for 2K address space at $C800-$CFFF
+//
+uint8_t Slot2KR(uint16_t address)
+{
+       if (intCXROM || intC8ROM)
+               return rom[address];
+
+       return (*(slotHandler2KR[enabledSlot]))(address & 0x7FF);
+}
+
+
+void Slot2KW(uint16_t address, uint8_t byte)
+{
+       if (intCXROM || intC8ROM)
+               return;
+
+       (*(slotHandler2KW[enabledSlot]))(address & 0x7FF, byte);
+}
+
+
 //
 // Actual emulated I/O functions follow
 //
@@ -420,13 +639,39 @@ void SwitchRAMWRT(uint16_t address, uint8_t)
 }
 
 
+//
+// Since any slots that aren't populated are set to read from the ROM anyway,
+// we only concern ourselves with switching populated slots here.  (Note that
+// the MB slot is a split ROM / I/O device, and it's taken care of in the
+// MB handler.)
+//
+// N.B.: SLOTCXROM is also INTCXROM
+//
 void SwitchSLOTCXROM(uint16_t address, uint8_t)
 {
-//WriteLog("Setting SLOTCXROM to %s...\n", ((address & 0x01) ^ 0x01 ? "ON" : "off"));
-       // This is the only soft switch that breaks the usual convention.
-       slotCXROM = !((bool)(address & 0x01));
-//     slot3Memory = (slotCXROM ? &rom[0] : &rom[0xC300]);
-       slot6Memory = (slotCXROM ? &diskROM[0] : &rom[0xC600]);
+WriteLog("Setting SLOTCXROM to %s...\n", (address & 0x01 ? "ON" : "off"));
+       intCXROM = (bool)(address & 0x01);
+
+       // INTC8ROM trumps all (only in the $C800--$CFFF range... which we don't account for yet...  :-/)
+//     if (intC8ROM)
+//             return;
+#if 0
+#if 1
+       if (intCXROM)
+       {
+               slot3Memory = &rom[0xC300];
+               slot6Memory = &rom[0xC600];
+       }
+       else
+       {
+               slot3Memory = (slotC3ROM ? &rom[0] : &rom[0xC300]);
+               slot6Memory = &diskROM[0];
+       }
+#else
+//     slot3Memory = (intCXROM ? &rom[0xC300] : &rom[0]);
+       slot6Memory = (intCXROM ? &rom[0xC600] : &diskROM[0]);
+#endif
+#endif
 }
 
 
@@ -438,16 +683,54 @@ void SwitchALTZP(uint16_t address, uint8_t)
 }
 
 //extern bool dumpDis;
-
+//
+// The interpretation of this name is that if it's set then we access the ROM
+// for the card actually sitting in SLOT 3 (if any)
+//
 void SwitchSLOTC3ROM(uint16_t address, uint8_t)
 {
 //dumpDis = true;
 //WriteLog("Setting SLOTC3ROM to %s...\n", (address & 0x01 ? "ON" : "off"));
        slotC3ROM = (bool)(address & 0x01);
+#if 1
+       if (intCXROM)
+               slot3Memory = &rom[0xC300];
+       else
+               slot3Memory = (slotC3ROM ? &rom[0] : &rom[0xC300]);
+#else
 //     slotC3ROM = false;
 // Seems the h/w forces this with an 80 column card in slot 3...
        slot3Memory = (slotC3ROM ? &rom[0] : &rom[0xC300]);
 //     slot3Memory = &rom[0xC300];
+#endif
+}
+
+
+/*
+We need to see where this is being switched from; if we know that, we can switch in the appropriate ROM to $C800-$CFFF.  N.B.: Will probably need a custom handler routine, as some cards (like the Apple Hi-Speed SCSI card) split the 2K range into a 1K RAM space and a 1K bank switch ROM space.
+*/
+//
+// This is a problem with split ROM / I/O regions.  Because we can't do that
+// cleanly, we have to have a read handler for this.
+//
+// N.B.: We could add AM_IOREAD_WRITE and AM_READ_IOWRITE to the memory handlers
+//       to take care of split ROM / I/O regions...
+//
+uint8_t SwitchINTC8ROMR(uint16_t)
+{
+WriteLog("Hitting INTC8ROM (read)...\n");
+       intC8ROM = false;
+       return rom[0xCFFF];
+}
+
+
+//
+// This resets the INTC8ROM switch (RW)
+//
+void SwitchINTC8ROMW(uint16_t, uint8_t)
+{
+WriteLog("Hitting INTC8ROM (write)...\n");
+       intC8ROM = false;
 }
 
 
@@ -460,13 +743,14 @@ void Switch80COL(uint16_t address, uint8_t)
 void SwitchALTCHARSET(uint16_t address, uint8_t)
 {
        alternateCharset = (bool)(address & 0x01);
+WriteLog("Setting ALTCHARSET to %s...\n", (alternateCharset ? "ON" : "off"));
 }
 
 
 uint8_t ReadKeyStrobe(uint16_t)
 {
-// No character data is read from here, just the 'any key was pressed' signal...
-//     uint8_t byte = lastKeyPressed | ((uint8_t)keyDown << 7);
+       // No character data is read from here, just the 'any key was pressed'
+       // signal...
        uint8_t byte = (uint8_t)keyDown << 7;
        keyDown = false;
        return byte;
@@ -501,7 +785,7 @@ uint8_t ReadRAMWRT(uint16_t)
 
 uint8_t ReadSLOTCXROM(uint16_t)
 {
-       return (uint8_t)slotCXROM << 7;
+       return (uint8_t)intCXROM << 7;
 }
 
 
@@ -513,7 +797,6 @@ uint8_t ReadALTZP(uint16_t)
 
 uint8_t ReadSLOTC3ROM(uint16_t)
 {
-//     return 0;
        return (uint8_t)slotC3ROM << 7;
 }
 
@@ -774,300 +1057,6 @@ void SwitchIOUDIS(uint16_t address, uint8_t)
 }
 
 
-uint8_t Slot6R(uint16_t address)
-{
-//WriteLog("Slot6R: address = %X\n", address & 0x0F);
-//     HandleSlot6(address, 0);
-//     return 0;
-       uint8_t state = address & 0x0F;
-
-       switch (state)
-       {
-       case 0x00:
-       case 0x01:
-       case 0x02:
-       case 0x03:
-       case 0x04:
-       case 0x05:
-       case 0x06:
-       case 0x07:
-               floppyDrive.ControlStepper(state);
-               break;
-       case 0x08:
-       case 0x09:
-               floppyDrive.ControlMotor(state & 0x01);
-               break;
-       case 0x0A:
-       case 0x0B:
-               floppyDrive.DriveEnable(state & 0x01);
-               break;
-       case 0x0C:
-               return floppyDrive.ReadWrite();
-               break;
-       case 0x0D:
-               return floppyDrive.GetLatchValue();
-               break;
-       case 0x0E:
-               floppyDrive.SetReadMode();
-               break;
-       case 0x0F:
-               floppyDrive.SetWriteMode();
-               break;
-       }
-
-       return 0;
-}
-
-
-void Slot6W(uint16_t address, uint8_t byte)
-{
-//WriteLog("Slot6W: address = %X, byte= %X\n", address & 0x0F, byte);
-//     HandleSlot6(address, byte);
-       uint8_t state = address & 0x0F;
-
-       switch (state)
-       {
-       case 0x00:
-       case 0x01:
-       case 0x02:
-       case 0x03:
-       case 0x04:
-       case 0x05:
-       case 0x06:
-       case 0x07:
-               floppyDrive.ControlStepper(state);
-               break;
-       case 0x08:
-       case 0x09:
-               floppyDrive.ControlMotor(state & 0x01);
-               break;
-       case 0x0A:
-       case 0x0B:
-               floppyDrive.DriveEnable(state & 0x01);
-               break;
-       case 0x0C:
-               floppyDrive.ReadWrite();
-               break;
-       case 0x0D:
-               floppyDrive.SetLatchValue(byte);
-               break;
-       case 0x0E:
-               floppyDrive.SetReadMode();
-               break;
-       case 0x0F:
-               floppyDrive.SetWriteMode();
-               break;
-       }
-}
-
-
-void HandleSlot6(uint16_t address, uint8_t byte)
-{
-}
-
-
-uint8_t MBRead(uint16_t address)
-{
-#if 1
-       // Not sure [Seems to work OK]
-       if (!slotCXROM)
-       {
-               return slot4Memory[address & 0x00FF];
-       }
-#endif
-
-       uint8_t regNum = address & 0x0F;
-       uint8_t chipNum = (address & 0x80) >> 7;
-
-#if 0
-       WriteLog("MBRead: address = %X [chip %d, reg %X, clock=$%X]\n", address & 0xFF, chipNum, regNum, GetCurrentV65C02Clock());
-#endif
-
-       switch (regNum)
-       {
-       case 0x00:
-               return mbvia[chipNum].orb & mbvia[chipNum].ddrb;
-
-       case 0x01:
-               return mbvia[chipNum].ora & mbvia[chipNum].ddra;
-
-       case 0x02:
-               return mbvia[chipNum].ddrb;
-
-       case 0x03:
-               return mbvia[chipNum].ddra;
-
-       case 0x04:
-               return mbvia[chipNum].timer1counter & 0xFF;
-
-       case 0x05:
-               return (mbvia[chipNum].timer1counter & 0xFF00) >> 8;
-
-       case 0x06:
-               return mbvia[chipNum].timer1latch & 0xFF;
-
-       case 0x07:
-               return (mbvia[chipNum].timer1latch & 0xFF00) >> 8;
-
-       case 0x08:
-               return mbvia[chipNum].timer2counter & 0xFF;
-
-       case 0x09:
-               return (mbvia[chipNum].timer2counter & 0xFF00) >> 8;
-
-       case 0x0B:
-               return mbvia[chipNum].acr;
-
-       case 0x0D:
-               return (mbvia[chipNum].ifr & 0x7F)
-                       | (mbvia[chipNum].ifr & 0x7F ? 0x80 : 0);
-
-       case 0x0E:
-               return mbvia[chipNum].ier | 0x80;
-
-       default:
-               WriteLog("Unhandled 6522 register %X read (chip %d)\n", regNum, chipNum);
-       }
-
-       return 0;
-}
-
-
-static uint8_t regLatch[2];
-void MBWrite(uint16_t address, uint8_t byte)
-{
-       uint8_t regNum = address & 0x0F;
-       uint8_t chipNum = (address & 0x80) >> 7;
-/*
-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
-
-Register  Function
---------  -------------------------
-0         Output Register B
-1         Output Register A
-2         Data Direction Register B
-3         Data Direction Register A
-4         Timer 1 Low byte counter (& latch)
-5         Timer 1 Hgh byte counter (& latch)
-6         Timer 1 Low byte latch
-7         Timer 1 Hgh byte latch (& reset IRQ flag)
-B         Aux Control Register
-D         Interrupt Flag Register
-E         Interrupt Enable Register
-
-bit 6 of ACR is like so:
-0: Timed interrupt each time Timer 1 is loaded
-1: Continuous interrupts
-
-bit 7 enables PB7 (bit 6 controls output type):
-0: One shot output
-1: Square wave output
-
-
-*/
-#if 0
-       WriteLog("MBWrite: address = %X, byte= %X [clock=$%X]", address & 0xFF, byte, GetCurrentV65C02Clock());
-
-       if (regNum == 0)
-               WriteLog("[OUTB -> %s%s%s]\n", (byte & 0x01 ? "BC1" : ""), (byte & 0x02 ? " BDIR" : ""), (byte & 0x04 ? " RST'" : ""));
-       else if (regNum == 1)
-               WriteLog("[OUTA -> %02X]\n", byte);
-       else if (regNum == 2)
-               WriteLog("[DDRB -> %02X]\n", byte);
-       else if (regNum == 3)
-               WriteLog("[DDRA -> %02X]\n", byte);
-       else
-               WriteLog("\n");
-#endif
-
-       switch (regNum)
-       {
-       case 0x00:
-               // Control of the AY-3-8912 is thru this port pretty much...
-               mbvia[chipNum].orb = byte;
-
-               if ((byte & 0x04) == 0)
-#ifdef USE_NEW_AY8910
-                       AYReset(chipNum);
-#else
-                       AY8910_reset(chipNum);
-#endif
-               else if ((byte & 0x03) == 0x03)
-                       regLatch[chipNum] = mbvia[chipNum].ora;
-               else if ((byte & 0x03) == 0x02)
-#ifdef USE_NEW_AY8910
-                       AYWrite(chipNum, regLatch[chipNum], mbvia[chipNum].ora);
-#else
-                       _AYWriteReg(chipNum, regLatch[chipNum], mbvia[chipNum].ora);
-#endif
-
-               break;
-
-       case 0x01:
-               mbvia[chipNum].ora = byte;
-               break;
-
-       case 0x02:
-               mbvia[chipNum].ddrb = byte;
-               break;
-
-       case 0x03:
-               mbvia[chipNum].ddra = byte;
-               break;
-
-       case 0x04:
-               mbvia[chipNum].timer1latch = (mbvia[chipNum].timer1latch & 0xFF00)
-                       | byte;
-               break;
-
-       case 0x05:
-               mbvia[chipNum].timer1latch = (mbvia[chipNum].timer1latch & 0x00FF)
-                       | (((uint16_t)byte) << 8);
-               mbvia[chipNum].timer1counter = mbvia[chipNum].timer1latch;
-               mbvia[chipNum].ifr &= 0x3F; // Clear T1 interrupt flag
-               break;
-
-       case 0x06:
-               mbvia[chipNum].timer1latch = (mbvia[chipNum].timer1latch & 0xFF00)
-                       | byte;
-               break;
-
-       case 0x07:
-               mbvia[chipNum].timer1latch = (mbvia[chipNum].timer1latch & 0x00FF)
-                       | (((uint16_t)byte) << 8);
-               mbvia[chipNum].ifr &= 0x3F; // Clear T1 interrupt flag
-               break;
-
-       case 0x0B:
-               mbvia[chipNum].acr = byte;
-               break;
-
-       case 0x0D:
-               mbvia[chipNum].ifr &= ~byte;
-               break;
-
-       case 0x0E:
-               if (byte & 0x80)
-                       // Setting bits in the IER
-                       mbvia[chipNum].ier |= byte;
-               else
-                       // Clearing bits in the IER
-                       mbvia[chipNum].ier &= ~byte;
-
-               break;
-       default:
-               WriteLog("Unhandled 6522 register $%X write $%02X (chip %d)\n", regNum, byte, chipNum);
-       }
-}
-
-
 uint8_t ReadButton0(uint16_t)
 {
        return (uint8_t)openAppleDown << 7;