]> Shamusworld >> Repos - thunder/blob - src/thunder.cpp
Some cleanup of the screen tile rendering. More to come.
[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                         screen = SDL_SetVideoMode(VIRTUAL_SCREEN_WIDTH * 2, VIRTUAL_SCREEN_HEIGHT * 2, 8, SDL_SWSURFACE  | SDL_DOUBLEBUF);
1247                         if (screen == NULL)
1248                         {
1249                                 cout << "Failed to initialize screen!" << endl;
1250                                 running = false;
1251                         }
1252
1253                         SDL_Color colors[256];
1254                         for(int i=0; i<256; i++)
1255                         {
1256                                 colors[i].r = palette[i*3+0];
1257                                 colors[i].g = palette[i*3+1];
1258                                 colors[i].b = palette[i*3+2];
1259                         }
1260                         SDL_SetPalette(screen, SDL_LOGPAL | SDL_PHYSPAL, colors, 0, 256);
1261
1262 #if 0
1263         // This confirms that we're getting video to the screen...
1264         SDL_LockSurface(screen);
1265
1266         uint8 pixel = 0;
1267         uint8 * pixels = (uint8 *)(screen->pixels);
1268
1269         for(uint32 y=0; y<480; y++)
1270                 for(uint32 x=0; x<640; x++)
1271                         pixels[(y * 640) + x] = pixel++;
1272
1273         SDL_UnlockSurface(screen);
1274         SDL_UpdateRect(screen, 0, 0, 0, 0);
1275 #endif
1276
1277                         for(int i=0; i<256; i++)
1278                                 keys[i] = 0;                            // Clear keyboard buffer...
1279
1280                         oldTicks = SDL_GetTicks();
1281
1282 WriteLog("About to set up audio...\n");
1283                         // This crap SHOULD be in sound.cpp (not yet created)...
1284                         SDL_AudioSpec desired, obtained;
1285                         desired.freq = 22050;
1286                         desired.format = AUDIO_U8;
1287                         desired.channels = 1;
1288                         desired.samples = 600;
1289                         desired.callback = SoundFunc;
1290                         desired.userdata = NULL;
1291                         // Also, should check to see if it got the hardware it needed, correct sample size, etc.
1292                         if (SDL_OpenAudio(&desired, &obtained) < 0)
1293                         {
1294                                 cout << "Couldn't open audio: " << SDL_GetError() << endl;
1295                                 return -1;
1296                         }
1297                         SDL_PauseAudio(0);                                                      // Get that audio going!
1298
1299 WriteLog("About to enter main loop...\n");
1300                         while (running)
1301                         {
1302                                 HandleGUIDebounce();                                    // Debounce GUI keys
1303                                 if (game_over_switch)
1304                                 {
1305                                         game_over_switch--;  // Countdown...
1306                                         if (game_over_switch == 0)
1307                                                 gram1[0x4380] = 0; // Kill music!
1308                                 }
1309 //testing... (works)
1310 //gram1[0x423D] = 1;
1311                                 //gram1[0x423D] = self_test;                    // Reset DSW1-1
1312                                 gram1[0x4268] = 0;                                              // Reset Video test
1313                                 gram1[0x427A] = 0;  gram1[0x427C] = 0;
1314                                 gram1[0x427B] = 0;  gram1[0x427D] = 0;
1315                                 gram1[0x427E] = 0;  gram1[0x427F] = 0;
1316                                 gram1[0x4280] = 0;  gram1[0x4281] = 0;
1317                                 gram1[0x4276] = 0;  gram1[0x426A] = 0;
1318                                 gram1[0x4278] = 0;  gram1[0x426C] = 0;
1319                                 gram1[0x4262] = 0;  gram1[0x4260] = 0;
1320                                 //gram1[0x4247] = 0;
1321
1322                                 // SDL key handling...
1323
1324                                 SDL_PumpEvents();                               // Force key events into the buffer.
1325
1326                                 if (keys[SDLK_ESCAPE])
1327                                         running = false;                     // ESC to exit...
1328
1329                                 if (debounce)
1330                                         debounce--;                          // Debounce toggle keys...
1331                                 else
1332                                 {
1333                                         if (keys[SDLK_F1])
1334                                         {
1335                                                 self_test = !self_test;            // Self-test (F1-toggle)
1336                                                 debounce = 10;                     // Key debounce value...
1337                                         }
1338                                         if (keys[SDLK_F2])
1339                                         {
1340                                                 gram1[0x4268] = 1;                 // Video test (F2)
1341                                                 debounce = 10;                     // Key debounce value...
1342                                         }
1343                                         if (keys[SDLK_F12])
1344                                         {
1345                                                 scr_type = !scr_type;              // Toggle screen (F12)
1346                                                 debounce = 10;                     // Key debounce value...
1347                                         }
1348                                         if (keys[SDLK_F3])
1349                                         {
1350                                                 show_scr = !show_scr;              // Toggle bkgrnd (F3)
1351                                                 debounce = 10;
1352                                         }
1353                                         if (keys[SDLK_F6])
1354                                         {
1355                                                 enable_cpu = !enable_cpu;          // Toggle CPUs (F6)
1356                                                 debounce = 10;
1357                                         }
1358                                         if (keys[SDLK_F5])
1359                                         {
1360                                                 refresh2 = !refresh2;             // Toggle 30/60Hz (F5)
1361                                                 SetRefreshRate(refresh2);         // Inform GUI of refresh
1362                                                 if (refresh2)
1363                                                         SpawnMsg(M60FPS);
1364                                                 else
1365                                                         SpawnMsg(M30FPS);
1366                                                 debounce = 10;                    // Key debounce value...
1367                                         }
1368                                         if (keys[SDLK_F4])                      // Do PCX snapshot (F4)
1369                                         {
1370                                                 SpawnSound(USERSOUND, SCAMERA);
1371                                                 SnapPCX(screen);
1372                                                 debounce = 10;
1373                                         }
1374                                         if (keys[SDLK_TAB])                      // Tab active/deactivate GUI
1375                                         {
1376                                                 if (ShowGUI())
1377                                                         DeactivateGUI();
1378                                                 else
1379                                                         ActivateGUI();
1380                                                 debounce = 10;
1381                                         }
1382                                 }
1383                                 //if (keys[0x3E])  gram1[0x4247] = 1;  // Screen hold DS (F4)
1384                                 if (keys[SDLK_RIGHT])                                           // Right arrow
1385                                 {
1386                                         if (ShowGUI())
1387                                                 SelectRight();                     // If GUI active...
1388                                         else
1389                                         {
1390                                                 if (!keys[SDLK_LEFT])                     // Disallow opposite directions @ same time
1391                                                         gram1[0x427F] = 1;               // Stick right
1392                                         }
1393                                 }
1394                                 if (keys[SDLK_LEFT])
1395                                 {
1396                                         if (ShowGUI())
1397                                                 SelectLeft();                      // If GUI active...
1398                                         else
1399                                         {
1400                                                 if (!keys[SDLK_RIGHT])                     // Disallow opposite directions@same time
1401                                                 gram1[0x4281] = 1;               // Left arrow
1402                                         }
1403                                 }
1404                                 if (keys[SDLK_UP])
1405                                 {
1406                                         if (ShowGUI())
1407                                                 SelectUp();                        // If GUI active...
1408                                         else
1409                                         {
1410                                                 if (!keys[SDLK_DOWN])                     // Disallow opposite directions@same time
1411                                                         gram1[0x427B] = 1;               // Up arrow
1412                                         }
1413                                 }
1414                                 if (keys[SDLK_DOWN])
1415                                 {
1416                                         if (ShowGUI())
1417                                                 SelectDown();                                   // If GUI active...
1418                                         else
1419                                         {
1420                                                 if (!keys[SDLK_UP])                             // Disallow opposite directions@same time
1421                                                         gram1[0x427D] = 1;                      // Down arrow
1422                                         }
1423                                 }
1424                                 if (keys[SDLK_RETURN])                                                  // Return
1425                                 {
1426                                         uint8 retval = UserSelectedSomething();
1427                                         if (retval == EXIT)
1428                                                 running = false;
1429                                         if (retval == REFRESH)
1430                                         {
1431                                                 refresh2 = !refresh2;
1432                                                 SetRefreshRate(refresh2);
1433                                         }
1434                                 }
1435                                 if (keys[SDLK_1])
1436                                         gram1[0x427A] = 1;                      // (1)
1437                                 if (keys[SDLK_2])
1438                                         gram1[0x427C] = 1;                      // (2)
1439                                 if (keys[SDLK_3])
1440                                         gram1[0x427E] = 1;                      // (3)
1441                                 if (keys[SDLK_5])
1442                                         gram1[0x4280] = 1;                      // (5)
1443                                 if (keys[SDLK_q] | keys[29])
1444                                         gram1[0x4276] = 1;                      // (Q)  Jump
1445                                 if (keys[SDLK_w])
1446                                         gram1[0x426A] = 1;                      // (W)
1447                                 if (fire_debounce)
1448                                         fire_debounce--;
1449                                 if (keys[SDLK_e] | keys[56])    // (E) Fire
1450                                 {
1451                                         if (!fire_debounce)
1452                                         {
1453                                                 gram1[0x4278] = 1;
1454
1455                                                 if (gram1[0x3F08] == 0xFF)              // Ugly kludge for debouncing gun
1456                                                         fire_debounce = 8;
1457                                                 else
1458                                                         fire_debounce = 2;
1459                                         }
1460                                 }
1461                                 if (keys[SDLK_r])
1462                                         gram1[0x426C] = 1;                      // (R)
1463                                 if (keys[SDLK_t])
1464                                         gram1[0x4262] = 1;                      // (T)
1465                                 if (keys[SDLK_y])
1466                                         gram1[0x4260] = 1;                      // (Y)
1467                                 if (keys[SDLK_F10])
1468                                         gram1[0x41A5]++;                        // Coin? (F10)
1469                                 if (keys[SDLK_z])
1470                                         gram1[0x4189]++;                        // ? (Z) credits l dig
1471                                 if (keys[SDLK_x])
1472                                         gram1[0x418A]++;                        // ? (X) credits r dig
1473                                 if (keys[SDLK_c])
1474                                         gram1[0x418C]++;                        // ? (C) Start
1475                                 if (keys[SDLK_v])
1476                                         gram1[0x418D]++;                        // ? (V)
1477                                 if (keys[SDLK_F7])
1478                                         SpawnSound(USERSOUND, 0);       // Do user sound (F7)
1479 //                              if (keys[SDLK_F8])
1480 //                              {
1481 //                                      gram1[0x4380] = 0;                      // (F8) kill music (this worx)
1482 //                                      charbase = false;                       // Switch chars out...
1483 //                              }
1484 //                              if (keys[SDLK_F9])  gram1[0x4285] = 1;          // (F9) strobe unknown loc
1485                                 if (keys[SDLK_F11])                             // (F11)
1486                                 {
1487                                         Execute6809(&cpu1, 10);
1488                                         Execute6809(&cpu2, 10);
1489                                 }
1490 //                      }
1491 //F12 is used above, but the values are ignored. So we'll do it here too.
1492                                 if (keys[SDLK_F12])
1493                                 {
1494                                         cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET;
1495                                         cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET;
1496                                 }
1497                                 if (keys[SDLK_d])                               // (D) start disassembly
1498                                         disasm = true;
1499 #if 0
1500         if (keys[SDLK_k])
1501                 gram1[0x5606] = 0x00;
1502         if (keys[SDLK_l])
1503         {
1504                 gram1[0x5607] = 0x01; // Hangs here... (CPU #1 waiting...)
1505                 WriteLog("\nMAIN: Stuffed $01 in $5607!!!\n\n");
1506         }
1507         if (keys[SDLK_o])
1508         {
1509                 gram1[0x5FF3] = 0x02;
1510                 WriteLog("\nMAIN: Stuffed $02 in $5FF3!!!\n\n");
1511         }
1512 #endif
1513
1514
1515                                 if (enable_cpu)
1516 //                              if (true)
1517                                 {
1518                                         // We can do this here because we're not executing the cores yet.
1519                                         cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ;
1520                                         cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ;
1521 //                                      while (cpu1.clock < 25000)
1522 // 1.538 MHz = 25633.333... cycles per frame (1/60 s)
1523 // 25600 cycles/frame
1524 // Setting interleave to 25 and below causes the V6809 core to hang...
1525 // 32 gets to the title screen before hanging...
1526 // 40 works, until it doesn't... :-P
1527 // 640 * 40
1528 // 800 * 32
1529 // Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though.
1530                                         for(uint32 i=0; i<640; i++)
1531 //                                      for(uint32 i=0; i<1280; i++)
1532                                         {
1533                                                 // Gay, but what are ya gonna do?
1534                                                 // There's better ways, such as keeping track of when slave writes to master, etc...
1535                                                 Execute6809(&cpu1, 40);
1536                                                 Execute6809(&cpu2, 40);
1537                                         }
1538                                 } // END: enable_cpu
1539
1540 //        if (refresh_++ == 1)                // 30 Hz...
1541 //        {
1542 //          if (scr_type)
1543 //            BlitWilliamsScreen(gram1);     // Display the screen...
1544 //          else
1545 //            BlitChar(screen, chr_rom, gram1);
1546 //          refresh_ = (refresh2 ? 1 : 0);    // 60/30 Hz...
1547 //        }
1548
1549 #if 0
1550 //temp, for testing...
1551 BlitChar(screen, chr_rom, gram1);
1552 #endif
1553                                 // Speed throttling happens here...
1554                                 while (SDL_GetTicks() - oldTicks < 16)  // Actually, it's 16.66... Need to account for that somehow
1555 //                              while (SDL_GetTicks() - oldTicks < 32)  // Actually, it's 16.66... Need to account for that somehow
1556                                         SDL_Delay(1);                           // Release our timeslice...
1557
1558                                 oldTicks = SDL_GetTicks();
1559 //cout << "Finished frame..." << endl;
1560                         }
1561
1562 //      Stop_audio_output();
1563 //      ReleaseTimer();
1564 //      ReleaseKeyboard();               // Release the interrupt...
1565 //      RestoreOldMode();                // Restore screen
1566                         if (brk && (cpu1.pc == brkpnt))
1567                                 cout << "CPU 1: Break at " << hex << cpu1.pc << endl;
1568                         if (brk2 && (cpu2.pc == brkpnt2))
1569                                 cout << "CPU 2: Break at " << hex << cpu2.pc << endl;
1570
1571                         lbuff[0] = 'q';                         // Temp kludge...
1572                 }
1573                 else if (lbuff[0] == 'b')  // Set/clear breakpoint
1574                 {
1575                         if (lbuff[1] != 0)
1576                         {
1577                                 lbuff[0] = 32;
1578                                 brkpnt = htod(lbuff);
1579                                 brk = true;
1580                                 cout << "Breakpoint #1 set at " << hex << brkpnt << dec << endl;
1581                         }
1582                         else
1583                         {
1584                                 brk = false;
1585                                 cout << "Breakpoint cleared" << endl;
1586                         }
1587                 }
1588                 else if (lbuff[0] == 'a')  // Set/clear breakpoint #2
1589                 {
1590                         if (lbuff[1] != 0)
1591                         {
1592                                 lbuff[0] = 32;
1593                                 brkpnt2 = htod(lbuff);
1594                                 brk2 = true;
1595                                 cout << "Breakpoint #2 set at " << hex << brkpnt2 << dec << endl;
1596                         }
1597                         else
1598                         {
1599                                 brk2 = false;
1600                                 cout << "Breakpoint cleared" << endl;
1601                         }
1602                 }
1603                 else if (lbuff[0] == 'i')  // Inspect registers
1604                 {
1605       printf("CPU1: A=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X",
1606               cpu1.a, cpu1.b, cpu1.cc, cpu1.dp, cpu1.x, cpu1.y, cpu1.s, cpu1.u, cpu1.pc);
1607       cout << " iclk=" << dec << cpu1.clock << endl;
1608       printf("CPU2: A=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X",
1609               cpu2.a, cpu2.b, cpu2.cc, cpu2.dp, cpu2.x, cpu2.y, cpu2.s, cpu2.u, cpu2.pc);
1610       cout << " iclk=" << dec << cpu2.clock << endl;
1611       if (brk)
1612         cout << "Breakpoint #1 set at " << hex << brkpnt << dec << endl;
1613       if (brk2)
1614         cout << "Breakpoint #2 set at " << hex << brkpnt2 << dec << endl;
1615     }
1616                 else if (strncmp(lbuff, "swap", 4) == 0)  // Swap ROMs
1617     {
1618       looking_at_rom = !looking_at_rom;
1619       cout << "Swapped:  Looking at ";
1620       (looking_at_rom ? cout << "ROM #1" : cout << "ROM #2");
1621       cout << endl;
1622     }
1623                 else if (strncmp(lbuff, "seek", 4) == 0)  // Seek non-zero bytes in RAM
1624     {
1625       if (lbuff[4] != 0)
1626       {
1627         for(int i=0; i<4; i++)
1628           lbuff[i] = 32;
1629         dpc = htod(lbuff);
1630       }
1631       do
1632       {
1633         x = gram1[dpc++];
1634       }
1635       while ((x == 0) && (dpc != 0xFFFF)); // Keep going until something found
1636       dpc--;
1637
1638       printf("%04X: ", dpc);       // Show data found...
1639       for(int i=0; i<16; i++)
1640         printf("%02X ", gram1[(uint16)(dpc+i)]);
1641       cout << " ";
1642       for(int i=0; i<16; i++)
1643       {
1644         uint8 a = gram1[dpc++];
1645         if (a<10)
1646           cout << (char)(a+48);
1647         if ((a>9) && (a<37))
1648           cout << (char)(a+55);
1649         if (a>36)
1650           cout << ".";
1651       }
1652       cout << endl;
1653     }
1654                 else if (lbuff[0] == 'v')    // View screen
1655                 {
1656 //                      SetVESA2();                           // Set up screen
1657                         BlitChar(screen, chr_rom, gram1);
1658                         getch();
1659 //                      RestoreOldMode();
1660                 }
1661
1662                 if (lbuff[0] == 'q')
1663                         active = false; //break;  // Quit
1664         }
1665
1666         SDL_Quit();                                                                     // Shut down SDL
1667
1668         for(int i=0; i<16; i++)
1669                 if (psg_adrs[i])
1670                         delete[] psg_adrs[i];                           // Deallocate if loaded
1671
1672         for(int i=0; i<14; i++)
1673                 if (fm_adrs[i])
1674                         delete[] fm_adrs[i];                            // Deallocate if loaded
1675
1676         LogDone();
1677
1678         return 1;
1679 }
1680
1681 #if 0
1682 Hitachi uC runs at 6.144 MHz
1683 YM2151 runs at 3.579580 MHz
1684
1685
1686 Rolling Thunder Memory map
1687 --------------------------
1688 Most of the decoding is done by custom chips (CUS47 and CUS41), so the memory
1689 map is inferred by program behaviour. The customs also handle internally irq
1690 and watchdog.
1691 The main CPU memory map is the same in all games because CUS47 is used by all
1692 games. The sub CPU and sound CPU, on the other hand, change because CUS41 is
1693 replaced by other chips.
1694 All RAM is shared between main and sub CPU, except for sound RAM which is shared
1695 between main and sound CPU; the portion of object RAM that is overlapped by sound
1696 RAM is used exclusively by the sub CPU.
1697
1698 MAIN CPU:
1699
1700 Address             Dir Data     Name      Description
1701 ------------------- --- -------- --------- -----------------------
1702 000x xxxx xxxx xxxx R/W xxxxxxxx SCROLL0   tilemap 0/1 RAM (shared with sub CPU)
1703 001x xxxx xxxx xxxx R/W xxxxxxxx SCROLL1   tilemap 2/3 RAM (shared with sub CPU)
1704 0100 00xx xxxx xxxx R/W xxxxxxxx SOUND     sound RAM (through CUS30, shared with MCU)
1705 0100 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1706 0100 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1707 010x xxxx xxxx xxxx R/W xxxxxxxx OBJECT    work RAM (shared with sub CPU) [1]
1708 0101 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1709 011x xxxx xxxx xxxx R   xxxxxxxx ROM 9D    program ROM (banked) [2]
1710 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 9C    program ROM
1711 1000 00-- ---- ----   W --------           watchdog reset (RES generated by CUS47)
1712 1000 01-- ---- ----   W --------           main CPU irq acknowledge (IRQ generated by CUS47)
1713 1000 1x-- ---- ----   W -------- BANK      tile gfx bank select (data is in A10) (latch in CUS47)
1714 1001 00-- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1715 1001 00-- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1716 1001 00-- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1717 1001 01-- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1718 1001 01-- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1719 1001 01-- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1720 1100 00-- ---- ----   W xxxxxxxx BACKCOLOR background color
1721
1722 [1] Note that this is partially overlapped by sound RAM
1723 [2] In Rolling Thunder and others, replaced by the ROM/voice expansion board
1724
1725
1726 SUB CPU:
1727
1728 Address             Dir Data     Name      Description
1729 ------------------- --- -------- --------- -----------------------
1730 000x xxxx xxxx xxxx R/W xxxxxxxx SUBOBJ    work RAM (shared with main CPU)
1731 0001 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1732 001x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR0   tilemap 0/1 RAM (shared with main CPU)
1733 010x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR1   tilemap 2/3 RAM (shared with main CPU)
1734 011x xxxx xxxx xxxx R   xxxxxxxx ROM 12D   program ROM (banked) [1]
1735 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 12C   program ROM
1736 1000 0--- ---- ----   W --------           watchdog reset (MRESET generated by CUS41)
1737 1000 1--- ---- ----   W --------           main CPU irq acknowledge (generated by CUS41)
1738 1101 0--- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1739 1101 0--- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1740 1101 0--- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1741 1101 1--- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1742 1101 1--- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1743 1101 1--- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1744
1745 [1] Only used by Rolling Thunder
1746
1747
1748 MCU:
1749
1750 Address             Dir Data     Name      Description
1751 ------------------- --- -------- --------- -----------------------
1752 0000 0000 xxxx xxxx                        MCU internal registers, timers, ports and RAM
1753 0001 xxxx xxxx xxxx R/W xxxxxxxx RAM 3F    sound RAM (through CUS30, partially shared with main CPU)
1754 0001 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1755 0001 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1756 0010 0--- --00 ---x R/W xxxxxxxx YMCS      YM2151
1757 0010 0--- --01 ----                        n.c.
1758 0010 0--- --10 ---- R   xxxxxxxx PORTA     switch inputs
1759 0010 0--- --11 ---- R   xxxxxxxx PORTB     dip switches
1760 01xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (lower half)
1761 10xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (upper half)
1762 1011 0--- ---- ----   W                    unknown (CUS41)
1763 1011 1--- ---- ----   W                    unknown (CUS41)
1764 1111 xxxx xxxx xxxx R   xxxxxxxx           MCU internal ROM
1765
1766
1767 Notes:
1768 -----
1769 - we are using an unusually high CPU interleave factor (800) to avoid hangs
1770   in rthunder. The two 6809 in this game synchronize using a semaphore at
1771   5606/5607 (CPU1) 1606/1607 (CPU2). CPU1 clears 5606, does some quick things,
1772   and then increments 5606. While it does its quick things (which require
1773   about 40 clock cycles) it expects CPU2 to clear 5607.
1774   Raising the interleave factor to 1000 makes wndrmomo crash during attract
1775   mode. I haven't investigated on the cause.
1776
1777 - There are two watchdogs, one per CPU (or maybe three). Handling them
1778   separately is necessary to allow entering service mode without manually
1779   resetting in rthunder and genpeitd: only one of the CPUs stops writing to
1780   the watchdog.
1781
1782 - The sprite hardware buffers spriteram: the program writes the sprite list to
1783   offsets 4-9 of every 16-byte block, then at the end writes to offset 0x1ff2 of
1784   sprite RAM to signal the chip that the list is complete. The chip will copy
1785   the list from 4-9 to 10-15 and use it from there. This has not been verified
1786   on the real hardware, but it is the most logical way of doing it.
1787   Emulating this behaviour and not using an external buffer is important in
1788   rthunder: when you insert a coin, the whole sprite RAM is cleared, but 0x1ff2
1789   is not written to. If we buffered spriteram to an external buffer, this would
1790   cause dangling sprites because the buffer would not be updated.
1791
1792 - spriteram buffering fixes sprite lag, but causes a glitch in rthunder when
1793   entering a door. The *closed* door is made of tiles, but the *moving* door is
1794   made of sprites. Since sprites are delayed by 1 frame, when you enter a door
1795   there is one frame where neither the tile-based closed door nor the
1796   sprite-based moving door is shown, so it flickers. This behavior has been
1797   confirmed on a real PCB.
1798
1799 TODO:
1800 ----
1801 - The two unknown writes for the MCU are probably watchdog reset and irq acknowledge,
1802   but they don't seem to work as expected. During the first few frames they are
1803   written out of order and hooking them up in the usual way causes the MCU to
1804   stop receiving interrupts.
1805
1806 #endif