]> Shamusworld >> Repos - stargem2/blobdiff - src/stargem2.cpp
Virtual 6809 is close to being 100% at this point; at least StarGem works
[stargem2] / src / stargem2.cpp
index ee1b814df06f51fcf20a007d67fb3845c7832ab3..107f8dbf241c13caab09edaff25b0b3f29de71e4 100755 (executable)
@@ -10,6 +10,7 @@
 // ---  ----------  ------------------------------------------------------------
 // JLH  06/15/2006  Added changelog ;-)
 // JLH  06/15/2006  Switched over to timeslice execution code
+// JLH  07/15/2009  Solved problem with DEMO mode (IRQ handling)
 //
 
 #include "SDL.h"
 #include "dis6809.h"
 #include "dis6808.h"
 
+//#define __DEBUG__
+//#define LOG_PIA1_IO
+
 using namespace std;
 
-#define ROM1           "01"
-#define ROM2           "02"
-#define ROM3           "03"
-#define ROM4           "04"
-#define ROM5           "05"
-#define ROM6           "06"
-#define ROM7           "07"
-#define ROM8           "08"
-#define ROM9           "09"
-#define ROM10          "10"
-#define ROM11          "11"
-#define ROM12          "12"
-#define SOUNDROM       "sg.snd"
+#define SOUNDROM       "ROMs/sg.snd"
 #define CMOS           "cmos.ram"
 #define SAVESTATE      "sg2.state"
 
+#define FRAME_DURATION_IN_CYCLES               (M6809_CLOCK_SPEED_IN_HZ / 60.0)
+#define SCANLINE_DURATION_IN_CYCLES            (FRAME_DURATION_IN_CYCLES / 256.0)
+// Interesting... This (1/16) causes the machine to crash in the demo (if run from clean start, otherwise it FUs demo)!
+// (1/32) fucks up the demo...
+// (1/64) works. Weird!
+//1/64 no more... but 1/128, 1/32 and 1/16 don't work either!
+//#define SG2_PIA_CALLBACK_DURATION            ((FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC) / 16.0)
+#define SG2_PIA_CALLBACK_DURATION              ((FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC) / 64.0)
+
 // Global variables
 
-uint8 * gram, * grom, * sram, * srom;                  // RAM & ROM pointers
+uint8 gram[0x10000], grom[0x10000], sram[0x10000], srom[0x10000]; // RAM & ROM spaces
 V6809REGS mainCPU;
 V6808REGS soundCPU;
 uint8 color[16];
 uint32 palette[256];
+bool paletteDirty = false;
 
 // Local variables
 
-//static uint8 lastKeyPressed = 0;
-//static bool keyDown = false;
-
-//static FloppyDrive floppyDrive;
-
-//enum { LC_BANK_1, LC_BANK_2 };
-
-//static uint8 visibleBank = LC_BANK_1;
-//static bool readRAM = false;
-//static bool writeRAM = false;
-
 static bool running = true;                                            // Machine running state flag...
 static uint32 startTicks;
 static uint8 * keys;                                                   // SDL raw keyboard matrix
+static uint64 clockFrameStart;                                 // V6809 clock at the start of the frame
+
+// Function prototypes
+
+uint8 RdMem6809(uint16 addr);
+void WrMem6809(uint16 addr, uint8 b);
+uint8 RdMem6808(uint16 addr);
+void WrMem6808(uint16 addr, uint8 b);
+bool LoadImg(const char * filename, uint8 * ram, int size);
+void SaveCMOS(void);
+bool LoadMachineState(void);
+void SaveMachineState(void);
 
 // Local timer callback functions
 
@@ -81,133 +84,155 @@ static void ScanlineCallback(void);
 
 
 //
-// 6809 memory functions
+// Main loop
 //
-
-uint8 RdMem6809(uint16 addr)
+int main(int /*argc*/, char * /*argv*/[])
 {
-       uint8 b;
+       InitLog("stargem2.log");
+       WriteLog("StarGem2 - A portable Stargate emulator by James L. Hammons\n");
+       WriteLog("(C) 2009 Underground Software\n\n");
 
-       if (addr >= 0x9000 && addr <= 0xCFFF)           // No ROM between $9000 - $CFFF...
-               b = gram[addr];
-       else
-       {
-               if (!gram[0xC900] && addr <= 0x8FFF)    // Check RAM $C900 bank switch
-                       b = gram[addr];
-               else
-                       b = grom[addr];
-       }
+       LoadSettings();
 
-//Is $C80E COUNT240? Hmm... No.
+       // Initialize Williams' palette (RGB coded as: 3 bits red, 3 bits green, 2 bits blue)
+       for(uint32 i=0; i<256; i++)
+               palette[i] =
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+               (((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151) << 24)
+                       | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 16)
+                       | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 8) | 0xFF;
+#else
+               ((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151)
+                       | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 8)
+                       | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 16) | 0xFF000000;
+#endif
 
-//temp...
-/*extern uint16 pcr;
-//if (addr >= 0xC000 && addr <= 0xCBFF)
-if (addr == 0x9C59)
-       WriteLog("RdMem: Reading address %04X [=%02X, PC=%04X]\n", addr, b, pcr);//*/
-/*if (addr >= 0xC80D && addr <= 0xC80F)
-       WriteLog("V6809 RdMem: Reading address %04X [=%02X, PC=%04X]\n", addr, b, mainCPU.pc);//*/
+       // Zero out memory
+       memset(gram, 0, 0x10000);
+       memset(grom, 0, 0x10000);
+       memset(sram, 0, 0x10000);
+       memset(srom, 0, 0x10000);
 
-       return b;
-}
+       // Set up V6809 & V6808 execution contexts
 
