1 // FB Alpha Cops'n Robbers driver module
2 // Based on MAME driver by Zsolt Vasvari
3 
4 // to do:
5 //	hook up analog inputs
6 //	make samples from MAME discrete sounds
7 
8 #include "tiles_generic.h"
9 #include "m6502_intf.h"
10 #include "samples.h"
11 
12 static UINT8 *AllMem;
13 static UINT8 *MemEnd;
14 static UINT8 *AllRam;
15 static UINT8 *RamEnd;
16 static UINT8 *DrvM6502ROM;
17 static UINT8 *DrvGfxROM0;
18 static UINT8 *DrvGfxROM1;
19 static UINT8 *DrvGfxROM2;
20 static UINT8 *DrvM6502RAM0;
21 static UINT8 *DrvM6502RAM1;
22 static UINT8 *DrvVidRAM;
23 static UINT8 *DrvTruckRAM;
24 static UINT8 *DrvBulletRAM;
25 static UINT8 *car_y;
26 static UINT8 *car_image;
27 
28 static UINT32 *DrvPalette;
29 static UINT8 DrvRecalc;
30 
31 static UINT8 truck_y;
32 
33 static INT32 vblank;
34 
35 static UINT8 DrvJoy1[8];
36 static UINT8 DrvJoy2[8];
37 static UINT8 DrvJoy3[8];
38 static UINT8 DrvJoy4[8];
39 static UINT8 DrvDips[1];
40 static UINT8 DrvInputs[3];
41 static UINT8 DrvReset;
42 
43 static struct BurnInputInfo CopsnrobInputList[] = {
44 	{"Coin 1",		BIT_DIGITAL,	DrvJoy1 + 7,	"p1 coin"	},
45 	{"CoiN 2",		BIT_DIGITAL,	DrvJoy2 + 7,	"p2 coin"	},
46 	{"Start 1",		BIT_DIGITAL,	DrvJoy1 + 6,	"p1 start"	},
47 	{"Start 2",		BIT_DIGITAL,	DrvJoy2 + 6,	"p2 start"	},
48 
49 	{"P1 Button 3",		BIT_DIGITAL,	DrvJoy4 + 4,	"p1 fire 3"	}, // PLACEHOLDER
50 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy3 + 7,	"p1 fire 1"	},
51 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy4 + 0,	"p1 fire 2"	},
52 
53 	{"P2 Button 3",		BIT_DIGITAL,	DrvJoy4 + 5,	"p2 fire 3"	}, // PLACEHOLDER
54 	{"P2 Button 1",		BIT_DIGITAL,	DrvJoy3 + 6,	"p2 fire 1"	},
55 	{"P2 Button 2",		BIT_DIGITAL,	DrvJoy4 + 1,	"p2 fire 2"	},
56 
57 	{"P3 Button 3",		BIT_DIGITAL,	DrvJoy4 + 6,	"p3 fire 3"	}, // PLACEHOLDER
58 	{"P3 Button 1",		BIT_DIGITAL,	DrvJoy3 + 5,	"p3 fire 1"	},
59 	{"P3 Button 2",		BIT_DIGITAL,	DrvJoy4 + 2,	"p3 fire 2"	},
60 
61 	{"P4 Button 3",		BIT_DIGITAL,	DrvJoy4 + 7,	"p4 fire 3"	}, // PLACEHOLDER
62 	{"P4 Button 1",		BIT_DIGITAL,	DrvJoy3 + 4,	"p4 fire 1"	},
63 	{"P4 Button 2",		BIT_DIGITAL,	DrvJoy4 + 3,	"p4 fire 2"	},
64 
65 	{"Reset",		BIT_DIGITAL,	&DrvReset,	"reset"		},
66 	{"Dip A",		BIT_DIPSWITCH,	DrvDips + 0,	"dip"		},
67 };
68 
69 STDINPUTINFO(Copsnrob)
70 
71 static struct BurnDIPInfo CopsnrobDIPList[]=
72 {
73 	{0x11, 0xff, 0xff, 0x03, NULL			},
74 
75 	{0   , 0xfe, 0   ,    4, "Coinage"		},
76 	{0x11, 0x01, 0x03, 0x03, "1 Coin/1 Player"	},
77 	{0x11, 0x01, 0x03, 0x02, "1 Coin/2 Players"	},
78 	{0x11, 0x01, 0x03, 0x01, "1 Coin/Game"		},
79 	{0x11, 0x01, 0x03, 0x00, "2 Coins/1 Player"	},
80 
81 	{0   , 0xfe, 0   ,    4, "Time Limit"		},
82 	{0x11, 0x01, 0x0c, 0x0c, "1min"			},
83 	{0x11, 0x01, 0x0c, 0x08, "1min 45sec"		},
84 	{0x11, 0x01, 0x0c, 0x04, "2min 20sec"		},
85 	{0x11, 0x01, 0x0c, 0x00, "3min"			},
86 };
87 
STDDIPINFO(Copsnrob)88 STDDIPINFO(Copsnrob)
89 
90 static UINT8 copsnrob_read(UINT16 address)
91 {
92 	UINT8 ret;
93 
94 	switch (address & 0x1fff)
95 	{
96 		case 0x1000:
97 			return vblank ? 0 : 0x80;
98 
99 		case 0x1002:
100 			ret = (DrvJoy4[0] ? 0x80 : 0);
101 		//	ret |= analog[0];
102 			return ret; // analog 1
103 
104 		case 0x1006:
105 			ret = (DrvJoy4[1] ? 0x80 : 0);
106 		//	ret |= analog[1];
107 			return ret; // analog 2
108 
109 		case 0x100a:
110 			ret = (DrvJoy4[2] ? 0x80 : 0);
111 		//	ret |= analog[2];
112 			return ret; // analog 3
113 
114 		case 0x100e:
115 			ret = (DrvJoy4[3] ? 0x80 : 0);
116 		//	ret |= analog[3];
117 			return ret; // analog 4
118 
119 		case 0x1012:
120 			return (DrvDips[0] & 0xf) | (DrvInputs[2] & 0xf0);
121 
122 		case 0x1016:
123 			return DrvInputs[0];
124 
125 		case 0x101a:
126 			return DrvInputs[1];
127 	}
128 
129 	return 0;
130 }
131 
copsnrob_write(UINT16 address,UINT8 data)132 static void copsnrob_write(UINT16 address, UINT8 data)
133 {
134 	switch (address & 0x1fff)
135 	{
136 		case 0x0500:
137 		case 0x0501:
138 		case 0x0502:
139 		case 0x0503:
140 		case 0x0504:
141 		case 0x0505:
142 		case 0x0506:
143 		case 0x0507:
144 			// misc_w (sound)
145 			// samples?
146 		return;
147 
148 		case 0x0600:
149 			truck_y = data;
150 		return;
151 
152 		case 0x0900:
153 		case 0x0901:
154 		case 0x0902:
155 		case 0x0903:
156 			car_image[address & 3] = data;
157 		return;
158 
159 		case 0x0a00:
160 		case 0x0a01:
161 		case 0x0a02:
162 		case 0x0a03:
163 			car_y[address & 3] = data;
164 		return;
165 
166 		case 0x1000:
167 			// led = ~data & 0x40
168 		return;
169 	}
170 }
171 
tilemap_callback(background)172 static tilemap_callback( background )
173 {
174 	TILE_SET_INFO(0, DrvVidRAM[offs] & 0x3f, 0, 0);
175 }
176 
tilemap_scan(flipx)177 static tilemap_scan( flipx )
178 {
179 	return (32 * row) + (31 - col);
180 }
181 
DrvDoReset()182 static INT32 DrvDoReset()
183 {
184 	memset (AllRam, 0, RamEnd - AllRam);
185 
186 	M6502Open(0);
187 	M6502Reset();
188 	M6502Close();
189 
190 //	samples?
191 
192 	truck_y = 0;
193 
194 	return 0;
195 }
196 
MemIndex()197 static INT32 MemIndex()
198 {
199 	UINT8 *Next; Next = AllMem;
200 
201 	DrvM6502ROM		= Next; Next += 0x000e00;
202 
203 	DrvGfxROM0		= Next; Next += 0x010000;
204 	DrvGfxROM1		= Next; Next += 0x010000;
205 	DrvGfxROM2		= Next; Next += 0x010000;
206 
207 	DrvPalette		= (UINT32*)Next; Next += 0x0002 * sizeof(UINT32);
208 
209 	AllRam			= Next;
210 
211 	DrvM6502RAM0		= Next; Next += 0x000200;
212 	DrvM6502RAM1		= Next; Next += 0x000100;
213 	DrvVidRAM		= Next; Next += 0x000400;
214 	DrvTruckRAM		= Next; Next += 0x000100;
215 	DrvBulletRAM		= Next; Next += 0x000100;
216 
217 	car_y			= Next; Next += 0x000004;
218 	car_image		= Next; Next += 0x000004;
219 
220 	RamEnd			= Next;
221 
222 	MemEnd			= Next;
223 
224 	return 0;
225 }
226 
DrvGfxDecode()227 static INT32 DrvGfxDecode()
228 {
229 	INT32 Plane[1]   = { 0 };
230 	INT32 XOffs0[8]  = { STEP8(0,1) };
231 	INT32 XOffs1[32] = { STEP8(7,-1), STEP8(15,-1), STEP8(23,-1), STEP8(31,-1) };
232 	INT32 XOffs2[16] = { STEP4(768+4,1), STEP4(512+4,1), STEP4(256+4,1), STEP4(0+4,1) };
233 	INT32 YOffs0[32] = { STEP32(0,8) };
234 	INT32 YOffs1[32] = { STEP32(0,32) };
235 //	INT32 YOffs2 = YOffs0;
236 
237 	UINT8 *tmp = (UINT8*)BurnMalloc(0x0800);
238 	if (tmp == NULL) {
239 		return 1;
240 	}
241 
242 	memcpy (tmp, DrvGfxROM0, 0x0200);
243 
244 	GfxDecode(0x0040, 1,  8,  8, Plane, XOffs0, YOffs0, 0x040, tmp, DrvGfxROM0);
245 
246 	memcpy (tmp, DrvGfxROM1, 0x0800);
247 
248 	GfxDecode(0x0010, 1, 32, 32, Plane, XOffs1, YOffs1, 0x400, tmp, DrvGfxROM1);
249 
250 	memcpy (tmp, DrvGfxROM2, 0x0100);
251 
252 	GfxDecode(0x0002, 1, 16, 32, Plane, XOffs2, YOffs0, 0x400, tmp, DrvGfxROM2);
253 
254 	BurnFree(tmp);
255 
256 	return 0;
257 }
258 
DrvInit()259 static INT32 DrvInit()
260 {
261 	AllMem = NULL;
262 	MemIndex();
263 	INT32 nLen = MemEnd - (UINT8 *)0;
264 	if ((AllMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
265 	memset(AllMem, 0, nLen);
266 	MemIndex();
267 
268 	{
269 		if (BurnLoadRom(DrvM6502ROM + 0x0000,  0, 1)) return 1;
270 		if (BurnLoadRom(DrvM6502ROM + 0x0200,  1, 1)) return 1;
271 		if (BurnLoadRom(DrvM6502ROM + 0x0400,  2, 1)) return 1;
272 		if (BurnLoadRom(DrvM6502ROM + 0x0600,  3, 1)) return 1;
273 		if (BurnLoadRom(DrvM6502ROM + 0x0800,  4, 1)) return 1;
274 		if (BurnLoadRom(DrvM6502ROM + 0x0a00,  5, 1)) return 1;
275 		if (BurnLoadRom(DrvM6502ROM + 0x0c00,  6, 1)) return 1;
276 
277 		if (BurnLoadRom(DrvGfxROM0  + 0x0000,  7, 1)) return 1;
278 
279 		if (BurnLoadRom(DrvGfxROM1  + 0x0000,  8, 1)) return 1;
280 		if (BurnLoadRom(DrvGfxROM1  + 0x0200,  9, 1)) return 1;
281 		if (BurnLoadRom(DrvGfxROM1  + 0x0400, 10, 1)) return 1;
282 		if (BurnLoadRom(DrvGfxROM1  + 0x0600, 11, 1)) return 1;
283 
284 		if (BurnLoadRom(DrvGfxROM2  + 0x0100, 12, 1)) return 1;
285 
286 		DrvGfxDecode();
287 	}
288 
289 	M6502Init(0, TYPE_M6502);
290 	M6502Open(0);
291 	for (INT32 i = 0; i < 0x10000; i+= 0x2000)
292 	{
293 		M6502MapMemory(DrvM6502RAM0,		0x0000 + i, 0x01ff + i, MAP_RAM);
294 		M6502MapMemory(DrvTruckRAM,		0x0700 + i, 0x07ff + i, MAP_WRITE); // no read
295 		M6502MapMemory(DrvBulletRAM,		0x0800 + i, 0x08ff + i, MAP_RAM);
296 		M6502MapMemory(DrvM6502RAM1,		0x0b00 + i, 0x0bff + i, MAP_RAM);
297 		M6502MapMemory(DrvVidRAM,		0x0c00 + i, 0x0fff + i, MAP_RAM);
298 		M6502MapMemory(DrvM6502ROM,		0x1200 + i, 0x1fff + i, MAP_ROM);
299 	}
300 	M6502SetWriteHandler(copsnrob_write);
301 	M6502SetReadHandler(copsnrob_read);
302 	M6502Close();
303 
304 	// samples?
305 
306 	GenericTilesInit();
307 	GenericTilemapInit(0, flipx_map_scan, background_map_callback, 8, 8, 32, 32);
308 	GenericTilemapSetGfx(0, DrvGfxROM0, 1, 8, 8, 0x1000, 0, 0);
309 
310 	DrvDoReset();
311 
312 	return 0;
313 }
314 
DrvExit()315 static INT32 DrvExit()
316 {
317 	GenericTilesExit();
318 
319 	M6502Exit();
320 
321 	// samples?
322 
323 	BurnFree(AllMem);
324 
325 	return 0;
326 }
327 
draw_cars()328 static void draw_cars()
329 {
330 
331 	INT32 pos[4] = { 0xe4, 0xc4, 0x24, 0x04 };
332 
333 	for (INT32 i = 0; i < 4; i++)
334 	{
335 		if (car_y[i] == 0) return;
336 
337 		Render32x32Tile_Mask_Clip(pTransDraw, car_image[i], pos[i], 256 - car_y[i], 0, 1, 0, 0, DrvGfxROM1);
338 	}
339 }
340 
draw_truck()341 static void draw_truck()
342 {
343 	for (INT32 y = 0; y < 256; y++)
344 	{
345 		if (DrvTruckRAM[255 - y] == 0) continue;
346 
347 		if ((truck_y & 0x1f) == ((y + 31) & 0x1f))
348 		{
349 			RenderCustomTile_Mask_Clip(pTransDraw, 16, 32, 0, 128, 256 - (y + 31), 0, 1, 0, 0, DrvGfxROM2);
350 
351 			y += 31;
352 		}
353 		else if ((truck_y & 0x1f) == (y & 0x1f))
354 		{
355 			RenderCustomTile_Mask_Clip(pTransDraw, 16, 32, 0, 128, 256 - y, 0, 1, 0, 0, DrvGfxROM2);
356 		}
357 	}
358 }
359 
draw_bullets()360 static void draw_bullets()
361 {
362 	for (INT32 x = 0; x < 256; x++)
363 	{
364 		UINT8 val = DrvBulletRAM[x];
365 		if ((val & 0x0f) == 0) continue;
366 
367 		for (INT32 bullet = 0; bullet < 4; bullet++)
368 		{
369 			if (val & (1 << bullet))
370 			{
371 				for (INT32 y = 0; y < nScreenHeight; y++)
372 				{
373 					if (DrvBulletRAM[y] & (0x10 << bullet))
374 					{
375 						pTransDraw[(y * nScreenWidth) + (256 - x)] = 1;
376 					}
377 				}
378 			}
379 		}
380 	}
381 }
382 
DrvDraw()383 static INT32 DrvDraw()
384 {
385 	if (DrvRecalc) {
386 		DrvPalette[0] = 0;
387 		DrvPalette[1] = BurnHighCol(0xff,0xff,0xff, 0);
388 		DrvRecalc = 0;
389 	}
390 
391 	GenericTilemapDraw(0, pTransDraw, 0);
392 
393 	draw_cars();
394 	draw_truck();
395 	draw_bullets();
396 
397 	BurnTransferCopy(DrvPalette);
398 
399 	return 0;
400 }
401 
DrvFrame()402 static INT32 DrvFrame()
403 {
404 	if (DrvReset) {
405 		DrvDoReset();
406 	}
407 
408 	{
409 		// static const ioport_value gun_table[] = {0x3f, 0x5f, 0x6f, 0x77, 0x7b, 0x7d, 0x7e};
410 
411 		memset (DrvInputs, 0xff, 3);
412 
413 		for (INT32 i = 0; i < 8; i++) {
414 			DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
415 			DrvInputs[1] ^= (DrvJoy2[i] & 1) << i;
416 			DrvInputs[2] ^= (DrvJoy3[i] & 1) << i;
417 		}
418 	}
419 
420 	INT32 nCyclesTotal = (894886 + (((nCurrentFrame & 3) == 3) ? 1 : 0)) / 60; // 894886.25
421 
422 	M6502Open(0);
423 	vblank = 0;
424 	M6502Run((nCyclesTotal * 208) / 256);
425 	vblank = 1;
426 	M6502Run((nCyclesTotal *  48) / 256);
427 	M6502Close();
428 
429 	if (pBurnSoundOut) {
430 //		samples?
431 	}
432 
433 	if (pBurnDraw) {
434 		DrvDraw();
435 	}
436 
437 	return 0;
438 }
439 
DrvScan(INT32 nAction,INT32 * pnMin)440 static INT32 DrvScan(INT32 nAction,INT32 *pnMin)
441 {
442 	struct BurnArea ba;
443 
444 	if (pnMin) {
445 		*pnMin = 0x029702;
446 	}
447 
448 	if (nAction & ACB_VOLATILE) {
449 		memset(&ba, 0, sizeof(ba));
450 
451 		ba.Data	  = AllRam;
452 		ba.nLen	  = RamEnd - AllRam;
453 		ba.szName = "All Ram";
454 		BurnAcb(&ba);
455 
456 		M6502Scan(nAction);
457 
458 		// samples?
459 
460 		SCAN_VAR(truck_y);
461 	}
462 
463 	return 0;
464 }
465 
466 
467 // Cops'n Robbers
468 
469 static struct BurnRomInfo copsnrobRomDesc[] = {
470 	{ "5777.l7",	0x0200, 0x2b62d627, 1 | BRF_PRG | BRF_ESS }, //  0 M6502 Code
471 	{ "5776.k7",	0x0200, 0x7fb12a49, 1 | BRF_PRG | BRF_ESS }, //  1
472 	{ "5775.j7",	0x0200, 0x627dee63, 1 | BRF_PRG | BRF_ESS }, //  2
473 	{ "5774.h7",	0x0200, 0xdfbcb7f2, 1 | BRF_PRG | BRF_ESS }, //  3
474 	{ "5773.e7",	0x0200, 0xff7c95f4, 1 | BRF_PRG | BRF_ESS }, //  4
475 	{ "5772.d7",	0x0200, 0x8d26afdc, 1 | BRF_PRG | BRF_ESS }, //  5
476 	{ "5771.b7",	0x0200, 0xd61758d6, 1 | BRF_PRG | BRF_ESS }, //  6
477 
478 	{ "5782.m3",	0x0200, 0x82b86852, 2 | BRF_GRA },           //  7 Characters
479 
480 	{ "5778.p1",	0x0200, 0x78bff86a, 3 | BRF_GRA },           //  8 Car tiles
481 	{ "5779.m1",	0x0200, 0x8b1d0d83, 3 | BRF_GRA },           //  9
482 	{ "5780.l1",	0x0200, 0x6f4c6bab, 3 | BRF_GRA },           // 10
483 	{ "5781.j1",	0x0200, 0xc87f2f13, 3 | BRF_GRA },           // 11
484 
485 	{ "5770.m2",	0x0100, 0xb00bbe77, 4 | BRF_GRA },           // 12 Truck tile
486 
487 	{ "5765.h8",	0x0020, 0x6cd58931, 0 | BRF_OPT },           // 13 Timing? proms
488 	{ "5766.k8",	0x0020, 0xe63edf4f, 0 | BRF_OPT },           // 14
489 	{ "5767.j8",	0x0020, 0x381b5ae4, 0 | BRF_OPT },           // 15
490 	{ "5768.n4",	0x0100, 0xcb7fc836, 0 | BRF_OPT },           // 16
491 	{ "5769.d5",	0x0100, 0x75081a5a, 0 | BRF_OPT },           // 17
492 };
493 
494 STD_ROM_PICK(copsnrob)
495 STD_ROM_FN(copsnrob)
496 
497 struct BurnDriverD BurnDrvCopsnrob = {
498 	"copsnrob", NULL, NULL, NULL, "1976",
499 	"Cops'n Robbers\0", "No sound", "Atari", "Miscellaneous",
500 	NULL, NULL, NULL, NULL,
501 	BDF_GAME_WORKING, 2, HARDWARE_MISC_PRE90S, GBF_SHOOT, 0,
502 	NULL, copsnrobRomInfo, copsnrobRomName, NULL, NULL, NULL, NULL, CopsnrobInputInfo, CopsnrobDIPInfo,
503 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 2,
504 	256, 208, 4, 3
505 };
506