2 // Apple 2 SDL Portable Apple Emulator
5 // (C) 2005 Underground Software
7 // Loosely based on AppleWin by Tom Charlesworth which was based on AppleWin by
8 // Oliver Schmidt which was based on AppleWin by Michael O'Brien. :-) Parts are
9 // also derived from ApplePC. Too bad it was closed source--it could have been
10 // *the* premier Apple II emulator out there.
12 // JLH = James L. Hammons <jlhamm@acm.org>
15 // --- ---------- ------------------------------------------------------------
16 // JLH 11/12/2005 Initial port to SDL
17 // JLH 11/18/2005 Wired up graphic soft switches
18 // JLH 12/02/2005 Setup timer subsystem for more accurate time keeping
19 // JLH 12/12/2005 Added preliminary state saving support
24 // - Port to SDL [DONE]
26 // - Weed out unneeded functions [DONE]
28 // - 128K IIe related stuff
29 // - State loading/saving
47 #include "applevideo.h"
53 #include "gui/window.h"
54 #include "gui/draggablewindow2.h"
55 #include "gui/textedit.h"
57 //using namespace std;
61 uint8 ram[0x10000], rom[0x10000]; // RAM & ROM spaces
62 uint8 diskRom[0x100]; // Disk ROM space
64 uint8 appleType = APPLE_TYPE_II;
68 static uint8 lastKeyPressed = 0;
69 static bool keyDown = false;
71 static FloppyDrive floppyDrive;
73 enum { LC_BANK_1, LC_BANK_2 };
75 static uint8 visibleBank = LC_BANK_1;
76 static bool readRAM = false;
77 static bool writeRAM = false;
79 static bool running = true; // Machine running state flag...
80 static uint32 startTicks;
82 static GUI * gui = NULL;
84 // Local functions (technically, they're global...)
86 bool LoadImg(char * filename, uint8 * ram, int size);
87 uint8 RdMem(uint16 addr);
88 void WrMem(uint16 addr, uint8 b);
89 static void SaveApple2State(const char * filename);
90 static bool LoadApple2State(const char * filename);
92 // Local timer callback functions
94 static void FrameCallback(void);
95 static void BlinkTimer(void);
99 Element * TestWindow(void)
101 Element * win = new DraggableWindow2(10, 10, 128, 128);
102 // ((DraggableWindow *)win)->AddElement(new TextEdit(4, 16, 92, 0, "u2prog.dsk", win));
107 Element * QuitEmulator(void)
116 Small Apple II memory map:
118 $C010 - Clear bit 7 of keyboard data ($C000)
119 $C030 - Toggle speaker diaphragm
121 $C054 - Select page 1
122 $C056 - Select lo-res
123 $C058 - Set annuciator-0 output to 0
124 $C05A - Set annuciator-0 output to 0
125 $C05D - Set annuciator-0 output to 1
126 $C05F - Set annuciator-0 output to 1
127 $C0E0 - Disk control stepper ($C0E0-7)
128 $C0E9 - Disk control motor (on)
129 $C0EA - Disk enable (drive 1)
131 $C0EE - Disk set read mode
135 // V65C02 read/write memory functions
138 uint8 RdMem(uint16 addr)
143 if (addr >= 0xC000 && addr <= 0xC0FF)
144 WriteLog("\n*** Read at I/O address %04X\n", addr);
147 if (addr >= 0xC080 && addr <= 0xC08F)
148 WriteLog("\n*** Read at I/O address %04X\n", addr);
151 if ((addr & 0xFFF0) == 0xC000)
153 return lastKeyPressed | (keyDown ? 0x80 : 0x00);
155 else if ((addr & 0xFFF0) == 0xC010)
157 //This is bogus: keyDown is set to false, so return val NEVER is set...
159 //Also, this is IIe/IIc only...!
160 uint8 retVal = lastKeyPressed | (keyDown ? 0x80 : 0x00);
164 else if ((addr & 0xFFF0) == 0xC030)
167 This is problematic, mainly because the v65C02 removes actual cycles run after each call.
168 Therefore, we don't really have a reliable method of sending a timestamp to the sound routine.
171 What we need to send is a delta T value but related to the IRQ buffer routine. E.g., if the buffer
172 hasn't had any changes in it then we just fill it with the last sample value and are done. Then
173 we need to adjust our delta T accordingly. What we could do is keep a running total of time since the
174 last change and adjust it accordingly, i.e., whenever a sound IRQ happens.
177 Have deltaT somewhere. Then, whenever there's a toggle, backfill buffer with last spkr state and reset
178 deltaT to zero. In the sound IRQ, if deltaT > buffer size, then subtract buffer size from deltaT. (?)
183 ToggleSpeaker(GetCurrentV65C02Clock());
184 //should it return something else here???
187 else if (addr == 0xC050)
191 else if (addr == 0xC051)
195 else if (addr == 0xC052)
199 else if (addr == 0xC053)
203 else if (addr == 0xC054)
205 displayPage2 = false;
207 else if (addr == 0xC055)
211 else if (addr == 0xC056)
215 else if (addr == 0xC057)
220 //Note that this is a kludge: The $D000-$DFFF 4K space is shared (since $C000-$CFFF is
221 //memory mapped) between TWO banks, and that that $E000-$FFFF RAM space is a single bank.
222 //[SHOULD BE FIXED NOW]
223 //OK! This switch selects bank 2 of the 4K bank at $D000-$DFFF. One access makes it
224 //visible, two makes it R/W.
260 else if ((addr & 0xFFFB) == 0xC080)
263 WriteLog("LC(R): $C080 49280 OECG R Read RAM bank 2; no write\n");
265 //$C080 49280 OECG R Read RAM bank 2; no write
266 visibleBank = LC_BANK_2;
270 else if ((addr & 0xFFFB) == 0xC081)
273 WriteLog("LC(R): $C081 49281 OECG RR Read ROM; write RAM bank 2\n");
275 //$C081 49281 ROMIN OECG RR Read ROM; write RAM bank 2
276 visibleBank = LC_BANK_2;
280 else if ((addr & 0xFFFB) == 0xC082)
283 WriteLog("LC(R): $C082 49282 OECG R Read ROM; no write\n");
285 //$C082 49282 OECG R Read ROM; no write
286 visibleBank = LC_BANK_2;
290 else if ((addr & 0xFFFB) == 0xC083)
293 WriteLog("LC(R): $C083 49283 OECG RR Read/Write RAM bank 2\n");
295 //$C083 49283 LCBANK2 OECG RR Read/write RAM bank 2
296 visibleBank = LC_BANK_2;
300 else if ((addr & 0xFFFB) == 0xC088)
303 WriteLog("LC(R): $%04X 49288 OECG R Read RAM bank 1; no write\n", addr);
305 //$C088 49288 OECG R Read RAM bank 1; no write
306 visibleBank = LC_BANK_1;
309 //Hm. Some stuff seems to want this.
310 //nope, was looking at $C0E8... return 0xFF;
312 else if ((addr & 0xFFFB) == 0xC089)
315 WriteLog("LC(R): $C089 49289 OECG RR Read ROM; write RAM bank 1\n");
317 //$C089 49289 OECG RR Read ROM; write RAM bank 1
318 visibleBank = LC_BANK_1;
322 else if ((addr & 0xFFFB) == 0xC08A)
325 WriteLog("LC(R): $C08A 49290 OECG R Read ROM; no write\n");
327 //$C08A 49290 OECG R Read ROM; no write
328 visibleBank = LC_BANK_1;
332 else if ((addr & 0xFFFB) == 0xC08B)
335 WriteLog("LC(R): $C08B 49291 OECG RR Read/Write RAM bank 1\n");
337 //$C08B 49291 OECG RR Read/write RAM bank 1
338 visibleBank = LC_BANK_1;
342 else if ((addr & 0xFFF8) == 0xC0E0)
344 floppyDrive.ControlStepper(addr & 0x07);
346 else if ((addr & 0xFFFE) == 0xC0E8)
348 floppyDrive.ControlMotor(addr & 0x01);
350 else if ((addr & 0xFFFE) == 0xC0EA)
352 floppyDrive.DriveEnable(addr & 0x01);
354 else if (addr == 0xC0EC)
356 return floppyDrive.ReadWrite();
357 //Hm, some stuff is looking at the return value. Dunno what it *should* be...
358 // OK, it's from the ReadWrite routine...
361 else if (addr == 0xC0ED)
363 return floppyDrive.GetLatchValue();
365 else if (addr == 0xC0EE)
367 floppyDrive.SetReadMode();
369 else if (addr == 0xC0EF)
371 floppyDrive.SetWriteMode();
375 if (addr >= 0xC100 && addr <= 0xCFFF) // The $C000-$CFFF block is *never* RAM
377 else if (addr >= 0xD000)
381 if (addr <= 0xDFFF && visibleBank == LC_BANK_1)
382 b = ram[addr - 0x1000];
397 APPENDIX F Assembly Language Program Listings
403 5 * ;ADDRESSES FOR FIRST 6522
404 6 ORB EQU $C400 ;PORT B
405 7 ORA EQU $C401 ;PORT A
406 8 DDRB EQU $C402 ;DATA DIRECTION REGISTER (A)
407 9 DDRA EQU $C403 ;DATA DIRECTION REGISTER (B)
408 10 * ;ADDRESSES FOR SECOND 6522
409 11 ORB2 EQU $C480 ;PORT B
410 12 ORA2 EQU $C481 ;PORT A
411 13 DDRB2 EQU $C482 ;DATA DIRECTION REGISTER (B)
412 14 DDRA2 EQU $C483 ;DATA DIRECTION REGISTER (A)
414 void WrMem(uint16 addr, uint8 b)
417 //extern V6809REGS regs;
418 //if (addr >= 0xC800 && addr <= 0xCBFE)
419 //if (addr == 0xC80F || addr == 0xC80D)
420 // WriteLog("WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, regs.pc, gram[0xCB00]);//*/
423 if (addr >= 0xC000 && addr <= 0xC0FF)
424 WriteLog("\n*** Write at I/O address %04X\n", addr);
427 Check the BIKO version on Asimov to see if it's been cracked or not...
429 7F3D: 29 07 AND #$07 [PC=7F3F, SP=01EA, CC=---B-I--, A=01, X=4B, Y=00]
430 7F3F: C9 06 CMP #$06 [PC=7F41, SP=01EA, CC=N--B-I--, A=01, X=4B, Y=00]
431 7F41: 90 03 BCC $7F46 [PC=7F46, SP=01EA, CC=N--B-I--, A=01, X=4B, Y=00]
432 [7F43: 4C 83 7E JMP $7E83] <- Skipped over... (Prints "THANK YOU VERY MUCH!")
433 7F46: AA TAX [PC=7F47, SP=01EA, CC=---B-I--, A=01, X=01, Y=00]
435 ; INX here *ensures* 1 - 6!!! BUG!!!
436 ; Or is it? Could this be part of a braindead copy protection scheme? It's
437 ; awfully close to NOP ($EA)...
438 ; Nothing else touches it once it's been written... Hmm...
440 7F47: E8 INX [PC=7F48, SP=01EA, CC=---B-I--, A=01, X=02, Y=00]
441 7F48: F8 SED [PC=7F49, SP=01EA, CC=---BDI--, A=01, X=02, Y=00]
442 7F49: 18 CLC [PC=7F4A, SP=01EA, CC=---BDI--, A=01, X=02, Y=00]
443 7F4A: BD 15 4E LDA $4E15,X [PC=7F4D, SP=01EA, CC=---BDI--, A=15, X=02, Y=00]
446 ; 4E15: 25 25 15 15 10 20
447 ; 4E1B: 03 41 99 99 01 00 12
450 7F4D: 65 FC ADC $FC [PC=7F4F, SP=01EA, CC=---BDI--, A=16, X=02, Y=00]
451 7F4F: 65 FC ADC $FC [PC=7F51, SP=01EA, CC=---BDI--, A=17, X=02, Y=00]
452 7F51: 65 FC ADC $FC [PC=7F53, SP=01EA, CC=---BDI--, A=18, X=02, Y=00]
453 7F53: 65 FC ADC $FC [PC=7F55, SP=01EA, CC=---BDI--, A=19, X=02, Y=00]
455 ; NO checking is done on the raised stat! Aarrrgggghhhhh!
457 7F55: 9D 15 4E STA $4E15,X [PC=7F58, SP=01EA, CC=---BDI--, A=19, X=02, Y=00]
458 7F58: D8 CLD [PC=7F59, SP=01EA, CC=---B-I--, A=19, X=02, Y=00]
460 ; Print "ALAKAZAM!" and so on...
462 7F59: 20 2C 40 JSR $402C [PC=402C, SP=01E8, CC=---B-I--, A=19, X=02, Y=00]
466 WriteLog("\n*** Byte %02X written at address %04X\n", b, addr);
469 CLR80STORE=$C000 ;80STORE Off- disable 80-column memory mapping (Write)
470 SET80STORE=$C001 ;80STORE On- enable 80-column memory mapping (WR-only)
472 CLRAUXRD = $C002 ;read from main 48K (WR-only)
473 SETAUXRD = $C003 ;read from aux/alt 48K (WR-only)
475 CLRAUXWR = $C004 ;write to main 48K (WR-only)
476 SETAUXWR = $C005 ;write to aux/alt 48K (WR-only)
478 CLRCXROM = $C006 ;use ROM on cards (WR-only)
479 SETCXROM = $C007 ;use internal ROM (WR-only)
481 CLRAUXZP = $C008 ;use main zero page, stack, & LC (WR-only)
482 SETAUXZP = $C009 ;use alt zero page, stack, & LC (WR-only)
484 CLRC3ROM = $C00A ;use internal Slot 3 ROM (WR-only)
485 SETC3ROM = $C00B ;use external Slot 3 ROM (WR-only)
487 CLR80VID = $C00C ;disable 80-column display mode (WR-only)
488 SET80VID = $C00D ;enable 80-column display mode (WR-only)
490 CLRALTCH = $C00E ;use main char set- norm LC, Flash UC (WR-only)
491 SETALTCH = $C00F ;use alt char set- norm inverse, LC; no Flash (WR-only)
495 alternateCharset = false;
497 else if (addr == 0xC00F)
499 alternateCharset = true;
501 else if ((addr & 0xFFF0) == 0xC010) // Keyboard strobe
503 //Actually, according to the A2 ref, this should do nothing since a write
504 //is immediately preceded by a read leaving it in the same state it was...
507 else if (addr == 0xC050)
511 else if (addr == 0xC051)
515 else if (addr == 0xC052)
519 else if (addr == 0xC053)
523 else if (addr == 0xC054)
525 displayPage2 = false;
527 else if (addr == 0xC055)
531 else if (addr == 0xC056)
535 else if (addr == 0xC057)
539 else if ((addr & 0xFFFB) == 0xC080)
542 WriteLog("LC(R): $C080 49280 OECG R Read RAM bank 2; no write\n");
544 //$C080 49280 OECG R Read RAM bank 2; no write
545 visibleBank = LC_BANK_2;
549 else if ((addr & 0xFFFB) == 0xC081)
552 WriteLog("LC(R): $C081 49281 OECG RR Read ROM; write RAM bank 2\n");
554 //$C081 49281 ROMIN OECG RR Read ROM; write RAM bank 2
555 visibleBank = LC_BANK_2;
559 else if ((addr & 0xFFFB) == 0xC082)
562 WriteLog("LC(R): $C082 49282 OECG R Read ROM; no write\n");
564 //$C082 49282 OECG R Read ROM; no write
565 visibleBank = LC_BANK_2;
569 else if ((addr & 0xFFFB) == 0xC083)
572 WriteLog("LC(R): $C083 49283 OECG RR Read/Write RAM bank 2\n");
574 //$C083 49283 LCBANK2 OECG RR Read/write RAM bank 2
575 visibleBank = LC_BANK_2;
579 else if ((addr & 0xFFFB) == 0xC088)
582 WriteLog("LC(R): $C088 49288 OECG R Read RAM bank 1; no write\n");
584 //$C088 49288 OECG R Read RAM bank 1; no write
585 visibleBank = LC_BANK_1;
589 else if ((addr & 0xFFFB) == 0xC089)
592 WriteLog("LC(R): $C089 49289 OECG RR Read ROM; write RAM bank 1\n");
594 //$C089 49289 OECG RR Read ROM; write RAM bank 1
595 visibleBank = LC_BANK_1;
599 else if ((addr & 0xFFFB) == 0xC08A)
602 WriteLog("LC(R): $C08A 49290 OECG R Read ROM; no write\n");
604 //$C08A 49290 OECG R Read ROM; no write
605 visibleBank = LC_BANK_1;
609 else if ((addr & 0xFFFB) == 0xC08B)
612 WriteLog("LC(R): $C08B 49291 OECG RR Read/Write RAM bank 1\n");
614 //$C08B 49291 OECG RR Read/write RAM bank 1
615 visibleBank = LC_BANK_1;
619 //This is determined by which slot it is in--this assumes slot 6. !!! FIX !!!
620 else if ((addr & 0xFFF8) == 0xC0E0)
622 floppyDrive.ControlStepper(addr & 0x07);
624 else if ((addr & 0xFFFE) == 0xC0E8)
626 floppyDrive.ControlMotor(addr & 0x01);
628 else if ((addr & 0xFFFE) == 0xC0EA)
630 floppyDrive.DriveEnable(addr & 0x01);
632 else if (addr == 0xC0EC)
634 //change this to Write()? (and the other to Read()?) Dunno. Seems to work OK, but still...
635 floppyDrive.ReadWrite();
637 else if (addr == 0xC0ED)
639 floppyDrive.SetLatchValue(b);
641 else if (addr == 0xC0EE)
643 floppyDrive.SetReadMode();
645 else if (addr == 0xC0EF)
647 floppyDrive.SetWriteMode();
649 //Still need to add missing I/O switches here...
655 if (addr <= 0xDFFF && visibleBank == LC_BANK_1)
656 ram[addr - 0x1000] = b;
668 // Load a file into RAM/ROM image space
670 bool LoadImg(char * filename, uint8 * ram, int size)
672 FILE * fp = fopen(filename, "rb");
677 fread(ram, 1, size, fp);
683 static void SaveApple2State(const char * filename)
687 static bool LoadApple2State(const char * filename)
695 int main(int /*argc*/, char * /*argv*/[])
697 InitLog("./apple2.log");
699 srand(time(NULL)); // Initialize RNG
702 //Need to bankify this stuff for the IIe emulation...
703 memset(ram, 0, 0x10000);
704 memset(rom, 0, 0x10000);
706 // Set up V65C02 execution context
707 memset(&mainCPU, 0, sizeof(V65C02REGS));
708 mainCPU.RdMem = RdMem;
709 mainCPU.WrMem = WrMem;
710 mainCPU.cpuFlags |= V65C02_ASSERT_LINE_RESET;
712 if (!LoadImg(settings.BIOSPath, rom + 0xD000, 0x3000))
714 WriteLog("Could not open file '%s'!\n", settings.BIOSPath);
718 //This is now included...
719 /* if (!LoadImg(settings.diskPath, diskRom, 0x100))
721 WriteLog("Could not open file '%s'!\nDisk II will be unavailable!\n", settings.diskPath);
725 //Load up disk image from config file (for now)...
726 floppyDrive.LoadImage(settings.diskImagePath1, 0);
727 // floppyDrive.LoadImage(settings.diskImagePath2, 1);
728 // floppyDrive.LoadImage("./disks/temp.nib", 1); // Load temp .nib file into second drive...
730 //Kill the DOS ROM in slot 6 for now...
732 memcpy(rom + 0xC600, diskROM, 0x100);
734 WriteLog("About to initialize video...\n");
737 std::cout << "Aborting!" << std::endl;
741 // Have to do this *after* video init but *before* sound init...!
742 //Shouldn't be necessary since we're not doing emulation in the ISR...
743 if (settings.autoStateSaving)
745 // Load last state from file...
746 if (!LoadApple2State(settings.autoStatePath))
747 WriteLog("Unable to use Apple2 state file \"%s\"!\n", settings.autoStatePath);
753 if (!LoadImg("./BT1_6502_RAM_SPACE.bin", ram, 0x10000))
755 cout << "Couldn't load state file!" << endl;
756 cout << "Aborting!!" << endl;
761 //-- -- -- -- ----- -----
762 //00 75 3B 53 FD 01 41 44
764 mainCPU.cpuFlags = 0;
774 displayPage2 = false;
781 memcpy(ram + 0xD000, ram + 0xC000, 0x1000);
784 WriteLog("About to initialize audio...\n");
786 SDL_EnableUNICODE(1); // Needed to do key translation shit
788 gui = new GUI(surface); // Set up the GUI system object...
789 gui->AddMenuTitle("Apple2");
790 gui->AddMenuItem("Test!", TestWindow/*, hotkey*/);
791 gui->AddMenuItem("");
792 gui->AddMenuItem("Quit", QuitEmulator, SDLK_q);
793 gui->CommitItemsToMenu();
795 SetupBlurTable(); // Set up the color TV emulation blur table
796 running = true; // Set running status...
798 InitializeEventList(); // Clear the event list before we use it...
799 SetCallbackTime(FrameCallback, 16666.66666667); // Set frame to fire at 1/60 s interval
800 SetCallbackTime(BlinkTimer, 250000); // Set up blinking at 1/4 s intervals
801 startTicks = SDL_GetTicks();
803 WriteLog("Entering main loop...\n");
806 double timeToNextEvent = GetTimeToNextEvent();
807 Execute65C02(&mainCPU, USEC_TO_M6502_CYCLES(timeToNextEvent));
808 //We MUST remove a frame's worth of time in order for the CPU to function... !!! FIX !!!
809 //(Fix so that this is not a requirement!)
810 //Fixed, but mainCPU.clock is destroyed in the bargain. Oh well.
811 // mainCPU.clock -= USEC_TO_M6502_CYCLES(timeToNextEvent);
812 // Handle CPU time delta for sound...
813 AddToSoundTimeBase(USEC_TO_M6502_CYCLES(timeToNextEvent));
817 if (settings.autoStateSaving)
819 // Save state here...
820 SaveApple2State(settings.autoStatePath);
822 floppyDrive.SaveImage();
837 -----------------------
838 space $A0 $A0 $A0 $A0 No xlation
839 RETURN $8D $8D $8D $8D No xlation
840 0 $B0 $B0 $B0 $B0 Need to screen shift+0 (?)
841 1! $B1 $B1 $A1 $A1 No xlation
842 2" $B2 $B2 $A2 $A2 No xlation
843 3# $B3 $B3 $A3 $A3 No xlation
844 4$ $B4 $B4 $A4 $A4 No xlation
845 5% $B5 $B5 $A5 $A5 No xlation
846 6& $B6 $B6 $A6 $A6 No xlation
847 7' $B7 $B7 $A7 $A7 No xlation
848 8( $B8 $B8 $A8 $A8 No xlation
849 9) $B9 $B9 $A9 $A9 No xlation
850 :* $BA $BA $AA $AA No xlation
851 ;+ $BB $BB $AB $AB No xlation
852 ,< $AC $AC $BC $BC No xlation
853 -= $AD $AD $BD $BD No xlation
854 .> $AE $AE $BE $BE No xlation
855 /? $AF $AF $BF $BF No xlation
868 M $CD $8D $DD $9D -> ODD
869 N^ $CE $8E $DE $9E -> ODD
871 P@ $D0 $90 $C0 $80 Need to xlate CTL+SHFT+P & SHFT+P (?)
884 ESC $9B $9B $9B $9B No xlation
887 static void FrameCallback(void)
891 while (SDL_PollEvent(&event))
896 if (event.key.keysym.unicode != 0)
898 //Need to do some key translation here, and screen out non-apple keys as well...
899 if (event.key.keysym.sym == SDLK_TAB) // Prelim key screening...
902 lastKeyPressed = event.key.keysym.unicode;
904 //kludge: should have a caps lock thingy here...
905 //or all uppercase for ][+...
906 if (lastKeyPressed >= 'a' && lastKeyPressed <='z')
907 lastKeyPressed &= 0xDF; // Convert to upper case...
910 // CTRL+RESET key emulation (mapped to CTRL+`)
911 // This doesn't work...
912 // if (event.key.keysym.sym == SDLK_BREAK && (event.key.keysym.mod & KMOD_CTRL))
913 // if (event.key.keysym.sym == SDLK_PAUSE && (event.key.keysym.mod & KMOD_CTRL))
914 if (event.key.keysym.sym == SDLK_BACKQUOTE && (event.key.keysym.mod & KMOD_CTRL))
915 //NOTE that this shouldn't take place until the key is lifted... !!! FIX !!!
916 //ALSO it seems to leave the machine in an inconsistent state vis-a-vis the language card...
917 mainCPU.cpuFlags |= V65C02_ASSERT_LINE_RESET;
919 if (event.key.keysym.sym == SDLK_RIGHT)
920 lastKeyPressed = 0x15, keyDown = true;
921 else if (event.key.keysym.sym == SDLK_LEFT)
922 lastKeyPressed = 0x08, keyDown = true;
924 // Use ALT+Q to exit, as well as the usual window decoration method
925 if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_ALT))
928 if (event.key.keysym.sym == SDLK_F12)
929 dumpDis = !dumpDis; // Toggle the disassembly process
930 else if (event.key.keysym.sym == SDLK_F11)
931 floppyDrive.LoadImage("./disks/bt1_char.dsk");//Kludge to load char disk...
932 else if (event.key.keysym.sym == SDLK_F9)
934 floppyDrive.CreateBlankImage();
935 // SpawnMessage("Image cleared...");
937 else if (event.key.keysym.sym == SDLK_F10)
939 floppyDrive.SwapImages();
940 // SpawnMessage("Image swapped...");
943 if (event.key.keysym.sym == SDLK_F2)// Toggle the palette
945 else if (event.key.keysym.sym == SDLK_F3)// Cycle through screen types
948 // if (event.key.keysym.sym == SDLK_F5) // Temp GUI launch key
949 if (event.key.keysym.sym == SDLK_F1) // GUI launch key
950 //NOTE: Should parse the output to determine whether or not the user requested
951 // to quit completely... !!! FIX !!!
960 //ick. HandleSoundAtFrameEdge(); // Sound stuff... (ick)
962 SetCallbackTime(FrameCallback, 16666.66666667);
964 //Instead of this, we should yield remaining time to other processes... !!! FIX !!!
966 //nope. SDL_Delay(10);
967 while (SDL_GetTicks() - startTicks < 16); // Wait for next frame...
968 startTicks = SDL_GetTicks();
971 static void BlinkTimer(void)
974 SetCallbackTime(BlinkTimer, 250000); // Set up blinking at 1/4 sec intervals