]> Shamusworld >> Repos - stargem2/commitdiff
More cleanup, chasing down problems with the demo mode
authorShamus Hammons <jlhamm@acm.org>
Tue, 21 Jul 2009 20:25:10 +0000 (20:25 +0000)
committerShamus Hammons <jlhamm@acm.org>
Tue, 21 Jul 2009 20:25:10 +0000 (20:25 +0000)
src/sound.cpp
src/stargem2.cpp
src/timing.h
src/v6809.cpp

index 8010d8985667c04bae056bcfe51c6f5d42cfa0fb..2f7522047072082c2b3c32fba6a6e04be0f340d4 100755 (executable)
 #include "types.h"
 #include "log.h"
 #include "v6808.h"
+#include "timing.h"
 
 //using namespace std;
 
+#define AUDIO_SAMPLE_RATE      44100
+
 // Local variables
 
 SDL_AudioSpec desired;
@@ -45,7 +48,7 @@ void SoundInit(void)
 {
 //     memory_malloc_secure((void **)&DACBuffer, BUFFER_SIZE * sizeof(uint16), "DAC buffer");
 
-       desired.freq = 44100;                                                   // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
+       desired.freq = AUDIO_SAMPLE_RATE;                               // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
        desired.format = AUDIO_U8;                                              // This uses the native endian (for portability)...
        desired.channels = 1;
 //     desired.samples = 4096;                                                 // Let's try a 4K buffer (can always go lower)
@@ -77,13 +80,21 @@ void SoundDone(void)
        }
 }
 
+/*
+The way to determine the # of cycles for each sample is to take the CPU clock frequency
+and divide by the sample rate.
+
+Like so:
+double cycles = M6808_CLOCK_SPEED_IN_HZ / AUDIO_SAMPLE_RATE;
+Then we need to separate out the fractional part from the integer part.
+*/
+
 //
 // Sound card callback handler
 //
 void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
 {
        extern V6808REGS soundCPU;
-//     extern uint8 * sram;
        extern uint8 sram[];
        int cnt = 0;
 
index 32248fcdd8d6bc854fe611d5f02c778a1c00e88a..8ad9c3632ab33e31a5e602b544beaeeb4aa6f22c 100755 (executable)
@@ -41,6 +41,14 @@ using namespace std;
 #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!
+//#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[0x10000], grom[0x10000], sram[0x10000], srom[0x10000]; // RAM & ROM spaces
@@ -57,6 +65,17 @@ 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
 
 static void FrameCallback(void);
@@ -64,152 +83,142 @@ static void ScanlineCallback(void);
 
 
 //
-// 6809 memory functions
+// Main loop
 //
-
-#ifdef LOG_PIA1_IO
-char piaRegsName[4][10] = { "PORTA", "PACTL", "PORTB", "PBCTL" };
-#endif
-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();
 
-       // 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...
+       // 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
-       {
-//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 * M6809_CYCLE_IN_USEC) / 65.10416666666667);
-//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...
-       }
+               ((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
 
-       // More kludge...
-       if ((addr == 0xC80C) && (gram[0xC80D] & 0x04))  // Read PORTA and DDR is set to Output
-       {
-               ClearLine(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
-       }
+       // Zero out memory
+       memset(gram, 0, 0x10000);
+       memset(grom, 0, 0x10000);
+       memset(sram, 0, 0x10000);
+       memset(srom, 0, 0x10000);
 
-       if ((addr == 0xC80E) && (gram[0xC80F] & 0x04))  // Read PORTB and DDR is set to Output
-       {
-               ClearLine(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
-       }
+       // Set up V6809 & V6808 execution contexts
 
-//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;
-}
+       memset(&mainCPU, 0, sizeof(V6809REGS));
+       mainCPU.RdMem = RdMem6809;
+       mainCPU.WrMem = WrMem6809;
+       mainCPU.cpuFlags |= V6809_ASSERT_LINE_RESET;
 
-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(&soundCPU, 0, sizeof(V6808REGS));
+       soundCPU.RdMem = RdMem6808;
+       soundCPU.WrMem = WrMem6808;
+       soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
 
-       gram[addr] = b;
+       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"
+               };
 
-       if (addr >= 0x0006 && addr < 0x97F7)                    // 304 pixels  152-128=24-16=8
+       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
-                       scrBuffer[saddr + 0] = palette[color[b >> 4]];
-                       scrBuffer[saddr + 1] = palette[color[b & 0x0F]];
+                       WriteLog("Could not open file '%s'!\n", ROMs[i]);
+                       return -1;
                }
        }
-       else if (addr >= 0xC000 && addr <= 0xC00F)
-       {
-// 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
-//#warning "This should only touch memory right before a render. !!! FIX !!!"
-//Now it does. :-)
-               color[addr - 0xC000] = b;
 
-#if 0
-               for(uint32 addr=0x0006; 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]];
-                       }
-               }
-#else
-               paletteDirty = true;
-#endif
-       }
-       else if (addr == 0xC80E)
+       if (!InitVideo())
        {
-               sram[0x0402] = b;                                                               // Connect PIAs in 6809 & 6808
-               soundCPU.cpuFlags |= V6808_ASSERT_LINE_IRQ;             // Start sound IRQ
+               cout << "Aborting!" << endl;
+               return -1;
        }
 
