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