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