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