]> Shamusworld >> Repos - thunder/blob - src/thunder.cpp
Oops, forgot to pull first before the changes. :-P
[thunder] / src / thunder.cpp
1 //
2 // Thunder: A Rolling Thunder Emulator
3 //
4 // by James Hammons
5 // (C) 2004, 2023 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  -----------------------------------------------------------
11 // JLH  07/23/2009  Added changelog ;-)
12 // JLH  08/12/2009  Stabilized emulation so that it works
13 // JLH  04/04/2014  Converted to SDL 2
14 // JLH  04/17/2014  Removed a metric fuck-tonne of cruft, added YM2151 & MCU
15 // JLH  01/13/2023  Finally fixed the sprite lag problem  :-D
16 //
17
18 #define THUNDER_VERSION         "1.2.1"
19
20 #include <SDL.h>
21 #include <string>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <time.h>
26 #include "gui.h"
27 #include "log.h"
28 #include "psg.h"
29 #include "screen.h"
30 #include "sound.h"
31 #include "v63701.h"
32 #include "v6809.h"
33 #include "video.h"
34 #include "ym2151.h"
35
36 #define ROM1   "rt3-1b.9c"
37 #define ROM2   "rt3-2b.12c"
38 #define ROM3   "rt3-3.12d"
39 #define ROM4   "rt1-4.6b"
40 #define ROM5   "rt1-5.4r"
41 #define ROM6   "rt1-6.4s"
42 #define ROM7   "rt1-7.7r"
43 #define ROM8   "rt1-8.7s"
44 #define ROM9   "rt1-9.12h"
45 #define ROM10  "rt1-10.12k"
46 #define ROM11  "rt1-11.12l"
47 #define ROM12  "rt1-12.12m"
48 #define ROM13  "rt1-13.12p"
49 #define ROM14  "rt1-14.12r"
50 #define ROM15  "rt1-15.12t"
51 #define ROM16  "rt1-16.12u"
52 #define ROM17  "rt1-17.f1"
53 #define ROM18  "rt1-18.h1"
54 #define ROM19  "rt1-19.k1"
55 #define ROM20  "rt1-20.m1"
56 #define ROM21  "rt1-21.f3"
57 #define ROM22  "rt1-22.h3"
58 #define PROM1  "mb7124e.3r"
59 #define PROM2  "mb7116e.3s"
60 #define PROM3  "mb7138h.4v"
61 #define PROM4  "mb7138h.6v"
62 #define PROM5  "mb7112e.6u"
63 #define MCUROM "rt1-mcu.bin"
64
65 // Global defines
66
67 uint8_t gram1[0x10000], grom1[0x10000], grom2[0x10000];
68 uint8_t grom3[0x8000], data_rom[0x40000], spr_rom[0x80000], voice_rom[0x20000];
69 uint8_t charROM[0x60000];               // Character ROM
70 uint8_t mcuMem[0x10000];                // 64K for MCU
71
72 // CPU execution contexts
73 V6809REGS cpu1, cpu2;
74 V63701REGS mcu;
75
76 // Bank switch addresses
77 uint32_t banksw1, banksw2;
78
79 // MCU inputs
80 Byte input1, input2, input3, input4, input5;
81
82 // Copy sprites flag
83 bool copySprites = false;
84
85 // Function prototypes
86 uint8_t MCUReadMemory(uint16_t address);
87 void MCUWriteMemory(uint16_t address, uint8_t data);
88
89 //
90 // Read a byte from memory
91 //
92 uint8_t MainReadMemory(uint16_t addr)
93 {
94         uint8_t b;
95
96         if (addr < 0x8000)
97         {
98                 // Memory shared with MCU (CPU #1 only! CPU #2 does not)
99                 if ((addr >= 0x4000) && (addr <= 0x43FF))
100                         return mcuMem[addr - 0x3000];
101
102                 if (addr >= 0x6000)
103                         return data_rom[banksw1 + (addr - 0x6000)];     // Get char data
104
105                 return gram1[addr];
106         }
107
108         return grom1[addr];
109 }
110
111 //
112 // Write a byte to memory
113 //
114 void MainWriteMemory(uint16_t address, uint8_t data)
115 {
116         if (address == 0x6000)
117                 SpawnSound(GAMESOUND, gram1[0x6200], 0);        // Do voice chan 1
118         if (address == 0x6400)
119                 SpawnSound(GAMESOUND, gram1[0x6600], 1);        // Do voice chan 2
120         if (address == 0x6800)
121                 banksw1 = (uint32_t)data << 13;                         // Set char data bankswitch base address
122
123         // Memory shared with MCU (CPU #1 only! CPU #2 does not)
124         if ((address >= 0x4000) && (address <= 0x43FF))
125                 mcuMem[address - 0x3000] = data;
126         else
127                 gram1[address] = data;
128
129         if (address == 0x5FF2)
130                 copySprites = true;
131         if (address == 0x8800)
132                 charBankSwitch = false;         // Char banksw1
133         if (address == 0x8C00)
134                 charBankSwitch = true;          // Char banksw2
135         if (address == 0x8400)                  // Frame go strobe? VBlank acknowledge?
136                 ClearLineOfCurrentV6809(V6809_LINE_IRQ); // IRQ Ack
137 }
138
139 //
140 // Read a byte from memory (2nd processor)
141 //
142 uint8_t SubReadMemory(uint16_t address)
143 {
144         if (address < 0x8000)
145         {
146                 if (address < 0x2000)
147                         return gram1[address + 0x4000];
148                 else if ((address >= 0x2000) && (address < 0x6000))
149                         return gram1[address - 0x2000];
150                 else if (address >= 0x6000)
151                         return grom3[banksw2 + (address - 0x6000)];
152         }
153
154         return grom2[address];
155 }
156
157 //
158 // Write a byte to memory (2nd processor)
159 //
160 void SubWriteMemory(uint16_t address, uint8_t data)
161 {
162         // Set sprite data bank switch
163         if (address == 0xD803)
164                 banksw2 = (uint32_t)(data & 0x03) << 13;
165
166         if (address < 0x2000)
167                 gram1[address + 0x4000] = data;
168
169         if ((address >= 0x2000) && (address < 0x6000))
170                 gram1[address - 0x2000] = data;
171
172         if (address == 0x1FF2)
173                 copySprites = true;
174
175         if (address == 0x8800)
176                 ClearLineOfCurrentV6809(V6809_LINE_IRQ); // IRQ Ack
177 }
178
179 uint8_t MCUReadMemory(uint16_t address)
180 {
181         if (address < 0x20)
182                 return InternalRegisterRead(address);
183         else if ((address >= 0x1000) && (address <= 0x113F))
184                 return ReadPSG(address - 0x1000);
185         else if ((address >= 0x2000) && (address <= 0x2001))
186                 return YMReadReg(0);
187         // Various joystick + buttons; all are active low.
188         else if (address == 0x2020)
189                 return input1.byte;
190         else if (address == 0x2021)
191                 return input2.byte;
192         // This is DSW1 & 2. All switch settings are active low.
193         else if (address == 0x2030)
194                 return input4.byte;
195         else if (address == 0x2031)
196                 return input5.byte;
197
198         return mcuMem[address];
199 }
200
201 void MCUWriteMemory(uint16_t address, uint8_t data)
202 {
203         static uint8_t ymRegister;
204
205         if (address < 0x20)
206         {
207                 InternalRegisterWrite(address, data);
208                 return;
209         }
210         else if (((address >= 0x4000) && (address <= 0xBFFF))
211                 || (address >= 0xF000))
212                 return;
213         else if ((address >= 0x1000) && (address <= 0x113F))
214         {
215                 WritePSG(address - 0x1000, data);
216                 return;
217         }
218         else if (address == 0x2000)
219         {
220                 ymRegister = data;
221                 return;
222         }
223         else if (address == 0x2001)
224         {
225                 YMWriteReg(0, ymRegister, data);
226                 return;
227         }
228
229         // RAM is from $0 - $3FFF, $C000 - $EFFF
230         mcuMem[address] = data;
231 }
232
233 uint8_t V63701ReadPort1(void)
234 {
235 //      printf("V63701ReadPort1: Read $%02X...\n", input3.byte);
236         return input3.byte;
237 }
238
239 uint8_t V63701ReadPort2(void)
240 {
241         return 0xFF;
242 }
243
244 void V63701WritePort1(uint8_t data)
245 {
246 //      printf("V63701WritePort1: Wrote $%02X...\n", data);
247 }
248
249 void V63701WritePort2(uint8_t data)
250 {
251 //      printf("V63701WritePort2: Wrote $%02X...\n", data);
252 }
253
254 //
255 // Generic Load file into image space
256 // (No error checking performed!  Responsibility of caller!)
257 //
258 bool LoadImg(const char * filename, uint8_t * mem, uint32_t address, uint32_t length)
259 {
260         char path[128];
261
262         strcpy(path, "./ROMs/");
263         strcat(path, filename);
264         FILE * file = fopen(path, "rb");
265
266         if (!file)
267         {
268                 printf("Could not open file \"%s\"!\n", filename);
269                 return false;
270         }
271
272         size_t ignored = fread(&mem[address], 1, length, file);
273         fclose(file);
274
275         return true;
276 }
277
278 //
279 // Read color PROMs
280 //
281 bool ReadColorPROMs(void)
282 {
283         FILE * file1 = fopen("./ROMs/" PROM3, "rb");
284
285         if (file1)
286         {
287                 for(int i=0; i<256; i++) // Load char pallete with PROM values
288                         for(int j=0; j<8; j++)
289                                 ccolor[i][j] = (uint8_t)fgetc(file1);
290
291                 fclose(file1);
292         }
293
294         file1 = fopen("./ROMs/" PROM4, "rb");
295
296         if (file1)
297         {
298                 for(int i=0; i<128; i++) // Load sprite pallete with PROM values
299                         for(int j=0; j<16; j++)
300                                 scolor[i][j] = (uint8_t)fgetc(file1);
301
302                 fclose(file1);
303         }
304
305         file1 = fopen("./ROMs/" PROM1, "rb");
306         FILE * file2 = fopen("./ROMs/" PROM2, "rb");
307
308         // If open was successful...
309         if (file1 && file2)
310         {
311                 // Palette is 12-bit RGB, we stretch it to 24-bit
312                 for(int i=0; i<256; i++)
313                 {
314                         uint8_t c1 = fgetc(file1);
315                         uint8_t c2 = fgetc(file2);
316                         uint8_t r = (uint8_t)c1 & 0x0F;
317                         uint8_t g = (uint8_t)c1 >> 4;
318                         uint8_t b = (uint8_t)c2;
319                         palette[i] = 0xFF000000 | (b << 20) | (b << 16) | (g << 12) | (g << 8) | (r << 4) | r;
320                 }
321
322                 fclose(file1);
323                 fclose(file2);
324         }
325
326         // PROM5 has the following in it (tile address decoder):
327         // 00:  00 20 40 60  02 22 42 62  04 24 44 64  06 26 46 66
328         // 10:  88 A8 C8 E8  8A AA CA EA  8C AC CC EC  8E AE CE EE
329
330         if (!file1)
331         {
332                 printf("Could not open PROM files!\n");
333                 return false;
334         }
335
336         return true;
337 }
338
339 //
340 // Unpack font data
341 //
342 bool UnpackFonts(void)
343 {
344         // 0x4000 $800 chars
345         FILE * file1 = fopen("./ROMs/" ROM7, "rb");
346         FILE * file2 = fopen("./ROMs/" ROM8, "rb");
347
348         if (!file1 || !file2)
349         {
350                 printf("Could not open either " ROM7 " or " ROM8 "!\n");
351                 return false;
352         }
353
354         for(long i=0; i<0x40000; i+=64)
355         {
356                 for(int j=0; j<64; j+=8)
357                 {
358                         uint8_t b1 = (uint8_t)fgetc(file1);
359                         uint8_t b2 = (uint8_t)fgetc(file1);
360                         uint8_t b3 = (uint8_t)fgetc(file2) ^ 0xFF;
361                         charROM[i + j + 0] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
362                         charROM[i + j + 1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
363                         charROM[i + j + 2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
364                         charROM[i + j + 3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
365                         charROM[i + j + 4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
366                         charROM[i + j + 5] = (b3 & 0x04)        | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
367                         charROM[i + j + 6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
368                         charROM[i + j + 7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
369                 }
370         }
371
372         fclose(file1);
373         fclose(file2);
374
375         file1 = fopen("./ROMs/" ROM5, "rb");
376         file2 = fopen("./ROMs/" ROM6, "rb");
377
378         if (!file1 || !file2)
379         {
380                 printf("Could not open either " ROM5 " or " ROM6 "!\n");
381                 return false;
382         }
383
384         for(long i=0x40000; i<0x60000; i+=64)
385         {
386                 for(int j=0; j<64; j+=8)
387                 {
388                         uint8_t b1 = (uint8_t)fgetc(file1);
389                         uint8_t b2 = (uint8_t)fgetc(file1);
390                         uint8_t b3 = (uint8_t)fgetc(file2) ^ 0xFF;
391                         charROM[i + j + 0] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
392                         charROM[i + j + 1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
393                         charROM[i + j + 2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
394                         charROM[i + j + 3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
395                         charROM[i + j + 4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
396                         charROM[i + j + 5] = (b3 & 0x04)        | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
397                         charROM[i + j + 6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
398                         charROM[i + j + 7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
399                 }
400         }
401
402         fclose(file1);
403         fclose(file2);
404
405         return true;
406 }
407
408 //
409 // Main loop
410 //
411 int main(int argc, char * argv[])
412 {
413         InitLog("thunder.log");
414
415         bool running;                                   // CPU running state flag...
416         SDL_Event event;                                // SDL "event"
417         uint32_t ticks, oldTicks;
418         uint8_t frameTickCount = 0;
419
420         printf("THUNDER v" THUNDER_VERSION " by James Hammons\n");
421         printf("Serial #20230113 / Prerelease\n");
422         printf("© 2003, 2023 Underground Software\n\n");
423         printf("This emulator is free software. If you paid for it you were RIPPED OFF\n\n");
424
425 //      SDL_WM_SetCaption("Thunder v"THUNDER_VERSION" ", "Thunder");
426
427         printf("Loading ROMs...\n");
428
429         if (!ReadColorPROMs())
430                 return -1;
431
432         // Load $8000-$FFFF 1st ROM
433         if (!LoadImg(ROM1, grom1, 0x8000, 0x8000))
434                 return -1;
435
436          // Load $8000-$FFFF 2nd ROM
437         if (!LoadImg(ROM2, grom2, 0x8000, 0x8000))
438                 return -1;
439
440         // Load 3rd ROM into its own space
441         if (!LoadImg(ROM3, grom3, 0, 0x8000))
442                 return -1;
443
444         if (!LoadImg(ROM17, data_rom, 0,       0x10000))
445                 return -1;
446
447         if (!LoadImg(ROM18, data_rom, 0x10000, 0x10000))
448                 return -1;
449
450         if (!LoadImg(ROM19, data_rom, 0x20000, 0x10000))
451                 return -1;
452
453         if (!LoadImg(ROM20, data_rom, 0x30000, 0x10000))
454                 return -1;
455
456         if (!LoadImg(ROM9,  spr_rom, 0,       0x10000))
457                 return -1;
458
459         if (!LoadImg(ROM10, spr_rom, 0x10000, 0x10000))
460                 return -1;
461
462         if (!LoadImg(ROM11, spr_rom, 0x20000, 0x10000))
463                 return -1;
464
465         if (!LoadImg(ROM12, spr_rom, 0x30000, 0x10000))
466                 return -1;
467
468         if (!LoadImg(ROM13, spr_rom, 0x40000, 0x10000))
469                 return -1;
470
471         if (!LoadImg(ROM14, spr_rom, 0x50000, 0x10000))
472                 return -1;
473
474         if (!LoadImg(ROM15, spr_rom, 0x60000, 0x10000))
475                 return -1;
476
477         if (!LoadImg(ROM16, spr_rom, 0x70000, 0x10000))
478                 return -1;
479
480         if (!LoadImg(ROM21, voice_rom, 0, 0x10000))
481                 return -1;
482
483         if (!LoadImg(ROM22, voice_rom, 0x10000, 0x10000))
484                 return -1;
485
486         // Load 5, 6, 7, 8th ROMs
487         if (!UnpackFonts())
488                 return -1;
489
490         // Load MCU program + data
491         if (!LoadImg(MCUROM, mcuMem, 0xF000, 0x1000))
492                 return -1;
493
494         if (!LoadImg(ROM4, mcuMem, 0x4000, 0x8000))
495                 return -1;
496
497         // Set up V6809, V63701 execution contexts
498         memset(&cpu1, 0, sizeof(V6809REGS));
499         cpu1.RdMem = MainReadMemory;
500         cpu1.WrMem = MainWriteMemory;
501         cpu1.cpuFlags |= V6809_LINE_RESET;
502
503         memset(&cpu2, 0, sizeof(V6809REGS));
504         cpu2.RdMem = SubReadMemory;
505         cpu2.WrMem = SubWriteMemory;
506         cpu2.cpuFlags |= V6809_LINE_RESET;
507
508         memset(&mcu, 0, sizeof(V63701REGS));
509         mcu.RdMem = MCUReadMemory;
510         mcu.WrMem = MCUWriteMemory;
511         mcu.cpuFlags |= V63701_LINE_RESET;
512
513         running = true;
514
515         // Set all inputs to inactive...
516         input1.byte = input2.byte = input3.byte = 0xFF;
517         banksw1 = 0;
518         banksw2 = 0;
519         InitGUI();                 // Reset # of coins
520
521         // Set up DIP switches...
522         input4.bit.b0 = 1;              // DSW B-0: Continues (1 = 6, 0 = 3)
523         input4.bit.b1 = 1;              // DSW B-2: ???
524         input4.bit.b2 = 1;              // DSW B-4: Difficulty (1 = normal, 0 = easy)
525         input4.bit.b3 = 1;              // DSW B-6: Bonus lives (70K/200K = 1, 100K/300K = 0)
526         input4.bit.b4 = 1;              // DSW A-0: Coin #2 credit
527         input4.bit.b5 = 1;              // DSW A-2: Freeze mode (0 = freeze)
528         input4.bit.b6 = 1;              // DSW A-4: Attract mode sound (1 = on)
529         input4.bit.b7 = 1;              // DSW A-6: Coin #1 credit
530
531         input5.bit.b0 = 1;              // DSW B-1: Cabinet type (1 = A, 0 = B)
532         input5.bit.b1 = 0;              // DSW B-3: Level select (0 = on)
533         input5.bit.b2 = 0;              // DSW B-5: Time (1 = 120, 0 = 150)
534         input5.bit.b3 = 0;              // DSW B-7: Lives (1 = 3, 0 = 5)
535         input5.bit.b4 = 1;              // DSW A-1: Coin #2 credit
536         input5.bit.b5 = 1;              // DSW A-3: Invulnerability (0 = on)
537         input5.bit.b6 = 1;              // DSW A-5: Coin #1 credit
538         input5.bit.b7 = 1;              // DSW A-7: Service mode
539
540 WriteLog("About to set up screen...\n");
541         InitVideo();
542
543         oldTicks = SDL_GetTicks();
544
545 WriteLog("About to set up audio...\n");
546         InitSound();
547
548 WriteLog("About to enter main loop...\n");
549         while (running)
550         {
551 //              HandleGUIDebounce();                                    // Debounce GUI keys
552
553 // Dipswitches are presented to the main CPUs as 0 or 1 at locations
554 // $423D - $425B by the MCU
555
556                 // SDL key handling...
557
558                 SDL_Event event;
559
560                 while (SDL_PollEvent(&event))
561                 {
562                         switch (event.type)
563                         {
564                         case SDL_KEYDOWN:
565                                 if (event.key.keysym.sym == SDLK_ESCAPE)
566                                         running = false;
567                                 // Do PCX snapshot (F4)
568                                 else if (event.key.keysym.sym == SDLK_F4)
569                                 {
570 //                                      SpawnSound(USERSOUND, SCAMERA);
571                                         SavePCXSnapshot();
572                                 }
573 #if 1
574                                 else if (event.key.keysym.sym == SDLK_5)
575                                         input1.bit.b5 = 0;
576                                 else if (event.key.keysym.sym == SDLK_1)
577                                         input1.bit.b6 = 0;
578                                 else if (event.key.keysym.sym == SDLK_2)
579                                         input2.bit.b6 = 0;
580                                 else if (event.key.keysym.sym == SDLK_c)        // Left
581                                         input3.bit.b5 = 0;
582                                 else if (event.key.keysym.sym == SDLK_z)        // Right
583                                         input3.bit.b4 = 0;
584                                 else if (event.key.keysym.sym == SDLK_s)        // Up
585                                         input2.bit.b2 = 0;
586                                 else if (event.key.keysym.sym == SDLK_x)        // Down
587                                         input1.bit.b2 = 0;
588                                 else if (event.key.keysym.sym == SDLK_k)        // Jump
589                                         input1.bit.b1 = 0;
590                                 else if (event.key.keysym.sym == SDLK_l)        // Fire
591                                         input3.bit.b3 = 0;
592
593                                 else if (event.key.keysym.sym == SDLK_F1)       // Service mode
594                                         input5.bit.b7 = !input5.bit.b7;
595
596                                 else if (event.key.keysym.sym == SDLK_q)
597                                         input4.bit.b7 = !input4.bit.b7;
598                                 else if (event.key.keysym.sym == SDLK_w)
599                                         input5.bit.b6 = !input5.bit.b6;
600                                 else if (event.key.keysym.sym == SDLK_e)
601                                         input5.bit.b5 = !input5.bit.b5;
602                                 else if (event.key.keysym.sym == SDLK_r)
603                                         input5.bit.b4 = !input5.bit.b4;
604                                 else if (event.key.keysym.sym == SDLK_t)
605                                         input5.bit.b3 = !input5.bit.b3;
606                                 else if (event.key.keysym.sym == SDLK_y)
607                                         input5.bit.b2 = !input5.bit.b2;
608                                 else if (event.key.keysym.sym == SDLK_u)
609                                         input5.bit.b1 = !input5.bit.b1;
610                                 else if (event.key.keysym.sym == SDLK_i)
611                                         input5.bit.b0 = !input5.bit.b0;
612
613 #else
614                                 else if (event.key.keysym.sym == SDLK_1)
615                                         input1.bit.b0 = 0;
616                                 else if (event.key.keysym.sym == SDLK_2)
617                                         input1.bit.b1 = 0;
618                                 else if (event.key.keysym.sym == SDLK_3)
619                                         input1.bit.b2 = 0;
620                                 else if (event.key.keysym.sym == SDLK_4)
621                                         input1.bit.b3 = 0;
622                                 else if (event.key.keysym.sym == SDLK_5)
623                                         input1.bit.b4 = 0;
624                                 else if (event.key.keysym.sym == SDLK_6)
625                                         input1.bit.b5 = 0;
626                                 else if (event.key.keysym.sym == SDLK_7)
627                                         input1.bit.b6 = 0;
628                                 else if (event.key.keysym.sym == SDLK_8)
629                                         input1.bit.b7 = 0;
630
631                                 else if (event.key.keysym.sym == SDLK_q)
632                                         input2.bit.b0 = 0;
633                                 else if (event.key.keysym.sym == SDLK_w)
634                                         input2.bit.b1 = 0;
635                                 else if (event.key.keysym.sym == SDLK_e)
636                                         input2.bit.b2 = 0;
637                                 else if (event.key.keysym.sym == SDLK_r)
638                                         input2.bit.b3 = 0;
639                                 else if (event.key.keysym.sym == SDLK_t)
640                                         input2.bit.b4 = 0;
641                                 else if (event.key.keysym.sym == SDLK_y)
642                                         input2.bit.b5 = 0;
643                                 else if (event.key.keysym.sym == SDLK_u)
644                                         input2.bit.b6 = 0;
645                                 else if (event.key.keysym.sym == SDLK_i)
646                                         input2.bit.b7 = 0;
647
648                                 else if (event.key.keysym.sym == SDLK_a)
649                                         input3.bit.b0 = 0;
650                                 else if (event.key.keysym.sym == SDLK_s)
651                                         input3.bit.b1 = 0;
652                                 else if (event.key.keysym.sym == SDLK_d)
653                                         input3.bit.b2 = 0;
654                                 else if (event.key.keysym.sym == SDLK_f)
655                                         input3.bit.b3 = 0;
656                                 else if (event.key.keysym.sym == SDLK_g)
657                                         input3.bit.b4 = 0;
658 #endif
659
660                                 break;
661                         case SDL_KEYUP:
662 #if 1
663                                 if (event.key.keysym.sym == SDLK_5)
664                                         input1.bit.b5 = 1;
665                                 else if (event.key.keysym.sym == SDLK_1)
666                                         input1.bit.b6 = 1;
667                                 else if (event.key.keysym.sym == SDLK_2)
668                                         input2.bit.b6 = 1;
669                                 else if (event.key.keysym.sym == SDLK_c)
670                                         input3.bit.b5 = 1;
671                                 else if (event.key.keysym.sym == SDLK_z)
672                                         input3.bit.b4 = 1;
673                                 else if (event.key.keysym.sym == SDLK_s)
674                                         input2.bit.b2 = 1;
675                                 else if (event.key.keysym.sym == SDLK_x)
676                                         input1.bit.b2 = 1;
677                                 else if (event.key.keysym.sym == SDLK_k)        // (Q)  Jump
678                                         input1.bit.b1 = 1;
679                                 else if (event.key.keysym.sym == SDLK_l)        // (E) Fire
680                                         input3.bit.b3 = 1;
681 #else
682                                 if (event.key.keysym.sym == SDLK_1)
683                                         input1.bit.b0 = 1;
684                                 else if (event.key.keysym.sym == SDLK_2)
685                                         input1.bit.b1 = 1;
686                                 else if (event.key.keysym.sym == SDLK_3)
687                                         input1.bit.b2 = 1;
688                                 else if (event.key.keysym.sym == SDLK_4)
689                                         input1.bit.b3 = 1;
690                                 else if (event.key.keysym.sym == SDLK_5)
691                                         input1.bit.b4 = 1;
692                                 else if (event.key.keysym.sym == SDLK_6)
693                                         input1.bit.b5 = 1;
694                                 else if (event.key.keysym.sym == SDLK_7)
695                                         input1.bit.b6 = 1;
696                                 else if (event.key.keysym.sym == SDLK_8)
697                                         input1.bit.b7 = 1;
698
699                                 else if (event.key.keysym.sym == SDLK_q)
700                                         input2.bit.b0 = 1;
701                                 else if (event.key.keysym.sym == SDLK_w)
702                                         input2.bit.b1 = 1;
703                                 else if (event.key.keysym.sym == SDLK_e)
704                                         input2.bit.b2 = 1;
705                                 else if (event.key.keysym.sym == SDLK_r)
706                                         input2.bit.b3 = 1;
707                                 else if (event.key.keysym.sym == SDLK_t)
708                                         input2.bit.b4 = 1;
709                                 else if (event.key.keysym.sym == SDLK_y)
710                                         input2.bit.b5 = 1;
711                                 else if (event.key.keysym.sym == SDLK_u)
712                                         input2.bit.b6 = 1;
713                                 else if (event.key.keysym.sym == SDLK_i)
714                                         input2.bit.b7 = 1;
715
716                                 else if (event.key.keysym.sym == SDLK_a)
717                                         input3.bit.b0 = 1;
718                                 else if (event.key.keysym.sym == SDLK_s)
719                                         input3.bit.b1 = 1;
720                                 else if (event.key.keysym.sym == SDLK_d)
721                                         input3.bit.b2 = 1;
722                                 else if (event.key.keysym.sym == SDLK_f)
723                                         input3.bit.b3 = 1;
724                                 else if (event.key.keysym.sym == SDLK_g)
725                                         input3.bit.b4 = 1;
726 #endif
727
728                                 break;
729                         }
730                 }
731
732 #if 0
733                                 if (keys[SDLK_ESCAPE])
734                                         running = false;                     // ESC to exit...
735
736                                 if (debounce)
737                                         debounce--;                          // Debounce toggle keys...
738                                 else
739                                 {
740                                         if (keys[SDLK_F1])
741                                         {
742                                                 self_test = !self_test;            // Self-test (F1-toggle)
743                                                 debounce = 10;                     // Key debounce value...
744                                         }
745                                         if (keys[SDLK_F2])
746                                         {
747                                                 gram1[0x4268] = 1;                 // Video test (F2)
748                                                 debounce = 10;                     // Key debounce value...
749                                         }
750                                         if (keys[SDLK_F12])
751                                         {
752                                                 scr_type = !scr_type;              // Toggle screen (F12)
753                                                 debounce = 10;                     // Key debounce value...
754                                         }
755                                         if (keys[SDLK_F3])
756                                         {
757                                                 show_scr = !show_scr;              // Toggle bkgrnd (F3)
758                                                 debounce = 10;
759                                         }
760                                         if (keys[SDLK_F6])
761                                         {
762                                                 enable_cpu = !enable_cpu;          // Toggle CPUs (F6)
763                                                 debounce = 10;
764                                         }
765                                         if (keys[SDLK_F5])
766                                         {
767                                                 refresh2 = !refresh2;             // Toggle 30/60Hz (F5)
768                                                 SetRefreshRate(refresh2);         // Inform GUI of refresh
769                                                 if (refresh2)
770                                                         SpawnMsg(M60FPS);
771                                                 else
772                                                         SpawnMsg(M30FPS);
773                                                 debounce = 10;                    // Key debounce value...
774                                         }
775                                         if (keys[SDLK_F4])                      // Do PCX snapshot (F4)
776                                         {
777                                                 SpawnSound(USERSOUND, SCAMERA);
778                                                 SnapPCX(screen);
779                                                 debounce = 10;
780                                         }
781                                         if (keys[SDLK_TAB])                      // Tab active/deactivate GUI
782                                         {
783                                                 if (ShowGUI())
784                                                         DeactivateGUI();
785                                                 else
786                                                         ActivateGUI();
787
788                                                 debounce = 10;
789                                         }
790                                 }
791                                 //if (keys[0x3E])  gram1[0x4247] = 1;  // Screen hold DS (F4)
792                                 if (keys[SDLK_RIGHT])                                           // Right arrow
793                                 {
794                                         if (ShowGUI())
795                                                 SelectRight();                     // If GUI active...
796                                         else
797                                         {
798                                                 if (!keys[SDLK_LEFT])                     // Disallow opposite directions @ same time
799                                                         gram1[0x427F] = 1;               // Stick right
800                                         }
801                                 }
802                                 if (keys[SDLK_LEFT])
803                                 {
804                                         if (ShowGUI())
805                                                 SelectLeft();                      // If GUI active...
806                                         else
807                                         {
808                                                 if (!keys[SDLK_RIGHT])                     // Disallow opposite directions@same time
809                                                 gram1[0x4281] = 1;               // Left arrow
810                                         }
811                                 }
812                                 if (keys[SDLK_UP])
813                                 {
814                                         if (ShowGUI())
815                                                 SelectUp();                        // If GUI active...
816                                         else
817                                         {
818                                                 if (!keys[SDLK_DOWN])                     // Disallow opposite directions@same time
819                                                         gram1[0x427B] = 1;               // Up arrow
820                                         }
821                                 }
822                                 if (keys[SDLK_DOWN])
823                                 {
824                                         if (ShowGUI())
825                                                 SelectDown();                                   // If GUI active...
826                                         else
827                                         {
828                                                 if (!keys[SDLK_UP])                             // Disallow opposite directions@same time
829                                                         gram1[0x427D] = 1;                      // Down arrow
830                                         }
831                                 }
832                                 if (keys[SDLK_RETURN])                                                  // Return
833                                 {
834                                         uint8_t retval = UserSelectedSomething();
835
836                                         if (retval == EXIT)
837                                                 running = false;
838
839                                         if (retval == REFRESH)
840                                         {
841                                                 refresh2 = !refresh2;
842                                                 SetRefreshRate(refresh2);
843                                         }
844                                 }
845
846                                 if (keys[SDLK_1])
847                                         gram1[0x427A] = 1;                      // (1)
848
849                                 if (keys[SDLK_2])
850                                         gram1[0x427C] = 1;                      // (2)
851
852                                 if (keys[SDLK_3])
853                                         gram1[0x427E] = 1;                      // (3)
854
855                                 if (keys[SDLK_5])
856                                         gram1[0x4280] = 1;                      // (5)
857
858                                 if (keys[SDLK_q] | keys[29])
859                                         gram1[0x4276] = 1;                      // (Q)  Jump
860
861                                 if (keys[SDLK_w])
862                                         gram1[0x426A] = 1;                      // (W)
863
864                                 if (fire_debounce)
865                                         fire_debounce--;
866
867                                 if (keys[SDLK_e] | keys[56])    // (E) Fire
868                                 {
869                                         if (!fire_debounce)
870                                         {
871                                                 gram1[0x4278] = 1;
872
873                                                 if (gram1[0x3F08] == 0xFF)              // Ugly kludge for debouncing gun
874                                                         fire_debounce = 8;
875                                                 else
876                                                         fire_debounce = 2;
877                                         }
878                                 }
879
880                                 if (keys[SDLK_r])
881                                         gram1[0x426C] = 1;                      // (R)
882
883                                 if (keys[SDLK_t])
884                                         gram1[0x4262] = 1;                      // (T)
885
886                                 if (keys[SDLK_y])
887                                         gram1[0x4260] = 1;                      // (Y)
888
889                                 if (keys[SDLK_F10])
890                                         gram1[0x41A5]++;                        // Coin? (F10)
891
892                                 if (keys[SDLK_z])
893                                         gram1[0x4189]++;                        // ? (Z) credits l dig
894
895                                 if (keys[SDLK_x])
896                                         gram1[0x418A]++;                        // ? (X) credits r dig
897
898                                 if (keys[SDLK_c])
899                                         gram1[0x418C]++;                        // ? (C) Start
900
901                                 if (keys[SDLK_v])
902                                         gram1[0x418D]++;                        // ? (V)
903
904                                 if (keys[SDLK_F7])
905                                         SpawnSound(USERSOUND, 0);       // Do user sound (F7)
906 #endif
907
908                 // We can do this here because we're not executing the cores yet.
909                 cpu1.cpuFlags |= V6809_LINE_IRQ;
910                 cpu2.cpuFlags |= V6809_LINE_IRQ;
911                 mcu.cpuFlags |= V63701_LINE_IRQ;
912 //                                      while (cpu1.clock < 25000)
913 // 1.538 MHz = 25633.333... cycles per frame (1/60 s)
914 // 25600 cycles/frame
915 // Setting interleave to 25 and below causes the V6809 core to hang...
916 // 32 gets to the title screen before hanging...
917 // 40 works, until it doesn't... :-P
918 // 640 * 40
919 // 800 * 32
920 // 20 seems to work...  :-)
921 // Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though.
922 //              for(int i=0; i<640; i++)
923                 for(int i=0; i<1280; i++)
924                 {
925                         // Gay, but what are ya gonna do?
926                         // There's better ways, such as keeping track of when slave writes to master, etc...
927 //                      Execute6809(&cpu1, 40);
928 //                      Execute6809(&cpu2, 40);
929                         Execute6809(&cpu1, 20);
930                         Execute6809(&cpu2, 20);
931
932                         // MCU runs at 1,536,000 Hz
933                         // 1536000 / 60 / 640 == 40
934 //                      Execute63701(&mcu, 40);
935                         Execute63701(&mcu, 20);
936                 }
937
938                 BlitChar(charROM, gram1);
939
940                 // Make sure that the sprite RAM lags by one frame...  :-)
941                 if (copySprites)
942                 {
943                         CopySprites();
944                         copySprites = false;
945                 }
946
947                 frameTickCount++;
948
949                 if (frameTickCount == 3)
950                         frameTickCount = 0;
951
952                 // Speed throttling happens here...
953                 // Actually, it's 16.66... Need to account for that somehow [DONE]
954                 while (SDL_GetTicks() - oldTicks < (16 + (frameTickCount == 2 ? 1 : 0)))
955                         SDL_Delay(1);                           // Release our timeslice...
956
957                 oldTicks = SDL_GetTicks();
958         }
959
960         SDL_Quit();
961         LogDone();
962
963         return 1;
964 }