-#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
-}
+       // Have to do this *after* video init but *before* sound init...!
+       WriteLog("About to load machine state...");
 
-//
-// 6808 memory functions
-//
+       if (!LoadMachineState())
+               WriteLog("Machine state file not found!\n");
+       else
+               WriteLog("done!\n");
 
-uint8 RdMem6808(uint16 addr)
+       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)
+       {
+               double timeToNextEvent = GetTimeToNextEvent();
+               Execute6809(&mainCPU, USEC_TO_M6809_CYCLES(timeToNextEvent));
+               HandleNextEvent();
+       }
+
+#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");
+
+/*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
 
-       // 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;
+       SoundDone();
+       VideoDone();
+       SaveCMOS();
+       SaveMachineState();
+       LogDone();
+
+       return 0;
 }
 
 //
@@ -261,10 +270,14 @@ bool LoadMachineState(void)
        ignoredResult = fread(&soundCPU, 1, sizeof(V6808REGS), fp);
        fclose(fp);
 
-//     for(int i=0x0006; i<0x97F8; i++)                                        // Set up backbuffer... ;-)
-//             WrMem6809(i, gram[i]);
+       // 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;                                                            // Set up backbuffer...
+       paletteDirty = true;
 
        mainCPU.RdMem = RdMem6809;                                                      // Make sure our function pointers are
        mainCPU.WrMem = WrMem6809;                                                      // pointing to the right places!
@@ -272,6 +285,8 @@ bool LoadMachineState(void)
        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;
 }
@@ -296,148 +311,132 @@ void SaveMachineState(void)
 }
 
 //
-// Main loop
+// 6809 memory functions
 //
-int main(int /*argc*/, char * /*argv*/[])
+
+#ifdef LOG_PIA1_IO
+char piaRegsName[4][10] = { "PORTA", "PACTL", "PORTB", "PBCTL" };
+#endif
+uint8 RdMem6809(uint16 addr)
 {
-       InitLog("stargem2.log");
-       WriteLog("StarGem2 - A portable Stargate emulator by James L. Hammons\n");
-       WriteLog("(C) 2009 Underground Software\n\n");
+       uint8 b;
 
-       LoadSettings();
+       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];
+       }
 
