]> Shamusworld >> Repos - thunder/blob - src/thunder.cpp
Added DIP switch fungibility, misc. code cleanups.
[thunder] / src / thunder.cpp
1 //
2 // Thunder: A Rolling Thunder Emulator
3 //
4 // by James Hammons
5 // (C) 2004, 2014 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 //
16
17 #define THUNDER_VERSION         "1.2.0"
18
19 #include <SDL2/SDL.h>
20 #include <string>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <time.h>
25 #include "gui.h"
26 #include "log.h"
27 #include "psg.h"
28 #include "screen.h"
29 #include "sound.h"
30 #include "v63701.h"
31 #include "v6809.h"
32 #include "video.h"
33 #include "ym2151.h"
34
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
66 // Global defines
67
68 uint8_t gram1[0x10000], grom1[0x10000], grom2[0x10000];
69 uint8_t grom3[0x8000], data_rom[0x40000], spr_rom[0x80000], voice_rom[0x20000];
70 uint8_t charROM[0x60000];               // Character ROM
71 uint8_t mcuMem[0x10000];                // 64K for MCU
72
73 // CPU execution contexts
74 V6809REGS cpu1, cpu2;
75 V63701REGS mcu;
76
77 // Bank switch addresses
78 uint32_t banksw1, banksw2;
79
80 // MCU inputs
81 Byte input1, input2, input3, input4, input5;
82
83 // Function prototypes
84 uint8_t MCUReadMemory(uint16_t address);
85 void MCUWriteMemory(uint16_t address, uint8_t data);
86
87
88 //
89 // Read a byte from memory
90 //
91 uint8_t MainReadMemory(uint16_t addr)
92 {
93         uint8_t b;
94
95         if (addr < 0x8000)
96         {
97                 // Memory shared with MCU (CPU #1 only! CPU #2 does not)
98                 if ((addr >= 0x4000) && (addr <= 0x43FF))
99                         return mcuMem[addr - 0x3000];
100
101                 if (addr >= 0x6000)
102                         return data_rom[banksw1 + (addr - 0x6000)];     // Get char data
103
104                 return gram1[addr];
105         }
106
107         return grom1[addr];
108 }
109
110
111 //
112 // Write a byte to memory
113 //
114 void MainWriteMemory(uint16_t address, uint8_t data)
115 {
116         extern bool disasm;
117
118         if (address == 0x6000)
119                 SpawnSound(GAMESOUND, gram1[0x6200], 0);        // Do voice chan 1
120         if (address == 0x6400)
121                 SpawnSound(GAMESOUND, gram1[0x6600], 1);        // Do voice chan 2
122         if (address == 0x6800)
123                 banksw1 = (uint32_t)data << 13;                         // Set char data bankswitch base address
124
125         // Memory shared with MCU (CPU #1 only! CPU #2 does not)
126         if ((address >= 0x4000) && (address <= 0x43FF))
127                 mcuMem[address - 0x3000] = data;
128         else
129                 gram1[address] = data;
130
131         if (address == 0x5FF2)
132                 CopySprites();
133         if (address == 0x8800)
134                 charBankSwitch = false;         // Char banksw1
135         if (address == 0x8C00)
136                 charBankSwitch = true;          // Char banksw2
137         if (address == 0x8400)          // Frame go strobe? VBlank acknowledge?
138         {
139 //              BlitChar(charROM, gram1);
140
141                 // IRQ Ack (may also be frame go...)
142                 ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);
143 #if 1
144         if (disasm)
145                 WriteLog("WriteMem: CPU #1 Acknowledging IRQ...\n", data);
146 #endif
147         }
148 }
149
150
151 //
152 // Read a byte from memory (2nd processor)
153 //
154 uint8_t SubReadMemory(uint16_t address)
155 {
156         if (address < 0x8000)
157         {
158                 if (address < 0x2000)
159                         return gram1[address + 0x4000];
160                 else if ((address >= 0x2000) && (address < 0x6000))
161                         return gram1[address - 0x2000];
162                 else if (address >= 0x6000)
163                         return grom3[banksw2 + (address - 0x6000)];
164         }
165
166         return grom2[address];
167 }
168
169
170 //
171 // Write a byte to memory (2nd processor)
172 //
173 void SubWriteMemory(uint16_t address, uint8_t data)
174 {
175         extern bool disasm;
176
177         // Set sprite data bank switch
178         if (address == 0xD803)
179                 banksw2 = (uint32_t)(data & 0x03) << 13;
180
181         if (address < 0x2000)
182                 gram1[address + 0x4000] = data;
183
184         if ((address >= 0x2000) && (address < 0x6000))
185                 gram1[address - 0x2000] = data;
186
187         if (address == 0x1FF2)
188                 CopySprites();
189
190         if (address == 0x8800)
191         {
192                 // IRQ Ack (may also be frame go...)
193                 ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);
194 #if 1
195         if (disasm)
196                 WriteLog("WriteMem: CPU #2 Acknowledging IRQ...\n", data);
197 #endif
198         }
199 }
200
201
202 uint8_t MCUReadMemory(uint16_t address)
203 {
204         if (address < 0x20)
205                 return InternalRegisterRead(address);
206         else if ((address >= 0x1000) && (address <= 0x113F))
207                 return ReadPSG(address - 0x1000);
208         else if ((address >= 0x2000) && (address <= 0x2001))
209                 return YMReadReg(0);
210         // Various joystick + buttons; all are active low.
211         else if (address == 0x2020)
212                 return input1.byte;
213         else if (address == 0x2021)
214                 return input2.byte;
215         // This is DSW1 & 2. All switch settings are active low.
216         else if (address == 0x2030)
217                 return input4.byte;
218         else if (address == 0x2031)
219                 return input5.byte;
220
221         return mcuMem[address];
222 }
223
224
225 void MCUWriteMemory(uint16_t address, uint8_t data)
226 {
227         static uint8_t ymRegister;
228
229         if (address < 0x20)
230         {
231                 InternalRegisterWrite(address, data);
232                 return;
233         }
234         else if (((address >= 0x4000) && (address <= 0xBFFF))
235                 || (address >= 0xF000))
236                 return;
237         else if ((address >= 0x1000) && (address <= 0x113F))
238         {
239                 WritePSG(address - 0x1000, data);
240                 return;
241         }
242         else if (address == 0x2000)
243         {
244                 ymRegister = data;
245                 return;
246         }
247         else if (address == 0x2001)
248         {
249                 YMWriteReg(0, ymRegister, data);
250                 return;
251         }
252
253         // RAM is from $0 - $3FFF, $C000 - $EFFF
254         mcuMem[address] = data;
255 }
256
257
258 uint8_t V63701ReadPort1(void)
259 {
260 //      printf("V63701ReadPort1: Read $%02X...\n", input3.byte);
261         return input3.byte;
262 }
263
264
265 uint8_t V63701ReadPort2(void)
266 {
267         return 0xFF;
268 }
269
270
271 void V63701WritePort1(uint8_t data)
272 {
273 //      printf("V63701WritePort1: Wrote $%02X...\n", data);
274 }
275
276
277 void V63701WritePort2(uint8_t data)
278 {
279 //      printf("V63701WritePort2: Wrote $%02X...\n", data);
280 }
281
282
283 //
284 // Generic Load file into image space
285 // (No error checking performed!  Responsibility of caller!)
286 //
287 bool LoadImg(const char * filename, uint8_t * mem, uint32_t address, uint32_t length)
288 {
289         char path[128];
290
291         strcpy(path, "./ROMs/");
292         strcat(path, filename);
293         FILE * file = fopen(path, "rb");
294
295         if (!file)
296         {
297                 printf("Could not open file \"%s\"!\n", filename);
298                 return false;
299         }
300
301         fread(&mem[address], 1, length, file);
302         fclose(file);
303
304         return true;
305 }
306
307
308 //
309 // Read color PROMs
310 //
311 bool ReadColorPROMs(void)
312 {
313         FILE * file1 = fopen("./ROMs/"PROM3, "rb");
314
315         if (file1)
316         {
317                 for(int i=0; i<256; i++) // Load char pallete with PROM values
318                         for(int j=0; j<8; j++)
319                                 ccolor[i][j] = (uint8_t)fgetc(file1);
320
321                 fclose(file1);
322         }
323
324         file1 = fopen("./ROMs/"PROM4, "rb");
325
326         if (file1)
327         {
328                 for(int i=0; i<128; i++) // Load sprite pallete with PROM values
329                         for(int j=0; j<16; j++)
330                                 scolor[i][j] = (uint8_t)fgetc(file1);
331
332                 fclose(file1);
333         }
334
335         file1 = fopen("./ROMs/"PROM1, "rb");
336         FILE * file2 = fopen("./ROMs/"PROM2, "rb");
337
338         // If open was successful...
339         if (file1 && file2)
340         {
341                 // Palette is 12-bit RGB, we stretch it to 24-bit
342                 for(int i=0; i<256; i++)
343                 {
344                         uint8_t c1 = fgetc(file1);
345                         uint8_t c2 = fgetc(file2);
346                         uint8_t r = (uint8_t)c1 & 0x0F;
347                         uint8_t g = (uint8_t)c1 >> 4;
348                         uint8_t b = (uint8_t)c2;
349                         palette[i] = 0xFF000000 | (b << 20) | (b << 16) | (g << 12) | (g << 8) | (r << 4) | r;
350                 }
351
352                 fclose(file1);
353                 fclose(file2);
354         }
355
356         // PROM5 has the following in it (tile address decoder):
357         // 00:  00 20 40 60  02 22 42 62  04 24 44 64  06 26 46 66
358         // 10:  88 A8 C8 E8  8A AA CA EA  8C AC CC EC  8E AE CE EE 
359
360         if (!file1)
361         {
362                 printf("Could not open PROM files!\n");
363                 return false;
364         }
365
366         return true;
367 }
368
369
370 //
371 // Unpack font data
372 //
373 bool UnpackFonts(void)
374 {
375         // 0x4000 $800 chars
376         FILE * file1 = fopen("./ROMs/"ROM7, "rb");
377         FILE * file2 = fopen("./ROMs/"ROM8, "rb");
378
379         if (!file1 || !file2)
380         {
381                 printf("Could not open either "ROM7" or "ROM8"!\n");
382                 return false;
383         }
384
385         for(long i=0; i<0x40000; i+=64)
386         {
387                 for(int j=0; j<64; j+=8)
388                 {
389                         uint8_t b1 = (uint8_t)fgetc(file1);
390                         uint8_t b2 = (uint8_t)fgetc(file1);
391                         uint8_t b3 = (uint8_t)fgetc(file2) ^ 0xFF;
392                         charROM[i + j + 0] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
393                         charROM[i + j + 1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
394                         charROM[i + j + 2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
395                         charROM[i + j + 3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
396                         charROM[i + j + 4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
397                         charROM[i + j + 5] = (b3 & 0x04)        | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
398                         charROM[i + j + 6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
399                         charROM[i + j + 7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
400                 }
401         }
402
403         fclose(file1);
404         fclose(file2);
405
406         file1 = fopen("./ROMs/"ROM5, "rb");
407         file2 = fopen("./ROMs/"ROM6, "rb");
408
409         if (!file1 || !file2)
410         {
411                 printf("Could not open either "ROM5" or "ROM6"!\n");
412                 return false;
413         }
414
415         for(long i=0x40000; i<0x60000; i+=64)
416         {
417                 for(int j=0; j<64; j+=8)
418                 {
419                         uint8_t b1 = (uint8_t)fgetc(file1);
420                         uint8_t b2 = (uint8_t)fgetc(file1);
421                         uint8_t b3 = (uint8_t)fgetc(file2) ^ 0xFF;
422                         charROM[i + j + 0] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
423                         charROM[i + j + 1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
424                         charROM[i + j + 2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
425                         charROM[i + j + 3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
426                         charROM[i + j + 4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
427                         charROM[i + j + 5] = (b3 & 0x04)        | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
428                         charROM[i + j + 6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
429                         charROM[i + j + 7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
430                 }
431         }
432
433         fclose(file1);
434         fclose(file2);
435
436         return true;
437 }
438
439
440 //
441 // Main loop
442 //
443 int main(int argc, char * argv[])
444 {
445         InitLog("thunder.log");
446
447         extern bool disasm;                             // From 'V6809.CPP'
448
449         bool running;                                   // CPU running state flag...
450         SDL_Event event;                                // SDL "event"
451         uint32_t ticks, oldTicks;
452         uint8_t frameTickCount = 0;
453
454         printf("THUNDER v"THUNDER_VERSION" by James Hammons\n");
455         printf("Serial #20149417 / Prerelease\n");
456         printf("© 2003, 2014 Underground Software\n\n");
457         printf("This emulator is free software. If you paid for it you were RIPPED OFF\n\n");
458
459 //      SDL_WM_SetCaption("Thunder v"THUNDER_VERSION" ", "Thunder");
460
461         printf("Loading ROMs...\n");
462
463         if (!ReadColorPROMs())
464                 return -1;
465
466         // Load $8000-$FFFF 1st ROM
467         if (!LoadImg(ROM1, grom1, 0x8000, 0x8000))
468                 return -1;
469
470          // Load $8000-$FFFF 2nd ROM
471         if (!LoadImg(ROM2, grom2, 0x8000, 0x8000))
472                 return -1;
473
474         // Load 3rd ROM into its own space
475         if (!LoadImg(ROM3, grom3, 0, 0x8000))
476                 return -1;
477
478         if (!LoadImg(ROM17, data_rom, 0,       0x10000))
479                 return -1;
480
481         if (!LoadImg(ROM18, data_rom, 0x10000, 0x10000))
482                 return -1;
483
484         if (!LoadImg(ROM19, data_rom, 0x20000, 0x10000))
485                 return -1;
486
487         if (!LoadImg(ROM20, data_rom, 0x30000, 0x10000))
488                 return -1;
489
490         if (!LoadImg(ROM9,  spr_rom, 0,       0x10000))
491                 return -1;
492
493         if (!LoadImg(ROM10, spr_rom, 0x10000, 0x10000))
494                 return -1;
495
496         if (!LoadImg(ROM11, spr_rom, 0x20000, 0x10000))
497                 return -1;
498
499         if (!LoadImg(ROM12, spr_rom, 0x30000, 0x10000))
500                 return -1;
501
502         if (!LoadImg(ROM13, spr_rom, 0x40000, 0x10000))
503                 return -1;
504
505         if (!LoadImg(ROM14, spr_rom, 0x50000, 0x10000))
506                 return -1;
507
508         if (!LoadImg(ROM15, spr_rom, 0x60000, 0x10000))
509                 return -1;
510
511         if (!LoadImg(ROM16, spr_rom, 0x70000, 0x10000))
512                 return -1;
513
514         if (!LoadImg(ROM21, voice_rom, 0, 0x10000))
515                 return -1;
516
517         if (!LoadImg(ROM22, voice_rom, 0x10000, 0x10000))
518                 return -1;
519
520         // Load 5, 6, 7, 8th ROMs
521         if (!UnpackFonts())
522                 return -1;
523
524         // Load MCU program + data
525         if (!LoadImg(MCUROM, mcuMem, 0xF000, 0x1000))
526                 return -1;
527
528         if (!LoadImg(ROM4, mcuMem, 0x4000, 0x8000))
529                 return -1;
530
531         // Set up V6809, V63701 execution contexts
532         memset(&cpu1, 0, sizeof(V6809REGS));
533         cpu1.RdMem = MainReadMemory;
534         cpu1.WrMem = MainWriteMemory;
535         cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET;
536
537         memset(&cpu2, 0, sizeof(V6809REGS));
538         cpu2.RdMem = SubReadMemory;
539         cpu2.WrMem = SubWriteMemory;
540         cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET;
541
542         memset(&mcu, 0, sizeof(V63701REGS));
543         mcu.RdMem = MCUReadMemory;
544         mcu.WrMem = MCUWriteMemory;
545         mcu.cpuFlags |= V63701_ASSERT_LINE_RESET;
546
547         running = true;
548
549         // Set all inputs to inactive...
550         input1.byte = input2.byte = input3.byte = 0xFF;
551         banksw1 = 0;
552         banksw2 = 0;
553         InitGUI();                 // Reset # of coins
554
555         // Set up DIP switches...
556         input4.bit.b0 = 1;              // DSW B-0: Contiues (1 = 6, 0 = 3)
557         input4.bit.b1 = 1;              // DSW B-2: ???
558         input4.bit.b2 = 1;              // DSW B-4: Difficulty (1 = normal, 0 = easy)
559         input4.bit.b3 = 1;              // DSW B-6: Bonus lives (70K/200K = 1, 100K/300K = 0)
560         input4.bit.b4 = 1;              // DSW A-0: Coin #2 credit
561         input4.bit.b5 = 1;              // DSW A-2: Freeze mode (0 = freeze)
562         input4.bit.b6 = 1;              // DSW A-4: Attract mode sound (1 = on)
563         input4.bit.b7 = 1;              // DSW A-6: Coin #1 credit
564
565         input5.bit.b0 = 1;              // DSW B-1: Cabinet type (1 = A, 0 = B)
566         input5.bit.b1 = 0;              // DSW B-3: Level select (0 = on)
567         input5.bit.b2 = 0;              // DSW B-5: Time (1 = 120, 0 = 150)
568         input5.bit.b3 = 0;              // DSW B-7: Lives (1 = 3, 0 = 5)
569         input5.bit.b4 = 1;              // DSW A-1: Coin #2 credit
570         input5.bit.b5 = 1;              // DSW A-3: Invulnerability (0 = on)
571         input5.bit.b6 = 1;              // DSW A-5: Coin #1 credit
572         input5.bit.b7 = 1;              // DSW A-7: Service mode
573
574 WriteLog("About to set up screen...\n");
575         InitVideo();
576
577         oldTicks = SDL_GetTicks();
578
579 WriteLog("About to set up audio...\n");
580         InitSound();
581
582 //memset(scrBuffer, 0xFF, VIRTUAL_SCREEN_WIDTH*VIRTUAL_SCREEN_HEIGHT*sizeof(uint32_t));
583 //RenderScreenBuffer();
584
585 WriteLog("About to enter main loop...\n");
586         while (running)
587         {
588 //              HandleGUIDebounce();                                    // Debounce GUI keys
589
590 // Dipswitches are presented to the main CPUs as 0 or 1 at locations
591 // $423D - $425B by the MCU
592
593 //testing... (works)
594 //gram1[0x423D] = 1;
595                 //gram1[0x423D] = self_test;                    // Reset DSW1-1
596 //              gram1[0x4268] = 0;                                              // Reset Video test
597
598                 // SDL key handling...
599
600                 SDL_Event event;
601
602                 while (SDL_PollEvent(&event))
603                 {
604                         switch (event.type)
605                         {
606                         case SDL_KEYDOWN:
607                                 if (event.key.keysym.sym == SDLK_ESCAPE)
608                                         running = false;
609                                 // Do PCX snapshot (F4)
610                                 else if (event.key.keysym.sym == SDLK_F4)
611                                 {
612 //                                      SpawnSound(USERSOUND, SCAMERA);
613                                         SavePCXSnapshot();
614                                 }
615 #if 1
616                                 else if (event.key.keysym.sym == SDLK_5)
617                                         input1.bit.b5 = 0;
618                                 else if (event.key.keysym.sym == SDLK_1)
619                                         input1.bit.b6 = 0;
620                                 else if (event.key.keysym.sym == SDLK_2)
621                                         input2.bit.b6 = 0;
622                                 else if (event.key.keysym.sym == SDLK_c)        // Left
623                                         input3.bit.b5 = 0;
624                                 else if (event.key.keysym.sym == SDLK_z)        // Right
625                                         input3.bit.b4 = 0;
626                                 else if (event.key.keysym.sym == SDLK_s)        // Up
627                                         input2.bit.b2 = 0;
628                                 else if (event.key.keysym.sym == SDLK_x)        // Down
629                                         input1.bit.b2 = 0;
630                                 else if (event.key.keysym.sym == SDLK_k)        // Jump
631                                         input1.bit.b1 = 0;
632                                 else if (event.key.keysym.sym == SDLK_l)        // Fire
633                                         input3.bit.b3 = 0;
634
635                                 else if (event.key.keysym.sym == SDLK_F1)       // Service mode
636                                         input5.bit.b7 = !input5.bit.b7;
637
638                                 else if (event.key.keysym.sym == SDLK_q)
639                                         input4.bit.b7 = !input4.bit.b7;
640                                 else if (event.key.keysym.sym == SDLK_w)
641                                         input5.bit.b6 = !input5.bit.b6;
642                                 else if (event.key.keysym.sym == SDLK_e)
643                                         input5.bit.b5 = !input5.bit.b5;
644                                 else if (event.key.keysym.sym == SDLK_r)
645                                         input5.bit.b4 = !input5.bit.b4;
646                                 else if (event.key.keysym.sym == SDLK_t)
647                                         input5.bit.b3 = !input5.bit.b3;
648                                 else if (event.key.keysym.sym == SDLK_y)
649                                         input5.bit.b2 = !input5.bit.b2;
650                                 else if (event.key.keysym.sym == SDLK_u)
651                                         input5.bit.b1 = !input5.bit.b1;
652                                 else if (event.key.keysym.sym == SDLK_i)
653                                         input5.bit.b0 = !input5.bit.b0;
654
655 #else
656                                 else if (event.key.keysym.sym == SDLK_1)
657                                         input1.bit.b0 = 0;
658                                 else if (event.key.keysym.sym == SDLK_2)
659                                         input1.bit.b1 = 0;
660                                 else if (event.key.keysym.sym == SDLK_3)
661                                         input1.bit.b2 = 0;
662                                 else if (event.key.keysym.sym == SDLK_4)
663                                         input1.bit.b3 = 0;
664                                 else if (event.key.keysym.sym == SDLK_5)
665                                         input1.bit.b4 = 0;
666                                 else if (event.key.keysym.sym == SDLK_6)
667                                         input1.bit.b5 = 0;
668                                 else if (event.key.keysym.sym == SDLK_7)
669                                         input1.bit.b6 = 0;
670                                 else if (event.key.keysym.sym == SDLK_8)
671                                         input1.bit.b7 = 0;
672
673                                 else if (event.key.keysym.sym == SDLK_q)
674                                         input2.bit.b0 = 0;
675                                 else if (event.key.keysym.sym == SDLK_w)
676                                         input2.bit.b1 = 0;
677                                 else if (event.key.keysym.sym == SDLK_e)
678                                         input2.bit.b2 = 0;
679                                 else if (event.key.keysym.sym == SDLK_r)
680                                         input2.bit.b3 = 0;
681                                 else if (event.key.keysym.sym == SDLK_t)
682                                         input2.bit.b4 = 0;
683                                 else if (event.key.keysym.sym == SDLK_y)
684                                         input2.bit.b5 = 0;
685                                 else if (event.key.keysym.sym == SDLK_u)
686                                         input2.bit.b6 = 0;
687                                 else if (event.key.keysym.sym == SDLK_i)
688                                         input2.bit.b7 = 0;
689
690                                 else if (event.key.keysym.sym == SDLK_a)
691                                         input3.bit.b0 = 0;
692                                 else if (event.key.keysym.sym == SDLK_s)
693                                         input3.bit.b1 = 0;
694                                 else if (event.key.keysym.sym == SDLK_d)
695                                         input3.bit.b2 = 0;
696                                 else if (event.key.keysym.sym == SDLK_f)
697                                         input3.bit.b3 = 0;
698                                 else if (event.key.keysym.sym == SDLK_g)
699                                         input3.bit.b4 = 0;
700 #endif
701
702                                 break;
703                         case SDL_KEYUP:
704 #if 1
705                                 if (event.key.keysym.sym == SDLK_5)
706                                         input1.bit.b5 = 1;
707                                 else if (event.key.keysym.sym == SDLK_1)
708                                         input1.bit.b6 = 1;
709                                 else if (event.key.keysym.sym == SDLK_2)
710                                         input2.bit.b6 = 1;
711                                 else if (event.key.keysym.sym == SDLK_c)
712                                         input3.bit.b5 = 1;
713                                 else if (event.key.keysym.sym == SDLK_z)
714                                         input3.bit.b4 = 1;
715                                 else if (event.key.keysym.sym == SDLK_s)
716                                         input2.bit.b2 = 1;
717                                 else if (event.key.keysym.sym == SDLK_x)
718                                         input1.bit.b2 = 1;
719                                 else if (event.key.keysym.sym == SDLK_k)        // (Q)  Jump
720                                         input1.bit.b1 = 1;
721                                 else if (event.key.keysym.sym == SDLK_l)        // (E) Fire
722                                         input3.bit.b3 = 1;
723 #else
724                                 if (event.key.keysym.sym == SDLK_1)
725                                         input1.bit.b0 = 1;
726                                 else if (event.key.keysym.sym == SDLK_2)
727                                         input1.bit.b1 = 1;
728                                 else if (event.key.keysym.sym == SDLK_3)
729                                         input1.bit.b2 = 1;
730                                 else if (event.key.keysym.sym == SDLK_4)
731                                         input1.bit.b3 = 1;
732                                 else if (event.key.keysym.sym == SDLK_5)
733                                         input1.bit.b4 = 1;
734                                 else if (event.key.keysym.sym == SDLK_6)
735                                         input1.bit.b5 = 1;
736                                 else if (event.key.keysym.sym == SDLK_7)
737                                         input1.bit.b6 = 1;
738                                 else if (event.key.keysym.sym == SDLK_8)
739                                         input1.bit.b7 = 1;
740
741                                 else if (event.key.keysym.sym == SDLK_q)
742                                         input2.bit.b0 = 1;
743                                 else if (event.key.keysym.sym == SDLK_w)
744                                         input2.bit.b1 = 1;
745                                 else if (event.key.keysym.sym == SDLK_e)
746                                         input2.bit.b2 = 1;
747                                 else if (event.key.keysym.sym == SDLK_r)
748                                         input2.bit.b3 = 1;
749                                 else if (event.key.keysym.sym == SDLK_t)
750                                         input2.bit.b4 = 1;
751                                 else if (event.key.keysym.sym == SDLK_y)
752                                         input2.bit.b5 = 1;
753                                 else if (event.key.keysym.sym == SDLK_u)
754                                         input2.bit.b6 = 1;
755                                 else if (event.key.keysym.sym == SDLK_i)
756                                         input2.bit.b7 = 1;
757
758                                 else if (event.key.keysym.sym == SDLK_a)
759                                         input3.bit.b0 = 1;
760                                 else if (event.key.keysym.sym == SDLK_s)
761                                         input3.bit.b1 = 1;
762                                 else if (event.key.keysym.sym == SDLK_d)
763                                         input3.bit.b2 = 1;
764                                 else if (event.key.keysym.sym == SDLK_f)
765                                         input3.bit.b3 = 1;
766                                 else if (event.key.keysym.sym == SDLK_g)
767                                         input3.bit.b4 = 1;
768 #endif
769
770                                 break;
771                         }
772                 }
773
774 #if 0
775                                 if (keys[SDLK_ESCAPE])
776                                         running = false;                     // ESC to exit...
777
778                                 if (debounce)
779                                         debounce--;                          // Debounce toggle keys...
780                                 else
781                                 {
782                                         if (keys[SDLK_F1])
783                                         {
784                                                 self_test = !self_test;            // Self-test (F1-toggle)
785                                                 debounce = 10;                     // Key debounce value...
786                                         }
787                                         if (keys[SDLK_F2])
788                                         {
789                                                 gram1[0x4268] = 1;                 // Video test (F2)
790                                                 debounce = 10;                     // Key debounce value...
791                                         }
792                                         if (keys[SDLK_F12])
793                                         {
794                                                 scr_type = !scr_type;              // Toggle screen (F12)
795                                                 debounce = 10;                     // Key debounce value...
796                                         }
797                                         if (keys[SDLK_F3])
798                                         {
799                                                 show_scr = !show_scr;              // Toggle bkgrnd (F3)
800                                                 debounce = 10;
801                                         }
802                                         if (keys[SDLK_F6])
803                                         {
804                                                 enable_cpu = !enable_cpu;          // Toggle CPUs (F6)
805                                                 debounce = 10;
806                                         }
807                                         if (keys[SDLK_F5])
808                                         {
809                                                 refresh2 = !refresh2;             // Toggle 30/60Hz (F5)
810                                                 SetRefreshRate(refresh2);         // Inform GUI of refresh
811                                                 if (refresh2)
812                                                         SpawnMsg(M60FPS);
813                                                 else
814                                                         SpawnMsg(M30FPS);
815                                                 debounce = 10;                    // Key debounce value...
816                                         }
817                                         if (keys[SDLK_F4])                      // Do PCX snapshot (F4)
818                                         {
819                                                 SpawnSound(USERSOUND, SCAMERA);
820                                                 SnapPCX(screen);
821                                                 debounce = 10;
822                                         }
823                                         if (keys[SDLK_TAB])                      // Tab active/deactivate GUI
824                                         {
825                                                 if (ShowGUI())
826                                                         DeactivateGUI();
827                                                 else
828                                                         ActivateGUI();
829
830                                                 debounce = 10;
831                                         }
832                                 }
833                                 //if (keys[0x3E])  gram1[0x4247] = 1;  // Screen hold DS (F4)
834                                 if (keys[SDLK_RIGHT])                                           // Right arrow
835                                 {
836                                         if (ShowGUI())
837                                                 SelectRight();                     // If GUI active...
838                                         else
839                                         {
840                                                 if (!keys[SDLK_LEFT])                     // Disallow opposite directions @ same time
841                                                         gram1[0x427F] = 1;               // Stick right
842                                         }
843                                 }
844                                 if (keys[SDLK_LEFT])
845                                 {
846                                         if (ShowGUI())
847                                                 SelectLeft();                      // If GUI active...
848                                         else
849                                         {
850                                                 if (!keys[SDLK_RIGHT])                     // Disallow opposite directions@same time
851                                                 gram1[0x4281] = 1;               // Left arrow
852                                         }
853                                 }
854                                 if (keys[SDLK_UP])
855                                 {
856                                         if (ShowGUI())
857                                                 SelectUp();                        // If GUI active...
858                                         else
859                                         {
860                                                 if (!keys[SDLK_DOWN])                     // Disallow opposite directions@same time
861                                                         gram1[0x427B] = 1;               // Up arrow
862                                         }
863                                 }
864                                 if (keys[SDLK_DOWN])
865                                 {
866                                         if (ShowGUI())
867                                                 SelectDown();                                   // If GUI active...
868                                         else
869                                         {
870                                                 if (!keys[SDLK_UP])                             // Disallow opposite directions@same time
871                                                         gram1[0x427D] = 1;                      // Down arrow
872                                         }
873                                 }
874                                 if (keys[SDLK_RETURN])                                                  // Return
875                                 {
876                                         uint8_t retval = UserSelectedSomething();
877
878                                         if (retval == EXIT)
879                                                 running = false;
880
881                                         if (retval == REFRESH)
882                                         {
883                                                 refresh2 = !refresh2;
884                                                 SetRefreshRate(refresh2);
885                                         }
886                                 }
887
888                                 if (keys[SDLK_1])
889                                         gram1[0x427A] = 1;                      // (1)
890
891                                 if (keys[SDLK_2])
892                                         gram1[0x427C] = 1;                      // (2)
893
894                                 if (keys[SDLK_3])
895                                         gram1[0x427E] = 1;                      // (3)
896
897                                 if (keys[SDLK_5])
898                                         gram1[0x4280] = 1;                      // (5)
899
900                                 if (keys[SDLK_q] | keys[29])
901                                         gram1[0x4276] = 1;                      // (Q)  Jump
902
903                                 if (keys[SDLK_w])
904                                         gram1[0x426A] = 1;                      // (W)
905
906                                 if (fire_debounce)
907                                         fire_debounce--;
908
909                                 if (keys[SDLK_e] | keys[56])    // (E) Fire
910                                 {
911                                         if (!fire_debounce)
912                                         {
913                                                 gram1[0x4278] = 1;
914
915                                                 if (gram1[0x3F08] == 0xFF)              // Ugly kludge for debouncing gun
916                                                         fire_debounce = 8;
917                                                 else
918                                                         fire_debounce = 2;
919                                         }
920                                 }
921
922                                 if (keys[SDLK_r])
923                                         gram1[0x426C] = 1;                      // (R)
924
925                                 if (keys[SDLK_t])
926                                         gram1[0x4262] = 1;                      // (T)
927
928                                 if (keys[SDLK_y])
929                                         gram1[0x4260] = 1;                      // (Y)
930
931                                 if (keys[SDLK_F10])
932                                         gram1[0x41A5]++;                        // Coin? (F10)
933
934                                 if (keys[SDLK_z])
935                                         gram1[0x4189]++;                        // ? (Z) credits l dig
936
937                                 if (keys[SDLK_x])
938                                         gram1[0x418A]++;                        // ? (X) credits r dig
939
940                                 if (keys[SDLK_c])
941                                         gram1[0x418C]++;                        // ? (C) Start
942
943                                 if (keys[SDLK_v])
944                                         gram1[0x418D]++;                        // ? (V)
945
946                                 if (keys[SDLK_F7])
947                                         SpawnSound(USERSOUND, 0);       // Do user sound (F7)
948 #endif
949
950                 // We can do this here because we're not executing the cores yet.
951                 cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ;
952                 cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ;
953                 mcu.cpuFlags |= V63701_ASSERT_LINE_IRQ;
954 //                                      while (cpu1.clock < 25000)
955 // 1.538 MHz = 25633.333... cycles per frame (1/60 s)
956 // 25600 cycles/frame
957 // Setting interleave to 25 and below causes the V6809 core to hang...
958 // 32 gets to the title screen before hanging...
959 // 40 works, until it doesn't... :-P
960 // 640 * 40
961 // 800 * 32
962 // Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though.
963                 for(int i=0; i<640; i++)
964                 {
965                         // Gay, but what are ya gonna do?
966                         // There's better ways, such as keeping track of when slave writes to master, etc...
967                         Execute6809(&cpu1, 40);
968                         Execute6809(&cpu2, 40);
969
970                         // MCU runs at 1,536,000 Hz
971                         // 1536000 / 60 / 640 == 40
972                         Execute63701(&mcu, 40);
973                 }
974
975                 BlitChar(charROM, gram1);
976
977                 frameTickCount++;
978
979                 if (frameTickCount == 3)
980                         frameTickCount = 0;
981
982                 // Speed throttling happens here...
983                 // Actually, it's 16.66... Need to account for that somehow [DONE]
984                 while (SDL_GetTicks() - oldTicks < (16 + (frameTickCount == 2 ? 1 : 0)))
985                         SDL_Delay(1);                           // Release our timeslice...
986
987                 oldTicks = SDL_GetTicks();
988         }
989
990         SDL_Quit();
991         LogDone();
992
993         return 1;
994 }
995
996 #if 0
997 /*
998 Hitachi uC runs at 6.144 MHz
999 YM2151 runs at 3.579580 MHz
1000
1001
1002 Rolling Thunder Memory map
1003 --------------------------
1004 Most of the decoding is done by custom chips (CUS47 and CUS41), so the memory
1005 map is inferred by program behaviour. The customs also handle internally irq
1006 and watchdog.
1007
1008 The main CPU memory map is the same in all games because CUS47 is used by all
1009 games. The sub CPU and sound CPU, on the other hand, change because CUS41 is
1010 replaced by other chips.
1011
1012 All RAM is shared between main and sub CPU, except for sound RAM which is
1013 shared between main and sound CPU; the portion of object RAM that is overlapped
1014 by sound RAM is used exclusively by the sub CPU.
1015
1016 MAIN CPU:
1017
1018 Address             Dir Data     Name      Description
1019 ------------------- --- -------- --------- -----------------------
1020 000x xxxx xxxx xxxx R/W xxxxxxxx SCROLL0   tilemap 0/1 RAM (shared with sub CPU)
1021 001x xxxx xxxx xxxx R/W xxxxxxxx SCROLL1   tilemap 2/3 RAM (shared with sub CPU)
1022 0100 00xx xxxx xxxx R/W xxxxxxxx SOUND     sound RAM (through CUS30, shared with MCU)
1023 0100 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1024 0100 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1025 010x xxxx xxxx xxxx R/W xxxxxxxx OBJECT    work RAM (shared with sub CPU) [1]
1026 0101 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1027 011x xxxx xxxx xxxx R   xxxxxxxx ROM 9D    program ROM (banked) [2]
1028 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 9C    program ROM
1029 1000 00-- ---- ----   W --------           watchdog reset (RES generated by CUS47)
1030 1000 01-- ---- ----   W --------           main CPU irq acknowledge (IRQ generated by CUS47)
1031 1000 1x-- ---- ----   W -------- BANK      tile gfx bank select (data is in A10) (latch in CUS47)
1032 1001 00-- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1033 1001 00-- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1034 1001 00-- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1035 1001 01-- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1036 1001 01-- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1037 1001 01-- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1038 1100 00-- ---- ----   W xxxxxxxx BACKCOLOR background color
1039
1040 [1] Note that this is partially overlapped by sound RAM
1041 [2] In Rolling Thunder and others, replaced by the ROM/voice expansion board
1042
1043
1044 SUB CPU:
1045
1046 Address             Dir Data     Name      Description
1047 ------------------- --- -------- --------- -----------------------
1048 000x xxxx xxxx xxxx R/W xxxxxxxx SUBOBJ    work RAM (shared with main CPU)
1049 0001 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1050 001x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR0   tilemap 0/1 RAM (shared with main CPU)
1051 010x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR1   tilemap 2/3 RAM (shared with main CPU)
1052 011x xxxx xxxx xxxx R   xxxxxxxx ROM 12D   program ROM (banked) [1]
1053 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 12C   program ROM
1054 1000 0--- ---- ----   W --------           watchdog reset (MRESET generated by CUS41)
1055 1000 1--- ---- ----   W --------           main CPU irq acknowledge (generated by CUS41)
1056 1101 0--- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1057 1101 0--- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1058 1101 0--- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1059 1101 1--- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1060 1101 1--- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1061 1101 1--- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1062
1063 [1] Only used by Rolling Thunder
1064
1065
1066 MCU:
1067
1068 Address             Dir Data     Name      Description
1069 ------------------- --- -------- --------- -----------------------
1070 0000 0000 xxxx xxxx                        MCU internal registers, timers, ports and RAM
1071 0001 xxxx xxxx xxxx R/W xxxxxxxx RAM 3F    sound RAM (through CUS30, partially shared with main CPU)
1072 0001 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1073 0001 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1074 0010 0--- --00 ---x R/W xxxxxxxx YMCS      YM2151
1075 0010 0--- --01 ----                        n.c.
1076 0010 0--- --10 ---- R   xxxxxxxx PORTA     switch inputs
1077 0010 0--- --11 ---- R   xxxxxxxx PORTB     dip switches
1078 01xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (lower half)
1079 10xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (upper half)
1080 1011 0--- ---- ----   W                    unknown (CUS41)
1081 1011 1--- ---- ----   W                    unknown (CUS41)
1082 1111 xxxx xxxx xxxx R   xxxxxxxx           MCU internal ROM
1083
1084
1085 Notes:
1086 -----
1087 - There are two watchdogs, one per CPU (or maybe three). Handling them
1088   separately is necessary to allow entering service mode without manually
1089   resetting in rthunder and genpeitd: only one of the CPUs stops writing to
1090   the watchdog.
1091
1092 - The sprite hardware buffers spriteram: the program writes the sprite list to
1093   offsets 4-9 of every 16-byte block, then at the end writes to offset 0x1ff2
1094   of sprite RAM to signal the chip that the list is complete. The chip will
1095   copy the list from 4-9 to 10-15 and use it from there. This has not been
1096   verified on the real hardware, but it is the most logical way of doing it.
1097   Emulating this behaviour and not using an external buffer is important in
1098   rthunder: when you insert a coin, the whole sprite RAM is cleared, but 0x1ff2
1099   is not written to. If we buffered spriteram to an external buffer, this would
1100   cause dangling sprites because the buffer would not be updated.
1101
1102 - spriteram buffering fixes sprite lag, but causes a glitch in rthunder when
1103   entering a door. The *closed* door is made of tiles, but the *moving* door is
1104   made of sprites. Since sprites are delayed by 1 frame, when you enter a door
1105   there is one frame where neither the tile-based closed door nor the
1106   sprite-based moving door is shown, so it flickers. This behavior has been
1107   confirmed on a real PCB.
1108
1109 TODO:
1110 ----
1111 - The two unknown writes for the MCU are probably watchdog reset and irq acknowledge,
1112   but they don't seem to work as expected. During the first few frames they are
1113   written out of order and hooking them up in the usual way causes the MCU to
1114   stop receiving interrupts.
1115 */
1116 #endif
1117