]> Shamusworld >> Repos - thunder/blob - src/thunder.cpp
59824249291e8b3aacf52ed39f61f851a79dd39b
[thunder] / src / thunder.cpp
1 //
2 // Thunder: A Rolling Thunder Emulator w/6809 debugger
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 //
15
16 #define THUNDER_VERSION         "1.0.0"
17
18 #include <iostream>
19 #include <iomanip>
20 #include <fstream>
21 #include <string>
22 #include <new>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 //#include <conio.h>                    // For getch()
27 #include <curses.h>                     // For getch()
28 #include <time.h>
29 #include <SDL2/SDL.h>           // Get yer SDL out...!
30 #include "v6809.h"
31 #include "screen.h"
32 #include "gui.h"
33 #include "log.h"
34 #include "video.h"
35
36 using namespace std;
37
38
39 #define ROM1   "rt3-1b.9c"
40 #define ROM2   "rt3-2b.12c"
41 #define ROM3   "rt3-3.12d"
42 #define ROM4   "rt1-4.6b"
43 #define ROM5   "rt1-5.4r"
44 #define ROM6   "rt1-6.4s"
45 #define ROM7   "rt1-7.7r"
46 #define ROM8   "rt1-8.7s"
47 #define ROM9   "rt1-9.12h"
48 #define ROM10  "rt1-10.12k"
49 #define ROM11  "rt1-11.12l"
50 #define ROM12  "rt1-12.12m"
51 #define ROM13  "rt1-13.12p"
52 #define ROM14  "rt1-14.12r"
53 #define ROM15  "rt1-15.12t"
54 #define ROM16  "rt1-16.12u"
55 #define ROM17  "rt1-17.f1"
56 #define ROM18  "rt1-18.h1"
57 #define ROM19  "rt1-19.k1"
58 #define ROM20  "rt1-20.m1"
59 #define ROM21  "rt1-21.f3"
60 #define ROM22  "rt1-22.h3"
61 #define PROM1  "mb7124e.3r"
62 #define PROM2  "mb7116e.3s"
63 #define PROM3  "mb7138h.4v"
64 #define PROM4  "mb7138h.6v"
65 #define PROM5  "mb7112e.6u"
66 #define MCUROM "rt1-mcu.bin"
67
68
69 // Global defines
70
71 SDL_Surface * screen;
72
73 uint8_t * gram, * grom;                         // Allocate RAM & ROM pointers
74 uint8_t gram1[0x10000], gram2[0x10000], grom1[0x10000], grom2[0x10000]; // Actual memory
75 uint8_t grom3[0x8000], grom4[0x8000], data_rom[0x40000], spr_rom[0x80000], voice_rom[0x20000];
76 uint8_t chr_rom[0x60000];                       // Character ROM pointer
77
78 V6809REGS cpu1, cpu2;
79
80 bool trace1 = false;                            // ditto...
81 bool looking_at_rom = true;                     // true = R1, false = R2
82 uint32_t banksw1, banksw2;                      // Bank switch addresses
83 uint16_t game_over_switch;                      // Game over delay
84 uint16_t dpc;                                           // Debug pc reg...
85 bool show_scr = true;                           // Whether or not to show background
86 bool enable_cpu = true;                         // Whether or not to enable CPUs
87 bool irqGoA = true;                                     // IRQ switch for CPU #1
88 bool irqGoB = true;                                     // IRQ switch for CPU #2
89
90 uint16_t refresh_ = 0;                          // Crappy global screen stuff...
91 bool refresh2 = true;
92
93 uint32_t psg_lens[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
94 uint8_t * psg_adrs[16];
95 uint32_t voc_lens[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
97 uint8_t * voc_adrs[32];
98 uint32_t fm_lens[14] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
99 uint8_t * fm_adrs[14];
100
101 fstream tr;                                                     // Tracelog hook
102 uint16_t pcx;                                           // Where we at?
103
104 //kludge, for now
105 //static uint8_t keys[0x1000];                          // SDL raw keyboard matrix
106
107 static char op_mat1[256] = {
108   1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
109   0, 0, 5, 5, 0, 0, 4, 4, 0, 5, 8, 0, 8, 5, 6, 6,
110   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
111   7, 7, 7, 7, 6, 6, 6, 6, 0, 5, 5, 5, 8, 5, 5, 5,
112   5, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5, 0, 5, 5, 0, 5,
113   5, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5, 0, 5, 5, 0, 5,
114   7, 0, 0, 7, 7, 0, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7,
115   2, 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2,
116   8, 8, 8, 9, 8, 8, 8, 0, 8, 8, 8, 8, 9, 3, 9, 0,
117   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
118   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
119   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
120   8, 8, 8, 9, 8, 8, 8, 0, 8, 8, 8, 8, 9, 0, 9, 0,
121   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
122   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
123   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
124 op_mat2[256] = {
125   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127   0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
128   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
129   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133   0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0,
134   0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,
135   0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 7,
136   0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 2,
137   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,
138   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
139   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7,
140   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 },
141 op_mat3[256] = {
142   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
143   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
144   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
145   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
146   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
147   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
148   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
149   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150   0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
151   0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
152   0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
153   0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
154   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
156   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
157   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
158 static char mnemonics[256][6] = {
159   "NEG  ","???  ","???  ","COM  ","LSR  ","???  ","ROR  ","ASR  ",
160   "LSL  ","ROL  ","DEC  ","???  ","INC  ","TST  ","JMP  ","CLR  ",
161   "PAGE1","PAGE2","NOP  ","SYNC ","???  ","???  ","LBRA ","LBSR ",
162   "???  ","DAA  ","ORCC ","???  ","ANDCC","SEX  ","EXG  ","TFR  ",
163   "BRA  ","BRN  ","BHI  ","BLS  ","BHS  ","BLO  ","BNE  ","BEQ  ",
164   "BVC  ","BVS  ","BPL  ","BMI  ","BGE  ","BLT  ","BGT  ","BLE  ",
165   "LEAX ","LEAY ","LEAS ","LEAU ","PSHS ","PULS ","PSHU ","PULU ",
166   "???  ","RTS  ","ABX  ","RTI  ","CWAI ","MUL  ","RESET","SWI  ",
167   "NEGA ","???  ","???  ","COMA ","LSRA ","???  ","RORA ","ASRA ",
168   "LSLA ","ROLA ","DECA ","???  ","INCA ","TSTA ","???  ","CLRA ",
169   "NEGB ","???  ","???  ","COMB ","LSRB ","???  ","RORB ","ASRB ",
170   "LSLB ","ROLB ","DECB ","???  ","INCB ","TSTB ","???  ","CLRB ",
171   "NEG  ","???  ","???  ","COM  ","LSR  ","???  ","ROR  ","ASR  ",
172   "LSL  ","ROL  ","DEC  ","???  ","INC  ","TST  ","JMP  ","CLR  ",
173   "NEG  ","???  ","???  ","COM  ","LSR  ","???  ","ROR  ","ASR  ",
174   "LSL  ","ROL  ","DEC  ","???  ","INC  ","TST  ","JMP  ","CLR  ",
175   "SUBA ","CMPA ","SCBA ","SUBD ","ANDA ","BITA ","LDA  ","???  ",
176   "EORA ","ADCA ","ORA  ","ADDA ","CMPX ","BSR  ","LDX  ","???  ",
177   "SUBA ","CMPA ","SBCA ","SUBD ","ANDA ","BITA ","LDA  ","STA  ",
178   "EORA ","ADCA ","ORA  ","ADDA ","CMPX ","JSR  ","LDX  ","STX  ",
179   "SUBA ","CMPA ","SBCA ","SUBD ","ANDA ","BITA ","LDA  ","STA  ",
180   "EORA ","ADCA ","ORA  ","ADDA ","CMPX ","JSR  ","LDX  ","STX  ",
181   "SUBA ","CMPA ","SBCA ","SUBD ","ANDA ","BITA ","LDA  ","STA  ",
182   "EORA ","ADCA ","ORA  ","ADDA ","CMPX ","JSR  ","LDX  ","STX  ",
183   "SUBB ","CMPB ","SCBB ","ADDD ","ANDB ","BITB ","LDB  ","???  ",
184   "EORB ","ADCB ","ORB  ","ADDB ","LDD  ","???  ","LDU  ","???  ",
185   "SUBB ","CMPB ","SBCB ","ADDD ","ANDB ","BITB ","LDB  ","STB  ",
186   "EORB ","ADCB ","ORB  ","ADDB ","LDD  ","STD  ","LDU  ","STU  ",
187   "SUBB ","CMPB ","SBCB ","ADDD ","ANDB ","BITB ","LDB  ","STB  ",
188   "EORB ","ADCB ","ORB  ","ADDB ","LDD  ","STD  ","LDU  ","STU  ",
189   "SUBB ","CMPB ","SBCB ","ADDD ","ANDB ","BITB ","LDB  ","STB  ",
190   "EORB ","ADCB ","ORB  ","ADDB ","LDD  ","STD  ","LDU  ","STU  " },
191 mnemonics2[256][6] = {
192   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
193   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
194   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
195   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
196   "???  ","LBRN ","LBHI ","LBLS ","LBHS ","LBLO ","LBNE ","LBEQ ",
197   "LBVC ","LBVS ","LBPL ","LBMI ","LBGE ","LBLT ","LBGT ","LBLE ",
198   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
199   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","SWI2 ",
200   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
201   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
202   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
203   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
204   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
205   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
206   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
207   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
208   "???  ","???  ","???  ","CMPD ","???  ","???  ","???  ","???  ",
209   "???  ","???  ","???  ","???  ","CMPY ","???  ","LDY  ","???  ",
210   "???  ","???  ","???  ","CMPD ","???  ","???  ","???  ","???  ",
211   "???  ","???  ","???  ","???  ","CMPY ","???  ","LDY  ","STY  ",
212   "???  ","???  ","???  ","CMPD ","???  ","???  ","???  ","???  ",
213   "???  ","???  ","???  ","???  ","CMPY ","???  ","LDY  ","STY  ",
214   "???  ","???  ","???  ","CMPD ","???  ","???  ","???  ","???  ",
215   "???  ","???  ","???  ","???  ","CMPY ","???  ","LDY  ","STY  ",
216   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
217   "???  ","???  ","???  ","???  ","???  ","???  ","LDS  ","???  ",
218   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
219   "???  ","???  ","???  ","???  ","???  ","???  ","LDS  ","STS  ",
220   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
221   "???  ","???  ","???  ","???  ","???  ","???  ","LDS  ","STS  ",
222   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
223   "???  ","???  ","???  ","???  ","???  ","???  ","LDS  ","STS  " },
224 mnemonics3[256][6] = {
225   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
226   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
227   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
228   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
229   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
230   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
231   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
232   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","SWI3 ",
233   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
234   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
235   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
236   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
237   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
238   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
239   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
240   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
241   "???  ","???  ","???  ","CMPU ","???  ","???  ","???  ","???  ",
242   "???  ","???  ","???  ","???  ","CMPS ","???  ","???  ","???  ",
243   "???  ","???  ","???  ","CMPU ","???  ","???  ","???  ","???  ",
244   "???  ","???  ","???  ","???  ","CMPS ","???  ","???  ","???  ",
245   "???  ","???  ","???  ","CMPU ","???  ","???  ","???  ","???  ",
246   "???  ","???  ","???  ","???  ","CMPS ","???  ","???  ","???  ",
247   "???  ","???  ","???  ","CMPU ","???  ","???  ","???  ","???  ",
248   "???  ","???  ","???  ","???  ","CMPS ","???  ","???  ","???  ",
249   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
250   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
251   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
252   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
253   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
254   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
255   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  ",
256   "???  ","???  ","???  ","???  ","???  ","???  ","???  ","???  " },
257 tregs[16][3] = {
258   "D",  "X", "Y",  "U",  "S",  "PC", "??", "??",
259   "A",  "B", "CC", "DP", "??", "??", "??", "??" },
260 iregs[4][2] = {"X", "Y", "U", "S" };
261
262
263 //
264 // Read a byte from memory (without touching PC. Not a Fetch!)
265 //
266 uint8_t RdMem(uint16_t addr)
267 {
268         uint8_t b;
269
270         // $4000-4300 is RAM shared with the microcontroller...
271
272         if (addr < 0x8000)
273         {
274                 if (addr > 0x5FFF)
275                         b = data_rom[banksw1 + (addr - 0x6000)];        // Get char data
276                 else
277                         b = gram1[addr];
278         }
279         else
280                 b = grom1[addr];
281
282         return b;
283 }
284
285
286 //
287 // Write a byte to memory
288 //
289 void WrMem(uint16_t addr, uint8_t b)
290 {
291         extern bool disasm;
292         extern bool charbase;                                                           // Needed for screen. Extern it in it??
293   //extern uint16_t sr, ur, xr, yr;            // Needed for tracelog
294   //extern uint16_t pcr;
295 /*  if ((addr>0x40FF) && (addr<0x4390))
296   {
297     tr << hex << addr << ":" << (int)b;
298     //for(int i=0; i<32; i++)
299     //{
300     //  if (gram1[0x4400+i]<0x10)  tr << "0";
301     //  tr << hex << (uint16_t)gram1[0x4400+i] << " ";
302     //}
303     tr << endl;
304   }//*/
305 #if 0
306         if (addr == 0x4182)
307         {
308                 WriteLog("\nWriteMem: CPU #1 writing $%02X to $4182!\n\n", b);
309         }
310 #endif
311
312         if (addr == 0x6000)
313                 SpawnSound(GAMESOUND, gram1[0x6200], 0);                // Do voice chan 1
314         if (addr == 0x6400)
315                 SpawnSound(GAMESOUND, gram1[0x6600], 1);                // Do voice chan 2
316         if (addr == 0x6800)
317                 banksw1 = (uint32_t)b << 13;                                            // Set char data bankswitch base address
318         if (addr > 0x4284 && addr < 0x42A5 && b)
319                 SpawnSound(PSGSOUND, addr - 0x4285);                    // Do PSG sound on chans 2, 3
320         if (addr == 0x4380)
321         {
322                 SpawnSound(FMSOUND, b);                                                 // Do FM sound on channel 4
323                 if (b == 12)
324                         game_over_switch = 240;                                         // Set game over delay...
325         }
326         if (addr < 0x423D || addr > 0x425C)                                     // Protect writes to DSWs
327                 gram1[addr] = b;
328         if (addr == 0x8800)
329                 charbase = false;                                                               // Char banksw1
330         if (addr == 0x8C00)
331                 charbase = true;                                                                // Char banksw2
332         if (addr == 0x8400)                                                                     // Frame go strobe? VBlank acknowledge?
333         {
334                 if (refresh_++ == 1)                                                            // 30 Hz...
335                 {
336                         BlitChar(screen, chr_rom, gram1);
337                         refresh_ = (refresh2 ? 1 : 0);                          // 60/30 Hz...
338                 }
339
340                 // IRQ Ack (may also be frame go...
341                 ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);
342 #if 1
343         if (disasm)
344                 WriteLog("WriteMem: CPU #1 Acknowledging IRQ...\n", b);
345 #endif
346         }
347 }
348
349
350 //
351 // Read a byte from memory (without touching PC. Not a Fetch!) (2nd processor)
352 //
353 uint8_t RdMemB(uint16_t addr)
354 {
355 //  extern uint16_t cpu2.s, cpu2.u, cpu2.x, cpu2.y;            // Needed for tracelog
356         uint8_t b;
357
358         if (addr < 0x8000)
359         {
360                 if (addr < 0x2000)
361                         b = gram1[addr + 0x4000];
362                 if (addr > 0x1FFF && addr < 0x6000)
363                         b = gram1[addr - 0x2000];
364                 if (addr > 0x5FFF)
365                         b = grom3[banksw2 + (addr - 0x6000)];           // Correct?
366         }
367         else
368                 b = grom2[addr];
369
370 /*  if ((addr>0x3FFF) && (addr<0x4400))  tr << "R-" << hex << pcx << ": "
371                                         << addr << "-"
372                                         << (int)looking_at_rom
373                                         << " [" << (int)b
374                                         << "] XR:" << xr << " YR:" << yr
375                                         << " SR:" << sr << " UR:" << ur
376                                         << endl; //*/
377         return b;
378 }
379
380
381 //
382 // Write a byte to memory (2nd processor)
383 //
384 void WrMemB(uint16_t addr, uint8_t b)
385 {
386         extern bool disasm;
387         extern bool charbase;
388   //extern uint16_t sr, ur, xr, yr;            // Needed for tracelog
389   //extern uint16_t pcr;
390 /*  if ((addr>0x00FF) && (addr<0x0390))
391   {
392     tr << hex << addr << ":" << (int)b;
393     //for(int i=0; i<32; i++)
394     //{
395     //  if (gram1[0x4400+i]<0x10)  tr << "0";
396     //  tr << hex << (uint16_t)gram1[0x4400+i] << " ";
397     //}
398     tr << endl;
399   }//*/
400 #if 0
401         if (addr == 0x0182)
402         {
403                 WriteLog("\nWriteMem: CPU #2 writing $%02X to $0182 ($4182)!\n\n", b);
404         }
405 #endif
406
407         if (addr == 0x6000)
408                 SpawnSound(GAMESOUND, gram1[0x6200], 0);                // Do voice chan 1
409         if (addr == 0x6400)
410                 SpawnSound(GAMESOUND, gram1[0x6600], 1);                // Do voice chan 2
411         if (addr > 0x0284 && addr < 0x02A5 && b)
412                 SpawnSound(PSGSOUND, addr - 0x0285);                    // Do PSG sound on chans 2, 3
413         if (addr == 0xD803)
414                 banksw2 = (uint32_t)(b & 0x03) << 13;                           // Set sprite data bank switch
415         if (addr == 0x0380)
416         {
417                 SpawnSound(FMSOUND, b);                                                 // Do FM sound on chan 4
418                 if (b == 12)
419                         game_over_switch = 240;                                         // Set game over delay...
420         }
421         if (addr < 0x023D || addr > 0x025C)                                     // Protect writes against DSWs
422         {
423                 if (addr < 0x2000)
424                         gram1[addr + 0x4000] = b;
425                 if (addr > 0x1FFF && addr < 0x6000)
426                         gram1[addr - 0x2000] = b;
427                 if (addr > 0x5FFF)
428                         gram1[addr] = b;
429         }
430         if (addr == 0x8800)
431         {
432                 // IRQ Ack (may also be frame go...)
433                 ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);
434 #if 1
435         if (disasm)
436                 WriteLog("WriteMem: CPU #2 Acknowledging IRQ...\n", b);
437 #endif
438         }
439 }
440
441
442 //
443 // Display bytes in mem in hex
444 //
445 void DisplayBytes(uint16_t src, unsigned long dst)
446 {
447         uint8_t cnt = 0;
448         WriteLog("%04X: ", src);
449
450         if (src > dst)
451                 dst += 0x10000;        // That should fix the FFFF bug...
452
453         for(unsigned long i=src; i<dst; i++)
454         {
455                 WriteLog("%02X ", (uint8_t)(looking_at_rom ? RdMem(i) : RdMemB(i)));
456                 cnt++;
457         }
458
459         // Pad the leftover spaces...
460         for(unsigned long i=cnt; i<5; i++)
461                 WriteLog("   ");
462 }
463
464
465 // temp crap...
466 uint8_t Fetch(void) { return RdMem(dpc); }
467 uint16_t FetchW(void) { return (uint16_t)((RdMem(dpc) << 8) | RdMem(dpc+1)); }
468 uint8_t FetchB(void) { return RdMemB(dpc); }
469 uint16_t FetchWB(void) { return (uint16_t)((RdMemB(dpc) << 8) | RdMemB(dpc+1)); }
470
471
472 //
473 // Decode a 6809 instruction at 'addr'
474 //
475 void Decode_6809()
476 {
477         uint8_t (* DFetch)();           // Decode Fetch() pointer...
478         uint16_t (* DFetchW)();          // Decode FetchW() pointer...
479         DFetch  = (looking_at_rom ? Fetch : FetchB);
480         DFetchW = (looking_at_rom ? FetchW : FetchWB);
481
482         /*  extern*/ uint16_t pcr, pcrB;              // Pull in 'pcr' from '6809.cpp'
483         uint16_t pc_save = pcr, pcB_save = pcrB;
484         pcr  = dpc;  pcrB = dpc;
485         uint8_t opcode = DFetch();             // Get the opcode ('fetch' cycle)
486         uint8_t opcode2, operand;
487         uint16_t loperand;
488         uint8_t admode = op_mat1[opcode];     // addressing mode
489         char outbuf[80], mnem[6], tmp[30];
490
491         strcpy(mnem, mnemonics[opcode]);  // Copy page 1 opcode
492
493         if (opcode == 0x10)             // Extended opcode?
494         {
495                 opcode2 = DFetch();     // Then get next byte
496                 admode = op_mat2[opcode2];    // And use it as index into 'op_mat2'
497                 strcpy(mnem, mnemonics2[opcode2]);  // Overwrite mnemonic
498         }
499
500         if (opcode == 0x11)             // Same as above...
501         {
502                 opcode2 = DFetch();
503                 admode = op_mat3[opcode2];
504                 strcpy(mnem, mnemonics3[opcode2]);  // Overwrite mnemonic
505         }
506
507         // Decode it...
508         switch (admode)
509         {
510         case 0:  // Illegal
511                 sprintf(outbuf, "???");
512                 break;
513         case 1:  // Zero page
514                 operand = DFetch();   // Get ZP address
515                 sprintf(outbuf, "%s $%02X", mnem, operand);
516                 break;
517         case 2:  // Absolute
518                 loperand = DFetchW(); // Get ABS address
519                 sprintf(outbuf, "%s $%04X", mnem, loperand);
520                 break;
521         case 3:  // Relative
522         {
523                 operand = DFetch();   // Get offset
524                 uint16_t tmpc = (looking_at_rom ? pcr : pcrB);
525                 sprintf(outbuf, "%s $%04X", mnem, tmpc+(int16_t)(int8_t)operand);
526                 break;
527         }
528         case 4:  // Long Relative
529         {
530                 loperand = DFetchW(); // Get long offset
531                 uint16_t tmpc = (looking_at_rom ? pcr : pcrB);
532                 sprintf(outbuf, "%s $%04X", mnem, tmpc+(int16_t)loperand);
533                 break;
534         }
535         case 5:  // Inherent
536                 sprintf(outbuf, "%s ", mnem);
537                 break;
538         case 6:  // Txfr/exchg/push/pull
539         {
540                 operand = DFetch();   // Get txfr/exg/push/pull byte
541
542                 if ((opcode == 0x1E) || (opcode == 0x1F))  // Is it TXF/EXG?
543                 {
544                         sprintf(tmp, "%s,%s", tregs[operand>>4], tregs[operand&0x0F]);
545                 }
546                 else
547                 {
548                         tmp[0] = 0;
549                         if (operand&0x01)  strcat(tmp, "CC ");
550                         if (operand&0x02)  strcat(tmp, "A ");
551                         if (operand&0x04)  strcat(tmp, "B ");
552                         if (operand&0x08)  strcat(tmp, "DP ");
553                         if (operand&0x10)  strcat(tmp, "X ");
554                         if (operand&0x20)  strcat(tmp, "Y ");
555                         if (operand&0x40)  (((opcode==0x34)||(opcode==0x35))
556                                                 ? strcat(tmp, "U ") : strcat(tmp, "S "));
557                         if (operand&0x80)  strcat(tmp, "PC");
558                 }
559                 sprintf(outbuf, "%s %s", mnem, tmp);
560                 break;
561         }
562         case 7:  // Indexed (the tough one!)
563         {
564                 operand = DFetch();   // Get IDX byte
565                 uint8_t reg = ((operand & 0x60) >> 5), idxind = ((operand & 0x10) >> 4),
566                         lo_nyb = (operand & 0x0F),  boff;
567                 uint16_t woff;
568
569                 strcpy(tmp, "??");
570
571                 if (!(operand & 0x80))      // Hi bit set? Then decode 4 bit offset
572                 {
573                         sprintf(tmp, "(%d),%s", (idxind ? -(16-lo_nyb) : lo_nyb),
574                                         iregs[reg]);
575                 }
576                 else   // Add the ($nnnn,R) code dude...
577                 {
578                         if (idxind)
579                         {
580                                 switch (lo_nyb)
581                                 {
582                                 case 1:   sprintf(tmp, "(,%s++)", iregs[reg]);  break;
583                                 case 3:   sprintf(tmp, "(,--%s)", iregs[reg]);  break;
584                                 case 4:   sprintf(tmp, "(,%s)", iregs[reg]);  break;
585                                 case 5:   sprintf(tmp, "(B,%s)", iregs[reg]);  break;
586                                 case 6:   sprintf(tmp, "(A,%s)", iregs[reg]);  break;
587                                 case 8:
588                                 { boff = DFetch();  sprintf(tmp, "($%02X,%s)", boff,
589                                                                                 iregs[reg]);  break; }
590                                 case 9:
591                                 { woff = DFetchW();  sprintf(tmp, "($%04X,%s)", woff,
592                                                                                         iregs[reg]);  break; }
593                                 case 11:  sprintf(tmp, "(D,%s)", iregs[reg]);  break;
594                                 case 12:
595                                 { boff = DFetch();  sprintf(tmp, "($%02X,PC)", boff);  break; }
596                                 case 13:
597                                 { woff = DFetchW();  sprintf(tmp, "($%04X,PC)", woff);  break; }
598                                 case 15:
599                                 { woff = DFetchW();  sprintf(tmp, "[$%04X]", woff);  break; }
600                                 default:  strcpy(tmp, "??");
601                                 }
602                         }
603                         else
604                         {
605                                 switch (lo_nyb)
606                                 {
607                                 case 0:   sprintf(tmp, ",%s+", iregs[reg]);  break;
608                                 case 1:   sprintf(tmp, ",%s++", iregs[reg]);  break;
609                                 case 2:   sprintf(tmp, ",-%s", iregs[reg]);  break;
610                                 case 3:   sprintf(tmp, ",--%s", iregs[reg]);  break;
611                                 case 4:   sprintf(tmp, ",%s", iregs[reg]);  break;
612                                 case 5:   sprintf(tmp, "(B),%s", iregs[reg]);  break;
613                                 case 6:   sprintf(tmp, "(A),%s", iregs[reg]);  break;
614                                 case 8:
615                                 { boff = DFetch();  sprintf(tmp, "($%02X),%s", boff,
616                                                                                 iregs[reg]);  break; }
617                                 case 9:
618                                 { woff = DFetchW();  sprintf(tmp, "($%04X),%s", woff,
619                                                                                 iregs[reg]);  break; }
620                                 case 11:  sprintf(tmp, "(D),%s", iregs[reg]);  break;
621                                 case 12:
622                                 { boff = DFetch();  sprintf(tmp, "($%02X),PC", boff);  break; }
623                                 case 13:
624                                 { woff = DFetchW();  sprintf(tmp, "($%04X),PC", woff);  break; }
625                                 default:  strcpy(tmp, "??");
626                                 }
627                         }
628                 }
629
630                 sprintf(outbuf, "%s %s", mnem, tmp);
631                 break;
632         }
633         case 8:  // Immediate
634                 operand = DFetch();   // Get IMM byte
635                 sprintf(outbuf, "%s #$%02X", mnem, operand);
636                 break;
637         case 9:  // Long Immediate
638                 loperand = DFetchW(); // Get IMM word
639                 sprintf(outbuf, "%s #$%04X", mnem, loperand);
640                 break;
641         }
642
643         DisplayBytes(dpc, (looking_at_rom ? pcr : pcrB));  // Show bytes
644         WriteLog(outbuf);
645         WriteLog("\n");     // display opcode & addressing, etc
646         dpc = (looking_at_rom ? pcr : pcrB);  // Advance debug PC
647         pcr = pc_save;
648         pcrB = pcB_save;  // Restore PCs
649 }
650
651
652 //
653 // Convert hex to dec
654 //
655 uint16_t htod(char * str)
656 {
657         uint16_t value = 0;
658         int len = strlen(str);
659
660         for(int i=0; i<len; i++)
661         {
662                 if (str[i] >= '0' && str[i] <= '9')
663                         value = (value << 4) | (unsigned)(str[i] - '0');
664                 else if (str[i] >= 'a' && str[i] <= 'f')
665                         value = (value << 4) | (unsigned)((str[i] - 'a') + 10);
666                 else if (str[i] >= 'A' && str[i] <= 'F')
667                         value = (value << 4) | (unsigned)((str[i] - 'A') + 10);
668         }
669
670         return value;
671 }
672
673
674 //
675 // Load 32K file into ROM image space
676 //
677 bool Load32KImg(char * filename, uint16_t address)
678 {
679 #if 0
680         ifstream ff;
681         char ch;
682
683         ff.open(filename, ios::binary | ios::in);
684
685         if (ff)
686         {
687                 // Read it in...
688                 for(long i=0; i<32768; i++)
689                 {
690                         ff.get(ch);
691                         grom[address+i] = ch;
692                 }
693
694                 ff.close();
695         }
696
697         return ff;
698 #else
699         FILE * file = fopen(filename, "rb");
700
701         if (!file)
702                 return false;
703
704         fread(&grom[address], 1, 0x8000, file);
705
706         return true;
707 #endif
708 }
709
710
711 //
712 // Generic Load file into image space
713 // (No error checking performed!  Responsibility of caller!)
714 //
715 bool LoadImg(const char * filename, uint8_t * mem, uint32_t address, uint32_t length)
716 {
717         ifstream ff;
718         char path[80];
719         char ch;
720
721         strcpy(path, "./ROMs/");
722         strcat(path, filename);
723 //  ff.open(filename, ios::binary | ios::in);  // Open 'da file...
724         ff.open(path, ios::binary | ios::in);       // Open 'da file...
725
726         if (ff)
727         {
728                 for(uint32_t i=0; i<length; i++)             // Read it in...
729                 {
730                         ff.get(ch);
731                         mem[address+i] = ch;
732                 }
733
734                 ff.close();                               // Close 'da file...
735         }
736
737         return ff;
738 }
739
740
741 //
742 // Read color PROMs
743 //
744 bool ReadColorPROMs(void)
745 {
746         fstream ff1, ff2;
747         //  uint8_t ch;
748         char ch;
749 //      extern uint8_t palette[768];     // Screen physical palette
750         extern uint32_t palette[256];     // Screen physical palette
751         extern uint8_t ccolor[256][8];   // Character color PROM values
752         extern uint8_t scolor[128][16];  // Sprite color PROM values
753
754         ff1.open("./ROMs/"PROM3, ios::binary | ios::in);
755
756         if (ff1)
757         {
758                 for(int i=0; i<256; i++) // Load char pallete with PROM values
759                 {
760                         for(int j=0; j<8; j++)
761                         {
762                                 ff1.get(ch);
763                                 ccolor[i][j] = (uint8_t)ch;
764                         }
765                 }
766
767                 ff1.close();
768         }
769
770         ff1.open("./ROMs/"PROM4, ios::binary | ios::in);
771
772         if (ff1)
773         {
774                 for(int i=0; i<128; i++) // Load sprite pallete with PROM values
775                 {
776                         for(int j=0; j<16; j++)
777                         {
778                                 ff1.get(ch);
779                                 scolor[i][j] = (uint8_t)ch;
780                         }
781                 }
782
783                 ff1.close();
784         }
785
786         ff1.open("./ROMs/"PROM1, ios::binary | ios::in);
787         ff2.open("./ROMs/"PROM2, ios::binary | ios::in);
788
789         // If open was successful...
790         if (ff1)
791         {
792                 // Palette is 12-bit RGB, we stretch it to 24-bit
793                 for(int i=0; i<256; i++)
794                 {
795                         char c1, c2;
796                         uint8_t r, g, b;
797                         ff1.get(c1);
798                         ff2.get(c2);
799                         r = (uint8_t)c1 & 0x0F;
800                         g = (uint8_t)c1 >> 4;
801                         b = (uint8_t)c2;
802                         palette[i] = 0xFF000000 | (b << 20) | (b << 16) | (g << 12) | (g << 8) | (r << 4) | r;
803                 }
804
805                 ff1.close();
806                 ff2.close();
807         }
808
809         // PROM5 has the following in it (tile address decoder):
810         // 00:  00 20 40 60 02 22 42 62  04 24 44 64 06 26 46 66
811         // 10:  88 A8 C8 E8 8A AA CA EA  8C AC CC EC 8E AE CE EE 
812
813         return ff1;
814 }
815
816
817 //
818 // Unpack font data
819 //
820 bool UnpackFonts(void)
821 {
822 //  uint8_t b1, b2, b3;
823         char b1, b2, b3;
824         fstream f1, f2;
825         //0x4000 $800 chars
826         f1.open("./ROMs/"ROM7, ios::binary | ios::in);
827         f2.open("./ROMs/"ROM8, ios::binary | ios::in);
828
829         if ((!f1) || (!f2))
830                 return false;  // Return if not found...
831
832         for(long i=0; i<0x40000; i+=64)
833         {
834                 for(int j=0; j<64; j+=8)
835                 {
836                         f1.get(b1);  f1.get(b2);  f2.get(b3);
837                         b3 ^= 0xFF; // Invert top data...
838                         chr_rom[i+j] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
839                         chr_rom[i+j+1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
840                         chr_rom[i+j+2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
841                         chr_rom[i+j+3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
842                         chr_rom[i+j+4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
843                         chr_rom[i+j+5] = (b3 & 0x04)        | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
844                         chr_rom[i+j+6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
845                         chr_rom[i+j+7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
846                 }
847         }
848
849         f1.close();
850         f2.close();
851
852         f1.open("./ROMs/"ROM5, ios::binary | ios::in);
853         f2.open("./ROMs/"ROM6, ios::binary | ios::in);
854
855         for(long i=0x40000; i<0x60000; i+=64)
856         {
857                 for(int j=0; j<64; j+=8)
858                 {
859                         f1.get(b1);  f1.get(b2);  f2.get(b3);
860                         b3 ^= 0xFF;                             // Invert top data
861                         chr_rom[i+j] = ((b3 & 0x80) >> 5) | ((b1 & 0x80) >> 6) | ((b1 & 0x08) >> 3);
862                         chr_rom[i+j+1] = ((b3 & 0x40) >> 4) | ((b1 & 0x40) >> 5) | ((b1 & 0x04) >> 2);
863                         chr_rom[i+j+2] = ((b3 & 0x20) >> 3) | ((b1 & 0x20) >> 4) | ((b1 & 0x02) >> 1);
864                         chr_rom[i+j+3] = ((b3 & 0x10) >> 2) | ((b1 & 0x10) >> 3) | (b1 & 0x01);
865                         chr_rom[i+j+4] = ((b3 & 0x08) >> 1) | ((b2 & 0x80) >> 6) | ((b2 & 0x08) >> 3);
866                         chr_rom[i+j+5] = (b3 & 0x04)        | ((b2 & 0x40) >> 5) | ((b2 & 0x04) >> 2);
867                         chr_rom[i+j+6] = ((b3 & 0x02) << 1) | ((b2 & 0x20) >> 4) | ((b2 & 0x02) >> 1);
868                         chr_rom[i+j+7] = ((b3 & 0x01) << 2) | ((b2 & 0x10) >> 3) | (b2 & 0x01);
869                 }
870         }
871
872         f1.close();
873         f2.close();
874
875         return true;                                // Made it!
876 }
877
878
879 //
880 // Get length of sample from WAV format
881 //
882 uint32_t GetWAVLength(fstream & file)
883 {
884         char ch;
885         uint32_t len;
886
887         file.ignore(16);                                                                        // Skip header BS
888
889         for(int i=0; i<2; i++)
890         {
891                 file.get(ch);  len = (int)(uint8_t)ch;
892                 file.get(ch);  len |= (int)(uint8_t)ch << 8;
893                 file.get(ch);  len |= (int)(uint8_t)ch << 16;
894                 file.get(ch);  len |= (int)(uint8_t)ch << 24;
895
896                 file.ignore(len + 4);                                                   // Skip intermediate data
897         }
898
899         file.get(ch);  len = (int)(uint8_t)ch;                                  // & finally get length of data
900         file.get(ch);  len |= (int)(uint8_t)ch << 8;
901         file.get(ch);  len |= (int)(uint8_t)ch << 16;
902         file.get(ch);  len |= (int)(uint8_t)ch << 24;
903
904         return len;
905 }
906
907
908 //
909 // Load PSG samples from disk
910 //
911 void LoadPSGs(void)
912 {
913         char file[40];
914         char ch;
915         uint32_t len;
916
917         for(int i=0; i<16; i++)
918         {
919                 fstream fp;
920
921                 psg_adrs[i] = NULL;                                                             // Zero out pointer
922                 sprintf(file, "./sounds/psg%i.wav", i);                 // Create filename
923
924                 fp.open(file, ios::binary | ios::in);                   // Attempt to open it...
925
926                 if (fp)
927                 {
928                         len = GetWAVLength(fp);                                         // Get WAV data length...
929                         psg_adrs[i] = new uint8_t[len];                         // Attempt to allocate space...
930
931                         if (psg_adrs[i] != NULL)
932                         {
933                                 for(int j=0; j<(signed)len; j++)
934                                 {
935                                         fp.get(ch);
936                                         psg_adrs[i][j] = ch;                            // & load it in...
937                                 }
938
939                                 psg_lens[i] = len;
940 //                              cout << "Found sample file: " << file << "\t[Length: " << dec << len << "]" << endl;
941                                 printf("Found sample file: %s\t[Length: %u]\n", file, len);
942                         }
943
944                         fp.close();
945                 }
946         }
947 }
948
949
950 //
951 // Load FM samples from disk
952 //
953 void LoadFMs(void)
954 {
955         char file[200];
956         char ch;
957         uint32_t len;
958
959         for(int i=0; i<14; i++)
960         {
961                 fstream fp;
962
963                 fm_adrs[i] = NULL;                                                              // Zero out pointer
964                 sprintf(file, "./sounds/fm%i.wav", i);                  // Create filename
965
966                 fp.open(file, ios::binary | ios::in);                   // Attempt to open it...
967
968                 if (fp)
969                 {
970                         len = GetWAVLength(fp);                                         // Get WAV length...
971                         fm_adrs[i] = new uint8_t[len];                                  // Attempt to allocate space...
972
973                         if (fm_adrs[i] != NULL)
974                         {
975                                 for(int j=0; j<(signed)len; j++)
976                                 {
977                                         fp.get(ch);
978                                         fm_adrs[i][j] = ch;                                     // & load it in...
979                                 }
980
981                                 fm_lens[i] = len;
982 //                              cout << "Found sample file: " << file << " [Length: " << dec << len << "]" << endl;
983                                 printf("Found sample file: %s\t[Length: %u]\n", file, len);
984                         }
985
986                         fp.close();
987                 }
988         }
989 }
990
991
992 //
993 // Main loop
994 //
995 int main(int argc, char * argv[])
996 {
997         InitLog("thunder.log");
998
999 extern bool disasm;     // From 'V6809.CPP'
1000         extern bool charbase;                                           // From 'SCREEN.CPP'
1001         charbase = false;
1002
1003         char lbuff[80];
1004         fstream ff;                       // Declare fstream without file hooks...
1005         bool brk = false, brk2 = false;   // Breakpoint set flag
1006         uint16_t brkpnt, brkpnt2;             // Where the breakpoint is...
1007         bool running;                     // CPU running state flag...
1008         bool self_test = false;           // Self-test switch
1009         bool scr_type = false;            // false=chars, true=pixels
1010         uint16_t debounce = 0;                // Key de-bounce counter
1011         uint16_t fire_debounce = 0;           // Fire button debounce counter
1012 //  bool refresh2 = true;             // Default to 60 Hz...
1013         uint8_t x;                           // General placeholder...
1014         bool active = true;                                             // Program running flag
1015
1016         SDL_Event event;                                                                // SDL "event"
1017         extern uint8_t palette[768];                                    // Screen physical palette
1018         uint32_t ticks, oldTicks;
1019
1020         cout << endl << "THUNDER v"THUNDER_VERSION" ";
1021         cout << "by James Hammons" << endl;
1022         cout << "Serial #20149404 / Prerelease" << endl;
1023         cout << "© 2003, 2014 Underground Software" << endl << endl;
1024
1025         cout << "This emulator is free software. If you paid for it you were RIPPED OFF"
1026                 << endl << endl;
1027
1028 #if 0
1029         cout << "Initializing SDL..." << endl;
1030
1031         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0)
1032         {
1033                 cout << "Couldn't initialize SDL: " << SDL_GetError() << endl;
1034                 return -1;
1035         }
1036 #endif
1037
1038 //      SDL_WM_SetCaption("Thunder v"THUNDER_VERSION" ", "Thunder");
1039
1040 //      keys = SDL_GetKeyState(NULL);                           // Get the SDL keyboard matrix
1041
1042         gram = gram1;  grom = grom1;           // Needed only for debugger
1043
1044 #if 0
1045         for(long i=0; i<0x10000; i++)
1046         {
1047                 gram[i] = 0;  grom[i] = 0;           // Zero out memory
1048                 gram2[i] = 0;  grom2[i] = 0;
1049         }
1050 #else
1051         memset(gram, 0, 0x10000);
1052         memset(grom, 0, 0x10000);
1053         memset(gram2, 0, 0x10000);
1054         memset(grom2, 0, 0x10000);
1055 #endif
1056
1057         game_over_switch = 0;   // Init game over delay
1058 //  cpu1.a = 0; cpu1.b = 0; cpu1.cc = 0; cpu1.dp = 0; cpu1.x = 0; cpu1.y = 0; cpu1.s = 0; ur = 0; cpu1.pc = 0;
1059
1060         cout << "Loading ROMs..." << endl;
1061 //  LoadCMOS();                            // Load CMOS at $CC00-$CFFF
1062         if (!ReadColorPROMs())                   // Load virtual PROMs
1063         { cout << "Could not open PROM files!" << endl;  return -1; }
1064
1065         if (!LoadImg(ROM1, grom1, 0x8000, 0x8000)) // Load $8000-$FFFF 1st ROM
1066         { cout << "Could not open file '" << ROM1 << "'!" << endl;  return -1; }
1067
1068         if (!LoadImg(ROM2, grom2, 0x8000, 0x8000)) // Load $8000-$FFFF 2nd ROM
1069         { cout << "Could not open file '" << ROM2 << "'!" << endl;  return -1; }
1070
1071         if (!LoadImg(ROM3, grom3, 0, 0x8000))      // Load 3rd ROM into its own space
1072         { cout << "Could not open file '" << ROM3 << "'!" << endl;  return -1; }
1073
1074         if (!LoadImg(ROM4, grom4, 0, 0x8000))      // Load 4rd ROM into its own space
1075         { cout << "Could not open file '" << ROM4 << "'!" << endl;  return -1; }
1076
1077         if (!LoadImg(ROM17, data_rom, 0,       0x10000))  // Load 17th ROM
1078         { cout << "Could not open file '" << ROM17 << "'!" << endl;  return -1; }
1079
1080         if (!LoadImg(ROM18, data_rom, 0x10000, 0x10000))  // Load 18th ROM
1081         { cout << "Could not open file '" << ROM18 << "'!" << endl;  return -1; }
1082
1083         if (!LoadImg(ROM19, data_rom, 0x20000, 0x10000))  // Load 19th ROM
1084         { cout << "Could not open file '" << ROM19 << "'!" << endl;  return -1; }
1085
1086         if (!LoadImg(ROM20, data_rom, 0x30000, 0x10000))  // Load 20th ROM
1087         { cout << "Could not open file '" << ROM20 << "'!" << endl;  return -1; }
1088
1089         if (!LoadImg(ROM9,  spr_rom, 0,       0x10000))   // Load 9th ROM
1090         { cout << "Could not open file '" << ROM9 << "'!" << endl;  return -1; }
1091
1092         if (!LoadImg(ROM10, spr_rom, 0x10000, 0x10000))   // Load 10th ROM
1093         { cout << "Could not open file '" << ROM10 << "'!" << endl;  return -1; }
1094
1095         if (!LoadImg(ROM11, spr_rom, 0x20000, 0x10000))   // Load 11th ROM
1096         { cout << "Could not open file '" << ROM11 << "'!" << endl;  return -1; }
1097
1098         if (!LoadImg(ROM12, spr_rom, 0x30000, 0x10000))   // Load 12th ROM
1099         { cout << "Could not open file '" << ROM12 << "'!" << endl;  return -1; }
1100
1101         if (!LoadImg(ROM13, spr_rom, 0x40000, 0x10000))   // Load 13th ROM
1102         { cout << "Could not open file '" << ROM13 << "'!" << endl;  return -1; }
1103
1104         if (!LoadImg(ROM14, spr_rom, 0x50000, 0x10000))   // Load 14th ROM
1105         { cout << "Could not open file '" << ROM14 << "'!" << endl;  return -1; }
1106
1107         if (!LoadImg(ROM15, spr_rom, 0x60000, 0x10000))   // Load 15th ROM
1108         { cout << "Could not open file '" << ROM15 << "'!" << endl;  return -1; }
1109
1110         if (!LoadImg(ROM16, spr_rom, 0x70000, 0x10000))   // Load 16th ROM
1111         { cout << "Could not open file '" << ROM16 << "'!" << endl;  return -1; }
1112
1113         if (!LoadImg(ROM21, voice_rom, 0, 0x10000))  // Load 21st ROM
1114         { cout << "Could not open file '" << ROM21 << "'!" << endl;  return -1; }
1115
1116         if (!LoadImg(ROM22, voice_rom, 0x10000, 0x10000))  // Load 22nd ROM
1117         { cout << "Could not open file '" << ROM22 << "'!" << endl;  return -1; }
1118
1119         if (!UnpackFonts())                         // Load 5, 6, 7, 8th ROMs
1120         {
1121                 cout << "Could not open font files!" << endl;
1122                 return -1;
1123         }
1124
1125         // Load samples if they're there...
1126         LoadPSGs();
1127         LoadFMs();
1128
1129   // Quick 'n' Dirty voice dump (sound 0x0E)
1130 /*  uint32_t adc = (voice_rom[26]<<8) | voice_rom[27];
1131   bool doneWitIt = false;
1132   int crh = 0;
1133   while (!doneWitIt)
1134   {
1135     if (voice_rom[adc] < 0x10)  tr << "0";
1136     tr << hex << (int)voice_rom[adc] << " ";
1137     if (crh++ > 24)  { crh = 0;  tr << endl; }
1138     if ((voice_rom[adc] == 0xFF) && (voice_rom[adc-1] != 0x00))
1139       doneWitIt = true;
1140     adc++;
1141   }//*/
1142
1143         // Set up V6809 execution contexts
1144
1145         memset(&cpu1, 0, sizeof(V6809REGS));
1146         cpu1.RdMem = RdMem;
1147         cpu1.WrMem = WrMem;
1148         cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET;
1149
1150         memset(&cpu2, 0, sizeof(V6809REGS));
1151         cpu2.RdMem = RdMemB;
1152         cpu2.WrMem = WrMemB;
1153         cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET;
1154
1155         bool firstTime = true;                                                          // kludge...
1156
1157 WriteLog("About to go to the main loop...\n");
1158         while (active)
1159         {
1160                 cout << ">";
1161                 if (firstTime)
1162                 {
1163                         firstTime = false;                                                      // crappy kludge...
1164                         lbuff[0] = 'r';
1165                         lbuff[1] = 0;
1166                 }
1167                 else
1168                         cin >> lbuff;
1169
1170                 if (lbuff[0] == 'd')
1171                 {
1172                         if (lbuff[1] != 0)
1173                         {
1174                                 lbuff[0] = 32;
1175                                 dpc = htod(lbuff);
1176                         }
1177                         printf("%04X: ", dpc);
1178                         uint16_t pc_save = cpu1.pc, pcB_save = cpu2.pc;
1179                         cpu1.pc = dpc;  cpu2.pc = dpc;
1180                         for(int i=0; i<16; i++)
1181                                 printf("%02X ", (looking_at_rom ? Fetch() : FetchB()));
1182                         cout << " ";
1183                         cpu1.pc = dpc;  cpu2.pc = dpc;
1184                         for(int i=0; i<16; i++)
1185                         {
1186                                 uint8_t a = (looking_at_rom ? Fetch() : FetchB());
1187                                 if (a<10)             cout << (char)(a+48);
1188                                 if ((a>9) && (a<37))  cout << (char)(a+55);
1189                                 if (a>36)             cout << ".";
1190                         }
1191                         cout << endl;
1192                         dpc = (looking_at_rom ? cpu1.pc : cpu2.pc);
1193                         cpu1.pc = pc_save;  cpu2.pc = pcB_save;
1194                 }
1195                 else if (lbuff[0] == 'e')
1196                 {
1197                         if (lbuff[1] != 0)
1198                         {
1199                                 lbuff[0] = 32;
1200                                 dpc = htod(lbuff);
1201                         }
1202                         printf("%04X: ", dpc);
1203                         for(int i=0; i<16; i++)  printf("%02X ", (uint8_t)gram[dpc++]);
1204                         cout << endl;
1205                 }
1206                 else if (lbuff[0] == 'l')
1207                 {
1208                         if (lbuff[1] != 0)
1209                         {
1210                                 lbuff[0] = 32;
1211                                 dpc = htod(lbuff);
1212                         }
1213                         for(int i=0; i<23; i++)
1214                                 Decode_6809();
1215                 }
1216                 else if (lbuff[0] == 't')
1217                 {
1218                         if (lbuff[1] != 0)
1219                         {
1220                                 lbuff[0] = 32;
1221                                 dpc = htod(lbuff);
1222                         }
1223                         if (looking_at_rom)
1224                         {
1225                                 cpu1.pc = dpc;
1226                                 Decode_6809();
1227                                 Execute6809(&cpu1, 1);
1228                                 dpc = cpu1.pc;
1229                                 printf("A=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X",
1230                                         cpu1.a, cpu1.b, cpu1.cc, cpu1.dp, cpu1.x, cpu1.y, cpu1.s, cpu1.u, cpu1.pc);
1231                                 cout << " iclock=" << cpu1.clock << endl;
1232                         }
1233                         else
1234                         {
1235                                 cpu2.pc = dpc;
1236                                 Decode_6809();
1237                                 Execute6809(&cpu2, 1);
1238                                 dpc = cpu2.pc;
1239                                 printf("A=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X",
1240                                         cpu2.a, cpu2.b, cpu2.cc, cpu2.dp, cpu2.x, cpu2.y, cpu2.s, cpu2.u, cpu2.pc);
1241                                 cout << " iclock=" << cpu2.clock << endl;
1242                         }
1243                 }
1244                 else if ((lbuff[0] == 'r') || (lbuff[0] == 'c')) // Run/continue...
1245                 {
1246 WriteLog("Executing 'run' command...\n");
1247                         uint32_t my_clock = 0;
1248                         running = true;                                                         // Set running status...
1249                         trace1 = false;
1250                         SetRefreshRate(refresh2);                                       // Tell GUI our refresh rate
1251       //for(uint16_t i=0; i<0x8000; i++)  gram2[i] = grom3[i]; //Temp
1252
1253                         if (lbuff[0] == 'r')                                            // If run, then reset CPUs
1254                         {
1255 WriteLog("Executing secondary 'run' command...\n");
1256 #if 1
1257                                 // This is data that is supposed to come from the MCU... So that's why it hangs
1258                                 gram1[0x4182] = 0xA6;          // Temp kludge
1259                                 gram1[0x4184] = 0xA6;
1260                                 gram1[0x4183] = 0x00;          // More of the same
1261                                 gram1[0x4185] = 0x00;
1262 #endif
1263                                 banksw1 = 0;                   // Will this work?
1264                                 banksw2 = 0;
1265 //        iclock = 0;                // Reset instr clock #1...
1266                                 InitGUI();                 // Reset # of coins
1267
1268 #if 0
1269                                 cpu1.pc = ((grom1[0xFFFE]<<8) | grom1[0xFFFF]); // Reset 6809 #1
1270                                 if (lbuff[1] != 0)
1271                                 {
1272                                 lbuff[0] = 32;  cpu1.pc = htod(lbuff);
1273                                 }
1274                                 else  cpu1.cc = 0xFF;                         // Set CC register
1275
1276                                 cpu2.pc = ((grom2[0xFFFE]<<8) | grom2[0xFFFF]); // Reset 6809 #2
1277                                 cpu2.cc = 0xFF;                              // Set CC register
1278                                 while(iclock < 8000)  // was 17000, 20000, 5000
1279                                 {
1280                                 Execute6809(&cpu1, 1);  Execute6809(&cpu2, 1);
1281                                 }
1282 #endif
1283 #if 0
1284 WriteLog("--> CPU clock #1: %u\n", cpu1.clock);
1285                                 // Will *this* help video sync? NO
1286                                 while (cpu1.clock < 8000)                               // was 17000, 20000, 5000
1287                                 {
1288                                         Execute6809(&cpu1, 1);
1289                                         Execute6809(&cpu2, 1);
1290                                 }
1291 #endif
1292                         }
1293
1294 WriteLog("About to set up screen...\n");
1295 #if 0
1296                         screen = SDL_SetVideoMode(VIRTUAL_SCREEN_WIDTH * 2, VIRTUAL_SCREEN_HEIGHT * 2, 8, SDL_SWSURFACE  | SDL_DOUBLEBUF);
1297                         if (screen == NULL)
1298                         {
1299                                 cout << "Failed to initialize screen!" << endl;
1300                                 running = false;
1301                         }
1302 #else
1303                         InitVideo();
1304 #endif
1305
1306 #if 0
1307                         SDL_Color colors[256];
1308
1309                         for(int i=0; i<256; i++)
1310                         {
1311                                 colors[i].r = palette[i*3+0];
1312                                 colors[i].g = palette[i*3+1];
1313                                 colors[i].b = palette[i*3+2];
1314                         }
1315
1316                         SDL_SetPalette(screen, SDL_LOGPAL | SDL_PHYSPAL, colors, 0, 256);
1317 #endif
1318
1319 #if 0
1320                         for(int i=0; i<256; i++)
1321                                 keys[i] = 0;                            // Clear keyboard buffer...
1322 #endif
1323
1324                         oldTicks = SDL_GetTicks();
1325
1326 WriteLog("About to set up audio...\n");
1327 #if 1
1328                         // This crap SHOULD be in sound.cpp (not yet created)...
1329                         SDL_AudioSpec desired, obtained;
1330                         desired.freq = 22050;
1331                         desired.format = AUDIO_U8;
1332                         desired.channels = 1;
1333                         desired.samples = 600;
1334                         desired.callback = SoundFunc;
1335                         desired.userdata = NULL;
1336                         // Also, should check to see if it got the hardware it needed, correct sample size, etc.
1337                         if (SDL_OpenAudio(&desired, &obtained) < 0)
1338                         {
1339                                 cout << "Couldn't open audio: " << SDL_GetError() << endl;
1340                                 return -1;
1341                         }
1342
1343                         SDL_PauseAudio(0);                                                      // Get that audio going!
1344 #endif
1345
1346 memset(scrBuffer, 0xFF, VIRTUAL_SCREEN_WIDTH*VIRTUAL_SCREEN_HEIGHT*sizeof(uint32_t));
1347 RenderScreenBuffer();
1348 WriteLog("About to enter main loop...\n");
1349                         while (running)
1350                         {
1351                                 HandleGUIDebounce();                                    // Debounce GUI keys
1352
1353                                 if (game_over_switch)
1354                                 {
1355                                         game_over_switch--;  // Countdown...
1356
1357                                         if (game_over_switch == 0)
1358                                                 gram1[0x4380] = 0; // Kill music!
1359                                 }
1360
1361 //testing... (works)
1362 //gram1[0x423D] = 1;
1363                                 //gram1[0x423D] = self_test;                    // Reset DSW1-1
1364                                 gram1[0x4268] = 0;                                              // Reset Video test
1365                                 gram1[0x427A] = 0;  gram1[0x427C] = 0;
1366                                 gram1[0x427B] = 0;  gram1[0x427D] = 0;
1367                                 gram1[0x427E] = 0;  gram1[0x427F] = 0;
1368                                 gram1[0x4280] = 0;  gram1[0x4281] = 0;
1369                                 gram1[0x4276] = 0;  gram1[0x426A] = 0;
1370                                 gram1[0x4278] = 0;  gram1[0x426C] = 0;
1371                                 gram1[0x4262] = 0;  gram1[0x4260] = 0;
1372                                 //gram1[0x4247] = 0;
1373
1374                                 // SDL key handling...
1375
1376 //                              SDL_PumpEvents();                               // Force key events into the buffer.
1377                                 SDL_Event event;
1378
1379                                 while (SDL_PollEvent(&event))
1380                                 {
1381                                         switch (event.type)
1382                                         {
1383                                         case SDL_KEYDOWN:
1384                                                 if (event.key.keysym.sym == SDLK_ESCAPE)
1385                                                         running = false;
1386                                         }
1387                                 }
1388
1389 #if 0
1390                                 if (keys[SDLK_ESCAPE])
1391                                         running = false;                     // ESC to exit...
1392
1393                                 if (debounce)
1394                                         debounce--;                          // Debounce toggle keys...
1395                                 else
1396                                 {
1397                                         if (keys[SDLK_F1])
1398                                         {
1399                                                 self_test = !self_test;            // Self-test (F1-toggle)
1400                                                 debounce = 10;                     // Key debounce value...
1401                                         }
1402                                         if (keys[SDLK_F2])
1403                                         {
1404                                                 gram1[0x4268] = 1;                 // Video test (F2)
1405                                                 debounce = 10;                     // Key debounce value...
1406                                         }
1407                                         if (keys[SDLK_F12])
1408                                         {
1409                                                 scr_type = !scr_type;              // Toggle screen (F12)
1410                                                 debounce = 10;                     // Key debounce value...
1411                                         }
1412                                         if (keys[SDLK_F3])
1413                                         {
1414                                                 show_scr = !show_scr;              // Toggle bkgrnd (F3)
1415                                                 debounce = 10;
1416                                         }
1417                                         if (keys[SDLK_F6])
1418                                         {
1419                                                 enable_cpu = !enable_cpu;          // Toggle CPUs (F6)
1420                                                 debounce = 10;
1421                                         }
1422                                         if (keys[SDLK_F5])
1423                                         {
1424                                                 refresh2 = !refresh2;             // Toggle 30/60Hz (F5)
1425                                                 SetRefreshRate(refresh2);         // Inform GUI of refresh
1426                                                 if (refresh2)
1427                                                         SpawnMsg(M60FPS);
1428                                                 else
1429                                                         SpawnMsg(M30FPS);
1430                                                 debounce = 10;                    // Key debounce value...
1431                                         }
1432                                         if (keys[SDLK_F4])                      // Do PCX snapshot (F4)
1433                                         {
1434                                                 SpawnSound(USERSOUND, SCAMERA);
1435                                                 SnapPCX(screen);
1436                                                 debounce = 10;
1437                                         }
1438                                         if (keys[SDLK_TAB])                      // Tab active/deactivate GUI
1439                                         {
1440                                                 if (ShowGUI())
1441                                                         DeactivateGUI();
1442                                                 else
1443                                                         ActivateGUI();
1444
1445                                                 debounce = 10;
1446                                         }
1447                                 }
1448                                 //if (keys[0x3E])  gram1[0x4247] = 1;  // Screen hold DS (F4)
1449                                 if (keys[SDLK_RIGHT])                                           // Right arrow
1450                                 {
1451                                         if (ShowGUI())
1452                                                 SelectRight();                     // If GUI active...
1453                                         else
1454                                         {
1455                                                 if (!keys[SDLK_LEFT])                     // Disallow opposite directions @ same time
1456                                                         gram1[0x427F] = 1;               // Stick right
1457                                         }
1458                                 }
1459                                 if (keys[SDLK_LEFT])
1460                                 {
1461                                         if (ShowGUI())
1462                                                 SelectLeft();                      // If GUI active...
1463                                         else
1464                                         {
1465                                                 if (!keys[SDLK_RIGHT])                     // Disallow opposite directions@same time
1466                                                 gram1[0x4281] = 1;               // Left arrow
1467                                         }
1468                                 }
1469                                 if (keys[SDLK_UP])
1470                                 {
1471                                         if (ShowGUI())
1472                                                 SelectUp();                        // If GUI active...
1473                                         else
1474                                         {
1475                                                 if (!keys[SDLK_DOWN])                     // Disallow opposite directions@same time
1476                                                         gram1[0x427B] = 1;               // Up arrow
1477                                         }
1478                                 }
1479                                 if (keys[SDLK_DOWN])
1480                                 {
1481                                         if (ShowGUI())
1482                                                 SelectDown();                                   // If GUI active...
1483                                         else
1484                                         {
1485                                                 if (!keys[SDLK_UP])                             // Disallow opposite directions@same time
1486                                                         gram1[0x427D] = 1;                      // Down arrow
1487                                         }
1488                                 }
1489                                 if (keys[SDLK_RETURN])                                                  // Return
1490                                 {
1491                                         uint8_t retval = UserSelectedSomething();
1492
1493                                         if (retval == EXIT)
1494                                                 running = false;
1495
1496                                         if (retval == REFRESH)
1497                                         {
1498                                                 refresh2 = !refresh2;
1499                                                 SetRefreshRate(refresh2);
1500                                         }
1501                                 }
1502
1503                                 if (keys[SDLK_1])
1504                                         gram1[0x427A] = 1;                      // (1)
1505
1506                                 if (keys[SDLK_2])
1507                                         gram1[0x427C] = 1;                      // (2)
1508
1509                                 if (keys[SDLK_3])
1510                                         gram1[0x427E] = 1;                      // (3)
1511
1512                                 if (keys[SDLK_5])
1513                                         gram1[0x4280] = 1;                      // (5)
1514
1515                                 if (keys[SDLK_q] | keys[29])
1516                                         gram1[0x4276] = 1;                      // (Q)  Jump
1517
1518                                 if (keys[SDLK_w])
1519                                         gram1[0x426A] = 1;                      // (W)
1520
1521                                 if (fire_debounce)
1522                                         fire_debounce--;
1523
1524                                 if (keys[SDLK_e] | keys[56])    // (E) Fire
1525                                 {
1526                                         if (!fire_debounce)
1527                                         {
1528                                                 gram1[0x4278] = 1;
1529
1530                                                 if (gram1[0x3F08] == 0xFF)              // Ugly kludge for debouncing gun
1531                                                         fire_debounce = 8;
1532                                                 else
1533                                                         fire_debounce = 2;
1534                                         }
1535                                 }
1536
1537                                 if (keys[SDLK_r])
1538                                         gram1[0x426C] = 1;                      // (R)
1539
1540                                 if (keys[SDLK_t])
1541                                         gram1[0x4262] = 1;                      // (T)
1542
1543                                 if (keys[SDLK_y])
1544                                         gram1[0x4260] = 1;                      // (Y)
1545
1546                                 if (keys[SDLK_F10])
1547                                         gram1[0x41A5]++;                        // Coin? (F10)
1548
1549                                 if (keys[SDLK_z])
1550                                         gram1[0x4189]++;                        // ? (Z) credits l dig
1551
1552                                 if (keys[SDLK_x])
1553                                         gram1[0x418A]++;                        // ? (X) credits r dig
1554
1555                                 if (keys[SDLK_c])
1556                                         gram1[0x418C]++;                        // ? (C) Start
1557
1558                                 if (keys[SDLK_v])
1559                                         gram1[0x418D]++;                        // ? (V)
1560
1561                                 if (keys[SDLK_F7])
1562                                         SpawnSound(USERSOUND, 0);       // Do user sound (F7)
1563
1564 //                              if (keys[SDLK_F8])
1565 //                              {
1566 //                                      gram1[0x4380] = 0;                      // (F8) kill music (this worx)
1567 //                                      charbase = false;                       // Switch chars out...
1568 //                              }
1569 //                              if (keys[SDLK_F9])  gram1[0x4285] = 1;          // (F9) strobe unknown loc
1570
1571                                 if (keys[SDLK_F11])                             // (F11)
1572                                 {
1573                                         Execute6809(&cpu1, 10);
1574                                         Execute6809(&cpu2, 10);
1575                                 }
1576 //                      }
1577 //F12 is used above, but the values are ignored. So we'll do it here too.
1578                                 if (keys[SDLK_F12])
1579                                 {
1580                                         cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET;
1581                                         cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET;
1582                                 }
1583
1584                                 if (keys[SDLK_d])                               // (D) start disassembly
1585                                         disasm = true;
1586 #if 0
1587         if (keys[SDLK_k])
1588                 gram1[0x5606] = 0x00;
1589         if (keys[SDLK_l])
1590         {
1591                 gram1[0x5607] = 0x01; // Hangs here... (CPU #1 waiting...)
1592                 WriteLog("\nMAIN: Stuffed $01 in $5607!!!\n\n");
1593         }
1594         if (keys[SDLK_o])
1595         {
1596                 gram1[0x5FF3] = 0x02;
1597                 WriteLog("\nMAIN: Stuffed $02 in $5FF3!!!\n\n");
1598         }
1599 #endif
1600 #endif
1601
1602                                 if (enable_cpu)
1603 //                              if (true)
1604                                 {
1605                                         // We can do this here because we're not executing the cores yet.
1606                                         cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ;
1607                                         cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ;
1608 //                                      while (cpu1.clock < 25000)
1609 // 1.538 MHz = 25633.333... cycles per frame (1/60 s)
1610 // 25600 cycles/frame
1611 // Setting interleave to 25 and below causes the V6809 core to hang...
1612 // 32 gets to the title screen before hanging...
1613 // 40 works, until it doesn't... :-P
1614 // 640 * 40
1615 // 800 * 32
1616 // Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though.
1617                                         for(uint32_t i=0; i<640; i++)
1618 //                                      for(uint32_t i=0; i<1280; i++)
1619                                         {
1620                                                 // Gay, but what are ya gonna do?
1621                                                 // There's better ways, such as keeping track of when slave writes to master, etc...
1622                                                 Execute6809(&cpu1, 40);
1623                                                 Execute6809(&cpu2, 40);
1624                                         }
1625                                 } // END: enable_cpu
1626
1627 //        if (refresh_++ == 1)                // 30 Hz...
1628 //        {
1629 //          if (scr_type)
1630 //            BlitWilliamsScreen(gram1);     // Display the screen...
1631 //          else
1632 //            BlitChar(screen, chr_rom, gram1);
1633 //          refresh_ = (refresh2 ? 1 : 0);    // 60/30 Hz...
1634 //        }
1635
1636 #if 0
1637 //temp, for testing...
1638 BlitChar(screen, chr_rom, gram1);
1639 #endif
1640                                 // Speed throttling happens here...
1641                                 while (SDL_GetTicks() - oldTicks < 16)  // Actually, it's 16.66... Need to account for that somehow
1642 //                              while (SDL_GetTicks() - oldTicks < 32)  // Actually, it's 16.66... Need to account for that somehow
1643                                         SDL_Delay(1);                           // Release our timeslice...
1644
1645                                 oldTicks = SDL_GetTicks();
1646 //cout << "Finished frame..." << endl;
1647                         }
1648
1649 //      Stop_audio_output();
1650 //      ReleaseTimer();
1651 //      ReleaseKeyboard();               // Release the interrupt...
1652 //      RestoreOldMode();                // Restore screen
1653                         if (brk && (cpu1.pc == brkpnt))
1654                                 cout << "CPU 1: Break at " << hex << cpu1.pc << endl;
1655                         if (brk2 && (cpu2.pc == brkpnt2))
1656                                 cout << "CPU 2: Break at " << hex << cpu2.pc << endl;
1657
1658                         lbuff[0] = 'q';                         // Temp kludge...
1659                 }
1660                 else if (lbuff[0] == 'b')  // Set/clear breakpoint
1661                 {
1662                         if (lbuff[1] != 0)
1663                         {
1664                                 lbuff[0] = 32;
1665                                 brkpnt = htod(lbuff);
1666                                 brk = true;
1667                                 cout << "Breakpoint #1 set at " << hex << brkpnt << dec << endl;
1668                         }
1669                         else
1670                         {
1671                                 brk = false;
1672                                 cout << "Breakpoint cleared" << endl;
1673                         }
1674                 }
1675                 else if (lbuff[0] == 'a')  // Set/clear breakpoint #2
1676                 {
1677                         if (lbuff[1] != 0)
1678                         {
1679                                 lbuff[0] = 32;
1680                                 brkpnt2 = htod(lbuff);
1681                                 brk2 = true;
1682                                 cout << "Breakpoint #2 set at " << hex << brkpnt2 << dec << endl;
1683                         }
1684                         else
1685                         {
1686                                 brk2 = false;
1687                                 cout << "Breakpoint cleared" << endl;
1688                         }
1689                 }
1690                 else if (lbuff[0] == 'i')  // Inspect registers
1691                 {
1692                         printf("CPU1: A=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X",
1693                                         cpu1.a, cpu1.b, cpu1.cc, cpu1.dp, cpu1.x, cpu1.y, cpu1.s, cpu1.u, cpu1.pc);
1694                         cout << " iclk=" << dec << cpu1.clock << endl;
1695                         printf("CPU2: A=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X",
1696                                         cpu2.a, cpu2.b, cpu2.cc, cpu2.dp, cpu2.x, cpu2.y, cpu2.s, cpu2.u, cpu2.pc);
1697                         cout << " iclk=" << dec << cpu2.clock << endl;
1698
1699                         if (brk)
1700                                 cout << "Breakpoint #1 set at " << hex << brkpnt << dec << endl;
1701
1702                         if (brk2)
1703                                 cout << "Breakpoint #2 set at " << hex << brkpnt2 << dec << endl;
1704                 }
1705                 else if (strncmp(lbuff, "swap", 4) == 0)  // Swap ROMs
1706                 {
1707                         looking_at_rom = !looking_at_rom;
1708                         cout << "Swapped:  Looking at ";
1709                         (looking_at_rom ? cout << "ROM #1" : cout << "ROM #2");
1710                         cout << endl;
1711                 }
1712                 else if (strncmp(lbuff, "seek", 4) == 0)  // Seek non-zero bytes in RAM
1713                 {
1714
1715                         if (lbuff[4] != 0)
1716                         {
1717                                 for(int i=0; i<4; i++)
1718                                 lbuff[i] = 32;
1719                                 dpc = htod(lbuff);
1720                         }
1721
1722                         do
1723                         {
1724                                 x = gram1[dpc++];
1725                         }
1726                         while ((x == 0) && (dpc != 0xFFFF)); // Keep going until something found
1727                         dpc--;
1728
1729                         printf("%04X: ", dpc);       // Show data found...
1730
1731                         for(int i=0; i<16; i++)
1732                                 printf("%02X ", gram1[(uint16_t)(dpc+i)]);
1733
1734                         cout << " ";
1735
1736                         for(int i=0; i<16; i++)
1737                         {
1738                                 uint8_t a = gram1[dpc++];
1739
1740                                 if (a<10)
1741                                         cout << (char)(a+48);
1742                                 if ((a>9) && (a<37))
1743                                         cout << (char)(a+55);
1744                                 if (a>36)
1745                                         cout << ".";
1746                         }
1747
1748                         cout << endl;
1749                 }
1750                 else if (lbuff[0] == 'v')    // View screen
1751                 {
1752                         BlitChar(screen, chr_rom, gram1);
1753                         getch();
1754                 }
1755
1756                 if (lbuff[0] == 'q')
1757                         active = false; //break;  // Quit
1758         }
1759
1760         SDL_Quit();                                                                     // Shut down SDL
1761
1762         for(int i=0; i<16; i++)
1763                 if (psg_adrs[i])
1764                         delete[] psg_adrs[i];                           // Deallocate if loaded
1765
1766         for(int i=0; i<14; i++)
1767                 if (fm_adrs[i])
1768                         delete[] fm_adrs[i];                            // Deallocate if loaded
1769
1770         LogDone();
1771
1772         return 1;
1773 }
1774
1775 #if 0
1776 Hitachi uC runs at 6.144 MHz
1777 YM2151 runs at 3.579580 MHz
1778
1779
1780 Rolling Thunder Memory map
1781 --------------------------
1782 Most of the decoding is done by custom chips (CUS47 and CUS41), so the memory
1783 map is inferred by program behaviour. The customs also handle internally irq
1784 and watchdog.
1785
1786 The main CPU memory map is the same in all games because CUS47 is used by all
1787 games. The sub CPU and sound CPU, on the other hand, change because CUS41 is
1788 replaced by other chips.
1789
1790 All RAM is shared between main and sub CPU, except for sound RAM which is
1791 shared between main and sound CPU; the portion of object RAM that is overlapped
1792 by sound RAM is used exclusively by the sub CPU.
1793
1794 MAIN CPU:
1795
1796 Address             Dir Data     Name      Description
1797 ------------------- --- -------- --------- -----------------------
1798 000x xxxx xxxx xxxx R/W xxxxxxxx SCROLL0   tilemap 0/1 RAM (shared with sub CPU)
1799 001x xxxx xxxx xxxx R/W xxxxxxxx SCROLL1   tilemap 2/3 RAM (shared with sub CPU)
1800 0100 00xx xxxx xxxx R/W xxxxxxxx SOUND     sound RAM (through CUS30, shared with MCU)
1801 0100 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1802 0100 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1803 010x xxxx xxxx xxxx R/W xxxxxxxx OBJECT    work RAM (shared with sub CPU) [1]
1804 0101 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1805 011x xxxx xxxx xxxx R   xxxxxxxx ROM 9D    program ROM (banked) [2]
1806 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 9C    program ROM
1807 1000 00-- ---- ----   W --------           watchdog reset (RES generated by CUS47)
1808 1000 01-- ---- ----   W --------           main CPU irq acknowledge (IRQ generated by CUS47)
1809 1000 1x-- ---- ----   W -------- BANK      tile gfx bank select (data is in A10) (latch in CUS47)
1810 1001 00-- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1811 1001 00-- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1812 1001 00-- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1813 1001 01-- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1814 1001 01-- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1815 1001 01-- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1816 1100 00-- ---- ----   W xxxxxxxx BACKCOLOR background color
1817
1818 [1] Note that this is partially overlapped by sound RAM
1819 [2] In Rolling Thunder and others, replaced by the ROM/voice expansion board
1820
1821
1822 SUB CPU:
1823
1824 Address             Dir Data     Name      Description
1825 ------------------- --- -------- --------- -----------------------
1826 000x xxxx xxxx xxxx R/W xxxxxxxx SUBOBJ    work RAM (shared with main CPU)
1827 0001 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1828 001x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR0   tilemap 0/1 RAM (shared with main CPU)
1829 010x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR1   tilemap 2/3 RAM (shared with main CPU)
1830 011x xxxx xxxx xxxx R   xxxxxxxx ROM 12D   program ROM (banked) [1]
1831 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 12C   program ROM
1832 1000 0--- ---- ----   W --------           watchdog reset (MRESET generated by CUS41)
1833 1000 1--- ---- ----   W --------           main CPU irq acknowledge (generated by CUS41)
1834 1101 0--- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1835 1101 0--- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1836 1101 0--- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1837 1101 1--- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1838 1101 1--- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1839 1101 1--- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1840
1841 [1] Only used by Rolling Thunder
1842
1843
1844 MCU:
1845
1846 Address             Dir Data     Name      Description
1847 ------------------- --- -------- --------- -----------------------
1848 0000 0000 xxxx xxxx                        MCU internal registers, timers, ports and RAM
1849 0001 xxxx xxxx xxxx R/W xxxxxxxx RAM 3F    sound RAM (through CUS30, partially shared with main CPU)
1850 0001 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1851 0001 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1852 0010 0--- --00 ---x R/W xxxxxxxx YMCS      YM2151
1853 0010 0--- --01 ----                        n.c.
1854 0010 0--- --10 ---- R   xxxxxxxx PORTA     switch inputs
1855 0010 0--- --11 ---- R   xxxxxxxx PORTB     dip switches
1856 01xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (lower half)
1857 10xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (upper half)
1858 1011 0--- ---- ----   W                    unknown (CUS41)
1859 1011 1--- ---- ----   W                    unknown (CUS41)
1860 1111 xxxx xxxx xxxx R   xxxxxxxx           MCU internal ROM
1861
1862
1863 Notes:
1864 -----
1865 - we are using an unusually high CPU interleave factor (800) to avoid hangs
1866   in rthunder. The two 6809 in this game synchronize using a semaphore at
1867   5606/5607 (CPU1) 1606/1607 (CPU2). CPU1 clears 5606, does some quick things,
1868   and then increments 5606. While it does its quick things (which require
1869   about 40 clock cycles) it expects CPU2 to clear 5607.
1870   Raising the interleave factor to 1000 makes wndrmomo crash during attract
1871   mode. I haven't investigated on the cause.
1872
1873 - There are two watchdogs, one per CPU (or maybe three). Handling them
1874   separately is necessary to allow entering service mode without manually
1875   resetting in rthunder and genpeitd: only one of the CPUs stops writing to
1876   the watchdog.
1877
1878 - The sprite hardware buffers spriteram: the program writes the sprite list to
1879   offsets 4-9 of every 16-byte block, then at the end writes to offset 0x1ff2 of
1880   sprite RAM to signal the chip that the list is complete. The chip will copy
1881   the list from 4-9 to 10-15 and use it from there. This has not been verified
1882   on the real hardware, but it is the most logical way of doing it.
1883   Emulating this behaviour and not using an external buffer is important in
1884   rthunder: when you insert a coin, the whole sprite RAM is cleared, but 0x1ff2
1885   is not written to. If we buffered spriteram to an external buffer, this would
1886   cause dangling sprites because the buffer would not be updated.
1887
1888 - spriteram buffering fixes sprite lag, but causes a glitch in rthunder when
1889   entering a door. The *closed* door is made of tiles, but the *moving* door is
1890   made of sprites. Since sprites are delayed by 1 frame, when you enter a door
1891   there is one frame where neither the tile-based closed door nor the
1892   sprite-based moving door is shown, so it flickers. This behavior has been
1893   confirmed on a real PCB.
1894
1895 TODO:
1896 ----
1897 - The two unknown writes for the MCU are probably watchdog reset and irq acknowledge,
1898   but they don't seem to work as expected. During the first few frames they are
1899   written out of order and hooking them up in the usual way causes the MCU to
1900   stop receiving interrupts.
1901
1902 #endif
1903