-void WrMem6809(uint16 addr, uint8 b)
-{
-//temp...
-//extern V6809REGS regs;
-//if (addr >= 0xC800 && addr <= 0xCBFE)
-//if (addr == 0xC80F || addr == 0xC80D)
-//     WriteLog("WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, regs.pc, gram[0xCB00]);//*/
-//if (addr == 0xC80E)
-/*if (addr >= 0xC800 && addr <= 0xC80F)
-       WriteLog("V6809 WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, mainCPU.pc, gram[0xCB00]);//*/
+       memset(&mainCPU, 0, sizeof(V6809REGS));
+       mainCPU.RdMem = RdMem6809;
+       mainCPU.WrMem = WrMem6809;
+       mainCPU.cpuFlags |= V6809_ASSERT_LINE_RESET;
 
-       gram[addr] = b;
+       memset(&soundCPU, 0, sizeof(V6808REGS));
+       soundCPU.RdMem = RdMem6808;
+       soundCPU.WrMem = WrMem6808;
+       soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
 
-       if (addr > 0x0006 && addr < 0x97F7)                     // 304 pixels  152-128=24-16=8
+       char ROMs[12][8] = {
+               "ROMs/01", "ROMs/02", "ROMs/03", "ROMs/04", "ROMs/05", "ROMs/06",
+               "ROMs/07", "ROMs/08", "ROMs/09", "ROMs/10", "ROMs/11", "ROMs/12"
+               };
+
+       for(int i=0; i<12; i++)
        {
-               // NOTE: Screen was 304 x 256, but we truncate the vertical dimension here...
-               uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
+               uint32 baseAddress = i * 0x1000;
 
-               if (sy > 5 && sy < 246)
+               if (i > 8)
+                       baseAddress += 0x4000;
+
+               if (!LoadImg(ROMs[i], grom + baseAddress, 0x1000))
                {
-                       uint32 saddr = 8 + sx + ((sy - 6) * 320);       // Calc screen address
-//Hmm. This approach won't work with palette color cycling...
-#if 0
-                       scrBuffer[saddr + 0] = b >> 4;
-                       scrBuffer[saddr + 1] = b & 0x0F;
-#else
-                       scrBuffer[saddr + 0] = palette[color[b >> 4]];
-                       scrBuffer[saddr + 1] = palette[color[b & 0x0F]];
-#endif
+                       WriteLog("Could not open file '%s'!\n", ROMs[i]);
+                       return -1;
                }
        }
-       else if (addr >= 0xC000 && addr <= 0xC00F)
-//Let's see if we can fix the color cycling here... [DONE]
-#if 0
-               color[addr - 0xC000] = b;                                               // color[] from VIDEO.CPP (not any more!)
-#else
-       {
-// A better strategy here would probably be to set a flag when the color register changes,
-// then change it before doing the render.
-// ALSO: This approach doesn't take the color to the edges of the screen
-               color[addr - 0xC000] = b;
 
-               for(uint32 addr=0x0007; addr<0x97F7; addr++)
-               {
-                       uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
+       if (!LoadImg(SOUNDROM, srom + 0xF800, 0x800))
+       {
+               WriteLog("Could not open file '%s'!\n", SOUNDROM);
+               return -1;
+       }
 
-                       if (sy > 5 && sy < 246)
-                       {
-                               uint32 saddr = 8 + sx + ((sy - 6) * 320);       // Calc screen address
-                               uint8 sb = gram[addr];
+       WriteLog("Stargate ROM images loaded...\n");
+       WriteLog("About to initialize video...\n");
 
-                               scrBuffer[saddr + 0] = palette[color[sb >> 4]];
-                               scrBuffer[saddr + 1] = palette[color[sb & 0x0F]];
-                       }
-               }
+       if (!InitVideo())
+       {
+               cout << "Aborting!" << endl;
+               return -1;
        }
-#endif
-       else if (addr == 0xC80E)
+
+       // Have to do this *after* video init but *before* sound init...!
+       WriteLog("About to load machine state...");
+
+       if (!LoadMachineState())
+               WriteLog("Machine state file not found!\n");
+       else
+               WriteLog("done!\n");
+
+       if (!LoadImg(CMOS, gram + 0xCC00, 0x400))
+               WriteLog("CMOS RAM not found!\n");
+
+       WriteLog("About to intialize audio...\n");
+       SoundInit();
+       keys = SDL_GetKeyState(NULL);
+       srom[0xF800] = 0x37;                                            // Fix checksum so ST works...
+       running = true;                                                         // Set running status...
+
+       InitializeEventList();                                          // Clear the event list before we use it...
+       SetCallbackTime(FrameCallback, FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC);
+       SetCallbackTime(ScanlineCallback, SG2_PIA_CALLBACK_DURATION);
+       clockFrameStart = mainCPU.clock;
+       startTicks = SDL_GetTicks();
+
+       WriteLog("Entering main loop...\n");
+
+       while (running)
        {
-               sram[0x0402] = b;                                                               // Connect PIAs in 6809 & 6808
-               soundCPU.cpuFlags |= V6808_ASSERT_LINE_IRQ;             // Start sound IRQ
+               double timeToNextEvent = GetTimeToNextEvent();
+               Execute6809(&mainCPU, USEC_TO_M6809_CYCLES(timeToNextEvent));
+               HandleNextEvent();
        }
-}
 
-//
-// 6808 memory functions
-//
+#ifdef __DEBUG__
+WriteLog("\n");
+WriteLog("$C900 = $%02X (0=RAM)\n", gram[0xC900]);
+WriteLog("PC: %04X, X: %04X, Y: %04X, S: %04X, U: %04X, A: %02X, B: %02X, DP: %02X, CC: %02X\n", mainCPU.pc, mainCPU.x, mainCPU.y, mainCPU.s, mainCPU.u, mainCPU.a, mainCPU.b, mainCPU.dp, mainCPU.cc);
+WriteLog("\n");
 
-uint8 RdMem6808(uint16 addr)
+/*uint16 pc = mainCPU.pc;//0x15BA;
+for(int i=0; i<200; i++)
+//while (pc < 0x9000)
 {
-       return (addr < 0xF000 ? sram[addr] : srom[addr]);
-}
+       pc += Decode6809(pc);
+       WriteLog("\n");
+}//*/
 
-void WrMem6808(uint16 addr, uint8 b)
+/*uint32 pc = 0;
+while (pc < 0xFFFF)
 {
-       sram[addr] = b;
+       pc += Decode6809(pc);
+       WriteLog("\n");
+}//*/
+#endif
+
+       SoundDone();
+       VideoDone();
+       SaveCMOS();
+       SaveMachineState();
+       LogDone();
+
+       return 0;
 }
 
 //
 // Load a file into RAM/ROM image space
 //