-       // 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;
+       // 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
-               ((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;
+       {
+//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...
+       }
 #endif
 
-       // Zero out memory
-       memset(gram, 0, 0x10000);
-       memset(grom, 0, 0x10000);
-       memset(sram, 0, 0x10000);
-       memset(srom, 0, 0x10000);
+       // More kludge...
+       if ((addr == 0xC80C) && (gram[0xC80D] & 0x04))  // Read PORTA and DDR is set to Output
+       {
+               ClearLine(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
+       }
 
-       // Set up V6809 & V6808 execution contexts
+       if ((addr == 0xC80E) && (gram[0xC80F] & 0x04))  // Read PORTB and DDR is set to Output
+       {
+               ClearLine(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
+       }
 
-       memset(&mainCPU, 0, sizeof(V6809REGS));
-       mainCPU.RdMem = RdMem6809;
-       mainCPU.WrMem = WrMem6809;
-       mainCPU.cpuFlags |= V6809_ASSERT_LINE_RESET;
+//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;
+}
 
-       memset(&soundCPU, 0, sizeof(V6808REGS));
-       soundCPU.RdMem = RdMem6808;
-       soundCPU.WrMem = WrMem6808;
-       soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
+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]);//*/
 
-       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"
-               };
+       gram[addr] = b;
 
-       for(int i=0; i<12; i++)
+       if (addr >= 0x0006 && addr < 0x97F7)                    // 304 pixels  152-128=24-16=8
        {
-               uint32 baseAddress = i * 0x1000;
-
-               if (i > 8)
-                       baseAddress += 0x4000;
+               // NOTE: Screen was 304 x 256, but we truncate the vertical dimension here...
+               uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
 
-               if (!LoadImg(ROMs[i], grom + baseAddress, 0x1000))
+               if (sy > 5 && sy < 246)
                {
-                       WriteLog("Could not open file '%s'!\n", ROMs[i]);
-                       return -1;
+                       uint32 saddr = 8 + sx + ((sy - 6) * 320);       // Calc screen address
+                       scrBuffer[saddr + 0] = palette[color[b >> 4]];
+                       scrBuffer[saddr + 1] = palette[color[b & 0x0F]];
                }
        }
-
-       if (!LoadImg(SOUNDROM, srom + 0xF800, 0x800))
+       else if (addr >= 0xC000 && addr <= 0xC00F)
        {
-               WriteLog("Could not open file '%s'!\n", SOUNDROM);
-               return -1;
+// This approach doesn't take the BG color to the edges of the screen
+               color[addr - 0xC000] = b;
+               paletteDirty = true;
        }
-
-       WriteLog("Stargate ROM images loaded...\n");
-       WriteLog("About to initialize video...\n");
-
-       if (!InitVideo())
+       else if (addr == 0xC80E)
        {
-               cout << "Aborting!" << endl;
-               return -1;
+               sram[0x0402] = b;                                                               // Connect PIAs in 6809 & 6808
+               soundCPU.cpuFlags |= V6808_ASSERT_LINE_IRQ;             // Start sound IRQ
        }
 
-       // 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, 16666.66666667); // Set frame to fire at 1/60 s interval
-//     SetCallbackTime(ScanlineCallback, 520.83333334); // Set scanline callback at 1/32 of frame
-       SetCallbackTime(ScanlineCallback, 520.83333334/2.0); // Set scanline callback at 1/64 of frame
-       clockFrameStart = mainCPU.clock;
-       startTicks = SDL_GetTicks();
-
-       WriteLog("Entering main loop...\n");
-
-       while (running)
-       {
-               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!)
-//Very odd... Execution seems to fuck up when using a 64-bit clock...
-//(i.e., when this is commented out!)
-//             mainCPU.clock -= USEC_TO_M6809_CYCLES(timeToNextEvent);
-               HandleNextEvent();
-       }
+#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
+}
 
-#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");
+//
+// 6808 memory functions
+//
 
-/*uint16 pc = mainCPU.pc;//0x15BA;
-for(int i=0; i<200; i++)
-//while (pc < 0x9000)
+uint8 RdMem6808(uint16 addr)
 {
-       pc += Decode6809(pc);
-       WriteLog("\n");
-}//*/
+       return (addr < 0xF000 ? sram[addr] : srom[addr]);
+}
 
