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