1 // FB Alpha Atari Blasteroids driver module
2 // Based on MAME driver by Aaron Giles
3 
4 // this game is very picky regarding timing!
5 
6 #include "tiles_generic.h"
7 #include "m68000_intf.h"
8 #include "m6502_intf.h"
9 #include "watchdog.h"
10 #include "burn_pal.h"
11 #include "atariic.h"
12 #include "atarimo.h"
13 #include "atarijsa.h"
14 
15 static UINT8 *AllMem;
16 static UINT8 *MemEnd;
17 static UINT8 *AllRam;
18 static UINT8 *RamEnd;
19 static UINT8 *Drv68KROM;
20 static UINT8 *DrvM6502ROM;
21 static UINT8 *DrvGfxROM0;
22 static UINT8 *DrvGfxROM1;
23 static UINT8 *DrvPfRAM;
24 static UINT8 *DrvMobRAM;
25 static UINT8 *DrvPriRAM;
26 static UINT8 *Drv68KRAM;
27 
28 static UINT8 DrvRecalc;
29 
30 static INT32 scanline_int_state;
31 static INT32 video_int_state;
32 static INT32 cpu_halted;
33 
34 static INT32 vblank;
35 
36 static UINT8 DrvJoy1[16];
37 static UINT8 DrvJoy2[16];
38 static UINT8 DrvJoy3[16];
39 static UINT8 DrvJoy4f[8];
40 static UINT16 DrvInputs[3];
41 static UINT8 DrvDips[1];
42 static UINT8 DrvReset;
43 
44 static UINT8 TrackA;
45 static UINT8 TrackB;
46 
47 static UINT32 linecycles;
48 
49 static struct BurnInputInfo BlstroidInputList[] = {
50 	{"P1 Coin",			BIT_DIGITAL,	DrvJoy3 + 0,	"p1 coin"	},
51 
52 	{"P1 Left",			BIT_DIGITAL,	DrvJoy4f + 0,	"p1 left"	},
53 	{"P1 Right",		BIT_DIGITAL,	DrvJoy4f + 1,	"p1 right"	},
54 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 fire 1"	},
55 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 fire 2"	},
56 	{"P1 Button 3",		BIT_DIGITAL,	DrvJoy1 + 2,	"p1 fire 3"	},
57 	{"P1 Button 4",		BIT_DIGITAL,	DrvJoy1 + 3,	"p1 fire 4"	},
58 
59 	{"P2 Coin",			BIT_DIGITAL,	DrvJoy3 + 1,	"p2 coin"	},
60 	{"P2 Left",			BIT_DIGITAL,	DrvJoy4f + 2,	"p2 left"	},
61 	{"P2 Right",		BIT_DIGITAL,	DrvJoy4f + 3,	"p2 right"	},
62 	{"P2 Button 1",		BIT_DIGITAL,	DrvJoy2 + 0,	"p2 fire 1"	},
63 	{"P2 Button 2",		BIT_DIGITAL,	DrvJoy2 + 1,	"p2 fire 2"	},
64 	{"P2 Button 3",		BIT_DIGITAL,	DrvJoy2 + 2,	"p2 fire 3"	},
65 	{"P2 Button 4",		BIT_DIGITAL,	DrvJoy2 + 3,	"p2 fire 4"	},
66 
67 	{"P3 Coin",			BIT_DIGITAL,	DrvJoy3 + 2,	"p3 coin"	},
68 
69 	{"Reset",			BIT_DIGITAL,	&DrvReset,		"reset"		},
70 	{"Dip A",			BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
71 };
72 
73 STDINPUTINFO(Blstroid)
74 
75 static struct BurnDIPInfo BlstroidDIPList[]=
76 {
77 	{0x10, 0xff, 0xff, 0x80, NULL			},
78 
79 	{0   , 0xfe, 0   ,    2, "Service Mode"	},
80 	{0x10, 0x01, 0x80, 0x80, "Off"			},
81 	{0x10, 0x01, 0x80, 0x00, "On"			},
82 };
83 
STDDIPINFO(Blstroid)84 STDDIPINFO(Blstroid)
85 
86 static void update_interrupts()
87 {
88 	INT32 state = 0;
89 	if (scanline_int_state) state = 1;
90 	if (video_int_state) state = 2;
91 	if (atarijsa_int_state) state = 4;
92 
93 	if (state) {
94 		SekSetIRQLine(state, CPU_IRQSTATUS_ACK);
95 	} else {
96 		SekSetIRQLine(7, CPU_IRQSTATUS_NONE);
97 	}
98 }
99 
blstroid_main_write_word(UINT32 address,UINT16 data)100 static void __fastcall blstroid_main_write_word(UINT32 address, UINT16 data)
101 {
102 	if (address & 0x7f8000) {
103 		SekWriteWord(address & 0x807fff, data);
104 		return;
105 	}
106 
107 	if ((address & 0xfff000) == 0x805000) {
108 		*((UINT16*)(DrvMobRAM + (address & 0xffe))) = BURN_ENDIAN_SWAP_INT16(data);
109 		AtariMoWrite(0, (address / 2) & 0x7ff, data);
110 		return;
111 	}
112 
113 	if ((address & 0xfffe00) == 0x800800) {
114 		*((UINT16*)(DrvPriRAM + (address & 0x1fe))) = BURN_ENDIAN_SWAP_INT16(data);
115 		return;
116 	}
117 
118 	switch (address)
119 	{
120 		case 0x800000:
121 			BurnWatchdogWrite();
122 		return;
123 
124 		case 0x800200:
125 			scanline_int_state = 0;
126 			update_interrupts();
127 		return;
128 
129 		case 0x800400:
130 			video_int_state = 0;
131 			update_interrupts();
132 		return;
133 
134 		case 0x800600:
135 		case 0x800601:
136 			AtariEEPROMUnlockWrite();
137 		return;
138 
139 		case 0x800a00:
140 			AtariJSAWrite(data);
141 		return;
142 
143 		case 0x800c00:
144 			AtariJSAResetWrite(0);
145 		return;
146 
147 		case 0x800e00:
148 			cpu_halted = 1;
149 		return;
150 	}
151 
152 	bprintf (0, _T("MW: %5.5x, %4.4x\n"), address, data);
153 }
154 
blstroid_main_write_byte(UINT32 address,UINT8 data)155 static void __fastcall blstroid_main_write_byte(UINT32 address, UINT8 data)
156 {
157 	if (address & 0x7f8000) {
158 		SekWriteByte(address & 0x807fff, data);
159 		return;
160 	}
161 
162 	if ((address & 0xfff000) == 0x805000) {
163 		DrvMobRAM[(address & 0xfff)^1] = data;
164 		AtariMoWrite(0, (address / 2) & 0x7ff, BURN_ENDIAN_SWAP_INT16(*((UINT16*)(DrvMobRAM + (address & 0xffe)))));
165 		return;
166 	}
167 
168 	if ((address & 0xfffe00) == 0x800800) {
169 		DrvPriRAM[(address & 0x1ff)^1] = data;
170 		return;
171 	}
172 
173 	switch (address)
174 	{
175 		case 0x800000:
176 		case 0x800001:
177 			BurnWatchdogWrite();
178 		return;
179 
180 		case 0x800200:
181 		case 0x800201:
182 			scanline_int_state = 0;
183 			update_interrupts();
184 		return;
185 
186 		case 0x800400:
187 		case 0x800401:
188 			video_int_state = 0;
189 			update_interrupts();
190 		return;
191 
192 		case 0x800600:
193 		case 0x800601:
194 			AtariEEPROMUnlockWrite();
195 		return;
196 
197 		case 0x800a00:
198 		case 0x800a01:
199 			AtariJSAWrite(data);
200 		return;
201 
202 		case 0x800c00:
203 		case 0x800c01:
204 			AtariJSAResetWrite(0);
205 		return;
206 
207 		case 0x800e00:
208 		case 0x800e01:
209 			cpu_halted = 1;
210 		return;
211 	}
212 
213 	bprintf (0, _T("MB: %5.5x, %2.2x\n"), address, data);
214 }
215 
input_read(INT32 select)216 static inline UINT16 input_read(INT32 select)
217 {
218 	UINT16 ret = DrvInputs[select] & ~0x30;
219 
220 	if (SekTotalCycles() - linecycles > 410) ret ^= 0x10;
221 	if (vblank) ret ^= 0x20;
222 	if (atarigen_cpu_to_sound_ready) ret ^= 0x40;
223 
224 	return ret;
225 }
226 
blstroid_main_read_word(UINT32 address)227 static UINT16 __fastcall blstroid_main_read_word(UINT32 address)
228 {
229 	if (address & 0x7f8000) {
230 		return SekReadWord(address & 0x807fff);
231 	}
232 
233 	if ((address & ~0x0383ff) == 0x801c00) address &= ~0x0383fc; // unmask masked input derp
234 
235 	switch (address & 0x807fff)
236 	{
237 		case 0x801400:
238 			return AtariJSARead();
239 
240 		case 0x801800:
241 			return 0xff00 | TrackA;
242 
243 		case 0x801804:
244 			return 0xff00 | TrackB;
245 
246 		case 0x801c00:
247 		case 0x801c02:
248 			return input_read((address / 2) & 1);
249 	}
250 
251 	bprintf (0, _T("RW: %5.5x\n"), address);
252 
253 	return 0;
254 }
255 
blstroid_main_read_byte(UINT32 address)256 static UINT8 __fastcall blstroid_main_read_byte(UINT32 address)
257 {
258 	if (address & 0x7f8000) {
259 		return SekReadByte(address & 0x807fff);
260 	}
261 
262 	if ((address & ~0x0383ff) == 0x801c00) address &= ~0x0383fc; // unmask masked input derp
263 
264 	switch (address & 0x807fff)
265 	{
266 		case 0x801400:
267 		case 0x801401:
268 			return AtariJSARead() >> ((~address & 1) * 8);
269 
270 		case 0x801800:
271 		case 0x801801:
272 			return (0xff00 | TrackA) >> ((~address & 1) * 8);
273 
274 		case 0x801804:
275 		case 0x801805:
276 			return (0xff00 | TrackB) >> ((~address & 1) * 8);
277 
278 		case 0x801c00:
279 		case 0x801c01:
280 		case 0x801c02:
281 		case 0x801c03:
282 			return (input_read((address / 2) & 1) >> ((~address & 1) * 8)) & 0xff;
283 	}
284 
285 	bprintf (0, _T("RB: %5.5x\n"), address);
286 
287 	return 0;
288 }
289 
tilemap_callback(bg)290 static tilemap_callback( bg )
291 {
292 	UINT16 data = BURN_ENDIAN_SWAP_INT16(*((UINT16*)(DrvPfRAM + offs * 2)));
293 
294 	TILE_SET_INFO(0, data, data >> 13, 0);
295 }
296 
DrvDoReset(INT32 clear_mem)297 static INT32 DrvDoReset(INT32 clear_mem)
298 {
299 	if (clear_mem) {
300 		memset (AllRam, 0, RamEnd - AllRam);
301 	}
302 
303 	SekOpen(0);
304 	SekReset();
305 	SekClose();
306 
307 	BurnWatchdogReset();
308 
309 	AtariJSAReset();
310 	AtariEEPROMReset();
311 
312 	scanline_int_state = 0;
313 	video_int_state = 0;
314 	cpu_halted = 0;
315 	TrackA = 0;
316 	TrackB = 0;
317 
318 	return 0;
319 }
320 
MemIndex()321 static INT32 MemIndex()
322 {
323 	UINT8 *Next; Next = AllMem;
324 
325 	Drv68KROM			= Next; Next += 0x040000;
326 	DrvM6502ROM			= Next; Next += 0x010000;
327 
328 	DrvGfxROM0			= Next; Next += 0x100000;
329 	DrvGfxROM1			= Next; Next += 0x200000;
330 
331 	BurnPalette			= (UINT32*)Next; Next += 0x200 * sizeof(UINT32);
332 
333 	AllRam				= Next;
334 
335 	BurnPalRAM			= Next; Next += 0x000400;
336 	DrvPfRAM			= Next; Next += 0x001000;
337 	DrvMobRAM			= Next; Next += 0x001000;
338 	Drv68KRAM			= Next; Next += 0x002000;
339 
340 	DrvPriRAM			= Next; Next += 0x000200;
341 
342 	atarimo_0_slipram 	= NULL;
343 
344 	RamEnd				= Next;
345 
346 	MemEnd				= Next;
347 
348 	return 0;
349 }
350 
DrvGfxDecode()351 static INT32 DrvGfxDecode()
352 {
353 	INT32 Plane0[4] = { STEP4(0,1) };
354 	INT32 XOffs0[16] = { 0,0, 4,4, 8,8, 12,12, 16,16, 20,20, 24,24, 28,28 };
355 	INT32 YOffs0[8] = { STEP8(0,32) };
356 
357 	INT32 half = (0x100000/2) * 8;
358 	INT32 Plane1[4] = { STEP4(0,1) };
359 	INT32 XOffs1[16] = { half+0, half+4, 0, 4, half+8, half+12, 8, 12,
360 			half+16, half+20, 16, 20, half+24, half+28, 24, 28 };
361 	INT32 YOffs1[8] = { STEP8(0,32) };
362 
363 	UINT8 *tmp = (UINT8*)BurnMalloc(0x100000);
364 	if (tmp == NULL) {
365 		return 1;
366 	}
367 
368 	memcpy (tmp, DrvGfxROM0, 0x040000);
369 
370 	GfxDecode(0x2000, 4, 16, 8, Plane0, XOffs0, YOffs0, 0x100, tmp, DrvGfxROM0);
371 
372 	memcpy (tmp, DrvGfxROM1, 0x100000);
373 
374 	GfxDecode(0x4000, 4, 16, 8, Plane1, XOffs1, YOffs1, 0x100, tmp, DrvGfxROM1);
375 
376 	BurnFree(tmp);
377 
378 	return 0;
379 }
380 
DrvInit()381 static INT32 DrvInit()
382 {
383 	static const struct atarimo_desc modesc =
384 	{
385 		1,					/* index to which gfx system */
386 		1,					/* number of motion object banks */
387 		1,					/* are the entries linked? */
388 		0,					/* are the entries split? */
389 		0,					/* render in reverse order? */
390 		0,					/* render in swapped X/Y order? */
391 		0,					/* does the neighbor bit affect the next object? */
392 		0,					/* pixels per SLIP entry (0 for no-slip) */
393 		0,					/* pixel offset for SLIPs */
394 		0,					/* maximum number of links to visit/scanline (0=all) */
395 
396 		0x000,				/* base palette entry */
397 		0x100,				/* maximum number of colors */
398 		0,					/* transparent pen index */
399 
400 		{{ 0,0,0x0ff8,0 }},	/* mask for the link */
401 		{{ 0 }},			/* mask for the graphics bank */
402 		{{ 0,0x3fff,0,0 }},	/* mask for the code index */
403 		{{ 0 }},			/* mask for the upper code index */
404 		{{ 0,0,0,0x000f }},	/* mask for the color */
405 		{{ 0,0,0,0xffc0 }},	/* mask for the X position */
406 		{{ 0xff80,0,0,0 }},	/* mask for the Y position */
407 		{{ 0 }},			/* mask for the width, in tiles*/
408 		{{ 0x000f,0,0,0 }},	/* mask for the height, in tiles */
409 		{{ 0,0x8000,0,0 }},	/* mask for the horizontal flip */
410 		{{ 0,0x4000,0,0 }},	/* mask for the vertical flip */
411 		{{ 0 }},			/* mask for the priority */
412 		{{ 0 }},			/* mask for the neighbor */
413 		{{ 0 }},			/* mask for absolute coordinates */
414 
415 		{{ 0 }},			/* mask for the special value */
416 		0,					/* resulting value to indicate "special" */
417 		0					/* callback routine for special entries */
418 	};
419 
420 	AllMem = NULL;
421 	MemIndex();
422 	INT32 nLen = MemEnd - (UINT8 *)0;
423 	if ((AllMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
424 	memset(AllMem, 0, nLen);
425 	MemIndex();
426 
427 	{
428 		INT32 k = 0;
429 		if (BurnLoadRom(Drv68KROM  + 0x000001, k++, 2)) return 1;
430 		if (BurnLoadRom(Drv68KROM  + 0x000000, k++, 2)) return 1;
431 		if (BurnLoadRom(Drv68KROM  + 0x020001, k++, 2)) return 1;
432 		if (BurnLoadRom(Drv68KROM  + 0x020000, k++, 2)) return 1;
433 
434 		if (BurnLoadRom(DrvM6502ROM+ 0x000000, k++, 1)) return 1;
435 
436 		if (BurnLoadRom(DrvGfxROM0 + 0x000000, k++, 1)) return 1;
437 		if (BurnLoadRom(DrvGfxROM0 + 0x010000, k++, 1)) return 1;
438 		if (BurnLoadRom(DrvGfxROM0 + 0x020000, k++, 1)) return 1;
439 		if (BurnLoadRom(DrvGfxROM0 + 0x030000, k++, 1)) return 1;
440 
441 		if (BurnLoadRom(DrvGfxROM1 + 0x000000, k++, 1)) return 1;
442 		if (BurnLoadRom(DrvGfxROM1 + 0x010000, k++, 1)) return 1;
443 		if (BurnLoadRom(DrvGfxROM1 + 0x020000, k++, 1)) return 1;
444 		if (BurnLoadRom(DrvGfxROM1 + 0x030000, k++, 1)) return 1;
445 		if (BurnLoadRom(DrvGfxROM1 + 0x040000, k++, 1)) return 1;
446 		if (BurnLoadRom(DrvGfxROM1 + 0x050000, k++, 1)) return 1;
447 		if (BurnLoadRom(DrvGfxROM1 + 0x060000, k++, 1)) return 1;
448 		if (BurnLoadRom(DrvGfxROM1 + 0x070000, k++, 1)) return 1;
449 		if (BurnLoadRom(DrvGfxROM1 + 0x080000, k++, 1)) return 1;
450 		if (BurnLoadRom(DrvGfxROM1 + 0x090000, k++, 1)) return 1;
451 		if (BurnLoadRom(DrvGfxROM1 + 0x0a0000, k++, 1)) return 1;
452 		if (BurnLoadRom(DrvGfxROM1 + 0x0b0000, k++, 1)) return 1;
453 		if (BurnLoadRom(DrvGfxROM1 + 0x0c0000, k++, 1)) return 1;
454 		if (BurnLoadRom(DrvGfxROM1 + 0x0d0000, k++, 1)) return 1;
455 		if (BurnLoadRom(DrvGfxROM1 + 0x0e0000, k++, 1)) return 1;
456 		if (BurnLoadRom(DrvGfxROM1 + 0x0f0000, k++, 1)) return 1;
457 
458 		DrvGfxDecode();
459 	}
460 
461 	AtariEEPROMInit(0x400);
462 
463 	SekInit(0, 0x68000);
464 	SekOpen(0);
465 	SekMapMemory(Drv68KROM,			0x000000, 0x03ffff, MAP_ROM);
466 	for (INT32 i = 0; i < 0x1000; i+= 0x400) {
467 		SekMapMemory(BurnPalRAM,	0x802000 + i, 0x8023ff + i, MAP_RAM);
468 		AtariEEPROMInstallMap(1, 	0x803000 + i, 0x8033ff + i);
469 	}
470 	SekMapMemory(DrvPfRAM,			0x804000, 0x804fff, MAP_RAM);
471 	SekMapMemory(DrvMobRAM,			0x805000, 0x805fff, MAP_ROM);
472 	SekMapMemory(Drv68KRAM,			0x806000, 0x807fff, MAP_RAM);
473 	SekSetWriteWordHandler(0,		blstroid_main_write_word);
474 	SekSetWriteByteHandler(0,		blstroid_main_write_byte);
475 	SekSetReadWordHandler(0,		blstroid_main_read_word);
476 	SekSetReadByteHandler(0,		blstroid_main_read_byte);
477 	SekClose();
478 
479 	BurnWatchdogInit(DrvDoReset, 180);
480 
481 	AtariJSAInit(DrvM6502ROM, &update_interrupts, NULL, NULL);
482 
483 	GenericTilesInit();
484 	GenericTilemapInit(0, TILEMAP_SCAN_ROWS, bg_map_callback, 16, 8, 64, 64);
485 	GenericTilemapSetGfx(0, DrvGfxROM0, 4, 16, 8, 0x100000, 0x100, 0x07);
486 	GenericTilemapSetGfx(1, DrvGfxROM1, 4, 16, 8, 0x200000, 0x000, 0x0f);
487 
488 	AtariMoInit(0, &modesc);
489 
490 	DrvDoReset(1);
491 
492 	return 0;
493 }
494 
DrvExit()495 static INT32 DrvExit()
496 {
497 	GenericTilesExit();
498 	SekExit();
499 
500 	AtariJSAExit();
501 	AtariMoExit();
502 	AtariEEPROMExit();
503 
504 	BurnFree(AllMem);
505 
506 	return 0;
507 }
508 
copy_sprites()509 static void copy_sprites()
510 {
511 	INT32 minx, maxx, miny, maxy;
512 	GenericTilesGetClip(&minx, &maxx, &miny, &maxy);
513 
514 	UINT16 *pri = (UINT16*)DrvPriRAM;
515 
516 	for (INT32 y = miny; y < maxy; y++)
517 	{
518 		UINT16 *mo = BurnBitmapGetPosition(31, 0, y);
519 		UINT16 *pf = BurnBitmapGetPosition(0, 0, y);
520 
521 		for (INT32 x = minx; x < maxx; x++)
522 		{
523 			if (mo[x] != 0xffff)
524 			{
525 				INT32 priaddr = ((pf[x] & 8) << 4) | (pf[x] & 0x70) | ((mo[x] & 0xf0) >> 4);
526 				if (BURN_ENDIAN_SWAP_INT16(pri[priaddr]) & 1)
527 					pf[x] = mo[x];
528 				mo[x] = 0xffff; // clear
529 			}
530 		}
531 	}
532 }
533 
DrvDraw()534 static INT32 DrvDraw()
535 {
536 	if (DrvRecalc) {
537 		BurnPaletteUpdate_xRRRRRGGGGGBBBBB();;
538 		DrvRecalc = 1; // force!!
539 	}
540 
541 	AtariMoRender(0);
542 
543 	BurnTransferClear();
544 
545 	if (nBurnLayer & 1) GenericTilemapDraw(0, pTransDraw, 0);
546 
547 	if (nSpriteEnable & 1) copy_sprites();
548 
549 	BurnTransferCopy(BurnPalette);
550 
551 	return 0;
552 }
553 
DrvFrame()554 static INT32 DrvFrame()
555 {
556 	BurnWatchdogUpdate();
557 
558 	if (DrvReset) {
559 		DrvDoReset(1);
560 	}
561 
562 	SekNewFrame();
563 	M6502NewFrame();
564 
565 	{
566 		DrvInputs[0] = 0xff7f | (DrvDips[0] & 0x80);
567 		DrvInputs[1] = 0xffff;
568 		DrvInputs[2] = 0;
569 
570 		for (INT32 i = 0; i < 16; i++) {
571 			DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
572 			DrvInputs[1] ^= (DrvJoy2[i] & 1) << i;
573 			DrvInputs[2] ^= (DrvJoy3[i] & 1) << i;
574 		}
575 
576 		atarijsa_input_port = DrvInputs[2] & 0xff;
577 		atarijsa_test_mask = 0x80;
578 		atarijsa_test_port = DrvDips[0] & atarijsa_test_mask;
579 
580 		{
581 			if (DrvJoy4f[0]) TrackA -= 4;
582 			if (DrvJoy4f[1]) TrackA += 4;
583 
584 			if (DrvJoy4f[2]) TrackB -= 4;
585 			if (DrvJoy4f[3]) TrackB += 4;
586 		}
587 
588 	}
589 
590 	INT32 nSoundBufferPos = 0;
591 	INT32 nInterleave = 262;
592 	INT32 nCyclesTotal[2] = { (INT32)(7159090 / 59.92), (INT32)(1789773 / 59.92) };
593 	INT32 nCyclesDone[2] = { 0, 0 };
594 
595 	SekOpen(0);
596 	M6502Open(0);
597 
598 	vblank = 0;
599 	for (INT32 i = 0; i < nInterleave; i++)
600 	{
601 		linecycles = SekTotalCycles();
602 
603 		CPU_RUN(0, Sek);
604 		CPU_RUN(1, M6502);
605 
606 		if (i == 247) {
607 			vblank = 1;
608 
609 			video_int_state = 1;
610 			update_interrupts();
611 
612 			if (pBurnDraw) {
613 				BurnDrvRedraw();
614 			}
615 		}
616 
617 		AtariJSAInterruptUpdate(nInterleave);
618 
619 		if (pBurnSoundOut && i&1) {
620 			INT32 nSegment = nBurnSoundLen / (nInterleave / 2);
621 			AtariJSAUpdate(pBurnSoundOut + (nSoundBufferPos << 1), nSegment);
622 			nSoundBufferPos += nSegment;
623 		}
624 	}
625 
626 	if (pBurnSoundOut) {
627 		INT32 nSegment = nBurnSoundLen - nSoundBufferPos;
628 		if (nSegment > 0) {
629 			AtariJSAUpdate(pBurnSoundOut + (nSoundBufferPos << 1), nSegment);
630 		}
631 	}
632 
633 	SekClose();
634 	M6502Close();
635 
636 	return 0;
637 }
638 
DrvScan(INT32 nAction,INT32 * pnMin)639 static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
640 {
641 	struct BurnArea ba;
642 
643 	if (pnMin) {
644 		*pnMin = 0x029702;
645 	}
646 
647 	if (nAction & ACB_VOLATILE) {
648 		memset(&ba, 0, sizeof(ba));
649 
650 		ba.Data	  = AllRam;
651 		ba.nLen	  = RamEnd - AllRam;
652 		ba.szName = "All Ram";
653 		BurnAcb(&ba);
654 
655 		SekScan(nAction);
656 
657 		AtariJSAScan(nAction, pnMin);
658 		AtariMoScan(nAction, pnMin);
659 
660 		BurnWatchdogScan(nAction);
661 
662 		SCAN_VAR(video_int_state);
663 		SCAN_VAR(scanline_int_state);
664 		SCAN_VAR(cpu_halted);
665 
666 		SCAN_VAR(TrackA);
667 		SCAN_VAR(TrackB);
668 	}
669 
670 	AtariEEPROMScan(nAction, pnMin);
671 
672 	return 0;
673 }
674 
675 
676 // Blasteroids (rev 4)
677 
678 static struct BurnRomInfo blstroidRomDesc[] = {
679 	{ "136057-4123.6c",		0x10000, 0xd14badc4, 1 | BRF_PRG | BRF_ESS }, //  0 M68K Code
680 	{ "136057-4121.6b",		0x10000, 0xae3e93e8, 1 | BRF_PRG | BRF_ESS }, //  1
681 	{ "136057-4124.4c",		0x10000, 0xfd2365df, 1 | BRF_PRG | BRF_ESS }, //  2
682 	{ "136057-4122.4b",		0x10000, 0xc364706e, 1 | BRF_PRG | BRF_ESS }, //  3
683 
684 	{ "136057-1135.2k",		0x10000, 0xbaa8b5fe, 2 | BRF_PRG | BRF_ESS }, //  4 M6502 Code
685 
686 	{ "136057-1101.1l",		0x10000, 0x3c2daa5b, 3 | BRF_GRA },           //  5 Background Layer
687 	{ "136057-1102.1m",		0x10000, 0xf84f0b97, 3 | BRF_GRA },           //  6
688 	{ "136057-1103.3l",		0x10000, 0xae5274f0, 3 | BRF_GRA },           //  7
689 	{ "136057-1104.3m",		0x10000, 0x4bb72060, 3 | BRF_GRA },           //  8
690 
691 	{ "136057-1105.5m",		0x10000, 0x50e0823f, 4 | BRF_GRA },           //  9 Sprites
692 	{ "136057-1107.67m",	0x10000, 0x729de7a9, 4 | BRF_GRA },           // 10
693 	{ "136057-1109.8m",		0x10000, 0x090e42ab, 4 | BRF_GRA },           // 11
694 	{ "136057-1111.10m",	0x10000, 0x1ff79e67, 4 | BRF_GRA },           // 12
695 	{ "136057-1113.11m",	0x10000, 0x4be1d504, 4 | BRF_GRA },           // 13
696 	{ "136057-1115.13m",	0x10000, 0xe4409310, 4 | BRF_GRA },           // 14
697 	{ "136057-1117.14m",	0x10000, 0x7aaca15e, 4 | BRF_GRA },           // 15
698 	{ "136057-1119.16m",	0x10000, 0x33690379, 4 | BRF_GRA },           // 16
699 	{ "136057-1106.5n",		0x10000, 0x2720ee71, 4 | BRF_GRA },           // 17
700 	{ "136057-1108.67n",	0x10000, 0x2faecd15, 4 | BRF_GRA },           // 18
701 	{ "136057-1110.8n",		0x10000, 0xa15e79e1, 4 | BRF_GRA },           // 19
702 	{ "136057-1112.10n",	0x10000, 0x4d5fc284, 4 | BRF_GRA },           // 20
703 	{ "136057-1114.11n",	0x10000, 0xa70fc6e6, 4 | BRF_GRA },           // 21
704 	{ "136057-1116.13n",	0x10000, 0xf423b4f8, 4 | BRF_GRA },           // 22
705 	{ "136057-1118.14n",	0x10000, 0x56fa3d16, 4 | BRF_GRA },           // 23
706 	{ "136057-1120.16n",	0x10000, 0xf257f738, 4 | BRF_GRA },           // 24
707 };
708 
709 STD_ROM_PICK(blstroid)
710 STD_ROM_FN(blstroid)
711 
712 struct BurnDriver BurnDrvBlstroid = {
713 	"blstroid", NULL, NULL, NULL, "1987",
714 	"Blasteroids (rev 4)\0", NULL, "Atari Games", "Miscellaneous",
715 	NULL, NULL, NULL, NULL,
716 	BDF_GAME_WORKING, 2, HARDWARE_MISC_PRE90S, GBF_MISC, 0,
717 	NULL, blstroidRomInfo, blstroidRomName, NULL, NULL, NULL, NULL, BlstroidInputInfo, BlstroidDIPInfo,
718 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x200,
719 	640, 240, 4, 3
720 };
721 
722 
723 // Blasteroids (rev 3)
724 
725 static struct BurnRomInfo blstroid3RomDesc[] = {
726 	{ "136057-3123.6c",		0x10000, 0x8fb050f5, 1 | BRF_PRG | BRF_ESS }, //  0 M68K Code
727 	{ "136057-3121.6b",		0x10000, 0x21fae262, 1 | BRF_PRG | BRF_ESS }, //  1
728 	{ "136057-3124.4c",		0x10000, 0xa9140c31, 1 | BRF_PRG | BRF_ESS }, //  2
729 	{ "136057-3122.4b",		0x10000, 0x137fbb17, 1 | BRF_PRG | BRF_ESS }, //  3
730 
731 	{ "136057-1135.2k",		0x10000, 0xbaa8b5fe, 2 | BRF_PRG | BRF_ESS }, //  4 M6502 Code
732 
733 	{ "136057-1101.1l",		0x10000, 0x3c2daa5b, 3 | BRF_GRA },           //  5 Background Layer
734 	{ "136057-1102.1m",		0x10000, 0xf84f0b97, 3 | BRF_GRA },           //  6
735 	{ "136057-1103.3l",		0x10000, 0xae5274f0, 3 | BRF_GRA },           //  7
736 	{ "136057-1104.3m",		0x10000, 0x4bb72060, 3 | BRF_GRA },           //  8
737 
738 	{ "136057-1105.5m",		0x10000, 0x50e0823f, 4 | BRF_GRA },           //  9 Sprites
739 	{ "136057-1107.67m",	0x10000, 0x729de7a9, 4 | BRF_GRA },           // 10
740 	{ "136057-1109.8m",		0x10000, 0x090e42ab, 4 | BRF_GRA },           // 11
741 	{ "136057-1111.10m",	0x10000, 0x1ff79e67, 4 | BRF_GRA },           // 12
742 	{ "136057-1113.11m",	0x10000, 0x4be1d504, 4 | BRF_GRA },           // 13
743 	{ "136057-1115.13m",	0x10000, 0xe4409310, 4 | BRF_GRA },           // 14
744 	{ "136057-1117.14m",	0x10000, 0x7aaca15e, 4 | BRF_GRA },           // 15
745 	{ "136057-1119.16m",	0x10000, 0x33690379, 4 | BRF_GRA },           // 16
746 	{ "136057-1106.5n",		0x10000, 0x2720ee71, 4 | BRF_GRA },           // 17
747 	{ "136057-1108.67n",	0x10000, 0x2faecd15, 4 | BRF_GRA },           // 18
748 	{ "136057-1110.8n",		0x10000, 0xa15e79e1, 4 | BRF_GRA },           // 19
749 	{ "136057-1112.10n",	0x10000, 0x4d5fc284, 4 | BRF_GRA },           // 20
750 	{ "136057-1114.11n",	0x10000, 0xa70fc6e6, 4 | BRF_GRA },           // 21
751 	{ "136057-1116.13n",	0x10000, 0xf423b4f8, 4 | BRF_GRA },           // 22
752 	{ "136057-1118.14n",	0x10000, 0x56fa3d16, 4 | BRF_GRA },           // 23
753 	{ "136057-1120.16n",	0x10000, 0xf257f738, 4 | BRF_GRA },           // 24
754 };
755 
756 STD_ROM_PICK(blstroid3)
757 STD_ROM_FN(blstroid3)
758 
759 struct BurnDriver BurnDrvBlstroid3 = {
760 	"blstroid3", "blstroid", NULL, NULL, "1987",
761 	"Blasteroids (rev 3)\0", NULL, "Atari Games", "Miscellaneous",
762 	NULL, NULL, NULL, NULL,
763 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_MISC_PRE90S, GBF_MISC, 0,
764 	NULL, blstroid3RomInfo, blstroid3RomName, NULL, NULL, NULL, NULL, BlstroidInputInfo, BlstroidDIPInfo,
765 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x200,
766 	640, 240, 4, 3
767 };
768 
769 
770 // Blasteroids (rev 2)
771 
772 static struct BurnRomInfo blstroid2RomDesc[] = {
773 	{ "136057-2123.6c",		0x10000, 0x5a092513, 1 | BRF_PRG | BRF_ESS }, //  0 M68K Code
774 	{ "136057-2121.6b",		0x10000, 0x486aac51, 1 | BRF_PRG | BRF_ESS }, //  1
775 	{ "136057-2124.4c",		0x10000, 0xd0fa38fe, 1 | BRF_PRG | BRF_ESS }, //  2
776 	{ "136057-2122.4b",		0x10000, 0x744bf921, 1 | BRF_PRG | BRF_ESS }, //  3
777 
778 	{ "136057-1135.2k",		0x10000, 0xbaa8b5fe, 2 | BRF_PRG | BRF_ESS }, //  4 M6502 Code
779 
780 	{ "136057-1101.1l",		0x10000, 0x3c2daa5b, 3 | BRF_GRA },           //  5 Background Layer
781 	{ "136057-1102.1m",		0x10000, 0xf84f0b97, 3 | BRF_GRA },           //  6
782 	{ "136057-1103.3l",		0x10000, 0xae5274f0, 3 | BRF_GRA },           //  7
783 	{ "136057-1104.3m",		0x10000, 0x4bb72060, 3 | BRF_GRA },           //  8
784 
785 	{ "136057-1105.5m",		0x10000, 0x50e0823f, 4 | BRF_GRA },           //  9 Sprites
786 	{ "136057-1107.67m",	0x10000, 0x729de7a9, 4 | BRF_GRA },           // 10
787 	{ "136057-1109.8m",		0x10000, 0x090e42ab, 4 | BRF_GRA },           // 11
788 	{ "136057-1111.10m",	0x10000, 0x1ff79e67, 4 | BRF_GRA },           // 12
789 	{ "136057-1113.11m",	0x10000, 0x4be1d504, 4 | BRF_GRA },           // 13
790 	{ "136057-1115.13m",	0x10000, 0xe4409310, 4 | BRF_GRA },           // 14
791 	{ "136057-1117.14m",	0x10000, 0x7aaca15e, 4 | BRF_GRA },           // 15
792 	{ "136057-1119.16m",	0x10000, 0x33690379, 4 | BRF_GRA },           // 16
793 	{ "136057-1106.5n",		0x10000, 0x2720ee71, 4 | BRF_GRA },           // 17
794 	{ "136057-1108.67n",	0x10000, 0x2faecd15, 4 | BRF_GRA },           // 18
795 	{ "136057-1110.8n",		0x10000, 0xa15e79e1, 4 | BRF_GRA },           // 19
796 	{ "136057-1112.10n",	0x10000, 0x4d5fc284, 4 | BRF_GRA },           // 20
797 	{ "136057-1114.11n",	0x10000, 0xa70fc6e6, 4 | BRF_GRA },           // 21
798 	{ "136057-1116.13n",	0x10000, 0xf423b4f8, 4 | BRF_GRA },           // 22
799 	{ "136057-1118.14n",	0x10000, 0x56fa3d16, 4 | BRF_GRA },           // 23
800 	{ "136057-1120.16n",	0x10000, 0xf257f738, 4 | BRF_GRA },           // 24
801 };
802 
803 STD_ROM_PICK(blstroid2)
804 STD_ROM_FN(blstroid2)
805 
806 struct BurnDriver BurnDrvBlstroid2 = {
807 	"blstroid2", "blstroid", NULL, NULL, "1987",
808 	"Blasteroids (rev 2)\0", NULL, "Atari Games", "Miscellaneous",
809 	NULL, NULL, NULL, NULL,
810 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_MISC_PRE90S, GBF_MISC, 0,
811 	NULL, blstroid2RomInfo, blstroid2RomName, NULL, NULL, NULL, NULL, BlstroidInputInfo, BlstroidDIPInfo,
812 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x200,
813 	640, 240, 4, 3
814 };
815 
816 
817 // Blasteroids (German, rev 2)
818 
819 static struct BurnRomInfo blstroidgRomDesc[] = {
820 	{ "136057-2223.6c",		0x10000, 0xcc82108b, 1 | BRF_PRG | BRF_ESS }, //  0 M68K Code
821 	{ "136057-2221.6b",		0x10000, 0x84822e68, 1 | BRF_PRG | BRF_ESS }, //  1
822 	{ "136057-2224.4c",		0x10000, 0x849249d4, 1 | BRF_PRG | BRF_ESS }, //  2
823 	{ "136057-2222.4b",		0x10000, 0xbdeaba0d, 1 | BRF_PRG | BRF_ESS }, //  3
824 
825 	{ "136057-1135.2k",		0x10000, 0xbaa8b5fe, 2 | BRF_PRG | BRF_ESS }, //  4 M6502 Code
826 
827 	{ "136057-1101.1l",		0x10000, 0x3c2daa5b, 3 | BRF_GRA },           //  5 Background Layer
828 	{ "136057-1102.1m",		0x10000, 0xf84f0b97, 3 | BRF_GRA },           //  6
829 	{ "136057-1103.3l",		0x10000, 0xae5274f0, 3 | BRF_GRA },           //  7
830 	{ "136057-1104.3m",		0x10000, 0x4bb72060, 3 | BRF_GRA },           //  8
831 
832 	{ "136057-1105.5m",		0x10000, 0x50e0823f, 4 | BRF_GRA },           //  9 Sprites
833 	{ "136057-1107.67m",	0x10000, 0x729de7a9, 4 | BRF_GRA },           // 10
834 	{ "136057-1109.8m",		0x10000, 0x090e42ab, 4 | BRF_GRA },           // 11
835 	{ "136057-1111.10m",	0x10000, 0x1ff79e67, 4 | BRF_GRA },           // 12
836 	{ "136057-1113.11m",	0x10000, 0x4be1d504, 4 | BRF_GRA },           // 13
837 	{ "136057-1115.13m",	0x10000, 0xe4409310, 4 | BRF_GRA },           // 14
838 	{ "136057-1117.14m",	0x10000, 0x7aaca15e, 4 | BRF_GRA },           // 15
839 	{ "136057-1119.16m",	0x10000, 0x33690379, 4 | BRF_GRA },           // 16
840 	{ "136057-1106.5n",		0x10000, 0x2720ee71, 4 | BRF_GRA },           // 17
841 	{ "136057-1108.67n",	0x10000, 0x2faecd15, 4 | BRF_GRA },           // 18
842 	{ "136057-1110.8n",		0x10000, 0xa15e79e1, 4 | BRF_GRA },           // 19
843 	{ "136057-1112.10n",	0x10000, 0x4d5fc284, 4 | BRF_GRA },           // 20
844 	{ "136057-1114.11n",	0x10000, 0xa70fc6e6, 4 | BRF_GRA },           // 21
845 	{ "136057-1116.13n",	0x10000, 0xf423b4f8, 4 | BRF_GRA },           // 22
846 	{ "136057-1118.14n",	0x10000, 0x56fa3d16, 4 | BRF_GRA },           // 23
847 	{ "136057-1120.16n",	0x10000, 0xf257f738, 4 | BRF_GRA },           // 24
848 };
849 
850 STD_ROM_PICK(blstroidg)
851 STD_ROM_FN(blstroidg)
852 
853 struct BurnDriver BurnDrvBlstroidg = {
854 	"blstroidg", "blstroid", NULL, NULL, "1987",
855 	"Blasteroids (German, rev 2)\0", NULL, "Atari Games", "Miscellaneous",
856 	NULL, NULL, NULL, NULL,
857 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_MISC_PRE90S, GBF_MISC, 0,
858 	NULL, blstroidgRomInfo, blstroidgRomName, NULL, NULL, NULL, NULL, BlstroidInputInfo, BlstroidDIPInfo,
859 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x200,
860 	640, 240, 4, 3
861 };
862 
863 
864 // Blasteroids (with heads)
865 
866 static struct BurnRomInfo blstroidhRomDesc[] = {
867 	{ "eheadh0.c6",			0x10000, 0x061f0898, 1 | BRF_PRG | BRF_ESS }, //  0 M68K Code
868 	{ "eheadl0.b6",			0x10000, 0xae8df7cb, 1 | BRF_PRG | BRF_ESS }, //  1
869 	{ "eheadh1.c5",			0x10000, 0x0b7a3cb6, 1 | BRF_PRG | BRF_ESS }, //  2
870 	{ "eheadl1.b5",			0x10000, 0x43971694, 1 | BRF_PRG | BRF_ESS }, //  3
871 
872 	{ "136057-1135.2k",		0x10000, 0xbaa8b5fe, 2 | BRF_PRG | BRF_ESS }, //  4 M6502 Code
873 
874 	{ "136057-1101.1l",		0x10000, 0x3c2daa5b, 3 | BRF_GRA },           //  5 Background Layer
875 	{ "136057-1102.1m",		0x10000, 0xf84f0b97, 3 | BRF_GRA },           //  6
876 	{ "136057-1103.3l",		0x10000, 0xae5274f0, 3 | BRF_GRA },           //  7
877 	{ "136057-1104.3m",		0x10000, 0x4bb72060, 3 | BRF_GRA },           //  8
878 
879 	{ "136057-1105.5m",		0x10000, 0x50e0823f, 4 | BRF_GRA },           //  9 Sprites
880 	{ "136057-1107.67m",	0x10000, 0x729de7a9, 4 | BRF_GRA },           // 10
881 	{ "136057-1109.8m",		0x10000, 0x090e42ab, 4 | BRF_GRA },           // 11
882 	{ "136057-1111.10m",	0x10000, 0x1ff79e67, 4 | BRF_GRA },           // 12
883 	{ "mol4.m12",			0x10000, 0x571139ea, 4 | BRF_GRA },           // 13
884 	{ "136057-1115.13m",	0x10000, 0xe4409310, 4 | BRF_GRA },           // 14
885 	{ "136057-1117.14m",	0x10000, 0x7aaca15e, 4 | BRF_GRA },           // 15
886 	{ "mol7.m16",			0x10000, 0xd27b2d91, 4 | BRF_GRA },           // 16
887 	{ "136057-1106.5n",		0x10000, 0x2720ee71, 4 | BRF_GRA },           // 17
888 	{ "136057-1108.67n",	0x10000, 0x2faecd15, 4 | BRF_GRA },           // 18
889 	{ "moh2.n8",			0x10000, 0xa15e79e1, 4 | BRF_GRA },           // 19
890 	{ "136057-1112.10n",	0x10000, 0x4d5fc284, 4 | BRF_GRA },           // 20
891 	{ "moh4.n12",			0x10000, 0x1a74e960, 4 | BRF_GRA },           // 21
892 	{ "136057-1116.13n",	0x10000, 0xf423b4f8, 4 | BRF_GRA },           // 22
893 	{ "136057-1118.14n",	0x10000, 0x56fa3d16, 4 | BRF_GRA },           // 23
894 	{ "moh7.n16",			0x10000, 0xa93cbbe7, 4 | BRF_GRA },           // 24
895 };
896 
897 STD_ROM_PICK(blstroidh)
898 STD_ROM_FN(blstroidh)
899 
900 struct BurnDriver BurnDrvBlstroidh = {
901 	"blstroidh", "blstroid", NULL, NULL, "1987",
902 	"Blasteroids (with heads)\0", NULL, "Atari Games", "Miscellaneous",
903 	NULL, NULL, NULL, NULL,
904 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_MISC_PRE90S, GBF_MISC, 0,
905 	NULL, blstroidhRomInfo, blstroidhRomName, NULL, NULL, NULL, NULL, BlstroidInputInfo, BlstroidDIPInfo,
906 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x200,
907 	640, 240, 4, 3
908 };
909