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