-bool LoadImg(char * filename, uint8 * ram, int size)
+bool LoadImg(const char * filename, uint8 * ram, int size)
 {
-       char pathname[4096];
-
-       strcpy(pathname, settings.BIOSPath);
-       strcat(pathname, filename);
-
-       FILE * fp = fopen(pathname, "rb");
+       FILE * fp = fopen(filename, "rb");
 
        if (fp == NULL)
-       {
-               WriteLog("Could not open file '%s'!\n", pathname);
                return false;
-       }
 
-       fread(ram, 1, size, fp);
+       size_t ignoredResult = fread(ram, 1, size, fp);
        fclose(fp);
 
        return true;
@@ -222,7 +247,7 @@ void SaveCMOS(void)
 
        if (fp != NULL)
        {
-               fwrite(gram + 0xCC00, 1, 1024, fp);
+               size_t ignoredResult = fwrite(gram + 0xCC00, 1, 1024, fp);
                fclose(fp);
        }
        else
@@ -240,19 +265,29 @@ bool LoadMachineState(void)
                return false;
 
        // This is kinda crappy--we don't do any sanity checking here!!!
-       fread(gram, 1, 0x10000, fp);
-       fread(sram, 1, 0x10000, fp);
-       fread(&mainCPU, 1, sizeof(V6809REGS), fp);
-       fread(&soundCPU, 1, sizeof(V6808REGS), fp);
+       size_t ignoredResult = fread(gram, 1, 0x10000, fp);
+       ignoredResult = fread(sram, 1, 0x10000, fp);
+       ignoredResult = fread(&mainCPU, 1, sizeof(V6809REGS), fp);
+       ignoredResult = fread(&soundCPU, 1, sizeof(V6808REGS), fp);
        fclose(fp);
 
-       for(int i=0x0006; i<0x97F8; i++)                                        // Set up backbuffer... ;-)
+       // Set up backbuffer... ;-)
+       for(uint16 i=0x0006; i<0x97F8; i++)                                     // Screen memory
+               WrMem6809(i, gram[i]);
+
+       for(uint16 i=0xC000; i<=0xC00F; i++)                            // Palette memory
                WrMem6809(i, gram[i]);
 
+       paletteDirty = true;
+
        mainCPU.RdMem = RdMem6809;                                                      // Make sure our function pointers are
        mainCPU.WrMem = WrMem6809;                                                      // pointing to the right places!
        soundCPU.RdMem = RdMem6808;
        soundCPU.WrMem = WrMem6808;
+       mainCPU.clock = 0;                                                                      // Zero out our clocks...
+       soundCPU.clock = 0;
+       mainCPU.clockOverrun = 0;                                                       // And overrun values...
+//notyet       soundCPU.clockOverrun = 0;
 
        return true;
 }
@@ -266,10 +301,10 @@ void SaveMachineState(void)
 
        if (fp != NULL)
        {
-               fwrite(gram, 1, 0x10000, fp);
-               fwrite(sram, 1, 0x10000, fp);
-               fwrite(&mainCPU, 1, sizeof(V6809REGS), fp);
-               fwrite(&soundCPU, 1, sizeof(V6808REGS), fp);
+               size_t ignoredResult = fwrite(gram, 1, 0x10000, fp);
+               ignoredResult = fwrite(sram, 1, 0x10000, fp);
+               ignoredResult = fwrite(&mainCPU, 1, sizeof(V6809REGS), fp);
+               ignoredResult = fwrite(&soundCPU, 1, sizeof(V6808REGS), fp);
                fclose(fp);
        }
        else
@@ -277,327 +312,132 @@ void SaveMachineState(void)
 }
 
 //
-// Main loop
+// 6809 memory functions
 //
-int main(int /*argc*/, char * /*argv*/[])
-{
-//     bool running;                                                                           // Machine running state flag...
-
-       LoadSettings();
-       InitLog("stargem2.log");
-       WriteLog("StarGem2 - A portable Stargate emulator by James L. Hammons\n");
 
-       // Initialize Williams' palette (RGB coded as: 3 bits red, 3 bits green, 2 bits blue)
-       for(uint32 i=0; i<256; i++)
-               palette[i] =
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-               (((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151) << 24)
-                       | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 16)
-                       | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 8) | 0xFF;
-#else
-               ((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151)
-                       | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 8)
-                       | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 16) | 0xFF000000;
+#ifdef LOG_PIA1_IO
+char piaRegsName[4][10] = { "PORTA", "PACTL", "PORTB", "PBCTL" };
 #endif
+uint8 RdMem6809(uint16 addr)
+{
+       uint8 b;
 
-       gram = new uint8[0x10000];
-       grom = new uint8[0x10000];
-       sram = new uint8[0x10000];
-       srom = new uint8[0x10000];
-
-       if (gram == NULL)
-       {
-               WriteLog("Could not allocate RAM space!\nAborting!\n");
-               return -1;
-       }
-       else if (grom == NULL)
+       if (addr >= 0x9000 && addr <= 0xCFFF)           // No ROM between $9000 - $CFFF...
+               b = gram[addr];
+       else
        {
-               WriteLog("Could not allocate ROM space!\nAborting!\n");
-               return -1;
+               if (!gram[0xC900] && addr <= 0x8FFF)    // Check RAM $C900 bank switch
+                       b = gram[addr];
+               else
+                       b = grom[addr];
        }
-       else if (sram == NULL)
+
+       // A wee kludge (though I doubt it reads from anywhere other than $CB00)...
+       if ((addr & 0xFF00) == 0xCB00)
+#if 0
+               b = gram[0xCB00] & 0xFC;                                // Only bits 2-7 are connected...
+#else
        {
-               WriteLog("Could not allocate sRAM space!\nAborting!\n");
-               return -1;
+//Interesting, this code ALSO fucks up the demo...
+//Except when the correct code is called in the scanline callback function...
+               uint32 elapsedCycles = (uint32)(GetCurrentV6809Clock() - clockFrameStart);
+               uint32 scanline = (uint32)((double)elapsedCycles / SCANLINE_DURATION_IN_CYCLES);
+//Changes here don't seem to do much...
+//             uint32 scanline = (uint32)(((double)elapsedCycles * M6809_CYCLE_IN_USEC) / 70.0);
+               b = (uint8)scanline & 0xFC;                             // Only bits 2-7 are connected...
        }
-       else if (srom == NULL)
+#endif
+
+       // More kludge...
+       if ((addr == 0xC80C) && (gram[0xC80D] & 0x04))  // Read PORTA and DDR is set to Output
        {
-               WriteLog("Could not allocate sROM space!\nAborting!\n");
-               return -1;
+               ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);         // Then clear the IRQ
+//OK, this ALSO fucks up the execution of the demo...
+// Which means that the timing is still off. :-/
+//             mainCPU.cpuFlags &= ~V6809_ASSERT_LINE_IRQ;                     // Then clear the IRQ
        }
 