-/*uint32 pc = 0;
-while (pc < 0xFFFF)
+void WrMem6808(uint16 addr, uint8 b)
 {
-       pc += Decode6809(pc);
-       WriteLog("\n");
-}//*/
-#endif
-
-       SoundDone();
-       VideoDone();
-       SaveCMOS();
-       SaveMachineState();
-       LogDone();
+       sram[addr] = b;
 
-       return 0;
+       // 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)
@@ -511,7 +510,6 @@ static void FrameCallback(void)
        }
 
        RenderScreenBuffer();                                           // 1 frame = 1/60 sec ~ 16667 cycles
-       SetCallbackTime(FrameCallback, 16666.66666667);
        clockFrameStart = mainCPU.clock;
 
        // Wait for next frame...
@@ -519,6 +517,7 @@ static void FrameCallback(void)
                SDL_Delay(1);
 
        startTicks = SDL_GetTicks();
+       SetCallbackTime(FrameCallback, FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC);
 }
 
 static void ScanlineCallback(void)
@@ -546,10 +545,9 @@ Apparently, COUNT240 is unimportant, at least as far as STARGATE is concerned...
 
        // This should set everything between $CB00-CBFF...
 //     gram[0xCB00] += 8;                                                      // Update video counter...
-       gram[0xCB00] += 4;                                                      // Update video counter...
+//     gram[0xCB00] += 4;                                                      // Update video counter...
 
-//     SetCallbackTime(ScanlineCallback, 520.83333334); // Set scanline callback at 1/32 of frame
-       SetCallbackTime(ScanlineCallback, 520.83333334/2.0); // Set scanline callback at 1/64 of frame
+       SetCallbackTime(ScanlineCallback, SG2_PIA_CALLBACK_DURATION);
 }
 
 
index 1be633ada402997daf8561aa30e28e10426e0a83..28f906eb3685b0add8c25046eb0c25da86b3b9f1 100755 (executable)
 //#define M68K_CYCLE_IN_USEC     (RISC_CYCLE_IN_USEC * 2)
 //#define HORIZ_PERIOD_IN_USEC   63.5555
 //#define M6502_CYCLE_IN_USEC      0.9765625
-#define M6808_CYCLE_IN_USEC      0.9765625
-#define M6809_CYCLE_IN_USEC      1.0
+
+//#define MASTER_CLOCK         (12000000)
+//#define SOUND_CLOCK                  (3579000)
+//     MDRV_CPU_ADD("maincpu", M6809, MASTER_CLOCK/3/4)
+//     MDRV_CPU_PROGRAM_MAP(defender_map)
+//     MDRV_CPU_ADD("soundcpu", M6808, SOUND_CLOCK)
+//     MDRV_CPU_PROGRAM_MAP(defender_sound_map)
+
+#define M6808_CLOCK_SPEED_IN_HZ                (3579000.0 / 4.0)
+#define M6809_CLOCK_SPEED_IN_HZ                (1000000.0)
+
+// Actually, it's 1.1176306230790722 usec
+//#define M6808_CYCLE_IN_USEC      (0.9765625)
+#define M6808_CYCLE_IN_USEC            (1000000.0 / M6808_CLOCK_SPEEK_IN_HZ)
+#define M6809_CYCLE_IN_USEC            (1000000.0 / M6809_CLOCK_SPEED_IN_HZ)
 
 //#define USEC_TO_RISC_CYCLES(u) (uint32)(((u) / RISC_CYCLE_IN_USEC) + 0.5)
 //#define USEC_TO_M68K_CYCLES(u) (uint32)(((u) / M68K_CYCLE_IN_USEC) + 0.5)
index 197cdea906a88ae1b653aecc253499be4220e8ae..cb670726874d0ab4cdad5e1bf31722bb76aae8d0 100755 (executable)
@@ -3049,34 +3049,60 @@ static void myMemcpy(void * dst, void * src, uint32 size)
 //
 // Function to execute 6809 instructions
 //
