From f51c96856129613e8aefd07a777dc59812ded4c7 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Tue, 21 Jul 2009 20:25:10 +0000 Subject: [PATCH] More cleanup, chasing down problems with the demo mode --- src/sound.cpp | 15 +- src/stargem2.cpp | 474 +++++++++++++++++++++++------------------------ src/timing.h | 17 +- src/v6809.cpp | 68 ++++--- 4 files changed, 307 insertions(+), 267 deletions(-) diff --git a/src/sound.cpp b/src/sound.cpp index 8010d89..2f75220 100755 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -26,9 +26,12 @@ #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; diff --git a/src/stargem2.cpp b/src/stargem2.cpp index 32248fc..8ad9c36 100755 --- a/src/stargem2.cpp +++ b/src/stargem2.cpp @@ -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); } diff --git a/src/timing.h b/src/timing.h index 1be633a..28f906e 100755 --- a/src/timing.h +++ b/src/timing.h @@ -16,8 +16,21 @@ //#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) diff --git a/src/v6809.cpp b/src/v6809.cpp index 197cdea..cb67072 100755 --- a/src/v6809.cpp +++ b/src/v6809.cpp @@ -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(®s, 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