X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fapple2.cpp;h=1eeb7e88c3ed95378516e43052e57d1f2f129b11;hb=c0001155bc0909da61f6c849c0be9b16e9b7f4b6;hp=976addcb19e6c66433a9136350af8304146d4139;hpb=5ad8269882e02adf942486e8ad51c17676e32027;p=apple2 diff --git a/src/apple2.cpp b/src/apple2.cpp index 976addc..1eeb7e8 100755 --- a/src/apple2.cpp +++ b/src/apple2.cpp @@ -31,7 +31,7 @@ #include "apple2.h" -#include +#include #include #include #include @@ -58,42 +58,55 @@ #define THREADED_65C02 #define CPU_THREAD_OVERFLOW_COMPENSATION -//#define DEBUG_LC +#define DEBUG_LC //#define CPU_CLOCK_CHECKING -#define THREAD_DEBUGGING +//#define THREAD_DEBUGGING +#define SOFT_SWITCH_DEBUGGING // Global variables -uint8 ram[0x10000], rom[0x10000]; // RAM & ROM spaces -uint8 ram2[0x10000]; -uint8 diskRom[0x100]; // Disk ROM space +uint8_t ram[0x10000], rom[0x10000]; // RAM & ROM spaces +uint8_t ram2[0x10000]; // Auxillary RAM +uint8_t diskRom[0x100]; // Disk ROM space V65C02REGS mainCPU; // v65C02 execution context -uint8 appleType = APPLE_TYPE_II; +uint8_t appleType = APPLE_TYPE_IIE; FloppyDrive floppyDrive; // Local variables -static uint8 lastKeyPressed = 0; +static uint8_t lastKeyPressed = 0; static bool keyDown = false; +static bool openAppleDown = false; +static bool closedAppleDown = false; +static bool store80Mode = false; +static bool vbl = false; +static bool slotCXROM = false; +static bool slotC3ROM = false; +static bool ramrd = false; +static bool ramwrt = false; +static bool altzp = false; +static bool ioudis = true; +bool dhires = false; //static FloppyDrive floppyDrive; enum { LC_BANK_1, LC_BANK_2 }; -static uint8 visibleBank = LC_BANK_1; +static uint8_t visibleBank = LC_BANK_1; static bool readRAM = false; static bool writeRAM = false; static bool running = true; // Machine running state flag... -static uint32 startTicks; +static uint32_t startTicks; +static bool pauseMode = false; static GUI * gui = NULL; // Local functions (technically, they're global...) -bool LoadImg(char * filename, uint8 * ram, int size); -uint8 RdMem(uint16 addr); -void WrMem(uint16 addr, uint8 b); +bool LoadImg(char * filename, uint8_t * ram, int size); +uint8_t RdMem(uint16_t addr); +void WrMem(uint16_t addr, uint8_t b); static void SaveApple2State(const char * filename); static bool LoadApple2State(const char * filename); @@ -111,6 +124,9 @@ static SDL_sem * mainSem = NULL; static bool cpuFinished = false; static bool cpuSleep = false; + +// NB: Apple //e Manual sez 6502 is running @ 1,022,727 Hz + // Let's try a thread... /* Here's how it works: Execute 1 frame's worth, then sleep. @@ -139,7 +155,10 @@ WriteLog("CPU: SDL_SemWait(mainSem);\n"); #endif SDL_SemWait(mainSem); - uint32 cycles = 17066; +// There are exactly 800 slices of 21.333 cycles per frame, so it works out +// evenly. +#if 0 + uint32_t cycles = 17066; #ifdef CPU_THREAD_OVERFLOW_COMPENSATION // ODD! It's closer *without* this overflow compensation. ??? WHY ??? overflow += 0.666666667; @@ -162,6 +181,27 @@ WriteLog("CPU: Execute65C02(&mainCPU, cycles);\n"); WriteLog("CPU: AdjustLastToggleCycles(mainCPU.clock);\n"); #endif AdjustLastToggleCycles(mainCPU.clock); +#else +#ifdef THREAD_DEBUGGING +WriteLog("CPU: Execute65C02(&mainCPU, cycles);\n"); +#endif + for(int i=0; i<800; i++) + { + uint32_t cycles = 21; + overflow += 0.333333334; + + if (overflow > 1.0) + { + cycles++; + overflow -= 1.0; + } + + Execute65C02(&mainCPU, cycles); + WriteSampleToBuffer(); + } +#endif + +//WriteLog("CPUThread: Supposedly end of frame...\n"); #ifdef THREAD_DEBUGGING WriteLog("CPU: SDL_mutexP(cpuMutex);\n"); @@ -200,6 +240,7 @@ WriteLog("CPU: SDL_mutexV(cpuMutex);\n"); } #endif + // Test GUI function Element * TestWindow(void) @@ -210,6 +251,7 @@ Element * TestWindow(void) return win; } + Element * QuitEmulator(void) { gui->Stop(); @@ -218,6 +260,7 @@ Element * QuitEmulator(void) return NULL; } + /* Small Apple II memory map: @@ -241,9 +284,9 @@ $C0EE - Disk set read mode // V65C02 read/write memory functions // -uint8 RdMem(uint16 addr) +uint8_t RdMem(uint16_t addr) { - uint8 b; + uint8_t b; #if 0 if (addr >= 0xC000 && addr <= 0xC0FF) @@ -258,15 +301,124 @@ if (addr >= 0xC080 && addr <= 0xC08F) { return lastKeyPressed | (keyDown ? 0x80 : 0x00); } - else if ((addr & 0xFFF0) == 0xC010) // Read $C010-$C01F +// else if ((addr & 0xFFF8) == 0xC010) // Read $C010-$C01F + else if (addr == 0xC010) { //This is bogus: keyDown is set to false, so return val NEVER is set... //Fixed... //Also, this is IIe/IIc only...! - uint8 retVal = lastKeyPressed | (keyDown ? 0x80 : 0x00); + uint8_t retVal = lastKeyPressed | (keyDown ? 0x80 : 0x00); keyDown = false; return retVal; } + // These are //e locations + else if (addr == 0xC011) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RDBANK2 (read)\n"); +#endif + return (visibleBank == LC_BANK_2 ? 0x80 : 0x00); + } + else if (addr == 0xC012) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RDLCRAM (read)\n"); +#endif + return (readRAM ? 0x80 : 0x00); + } + else if (addr == 0xC013) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMRD (read)\n"); +#endif + return (ramrd ? 0x80 : 0x00); + } + else if (addr == 0xC014) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMWRT (read)\n"); +#endif + return (ramwrt ? 0x80 : 0x00); + } + else if (addr == 0xC015) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTCXROM (read)\n"); +#endif + return (slotCXROM ? 0x80 : 0x00); + } + else if (addr == 0xC016) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTZP (read)\n"); +#endif + return (altzp ? 0x80 : 0x00); + } + else if (addr == 0xC017) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTC3ROM (read)\n"); +#endif + return (slotC3ROM ? 0x80 : 0x00); + } + else if (addr == 0xC018) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80STORE (read)\n"); +#endif + return (store80Mode ? 0x80 : 0x00); + } + else if (addr == 0xC019) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("VBL (read)\n"); +#endif +// NB: The doco suggests that this signal goes LOW when in the VBI. +// Which means that we need to control this by counting lines somewhere. + return (vbl ? 0x80 : 0x00); + } + else if (addr == 0xC01A) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT (read)\n"); +#endif + return (textMode ? 0x80 : 0x00); + } + else if (addr == 0xC01B) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED (read)\n"); +#endif + return (mixedMode ? 0x80 : 0x00); + } + else if (addr == 0xC01C) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 (read)\n"); +#endif + return (displayPage2 ? 0x80 : 0x00); + } + else if (addr == 0xC01D) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES (read)\n"); +#endif + return (hiRes ? 0x80 : 0x00); + } + else if (addr == 0xC01E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTCHARSET (read)\n"); +#endif + return (alternateCharset ? 0x80 : 0x00); + } + else if (addr == 0xC01F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80COL (read)\n"); +#endif + return (col80Mode ? 0x80 : 0x00); + } else if ((addr & 0xFFF0) == 0xC030) // Read $C030-$C03F { /* @@ -292,36 +444,120 @@ deltaT to zero. In the sound IRQ, if deltaT > buffer size, then subtract buffer } else if (addr == 0xC050) // Read $C050 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT off (read)\n"); +#endif textMode = false; } else if (addr == 0xC051) // Read $C051 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT on (read)\n"); +#endif textMode = true; } else if (addr == 0xC052) // Read $C052 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED off (read)\n"); +#endif mixedMode = false; } else if (addr == 0xC053) // Read $C053 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED on (read)\n"); +#endif mixedMode = true; } else if (addr == 0xC054) // Read $C054 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 off (read)\n"); +#endif displayPage2 = false; } else if (addr == 0xC055) // Read $C055 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 on (read)\n"); +#endif displayPage2 = true; } else if (addr == 0xC056) // Read $C056 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES off (read)\n"); +#endif hiRes = false; } else if (addr == 0xC057) // Read $C057 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES on (read)\n"); +#endif hiRes = true; } + else if (addr == 0xC05E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES on (read)\n"); +#endif + if (ioudis) + dhires = true; + } + else if (addr == 0xC05F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES off (read)\n"); +#endif + if (ioudis) + dhires = false; + } + else if (addr == 0xC061) // Read $C061 + { + // Open Apple key (or push button 0) + return (openAppleDown ? 0x80 : 0x00); + } + else if (addr == 0xC062) // Read $C062 + { + // Open Apple key (or push button 0) + return (closedAppleDown ? 0x80 : 0x00); + } + // The way the paddles work is that a strobe is written (or read) to $C070, + // then software counts down the time that it takes for the paddle outputs + // to have bit 7 return to 0. If there are no paddles connected, bit 7 + // stays at 1. + else if (addr == 0xC064) // Paddles 0-3 + { + return 0xFF; + } + else if (addr == 0xC065) + { + return 0xFF; + } + else if (addr == 0xC066) + { + return 0xFF; + } + else if (addr == 0xC067) + { + return 0xFF; + } + else if (addr == 0xC07E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("IOUDIS (read)\n"); +#endif + return (ioudis ? 0x80 : 0x00); + } + else if (addr == 0xC07F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES (read)\n"); +#endif + return (dhires ? 0x80 : 0x00); + } //Note that this is a kludge: The $D000-$DFFF 4K space is shared (since $C000-$CFFF is //memory mapped) between TWO banks, and that that $E000-$FFFF RAM space is a single bank. @@ -459,9 +695,6 @@ WriteLog("LC(R): $C08B 49291 OECG RR Read/Write RAM bank 1\n"); else if (addr == 0xC0EC) { return floppyDrive.ReadWrite(); -//Hm, some stuff is looking at the return value. Dunno what it *should* be... -// OK, it's from the ReadWrite routine... -//return 0xFF; } else if (addr == 0xC0ED) { @@ -483,62 +716,99 @@ if (addr >= 0xD000 && addr <= 0xD00F) showpath = true; #endif //This sux... - if (addr >= 0xC100 && addr <= 0xCFFF) // The $C000-$CFFF block is *never* RAM -#ifdef LC_DEBUGGING + if (addr >= 0xC100 && addr <= 0xC7FF) // The $C000-$CFFF block is *never* RAM { -#endif - b = rom[addr]; +// Looks like the ][e ref manual got this one wrong: slotCXROM set should mean +// use internal ROM, NOT slot ROM. :-/ +// (fixed now, by setting the switch correctly in the write mem section :-P) + if (!slotCXROM) +// if (slotCXROM) + b = rom[addr]; + else + { + if (addr >= 0xC100 && addr <= 0xC1FF) + b = parallelROM[addr & 0xFF]; + else if (addr >= 0xC600 && addr <= 0xC6FF) + b = diskROM[addr & 0xFF]; + else if (addr >= 0xC300 && addr <= 0xC3FF && !slotC3ROM) + b = rom[addr]; + else + b = 0xFF; +// b = rom[addr]; + } #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from $C100-$CFFF block...\n"); - } #endif + } + else if (addr >= 0xC800 && addr <= 0xCFFF) // 2K peripheral or OS ROM + { + b = rom[addr]; + } else if (addr >= 0xD000) { if (readRAM) { if (addr <= 0xDFFF && visibleBank == LC_BANK_1) #ifdef LC_DEBUGGING - { + { #endif - b = ram[addr - 0x1000]; +// b = ram[addr - 0x1000]; + b = (altzp ? ram2[addr - 0x1000] : ram[addr - 0x1000]); #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from LC bank #1 (ram[addr - 0x1000])...\n"); - } + } #endif else #ifdef LC_DEBUGGING - { + { #endif - b = ram[addr]; +// b = ram[addr]; + b = (altzp ? ram2[addr] : ram[addr]); #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from LC bank #2 (ram[addr])...\n"); - } + } #endif } else #ifdef LC_DEBUGGING - { + { #endif b = rom[addr]; #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from LC ROM (rom[addr])...\n"); - } + } #endif } else -#ifdef LC_DEBUGGING { +// 80STORE only works for WRITING, not READING! +#if 0 + // Check for 80STORE mode (STORE80 takes precedence over RAMRD/WRT)... + if ((((addr >= 0x0400) && (addr <= 0x07FF)) || ((addr >= 0x2000) && (addr <= 0x3FFF))) && store80Mode) + { + if (displayPage2) + b = ram2[addr]; + else + b = ram[addr]; + + return b; + } #endif - b = ram[addr]; + + // Finally, check for auxillary/altzp write switches + if (addr < 0x0200) + b = (altzp ? ram2[addr] : ram[addr]); + else + b = (ramrd ? ram2[addr] : ram[addr]); #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from ram[addr]...\n"); - } #endif + } #ifdef LC_DEBUGGING if (addr >= 0xD000 && addr <= 0xD00F) @@ -569,7 +839,7 @@ APPENDIX F Assembly Language Program Listings 13 DDRB2 EQU $C482 ;DATA DIRECTION REGISTER (B) 14 DDRA2 EQU $C483 ;DATA DIRECTION REGISTER (A) */ -void WrMem(uint16 addr, uint8 b) +void WrMem(uint16_t addr, uint8_t b) { //temp... //extern V6809REGS regs; @@ -650,12 +920,117 @@ SET80VID = $C00D ;enable 80-column display mode (WR-only) CLRALTCH = $C00E ;use main char set- norm LC, Flash UC (WR-only) SETALTCH = $C00F ;use alt char set- norm inverse, LC; no Flash (WR-only) */ - if (addr == 0xC00E) + if (addr == 0xC000) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80STORE off (write)\n"); +#endif + store80Mode = false; + } + else if (addr == 0xC001) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80STORE on (write)\n"); +#endif + store80Mode = true; + } + else if (addr == 0xC002) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMRD off (write)\n"); +#endif + ramrd = false; + } + else if (addr == 0xC003) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMRD on (write)\n"); +#endif + ramrd = true; + } + else if (addr == 0xC004) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMWRT off (write)\n"); +#endif + ramwrt = false; + } + else if (addr == 0xC005) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMWRT on (write)\n"); +#endif + ramwrt = true; + } + else if (addr == 0xC006) + { + // This is the only soft switch that breaks the usual convention. +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTCXROM on (write)\n"); +#endif + slotCXROM = true; + } + else if (addr == 0xC007) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTCXROM off (write)\n"); +#endif + slotCXROM = false; + } + else if (addr == 0xC008) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTZP off (write)\n"); +#endif + altzp = false; + } + else if (addr == 0xC009) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTZP on (write)\n"); +#endif + altzp = true; + } + else if (addr == 0xC00A) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTC3ROM off (write)\n"); +#endif + slotC3ROM = false; + } + else if (addr == 0xC00B) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTC3ROM on (write)\n"); +#endif + slotC3ROM = true; + } + else if (addr == 0xC00C) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80COL off (write)\n"); +#endif + col80Mode = false; + } + else if (addr == 0xC00D) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80COL on (write)\n"); +#endif + col80Mode = true; + } + else if (addr == 0xC00E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTCHARSET off (write)\n"); +#endif alternateCharset = false; } else if (addr == 0xC00F) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTCHARSET on (write)\n"); +#endif alternateCharset = true; } else if ((addr & 0xFFF0) == 0xC010) // Keyboard strobe @@ -667,36 +1042,95 @@ SETALTCH = $C00F ;use alt char set- norm inverse, LC; no Flash (WR-only) } else if (addr == 0xC050) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT off (write)\n"); +#endif textMode = false; } else if (addr == 0xC051) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT on (write)\n"); +#endif textMode = true; } else if (addr == 0xC052) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED off (write)\n"); +#endif mixedMode = false; } else if (addr == 0xC053) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED on (write)\n"); +#endif mixedMode = true; } else if (addr == 0xC054) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 off (write)\n"); +#endif displayPage2 = false; } else if (addr == 0xC055) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 on (write)\n"); +#endif displayPage2 = true; } else if (addr == 0xC056) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES off (write)\n"); +#endif hiRes = false; } else if (addr == 0xC057) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES on (write)\n"); +#endif hiRes = true; } + else if (addr == 0xC05E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES on (write)\n"); +#endif + if (ioudis) + dhires = true; + +//static int goDumpDis = 0; +//goDumpDis++; +//if (goDumpDis == 2) +// dumpDis = true; + } + else if (addr == 0xC05F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES off (write)\n"); +#endif + if (ioudis) + dhires = false; + } + else if (addr == 0xC07E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("IOUDIS on (write)\n"); +#endif + ioudis = true; + } + else if (addr == 0xC07F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("IOUDIS off (write)\n"); +#endif + ioudis = false; + } else if ((addr & 0xFFFB) == 0xC080) { #ifdef DEBUG_LC @@ -824,22 +1258,84 @@ if (addr >= 0xD000 && addr <= 0xD00F) { if (writeRAM) { +#if 0 if (addr <= 0xDFFF && visibleBank == LC_BANK_1) ram[addr - 0x1000] = b; else ram[addr] = b; +#else + if (addr <= 0xDFFF && visibleBank == LC_BANK_1) + { + if (altzp) + ram2[addr - 0x1000] = b; + else + ram[addr - 0x1000] = b; + } + else + { + if (altzp) + ram2[addr] = b; + else + ram[addr] = b; + } +#endif } return; } - ram[addr] = b; + // Check for 80STORE mode (STORE80 takes precedence over RAMRD/WRT)... + if ((((addr >= 0x0400) && (addr <= 0x07FF)) || ((addr >= 0x2000) && (addr <= 0x3FFF))) && store80Mode) + { + if (displayPage2) + ram2[addr] = b; + else + ram[addr] = b; + + return; + } + + // Finally, check for auxillary/altzp write switches +#if 0 + if (ramwrt) + ram2[addr] = b; + else + { + if (altzp) + ram2[addr] = b; + else + ram[addr] = b; + } +#else + if (addr < 0x0200) +// if (addr < 0x0200 || addr >= 0xD000) + { +#if 0 +if (addr == 0x38) + WriteLog("Write $38: $%02X\n", b); +else if (addr == 0x39) + WriteLog("Write $39: $%02X\n", b); +#endif + if (altzp) + ram2[addr] = b; + else + ram[addr] = b; + } + else + { + if (ramwrt) + ram2[addr] = b; + else + ram[addr] = b; + } +#endif } + // // Load a file into RAM/ROM image space // -bool LoadImg(char * filename, uint8 * ram, int size) +bool LoadImg(char * filename, uint8_t * ram, int size) { FILE * fp = fopen(filename, "rb"); @@ -852,19 +1348,22 @@ bool LoadImg(char * filename, uint8 * ram, int size) return true; } + static void SaveApple2State(const char * filename) { } + static bool LoadApple2State(const char * filename) { return false; } + #ifdef CPU_CLOCK_CHECKING -uint8 counter = 0; -uint32 totalCPU = 0; -uint64 lastClock = 0; +uint8_t counter = 0; +uint32_t totalCPU = 0; +uint64_t lastClock = 0; #endif // // Main loop @@ -876,7 +1375,6 @@ int main(int /*argc*/, char * /*argv*/[]) srand(time(NULL)); // Initialize RNG // Zero out memory -//Need to bankify this stuff for the IIe emulation... memset(ram, 0, 0x10000); memset(rom, 0, 0x10000); memset(ram2, 0, 0x10000); @@ -887,7 +1385,9 @@ int main(int /*argc*/, char * /*argv*/[]) mainCPU.WrMem = WrMem; mainCPU.cpuFlags |= V65C02_ASSERT_LINE_RESET; - if (!LoadImg(settings.BIOSPath, rom + 0xD000, 0x3000)) +// alternateCharset = true; +// if (!LoadImg(settings.BIOSPath, rom + 0xD000, 0x3000)) + if (!LoadImg(settings.BIOSPath, rom + 0xC000, 0x4000)) { WriteLog("Could not open file '%s'!\n", settings.BIOSPath); return -1; @@ -907,9 +1407,11 @@ int main(int /*argc*/, char * /*argv*/[]) //Kill the DOS ROM in slot 6 for now... //not - memcpy(rom + 0xC600, diskROM, 0x100); +// memcpy(rom + 0xC600, diskROM, 0x100); +// memcpy(rom + 0xC700, diskROM, 0x100); // Slot 7??? WriteLog("About to initialize video...\n"); + if (!InitVideo()) { std::cout << "Aborting!" << std::endl; @@ -961,10 +1463,12 @@ memcpy(ram + 0xD000, ram + 0xC000, 0x1000); WriteLog("About to initialize audio...\n"); SoundInit(); - SDL_EnableUNICODE(1); // Needed to do key translation shit +//nope SDL_EnableUNICODE(1); // Needed to do key translation shit // gui = new GUI(surface); // Set up the GUI system object... - gui = new GUI(mainSurface); // Set up the GUI system object... +// gui = new GUI(mainSurface); // Set up the GUI system object... +// SDL 2... this will likely cause Apple 2 to crash +// gui = new GUI(NULL); // Set up the GUI system object... #if 0 gui->AddMenuTitle("Apple2"); gui->AddMenuItem("Test!", TestWindow/*, hotkey*/); @@ -983,9 +1487,9 @@ memcpy(ram + 0xD000, ram + 0xC000, 0x1000); #ifdef THREADED_65C02 cpuCond = SDL_CreateCond(); - cpuThread = SDL_CreateThread(CPUThreadFunc, NULL); -//Hmm... CPU does POST (+1), wait, then WAIT (-1) mainSem = SDL_CreateSemaphore(1); + cpuThread = SDL_CreateThread(CPUThreadFunc, NULL, NULL); +//Hmm... CPU does POST (+1), wait, then WAIT (-1) // SDL_sem * mainMutex = SDL_CreateMutex(); #endif @@ -1055,6 +1559,7 @@ floppyDrive.SaveImage(); return 0; } + /* Apple II keycodes ----------------- @@ -1110,6 +1615,8 @@ Z $DA $9A $DA $9A ESC $9B $9B $9B $9B No xlation */ +//static uint64_t lastCPUCycles = 0; +static uint32_t frameCount = 0; static void FrameCallback(void) { SDL_Event event; @@ -1118,21 +1625,24 @@ static void FrameCallback(void) { switch (event.type) { - case SDL_KEYDOWN: - if (event.key.keysym.unicode != 0) - { + case SDL_TEXTINPUT: //Need to do some key translation here, and screen out non-apple keys as well... - if (event.key.keysym.sym == SDLK_TAB) // Prelim key screening... - break; - - lastKeyPressed = event.key.keysym.unicode; - keyDown = true; - //kludge: should have a caps lock thingy here... - //or all uppercase for ][+... - if (lastKeyPressed >= 'a' && lastKeyPressed <='z') - lastKeyPressed &= 0xDF; // Convert to upper case... - } +//(really, could do it all in SDL_KEYDOWN, would just have to get symbols & +// everything else done separately. this is slightly easier. :-P) +// if (event.key.keysym.sym == SDLK_TAB) // Prelim key screening... + if (event.edit.text[0] == '\t') // Prelim key screening... + break; + + lastKeyPressed = event.edit.text[0]; + keyDown = true; + //kludge: should have a caps lock thingy here... + //or all uppercase for ][+... +// if (lastKeyPressed >= 'a' && lastKeyPressed <='z') +// lastKeyPressed &= 0xDF; // Convert to upper case... + + break; + case SDL_KEYDOWN: // CTRL+RESET key emulation (mapped to CTRL+`) // This doesn't work... // if (event.key.keysym.sym == SDLK_BREAK && (event.key.keysym.mod & KMOD_CTRL)) @@ -1146,12 +1656,55 @@ static void FrameCallback(void) lastKeyPressed = 0x15, keyDown = true; else if (event.key.keysym.sym == SDLK_LEFT) lastKeyPressed = 0x08, keyDown = true; + else if (event.key.keysym.sym == SDLK_UP) + lastKeyPressed = 0x0B, keyDown = true; + else if (event.key.keysym.sym == SDLK_DOWN) + lastKeyPressed = 0x0A, keyDown = true; + else if (event.key.keysym.sym == SDLK_RETURN) + lastKeyPressed = 0x0D, keyDown = true; + else if (event.key.keysym.sym == SDLK_ESCAPE) + lastKeyPressed = 0x1B, keyDown = true; + else if (event.key.keysym.sym == SDLK_BACKSPACE) + lastKeyPressed = 0x7F, keyDown = true; + + // Fix CTRL+key combo... + if (event.key.keysym.mod & KMOD_CTRL) + { + if (event.key.keysym.sym >= SDLK_a && event.key.keysym.sym <= SDLK_z) + { + lastKeyPressed = (event.key.keysym.sym - SDLK_a) + 1; + keyDown = true; +//printf("Key combo pressed: CTRL+%c\n", lastKeyPressed + 0x40); + } + } // Use ALT+Q to exit, as well as the usual window decoration method if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_ALT)) running = false; - if (event.key.keysym.sym == SDLK_F12) + if (event.key.keysym.sym == SDLK_PAUSE) + { + pauseMode = !pauseMode; + + if (pauseMode) + { + SoundPause(); + SpawnMessage("*** PAUSED ***"); + } + else + { + SoundResume(); + SpawnMessage("*** RESUME ***"); + } + } + + // Paddle buttons 0 & 1 + if (event.key.keysym.sym == SDLK_INSERT) + openAppleDown = true; + if (event.key.keysym.sym == SDLK_PAGEUP) + closedAppleDown = true; + + if (event.key.keysym.sym == SDLK_F11) dumpDis = !dumpDis; // Toggle the disassembly process // else if (event.key.keysym.sym == SDLK_F11) // floppyDrive.LoadImage("./disks/bt1_char.dsk");//Kludge to load char disk... @@ -1196,13 +1749,39 @@ else if (event.key.keysym.sym == SDLK_F10) SpawnMessage("Volume: %s", volStr); } + static bool fullscreenDebounce = false; + + if (event.key.keysym.sym == SDLK_F12) + { + if (!fullscreenDebounce) + { + ToggleFullScreen(); + fullscreenDebounce = true; + } + } +// else + + break; + case SDL_KEYUP: + if (event.key.keysym.sym == SDLK_F12) + fullscreenDebounce = false; + + // Paddle buttons 0 & 1 + if (event.key.keysym.sym == SDLK_INSERT) + openAppleDown = false; + if (event.key.keysym.sym == SDLK_PAGEUP) + closedAppleDown = false; + +// if (event.key.keysym.sym >= SDLK_a && event.key.keysym.sym <= SDLK_z) +// keyDown = false; + break; case SDL_QUIT: running = false; } } -#warning "!!! Taking MAJOR time hit with the video frame rendering !!!" +//#warning "!!! Taking MAJOR time hit with the video frame rendering !!!" RenderVideoFrame(); SetCallbackTime(FrameCallback, 16666.66666667); @@ -1211,10 +1790,10 @@ else if (event.key.keysym.sym == SDLK_F10) counter++; if (counter == 60) { - uint64 clock = GetCurrentV65C02Clock(); -//totalCPU += (uint32)(clock - lastClock); + uint64_t clock = GetCurrentV65C02Clock(); +//totalCPU += (uint32_t)(clock - lastClock); - printf("Executed %u cycles...\n", (uint32)(clock - lastClock)); + printf("Executed %u cycles...\n", (uint32_t)(clock - lastClock)); lastClock = clock; // totalCPU = 0; counter = 0; @@ -1226,23 +1805,42 @@ if (counter == 60) //Actually, slows things down too much... //SDL_Delay(10); // while (SDL_GetTicks() - startTicks < 16); // Wait for next frame... - while (SDL_GetTicks() - startTicks < 16) + +// This is the problem: If you set the interval to 16, it runs faster than +// 1/60s per frame. If you set it to 17, it runs slower. What we need is to +// have it do 16 for one frame, then 17 for two others. Then it should average +// out to 1/60s per frame every 3 frames. + frameCount = (frameCount + 1) % 3; + + uint32_t waitFrameTime = 17 - (frameCount == 0 ? 1 : 0); + + while (SDL_GetTicks() - startTicks < waitFrameTime) SDL_Delay(1); // Wait for next frame... startTicks = SDL_GetTicks(); +#if 0 + uint64_t cpuCycles = GetCurrentV65C02Clock(); + uint32_t cyclesBurned = (uint32_t)(cpuCycles - lastCPUCycles); + WriteLog("FrameCallback: used %i cycles\n", cyclesBurned); + lastCPUCycles = cpuCycles; +#endif + //let's wait, then signal... //works longer, but then still falls behind... #ifdef THREADED_65C02 - SDL_CondSignal(cpuCond);//OK, let the CPU go another frame... + if (!pauseMode) + SDL_CondSignal(cpuCond);//OK, let the CPU go another frame... #endif } + static void BlinkTimer(void) { flash = !flash; SetCallbackTime(BlinkTimer, 250000); // Set up blinking at 1/4 sec intervals } + /* Next problem is this: How to have events occur and synchronize with the rest of the threads? @@ -1254,7 +1852,7 @@ One way would be to use a fractional accumulator, then subtract 1 every time it overflows. Like so: double overflow = 0; -uint32 time = 20; +uint32_t time = 20; while (!done) { Execute6808(&soundCPU, time);