-#define NON_DESTRUCTIVE_CLOCK
-#ifdef NON_DESTRUCTIVE_CLOCK
-//static uint32 leftover = 0;
-//#include "log.h"
+//#define DEBUG_ILLEGAL
+#ifdef DEBUG_ILLEGAL
+#include "log.h"
+#include "dis6809.h"
+uint8 btPtr = 0;
+uint8 backTrace[256];
+V6809REGS btRegs[256];
+bool tripped = false;
 #endif
 void Execute6809(V6809REGS * context, uint32 cycles)
 {
-       // This seriously fucks up the leftover counting...
-       if (cycles == 0)
+       // If this is not in place, the clockOverrun calculations can cause the V6809 to get
+       // stuck in an infinite loop.
+       if (cycles == 0)                                                        // Nothing to do, so bail!
                return;
 
-//WriteLog("V6809: cycles = %u, regs.clock = %u, leftover = %u \n", cycles, regs.clock, leftover);
        myMemcpy(&regs, context, sizeof(V6809REGS));
 
        // Execute here...
-#ifdef NON_DESTRUCTIVE_CLOCK
-//Very odd.. It fucks up when using the following code for a timeslice!
-//     cycles -= regs.clockOverrun;//leftover;
-//     uint64 endCycles = regs.clock + (uint64)(cycles - leftover);
+
+       // Since we can't guarantee that we'll execute the number of cycles passed in
+       // exactly, we have to keep track of how much we overran the number of cycles
+       // the last time we executed. Since we already executed those cycles, this time
+       // through we remove them from the cycles passed in in order to come out
+       // approximately even. Over the long run, this unevenness in execution times
+       // evens out.
        uint64 endCycles = regs.clock + (uint64)(cycles - regs.clockOverrun);
-//     uint64 endCycles = regs.clock + (uint64)cycles;
-//WriteLog("V6809: endCycles = %u, regs.clock = %u, leftover = %u \n", endCycles, regs.clock, leftover);
 
        while (regs.clock < endCycles)
-#else
-       while (regs.clock < cycles)
-#endif
        {
+#ifdef DEBUG_ILLEGAL
+if (!tripped)
+{
+       backTrace[btPtr] = regs.RdMem(regs.pc);
+       btRegs[btPtr] = regs;
+       btPtr = (btPtr + 1) & 0xFF;
+
+       if (regs.cpuFlags & V6809_STATE_ILLEGAL_INST)
+       {
+               WriteLog("V6809: Executed illegal instruction!!!!\n\nBacktrace:\n\n");
+               regs.cpuFlags &= ~V6809_STATE_ILLEGAL_INST;
+
+               for(uint16 i=btPtr; i<btPtr+256; i++)
+               {
+                       Decode6809(btRegs[i & 0xFF].pc);
+// Note that these values are *before* execution, so stale...
+                       WriteLog("\n\tA=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X\n",
+                               btRegs[i & 0xFF].a, btRegs[i & 0xFF].b, btRegs[i & 0xFF].cc, btRegs[i & 0xFF].dp, btRegs[i & 0xFF].x, btRegs[i & 0xFF].y, btRegs[i & 0xFF].s, btRegs[i & 0xFF].u, btRegs[i & 0xFF].pc);//*/
+               }
+
+               tripped = true;
+       }
+}
+#endif
 #ifdef __DEBUG__
 //Decode6809(regs.pc);
 static bool disasm = false;
@@ -3198,16 +3224,8 @@ if (disasm) WriteLog("\tA=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04
 #endif
        }
 
-//This is a lame way of doing it, but in the end the simplest--however, it destroys any
-//record of elasped CPU time. Not sure that it's important to keep track, but there it is.
-// Now we use a 64-bit integer, so it won't wrap for about 500 millenia. ;-)
-#ifdef NON_DESTRUCTIVE_CLOCK
-//     leftover = (uint32)(regs.clock - endCycles);
+       // Keep track of how much we overran so we can adjust on the next run...
        regs.clockOverrun = (uint32)(regs.clock - endCycles);
-//WriteLog("V6809: leftover = %u\n", leftover);
-#else
-       regs.clock -= cycles;
-#endif
 
        myMemcpy(context, &regs, sizeof(V6809REGS));
 }