2 // Thunder: A Rolling Thunder Emulator
5 // (C) 2004, 2023 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- -----------------------------------------------------------
11 // JLH 07/23/2009 Added changelog ;-)
12 // JLH 08/12/2009 Stabilized emulation so that it works
13 // JLH 04/04/2014 Converted to SDL 2
14 // JLH 04/17/2014 Removed a metric fuck-tonne of cruft, added YM2151 & MCU
15 // JLH 01/13/2023 Finally fixed the sprite lag problem :-D
18 #define THUNDER_VERSION "1.2.1"
36 #define ROM1 "rt3-1b.9c"
37 #define ROM2 "rt3-2b.12c"
38 #define ROM3 "rt3-3.12d"
39 #define ROM4 "rt1-4.6b"
40 #define ROM5 "rt1-5.4r"
41 #define ROM6 "rt1-6.4s"
42 #define ROM7 "rt1-7.7r"
43 #define ROM8 "rt1-8.7s"
44 #define ROM9 "rt1-9.12h"
45 #define ROM10 "rt1-10.12k"
46 #define ROM11 "rt1-11.12l"
47 #define ROM12 "rt1-12.12m"
48 #define ROM13 "rt1-13.12p"
49 #define ROM14 "rt1-14.12r"
50 #define ROM15 "rt1-15.12t"
51 #define ROM16 "rt1-16.12u"
52 #define ROM17 "rt1-17.f1"
53 #define ROM18 "rt1-18.h1"
54 #define ROM19 "rt1-19.k1"
55 #define ROM20 "rt1-20.m1"
56 #define ROM21 "rt1-21.f3"
57 #define ROM22 "rt1-22.h3"
58 #define PROM1 "mb7124e.3r"
59 #define PROM2 "mb7116e.3s"
60 #define PROM3 "mb7138h.4v"
61 #define PROM4 "mb7138h.6v"
62 #define PROM5 "mb7112e.6u"
63 #define MCUROM "rt1-mcu.bin"
67 uint8_t gram1[0x10000], grom1[0x10000], grom2[0x10000];
68 uint8_t grom3[0x8000], data_rom[0x40000], spr_rom[0x80000], voice_rom[0x20000];
69 uint8_t charROM[0x60000]; // Character ROM
70 uint8_t mcuMem[0x10000]; // 64K for MCU
72 // CPU execution contexts
76 // Bank switch addresses
77 uint32_t banksw1, banksw2;
80 Byte input1, input2, input3, input4, input5;
83 bool copySprites = false;
85 // Function prototypes
86 uint8_t MCUReadMemory(uint16_t address);
87 void MCUWriteMemory(uint16_t address, uint8_t data);
90 // Read a byte from memory
92 uint8_t MainReadMemory(uint16_t addr)
98 // Memory shared with MCU (CPU #1 only! CPU #2 does not)
99 if ((addr >= 0x4000) && (addr <= 0x43FF))
100 return mcuMem[addr - 0x3000];
103 return data_rom[banksw1 + (addr - 0x6000)]; // Get char data
112 // Write a byte to memory
114 void MainWriteMemory(uint16_t address, uint8_t data)
116 if (address == 0x6000)
117 SpawnSound(GAMESOUND, gram1[0x6200], 0); // Do voice chan 1
118 if (address == 0x6400)
119 SpawnSound(GAMESOUND, gram1[0x6600], 1); // Do voice chan 2
120 if (address == 0x6800)
121 banksw1 = (uint32_t)data << 13; // Set char data bankswitch base address
123 // Memory shared with MCU (CPU #1 only! CPU #2 does not)
124 if ((address >= 0x4000) && (address <= 0x43FF))
125 mcuMem[address - 0x3000] = data;
127 gram1[address] = data;
129 if (address == 0x5FF2)
131 if (address == 0x8800)
132 charBankSwitch = false; // Char banksw1
133 if (address == 0x8C00)
134 charBankSwitch = true; // Char banksw2
135 if (address == 0x8400) // Frame go strobe? VBlank acknowledge?
136 ClearLineOfCurrentV6809(V6809_LINE_IRQ); // IRQ Ack
140 // Read a byte from memory (2nd processor)
142 uint8_t SubReadMemory(uint16_t address)
144 if (address < 0x8000)
146 if (address < 0x2000)
147 return gram1[address + 0x4000];
148 else if ((address >= 0x2000) && (address < 0x6000))
149 return gram1[address - 0x2000];
150 else if (address >= 0x6000)
151 return grom3[banksw2 + (address - 0x6000)];
154 return grom2[address];
158 // Write a byte to memory (2nd processor)
160 void SubWriteMemory(uint16_t address, uint8_t data)
162 // Set sprite data bank switch
163 if (address == 0xD803)
164 banksw2 = (uint32_t)(data & 0x03) << 13;
166 if (address < 0x2000)
167 gram1[address + 0x4000] = data;
169 if ((address >= 0x2000) && (address < 0x6000))
170 gram1[address - 0x2000] = data;
172 if (address == 0x1FF2)
175 if (address == 0x8800)
176 ClearLineOfCurrentV6809(V6809_LINE_IRQ); // IRQ Ack
179 uint8_t MCUReadMemory(uint16_t address)
182 return InternalRegisterRead(address);
183 else if ((address >= 0x1000) && (address <= 0x113F))
184 return ReadPSG(address - 0x1000);
185 else if ((address >= 0x2000) && (address <= 0x2001))
187 // Various joystick + buttons; all are active low.
188 else if (address == 0x2020)
190 else if (address == 0x2021)
192 // This is DSW1 & 2. All switch settings are active low.
193 else if (address == 0x2030)
195 else if (address == 0x2031)
198 return mcuMem[address];
201 void MCUWriteMemory(uint16_t address, uint8_t data)
203 static uint8_t ymRegister;
207 InternalRegisterWrite(address, data);
210 else if (((address >= 0x4000) && (address <= 0xBFFF))
211 || (address >= 0xF000))
213 else if ((address >= 0x1000) && (address <= 0x113F))
215 WritePSG(address - 0x1000, data);
218 else if (address == 0x2000)
223 else if (address == 0x2001)
225 YMWriteReg(0, ymRegister, data);
229 // RAM is from $0 - $3FFF, $C000 - $EFFF
230 mcuMem[address] = data;
233 uint8_t V63701ReadPort1(void)
235 // printf("V63701ReadPort1: Read $%02X...\n", input3.byte);
239 uint8_t V63701ReadPort2(void)
244 void V63701WritePort1(uint8_t data)
246 // printf("V63701WritePort1: Wrote $%02X...\n", data);
249 void V63701WritePort2(uint8_t data)
251 // printf("V63701WritePort2: Wrote $%02X...\n", data);
255 // Generic Load file into image space
256 // (No error checking performed! Responsibility of caller!)
258 bool LoadImg(const char * filename, uint8_t * mem, uint32_t address, uint32_t length)
262 strcpy(path, "./ROMs/");
263 strcat(path, filename);
264 FILE * file = fopen(path, "rb");
268 printf("Could not open file \"%s\"!\n", filename);
272 size_t ignored = fread(&mem[address], 1, length, file);
281 bool ReadColorPROMs(void)
283 FILE * file1 = fopen("./ROMs/" PROM3, "rb");
287 for(int i=0; i<256; i++) // Load char pallete with PROM values
288 for(int j=0; j<8; j++)
289 ccolor[i][j] = (uint8_t)fgetc(file1);
294 file1 = fopen("./ROMs/" PROM4, "rb");
298 for(int i=0; i<128; i++) // Load sprite pallete with PROM values
299 for(int j=0; j<16; j++)
300 scolor[i][j] = (uint8_t)fgetc(file1);
305 file1 = fopen("./ROMs/" PROM1, "rb");
306 FILE * file2 = fopen("./ROMs/" PROM2, "rb");
308 // If open was successful...
311 // Palette is 12-bit RGB, we stretch it to 24-bit
312 for(int i=0; i<256; i++)
314 uint8_t c1 = fgetc(file1);
315 uint8_t c2 = fgetc(file2);
316 uint8_t r = (uint8_t)c1 & 0x0F;
317 uint8_t g = (uint8_t)c1 >> 4;
318 uint8_t b = (uint8_t)c2;
319 palette[i] = 0xFF000000 | (b << 20) | (b << 16) | (g << 12) | (g << 8) | (r << 4) | r;
326 // PROM5 has the following in it (tile address decoder):
327 // 00: 00 20 40 60 02 22 42 62 04 24 44 64 06 26 46 66
328 // 10: 88 A8 C8 E8 8A AA CA EA 8C AC CC EC 8E AE CE EE
332 printf("Could not open PROM files!\n");
342 bool UnpackFonts(void)
345 FILE * file1 = fopen("./ROMs/" ROM7, "rb");
346 FILE * file2 = fopen("./ROMs/" ROM8, "rb");
348 if (!file1 || !file2)
350 printf("Could not open either " ROM7 " or " ROM8 "!\n");
354 for(long i=0; i<0x40000; i+=64)
356 for(int j=0; j<64; j+=8)
358 uint8_t b1 = (uint8_t)fgetc(file1);
359 uint8_t b2 = (uint8_t)fgetc(file1);
360 uint8_t b3 = (uint8_t)fgetc(file2) ^ 0xFF;
361 charROM[i + j + 0] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
362 charROM[i + j + 1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
363 charROM[i + j + 2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
364 charROM[i + j + 3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
365 charROM[i + j + 4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
366 charROM[i + j + 5] = (b3 & 0x04) | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
367 charROM[i + j + 6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
368 charROM[i + j + 7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
375 file1 = fopen("./ROMs/" ROM5, "rb");
376 file2 = fopen("./ROMs/" ROM6, "rb");
378 if (!file1 || !file2)
380 printf("Could not open either " ROM5 " or " ROM6 "!\n");
384 for(long i=0x40000; i<0x60000; i+=64)
386 for(int j=0; j<64; j+=8)
388 uint8_t b1 = (uint8_t)fgetc(file1);
389 uint8_t b2 = (uint8_t)fgetc(file1);
390 uint8_t b3 = (uint8_t)fgetc(file2) ^ 0xFF;
391 charROM[i + j + 0] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
392 charROM[i + j + 1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
393 charROM[i + j + 2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
394 charROM[i + j + 3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
395 charROM[i + j + 4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
396 charROM[i + j + 5] = (b3 & 0x04) | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
397 charROM[i + j + 6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
398 charROM[i + j + 7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
411 int main(int argc, char * argv[])
413 InitLog("thunder.log");
415 bool running; // CPU running state flag...
416 SDL_Event event; // SDL "event"
417 uint32_t ticks, oldTicks;
418 uint8_t frameTickCount = 0;
420 printf("THUNDER v" THUNDER_VERSION " by James Hammons\n");
421 printf("Serial #20230113 / Prerelease\n");
422 printf("© 2003, 2023 Underground Software\n\n");
423 printf("This emulator is free software. If you paid for it you were RIPPED OFF\n\n");
425 // SDL_WM_SetCaption("Thunder v"THUNDER_VERSION" ", "Thunder");
427 printf("Loading ROMs...\n");
429 if (!ReadColorPROMs())
432 // Load $8000-$FFFF 1st ROM
433 if (!LoadImg(ROM1, grom1, 0x8000, 0x8000))
436 // Load $8000-$FFFF 2nd ROM
437 if (!LoadImg(ROM2, grom2, 0x8000, 0x8000))
440 // Load 3rd ROM into its own space
441 if (!LoadImg(ROM3, grom3, 0, 0x8000))
444 if (!LoadImg(ROM17, data_rom, 0, 0x10000))
447 if (!LoadImg(ROM18, data_rom, 0x10000, 0x10000))
450 if (!LoadImg(ROM19, data_rom, 0x20000, 0x10000))
453 if (!LoadImg(ROM20, data_rom, 0x30000, 0x10000))
456 if (!LoadImg(ROM9, spr_rom, 0, 0x10000))
459 if (!LoadImg(ROM10, spr_rom, 0x10000, 0x10000))
462 if (!LoadImg(ROM11, spr_rom, 0x20000, 0x10000))
465 if (!LoadImg(ROM12, spr_rom, 0x30000, 0x10000))
468 if (!LoadImg(ROM13, spr_rom, 0x40000, 0x10000))
471 if (!LoadImg(ROM14, spr_rom, 0x50000, 0x10000))
474 if (!LoadImg(ROM15, spr_rom, 0x60000, 0x10000))
477 if (!LoadImg(ROM16, spr_rom, 0x70000, 0x10000))
480 if (!LoadImg(ROM21, voice_rom, 0, 0x10000))
483 if (!LoadImg(ROM22, voice_rom, 0x10000, 0x10000))
486 // Load 5, 6, 7, 8th ROMs
490 // Load MCU program + data
491 if (!LoadImg(MCUROM, mcuMem, 0xF000, 0x1000))
494 if (!LoadImg(ROM4, mcuMem, 0x4000, 0x8000))
497 // Set up V6809, V63701 execution contexts
498 memset(&cpu1, 0, sizeof(V6809REGS));
499 cpu1.RdMem = MainReadMemory;
500 cpu1.WrMem = MainWriteMemory;
501 cpu1.cpuFlags |= V6809_LINE_RESET;
503 memset(&cpu2, 0, sizeof(V6809REGS));
504 cpu2.RdMem = SubReadMemory;
505 cpu2.WrMem = SubWriteMemory;
506 cpu2.cpuFlags |= V6809_LINE_RESET;
508 memset(&mcu, 0, sizeof(V63701REGS));
509 mcu.RdMem = MCUReadMemory;
510 mcu.WrMem = MCUWriteMemory;
511 mcu.cpuFlags |= V63701_LINE_RESET;
515 // Set all inputs to inactive...
516 input1.byte = input2.byte = input3.byte = 0xFF;
519 InitGUI(); // Reset # of coins
521 // Set up DIP switches...
522 input4.bit.b0 = 1; // DSW B-0: Continues (1 = 6, 0 = 3)
523 input4.bit.b1 = 1; // DSW B-2: ???
524 input4.bit.b2 = 1; // DSW B-4: Difficulty (1 = normal, 0 = easy)
525 input4.bit.b3 = 1; // DSW B-6: Bonus lives (70K/200K = 1, 100K/300K = 0)
526 input4.bit.b4 = 1; // DSW A-0: Coin #2 credit
527 input4.bit.b5 = 1; // DSW A-2: Freeze mode (0 = freeze)
528 input4.bit.b6 = 1; // DSW A-4: Attract mode sound (1 = on)
529 input4.bit.b7 = 1; // DSW A-6: Coin #1 credit
531 input5.bit.b0 = 1; // DSW B-1: Cabinet type (1 = A, 0 = B)
532 input5.bit.b1 = 0; // DSW B-3: Level select (0 = on)
533 input5.bit.b2 = 0; // DSW B-5: Time (1 = 120, 0 = 150)
534 input5.bit.b3 = 0; // DSW B-7: Lives (1 = 3, 0 = 5)
535 input5.bit.b4 = 1; // DSW A-1: Coin #2 credit
536 input5.bit.b5 = 1; // DSW A-3: Invulnerability (0 = on)
537 input5.bit.b6 = 1; // DSW A-5: Coin #1 credit
538 input5.bit.b7 = 1; // DSW A-7: Service mode
540 WriteLog("About to set up screen...\n");
543 oldTicks = SDL_GetTicks();
545 WriteLog("About to set up audio...\n");
548 WriteLog("About to enter main loop...\n");
551 // HandleGUIDebounce(); // Debounce GUI keys
553 // Dipswitches are presented to the main CPUs as 0 or 1 at locations
554 // $423D - $425B by the MCU
556 // SDL key handling...
560 while (SDL_PollEvent(&event))
565 if (event.key.keysym.sym == SDLK_ESCAPE)
567 // Do PCX snapshot (F4)
568 else if (event.key.keysym.sym == SDLK_F4)
570 // SpawnSound(USERSOUND, SCAMERA);
574 else if (event.key.keysym.sym == SDLK_5)
576 else if (event.key.keysym.sym == SDLK_1)
578 else if (event.key.keysym.sym == SDLK_2)
580 else if (event.key.keysym.sym == SDLK_c) // Left
582 else if (event.key.keysym.sym == SDLK_z) // Right
584 else if (event.key.keysym.sym == SDLK_s) // Up
586 else if (event.key.keysym.sym == SDLK_x) // Down
588 else if (event.key.keysym.sym == SDLK_k) // Jump
590 else if (event.key.keysym.sym == SDLK_l) // Fire
593 else if (event.key.keysym.sym == SDLK_F1) // Service mode
594 input5.bit.b7 = !input5.bit.b7;
596 else if (event.key.keysym.sym == SDLK_q)
597 input4.bit.b7 = !input4.bit.b7;
598 else if (event.key.keysym.sym == SDLK_w)
599 input5.bit.b6 = !input5.bit.b6;
600 else if (event.key.keysym.sym == SDLK_e)
601 input5.bit.b5 = !input5.bit.b5;
602 else if (event.key.keysym.sym == SDLK_r)
603 input5.bit.b4 = !input5.bit.b4;
604 else if (event.key.keysym.sym == SDLK_t)
605 input5.bit.b3 = !input5.bit.b3;
606 else if (event.key.keysym.sym == SDLK_y)
607 input5.bit.b2 = !input5.bit.b2;
608 else if (event.key.keysym.sym == SDLK_u)
609 input5.bit.b1 = !input5.bit.b1;
610 else if (event.key.keysym.sym == SDLK_i)
611 input5.bit.b0 = !input5.bit.b0;
614 else if (event.key.keysym.sym == SDLK_1)
616 else if (event.key.keysym.sym == SDLK_2)
618 else if (event.key.keysym.sym == SDLK_3)
620 else if (event.key.keysym.sym == SDLK_4)
622 else if (event.key.keysym.sym == SDLK_5)
624 else if (event.key.keysym.sym == SDLK_6)
626 else if (event.key.keysym.sym == SDLK_7)
628 else if (event.key.keysym.sym == SDLK_8)
631 else if (event.key.keysym.sym == SDLK_q)
633 else if (event.key.keysym.sym == SDLK_w)
635 else if (event.key.keysym.sym == SDLK_e)
637 else if (event.key.keysym.sym == SDLK_r)
639 else if (event.key.keysym.sym == SDLK_t)
641 else if (event.key.keysym.sym == SDLK_y)
643 else if (event.key.keysym.sym == SDLK_u)
645 else if (event.key.keysym.sym == SDLK_i)
648 else if (event.key.keysym.sym == SDLK_a)
650 else if (event.key.keysym.sym == SDLK_s)
652 else if (event.key.keysym.sym == SDLK_d)
654 else if (event.key.keysym.sym == SDLK_f)
656 else if (event.key.keysym.sym == SDLK_g)
663 if (event.key.keysym.sym == SDLK_5)
665 else if (event.key.keysym.sym == SDLK_1)
667 else if (event.key.keysym.sym == SDLK_2)
669 else if (event.key.keysym.sym == SDLK_c)
671 else if (event.key.keysym.sym == SDLK_z)
673 else if (event.key.keysym.sym == SDLK_s)
675 else if (event.key.keysym.sym == SDLK_x)
677 else if (event.key.keysym.sym == SDLK_k) // (Q) Jump
679 else if (event.key.keysym.sym == SDLK_l) // (E) Fire
682 if (event.key.keysym.sym == SDLK_1)
684 else if (event.key.keysym.sym == SDLK_2)
686 else if (event.key.keysym.sym == SDLK_3)
688 else if (event.key.keysym.sym == SDLK_4)
690 else if (event.key.keysym.sym == SDLK_5)
692 else if (event.key.keysym.sym == SDLK_6)
694 else if (event.key.keysym.sym == SDLK_7)
696 else if (event.key.keysym.sym == SDLK_8)
699 else if (event.key.keysym.sym == SDLK_q)
701 else if (event.key.keysym.sym == SDLK_w)
703 else if (event.key.keysym.sym == SDLK_e)
705 else if (event.key.keysym.sym == SDLK_r)
707 else if (event.key.keysym.sym == SDLK_t)
709 else if (event.key.keysym.sym == SDLK_y)
711 else if (event.key.keysym.sym == SDLK_u)
713 else if (event.key.keysym.sym == SDLK_i)
716 else if (event.key.keysym.sym == SDLK_a)
718 else if (event.key.keysym.sym == SDLK_s)
720 else if (event.key.keysym.sym == SDLK_d)
722 else if (event.key.keysym.sym == SDLK_f)
724 else if (event.key.keysym.sym == SDLK_g)
733 if (keys[SDLK_ESCAPE])
734 running = false; // ESC to exit...
737 debounce--; // Debounce toggle keys...
742 self_test = !self_test; // Self-test (F1-toggle)
743 debounce = 10; // Key debounce value...
747 gram1[0x4268] = 1; // Video test (F2)
748 debounce = 10; // Key debounce value...
752 scr_type = !scr_type; // Toggle screen (F12)
753 debounce = 10; // Key debounce value...
757 show_scr = !show_scr; // Toggle bkgrnd (F3)
762 enable_cpu = !enable_cpu; // Toggle CPUs (F6)
767 refresh2 = !refresh2; // Toggle 30/60Hz (F5)
768 SetRefreshRate(refresh2); // Inform GUI of refresh
773 debounce = 10; // Key debounce value...
775 if (keys[SDLK_F4]) // Do PCX snapshot (F4)
777 SpawnSound(USERSOUND, SCAMERA);
781 if (keys[SDLK_TAB]) // Tab active/deactivate GUI
791 //if (keys[0x3E]) gram1[0x4247] = 1; // Screen hold DS (F4)
792 if (keys[SDLK_RIGHT]) // Right arrow
795 SelectRight(); // If GUI active...
798 if (!keys[SDLK_LEFT]) // Disallow opposite directions @ same time
799 gram1[0x427F] = 1; // Stick right
805 SelectLeft(); // If GUI active...
808 if (!keys[SDLK_RIGHT]) // Disallow opposite directions@same time
809 gram1[0x4281] = 1; // Left arrow
815 SelectUp(); // If GUI active...
818 if (!keys[SDLK_DOWN]) // Disallow opposite directions@same time
819 gram1[0x427B] = 1; // Up arrow
825 SelectDown(); // If GUI active...
828 if (!keys[SDLK_UP]) // Disallow opposite directions@same time
829 gram1[0x427D] = 1; // Down arrow
832 if (keys[SDLK_RETURN]) // Return
834 uint8_t retval = UserSelectedSomething();
839 if (retval == REFRESH)
841 refresh2 = !refresh2;
842 SetRefreshRate(refresh2);
847 gram1[0x427A] = 1; // (1)
850 gram1[0x427C] = 1; // (2)
853 gram1[0x427E] = 1; // (3)
856 gram1[0x4280] = 1; // (5)
858 if (keys[SDLK_q] | keys[29])
859 gram1[0x4276] = 1; // (Q) Jump
862 gram1[0x426A] = 1; // (W)
867 if (keys[SDLK_e] | keys[56]) // (E) Fire
873 if (gram1[0x3F08] == 0xFF) // Ugly kludge for debouncing gun
881 gram1[0x426C] = 1; // (R)
884 gram1[0x4262] = 1; // (T)
887 gram1[0x4260] = 1; // (Y)
890 gram1[0x41A5]++; // Coin? (F10)
893 gram1[0x4189]++; // ? (Z) credits l dig
896 gram1[0x418A]++; // ? (X) credits r dig
899 gram1[0x418C]++; // ? (C) Start
902 gram1[0x418D]++; // ? (V)
905 SpawnSound(USERSOUND, 0); // Do user sound (F7)
908 // We can do this here because we're not executing the cores yet.
909 cpu1.cpuFlags |= V6809_LINE_IRQ;
910 cpu2.cpuFlags |= V6809_LINE_IRQ;
911 mcu.cpuFlags |= V63701_LINE_IRQ;
912 // while (cpu1.clock < 25000)
913 // 1.538 MHz = 25633.333... cycles per frame (1/60 s)
914 // 25600 cycles/frame
915 // Setting interleave to 25 and below causes the V6809 core to hang...
916 // 32 gets to the title screen before hanging...
917 // 40 works, until it doesn't... :-P
920 // 20 seems to work... :-)
921 // Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though.
922 // for(int i=0; i<640; i++)
923 for(int i=0; i<1280; i++)
925 // Gay, but what are ya gonna do?
926 // There's better ways, such as keeping track of when slave writes to master, etc...
927 // Execute6809(&cpu1, 40);
928 // Execute6809(&cpu2, 40);
929 Execute6809(&cpu1, 20);
930 Execute6809(&cpu2, 20);
932 // MCU runs at 1,536,000 Hz
933 // 1536000 / 60 / 640 == 40
934 // Execute63701(&mcu, 40);
935 Execute63701(&mcu, 20);
938 BlitChar(charROM, gram1);
940 // Make sure that the sprite RAM lags by one frame... :-)
949 if (frameTickCount == 3)
952 // Speed throttling happens here...
953 // Actually, it's 16.66... Need to account for that somehow [DONE]
954 while (SDL_GetTicks() - oldTicks < (16 + (frameTickCount == 2 ? 1 : 0)))
955 SDL_Delay(1); // Release our timeslice...
957 oldTicks = SDL_GetTicks();