]> Shamusworld >> Repos - thunder/blob - src/thunder.cpp
Emulator working with YM2151 and V63701 emus in place.
[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 "screen.h"
32 #include "sound.h"
33 #include "v63701.h"
34 #include "v6809.h"
35 #include "video.h"
36 #include "ym2151.h"
37
38
39 using namespace std;
40
41
42 #define ROM1   "rt3-1b.9c"
43 #define ROM2   "rt3-2b.12c"
44 #define ROM3   "rt3-3.12d"
45 #define ROM4   "rt1-4.6b"
46 #define ROM5   "rt1-5.4r"
47 #define ROM6   "rt1-6.4s"
48 #define ROM7   "rt1-7.7r"
49 #define ROM8   "rt1-8.7s"
50 #define ROM9   "rt1-9.12h"
51 #define ROM10  "rt1-10.12k"
52 #define ROM11  "rt1-11.12l"
53 #define ROM12  "rt1-12.12m"
54 #define ROM13  "rt1-13.12p"
55 #define ROM14  "rt1-14.12r"
56 #define ROM15  "rt1-15.12t"
57 #define ROM16  "rt1-16.12u"
58 #define ROM17  "rt1-17.f1"
59 #define ROM18  "rt1-18.h1"
60 #define ROM19  "rt1-19.k1"
61 #define ROM20  "rt1-20.m1"
62 #define ROM21  "rt1-21.f3"
63 #define ROM22  "rt1-22.h3"
64 #define PROM1  "mb7124e.3r"
65 #define PROM2  "mb7116e.3s"
66 #define PROM3  "mb7138h.4v"
67 #define PROM4  "mb7138h.6v"
68 #define PROM5  "mb7112e.6u"
69 #define MCUROM "rt1-mcu.bin"
70
71
72 // Global defines
73
74 SDL_Surface * screen;
75
76 uint8_t * gram, * grom;                         // Allocate RAM & ROM pointers
77 uint8_t gram1[0x10000], gram2[0x10000], grom1[0x10000], grom2[0x10000]; // Actual memory
78 uint8_t grom3[0x8000], grom4[0x8000], data_rom[0x40000], spr_rom[0x80000], voice_rom[0x20000];
79 uint8_t chr_rom[0x60000];                       // Character ROM pointer
80 uint8_t mcuMem[0x10000];                // 64K for MCU
81
82 V6809REGS cpu1, cpu2;
83 V63701REGS mcu;
84
85 bool trace1 = false;                    // ditto...
86 bool looking_at_rom = true;             // true = R1, false = R2
87 uint32_t banksw1, banksw2;              // Bank switch addresses
88 uint16_t game_over_switch;              // Game over delay
89 uint16_t dpc;                                   // Debug pc reg...
90 bool show_scr = true;                   // Whether or not to show background
91 bool enable_cpu = true;                 // Whether or not to enable CPUs
92 bool irqGoA = true;                             // IRQ switch for CPU #1
93 bool irqGoB = true;                             // IRQ switch for CPU #2
94
95 uint16_t refresh_ = 0;                  // Crappy global screen stuff...
96 bool refresh2 = true;
97
98 uint32_t psg_lens[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
99 uint8_t * psg_adrs[16];
100 //uint32_t voc_lens[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101 //                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
102 //uint8_t * voc_adrs[32];
103 //uint32_t fm_lens[14] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
104 //uint8_t * fm_adrs[14];
105
106 Byte input1, input2, input3, input4, input5;
107
108 fstream tr;                                                     // Tracelog hook
109 uint16_t pcx;                                           // Where we at?
110
111
112 //
113 // Read a byte from memory (without touching PC. Not a Fetch!)
114 //
115 uint8_t RdMem(uint16_t addr)
116 {
117         uint8_t b;
118
119         // $4000-4300 is RAM shared with the microcontroller...
120
121         if (addr < 0x8000)
122         {
123                 // Memory shared with MCU (CPU #1 only! CPU #2 does not)
124                 if ((addr >= 0x4000) && (addr <= 0x43FF))
125                         return mcuMem[addr - 0x3000];
126
127                 if (addr > 0x5FFF)
128                         b = data_rom[banksw1 + (addr - 0x6000)];        // Get char data
129                 else
130                         b = gram1[addr];
131         }
132         else
133                 b = grom1[addr];
134
135         return b;
136 }
137
138
139 //
140 // Write a byte to memory
141 //
142 void WrMem(uint16_t addr, uint8_t b)
143 {
144         extern bool disasm;
145         extern bool charbase;   // Needed for screen. Extern it in it??
146 #if 0
147         if (addr == 0x4182)
148         {
149                 WriteLog("\nWriteMem: CPU #1 writing $%02X to $4182!\n\n", b);
150         }
151 #endif
152 #if 0
153 if (((addr >= 0x4180) && (addr <= 0x4191)) || (addr == 0x4380))
154         printf("WriteMem: CPU #1 writing $%02X to $%04X...\n", b, addr);
155 #endif
156
157         if (addr == 0x6000)
158                 SpawnSound(GAMESOUND, gram1[0x6200], 0);                // Do voice chan 1
159         if (addr == 0x6400)
160                 SpawnSound(GAMESOUND, gram1[0x6600], 1);                // Do voice chan 2
161         if (addr == 0x6800)
162                 banksw1 = (uint32_t)b << 13;                                            // Set char data bankswitch base address
163         if (addr > 0x4284 && addr < 0x42A5 && b)
164                 SpawnSound(PSGSOUND, addr - 0x4285);                    // Do PSG sound on chans 2, 3
165 #if 0
166         if (addr == 0x4380)
167         {
168                 SpawnSound(FMSOUND, b);                                                 // Do FM sound on channel 4
169                 if (b == 12)
170                         game_over_switch = 240;                                         // Set game over delay...
171         }
172 #endif
173 //      if (addr < 0x423D || addr > 0x425C)                                     // Protect writes to DSWs
174 //if (addr == 0x4191)
175 //{
176 //      printf("V6809: Writing %02X to $4191...\n", b);
177 //}
178         // Memory shared with MCU (CPU #1 only! CPU #2 does not)
179         if ((addr >= 0x4000) && (addr <= 0x43FF))
180                 mcuMem[addr - 0x3000] = b;
181         else
182                 gram1[addr] = b;
183
184         if (addr == 0x8800)
185                 charbase = false;                                                               // Char banksw1
186         if (addr == 0x8C00)
187                 charbase = true;                                                                // Char banksw2
188         if (addr == 0x8400)                                                                     // Frame go strobe? VBlank acknowledge?
189         {
190                 if (refresh_++ == 1)                                                            // 30 Hz...
191                 {
192                         BlitChar(screen, chr_rom, gram1);
193                         refresh_ = (refresh2 ? 1 : 0);                          // 60/30 Hz...
194                 }
195
196                 // IRQ Ack (may also be frame go...
197                 ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);
198 #if 1
199         if (disasm)
200                 WriteLog("WriteMem: CPU #1 Acknowledging IRQ...\n", b);
201 #endif
202         }
203 }
204
205
206 //
207 // Read a byte from memory (without touching PC. Not a Fetch!) (2nd processor)
208 //
209 uint8_t RdMemB(uint16_t addr)
210 {
211         uint8_t b;
212
213         if (addr < 0x8000)
214         {
215                 if (addr < 0x2000)
216                         b = gram1[addr + 0x4000];
217                 if (addr > 0x1FFF && addr < 0x6000)
218                         b = gram1[addr - 0x2000];
219                 if (addr > 0x5FFF)
220                         b = grom3[banksw2 + (addr - 0x6000)];
221         }
222         else
223                 b = grom2[addr];
224
225         return b;
226 }
227
228
229 //
230 // Write a byte to memory (2nd processor)
231 //
232 void WrMemB(uint16_t addr, uint8_t b)
233 {
234         extern bool disasm;
235         extern bool charbase;
236
237 #if 0
238         if (addr == 0x0182)
239         {
240                 WriteLog("\nWriteMem: CPU #2 writing $%02X to $0182 ($4182)!\n\n", b);
241         }
242 #endif
243 #if 0
244 if (((addr >= 0x0180) && (addr <= 0x0191)) || (addr == 0x0380))
245         printf("WriteMem: CPU #2 writing $%02X to $%04X...\n", b, addr);
246 #endif
247
248 #if 0
249         if (addr == 0x6000)
250                 SpawnSound(GAMESOUND, gram1[0x6200], 0);                // Do voice chan 1
251         if (addr == 0x6400)
252                 SpawnSound(GAMESOUND, gram1[0x6600], 1);                // Do voice chan 2
253         if (addr > 0x0284 && addr < 0x02A5 && b)
254                 SpawnSound(PSGSOUND, addr - 0x0285);                    // Do PSG sound on chans 2, 3
255 #endif
256         if (addr == 0xD803)
257                 banksw2 = (uint32_t)(b & 0x03) << 13;                           // Set sprite data bank switch
258 #if 0
259         if (addr == 0x0380)
260         {
261                 SpawnSound(FMSOUND, b);                                                 // Do FM sound on chan 4
262                 if (b == 12)
263                         game_over_switch = 240;                                         // Set game over delay...
264         }
265 #endif
266 //      if (addr < 0x023D || addr > 0x025C)                                     // Protect writes against DSWs
267         {
268                 if (addr < 0x2000)
269                         gram1[addr + 0x4000] = b;
270                 if (addr > 0x1FFF && addr < 0x6000)
271                         gram1[addr - 0x2000] = b;
272 //              if (addr > 0x5FFF)
273 //                      gram1[addr] = b;
274         }
275         if (addr == 0x8800)
276         {
277                 // IRQ Ack (may also be frame go...)
278                 ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);
279 #if 1
280         if (disasm)
281                 WriteLog("WriteMem: CPU #2 Acknowledging IRQ...\n", b);
282 #endif
283         }
284 }
285
286
287 uint8_t MCUReadMemory(uint16_t address)
288 {
289         if (address < 0x20)
290         {
291 //              printf("V63701 read $%02X from $%02X...\n", memory[address], address);
292                 return InternalRegisterRead(address);
293         }
294         else if ((address >= 0x2000) && (address <= 0x2001))
295         {
296 //              return 0;       //for now
297                 return YMReadReg(0);
298         }
299         // Various joystick + buttons; all are active low.
300         else if (address == 0x2020)
301         {
302 //printf("MCURead: Returning $%02X from $2020...\n", input1.byte);
303                 return input1.byte;
304         }
305         else if (address == 0x2021)
306         {
307 //extern bool V63701LogGo;
308 //if (input2.byte == 0xDF)
309 //      V63701LogGo = true;
310
311 //printf("MCURead: Returning $%02X from $2021...\n", input2.byte);
312                 return input2.byte;
313         }
314         // This is DSW1 & 2. All switch settings are active low.
315         else if (address == 0x2030)
316         {
317 //printf("MCURead: Returning $%02X from $2030...\n", input4.byte);
318                 return input4.byte;
319         }
320         else if (address == 0x2031)
321         {
322 //printf("MCURead: Returning $%02X from $2031...\n", input5.byte);
323                 return input5.byte;
324         }
325
326         return mcuMem[address];
327 }
328
329
330 void MCUWriteMemory(uint16_t address, uint8_t data)
331 {
332         static uint8_t ymRegister;
333
334 #if 1
335         if (address < 0x20)
336         {
337 //              printf("V63701 wrote $%02X to $%02X...\n", data, address);
338                 InternalRegisterWrite(address, data);
339                 return;
340         }
341 #endif
342
343 //if (address == 0x1191)
344 //{
345 //      printf("V63701: Writing $%02X to $1191...\n", data);
346 //}
347 #if 0
348         // Translate local reads @ $1000-$13FF to $4000-$43FF in shared RAM
349         if ((address >= 0x1000) && (address <= 0x13FF))
350         {
351                 gram1[0x3000 + address] = data;
352                 return;
353         }
354 #endif
355
356         if (((address >= 0x4000) && (address <= 0xBFFF))
357                 || (address >= 0xF000))
358                 return;
359         else if (address == 0x2000)
360         {
361                 ymRegister = data;
362                 return;
363         }
364         else if (address == 0x2001)
365         {
366 //printf("Writing $%02X to YM2151 register $%02X...\n", data, ymRegister);
367                 YMWriteReg(0, ymRegister, data);
368                 return;
369         }
370
371         // RAM is from $0 - $3FFF, $C000 - $EFFF
372         mcuMem[address] = data;
373 }
374
375
376 uint8_t V63701ReadPort1(void)
377 {
378 //      printf("V63701ReadPort1: Read $%02X...\n", input3.byte);
379         return input3.byte;
380 }
381
382
383 uint8_t V63701ReadPort2(void)
384 {
385         return 0xFF;
386 }
387
388
389 void V63701WritePort1(uint8_t data)
390 {
391 //      printf("V63701WritePort1: Wrote $%02X...\n", data);
392 }
393
394
395 void V63701WritePort2(uint8_t data)
396 {
397 //      printf("V63701WritePort2: Wrote $%02X...\n", data);
398 }
399
400
401 //
402 // Generic Load file into image space
403 // (No error checking performed!  Responsibility of caller!)
404 //
405 bool LoadImg(const char * filename, uint8_t * mem, uint32_t address, uint32_t length)
406 {
407         char path[128];
408
409         strcpy(path, "./ROMs/");
410         strcat(path, filename);
411         FILE * file = fopen(path, "rb");
412
413         if (!file)
414                 return false;
415
416         fread(&mem[address], 1, length, file);
417         fclose(file);
418
419         return true;
420 }
421
422
423 //
424 // Read color PROMs
425 //
426 bool ReadColorPROMs(void)
427 {
428         fstream ff1, ff2;
429         //  uint8_t ch;
430         char ch;
431         extern uint32_t palette[256];     // Screen physical palette
432         extern uint8_t ccolor[256][8];   // Character color PROM values
433         extern uint8_t scolor[128][16];  // Sprite color PROM values
434
435         ff1.open("./ROMs/"PROM3, ios::binary | ios::in);
436
437         if (ff1)
438         {
439                 for(int i=0; i<256; i++) // Load char pallete with PROM values
440                 {
441                         for(int j=0; j<8; j++)
442                         {
443                                 ff1.get(ch);
444                                 ccolor[i][j] = (uint8_t)ch;
445                         }
446                 }
447
448                 ff1.close();
449         }
450
451         ff1.open("./ROMs/"PROM4, ios::binary | ios::in);
452
453         if (ff1)
454         {
455                 for(int i=0; i<128; i++) // Load sprite pallete with PROM values
456                 {
457                         for(int j=0; j<16; j++)
458                         {
459                                 ff1.get(ch);
460                                 scolor[i][j] = (uint8_t)ch;
461                         }
462                 }
463
464                 ff1.close();
465         }
466
467         ff1.open("./ROMs/"PROM1, ios::binary | ios::in);
468         ff2.open("./ROMs/"PROM2, ios::binary | ios::in);
469
470         // If open was successful...
471         if (ff1 && ff2)
472         {
473                 // Palette is 12-bit RGB, we stretch it to 24-bit
474                 for(int i=0; i<256; i++)
475                 {
476                         char c1, c2;
477                         ff1.get(c1);
478                         ff2.get(c2);
479                         uint8_t r = (uint8_t)c1 & 0x0F;
480                         uint8_t g = (uint8_t)c1 >> 4;
481                         uint8_t b = (uint8_t)c2;
482                         palette[i] = 0xFF000000 | (b << 20) | (b << 16) | (g << 12) | (g << 8) | (r << 4) | r;
483                 }
484
485                 ff1.close();
486                 ff2.close();
487         }
488
489         // PROM5 has the following in it (tile address decoder):
490         // 00:  00 20 40 60  02 22 42 62  04 24 44 64  06 26 46 66
491         // 10:  88 A8 C8 E8  8A AA CA EA  8C AC CC EC  8E AE CE EE 
492
493         return ff1;
494 }
495
496
497 //
498 // Unpack font data
499 //
500 bool UnpackFonts(void)
501 {
502 //  uint8_t b1, b2, b3;
503         char b1, b2, b3;
504         fstream f1, f2;
505         //0x4000 $800 chars
506         f1.open("./ROMs/"ROM7, ios::binary | ios::in);
507         f2.open("./ROMs/"ROM8, ios::binary | ios::in);
508
509         if ((!f1) || (!f2))
510                 return false;  // Return if not found...
511
512         for(long i=0; i<0x40000; i+=64)
513         {
514                 for(int j=0; j<64; j+=8)
515                 {
516                         f1.get(b1);  f1.get(b2);  f2.get(b3);
517                         b3 ^= 0xFF; // Invert top data...
518                         chr_rom[i+j] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
519                         chr_rom[i+j+1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
520                         chr_rom[i+j+2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
521                         chr_rom[i+j+3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
522                         chr_rom[i+j+4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
523                         chr_rom[i+j+5] = (b3 & 0x04)        | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
524                         chr_rom[i+j+6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
525                         chr_rom[i+j+7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
526                 }
527         }
528
529         f1.close();
530         f2.close();
531
532         f1.open("./ROMs/"ROM5, ios::binary | ios::in);
533         f2.open("./ROMs/"ROM6, ios::binary | ios::in);
534
535         for(long i=0x40000; i<0x60000; i+=64)
536         {
537                 for(int j=0; j<64; j+=8)
538                 {
539                         f1.get(b1);  f1.get(b2);  f2.get(b3);
540                         b3 ^= 0xFF;                             // Invert top data
541                         chr_rom[i+j] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
542                         chr_rom[i+j+1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
543                         chr_rom[i+j+2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
544                         chr_rom[i+j+3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
545                         chr_rom[i+j+4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
546                         chr_rom[i+j+5] = (b3 & 0x04)        | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
547                         chr_rom[i+j+6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
548                         chr_rom[i+j+7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
549                 }
550         }
551
552         f1.close();
553         f2.close();
554
555         return true;                                // Made it!
556 }
557
558
559 //
560 // Get length of sample from WAV format
561 //
562 uint32_t GetWAVLength(fstream & file)
563 {
564         char ch;
565         uint32_t len;
566
567         file.ignore(16);                                                                        // Skip header BS
568
569         for(int i=0; i<2; i++)
570         {
571                 file.get(ch);  len = (int)(uint8_t)ch;
572                 file.get(ch);  len |= (int)(uint8_t)ch << 8;
573                 file.get(ch);  len |= (int)(uint8_t)ch << 16;
574                 file.get(ch);  len |= (int)(uint8_t)ch << 24;
575
576                 // Skip intermediate data
577                 file.ignore(len + 4);
578         }
579
580         // & finally get length of data
581         file.get(ch);  len = (int)(uint8_t)ch;
582         file.get(ch);  len |= (int)(uint8_t)ch << 8;
583         file.get(ch);  len |= (int)(uint8_t)ch << 16;
584         file.get(ch);  len |= (int)(uint8_t)ch << 24;
585
586         return len;
587 }
588
589
590 //
591 // Load PSG samples from disk
592 //
593 void LoadPSGs(void)
594 {
595         char file[40];
596         char ch;
597         uint32_t len;
598
599         for(int i=0; i<16; i++)
600         {
601                 fstream fp;
602
603                 psg_adrs[i] = NULL;                                                             // Zero out pointer
604                 sprintf(file, "./sounds/psg%i.wav", i);                 // Create filename
605
606                 fp.open(file, ios::binary | ios::in);                   // Attempt to open it...
607
608                 if (fp)
609                 {
610                         len = GetWAVLength(fp);                                         // Get WAV data length...
611                         psg_adrs[i] = new uint8_t[len];                         // Attempt to allocate space...
612
613                         if (psg_adrs[i] != NULL)
614                         {
615                                 for(int j=0; j<(signed)len; j++)
616                                 {
617                                         fp.get(ch);
618                                         psg_adrs[i][j] = ch;                            // & load it in...
619                                 }
620
621                                 psg_lens[i] = len;
622                                 printf("Found sample file: %s\t[Length: %u]\n", file, len);
623                         }
624
625                         fp.close();
626                 }
627         }
628 }
629
630
631 #if 0
632 //
633 // Load FM samples from disk
634 //
635 void LoadFMs(void)
636 {
637         char file[200];
638         char ch;
639         uint32_t len;
640
641         for(int i=0; i<14; i++)
642         {
643                 fstream fp;
644
645                 fm_adrs[i] = NULL;                                              // Zero out pointer
646                 sprintf(file, "./sounds/fm%i.wav", i);  // Create filename
647                 fp.open(file, ios::binary | ios::in);   // Attempt to open it...
648
649                 if (!fp)
650                         continue;
651
652                 len = GetWAVLength(fp);                                 // Get WAV length...
653                 fm_adrs[i] = new uint8_t[len];                  // Attempt to allocate space...
654
655                 if (fm_adrs[i] != NULL)
656                 {
657                         for(int j=0; j<(signed)len; j++)
658                         {
659                                 fp.get(ch);
660                                 fm_adrs[i][j] = ch;                                     // & load it in...
661                         }
662
663                         fm_lens[i] = len;
664                         printf("Found sample file: %s\t[Length: %u]\n", file, len);
665                 }
666
667                 fp.close();
668         }
669 }
670 #endif
671
672
673 //
674 // Main loop
675 //
676 int main(int argc, char * argv[])
677 {
678         InitLog("thunder.log");
679
680 extern bool disasm;     // From 'V6809.CPP'
681         extern bool charbase;                                           // From 'SCREEN.CPP'
682         charbase = false;
683
684         char lbuff[80];
685         fstream ff;                       // Declare fstream without file hooks...
686         bool brk = false, brk2 = false;   // Breakpoint set flag
687         uint16_t brkpnt, brkpnt2;             // Where the breakpoint is...
688         bool running;                     // CPU running state flag...
689         bool self_test = false;           // Self-test switch
690         bool scr_type = false;            // false=chars, true=pixels
691         uint16_t debounce = 0;                // Key de-bounce counter
692         uint16_t fire_debounce = 0;           // Fire button debounce counter
693         uint8_t x;                           // General placeholder...
694         bool active = true;                                             // Program running flag
695
696         SDL_Event event;                                                                // SDL "event"
697         extern uint8_t palette[768];                                    // Screen physical palette
698         uint32_t ticks, oldTicks;
699
700         cout << endl << "THUNDER v"THUNDER_VERSION" ";
701         cout << "by James Hammons" << endl;
702         cout << "Serial #20149417 / Prerelease" << endl;
703         cout << "© 2003, 2014 Underground Software" << endl << endl;
704
705         cout << "This emulator is free software. If you paid for it you were RIPPED OFF"
706                 << endl << endl;
707
708 //      SDL_WM_SetCaption("Thunder v"THUNDER_VERSION" ", "Thunder");
709
710         gram = gram1;  grom = grom1;           // Needed only for debugger
711
712         memset(gram, 0, 0x10000);
713         memset(grom, 0, 0x10000);
714         memset(gram2, 0, 0x10000);
715         memset(grom2, 0, 0x10000);
716
717         game_over_switch = 0;   // Init game over delay
718
719         cout << "Loading ROMs..." << endl;
720         if (!ReadColorPROMs())                   // Load virtual PROMs
721         { cout << "Could not open PROM files!" << endl;  return -1; }
722
723         if (!LoadImg(ROM1, grom1, 0x8000, 0x8000)) // Load $8000-$FFFF 1st ROM
724         { cout << "Could not open file '" << ROM1 << "'!" << endl;  return -1; }
725
726         if (!LoadImg(ROM2, grom2, 0x8000, 0x8000)) // Load $8000-$FFFF 2nd ROM
727         { cout << "Could not open file '" << ROM2 << "'!" << endl;  return -1; }
728
729         if (!LoadImg(ROM3, grom3, 0, 0x8000))      // Load 3rd ROM into its own space
730         { cout << "Could not open file '" << ROM3 << "'!" << endl;  return -1; }
731
732 //      if (!LoadImg(ROM4, grom4, 0, 0x8000))      // Load 4rd ROM into its own space
733 //      { cout << "Could not open file '" << ROM4 << "'!" << endl;  return -1; }
734
735         if (!LoadImg(ROM17, data_rom, 0,       0x10000))  // Load 17th ROM
736         { cout << "Could not open file '" << ROM17 << "'!" << endl;  return -1; }
737
738         if (!LoadImg(ROM18, data_rom, 0x10000, 0x10000))  // Load 18th ROM
739         { cout << "Could not open file '" << ROM18 << "'!" << endl;  return -1; }
740
741         if (!LoadImg(ROM19, data_rom, 0x20000, 0x10000))  // Load 19th ROM
742         { cout << "Could not open file '" << ROM19 << "'!" << endl;  return -1; }
743
744         if (!LoadImg(ROM20, data_rom, 0x30000, 0x10000))  // Load 20th ROM
745         { cout << "Could not open file '" << ROM20 << "'!" << endl;  return -1; }
746
747         if (!LoadImg(ROM9,  spr_rom, 0,       0x10000))   // Load 9th ROM
748         { cout << "Could not open file '" << ROM9 << "'!" << endl;  return -1; }
749
750         if (!LoadImg(ROM10, spr_rom, 0x10000, 0x10000))   // Load 10th ROM
751         { cout << "Could not open file '" << ROM10 << "'!" << endl;  return -1; }
752
753         if (!LoadImg(ROM11, spr_rom, 0x20000, 0x10000))   // Load 11th ROM
754         { cout << "Could not open file '" << ROM11 << "'!" << endl;  return -1; }
755
756         if (!LoadImg(ROM12, spr_rom, 0x30000, 0x10000))   // Load 12th ROM
757         { cout << "Could not open file '" << ROM12 << "'!" << endl;  return -1; }
758
759         if (!LoadImg(ROM13, spr_rom, 0x40000, 0x10000))   // Load 13th ROM
760         { cout << "Could not open file '" << ROM13 << "'!" << endl;  return -1; }
761
762         if (!LoadImg(ROM14, spr_rom, 0x50000, 0x10000))   // Load 14th ROM
763         { cout << "Could not open file '" << ROM14 << "'!" << endl;  return -1; }
764
765         if (!LoadImg(ROM15, spr_rom, 0x60000, 0x10000))   // Load 15th ROM
766         { cout << "Could not open file '" << ROM15 << "'!" << endl;  return -1; }
767
768         if (!LoadImg(ROM16, spr_rom, 0x70000, 0x10000))   // Load 16th ROM
769         { cout << "Could not open file '" << ROM16 << "'!" << endl;  return -1; }
770
771         if (!LoadImg(ROM21, voice_rom, 0, 0x10000))  // Load 21st ROM
772         { cout << "Could not open file '" << ROM21 << "'!" << endl;  return -1; }
773
774         if (!LoadImg(ROM22, voice_rom, 0x10000, 0x10000))  // Load 22nd ROM
775         { cout << "Could not open file '" << ROM22 << "'!" << endl;  return -1; }
776
777         if (!UnpackFonts())                         // Load 5, 6, 7, 8th ROMs
778         {
779                 cout << "Could not open font files!" << endl;
780                 return -1;
781         }
782
783         // Load MCU program + data
784         if (!LoadImg(MCUROM, mcuMem, 0xF000, 0x1000))   // Load MCU ROM
785         { cout << "Could not open file '" << MCUROM << "'!" << endl;  return -1; }
786
787         if (!LoadImg(ROM4, mcuMem, 0x4000, 0x8000))             // Load 4th ROM
788         { cout << "Could not open file '" << ROM4 << "'!" << endl;  return -1; }
789
790         // Load samples if they're there...
791         LoadPSGs();
792 //      LoadFMs();
793
794         // Set up V6809 execution contexts
795
796         memset(&cpu1, 0, sizeof(V6809REGS));
797         cpu1.RdMem = RdMem;
798         cpu1.WrMem = WrMem;
799         cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET;
800
801         memset(&cpu2, 0, sizeof(V6809REGS));
802         cpu2.RdMem = RdMemB;
803         cpu2.WrMem = WrMemB;
804         cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET;
805
806         memset(&mcu, 0, sizeof(V63701REGS));
807         mcu.RdMem = MCUReadMemory;
808         mcu.WrMem = MCUWriteMemory;
809         mcu.cpuFlags |= V63701_ASSERT_LINE_RESET;
810
811         uint32_t my_clock = 0;
812         running = true;                                                         // Set running status...
813         trace1 = false;
814         SetRefreshRate(refresh2);                                       // Tell GUI our refresh rate
815
816         // Set all inputs to inactive...
817         input1.byte = input2.byte = input3.byte = input4.byte = input5.byte = 0xFF;
818 //      mcu.port1 = 0xFF;
819 //      mcu.port2 = 0xFF;
820 #if 0
821         // This is data that is supposed to come from the MCU... So that's why it hangs
822         gram1[0x4182] = 0xA6;          // Temp kludge
823         gram1[0x4184] = 0xA6;
824         gram1[0x4183] = 0x00;          // More of the same
825         gram1[0x4185] = 0x00;
826 #endif
827         banksw1 = 0;                   // Will this work?
828         banksw2 = 0;
829 //        iclock = 0;                // Reset instr clock #1...
830         InitGUI();                 // Reset # of coins
831
832 WriteLog("About to set up screen...\n");
833         InitVideo();
834
835         oldTicks = SDL_GetTicks();
836
837 WriteLog("About to set up audio...\n");
838 #if 0
839         // This crap SHOULD be in sound.cpp (not yet created)...
840         SDL_AudioSpec desired, obtained;
841         desired.freq = 22050;
842         desired.format = AUDIO_U8;
843         desired.channels = 1;
844         desired.samples = 600;
845         desired.callback = SoundFunc;
846         desired.userdata = NULL;
847         // Also, should check to see if it got the hardware it needed, correct sample size, etc.
848         if (SDL_OpenAudio(&desired, &obtained) < 0)
849         {
850                 cout << "Couldn't open audio: " << SDL_GetError() << endl;
851                 return -1;
852         }
853
854         SDL_PauseAudio(0);                                                      // Get that audio going!
855 #else
856         InitSound();
857 #endif
858
859 memset(scrBuffer, 0xFF, VIRTUAL_SCREEN_WIDTH*VIRTUAL_SCREEN_HEIGHT*sizeof(uint32_t));
860 RenderScreenBuffer();
861
862 WriteLog("About to enter main loop...\n");
863         while (running)
864         {
865                 HandleGUIDebounce();                                    // Debounce GUI keys
866
867 #if 0
868                 if (game_over_switch)
869                 {
870                         game_over_switch--;  // Countdown...
871
872                         if (game_over_switch == 0)
873                                 gram1[0x4380] = 0; // Kill music!
874                 }
875 #endif
876
877 // Dipswitches are presented to the main CPUs as 0 or 1 at locations
878 // $423D - $425B by the MCU
879
880 //testing... (works)
881 //gram1[0x423D] = 1;
882                 //gram1[0x423D] = self_test;                    // Reset DSW1-1
883 //              gram1[0x4268] = 0;                                              // Reset Video test
884 //              gram1[0x427A] = 0;  gram1[0x427C] = 0;
885                 //gram1[0x427B] = 0;  gram1[0x427D] = 0;
886 //              gram1[0x427E] = 0;//  gram1[0x427F] = 0;
887 //              gram1[0x4280] = 0;//  gram1[0x4281] = 0;
888                 //gram1[0x4276] = 0;
889 //              gram1[0x426A] = 0;
890                 //gram1[0x4278] = 0;
891 //              gram1[0x426C] = 0;
892 //              gram1[0x4262] = 0;  gram1[0x4260] = 0;
893                 //gram1[0x4247] = 0;
894
895                 // SDL key handling...
896
897                 SDL_Event event;
898
899                 while (SDL_PollEvent(&event))
900                 {
901                         switch (event.type)
902                         {
903                         case SDL_KEYDOWN:
904                                 if (event.key.keysym.sym == SDLK_ESCAPE)
905                                         running = false;
906                                 // Do PCX snapshot (F4)
907                                 else if (event.key.keysym.sym == SDLK_F4)
908                                 {
909 //                                      SpawnSound(USERSOUND, SCAMERA);
910                                         SavePCXSnapshot();
911 //                                      debounce = 10;
912                                 }
913 #if 1
914                                 else if (event.key.keysym.sym == SDLK_5)
915                                         input1.bit.b5 = 0;
916                                 else if (event.key.keysym.sym == SDLK_1)
917                                         input1.bit.b6 = 0;
918                                 else if (event.key.keysym.sym == SDLK_RIGHT)
919                                         input3.bit.b5 = 0;
920                                 else if (event.key.keysym.sym == SDLK_LEFT)
921                                         input3.bit.b4 = 0;
922                                 else if (event.key.keysym.sym == SDLK_UP)
923                                         input2.bit.b2 = 0;
924                                 else if (event.key.keysym.sym == SDLK_DOWN)
925                                         input1.bit.b2 = 0;
926                                 else if (event.key.keysym.sym == SDLK_q)        // (Q)  Jump
927                                         input1.bit.b1 = 0;
928                                 else if (event.key.keysym.sym == SDLK_e)        // (E) Fire
929                                         input3.bit.b3 = 0;
930 #else
931                                 else if (event.key.keysym.sym == SDLK_1)
932                                         input1.bit.b0 = 0;
933                                 else if (event.key.keysym.sym == SDLK_2)
934                                         input1.bit.b1 = 0;
935                                 else if (event.key.keysym.sym == SDLK_3)
936                                         input1.bit.b2 = 0;
937                                 else if (event.key.keysym.sym == SDLK_4)
938                                         input1.bit.b3 = 0;
939                                 else if (event.key.keysym.sym == SDLK_5)
940                                         input1.bit.b4 = 0;
941                                 else if (event.key.keysym.sym == SDLK_6)
942                                         input1.bit.b5 = 0;
943                                 else if (event.key.keysym.sym == SDLK_7)
944                                         input1.bit.b6 = 0;
945                                 else if (event.key.keysym.sym == SDLK_8)
946                                         input1.bit.b7 = 0;
947
948                                 else if (event.key.keysym.sym == SDLK_q)
949                                         input2.bit.b0 = 0;
950                                 else if (event.key.keysym.sym == SDLK_w)
951                                         input2.bit.b1 = 0;
952                                 else if (event.key.keysym.sym == SDLK_e)
953                                         input2.bit.b2 = 0;
954                                 else if (event.key.keysym.sym == SDLK_r)
955                                         input2.bit.b3 = 0;
956                                 else if (event.key.keysym.sym == SDLK_t)
957                                         input2.bit.b4 = 0;
958                                 else if (event.key.keysym.sym == SDLK_y)
959                                         input2.bit.b5 = 0;
960                                 else if (event.key.keysym.sym == SDLK_u)
961                                         input2.bit.b6 = 0;
962                                 else if (event.key.keysym.sym == SDLK_i)
963                                         input2.bit.b7 = 0;
964
965                                 else if (event.key.keysym.sym == SDLK_a)
966                                         input3.bit.b0 = 0;
967                                 else if (event.key.keysym.sym == SDLK_s)
968                                         input3.bit.b1 = 0;
969                                 else if (event.key.keysym.sym == SDLK_d)
970                                         input3.bit.b2 = 0;
971                                 else if (event.key.keysym.sym == SDLK_f)
972                                         input3.bit.b3 = 0;
973                                 else if (event.key.keysym.sym == SDLK_g)
974                                         input3.bit.b4 = 0;
975 #endif
976
977                                 break;
978                         case SDL_KEYUP:
979 #if 1
980                                 if (event.key.keysym.sym == SDLK_5)
981                                         input1.bit.b5 = 1;
982                                 else if (event.key.keysym.sym == SDLK_1)
983                                         input1.bit.b6 = 1;
984                                 else if (event.key.keysym.sym == SDLK_RIGHT)
985                                         input3.bit.b5 = 1;
986                                 else if (event.key.keysym.sym == SDLK_LEFT)
987                                         input3.bit.b4 = 1;
988                                 else if (event.key.keysym.sym == SDLK_UP)
989                                         input2.bit.b2 = 1;
990                                 else if (event.key.keysym.sym == SDLK_DOWN)
991                                         input1.bit.b2 = 1;
992                                 else if (event.key.keysym.sym == SDLK_q)        // (Q)  Jump
993                                         input1.bit.b1 = 1;
994                                 else if (event.key.keysym.sym == SDLK_e)        // (E) Fire
995                                         input3.bit.b3 = 1;
996 #else
997                                 if (event.key.keysym.sym == SDLK_1)
998                                         input1.bit.b0 = 1;
999                                 else if (event.key.keysym.sym == SDLK_2)
1000                                         input1.bit.b1 = 1;
1001                                 else if (event.key.keysym.sym == SDLK_3)
1002                                         input1.bit.b2 = 1;
1003                                 else if (event.key.keysym.sym == SDLK_4)
1004                                         input1.bit.b3 = 1;
1005                                 else if (event.key.keysym.sym == SDLK_5)
1006                                         input1.bit.b4 = 1;
1007                                 else if (event.key.keysym.sym == SDLK_6)
1008                                         input1.bit.b5 = 1;
1009                                 else if (event.key.keysym.sym == SDLK_7)
1010                                         input1.bit.b6 = 1;
1011                                 else if (event.key.keysym.sym == SDLK_8)
1012                                         input1.bit.b7 = 1;
1013
1014                                 else if (event.key.keysym.sym == SDLK_q)
1015                                         input2.bit.b0 = 1;
1016                                 else if (event.key.keysym.sym == SDLK_w)
1017                                         input2.bit.b1 = 1;
1018                                 else if (event.key.keysym.sym == SDLK_e)
1019                                         input2.bit.b2 = 1;
1020                                 else if (event.key.keysym.sym == SDLK_r)
1021                                         input2.bit.b3 = 1;
1022                                 else if (event.key.keysym.sym == SDLK_t)
1023                                         input2.bit.b4 = 1;
1024                                 else if (event.key.keysym.sym == SDLK_y)
1025                                         input2.bit.b5 = 1;
1026                                 else if (event.key.keysym.sym == SDLK_u)
1027                                         input2.bit.b6 = 1;
1028                                 else if (event.key.keysym.sym == SDLK_i)
1029                                         input2.bit.b7 = 1;
1030
1031                                 else if (event.key.keysym.sym == SDLK_a)
1032                                         input3.bit.b0 = 1;
1033                                 else if (event.key.keysym.sym == SDLK_s)
1034                                         input3.bit.b1 = 1;
1035                                 else if (event.key.keysym.sym == SDLK_d)
1036                                         input3.bit.b2 = 1;
1037                                 else if (event.key.keysym.sym == SDLK_f)
1038                                         input3.bit.b3 = 1;
1039                                 else if (event.key.keysym.sym == SDLK_g)
1040                                         input3.bit.b4 = 1;
1041 #endif
1042
1043                                 break;
1044                         }
1045                 }
1046
1047 #if 0
1048                                 if (keys[SDLK_ESCAPE])
1049                                         running = false;                     // ESC to exit...
1050
1051                                 if (debounce)
1052                                         debounce--;                          // Debounce toggle keys...
1053                                 else
1054                                 {
1055                                         if (keys[SDLK_F1])
1056                                         {
1057                                                 self_test = !self_test;            // Self-test (F1-toggle)
1058                                                 debounce = 10;                     // Key debounce value...
1059                                         }
1060                                         if (keys[SDLK_F2])
1061                                         {
1062                                                 gram1[0x4268] = 1;                 // Video test (F2)
1063                                                 debounce = 10;                     // Key debounce value...
1064                                         }
1065                                         if (keys[SDLK_F12])
1066                                         {
1067                                                 scr_type = !scr_type;              // Toggle screen (F12)
1068                                                 debounce = 10;                     // Key debounce value...
1069                                         }
1070                                         if (keys[SDLK_F3])
1071                                         {
1072                                                 show_scr = !show_scr;              // Toggle bkgrnd (F3)
1073                                                 debounce = 10;
1074                                         }
1075                                         if (keys[SDLK_F6])
1076                                         {
1077                                                 enable_cpu = !enable_cpu;          // Toggle CPUs (F6)
1078                                                 debounce = 10;
1079                                         }
1080                                         if (keys[SDLK_F5])
1081                                         {
1082                                                 refresh2 = !refresh2;             // Toggle 30/60Hz (F5)
1083                                                 SetRefreshRate(refresh2);         // Inform GUI of refresh
1084                                                 if (refresh2)
1085                                                         SpawnMsg(M60FPS);
1086                                                 else
1087                                                         SpawnMsg(M30FPS);
1088                                                 debounce = 10;                    // Key debounce value...
1089                                         }
1090                                         if (keys[SDLK_F4])                      // Do PCX snapshot (F4)
1091                                         {
1092                                                 SpawnSound(USERSOUND, SCAMERA);
1093                                                 SnapPCX(screen);
1094                                                 debounce = 10;
1095                                         }
1096                                         if (keys[SDLK_TAB])                      // Tab active/deactivate GUI
1097                                         {
1098                                                 if (ShowGUI())
1099                                                         DeactivateGUI();
1100                                                 else
1101                                                         ActivateGUI();
1102
1103                                                 debounce = 10;
1104                                         }
1105                                 }
1106                                 //if (keys[0x3E])  gram1[0x4247] = 1;  // Screen hold DS (F4)
1107                                 if (keys[SDLK_RIGHT])                                           // Right arrow
1108                                 {
1109                                         if (ShowGUI())
1110                                                 SelectRight();                     // If GUI active...
1111                                         else
1112                                         {
1113                                                 if (!keys[SDLK_LEFT])                     // Disallow opposite directions @ same time
1114                                                         gram1[0x427F] = 1;               // Stick right
1115                                         }
1116                                 }
1117                                 if (keys[SDLK_LEFT])
1118                                 {
1119                                         if (ShowGUI())
1120                                                 SelectLeft();                      // If GUI active...
1121                                         else
1122                                         {
1123                                                 if (!keys[SDLK_RIGHT])                     // Disallow opposite directions@same time
1124                                                 gram1[0x4281] = 1;               // Left arrow
1125                                         }
1126                                 }
1127                                 if (keys[SDLK_UP])
1128                                 {
1129                                         if (ShowGUI())
1130                                                 SelectUp();                        // If GUI active...
1131                                         else
1132                                         {
1133                                                 if (!keys[SDLK_DOWN])                     // Disallow opposite directions@same time
1134                                                         gram1[0x427B] = 1;               // Up arrow
1135                                         }
1136                                 }
1137                                 if (keys[SDLK_DOWN])
1138                                 {
1139                                         if (ShowGUI())
1140                                                 SelectDown();                                   // If GUI active...
1141                                         else
1142                                         {
1143                                                 if (!keys[SDLK_UP])                             // Disallow opposite directions@same time
1144                                                         gram1[0x427D] = 1;                      // Down arrow
1145                                         }
1146                                 }
1147                                 if (keys[SDLK_RETURN])                                                  // Return
1148                                 {
1149                                         uint8_t retval = UserSelectedSomething();
1150
1151                                         if (retval == EXIT)
1152                                                 running = false;
1153
1154                                         if (retval == REFRESH)
1155                                         {
1156                                                 refresh2 = !refresh2;
1157                                                 SetRefreshRate(refresh2);
1158                                         }
1159                                 }
1160
1161                                 if (keys[SDLK_1])
1162                                         gram1[0x427A] = 1;                      // (1)
1163
1164                                 if (keys[SDLK_2])
1165                                         gram1[0x427C] = 1;                      // (2)
1166
1167                                 if (keys[SDLK_3])
1168                                         gram1[0x427E] = 1;                      // (3)
1169
1170                                 if (keys[SDLK_5])
1171                                         gram1[0x4280] = 1;                      // (5)
1172
1173                                 if (keys[SDLK_q] | keys[29])
1174                                         gram1[0x4276] = 1;                      // (Q)  Jump
1175
1176                                 if (keys[SDLK_w])
1177                                         gram1[0x426A] = 1;                      // (W)
1178
1179                                 if (fire_debounce)
1180                                         fire_debounce--;
1181
1182                                 if (keys[SDLK_e] | keys[56])    // (E) Fire
1183                                 {
1184                                         if (!fire_debounce)
1185                                         {
1186                                                 gram1[0x4278] = 1;
1187
1188                                                 if (gram1[0x3F08] == 0xFF)              // Ugly kludge for debouncing gun
1189                                                         fire_debounce = 8;
1190                                                 else
1191                                                         fire_debounce = 2;
1192                                         }
1193                                 }
1194
1195                                 if (keys[SDLK_r])
1196                                         gram1[0x426C] = 1;                      // (R)
1197
1198                                 if (keys[SDLK_t])
1199                                         gram1[0x4262] = 1;                      // (T)
1200
1201                                 if (keys[SDLK_y])
1202                                         gram1[0x4260] = 1;                      // (Y)
1203
1204                                 if (keys[SDLK_F10])
1205                                         gram1[0x41A5]++;                        // Coin? (F10)
1206
1207                                 if (keys[SDLK_z])
1208                                         gram1[0x4189]++;                        // ? (Z) credits l dig
1209
1210                                 if (keys[SDLK_x])
1211                                         gram1[0x418A]++;                        // ? (X) credits r dig
1212
1213                                 if (keys[SDLK_c])
1214                                         gram1[0x418C]++;                        // ? (C) Start
1215
1216                                 if (keys[SDLK_v])
1217                                         gram1[0x418D]++;                        // ? (V)
1218
1219                                 if (keys[SDLK_F7])
1220                                         SpawnSound(USERSOUND, 0);       // Do user sound (F7)
1221
1222 //                              if (keys[SDLK_F8])
1223 //                              {
1224 //                                      gram1[0x4380] = 0;                      // (F8) kill music (this worx)
1225 //                                      charbase = false;                       // Switch chars out...
1226 //                              }
1227 //                              if (keys[SDLK_F9])  gram1[0x4285] = 1;          // (F9) strobe unknown loc
1228
1229                                 if (keys[SDLK_F11])                             // (F11)
1230                                 {
1231                                         Execute6809(&cpu1, 10);
1232                                         Execute6809(&cpu2, 10);
1233                                 }
1234 //                      }
1235 //F12 is used above, but the values are ignored. So we'll do it here too.
1236                                 if (keys[SDLK_F12])
1237                                 {
1238                                         cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET;
1239                                         cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET;
1240                                 }
1241
1242                                 if (keys[SDLK_d])                               // (D) start disassembly
1243                                         disasm = true;
1244 #if 0
1245         if (keys[SDLK_k])
1246                 gram1[0x5606] = 0x00;
1247         if (keys[SDLK_l])
1248         {
1249                 gram1[0x5607] = 0x01; // Hangs here... (CPU #1 waiting...)
1250                 WriteLog("\nMAIN: Stuffed $01 in $5607!!!\n\n");
1251         }
1252         if (keys[SDLK_o])
1253         {
1254                 gram1[0x5FF3] = 0x02;
1255                 WriteLog("\nMAIN: Stuffed $02 in $5FF3!!!\n\n");
1256         }
1257 #endif
1258 #endif
1259
1260                 if (enable_cpu)
1261 //                              if (true)
1262                 {
1263                         // We can do this here because we're not executing the cores yet.
1264                         cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ;
1265                         cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ;
1266                         mcu.cpuFlags |= V63701_ASSERT_LINE_IRQ;
1267 //                                      while (cpu1.clock < 25000)
1268 // 1.538 MHz = 25633.333... cycles per frame (1/60 s)
1269 // 25600 cycles/frame
1270 // Setting interleave to 25 and below causes the V6809 core to hang...
1271 // 32 gets to the title screen before hanging...
1272 // 40 works, until it doesn't... :-P
1273 // 640 * 40
1274 // 800 * 32
1275 // Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though.
1276                         for(uint32_t i=0; i<640; i++)
1277 //                                      for(uint32_t i=0; i<1280; i++)
1278                         {
1279                                 // Gay, but what are ya gonna do?
1280                                 // There's better ways, such as keeping track of when slave writes to master, etc...
1281                                 Execute6809(&cpu1, 40);
1282                                 Execute6809(&cpu2, 40);
1283
1284                                 // MCU runs at 1,536,000 Hz
1285                                 // 1536000 / 60 / 640 == 40
1286                                 Execute63701(&mcu, 40);
1287                         }
1288                 } // END: enable_cpu
1289
1290                 // Speed throttling happens here...
1291                 while (SDL_GetTicks() - oldTicks < 16)  // Actually, it's 16.66... Need to account for that somehow
1292 //                              while (SDL_GetTicks() - oldTicks < 32)  // Actually, it's 16.66... Need to account for that somehow
1293                         SDL_Delay(1);                           // Release our timeslice...
1294
1295                 oldTicks = SDL_GetTicks();
1296 //cout << "Finished frame..." << endl;
1297         }
1298
1299         SDL_Quit();
1300
1301         // Deallocate sounds if they were loaded
1302         for(int i=0; i<16; i++)
1303                 if (psg_adrs[i])
1304                         delete[] psg_adrs[i];
1305
1306 #if 0
1307         for(int i=0; i<14; i++)
1308                 if (fm_adrs[i])
1309                         delete[] fm_adrs[i];
1310 #endif
1311
1312         LogDone();
1313
1314         return 1;
1315 }
1316
1317 #if 0
1318 Hitachi uC runs at 6.144 MHz
1319 YM2151 runs at 3.579580 MHz
1320
1321
1322 Rolling Thunder Memory map
1323 --------------------------
1324 Most of the decoding is done by custom chips (CUS47 and CUS41), so the memory
1325 map is inferred by program behaviour. The customs also handle internally irq
1326 and watchdog.
1327
1328 The main CPU memory map is the same in all games because CUS47 is used by all
1329 games. The sub CPU and sound CPU, on the other hand, change because CUS41 is
1330 replaced by other chips.
1331
1332 All RAM is shared between main and sub CPU, except for sound RAM which is
1333 shared between main and sound CPU; the portion of object RAM that is overlapped
1334 by sound RAM is used exclusively by the sub CPU.
1335
1336 MAIN CPU:
1337
1338 Address             Dir Data     Name      Description
1339 ------------------- --- -------- --------- -----------------------
1340 000x xxxx xxxx xxxx R/W xxxxxxxx SCROLL0   tilemap 0/1 RAM (shared with sub CPU)
1341 001x xxxx xxxx xxxx R/W xxxxxxxx SCROLL1   tilemap 2/3 RAM (shared with sub CPU)
1342 0100 00xx xxxx xxxx R/W xxxxxxxx SOUND     sound RAM (through CUS30, shared with MCU)
1343 0100 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1344 0100 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1345 010x xxxx xxxx xxxx R/W xxxxxxxx OBJECT    work RAM (shared with sub CPU) [1]
1346 0101 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1347 011x xxxx xxxx xxxx R   xxxxxxxx ROM 9D    program ROM (banked) [2]
1348 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 9C    program ROM
1349 1000 00-- ---- ----   W --------           watchdog reset (RES generated by CUS47)
1350 1000 01-- ---- ----   W --------           main CPU irq acknowledge (IRQ generated by CUS47)
1351 1000 1x-- ---- ----   W -------- BANK      tile gfx bank select (data is in A10) (latch in CUS47)
1352 1001 00-- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1353 1001 00-- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1354 1001 00-- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1355 1001 01-- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1356 1001 01-- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1357 1001 01-- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1358 1100 00-- ---- ----   W xxxxxxxx BACKCOLOR background color
1359
1360 [1] Note that this is partially overlapped by sound RAM
1361 [2] In Rolling Thunder and others, replaced by the ROM/voice expansion board
1362
1363
1364 SUB CPU:
1365
1366 Address             Dir Data     Name      Description
1367 ------------------- --- -------- --------- -----------------------
1368 000x xxxx xxxx xxxx R/W xxxxxxxx SUBOBJ    work RAM (shared with main CPU)
1369 0001 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1370 001x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR0   tilemap 0/1 RAM (shared with main CPU)
1371 010x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR1   tilemap 2/3 RAM (shared with main CPU)
1372 011x xxxx xxxx xxxx R   xxxxxxxx ROM 12D   program ROM (banked) [1]
1373 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 12C   program ROM
1374 1000 0--- ---- ----   W --------           watchdog reset (MRESET generated by CUS41)
1375 1000 1--- ---- ----   W --------           main CPU irq acknowledge (generated by CUS41)
1376 1101 0--- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1377 1101 0--- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1378 1101 0--- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1379 1101 1--- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1380 1101 1--- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1381 1101 1--- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1382
1383 [1] Only used by Rolling Thunder
1384
1385
1386 MCU:
1387
1388 Address             Dir Data     Name      Description
1389 ------------------- --- -------- --------- -----------------------
1390 0000 0000 xxxx xxxx                        MCU internal registers, timers, ports and RAM
1391 0001 xxxx xxxx xxxx R/W xxxxxxxx RAM 3F    sound RAM (through CUS30, partially shared with main CPU)
1392 0001 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1393 0001 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1394 0010 0--- --00 ---x R/W xxxxxxxx YMCS      YM2151
1395 0010 0--- --01 ----                        n.c.
1396 0010 0--- --10 ---- R   xxxxxxxx PORTA     switch inputs
1397 0010 0--- --11 ---- R   xxxxxxxx PORTB     dip switches
1398 01xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (lower half)
1399 10xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (upper half)
1400 1011 0--- ---- ----   W                    unknown (CUS41)
1401 1011 1--- ---- ----   W                    unknown (CUS41)
1402 1111 xxxx xxxx xxxx R   xxxxxxxx           MCU internal ROM
1403
1404
1405 Notes:
1406 -----
1407 - we are using an unusually high CPU interleave factor (800) to avoid hangs
1408   in rthunder. The two 6809 in this game synchronize using a semaphore at
1409   5606/5607 (CPU1) 1606/1607 (CPU2). CPU1 clears 5606, does some quick things,
1410   and then increments 5606. While it does its quick things (which require
1411   about 40 clock cycles) it expects CPU2 to clear 5607.
1412   Raising the interleave factor to 1000 makes wndrmomo crash during attract
1413   mode. I haven't investigated on the cause.
1414
1415 - There are two watchdogs, one per CPU (or maybe three). Handling them
1416   separately is necessary to allow entering service mode without manually
1417   resetting in rthunder and genpeitd: only one of the CPUs stops writing to
1418   the watchdog.
1419
1420 - The sprite hardware buffers spriteram: the program writes the sprite list to
1421   offsets 4-9 of every 16-byte block, then at the end writes to offset 0x1ff2 of
1422   sprite RAM to signal the chip that the list is complete. The chip will copy
1423   the list from 4-9 to 10-15 and use it from there. This has not been verified
1424   on the real hardware, but it is the most logical way of doing it.
1425   Emulating this behaviour and not using an external buffer is important in
1426   rthunder: when you insert a coin, the whole sprite RAM is cleared, but 0x1ff2
1427   is not written to. If we buffered spriteram to an external buffer, this would
1428   cause dangling sprites because the buffer would not be updated.
1429
1430 - spriteram buffering fixes sprite lag, but causes a glitch in rthunder when
1431   entering a door. The *closed* door is made of tiles, but the *moving* door is
1432   made of sprites. Since sprites are delayed by 1 frame, when you enter a door
1433   there is one frame where neither the tile-based closed door nor the
1434   sprite-based moving door is shown, so it flickers. This behavior has been
1435   confirmed on a real PCB.
1436
1437 TODO:
1438 ----
1439 - The two unknown writes for the MCU are probably watchdog reset and irq acknowledge,
1440   but they don't seem to work as expected. During the first few frames they are
1441   written out of order and hooking them up in the usual way causes the MCU to
1442   stop receiving interrupts.
1443
1444 #endif
1445