-       // Zero out memory
-       for(long i=0; i<0x10000; i++)
-               gram[i] = grom[i] = sram[i] = srom[i] = 0;
-
-       // Set up V6809 & V6808 execution contexts
-       
-       memset(&mainCPU, sizeof(V6809REGS), 0);
-       mainCPU.RdMem = RdMem6809;
-       mainCPU.WrMem = WrMem6809;
-       mainCPU.cpuFlags |= V6809_ASSERT_LINE_RESET;
-
-       memset(&soundCPU, sizeof(V6808REGS), 0);
-       soundCPU.RdMem = RdMem6808;
-       soundCPU.WrMem = WrMem6808;
-       soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
-
-       if (!LoadImg(CMOS, gram + 0xCC00, 0x400))
-               WriteLog("CMOS RAM not found!\n");
-
-       if (!LoadImg(ROM1, grom + 0x0000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM2, grom + 0x1000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM3, grom + 0x2000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM4, grom + 0x3000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM5, grom + 0x4000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM6, grom + 0x5000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM7, grom + 0x6000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM8, grom + 0x7000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM9, grom + 0x8000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM10, grom + 0xD000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM11, grom + 0xE000, 0x1000))
-               return -1;
-
-       if (!LoadImg(ROM12, grom + 0xF000, 0x1000))
-               return -1;
-
-       if (!LoadImg(SOUNDROM, srom + 0xF800, 0x800))
-               return -1;
-
-       WriteLog("Stargate ROM images loaded...\n");
-       WriteLog("About to initialize video...\n");
-
-       if (!InitVideo())
+       if ((addr == 0xC80E) && (gram[0xC80F] & 0x04))  // Read PORTB and DDR is set to Output
        {
-               cout << "Aborting!" << endl;
-               return -1;
+               ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);         // Then clear the IRQ
+//OK, this ALSO fucks up the execution of the demo...
+//             mainCPU.cpuFlags &= ~V6809_ASSERT_LINE_IRQ;                     // Then clear the IRQ
        }
 
-       // Have to do this *after* video init but *before* sound init...!
-       if (!LoadMachineState())
-               WriteLog("Machine state file not found!\n");
-
-       WriteLog("About to intialize audio...\n");
-       SoundInit();
-//     uint8 * keys = SDL_GetKeyState(NULL);
-       keys = SDL_GetKeyState(NULL);
-
-//     running = true;                                                         // Set running status...
-       srom[0xF800] = 0x37;                                            // Fix checksum so ST works...
+//temp...
+/*extern uint16 pcr;
+//if (addr >= 0xC000 && addr <= 0xCBFF)
+if (addr == 0x9C59)
+       WriteLog("RdMem: Reading address %04X [=%02X, PC=%04X]\n", addr, b, pcr);//*/
+#ifdef LOG_PIA1_IO
+/*if (addr >= 0xC80C && addr <= 0xC80F)
+       WriteLog("V6809 RdMem: Reading PIA (%s) address %04X [<-%02X, PC=%04X]\n", piaRegsName[addr&0x03], addr, b, GetCurrentV6809PC());//*/
+#endif
+       return b;
+}
 
