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