]> Shamusworld >> Repos - thunder/blob - src/thunder.cpp
d3134ed62db44ff5d5f84bf57f421836b474e1c5
[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                                                 debounce = 10;
1410                                         }
1411                                 }
1412                                 //if (keys[0x3E])  gram1[0x4247] = 1;  // Screen hold DS (F4)
1413                                 if (keys[SDLK_RIGHT])                                           // Right arrow
1414                                 {
1415                                         if (ShowGUI())
1416                                                 SelectRight();                     // If GUI active...
1417                                         else
1418                                         {
1419                                                 if (!keys[SDLK_LEFT])                     // Disallow opposite directions @ same time
1420                                                         gram1[0x427F] = 1;               // Stick right
1421                                         }
1422                                 }
1423                                 if (keys[SDLK_LEFT])
1424                                 {
1425                                         if (ShowGUI())
1426                                                 SelectLeft();                      // If GUI active...
1427                                         else
1428                                         {
1429                                                 if (!keys[SDLK_RIGHT])                     // Disallow opposite directions@same time
1430                                                 gram1[0x4281] = 1;               // Left arrow
1431                                         }
1432                                 }
1433                                 if (keys[SDLK_UP])
1434                                 {
1435                                         if (ShowGUI())
1436                                                 SelectUp();                        // If GUI active...
1437                                         else
1438                                         {
1439                                                 if (!keys[SDLK_DOWN])                     // Disallow opposite directions@same time
1440                                                         gram1[0x427B] = 1;               // Up arrow
1441                                         }
1442                                 }
1443                                 if (keys[SDLK_DOWN])
1444                                 {
1445                                         if (ShowGUI())
1446                                                 SelectDown();                                   // If GUI active...
1447                                         else
1448                                         {
1449                                                 if (!keys[SDLK_UP])                             // Disallow opposite directions@same time
1450                                                         gram1[0x427D] = 1;                      // Down arrow
1451                                         }
1452                                 }
1453                                 if (keys[SDLK_RETURN])                                                  // Return
1454                                 {
1455                                         uint8_t retval = UserSelectedSomething();
1456                                         if (retval == EXIT)
1457                                                 running = false;
1458                                         if (retval == REFRESH)
1459                                         {
1460                                                 refresh2 = !refresh2;
1461                                                 SetRefreshRate(refresh2);
1462                                         }
1463                                 }
1464                                 if (keys[SDLK_1])
1465                                         gram1[0x427A] = 1;                      // (1)
1466                                 if (keys[SDLK_2])
1467                                         gram1[0x427C] = 1;                      // (2)
1468                                 if (keys[SDLK_3])
1469                                         gram1[0x427E] = 1;                      // (3)
1470                                 if (keys[SDLK_5])
1471                                         gram1[0x4280] = 1;                      // (5)
1472                                 if (keys[SDLK_q] | keys[29])
1473                                         gram1[0x4276] = 1;                      // (Q)  Jump
1474                                 if (keys[SDLK_w])
1475                                         gram1[0x426A] = 1;                      // (W)
1476                                 if (fire_debounce)
1477                                         fire_debounce--;
1478                                 if (keys[SDLK_e] | keys[56])    // (E) Fire
1479                                 {
1480                                         if (!fire_debounce)
1481                                         {
1482                                                 gram1[0x4278] = 1;
1483
1484                                                 if (gram1[0x3F08] == 0xFF)              // Ugly kludge for debouncing gun
1485                                                         fire_debounce = 8;
1486                                                 else
1487                                                         fire_debounce = 2;
1488                                         }
1489                                 }
1490                                 if (keys[SDLK_r])
1491                                         gram1[0x426C] = 1;                      // (R)
1492                                 if (keys[SDLK_t])
1493                                         gram1[0x4262] = 1;                      // (T)
1494                                 if (keys[SDLK_y])
1495                                         gram1[0x4260] = 1;                      // (Y)
1496                                 if (keys[SDLK_F10])
1497                                         gram1[0x41A5]++;                        // Coin? (F10)
1498                                 if (keys[SDLK_z])
1499                                         gram1[0x4189]++;                        // ? (Z) credits l dig
1500                                 if (keys[SDLK_x])
1501                                         gram1[0x418A]++;                        // ? (X) credits r dig
1502                                 if (keys[SDLK_c])
1503                                         gram1[0x418C]++;                        // ? (C) Start
1504                                 if (keys[SDLK_v])
1505                                         gram1[0x418D]++;                        // ? (V)
1506                                 if (keys[SDLK_F7])
1507                                         SpawnSound(USERSOUND, 0);       // Do user sound (F7)
1508 //                              if (keys[SDLK_F8])
1509 //                              {
1510 //                                      gram1[0x4380] = 0;                      // (F8) kill music (this worx)
1511 //                                      charbase = false;                       // Switch chars out...
1512 //                              }
1513 //                              if (keys[SDLK_F9])  gram1[0x4285] = 1;          // (F9) strobe unknown loc
1514                                 if (keys[SDLK_F11])                             // (F11)
1515                                 {
1516                                         Execute6809(&cpu1, 10);
1517                                         Execute6809(&cpu2, 10);
1518                                 }
1519 //                      }
1520 //F12 is used above, but the values are ignored. So we'll do it here too.
1521                                 if (keys[SDLK_F12])
1522                                 {
1523                                         cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET;
1524                                         cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET;
1525                                 }
1526                                 if (keys[SDLK_d])                               // (D) start disassembly
1527                                         disasm = true;
1528 #if 0
1529         if (keys[SDLK_k])
1530                 gram1[0x5606] = 0x00;
1531         if (keys[SDLK_l])
1532         {
1533                 gram1[0x5607] = 0x01; // Hangs here... (CPU #1 waiting...)
1534                 WriteLog("\nMAIN: Stuffed $01 in $5607!!!\n\n");
1535         }
1536         if (keys[SDLK_o])
1537         {
1538                 gram1[0x5FF3] = 0x02;
1539                 WriteLog("\nMAIN: Stuffed $02 in $5FF3!!!\n\n");
1540         }
1541 #endif
1542
1543
1544                                 if (enable_cpu)
1545 //                              if (true)
1546                                 {
1547                                         // We can do this here because we're not executing the cores yet.
1548                                         cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ;
1549                                         cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ;
1550 //                                      while (cpu1.clock < 25000)
1551 // 1.538 MHz = 25633.333... cycles per frame (1/60 s)
1552 // 25600 cycles/frame
1553 // Setting interleave to 25 and below causes the V6809 core to hang...
1554 // 32 gets to the title screen before hanging...
1555 // 40 works, until it doesn't... :-P
1556 // 640 * 40
1557 // 800 * 32
1558 // Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though.
1559                                         for(uint32_t i=0; i<640; i++)
1560 //                                      for(uint32_t i=0; i<1280; i++)
1561                                         {
1562                                                 // Gay, but what are ya gonna do?
1563                                                 // There's better ways, such as keeping track of when slave writes to master, etc...
1564                                                 Execute6809(&cpu1, 40);
1565                                                 Execute6809(&cpu2, 40);
1566                                         }
1567                                 } // END: enable_cpu
1568
1569 //        if (refresh_++ == 1)                // 30 Hz...
1570 //        {
1571 //          if (scr_type)
1572 //            BlitWilliamsScreen(gram1);     // Display the screen...
1573 //          else
1574 //            BlitChar(screen, chr_rom, gram1);
1575 //          refresh_ = (refresh2 ? 1 : 0);    // 60/30 Hz...
1576 //        }
1577
1578 #if 0
1579 //temp, for testing...
1580 BlitChar(screen, chr_rom, gram1);
1581 #endif
1582                                 // Speed throttling happens here...
1583                                 while (SDL_GetTicks() - oldTicks < 16)  // Actually, it's 16.66... Need to account for that somehow
1584 //                              while (SDL_GetTicks() - oldTicks < 32)  // Actually, it's 16.66... Need to account for that somehow
1585                                         SDL_Delay(1);                           // Release our timeslice...
1586
1587                                 oldTicks = SDL_GetTicks();
1588 //cout << "Finished frame..." << endl;
1589                         }
1590
1591 //      Stop_audio_output();
1592 //      ReleaseTimer();
1593 //      ReleaseKeyboard();               // Release the interrupt...
1594 //      RestoreOldMode();                // Restore screen
1595                         if (brk && (cpu1.pc == brkpnt))
1596                                 cout << "CPU 1: Break at " << hex << cpu1.pc << endl;
1597                         if (brk2 && (cpu2.pc == brkpnt2))
1598                                 cout << "CPU 2: Break at " << hex << cpu2.pc << endl;
1599
1600                         lbuff[0] = 'q';                         // Temp kludge...
1601                 }
1602                 else if (lbuff[0] == 'b')  // Set/clear breakpoint
1603                 {
1604                         if (lbuff[1] != 0)
1605                         {
1606                                 lbuff[0] = 32;
1607                                 brkpnt = htod(lbuff);
1608                                 brk = true;
1609                                 cout << "Breakpoint #1 set at " << hex << brkpnt << dec << endl;
1610                         }
1611                         else
1612                         {
1613                                 brk = false;
1614                                 cout << "Breakpoint cleared" << endl;
1615                         }
1616                 }
1617                 else if (lbuff[0] == 'a')  // Set/clear breakpoint #2
1618                 {
1619                         if (lbuff[1] != 0)
1620                         {
1621                                 lbuff[0] = 32;
1622                                 brkpnt2 = htod(lbuff);
1623                                 brk2 = true;
1624                                 cout << "Breakpoint #2 set at " << hex << brkpnt2 << dec << endl;
1625                         }
1626                         else
1627                         {
1628                                 brk2 = false;
1629                                 cout << "Breakpoint cleared" << endl;
1630                         }
1631                 }
1632                 else if (lbuff[0] == 'i')  // Inspect registers
1633                 {
1634                         printf("CPU1: A=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X",
1635                                         cpu1.a, cpu1.b, cpu1.cc, cpu1.dp, cpu1.x, cpu1.y, cpu1.s, cpu1.u, cpu1.pc);
1636                         cout << " iclk=" << dec << cpu1.clock << endl;
1637                         printf("CPU2: A=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X",
1638                                         cpu2.a, cpu2.b, cpu2.cc, cpu2.dp, cpu2.x, cpu2.y, cpu2.s, cpu2.u, cpu2.pc);
1639                         cout << " iclk=" << dec << cpu2.clock << endl;
1640
1641                         if (brk)
1642                                 cout << "Breakpoint #1 set at " << hex << brkpnt << dec << endl;
1643
1644                         if (brk2)
1645                                 cout << "Breakpoint #2 set at " << hex << brkpnt2 << dec << endl;
1646                 }
1647                 else if (strncmp(lbuff, "swap", 4) == 0)  // Swap ROMs
1648                 {
1649                         looking_at_rom = !looking_at_rom;
1650                         cout << "Swapped:  Looking at ";
1651                         (looking_at_rom ? cout << "ROM #1" : cout << "ROM #2");
1652                         cout << endl;
1653                 }
1654                 else if (strncmp(lbuff, "seek", 4) == 0)  // Seek non-zero bytes in RAM
1655                 {
1656
1657                         if (lbuff[4] != 0)
1658                         {
1659                                 for(int i=0; i<4; i++)
1660                                 lbuff[i] = 32;
1661                                 dpc = htod(lbuff);
1662                         }
1663
1664                         do
1665                         {
1666                                 x = gram1[dpc++];
1667                         }
1668                         while ((x == 0) && (dpc != 0xFFFF)); // Keep going until something found
1669                         dpc--;
1670
1671                         printf("%04X: ", dpc);       // Show data found...
1672
1673                         for(int i=0; i<16; i++)
1674                                 printf("%02X ", gram1[(uint16_t)(dpc+i)]);
1675
1676                         cout << " ";
1677
1678                         for(int i=0; i<16; i++)
1679                         {
1680                                 uint8_t a = gram1[dpc++];
1681
1682                                 if (a<10)
1683                                         cout << (char)(a+48);
1684                                 if ((a>9) && (a<37))
1685                                         cout << (char)(a+55);
1686                                 if (a>36)
1687                                         cout << ".";
1688                         }
1689
1690                         cout << endl;
1691                 }
1692                 else if (lbuff[0] == 'v')    // View screen
1693                 {
1694                         BlitChar(screen, chr_rom, gram1);
1695                         getch();
1696                 }
1697
1698                 if (lbuff[0] == 'q')
1699                         active = false; //break;  // Quit
1700         }
1701
1702         SDL_Quit();                                                                     // Shut down SDL
1703
1704         for(int i=0; i<16; i++)
1705                 if (psg_adrs[i])
1706                         delete[] psg_adrs[i];                           // Deallocate if loaded
1707
1708         for(int i=0; i<14; i++)
1709                 if (fm_adrs[i])
1710                         delete[] fm_adrs[i];                            // Deallocate if loaded
1711
1712         LogDone();
1713
1714         return 1;
1715 }
1716
1717 #if 0
1718 Hitachi uC runs at 6.144 MHz
1719 YM2151 runs at 3.579580 MHz
1720
1721
1722 Rolling Thunder Memory map
1723 --------------------------
1724 Most of the decoding is done by custom chips (CUS47 and CUS41), so the memory
1725 map is inferred by program behaviour. The customs also handle internally irq
1726 and watchdog.
1727
1728 The main CPU memory map is the same in all games because CUS47 is used by all
1729 games. The sub CPU and sound CPU, on the other hand, change because CUS41 is
1730 replaced by other chips.
1731
1732 All RAM is shared between main and sub CPU, except for sound RAM which is
1733 shared between main and sound CPU; the portion of object RAM that is overlapped
1734 by sound RAM is used exclusively by the sub CPU.
1735
1736 MAIN CPU:
1737
1738 Address             Dir Data     Name      Description
1739 ------------------- --- -------- --------- -----------------------
1740 000x xxxx xxxx xxxx R/W xxxxxxxx SCROLL0   tilemap 0/1 RAM (shared with sub CPU)
1741 001x xxxx xxxx xxxx R/W xxxxxxxx SCROLL1   tilemap 2/3 RAM (shared with sub CPU)
1742 0100 00xx xxxx xxxx R/W xxxxxxxx SOUND     sound RAM (through CUS30, shared with MCU)
1743 0100 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1744 0100 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1745 010x xxxx xxxx xxxx R/W xxxxxxxx OBJECT    work RAM (shared with sub CPU) [1]
1746 0101 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1747 011x xxxx xxxx xxxx R   xxxxxxxx ROM 9D    program ROM (banked) [2]
1748 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 9C    program ROM
1749 1000 00-- ---- ----   W --------           watchdog reset (RES generated by CUS47)
1750 1000 01-- ---- ----   W --------           main CPU irq acknowledge (IRQ generated by CUS47)
1751 1000 1x-- ---- ----   W -------- BANK      tile gfx bank select (data is in A10) (latch in CUS47)
1752 1001 00-- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1753 1001 00-- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1754 1001 00-- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1755 1001 01-- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1756 1001 01-- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1757 1001 01-- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1758 1100 00-- ---- ----   W xxxxxxxx BACKCOLOR background color
1759
1760 [1] Note that this is partially overlapped by sound RAM
1761 [2] In Rolling Thunder and others, replaced by the ROM/voice expansion board
1762
1763
1764 SUB CPU:
1765
1766 Address             Dir Data     Name      Description
1767 ------------------- --- -------- --------- -----------------------
1768 000x xxxx xxxx xxxx R/W xxxxxxxx SUBOBJ    work RAM (shared with main CPU)
1769 0001 1xxx xxxx xxxx R/W xxxxxxxx           portion holding sprite registers
1770 001x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR0   tilemap 0/1 RAM (shared with main CPU)
1771 010x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR1   tilemap 2/3 RAM (shared with main CPU)
1772 011x xxxx xxxx xxxx R   xxxxxxxx ROM 12D   program ROM (banked) [1]
1773 1xxx xxxx xxxx xxxx R   xxxxxxxx ROM 12C   program ROM
1774 1000 0--- ---- ----   W --------           watchdog reset (MRESET generated by CUS41)
1775 1000 1--- ---- ----   W --------           main CPU irq acknowledge (generated by CUS41)
1776 1101 0--- ---- -x0x   W xxxxxxxx LATCH0    tilemap 0/1 X scroll + priority
1777 1101 0--- ---- -x10   W xxxxxxxx LATCH0    tilemap 0/1 Y scroll
1778 1101 0--- ---- --11   W ------xx BAMNKM    ROM 9D bank select
1779 1101 1--- ---- -x0x   W xxxxxxxx LATCH1    tilemap 2/3 X scroll + priority
1780 1101 1--- ---- -x10   W xxxxxxxx LATCH1    tilemap 2/3 Y scroll
1781 1101 1--- ---- --11   W ------xx BAMNKS    ROM 12D bank select
1782
1783 [1] Only used by Rolling Thunder
1784
1785
1786 MCU:
1787
1788 Address             Dir Data     Name      Description
1789 ------------------- --- -------- --------- -----------------------
1790 0000 0000 xxxx xxxx                        MCU internal registers, timers, ports and RAM
1791 0001 xxxx xxxx xxxx R/W xxxxxxxx RAM 3F    sound RAM (through CUS30, partially shared with main CPU)
1792 0001 0000 xxxx xxxx R/W xxxxxxxx           portion holding the sound wave data
1793 0001 0001 00xx xxxx R/W xxxxxxxx           portion holding the sound registers
1794 0010 0--- --00 ---x R/W xxxxxxxx YMCS      YM2151
1795 0010 0--- --01 ----                        n.c.
1796 0010 0--- --10 ---- R   xxxxxxxx PORTA     switch inputs
1797 0010 0--- --11 ---- R   xxxxxxxx PORTB     dip switches
1798 01xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (lower half)
1799 10xx xxxx xxxx xxxx R   xxxxxxxx ROM 6B    program ROM (upper half)
1800 1011 0--- ---- ----   W                    unknown (CUS41)
1801 1011 1--- ---- ----   W                    unknown (CUS41)
1802 1111 xxxx xxxx xxxx R   xxxxxxxx           MCU internal ROM
1803
1804
1805 Notes:
1806 -----
1807 - we are using an unusually high CPU interleave factor (800) to avoid hangs
1808   in rthunder. The two 6809 in this game synchronize using a semaphore at
1809   5606/5607 (CPU1) 1606/1607 (CPU2). CPU1 clears 5606, does some quick things,
1810   and then increments 5606. While it does its quick things (which require
1811   about 40 clock cycles) it expects CPU2 to clear 5607.
1812   Raising the interleave factor to 1000 makes wndrmomo crash during attract
1813   mode. I haven't investigated on the cause.
1814
1815 - There are two watchdogs, one per CPU (or maybe three). Handling them
1816   separately is necessary to allow entering service mode without manually
1817   resetting in rthunder and genpeitd: only one of the CPUs stops writing to
1818   the watchdog.
1819
1820 - The sprite hardware buffers spriteram: the program writes the sprite list to
1821   offsets 4-9 of every 16-byte block, then at the end writes to offset 0x1ff2 of
1822   sprite RAM to signal the chip that the list is complete. The chip will copy
1823   the list from 4-9 to 10-15 and use it from there. This has not been verified
1824   on the real hardware, but it is the most logical way of doing it.
1825   Emulating this behaviour and not using an external buffer is important in
1826   rthunder: when you insert a coin, the whole sprite RAM is cleared, but 0x1ff2
1827   is not written to. If we buffered spriteram to an external buffer, this would
1828   cause dangling sprites because the buffer would not be updated.
1829
1830 - spriteram buffering fixes sprite lag, but causes a glitch in rthunder when
1831   entering a door. The *closed* door is made of tiles, but the *moving* door is
1832   made of sprites. Since sprites are delayed by 1 frame, when you enter a door
1833   there is one frame where neither the tile-based closed door nor the
1834   sprite-based moving door is shown, so it flickers. This behavior has been
1835   confirmed on a real PCB.
1836
1837 TODO:
1838 ----
1839 - The two unknown writes for the MCU are probably watchdog reset and irq acknowledge,
1840   but they don't seem to work as expected. During the first few frames they are
1841   written out of order and hooking them up in the usual way causes the MCU to
1842   stop receiving interrupts.
1843
1844 #endif
1845