-#if 0
+void WrMem6809(uint16 addr, uint8 b)
+{
+//temp...
+//extern V6809REGS regs;
+//if (addr >= 0xC800 && addr <= 0xCBFE)
+//if (addr == 0xC80F || addr == 0xC80D)
+//     WriteLog("WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, regs.pc, gram[0xCB00]);//*/
+//if (addr == 0xC80E)
+/*if (addr >= 0xC800 && addr <= 0xC80F)
+       WriteLog("V6809 WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, mainCPU.pc, gram[0xCB00]);//*/
 
-//kludge...
-//This didn't work--it still acted like the old way (interrupt @ VC = 0)
-//gram[0xCB00] = 64*3;
+       gram[addr] = b;
 
-       WriteLog("Entering main loop...\n");
-       while (running)
+       if (addr >= 0x0006 && addr < 0x97F7)                    // 304 pixels  152-128=24-16=8
        {
-               SDL_PumpEvents();                                               // Force key events into the buffer.
-               gram[0xC804] = gram[0xC806] = gram[0xC80C] = 0; // Reset PIA ports...
-
-               if (keys[SDLK_ESCAPE])
-                       running = false;                                        // ESC to exit...
-
-               if (keys[SDLK_SEMICOLON])
-                       gram[0xC804] |= 0x01;                           // Fire (;)
-               if (keys[SDLK_l])
-                       gram[0xC804] |= 0x02;                           // Thrust (L)
-               if (keys[SDLK_SPACE])
-                       gram[0xC804] |= 0x04;                           // Smart Bomb (space)
-               if (keys[SDLK_BACKSPACE])
-                       gram[0xC804] |= 0x08;                           // Hyperspace (BkSp)
-               if (keys[SDLK_2])
-                       gram[0xC804] |= 0x10;                           // Two Player Start (2)
-               if (keys[SDLK_1])
-                       gram[0xC804] |= 0x20;                           // One Player Start (1)
-               if (keys[SDLK_RETURN])
-                       gram[0xC804] |= 0x40;                           // Reverse (Enter)
-               if (keys[SDLK_f])
-                       gram[0xC804] |= 0x80;                           // Down (F)
-
-               if (keys[SDLK_r])
-                       gram[0xC806] |= 0x01;                           // Up (R)
-               if (keys[SDLK_a])
-                       gram[0xC806] |= 0x02;                           // Inviso (A)
-
-               if (keys[SDLK_F1])
-                       gram[0xC80C] |= 0x01;                           // Auto up (F1)
-               if (keys[SDLK_F2])
-                       gram[0xC80C] |= 0x02;                           // Advance (F2)
-               if (keys[SDLK_5])
-                       gram[0xC80C] |= 0x04;                           // Right Coin (5)
-               if (keys[SDLK_F3])
-                       gram[0xC80C] |= 0x08;                           // High Score Reset (F3)
-               if (keys[SDLK_3])
-                       gram[0xC80C] |= 0x10;                           // Left Coin (3)
-               if (keys[SDLK_4])
-                       gram[0xC80C] |= 0x20;                           // Center Coin (4)
-               if (keys[SDLK_F4])
-                       gram[0xC80C] |= 0x40;                           // Slam Switch (F4)
-
-               if (keys[SDLK_F5])                                              // Sound CPU self-test (F5)
-                       soundCPU.cpuFlags |= V6808_ASSERT_LINE_NMI;
-               if (keys[SDLK_F6])                                              // Reset the 6808 (F6)
-                       soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
-
-/*
-$CB00 is scanline counter, bits 2-7 (1 frame/240 =69.44... usec)
-
-Some places of interest to look at:
-
-RdMem: Reading address C80E [=0C, PC=15C3]     <- Inside interrupt (read, then discarded)...
-RdMem: Reading address CB00 [=43, PC=15C6]     <- interrupt
-RdMem: Reading address C80C [=00, PC=0758]     <- input (?)
-RdMem: Reading address C80C [=00, PC=07B9]     <- input (?)
-RdMem: Reading address C806 [=00, PC=078C]     <- input
-RdMem: Reading address C804 [=00, PC=2679]     <- input
-*/
-               uint32 startTicks = SDL_GetTicks();
-//             long video_clk = 0;
-//             gram[0xCB00] = 0;
-
-/*
-//This is where the interrupt mask is restored in CC... Hmm...
-//This enables interrupts *after* the previous interrupt has occurred... Hmm.
-//Could $C80F (rom_pia_ctrlb) be the IRQ inhibit? Yes, it is!
-
-       // the IRQ signal comes into CB1, and is set to VA11
-       pia_1_cb1_w(0, scanline & 0x20);
-...
-       // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
-       pia_1_ca1_w(0, 0);
-...
-       // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
-       pia_1_ca1_w(0, 1);
-*/
+               // NOTE: Screen was 304 x 256, but we truncate the vertical dimension here...
+               uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
 
-//WriteLog("--> Start of frame...\n");
-               for(int i=0; i<3; i++)
+               if (sy > 5 && sy < 246)
                {
-//Not sure, but this *might* fix IRQ problem...
-//Checking the PIA IRQ mask for an IRQ seems to work OK. Now if only the timing elsewhere was right...
-                       if (gram[0xC80F] & 0x01)
-                               mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
-
-                       Execute6809(&mainCPU, 4000);
-                       mainCPU.clock -= 4000;                          // Remove 4K ticks from clock (in case it overflowed)
-//Not sure, but this *might* fix IRQ problem...
-//Checking the PIA IRQ mask for an IRQ seems to work OK. Now if only the timing elsewhere was right...
-/*                     if (gram[0xC80F] & 0x01)
-                               mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
-
-                       gram[0xCB00] += 64;                                     // Update video counter...
+                       uint32 saddr = 8 + sx + ((sy - 6) * 320);       // Calc screen address
+                       scrBuffer[saddr + 0] = palette[color[b >> 4]];
+                       scrBuffer[saddr + 1] = palette[color[b & 0x0F]];
                }
-
-//Hmm.
-/*if (gram[0xC80E] & 0x01)
-       mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
-//48 lines... (+ 16)
-//gram[0xCB00] = 0;
-               Execute6809(&mainCPU, 3000);
-               mainCPU.clock -= 3000;                                  // Remove 3K ticks from clock (in case it overflowed)
-//Not sure, but this *might* fix IRQ problem...
-//if (gram[0xC80F] & 0x01)
-//This isn't the right port on the PIA, but it does seem to make it through the demo now...
-//Lesse if this works... Seems to!
-               if (gram[0xC80D] & 0x01)                                // Do COUNT240 IRQ (if enabled!)
-                       mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
-
-/*if (gram[0xC80F] & 0x01)
-               mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
-gram[0xCB00] = 0; //*/
-
-               gram[0xCB00] += 48;                                             // Update video counter...
-
-               Execute6809(&mainCPU, 1000);
-               mainCPU.clock -= 1000;                                  // Remove 1K ticks from clock (in case it overflowed)
-//Eh?
-//Ok, this is the interrupt it's looking for, but still...
-//if (gram[0xC80F] & 0x01)
-//             mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
-
-               gram[0xCB00] += 16;                                             // Update video counter...
-
-//             RenderScreenBuffer();
-               RenderScreenBuffer2();  // 1 frame = 16667 cycles
-//             WriteLog("Main: Rendered back buffer. [6809 PC=%04X]\n", pcr);
-
-               Execute6809(&mainCPU, 667);                             // Do QnD VBLANK
-
-               // 1/60 sec = ? ms (16.6 ms)
-               while (SDL_GetTicks() - startTicks < 16);       // Wait for next frame...
-
-//kludge, temp...
-//Very interesting! It's the palette rotation that's slowing it down!
-//Fixed now, but this allows the color rotation while the wrong timing is in effect...
-/*for(int i=0; i<16; i++)
-       WrMem(0xC000 + i, gram[0x9C26 + i]);//*/
        }
-
-/*uint16 pc = 0x15BA;
-for(int i=0; i<200; i++)
-//while (pc < 0x9000)
-       pc += Decode6809(pc);//*/
-
-#else
-
-       running = true;                                                         // Set running status...
-
-       InitializeEventList();                                          // Clear the event list before we use it...
-       SetCallbackTime(FrameCallback, 16666.66666667); // Set frame to fire at 1/60 s interval
-//     SetCallbackTime(BlinkTimer, 250000);            // Set up blinking at 1/4 s intervals
-       SetCallbackTime(ScanlineCallback, 520.83333334); // Set scanline callback at 1/32 of frame
-//     SetCallbackTime(ScanlineCallback, 520.83333334*32.00); // Set scanline callback at 1/32 of frame
-       startTicks = SDL_GetTicks();
-
-       WriteLog("Entering main loop...\n");
-
-       while (running)
+       else if (addr >= 0xC000 && addr <= 0xC00F)
        {
-               double timeToNextEvent = GetTimeToNextEvent();
-               Execute6809(&mainCPU, USEC_TO_M6809_CYCLES(timeToNextEvent));
-//We MUST remove a frame's worth of time in order for the CPU to function... !!! FIX !!!
-//(Fix so that this is not a requirement!)
-               mainCPU.clock -= USEC_TO_M6809_CYCLES(timeToNextEvent);
-               HandleNextEvent();
+// This approach doesn't take the BG color to the edges of the screen
+               color[addr - 0xC000] = b;
+               paletteDirty = true;
+       }
+       else if (addr == 0xC80E)
+       {
+               sram[0x0402] = b;                                                               // Connect PIAs in 6809 & 6808
+               soundCPU.cpuFlags |= V6808_ASSERT_LINE_IRQ;             // Start sound IRQ
        }
 
+#ifdef LOG_PIA1_IO
+//if (addr >= 0xC80C && addr <= 0xC80F)
+if (addr == 0xC80D)
+       WriteLog("V6809 WrMem: Writing PIA (%s) address %04X [->%02X, PC=%04X]\n", piaRegsName[addr&0x03], addr, b, GetCurrentV6809PC());//*/
 #endif
+}
 
-       SoundDone();
-       VideoDone();
-       SaveCMOS();
-       SaveMachineState();
-       LogDone();
+//
+// 6808 memory functions
+//
 
-       delete[] gram;                                                          // Deallocate RAM & ROM spaces
-       delete[] grom;
-       delete[] sram;
-       delete[] srom;
+uint8 RdMem6808(uint16 addr)
+{
+       return (addr < 0xF000 ? sram[addr] : srom[addr]);
+}
 
-       return 0;
+void WrMem6808(uint16 addr, uint8 b)
+{
+       sram[addr] = b;
+
+       // A total guess, but let's try it...
+//It probably depends on how the PIA is configured, so this is most likely wrong.
+// It is wrong: IRQs are cleared on PIA PORTx reads!
+//     if (addr == 0x0401)
+//             soundCPU.cpuFlags &= ~V6808_ASSERT_LINE_IRQ;
 }
 
 static void FrameCallback(void)
@@ -608,78 +448,94 @@ static void FrameCallback(void)
        if (keys[SDLK_ESCAPE])
                running = false;                                                // ESC to exit...
 
-//Convert this stuff to use the settings module... !!! FIX !!!
-       if (keys[SDLK_SEMICOLON])
-               gram[0xC804] |= 0x01;                                   // Fire (;)
-       if (keys[SDLK_l])
-               gram[0xC804] |= 0x02;                                   // Thrust (L)
-       if (keys[SDLK_SPACE])
-               gram[0xC804] |= 0x04;                                   // Smart Bomb (space)
-       if (keys[SDLK_BACKSPACE])
-               gram[0xC804] |= 0x08;                                   // Hyperspace (BkSp)
-       if (keys[SDLK_2])
-               gram[0xC804] |= 0x10;                                   // Two Player Start (2)
-       if (keys[SDLK_1])
-               gram[0xC804] |= 0x20;                                   // One Player Start (1)
-       if (keys[SDLK_RETURN])
-               gram[0xC804] |= 0x40;                                   // Reverse (Enter)
-       if (keys[SDLK_f])
-               gram[0xC804] |= 0x80;                                   // Down (F)
-
-       if (keys[SDLK_r])
-               gram[0xC806] |= 0x01;                                   // Up (R)
-       if (keys[SDLK_a])
-               gram[0xC806] |= 0x02;                                   // Inviso (A)
-
-       if (keys[SDLK_F1])
-               gram[0xC80C] |= 0x01;                                   // Auto up (F1)
-       if (keys[SDLK_F2])
-               gram[0xC80C] |= 0x02;                                   // Advance (F2)
-       if (keys[SDLK_5])
-               gram[0xC80C] |= 0x04;                                   // Right Coin (5)
-       if (keys[SDLK_F3])
-               gram[0xC80C] |= 0x08;                                   // High Score Reset (F3)
-       if (keys[SDLK_3])
-               gram[0xC80C] |= 0x10;                                   // Left Coin (3)
-       if (keys[SDLK_4])
-               gram[0xC80C] |= 0x20;                                   // Center Coin (4)
-       if (keys[SDLK_F4])
-               gram[0xC80C] |= 0x40;                                   // Slam Switch (F4)
+       if (keys[settings.keyBindings[S_KEY_FIRE]])                     gram[0xC804] |= 0x01;
+       if (keys[settings.keyBindings[S_KEY_THRUST]])           gram[0xC804] |= 0x02;
+       if (keys[settings.keyBindings[S_KEY_SMARTBOMB]])        gram[0xC804] |= 0x04;
+       if (keys[settings.keyBindings[S_KEY_HYPERSPACE]])       gram[0xC804] |= 0x08;
+       if (keys[settings.keyBindings[S_KEY_2P_START]])         gram[0xC804] |= 0x10;
+       if (keys[settings.keyBindings[S_KEY_1P_START]])         gram[0xC804] |= 0x20;
+       if (keys[settings.keyBindings[S_KEY_REVERSE]])          gram[0xC804] |= 0x40;
+       if (keys[settings.keyBindings[S_KEY_DOWN]])                     gram[0xC804] |= 0x80;
+
+       if (keys[settings.keyBindings[S_KEY_UP]])                       gram[0xC806] |= 0x01;
+       if (keys[settings.keyBindings[S_KEY_INVISO]])           gram[0xC806] |= 0x02;
+
+       if (keys[settings.keyBindings[S_KEY_AUTO_UP]])          gram[0xC80C] |= 0x01;
+       if (keys[settings.keyBindings[S_KEY_ADVANCE]])          gram[0xC80C] |= 0x02;
+       if (keys[settings.keyBindings[S_KEY_RIGHT_COIN]])       gram[0xC80C] |= 0x04;
+       if (keys[settings.keyBindings[S_KEY_HS_RESET]])         gram[0xC80C] |= 0x08;
+       if (keys[settings.keyBindings[S_KEY_LEFT_COIN]])        gram[0xC80C] |= 0x10;
+       if (keys[settings.keyBindings[S_KEY_CENTER_COIN]])      gram[0xC80C] |= 0x20;
+       if (keys[settings.keyBindings[S_KEY_SLAM_SWITCH]])      gram[0xC80C] |= 0x40;
 
        if (keys[SDLK_F5])                                                      // Sound CPU self-test (F5)
                soundCPU.cpuFlags |= V6808_ASSERT_LINE_NMI;
        if (keys[SDLK_F6])                                                      // Reset the 6808 (F6)
                soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
+//Temp, for testing...
+extern bool disasm;
+//disasm = true;
+       if (keys[SDLK_F9])
+               disasm = true;
+
+       if (paletteDirty)
+       {
+               for(uint32 addr=0x0006; addr<0x97F7; addr++)
+               {
+                       uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
 
-       RenderScreenBuffer2();                                          // 1 frame = 1/60 sec ~ 16667 cycles
-       SetCallbackTime(FrameCallback, 16666.66666667);
+                       if (sy > 5 && sy < 246)
+                       {
+                               uint32 saddr = 8 + sx + ((sy - 6) * 320);       // Calc screen address
+                               uint8 sb = gram[addr];
+
+                               scrBuffer[saddr + 0] = palette[color[sb >> 4]];
+                               scrBuffer[saddr + 1] = palette[color[sb & 0x0F]];
+                       }
+               }
+
+               paletteDirty = false;
+       }
+
+       RenderScreenBuffer();                                           // 1 frame = 1/60 sec ~ 16667 cycles
+       clockFrameStart = mainCPU.clock;
+
+       // Wait for next frame...
+       while (SDL_GetTicks() - startTicks < 16)
+               SDL_Delay(1);
 
-       while (SDL_GetTicks() - startTicks < 16);       // Wait for next frame...
        startTicks = SDL_GetTicks();
+       SetCallbackTime(FrameCallback, FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC);
 }
 
 static void ScanlineCallback(void)
 {
-// CA1 of PIA 1 maps to $C80C-F... <-- Count240 is in PIA1...
-// What about COUNT240???
-
-//wil wok? Yes, but still screws up on the demo...
-/*     if (gram[0xCB00] & 0x20)
-               if (gram[0xC80F] & 0x01)
-                       mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
+#if 0
        if ((gram[0xCB00] & 0x20) && (gram[0xC80F] & 0x01))
                mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
+#else
+       mainCPU.cpuFlags &= ~V6809_ASSERT_LINE_IRQ;
 
-//Is $C80E COUNT240? Hmm... Doesn't seem to be. Bleh.
-/*     if (gram[0xCB00] >= 240)
-               gram[0xC80E] = 0xFF;
-       else
-               gram[0xC80E] = 0x00;//*/
-//     gram[0xC80E] = (gram[0xCB00] >= 240 ? 0xFF : 0x00);
+       if ((RdMem6809(0xCB00) & 0x20) && (gram[0xC80F] & 0x01))
+               mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
+#endif
 
-       gram[0xCB00] += 8;                                                      // Update video counter...
+/*
+The problem is that this is already asserted above, by virtue of the fact that
+240 = $F0 = bit 5 is set! So this does nothing! So obviously, the above IRQ assertion
+is wrong--just need to figure out how the write of $20 and $00 affects the PBCTRL in the PIA.
+It looks like Stargate never asserts the COUNT240 IRQ, and could be because of the above...
 
-       SetCallbackTime(ScanlineCallback, 520.83333334); // Set scanline callback at 1/32 of frame
+Apparently, COUNT240 is unimportant, at least as far as STARGATE is concerned...
+*/
+//     if ((gram[0xCB00] >= 240) && (gram[0xC80D] & 0x09))     // Do COUNT240 IRQ (if enabled!)
+//             mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
+
+       // This should set everything between $CB00-CBFF...
+//     gram[0xCB00] += 8;                                                      // Update video counter...
+//     gram[0xCB00] += 4;                                                      // Update video counter...
+
+       SetCallbackTime(ScanlineCallback, SG2_PIA_CALLBACK_DURATION);
 }
 
 
