1 // Based on MAME driver by David Graves
2
3 #include "tiles_generic.h"
4 #include "m68000_intf.h"
5 #include "z80_intf.h"
6 #include "taito.h"
7 #include "taito_ic.h"
8 #include "burn_ym2610.h"
9 #include "eeprom.h"
10 #include "burn_gun.h"
11
12 static double OthunderYM2610AY8910RouteMasterVol;
13 static double OthunderYM2610Route1MasterVol;
14 static double OthunderYM2610Route2MasterVol;
15 static UINT8 *OthunderPan;
16
17 #ifdef BUILD_A68K
18 static bool bUseAsm68KCoreOldValue = false;
19 #endif
20
21 #define A(a, b, c, d) {a, b, (UINT8*)(c), d}
22
23 static struct BurnInputInfo OthunderInputList[] =
24 {
25 {"Coin 1" , BIT_DIGITAL , TC0220IOCInputPort0 + 3, "p1 coin" },
26 {"Start 1" , BIT_DIGITAL , TC0220IOCInputPort0 + 6, "p1 start" },
27 {"Coin 2" , BIT_DIGITAL , TC0220IOCInputPort0 + 2, "p2 coin" },
28 {"Start 2" , BIT_DIGITAL , TC0220IOCInputPort0 + 7, "p2 start" },
29
30 A("P1 Gun X" , BIT_ANALOG_REL, &TaitoAnalogPort0 , "mouse x-axis" ),
31 A("P1 Gun Y" , BIT_ANALOG_REL, &TaitoAnalogPort1 , "mouse y-axis" ),
32 {"P1 Fire 1" , BIT_DIGITAL , TC0220IOCInputPort2 + 0, "mouse button 1" },
33 {"P1 Fire 2" , BIT_DIGITAL , TC0220IOCInputPort2 + 2, "mouse button 2" },
34
35 A("P2 Gun X" , BIT_ANALOG_REL, &TaitoAnalogPort2 , "p2 x-axis" ),
36 A("P2 Gun Y" , BIT_ANALOG_REL, &TaitoAnalogPort3 , "p2 y-axis" ),
37 {"P2 Fire 1" , BIT_DIGITAL , TC0220IOCInputPort2 + 1, "p2 fire 1" },
38 {"P2 Fire 2" , BIT_DIGITAL , TC0220IOCInputPort2 + 3, "p2 fire 2" },
39
40 {"Reset" , BIT_DIGITAL , &TaitoReset , "reset" },
41 {"Service" , BIT_DIGITAL , TC0220IOCInputPort0 + 4, "service" },
42 {"Dip 1" , BIT_DIPSWITCH , TC0220IOCDip + 0 , "dip" },
43 {"Dip 2" , BIT_DIPSWITCH , TC0220IOCDip + 1 , "dip" },
44 {"Dip 3" , BIT_DIPSWITCH , TaitoDip + 0 , "dip" },
45 };
46
STDINPUTINFO(Othunder)47 STDINPUTINFO(Othunder)
48
49 #undef A
50
51 static void TC0220IOCMakeInputs()
52 {
53 // Reset Inputs
54 TC0220IOCInput[0] = 0xff;
55 TC0220IOCInput[1] = 0xff;
56 TC0220IOCInput[2] = 0xff;
57
58 for (INT32 i = 0; i < 8; i++) {
59 TC0220IOCInput[0] -= (TC0220IOCInputPort0[i] & 1) << i;
60 TC0220IOCInput[1] -= (TC0220IOCInputPort1[i] & 1) << i;
61 TC0220IOCInput[2] -= (TC0220IOCInputPort2[i] & 1) << i;
62 }
63 }
64
OthunderMakeInputs()65 static void OthunderMakeInputs()
66 {
67 TC0220IOCMakeInputs();
68
69 BurnGunMakeInputs(0, (INT16)TaitoAnalogPort0, (INT16)TaitoAnalogPort1);
70 BurnGunMakeInputs(1, (INT16)TaitoAnalogPort2, (INT16)TaitoAnalogPort3);
71 }
72
73 static struct BurnDIPInfo OthunderDIPList[]=
74 {
75 // Default Values
76 {0x0e, 0xff, 0xff, 0xff, NULL },
77 {0x0f, 0xff, 0xff, 0x7f, NULL },
78 {0x10, 0xff, 0xff, 0x07, NULL },
79
80 // Dip 1
81 {0 , 0xfe, 0 , 2 , "Allow Continue" },
82 {0x0e, 0x01, 0x02, 0x00, "Off" },
83 {0x0e, 0x01, 0x02, 0x02, "On" },
84
85 {0 , 0xfe, 0 , 2 , "Service Mode" },
86 {0x0e, 0x01, 0x04, 0x04, "Off" },
87 {0x0e, 0x01, 0x04, 0x00, "On" },
88
89 {0 , 0xfe, 0 , 2 , "Demo Sounds" },
90 {0x0e, 0x01, 0x08, 0x00, "Off" },
91 {0x0e, 0x01, 0x08, 0x08, "On" },
92
93 {0 , 0xfe, 0 , 4 , "Coin A" },
94 {0x0e, 0x01, 0x30, 0x00, "4 Coins 1 Credit" },
95 {0x0e, 0x01, 0x30, 0x10, "3 Coins 1 Credit" },
96 {0x0e, 0x01, 0x30, 0x20, "2 Coins 1 Credit" },
97 {0x0e, 0x01, 0x30, 0x30, "1 Coin 1 Credit" },
98
99 {0 , 0xfe, 0 , 4 , "Coin B" },
100 {0x0e, 0x01, 0xc0, 0xc0, "1 Coin 2 Credits" },
101 {0x0e, 0x01, 0xc0, 0x80, "1 Coin 3 Credits" },
102 {0x0e, 0x01, 0xc0, 0x40, "1 Coin 4 Credits" },
103 {0x0e, 0x01, 0xc0, 0x00, "1 Coin 6 Credits" },
104
105 // Dip 2
106 {0 , 0xfe, 0 , 4 , "Difficulty" },
107 {0x0f, 0x01, 0x03, 0x02, "Easy" },
108 {0x0f, 0x01, 0x03, 0x03, "Medium" },
109 {0x0f, 0x01, 0x03, 0x01, "Hard" },
110 {0x0f, 0x01, 0x03, 0x00, "Hardest" },
111
112 {0 , 0xfe, 0 , 4 , "Magazines/Rockets" },
113 {0x0f, 0x01, 0x0c, 0x0c, "5/3" },
114 {0x0f, 0x01, 0x0c, 0x08, "6/4" },
115 {0x0f, 0x01, 0x0c, 0x04, "7/5" },
116 {0x0f, 0x01, 0x0c, 0x00, "8/6" },
117
118 {0 , 0xfe, 0 , 4 , "Bullets per Magazine" },
119 {0x0f, 0x01, 0x30, 0x00, "30" },
120 {0x0f, 0x01, 0x30, 0x10, "35" },
121 {0x0f, 0x01, 0x30, 0x30, "40" },
122 {0x0f, 0x01, 0x30, 0x20, "50" },
123
124 {0 , 0xfe, 0 , 2 , "Language" },
125 {0x0f, 0x01, 0x80, 0x00, "English" },
126 {0x0f, 0x01, 0x80, 0x80, "Japanese" },
127
128 // Dip 3
129 {0 , 0xfe, 0 , 4 , "Stereo Seperation" },
130 {0x10, 0x01, 0x07, 0x07, "Maximum" },
131 {0x10, 0x01, 0x07, 0x03, "High" },
132 {0x10, 0x01, 0x07, 0x01, "Medium" },
133 {0x10, 0x01, 0x07, 0x00, "Low" },
134 };
135
136 STDDIPINFO(Othunder)
137
138 static struct BurnDIPInfo OthunderjDIPList[]=
139 {
140 // Default Values
141 {0x0e, 0xff, 0xff, 0xff, NULL },
142 {0x0f, 0xff, 0xff, 0x7f, NULL },
143 {0x10, 0xff, 0xff, 0x07, NULL },
144
145 // Dip 1
146 {0 , 0xfe, 0 , 2 , "Allow Continue" },
147 {0x0e, 0x01, 0x02, 0x00, "Off" },
148 {0x0e, 0x01, 0x02, 0x02, "On" },
149
150 {0 , 0xfe, 0 , 2 , "Service Mode" },
151 {0x0e, 0x01, 0x04, 0x04, "Off" },
152 {0x0e, 0x01, 0x04, 0x00, "On" },
153
154 {0 , 0xfe, 0 , 2 , "Demo Sounds" },
155 {0x0e, 0x01, 0x08, 0x00, "Off" },
156 {0x0e, 0x01, 0x08, 0x08, "On" },
157
158 {0 , 0xfe, 0 , 4 , "Coin A" },
159 {0x0e, 0x01, 0x30, 0x10, "2 Coins 1 Credit" },
160 {0x0e, 0x01, 0x30, 0x30, "1 Coin 1 Credit" },
161 {0x0e, 0x01, 0x30, 0x00, "2 Coins 3 Credits" },
162 {0x0e, 0x01, 0x30, 0x20, "1 Coin 2 Credits" },
163
164 {0 , 0xfe, 0 , 4 , "Coin B" },
165 {0x0e, 0x01, 0xc0, 0x40, "2 Coins 1 Credit" },
166 {0x0e, 0x01, 0xc0, 0xc0, "1 Coin 1 Credit" },
167 {0x0e, 0x01, 0xc0, 0x00, "2 Coins 3 Credits" },
168 {0x0e, 0x01, 0xc0, 0x80, "1 Coin 2 Credits" },
169
170 // Dip 2
171 {0 , 0xfe, 0 , 4 , "Difficulty" },
172 {0x0f, 0x01, 0x03, 0x02, "Easy" },
173 {0x0f, 0x01, 0x03, 0x03, "Medium" },
174 {0x0f, 0x01, 0x03, 0x01, "Hard" },
175 {0x0f, 0x01, 0x03, 0x00, "Hardest" },
176
177 {0 , 0xfe, 0 , 4 , "Magazines/Rockets" },
178 {0x0f, 0x01, 0x0c, 0x0c, "5/3" },
179 {0x0f, 0x01, 0x0c, 0x08, "6/4" },
180 {0x0f, 0x01, 0x0c, 0x04, "7/5" },
181 {0x0f, 0x01, 0x0c, 0x00, "8/6" },
182
183 {0 , 0xfe, 0 , 4 , "Bullets per Magazine" },
184 {0x0f, 0x01, 0x30, 0x00, "30" },
185 {0x0f, 0x01, 0x30, 0x10, "35" },
186 {0x0f, 0x01, 0x30, 0x30, "40" },
187 {0x0f, 0x01, 0x30, 0x20, "50" },
188
189 {0 , 0xfe, 0 , 2 , "language" },
190 {0x0f, 0x01, 0x80, 0x00, "English" },
191 {0x0f, 0x01, 0x80, 0x80, "Japanese" },
192
193 // Dip 3
194 {0 , 0xfe, 0 , 4 , "Stereo Seperation" },
195 {0x10, 0x01, 0x07, 0x07, "Maximum" },
196 {0x10, 0x01, 0x07, 0x03, "High" },
197 {0x10, 0x01, 0x07, 0x01, "Medium" },
198 {0x10, 0x01, 0x07, 0x00, "Low" },
199 };
200
201 STDDIPINFO(Othunderj)
202
203 static struct BurnDIPInfo OthunderuDIPList[]=
204 {
205 // Default Values
206 {0x0e, 0xff, 0xff, 0xff, NULL },
207 {0x0f, 0xff, 0xff, 0x7f, NULL },
208 {0x10, 0xff, 0xff, 0x07, NULL },
209
210 // Dip 1
211 {0 , 0xfe, 0 , 2 , "Allow Continue" },
212 {0x0e, 0x01, 0x02, 0x00, "Off" },
213 {0x0e, 0x01, 0x02, 0x02, "On" },
214
215 {0 , 0xfe, 0 , 2 , "Service Mode" },
216 {0x0e, 0x01, 0x04, 0x04, "Off" },
217 {0x0e, 0x01, 0x04, 0x00, "On" },
218
219 {0 , 0xfe, 0 , 2 , "Demo Sounds" },
220 {0x0e, 0x01, 0x08, 0x00, "Off" },
221 {0x0e, 0x01, 0x08, 0x08, "On" },
222
223 {0 , 0xfe, 0 , 4 , "Coin A" },
224 {0x0e, 0x01, 0x30, 0x10, "2 Coins 1 Credit" },
225 {0x0e, 0x01, 0x30, 0x30, "1 Coin 1 Credit" },
226 {0x0e, 0x01, 0x30, 0x00, "2 Coins 3 Credits" },
227 {0x0e, 0x01, 0x30, 0x20, "1 Coin 2 Credits" },
228
229 {0 , 0xfe, 0 , 4 , "Coin B" },
230 {0x0e, 0x01, 0xc0, 0x40, "2 Coins 1 Credit" },
231 {0x0e, 0x01, 0xc0, 0xc0, "1 Coin 1 Credit" },
232 {0x0e, 0x01, 0xc0, 0x00, "2 Coins 3 Credits" },
233 {0x0e, 0x01, 0xc0, 0x80, "1 Coin 2 Credits" },
234
235 // Dip 2
236 {0 , 0xfe, 0 , 4 , "Difficulty" },
237 {0x0f, 0x01, 0x03, 0x02, "Easy" },
238 {0x0f, 0x01, 0x03, 0x03, "Medium" },
239 {0x0f, 0x01, 0x03, 0x01, "Hard" },
240 {0x0f, 0x01, 0x03, 0x00, "Hardest" },
241
242 {0 , 0xfe, 0 , 4 , "Magazines/Rockets" },
243 {0x0f, 0x01, 0x0c, 0x0c, "5/3" },
244 {0x0f, 0x01, 0x0c, 0x08, "6/4" },
245 {0x0f, 0x01, 0x0c, 0x04, "7/5" },
246 {0x0f, 0x01, 0x0c, 0x00, "8/6" },
247
248 {0 , 0xfe, 0 , 4 , "Bullets per Magazine" },
249 {0x0f, 0x01, 0x30, 0x00, "30" },
250 {0x0f, 0x01, 0x30, 0x10, "35" },
251 {0x0f, 0x01, 0x30, 0x30, "40" },
252 {0x0f, 0x01, 0x30, 0x20, "50" },
253
254 {0 , 0xfe, 0 , 2 , "Continue Price" },
255 {0x0f, 0x01, 0x40, 0x00, "1 Coin 1 Credit" },
256 {0x0f, 0x01, 0x40, 0x40, "Same as Start" },
257
258 {0 , 0xfe, 0 , 2 , "language" },
259 {0x0f, 0x01, 0x80, 0x00, "English" },
260 {0x0f, 0x01, 0x80, 0x80, "Japanese" },
261
262 // Dip 3
263 {0 , 0xfe, 0 , 4 , "Stereo Seperation" },
264 {0x10, 0x01, 0x07, 0x07, "Maximum" },
265 {0x10, 0x01, 0x07, 0x03, "High" },
266 {0x10, 0x01, 0x07, 0x01, "Medium" },
267 {0x10, 0x01, 0x07, 0x00, "Low" },
268 };
269
270 STDDIPINFO(Othunderu)
271
272 static struct BurnRomInfo OthunderRomDesc[] = {
273 { "b67-20-1.ic63", 0x20000, 0x851a453b, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
274 { "b67-23-1.ic64", 0x20000, 0x6e4f3d56, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
275 { "b67-14.ic61", 0x20000, 0x7f3dd724, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
276 { "b67-15.ic62", 0x20000, 0xe84f62d0, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
277
278 { "b67-13.ic40", 0x10000, 0x2936b4b1, BRF_ESS | BRF_PRG | TAITO_Z80ROM1 },
279
280 { "b67-06.ic66", 0x80000, 0xb9a38d64, BRF_GRA | TAITO_CHARS},
281
282 { "b67-01.ic1", 0x80000, 0x81ad9acb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
283 { "b67-02.ic2", 0x80000, 0xc20cd2fb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
284 { "b67-03.ic3", 0x80000, 0xbc9019ed, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
285 { "b67-04.ic4", 0x80000, 0x2af4c8af, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
286
287 { "b67-05.ic43", 0x80000, 0x9593e42b, BRF_GRA | TAITO_SPRITEMAP },
288
289 { "b67-08.ic67", 0x80000, 0x458f41fb, BRF_SND | TAITO_YM2610A },
290
291 { "b67-07.ic44", 0x80000, 0x4f834357, BRF_SND | TAITO_YM2610B },
292
293 { "93c46_eeprom-othunder.ic86", 0x00080, 0x3729b844, BRF_PRG | TAITO_DEFAULT_EEPROM },
294
295 { "plhs18p8b-b67-09.ic15", 0x00149, 0x62035487, BRF_OPT },
296 { "pal16l8a-b67-11.ic36", 0x00104, 0x3177fb06, BRF_OPT },
297 { "pal20l8b-b67-12.ic37", 0x00144, 0xa47c2798, BRF_OPT },
298 { "pal20l8b-b67-10.ic33", 0x00144, 0x4ced09c7, BRF_OPT },
299 };
300
301 STD_ROM_PICK(Othunder)
302 STD_ROM_FN(Othunder)
303
304 static struct BurnRomInfo OthunderoRomDesc[] = {
305 { "b67-20.ic63", 0x20000, 0x21439ea2, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
306 { "b67-23.ic64", 0x20000, 0x789e9daa, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
307 { "b67-14.ic61", 0x20000, 0x7f3dd724, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
308 { "b67-15.ic62", 0x20000, 0xe84f62d0, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
309
310 { "b67-13.ic40", 0x10000, 0x2936b4b1, BRF_ESS | BRF_PRG | TAITO_Z80ROM1 },
311
312 { "b67-06.ic66", 0x80000, 0xb9a38d64, BRF_GRA | TAITO_CHARS},
313
314 { "b67-01.ic1", 0x80000, 0x81ad9acb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
315 { "b67-02.ic2", 0x80000, 0xc20cd2fb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
316 { "b67-03.ic3", 0x80000, 0xbc9019ed, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
317 { "b67-04.ic4", 0x80000, 0x2af4c8af, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
318
319 { "b67-05.ic43", 0x80000, 0x9593e42b, BRF_GRA | TAITO_SPRITEMAP },
320
321 { "b67-08.ic67", 0x80000, 0x458f41fb, BRF_SND | TAITO_YM2610A },
322
323 { "b67-07.ic44", 0x80000, 0x4f834357, BRF_SND | TAITO_YM2610B },
324
325 { "93c46_eeprom-othunder.ic86", 0x00080, 0x3729b844, BRF_PRG | TAITO_DEFAULT_EEPROM },
326
327 { "plhs18p8b-b67-09.ic15", 0x00149, 0x62035487, BRF_OPT },
328 { "pal16l8a-b67-11.ic36", 0x00104, 0x3177fb06, BRF_OPT },
329 { "pal20l8b-b67-12.ic37", 0x00144, 0xa47c2798, BRF_OPT },
330 { "pal20l8b-b67-10.ic33", 0x00144, 0x4ced09c7, BRF_OPT },
331 };
332
333 STD_ROM_PICK(Othundero)
334 STD_ROM_FN(Othundero)
335
336 static struct BurnRomInfo OthunderuRomDesc[] = {
337 { "b67-20-1.ic63", 0x20000, 0x851a453b, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
338 { "b67-22-1.ic64", 0x20000, 0x19480dc0, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
339 { "b67-14.ic61", 0x20000, 0x7f3dd724, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
340 { "b67-15.ic62", 0x20000, 0xe84f62d0, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
341
342 { "b67-13.ic40", 0x10000, 0x2936b4b1, BRF_ESS | BRF_PRG | TAITO_Z80ROM1 },
343
344 { "b67-06.ic66", 0x80000, 0xb9a38d64, BRF_GRA | TAITO_CHARS},
345
346 { "b67-01.ic1", 0x80000, 0x81ad9acb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
347 { "b67-02.ic2", 0x80000, 0xc20cd2fb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
348 { "b67-03.ic3", 0x80000, 0xbc9019ed, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
349 { "b67-04.ic4", 0x80000, 0x2af4c8af, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
350
351 { "b67-05.ic43", 0x80000, 0x9593e42b, BRF_GRA | TAITO_SPRITEMAP },
352
353 { "b67-08.ic67", 0x80000, 0x458f41fb, BRF_SND | TAITO_YM2610A },
354
355 { "b67-07.ic44", 0x80000, 0x4f834357, BRF_SND | TAITO_YM2610B },
356
357 { "93c46_eeprom-othunder.ic86", 0x00080, 0x3729b844, BRF_PRG | TAITO_DEFAULT_EEPROM },
358
359 { "plhs18p8b-b67-09.ic15", 0x00149, 0x62035487, BRF_OPT },
360 { "pal16l8a-b67-11.ic36", 0x00104, 0x3177fb06, BRF_OPT },
361 { "pal20l8b-b67-12.ic37", 0x00144, 0xa47c2798, BRF_OPT },
362 { "pal20l8b-b67-10.ic33", 0x00144, 0x4ced09c7, BRF_OPT },
363 };
364
365 STD_ROM_PICK(Othunderu)
366 STD_ROM_FN(Othunderu)
367
368 static struct BurnRomInfo OthunderuoRomDesc[] = {
369 { "b67-20.ic63", 0x20000, 0x21439ea2, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
370 { "b67-22.ic64", 0x20000, 0x0f99ad3c, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
371 { "b67-14.ic61", 0x20000, 0x7f3dd724, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
372 { "b67-15.ic62", 0x20000, 0xe84f62d0, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
373
374 { "b67-13.ic40", 0x10000, 0x2936b4b1, BRF_ESS | BRF_PRG | TAITO_Z80ROM1 },
375
376 { "b67-06.ic66", 0x80000, 0xb9a38d64, BRF_GRA | TAITO_CHARS},
377
378 { "b67-01.ic1", 0x80000, 0x81ad9acb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
379 { "b67-02.ic2", 0x80000, 0xc20cd2fb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
380 { "b67-03.ic3", 0x80000, 0xbc9019ed, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
381 { "b67-04.ic4", 0x80000, 0x2af4c8af, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
382
383 { "b67-05.ic43", 0x80000, 0x9593e42b, BRF_GRA | TAITO_SPRITEMAP },
384
385 { "b67-08.ic67", 0x80000, 0x458f41fb, BRF_SND | TAITO_YM2610A },
386
387 { "b67-07.ic44", 0x80000, 0x4f834357, BRF_SND | TAITO_YM2610B },
388
389 { "93c46_eeprom-othunder.ic86", 0x00080, 0x3729b844, BRF_PRG | TAITO_DEFAULT_EEPROM },
390
391 { "plhs18p8b-b67-09.ic15", 0x00149, 0x62035487, BRF_OPT },
392 { "pal16l8a-b67-11.ic36", 0x00104, 0x3177fb06, BRF_OPT },
393 { "pal20l8b-b67-12.ic37", 0x00144, 0xa47c2798, BRF_OPT },
394 { "pal20l8b-b67-10.ic33", 0x00144, 0x4ced09c7, BRF_OPT },
395 };
396
397 STD_ROM_PICK(Othunderuo)
398 STD_ROM_FN(Othunderuo)
399
400 static struct BurnRomInfo OthunderjRomDesc[] = {
401 { "b67-20.ic63", 0x20000, 0x21439ea2, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
402 { "b67-21.ic64", 0x20000, 0x9690fc86, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
403 { "b67-14.ic61", 0x20000, 0x7f3dd724, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
404 { "b67-15.ic62", 0x20000, 0xe84f62d0, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
405
406 { "b67-13.ic40", 0x10000, 0x2936b4b1, BRF_ESS | BRF_PRG | TAITO_Z80ROM1 },
407
408 { "b67-06.ic66", 0x80000, 0xb9a38d64, BRF_GRA | TAITO_CHARS},
409
410 { "b67-01.ic1", 0x80000, 0x81ad9acb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
411 { "b67-02.ic2", 0x80000, 0xc20cd2fb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
412 { "b67-03.ic3", 0x80000, 0xbc9019ed, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
413 { "b67-04.ic4", 0x80000, 0x2af4c8af, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
414
415 { "b67-05.ic43", 0x80000, 0x9593e42b, BRF_GRA | TAITO_SPRITEMAP },
416
417 { "b67-08.ic67", 0x80000, 0x458f41fb, BRF_SND | TAITO_YM2610A },
418
419 { "b67-07.ic44", 0x80000, 0x4f834357, BRF_SND | TAITO_YM2610B },
420
421 { "93c46_eeprom-othunder.ic86", 0x00080, 0x3729b844, BRF_PRG | TAITO_DEFAULT_EEPROM },
422
423 { "plhs18p8b-b67-09.ic15", 0x00149, 0x62035487, BRF_OPT },
424 { "pal16l8a-b67-11.ic36", 0x00104, 0x3177fb06, BRF_OPT },
425 { "pal20l8b-b67-12.ic37", 0x00144, 0xa47c2798, BRF_OPT },
426 { "pal20l8b-b67-10.ic33", 0x00144, 0x4ced09c7, BRF_OPT },
427 };
428
429 STD_ROM_PICK(Othunderj)
430 STD_ROM_FN(Othunderj)
431
432 static struct BurnRomInfo OthunderjscRomDesc[] = {
433 // SC stands for Shopping Center. It was put in a smaller, single player cabinet aimed at children
434 { "b67-24.ic63", 0x20000, 0x18670e0b, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
435 { "b67-25.ic64", 0x20000, 0x3d422991, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
436 { "b67-14.ic61", 0x20000, 0x7f3dd724, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
437 { "b67-15.ic62", 0x20000, 0xe84f62d0, BRF_ESS | BRF_PRG | TAITO_68KROM1_BYTESWAP },
438
439 { "b67-13.ic40", 0x10000, 0x2936b4b1, BRF_ESS | BRF_PRG | TAITO_Z80ROM1 },
440
441 { "b67-06.ic66", 0x80000, 0xb9a38d64, BRF_GRA | TAITO_CHARS},
442
443 { "b67-01.ic1", 0x80000, 0x81ad9acb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
444 { "b67-02.ic2", 0x80000, 0xc20cd2fb, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
445 { "b67-03.ic3", 0x80000, 0xbc9019ed, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
446 { "b67-04.ic4", 0x80000, 0x2af4c8af, BRF_GRA | TAITO_SPRITESA_BYTESWAP32 },
447
448 { "b67-05.ic43", 0x80000, 0x9593e42b, BRF_GRA | TAITO_SPRITEMAP },
449
450 { "b67-08.ic67", 0x80000, 0x458f41fb, BRF_SND | TAITO_YM2610A },
451
452 { "b67-07.ic44", 0x80000, 0x4f834357, BRF_SND | TAITO_YM2610B },
453
454 { "93c46_eeprom-othunder.ic86", 0x00080, 0x3729b844, BRF_PRG | TAITO_DEFAULT_EEPROM },
455
456 { "plhs18p8b-b67-09.ic15", 0x00149, 0x62035487, BRF_OPT },
457 { "pal16l8a-b67-11.ic36", 0x00104, 0x3177fb06, BRF_OPT },
458 { "pal20l8b-b67-12.ic37", 0x00144, 0xa47c2798, BRF_OPT },
459 { "pal20l8b-b67-10.ic33", 0x00144, 0x4ced09c7, BRF_OPT },
460 };
461
462 STD_ROM_PICK(Othunderjsc)
STD_ROM_FN(Othunderjsc)463 STD_ROM_FN(Othunderjsc)
464
465 static INT32 MemIndex()
466 {
467 UINT8 *Next; Next = TaitoMem;
468
469 Taito68KRom1 = Next; Next += Taito68KRom1Size;
470 TaitoZ80Rom1 = Next; Next += TaitoZ80Rom1Size;
471 TaitoSpriteMapRom = Next; Next += TaitoSpriteMapRomSize;
472 TaitoYM2610ARom = Next; Next += TaitoYM2610ARomSize;
473 TaitoYM2610BRom = Next; Next += TaitoYM2610BRomSize;
474 TaitoDefaultEEProm = Next; Next += TaitoDefaultEEPromSize;
475
476 TaitoRamStart = Next;
477
478 Taito68KRam1 = Next; Next += 0x10000;
479 TaitoZ80Ram1 = Next; Next += 0x02000;
480 TaitoSpriteRam = Next; Next += 0x00600;
481 OthunderPan = Next; Next += 0x00004;
482
483 TaitoRamEnd = Next;
484
485 TaitoChars = Next; Next += TaitoNumChar * TaitoCharWidth * TaitoCharHeight;
486 TaitoSpritesA = Next; Next += TaitoNumSpriteA * TaitoSpriteAWidth * TaitoSpriteAHeight;
487 TaitoPalette = (UINT32*)Next; Next += 0x01000 * sizeof(UINT32);
488
489 TaitoMemEnd = Next;
490
491 return 0;
492 }
493
OthunderDoReset()494 static INT32 OthunderDoReset()
495 {
496 TaitoDoReset();
497
498 return 0;
499 }
500
OthunderInputBypassRead(INT32 Offset)501 static UINT8 OthunderInputBypassRead(INT32 Offset)
502 {
503 switch (Offset) {
504 case 0x03: {
505 return (EEPROMRead() & 1) << 7;
506 }
507
508 default: {
509 return TC0220IOCRead(Offset);
510 }
511 }
512
513 return 0;
514 }
515
OthunderInputBypassWrite(INT32 Offset,UINT16 Data)516 static void OthunderInputBypassWrite(INT32 Offset, UINT16 Data)
517 {
518 switch (Offset) {
519 case 0x03: {
520 EEPROMWrite(Data & 0x20, Data & 0x10, Data & 0x40);
521 return;
522 }
523
524 default: {
525 TC0220IOCWrite(Offset, Data & 0xff);
526 }
527 }
528 }
529
Othunder68KReadByte(UINT32 a)530 UINT8 __fastcall Othunder68KReadByte(UINT32 a)
531 {
532 switch (a) {
533 case 0x500001: {
534 return ~BurnGunReturnX(0);
535 }
536
537 case 0x500003: {
538 return BurnGunReturnY(0);
539 }
540
541 case 0x500005: {
542 return ~BurnGunReturnX(1);
543 }
544
545 case 0x500007: {
546 return BurnGunReturnY(1);
547 }
548
549 default: {
550 bprintf(PRINT_NORMAL, _T("68K #1 Read byte => %06X\n"), a);
551 }
552 }
553
554 return 0;
555 }
556
Othunder68KWriteByte(UINT32 a,UINT8 d)557 void __fastcall Othunder68KWriteByte(UINT32 a, UINT8 d)
558 {
559 TC0100SCN0ByteWrite_Map(0x200000, 0x20ffff)
560
561 switch (a) {
562 case 0x500001:
563 case 0x500003:
564 case 0x500005:
565 case 0x500007: {
566 nTaitoCyclesDone[0] += SekRun(10);
567 SekSetIRQLine(6, CPU_IRQSTATUS_AUTO);
568 return;
569 }
570
571 default: {
572 bprintf(PRINT_NORMAL, _T("68K #1 Write byte => %06X, %02X\n"), a, d);
573 }
574 }
575 }
576
Othunder68KReadWord(UINT32 a)577 UINT16 __fastcall Othunder68KReadWord(UINT32 a)
578 {
579 switch (a) {
580 case 0x090000:
581 case 0x090002:
582 case 0x090004:
583 case 0x090006:
584 case 0x090008:
585 case 0x09000a:
586 case 0x09000c:
587 case 0x09000e: {
588 return OthunderInputBypassRead((a - 0x090000) >> 1);
589 }
590
591 case 0x100002: {
592 return TC0110PCRWordRead(0);
593 }
594
595 default: {
596 bprintf(PRINT_NORMAL, _T("68K #1 Read word => %06X\n"), a);
597 }
598 }
599
600 return 0;
601 }
602
Othunder68KWriteWord(UINT32 a,UINT16 d)603 void __fastcall Othunder68KWriteWord(UINT32 a, UINT16 d)
604 {
605 TC0100SCN0WordWrite_Map(0x200000, 0x20ffff)
606 TC0100SCN0CtrlWordWrite_Map(0x220000)
607
608 switch (a) {
609 case 0x090000:
610 case 0x090002:
611 case 0x090004:
612 case 0x090006:
613 case 0x090008:
614 case 0x09000a:
615 case 0x09000c:
616 case 0x09000e: {
617 OthunderInputBypassWrite((a - 0x090000) >> 1, d);
618 return;
619 }
620
621 case 0x100000:
622 case 0x100002:
623 case 0x100004: {
624 TC0110PCRStep1RBSwapWordWrite(0, (a - 0x100000) >> 1, d);
625 return;
626 }
627
628 case 0x300000: {
629 TC0140SYTPortWrite(d & 0xff);
630 return;
631 }
632
633 case 0x300002: {
634 TC0140SYTCommWrite(d & 0xff);
635 return;
636 }
637
638 case 0x500000:
639 case 0x500002:
640 case 0x500004:
641 case 0x500006: {
642 nTaitoCyclesDone[0] += SekRun(10);
643 SekSetIRQLine(6, CPU_IRQSTATUS_AUTO);
644 return;
645 }
646
647 case 0x600000:
648 case 0x600002: {
649 // irq ack
650 return;
651 }
652
653 default: {
654 bprintf(PRINT_NORMAL, _T("68K #1 Write word => %06X, %04X\n"), a, d);
655 }
656 }
657 }
658
OthunderZ80Read(UINT16 a)659 UINT8 __fastcall OthunderZ80Read(UINT16 a)
660 {
661 switch (a) {
662 case 0xe000: {
663 return BurnYM2610Read(0);
664 }
665
666 case 0xe002: {
667 return BurnYM2610Read(2);
668 }
669
670 case 0xe201: {
671 return TC0140SYTSlaveCommRead();
672 }
673
674 case 0xea00: {
675 return TaitoDip[0];
676 }
677
678 default: {
679 bprintf(PRINT_NORMAL, _T("Z80 Read => %04X\n"), a);
680 }
681 }
682
683 return 0;
684 }
685
OthunderZ80Write(UINT16 a,UINT8 d)686 void __fastcall OthunderZ80Write(UINT16 a, UINT8 d)
687 {
688 switch (a) {
689 case 0xe000: {
690 BurnYM2610Write(0, d);
691 return;
692 }
693
694 case 0xe001: {
695 BurnYM2610Write(1, d);
696 return;
697 }
698
699 case 0xe002: {
700 BurnYM2610Write(2, d);
701 return;
702 }
703
704 case 0xe003: {
705 BurnYM2610Write(3, d);
706 return;
707 }
708
709 case 0xe200: {
710 TC0140SYTSlavePortWrite(d);
711 return;
712 }
713
714 case 0xe201: {
715 TC0140SYTSlaveCommWrite(d);
716 return;
717 }
718
719 case 0xe400:
720 case 0xe401:
721 case 0xe402:
722 case 0xe403: {
723 INT32 lVol, rVol;
724
725 OthunderPan[a & 0x0003] = d & 0x1f;
726
727 rVol = (OthunderPan[0] + OthunderPan[2]) * 100 / (2 * 0x1f);
728 lVol = (OthunderPan[1] + OthunderPan[3]) * 100 / (2 * 0x1f);
729 BurnYM2610SetLeftVolume(BURN_SND_YM2610_AY8910_ROUTE, OthunderYM2610AY8910RouteMasterVol * lVol / 100.0);
730 BurnYM2610SetRightVolume(BURN_SND_YM2610_AY8910_ROUTE, OthunderYM2610AY8910RouteMasterVol * rVol / 100.0);
731
732 rVol = OthunderPan[0] * 100 / 0x1f;
733 lVol = OthunderPan[1] * 100 / 0x1f;
734 if (rVol == 0) rVol = 100; // Fixes player gunshot can only be heard through the left speaker.
735 BurnYM2610SetLeftVolume(BURN_SND_YM2610_YM2610_ROUTE_1, OthunderYM2610Route1MasterVol * lVol / 100.0);
736 BurnYM2610SetRightVolume(BURN_SND_YM2610_YM2610_ROUTE_1, OthunderYM2610Route1MasterVol * rVol / 100.0);
737
738 /* CH2 */
739 rVol = OthunderPan[2] * 100 / 0x1f;
740 lVol = OthunderPan[3] * 100 / 0x1f;
741 BurnYM2610SetLeftVolume(BURN_SND_YM2610_YM2610_ROUTE_2, OthunderYM2610Route2MasterVol * lVol / 100.0);
742 BurnYM2610SetRightVolume(BURN_SND_YM2610_YM2610_ROUTE_2, OthunderYM2610Route2MasterVol * rVol / 100.0);
743 return;
744 }
745
746 case 0xe600: {
747 // nop
748 return;
749 }
750
751 case 0xee00: {
752 // nop
753 return;
754 }
755
756 case 0xf000: {
757 // nop
758 return;
759 }
760
761 case 0xf200: {
762 TaitoZ80Bank = (d - 1) & 7;
763 ZetMapArea(0x4000, 0x7fff, 0, TaitoZ80Rom1 + 0x4000 + (TaitoZ80Bank * 0x4000));
764 ZetMapArea(0x4000, 0x7fff, 2, TaitoZ80Rom1 + 0x4000 + (TaitoZ80Bank * 0x4000));
765 return;
766 }
767
768 default: {
769 bprintf(PRINT_NORMAL, _T("Z80 Write => %04X, %02X\n"), a, d);
770 }
771 }
772 }
773
774 static const eeprom_interface othunder_eeprom_interface = {
775 6, /* address bits */
776 16, /* data bits */
777 "0110", /* read command */
778 "0101", /* write command */
779 "0111", /* erase command */
780 "0100000000", /* lock command */
781 "0100111111", /* unlock command */
782 0,
783 0
784 };
785
786 static const UINT8 othunder_default_eeprom[128] = {
787 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x41, 0x41, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xf0, 0xf0,
788 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x41, 0x41, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xf0, 0xf0,
789 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0xf0, 0x00,
790 0x00, 0x01, 0x42, 0x85, 0x00, 0x00, 0xf1, 0xe3, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0xf0, 0x00,
791 0x00, 0x01, 0x42, 0x85, 0x00, 0x00, 0xf1, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
792 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
793 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
794 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
795 };
796
OthunderFMIRQHandler(INT32,INT32 nStatus)797 static void OthunderFMIRQHandler(INT32, INT32 nStatus)
798 {
799 ZetSetIRQLine(0, (nStatus) ? CPU_IRQSTATUS_ACK : CPU_IRQSTATUS_NONE);
800 }
801
802 static INT32 CharPlaneOffsets[4] = { 0, 1, 2, 3 };
803 static INT32 CharXOffsets[8] = { 8, 12, 0, 4, 24, 28, 16, 20 };
804 static INT32 CharYOffsets[8] = { 0, 32, 64, 96, 128, 160, 192, 224 };
805 static INT32 SpritePlaneOffsets[4] = { 0, 8, 16, 24 };
806 static INT32 SpriteXOffsets[16] = { 32, 33, 34, 35, 36, 37, 38, 39, 0, 1, 2, 3, 4, 5, 6, 7 };
807 static INT32 SpriteYOffsets[8] = { 0, 64, 128, 192, 256, 320, 384, 448 };
808
809 #ifdef BUILD_A68K
SwitchToMusashi()810 static void SwitchToMusashi()
811 {
812 if (bBurnUseASMCPUEmulation) {
813 #if 1 && defined FBA_DEBUG
814 bprintf(PRINT_NORMAL, _T("Switching to Musashi 68000 core\n"));
815 #endif
816 bUseAsm68KCoreOldValue = bBurnUseASMCPUEmulation;
817 bBurnUseASMCPUEmulation = false;
818 }
819 }
820 #endif
821
OthunderInit()822 static INT32 OthunderInit()
823 {
824 INT32 nLen;
825
826 TaitoCharModulo = 0x100;
827 TaitoCharNumPlanes = 4;
828 TaitoCharWidth = 8;
829 TaitoCharHeight = 8;
830 TaitoCharPlaneOffsets = CharPlaneOffsets;
831 TaitoCharXOffsets = CharXOffsets;
832 TaitoCharYOffsets = CharYOffsets;
833 TaitoNumChar = 0x4000;
834
835 TaitoSpriteAModulo = 0x200;
836 TaitoSpriteANumPlanes = 4;
837 TaitoSpriteAWidth = 16;
838 TaitoSpriteAHeight = 8;
839 TaitoSpriteAPlaneOffsets = SpritePlaneOffsets;
840 TaitoSpriteAXOffsets = SpriteXOffsets;
841 TaitoSpriteAYOffsets = SpriteYOffsets;
842 TaitoNumSpriteA = 0x8000;
843
844 TaitoNum68Ks = 1;
845 TaitoNumZ80s = 1;
846 TaitoNumYM2610 = 1;
847 TaitoNumEEPROM = 1;
848
849 TaitoLoadRoms(0);
850
851 // Allocate and Blank all required memory
852 TaitoMem = NULL;
853 MemIndex();
854 nLen = TaitoMemEnd - (UINT8 *)0;
855 if ((TaitoMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
856 memset(TaitoMem, 0, nLen);
857 MemIndex();
858
859 GenericTilesInit();
860
861 TC0100SCNInit(0, TaitoNumChar, 4, 8, 1, NULL);
862 TC0110PCRInit(1, 0x1000);
863 TC0140SYTInit(0);
864 TC0220IOCInit();
865
866 if (TaitoLoadRoms(1)) return 1;
867
868 #ifdef BUILD_A68K
869 SwitchToMusashi();
870 #endif
871
872 // Setup the 68000 emulation
873 SekInit(0, 0x68000);
874 SekOpen(0);
875 SekMapMemory(Taito68KRom1 , 0x000000, 0x07ffff, MAP_ROM);
876 SekMapMemory(Taito68KRam1 , 0x080000, 0x08ffff, MAP_RAM);
877 SekMapMemory(TC0100SCNRam[0] , 0x200000, 0x20ffff, MAP_READ);
878 SekMapMemory(TaitoSpriteRam , 0x400000, 0x4005ff, MAP_RAM);
879 SekSetReadWordHandler(0, Othunder68KReadWord);
880 SekSetWriteWordHandler(0, Othunder68KWriteWord);
881 SekSetReadByteHandler(0, Othunder68KReadByte);
882 SekSetWriteByteHandler(0, Othunder68KWriteByte);
883 SekClose();
884
885 ZetInit(0);
886 ZetOpen(0);
887 ZetSetReadHandler(OthunderZ80Read);
888 ZetSetWriteHandler(OthunderZ80Write);
889 ZetMapArea(0x0000, 0x3fff, 0, TaitoZ80Rom1 );
890 ZetMapArea(0x0000, 0x3fff, 2, TaitoZ80Rom1 );
891 ZetMapArea(0x4000, 0x7fff, 0, TaitoZ80Rom1 + 0x4000 );
892 ZetMapArea(0x4000, 0x7fff, 2, TaitoZ80Rom1 + 0x4000 );
893 ZetMapArea(0xc000, 0xdfff, 0, TaitoZ80Ram1 );
894 ZetMapArea(0xc000, 0xdfff, 1, TaitoZ80Ram1 );
895 ZetMapArea(0xc000, 0xdfff, 2, TaitoZ80Ram1 );
896 ZetClose();
897
898 BurnYM2610Init(16000000 / 2, TaitoYM2610ARom, (INT32*)&TaitoYM2610ARomSize, TaitoYM2610BRom, (INT32*)&TaitoYM2610BRomSize, &OthunderFMIRQHandler, 0);
899 BurnTimerAttachZet(16000000 / 4);
900 OthunderYM2610AY8910RouteMasterVol = 0.25;
901 OthunderYM2610Route1MasterVol = 1.00;
902 OthunderYM2610Route2MasterVol = 1.00;
903 bYM2610UseSeperateVolumes = 1;
904
905 EEPROMInit(&othunder_eeprom_interface);
906 if (!EEPROMAvailable()) EEPROMFill(TaitoDefaultEEProm, 0, 128);
907
908 TaitoMakeInputsFunction = OthunderMakeInputs;
909 TaitoIrqLine = 5;
910 TaitoFrameInterleave = 100;
911 TaitoFlipScreenX = 1;
912
913 nTaitoCyclesTotal[0] = 13000000 / 60;
914 nTaitoCyclesTotal[1] = (16000000 / 4) / 60;
915
916 BurnGunInit(2, true);
917
918 // Reset the driver
919 OthunderDoReset();
920
921 return 0;
922 }
923
OthunderExit()924 static INT32 OthunderExit()
925 {
926 TaitoExit();
927
928 #ifdef BUILD_A68K
929 // Switch back CPU core if needed
930 if (bUseAsm68KCoreOldValue) {
931 #if 1 && defined FBA_DEBUG
932 bprintf(PRINT_NORMAL, _T("Switching back to A68K core\n"));
933 #endif
934 bUseAsm68KCoreOldValue = false;
935 bBurnUseASMCPUEmulation = true;
936 }
937 #endif
938
939 return 0;
940 }
941
RenderSpriteZoom(INT32 Code,INT32 sx,INT32 sy,INT32 Colour,INT32 xFlip,INT32 yFlip,INT32 xScale,INT32 yScale,UINT8 * pSource)942 static void RenderSpriteZoom(INT32 Code, INT32 sx, INT32 sy, INT32 Colour, INT32 xFlip, INT32 yFlip, INT32 xScale, INT32 yScale, UINT8* pSource)
943 {
944 // We can use sprite A for sizes, etc. as only Chase HQ uses sprite B and it has the same sizes and count
945
946 UINT8 *SourceBase = pSource + ((Code % TaitoNumSpriteA) * TaitoSpriteAWidth * TaitoSpriteAHeight);
947
948 INT32 SpriteScreenHeight = (yScale * TaitoSpriteAHeight + 0x8000) >> 16;
949 INT32 SpriteScreenWidth = (xScale * TaitoSpriteAWidth + 0x8000) >> 16;
950
951 Colour = 0x10 * (Colour % 0x100);
952
953 if (TaitoFlipScreenX) {
954 xFlip = !xFlip;
955 sx = 320 - sx - (xScale >> 12);
956 }
957
958 if (SpriteScreenWidth && SpriteScreenHeight) {
959 INT32 dx = (TaitoSpriteAWidth << 16) / SpriteScreenWidth;
960 INT32 dy = (TaitoSpriteAHeight << 16) / SpriteScreenHeight;
961
962 INT32 ex = sx + SpriteScreenWidth;
963 INT32 ey = sy + SpriteScreenHeight;
964
965 INT32 xIndexBase;
966 INT32 yIndex;
967
968 if (xFlip) {
969 xIndexBase = (SpriteScreenWidth - 1) * dx;
970 dx = -dx;
971 } else {
972 xIndexBase = 0;
973 }
974
975 if (yFlip) {
976 yIndex = (SpriteScreenHeight - 1) * dy;
977 dy = -dy;
978 } else {
979 yIndex = 0;
980 }
981
982 if (sx < 0) {
983 INT32 Pixels = 0 - sx;
984 sx += Pixels;
985 xIndexBase += Pixels * dx;
986 }
987
988 if (sy < 0) {
989 INT32 Pixels = 0 - sy;
990 sy += Pixels;
991 yIndex += Pixels * dy;
992 }
993
994 if (ex > nScreenWidth) {
995 INT32 Pixels = ex - nScreenWidth;
996 ex -= Pixels;
997 }
998
999 if (ey > nScreenHeight) {
1000 INT32 Pixels = ey - nScreenHeight;
1001 ey -= Pixels;
1002 }
1003
1004 if (ex > sx) {
1005 INT32 y;
1006
1007 for (y = sy; y < ey; y++) {
1008 UINT8 *Source = SourceBase + ((yIndex >> 16) * TaitoSpriteAWidth);
1009 UINT16* pPixel = pTransDraw + (y * nScreenWidth);
1010
1011 INT32 x, xIndex = xIndexBase;
1012 for (x = sx; x < ex; x++) {
1013 INT32 c = Source[xIndex >> 16];
1014 if (c != 0) {
1015 pPixel[x] = c | Colour;
1016 }
1017 xIndex += dx;
1018 }
1019
1020 yIndex += dy;
1021 }
1022 }
1023 }
1024 }
1025
OthunderRenderSprites(INT32 PriorityDraw)1026 static void OthunderRenderSprites(INT32 PriorityDraw)
1027 {
1028 UINT16 *SpriteMap = (UINT16*)TaitoSpriteMapRom;
1029 UINT16 *SpriteRam = (UINT16*)TaitoSpriteRam;
1030 INT32 Offset, Data, Tile, Colour, xFlip, yFlip;
1031 INT32 x, y, Priority, xCur, yCur;
1032 INT32 xZoom, yZoom, zx, zy;
1033 INT32 SpriteChunk, MapOffset, Code, j, k, px, py;
1034 INT32 BadChunks;
1035
1036 for (Offset = 0x300 - 4; Offset >= 0; Offset -= 4) {
1037 Data = BURN_ENDIAN_SWAP_INT16(SpriteRam[Offset + 1]);
1038 Priority = (Data & 0x8000) >> 15;
1039
1040 if (Priority != 0 && Priority != 1) bprintf(PRINT_NORMAL, _T("Unused Priority %x\n"), Priority);
1041 if (Priority != PriorityDraw) continue;
1042
1043 xFlip = (Data & 0x4000) >> 14;
1044 x = Data & 0x1ff;
1045
1046 Data = BURN_ENDIAN_SWAP_INT16(SpriteRam[Offset + 3]);
1047 yFlip = (Data & 0x8000) >> 15;
1048 Tile = Data & 0x1fff;
1049 if (!Tile) continue;
1050
1051 Data = BURN_ENDIAN_SWAP_INT16(SpriteRam[Offset + 0]);
1052 yZoom = (Data & 0xfe00) >> 9;
1053 y = Data & 0x1ff;
1054
1055 Data = BURN_ENDIAN_SWAP_INT16(SpriteRam[Offset + 2]);
1056 Colour = (Data & 0xff00) >> 8;
1057 xZoom = (Data & 0x7f);
1058
1059 MapOffset = Tile << 5;
1060
1061 xZoom += 1;
1062 yZoom += 1;
1063
1064 y += 3;
1065
1066 if (x > 0x140) x -= 0x200;
1067 if (y > 0x140) y -= 0x200;
1068
1069 BadChunks = 0;
1070
1071 for (SpriteChunk = 0; SpriteChunk < 32; SpriteChunk++) {
1072 k = SpriteChunk % 4;
1073 j = SpriteChunk / 4;
1074
1075 px = xFlip ? (3 - k) : k;
1076 py = yFlip ? (7 - j) : j;
1077
1078 Code = BURN_ENDIAN_SWAP_INT16(SpriteMap[MapOffset + px + (py << 2)]);
1079 Code &= (TaitoNumSpriteA - 1);
1080
1081 if (Code == 0xffff) {
1082 BadChunks += 1;
1083 continue;
1084 }
1085
1086 xCur = x + ((k * xZoom) / 4);
1087 yCur = y + ((j * yZoom) / 8);
1088
1089 zx = x + (((k + 1) * xZoom) / 4) - xCur;
1090 zy = y + (((j + 1) * yZoom) / 8) - yCur;
1091
1092 yCur -= 16;
1093
1094 RenderSpriteZoom(Code, xCur, yCur, Colour, xFlip, yFlip, zx << 12, zy << 13, TaitoSpritesA);
1095 }
1096
1097 }
1098 }
1099
OthunderDraw()1100 static INT32 OthunderDraw()
1101 {
1102 INT32 Disable = TC0100SCNCtrl[0][6] & 0xf7;
1103
1104 BurnTransferClear();
1105
1106 if (TC0100SCNBottomLayer(0)) {
1107 if (!(Disable & 0x02)) TC0100SCNRenderFgLayer(0, 1, TaitoChars);
1108 OthunderRenderSprites(1);
1109 if (!(Disable & 0x01)) TC0100SCNRenderBgLayer(0, 0, TaitoChars);
1110 } else {
1111 if (!(Disable & 0x01)) TC0100SCNRenderBgLayer(0, 1, TaitoChars);
1112 OthunderRenderSprites(1);
1113 if (!(Disable & 0x02)) TC0100SCNRenderFgLayer(0, 0, TaitoChars);
1114 }
1115
1116 OthunderRenderSprites(0);
1117
1118 if (!(Disable & 0x04)) TC0100SCNRenderCharLayer(0);
1119 BurnTransferCopy(TC0110PCRPalette);
1120
1121 for (INT32 i = 0; i < nBurnGunNumPlayers; i++) {
1122 BurnGunDrawTarget(i, BurnGunX[i] >> 8, BurnGunY[i] >> 8);
1123 }
1124
1125 return 0;
1126 }
1127
OthunderFrame()1128 static INT32 OthunderFrame()
1129 {
1130 INT32 nInterleave = TaitoFrameInterleave;
1131
1132 if (TaitoReset) OthunderDoReset();
1133
1134 TaitoMakeInputsFunction();
1135
1136 nTaitoCyclesDone[0] = nTaitoCyclesDone[1] = 0;
1137
1138 SekNewFrame();
1139 ZetNewFrame();
1140
1141 for (INT32 i = 0; i < nInterleave; i++) {
1142 INT32 nCurrentCPU, nNext;
1143
1144 // Run 68000 #1
1145 nCurrentCPU = 0;
1146 SekOpen(0);
1147 nNext = (i + 1) * nTaitoCyclesTotal[nCurrentCPU] / nInterleave;
1148 nTaitoCyclesSegment = nNext - nTaitoCyclesDone[nCurrentCPU];
1149 nTaitoCyclesDone[nCurrentCPU] += SekRun(nTaitoCyclesSegment);
1150 if (i == (TaitoFrameInterleave - 1)) SekSetIRQLine(TaitoIrqLine, CPU_IRQSTATUS_AUTO);
1151 SekClose();
1152
1153 ZetOpen(0);
1154 BurnTimerUpdate(i * (nTaitoCyclesTotal[1] / nInterleave));
1155 ZetClose();
1156 }
1157
1158 ZetOpen(0);
1159 BurnTimerEndFrame(nTaitoCyclesTotal[1]);
1160 if (pBurnSoundOut) {
1161 BurnYM2610Update(pBurnSoundOut, nBurnSoundLen);
1162 }
1163 ZetClose();
1164
1165 if (pBurnDraw) BurnDrvRedraw();
1166
1167 return 0;
1168 }
1169
OthunderScan(INT32 nAction,INT32 * pnMin)1170 static INT32 OthunderScan(INT32 nAction, INT32 *pnMin)
1171 {
1172 struct BurnArea ba;
1173
1174 if (pnMin != NULL) { // Return minimum compatible version
1175 *pnMin = 0x029709;
1176 }
1177
1178 if (nAction & ACB_MEMORY_RAM) {
1179 memset(&ba, 0, sizeof(ba));
1180 ba.Data = TaitoRamStart;
1181 ba.nLen = TaitoRamEnd-TaitoRamStart;
1182 ba.szName = "All Ram";
1183 BurnAcb(&ba);
1184 }
1185
1186 TaitoICScan(nAction);
1187
1188 if (nAction & ACB_DRIVER_DATA) {
1189 SekScan(nAction);
1190 ZetScan(nAction);
1191
1192 BurnYM2610Scan(nAction, pnMin);
1193
1194 BurnGunScan();
1195
1196 SCAN_VAR(TaitoInput);
1197 SCAN_VAR(TaitoZ80Bank);
1198 SCAN_VAR(nTaitoCyclesDone);
1199 SCAN_VAR(nTaitoCyclesSegment);
1200 }
1201
1202 if (nAction & ACB_WRITE) {
1203 if (TaitoZ80Bank) {
1204 ZetOpen(0);
1205 ZetMapArea(0x4000, 0x7fff, 0, TaitoZ80Rom1 + 0x4000 + (TaitoZ80Bank * 0x4000));
1206 ZetMapArea(0x4000, 0x7fff, 2, TaitoZ80Rom1 + 0x4000 + (TaitoZ80Bank * 0x4000));
1207 ZetClose();
1208 }
1209 }
1210
1211 return 0;
1212 }
1213
1214 struct BurnDriver BurnDrvOthunder = {
1215 "othunder", NULL, NULL, NULL, "1988",
1216 "Operation Thunderbolt (World, rev 1)\0", NULL, "Taito Corporation Japan", "Taito Misc",
1217 NULL, NULL, NULL, NULL,
1218 BDF_GAME_WORKING, 2, HARDWARE_TAITO_MISC, GBF_SHOOT, 0,
1219 NULL, OthunderRomInfo, OthunderRomName, NULL, NULL, NULL, NULL, OthunderInputInfo, OthunderDIPInfo,
1220 OthunderInit, OthunderExit, OthunderFrame, OthunderDraw, OthunderScan,
1221 NULL, 0x1000, 320, 240, 4, 3
1222 };
1223
1224 struct BurnDriver BurnDrvOthundero = {
1225 "othundero", "othunder", NULL, NULL, "1988",
1226 "Operation Thunderbolt (World)\0", NULL, "Taito Corporation Japan", "Taito Misc",
1227 NULL, NULL, NULL, NULL,
1228 BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_TAITO_MISC, GBF_SHOOT, 0,
1229 NULL, OthunderoRomInfo, OthunderoRomName, NULL, NULL, NULL, NULL, OthunderInputInfo, OthunderuDIPInfo,
1230 OthunderInit, OthunderExit, OthunderFrame, OthunderDraw, OthunderScan,
1231 NULL, 0x1000, 320, 240, 4, 3
1232 };
1233
1234 struct BurnDriver BurnDrvOthunderu = {
1235 "othunderu", "othunder", NULL, NULL, "1988",
1236 "Operation Thunderbolt (US, rev 1)\0", NULL, "Taito America Corporation", "Taito Misc",
1237 NULL, NULL, NULL, NULL,
1238 BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_TAITO_MISC, GBF_SHOOT, 0,
1239 NULL, OthunderuRomInfo, OthunderuRomName, NULL, NULL, NULL, NULL, OthunderInputInfo, OthunderuDIPInfo,
1240 OthunderInit, OthunderExit, OthunderFrame, OthunderDraw, OthunderScan,
1241 NULL, 0x1000, 320, 240, 4, 3
1242 };
1243
1244 struct BurnDriver BurnDrvOthunderuo = {
1245 "othunderuo", "othunder", NULL, NULL, "1988",
1246 "Operation Thunderbolt (US)\0", NULL, "Taito America Corporation", "Taito Misc",
1247 NULL, NULL, NULL, NULL,
1248 BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_TAITO_MISC, GBF_SHOOT, 0,
1249 NULL, OthunderuoRomInfo, OthunderuoRomName, NULL, NULL, NULL, NULL, OthunderInputInfo, OthunderuDIPInfo,
1250 OthunderInit, OthunderExit, OthunderFrame, OthunderDraw, OthunderScan,
1251 NULL, 0x1000, 320, 240, 4, 3
1252 };
1253
1254 struct BurnDriver BurnDrvOthunderj = {
1255 "othunderj", "othunder", NULL, NULL, "1988",
1256 "Operation Thunderbolt (Japan)\0", NULL, "Taito Corporation", "Taito Misc",
1257 NULL, NULL, NULL, NULL,
1258 BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_TAITO_MISC, GBF_SHOOT, 0,
1259 NULL, OthunderjRomInfo, OthunderjRomName, NULL, NULL, NULL, NULL, OthunderInputInfo, OthunderjDIPInfo,
1260 OthunderInit, OthunderExit, OthunderFrame, OthunderDraw, OthunderScan,
1261 NULL, 0x1000, 320, 240, 4, 3
1262 };
1263
1264 struct BurnDriver BurnDrvOthunderjsc = {
1265 "othunderjsc", "othunder", NULL, NULL, "1988",
1266 "Operation Thunderbolt (Japan, SC)\0", NULL, "Taito Corporation", "Taito Misc",
1267 NULL, NULL, NULL, NULL,
1268 BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_TAITO_MISC, GBF_SHOOT, 0,
1269 NULL, OthunderjscRomInfo, OthunderjscRomName, NULL, NULL, NULL, NULL, OthunderInputInfo, OthunderjDIPInfo,
1270 OthunderInit, OthunderExit, OthunderFrame, OthunderDraw, OthunderScan,
1271 NULL, 0x1000, 320, 240, 4, 3
1272 };