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