@@ -1065,3 +921,226 @@ PIA initialization:
 
 */
 
+#if 0
+
+#define PIA_IRQ1                               (0x80)
+#define PIA_IRQ2                               (0x40)
+
+#define IRQ1_ENABLED(c)                        ( (((c) >> 0) & 0x01))
+#define C1_LOW_TO_HIGH(c)              ( (((c) >> 1) & 0x01))
+#define C1_HIGH_TO_LOW(c)              (!(((c) >> 1) & 0x01))
+#define OUTPUT_SELECTED(c)             ( (((c) >> 2) & 0x01))
+#define IRQ2_ENABLED(c)                        ( (((c) >> 3) & 0x01))
+#define STROBE_E_RESET(c)              ( (((c) >> 3) & 0x01))
+#define STROBE_C1_RESET(c)             (!(((c) >> 3) & 0x01))
+#define C2_SET(c)                              ( (((c) >> 3) & 0x01))
+#define C2_LOW_TO_HIGH(c)              ( (((c) >> 4) & 0x01))
+#define C2_HIGH_TO_LOW(c)              (!(((c) >> 4) & 0x01))
+#define C2_SET_MODE(c)                 ( (((c) >> 4) & 0x01))
+#define C2_STROBE_MODE(c)              (!(((c) >> 4) & 0x01))
+#define C2_OUTPUT(c)                   ( (((c) >> 5) & 0x01))
+#define C2_INPUT(c)                            (!(((c) >> 5) & 0x01))
+
+WRITE8_DEVICE_HANDLER( pia6821_ca1_w )
+{
+       pia6821_state *p = get_token(device);
+
+       /* limit the data to 0 or 1 */
+       data = data ? TRUE : FALSE;
+
+       LOG(("PIA #%s: set input CA1 = %d\n", device->tag, data));
+
+       /* the new state has caused a transition */
+       if ((p->in_ca1 != data) &&
+               ((data && C1_LOW_TO_HIGH(p->ctl_a)) || (!data && C1_HIGH_TO_LOW(p->ctl_a))))
+       {
+               LOG(("PIA #%s: CA1 triggering\n", device->tag));
+
+               /* mark the IRQ */
+               p->irq_a1 = TRUE;
+
+               /* update externals */
+               update_interrupts(device);
+
+               /* CA2 is configured as output and in read strobe mode and cleared by a CA1 transition */
+               if (C2_OUTPUT(p->ctl_a) && C2_STROBE_MODE(p->ctl_a) && STROBE_C1_RESET(p->ctl_a))
+                       set_out_ca2(device, TRUE);
+       }
+
+       /* set the new value for CA1 */
+       p->in_ca1 = data;
+       p->in_ca1_pushed = TRUE;
+}
+
+WRITE8_DEVICE_HANDLER( pia6821_cb1_w )
+{
+       pia6821_state *p = get_token(device);
+
+       /* limit the data to 0 or 1 */
+       data = data ? 1 : 0;
+
+       LOG(("PIA #%s: set input CB1 = %d\n", device->tag, data));
+
+       /* the new state has caused a transition */
+       if ((p->in_cb1 != data) &&
+               ((data && C1_LOW_TO_HIGH(p->ctl_b)) || (!data && C1_HIGH_TO_LOW(p->ctl_b))))
+       {
+               LOG(("PIA #%s: CB1 triggering\n", device->tag));
+
+               /* mark the IRQ */
+               p->irq_b1 = 1;
+
+               /* update externals */
+               update_interrupts(device);
+
+               /* If CB2 is configured as a write-strobe output which is reset by a CB1
+           transition, this reset will only happen when a read from port B implicitly
+           clears the IRQ B1 flag.  So we handle the CB2 reset there.  Note that this
+           is different from what happens with port A. */
+       }
+
+       /* set the new value for CB1 */
+       p->in_cb1 = data;
+       p->in_cb1_pushed = TRUE;
+}
+
+static void update_interrupts(const device_config *device)
+{
+       pia6821_state *p = get_token(device);
+       int new_state;
+
+       /* start with IRQ A */
+       new_state = (p->irq_a1 && IRQ1_ENABLED(p->ctl_a)) || (p->irq_a2 && IRQ2_ENABLED(p->ctl_a));
+
+       if (new_state != p->irq_a_state)
+       {
+               p->irq_a_state = new_state;
+               devcb_call_write_line(&p->irq_a_func, p->irq_a_state);
+       }
+
+       /* then do IRQ B */
+       new_state = (p->irq_b1 && IRQ1_ENABLED(p->ctl_b)) || (p->irq_b2 && IRQ2_ENABLED(p->ctl_b));
+
+       if (new_state != p->irq_b_state)
+       {
+               p->irq_b_state = new_state;
+               devcb_call_write_line(&p->irq_b_func, p->irq_b_state);
+       }
+}
+
+static void control_b_w(const device_config *device, UINT8 data)
+{
+       pia6821_state *p = get_token(device);
+       int temp;
+
+       /* bit 7 and 6 are read only */
+       data &= 0x3f;
+
+       LOG(("PIA #%s: control B write = %02X\n", device->tag, data));
+
+       /* update the control register */
+       p->ctl_b = data;
+
+       if (C2_SET_MODE(p->ctl_b))
+               /* set/reset mode - bit value determines the new output */
+               temp = C2_SET(p->ctl_b);
+       else
+               /* strobe mode - output is always high unless strobed */
+               temp = TRUE;
+
+       set_out_cb2(device, temp);
+
+       /* update externals */
+       update_interrupts(device);
+}
+
+static void control_a_w(const device_config *device, UINT8 data)
+{
+       pia6821_state *p = get_token(device);
+
+       /* bit 7 and 6 are read only */
+       data &= 0x3f;
+
+       LOG(("PIA #%s: control A write = %02X\n", device->tag, data));
+
+       /* update the control register */
+       p->ctl_a = data;
+
+       /* CA2 is configured as output */
+       if (C2_OUTPUT(p->ctl_a))
+       {
+               int temp;
+
+               if (C2_SET_MODE(p->ctl_a))
+                       /* set/reset mode - bit value determines the new output */
+                       temp = C2_SET(p->ctl_a);
+               else
+                       /* strobe mode - output is always high unless strobed */
+                       temp = TRUE;
+
+               set_out_ca2(device, temp);
+       }
+
+       /* update externals */
+       update_interrupts(device);
+}
+
+
+CTRL REGISTER:
+
+B7        B6        B5 B4 B3     B2   B1 B0
+--------------------------------------------------
+IRQA(B)1  IRQA(B)2  CA(B)2 Ctrl  DDR  CA(B)1 Ctrl
+
+Bits 6 & 7 are RO. IRQs are cleared on read of PORTA when not in DDR mode
+DDR: 0: DDR selected, 1: Output register selected
+CA1(CB1) Ctrl: B0: 0/1 Dis/enable interrupt IRQA(B)
+               B1: 0/1 IRQ set by Hi-to-Lo/Lo-to-Hi transition on CA(B)1
+CA2(CB2) Ctrl: If B5==0, B4 & B3 are similar to B1 & B0
+
+Entering main loop...
+V6809 WrMem: Writing PIA (PACTL) address C80D [->00, PC=F4DC] --> Set DDR on PORTA, IRQs off
+V6809 WrMem: Writing PIA (PORTA) address C80C [->00, PC=F4DF] --> Set DDR to all input on PORTA
+V6809 WrMem: Writing PIA (PACTL) address C80D [->3C, PC=F4E4] --> Set Output on PORTA, Set CA2 = 1, disable IRQA1
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->00, PC=F4E7] --> Set DDR on PORTB, IRQs off
+V6809 WrMem: Writing PIA (PORTB) address C80E [->C0, PC=F4EC] --> Set DDR to output on 6,7 input on 0-5 on PORTB
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->3C, PC=F4F1] --> Set Output on PORTA, Set CB2 = 1, disable IRQB1
+V6809 WrMem: Writing PIA (PORTB) address C80E [->C0, PC=F4F6] --> Send 1s on bits 6 & 7 on PORTB
+V6809 WrMem: Writing PIA (PACTL) address C80D [->34, PC=F523] --> Set Output on PORTA, Set CA2 = 0, disable IRQA1
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=F526] --> Set Output on PORTB, Set CB2 = 0, disable IRQB1
+V6809 WrMem: Writing PIA (PORTB) address C80E [->00, PC=F529] --> Send 0s on bits 6 & 7 on PORTB
+V6809 WrMem: Writing PIA (PORTA) address C80C [->00, PC=6076] --> Do nothing
+V6809 WrMem: Writing PIA (PACTL) address C80D [->00, PC=6076] --> Set DDR on PORTA, IRQs off
+V6809 WrMem: Writing PIA (PORTA) address C80C [->00, PC=607B] --> Set DDR to all input on PORTA
+V6809 WrMem: Writing PIA (PACTL) address C80D [->34, PC=607B] --> Set Output on PORTA, Set CA2 = 0, disable IRQA1
+V6809 WrMem: Writing PIA (PORTB) address C80E [->00, PC=6076] --> Send 0s on bits 6 & 7 on PORTB
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->00, PC=6076] --> Set DDR on PORTB, IRQs off
+V6809 WrMem: Writing PIA (PORTB) address C80E [->FF, PC=607B] --> Set DDR to all output on PORTB
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=607B] --> Set Output on PORTB, Set CB2 = 0, enable IRQB1
+V6809 WrMem: Writing PIA (PORTB) address C80E [->3F, PC=6088] --> Send $3F on PORTB
+V6809 WrMem: Writing PIA (PORTB) address C80E [->0C, PC=60DB] --> Send $0C on PORTB
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3] --> Set Output on PORTB, Set CB2 = 0, disable IRQB1
+ 6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]  --> Clear IRQBs
+ 6809 RdMem: Reading PIA (PORTA) address C80C [=00, PC=075B]  --> Clear IRQAs
+ 6809 RdMem: Reading PIA (PORTA) address C80C [=00, PC=07B9]  --> Clear IRQAs
+
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644] --> Set Output on PORTB, Set CB2 = 0, enable IRQB1
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3] --> Set Output on PORTB, Set CB2 = 0, disable IRQB1
+ 6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]  --> Clear IRQBs
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
+ 6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
+ 6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
+ 6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
+ 6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
+V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
+ 6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
+
+#endif