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