1 // FB Alpha Bomby Car driver module
2 // Based on MAME driver by Luca Elia
3 
4 #include "tiles_generic.h"
5 #include "m68000_intf.h"
6 #include "msm6295.h"
7 
8 static UINT8 DrvInputPort0[8]     = {0, 0, 0, 0, 0, 0, 0, 0};
9 static UINT8 DrvInputPort1[8]     = {0, 0, 0, 0, 0, 0, 0, 0};
10 static UINT8 DrvDip[2]            = {0, 0};
11 static UINT8 DrvInput[2]          = {0x00, 0x00};
12 static UINT8 DrvReset             = 0;
13 
14 static UINT8 *Mem                 = NULL;
15 static UINT8 *MemEnd              = NULL;
16 static UINT8 *RamStart            = NULL;
17 static UINT8 *RamEnd              = NULL;
18 static UINT8 *Drv68KRom           = NULL;
19 static UINT8 *Drv68KRam           = NULL;
20 static UINT8 *DrvVRam0            = NULL;
21 static UINT8 *DrvVRam1            = NULL;
22 static UINT8 *DrvSpriteRam        = NULL;
23 static UINT8 *DrvPaletteRam       = NULL;
24 static UINT8 *DrvScroll0          = NULL;
25 static UINT8 *DrvScroll1          = NULL;
26 static UINT8 *DrvSprites          = NULL;
27 static UINT8 *DrvTempRom          = NULL;
28 static UINT32 *DrvPalette         = NULL;
29 
30 static UINT8 DrvEncrypted         = 0;
31 static UINT8 DrvIsWatrball        = 0;
32 static UINT8 BlmbyPotWheel        = 0;
33 static UINT32 DrvOkiBank          = 0;
34 static INT32 DrvToggle            = 0;
35 
36 static struct BurnInputInfo DrvInputList[] =
37 {
38 	{"Coin 1"            , BIT_DIGITAL  , DrvInputPort0 + 6, "p1 coin"   },
39 	{"Start 1"           , BIT_DIGITAL  , DrvInputPort1 + 6, "p1 start"  },
40 	{"Coin 2"            , BIT_DIGITAL  , DrvInputPort0 + 7, "p2 coin"   },
41 	{"Start 2"           , BIT_DIGITAL  , DrvInputPort1 + 7, "p2 start"  },
42 
43 	{"P1 Up"             , BIT_DIGITAL  , DrvInputPort0 + 0, "p1 up"     },
44 	{"P1 Down"           , BIT_DIGITAL  , DrvInputPort0 + 1, "p1 down"   },
45 	{"P1 Left"           , BIT_DIGITAL  , DrvInputPort0 + 3, "p1 left"   },
46 	{"P1 Right"          , BIT_DIGITAL  , DrvInputPort0 + 2, "p1 right"  },
47 	{"P1 Fire 1"         , BIT_DIGITAL  , DrvInputPort0 + 5, "p1 fire 1" },
48 	{"P1 Fire 2"         , BIT_DIGITAL  , DrvInputPort0 + 4, "p1 fire 2" },
49 
50 	{"P2 Up"             , BIT_DIGITAL  , DrvInputPort1 + 0, "p2 up"     },
51 	{"P2 Down"           , BIT_DIGITAL  , DrvInputPort1 + 1, "p2 down"   },
52 	{"P2 Left"           , BIT_DIGITAL  , DrvInputPort1 + 3, "p2 left"   },
53 	{"P2 Right"          , BIT_DIGITAL  , DrvInputPort1 + 2, "p2 right"  },
54 	{"P2 Fire 1"         , BIT_DIGITAL  , DrvInputPort1 + 5, "p2 fire 1" },
55 	{"P2 Fire 2"         , BIT_DIGITAL  , DrvInputPort1 + 4, "p2 fire 2" },
56 
57 	{"Reset"             , BIT_DIGITAL  , &DrvReset        , "reset"     },
58 	{"Dip 1"             , BIT_DIPSWITCH, DrvDip + 0       , "dip"       },
59 	{"Dip 2"             , BIT_DIPSWITCH, DrvDip + 1       , "dip"       },
60 };
61 
STDINPUTINFO(Drv)62 STDINPUTINFO(Drv)
63 
64 static inline void DrvMakeInputs()
65 {
66 	DrvInput[0] = DrvInput[1] = 0xff;
67 
68 	for (INT32 i = 0; i < 8; i++) {
69 		DrvInput[0] ^= (DrvInputPort0[i] & 1) << i;
70 		DrvInput[1] ^= (DrvInputPort1[i] & 1) << i;
71 	}
72 }
73 
74 static struct BurnDIPInfo DrvDIPList[]=
75 {
76 	// Default Values
77 	{0x11, 0xff, 0xff, 0xdf, NULL                     },
78 	{0x12, 0xff, 0xff, 0xff, NULL                     },
79 
80 	// Dip 1
81 	{0   , 0xfe, 0   , 4   , "Difficulty"             },
82 	{0x11, 0x01, 0x03, 0x02, "Easy"                   },
83 	{0x11, 0x01, 0x03, 0x03, "Normal"                 },
84 	{0x11, 0x01, 0x03, 0x01, "Hard"                   },
85 	{0x11, 0x01, 0x03, 0x00, "Hardest"                },
86 
87 	{0   , 0xfe, 0   , 2   , "Joysticks"              },
88 	{0x11, 0x01, 0x04, 0x00, "1"                      },
89 	{0x11, 0x01, 0x04, 0x04, "2"                      },
90 
91 	{0   , 0xfe, 0   , 1   , "Controls"               },
92 	{0x11, 0x01, 0x18, 0x18, "Joystick"               },
93 
94 	{0   , 0xfe, 0   , 2   , "Demo Sounds"            },
95 	{0x11, 0x01, 0x20, 0x20, "Off"                    },
96 	{0x11, 0x01, 0x20, 0x00, "On"                     },
97 
98 	{0   , 0xfe, 0   , 2   , "Service Mode"           },
99 	{0x11, 0x01, 0x80, 0x80, "Off"                    },
100 	{0x11, 0x01, 0x80, 0x00, "On"                     },
101 
102 	// Dip 2
103 	{0   , 0xfe, 0   , 8   , "Coin A"                 },
104 	{0x12, 0x01, 0x07, 0x07, "1 Coin  1 Credit"       },
105 	{0x12, 0x01, 0x07, 0x00, "3 Coins 4 Credits"      },
106 	{0x12, 0x01, 0x07, 0x01, "2 Coins 3 Credits"      },
107 	{0x12, 0x01, 0x07, 0x06, "1 Coin  2 Credits"      },
108 	{0x12, 0x01, 0x07, 0x05, "1 Coin  3 Credits"      },
109 	{0x12, 0x01, 0x07, 0x04, "1 Coin  4 Credits"      },
110 	{0x12, 0x01, 0x07, 0x03, "1 Coin  5 Credits"      },
111 	{0x12, 0x01, 0x07, 0x02, "1 Coin  6 Credits"      },
112 
113 	{0   , 0xfe, 0   , 8   , "Coin B"                 },
114 	{0x12, 0x01, 0x38, 0x10, "6 Coins 1 Credit"       },
115 	{0x12, 0x01, 0x38, 0x18, "5 Coins 1 Credit"       },
116 	{0x12, 0x01, 0x38, 0x20, "4 Coins 1 Credit"       },
117 	{0x12, 0x01, 0x38, 0x28, "3 Coins 1 Credit"       },
118 	{0x12, 0x01, 0x38, 0x30, "2 Coins 1 Credit"       },
119 	{0x12, 0x01, 0x38, 0x08, "3 Coins 2 Credits"      },
120 	{0x12, 0x01, 0x38, 0x00, "4 Coins 3 Credits"      },
121 	{0x12, 0x01, 0x38, 0x38, "1 Coin  1 Credit"       },
122 
123 	{0   , 0xfe, 0   , 2   , "Credits to Start"       },
124 	{0x12, 0x01, 0x40, 0x40, "1"                      },
125 	{0x12, 0x01, 0x40, 0x00, "2"                      },
126 
127 	{0   , 0xfe, 0   , 2   , "Free Play"              },
128 	{0x12, 0x01, 0x80, 0x80, "Off"                    },
129 	{0x12, 0x01, 0x80, 0x00, "On"                     },
130 };
131 
132 STDDIPINFO(Drv)
133 
134 static struct BurnDIPInfo WatrballDIPList[]=
135 {
136 	// Default Values
137 	{0x11, 0xff, 0xff, 0xdf, NULL                     },
138 	{0x12, 0xff, 0xff, 0xff, NULL                     },
139 
140 	// Dip 1
141 	{0   , 0xfe, 0   , 4   , "Difficulty"             },
142 	{0x11, 0x01, 0x03, 0x02, "Easy"                   },
143 	{0x11, 0x01, 0x03, 0x03, "Normal"                 },
144 	{0x11, 0x01, 0x03, 0x01, "Hard"                   },
145 	{0x11, 0x01, 0x03, 0x00, "Hardest"                },
146 
147 	{0   , 0xfe, 0   , 2   , "Demo Sounds"            },
148 	{0x11, 0x01, 0x20, 0x20, "Off"                    },
149 	{0x11, 0x01, 0x20, 0x00, "On"                     },
150 
151 	{0   , 0xfe, 0   , 2   , "Service Mode"           },
152 	{0x11, 0x01, 0x80, 0x80, "Off"                    },
153 	{0x11, 0x01, 0x80, 0x00, "On"                     },
154 
155 	// Dip 2
156 	{0   , 0xfe, 0   , 8   , "Coin A"                 },
157 	{0x12, 0x01, 0x07, 0x07, "1 Coin  1 Credit"       },
158 	{0x12, 0x01, 0x07, 0x00, "3 Coins 4 Credits"      },
159 	{0x12, 0x01, 0x07, 0x01, "2 Coins 3 Credits"      },
160 	{0x12, 0x01, 0x07, 0x06, "1 Coin  2 Credits"      },
161 	{0x12, 0x01, 0x07, 0x05, "1 Coin  3 Credits"      },
162 	{0x12, 0x01, 0x07, 0x04, "1 Coin  4 Credits"      },
163 	{0x12, 0x01, 0x07, 0x03, "1 Coin  5 Credits"      },
164 	{0x12, 0x01, 0x07, 0x02, "1 Coin  6 Credits"      },
165 
166 	{0   , 0xfe, 0   , 8   , "Coin B"                 },
167 	{0x12, 0x01, 0x38, 0x10, "6 Coins 1 Credit"       },
168 	{0x12, 0x01, 0x38, 0x18, "5 Coins 1 Credit"       },
169 	{0x12, 0x01, 0x38, 0x20, "4 Coins 1 Credit"       },
170 	{0x12, 0x01, 0x38, 0x28, "3 Coins 1 Credit"       },
171 	{0x12, 0x01, 0x38, 0x30, "2 Coins 1 Credit"       },
172 	{0x12, 0x01, 0x38, 0x08, "3 Coins 2 Credits"      },
173 	{0x12, 0x01, 0x38, 0x00, "4 Coins 3 Credits"      },
174 	{0x12, 0x01, 0x38, 0x38, "1 Coin  1 Credit"       },
175 };
176 
177 STDDIPINFO(Watrball)
178 
179 static struct BurnRomInfo DrvRomDesc[] = {
180 	{ "bcrom4.bin",    0x80000, 0x06d490ba, BRF_ESS | BRF_PRG }, //  0	68000 Program Code
181 	{ "bcrom6.bin",    0x80000, 0x33aca664, BRF_ESS | BRF_PRG }, //	 1
182 
183 	{ "bc_rom7",       0x80000, 0xe55ca79b, BRF_GRA },	     //  2	Sprites
184 	{ "bc_rom8",       0x80000, 0xcdf38c96, BRF_GRA },	     //  3
185 	{ "bc_rom9",       0x80000, 0x0337ab3d, BRF_GRA },	     //  4
186 	{ "bc_rom10",      0x80000, 0x5458917e, BRF_GRA },	     //  5
187 
188 	{ "bc_rom1",       0x80000, 0xac6f8ba1, BRF_SND },	     //  6	Samples
189 	{ "bc_rom2",       0x80000, 0xa4bc31bf, BRF_SND },	     //  7
190 };
191 
192 STD_ROM_PICK(Drv)
193 STD_ROM_FN(Drv)
194 
195 static struct BurnRomInfo DrvuRomDesc[] = {
196 	{ "bc_rom4",       0x80000, 0x76f054a2, BRF_ESS | BRF_PRG }, //  0	68000 Program Code
197 	{ "bc_rom6",       0x80000, 0x2570b4c5, BRF_ESS | BRF_PRG }, //	 1
198 
199 	{ "bc_rom7",       0x80000, 0xe55ca79b, BRF_GRA },	     //  2	Sprites
200 	{ "bc_rom8",       0x80000, 0xcdf38c96, BRF_GRA },	     //  3
201 	{ "bc_rom9",       0x80000, 0x0337ab3d, BRF_GRA },	     //  4
202 	{ "bc_rom10",      0x80000, 0x5458917e, BRF_GRA },	     //  5
203 
204 	{ "bc_rom1",       0x80000, 0xac6f8ba1, BRF_SND },	     //  6	Samples
205 	{ "bc_rom2",       0x80000, 0xa4bc31bf, BRF_SND },	     //  7
206 };
207 
208 STD_ROM_PICK(Drvu)
209 STD_ROM_FN(Drvu)
210 
211 static struct BurnRomInfo WatrballRomDesc[] = {
212 	{ "rom4.bin",      0x20000, 0xbfbfa720, BRF_ESS | BRF_PRG }, //  0	68000 Program Code
213 	{ "rom6.bin",      0x20000, 0xacff9b01, BRF_ESS | BRF_PRG }, //	 1
214 
215 	{ "rom7.bin",      0x80000, 0xe7e5c311, BRF_GRA },	     //  2	Sprites
216 	{ "rom8.bin",      0x80000, 0xfd27ce6e, BRF_GRA },	     //  3
217 	{ "rom9.bin",      0x80000, 0x122cc0ad, BRF_GRA },	     //  4
218 	{ "rom10.bin",     0x80000, 0x22a2a706, BRF_GRA },	     //  5
219 
220 	{ "rom1.bin",      0x80000, 0x7f88dee7, BRF_SND },	     //  6	Samples
221 };
222 
223 STD_ROM_PICK(Watrball)
STD_ROM_FN(Watrball)224 STD_ROM_FN(Watrball)
225 
226 static INT32 MemIndex()
227 {
228 	UINT8 *Next; Next = Mem;
229 
230 	Drv68KRom              = Next; Next += 0x100000;
231 	MSM6295ROM             = Next; Next += 0x100000;
232 
233 	RamStart               = Next;
234 
235 	Drv68KRam              = Next; Next += 0x006000;
236 	DrvVRam0               = Next; Next += 0x002000;
237 	DrvVRam1               = Next; Next += 0x002000;
238 	DrvSpriteRam           = Next; Next += 0x002000;
239 	DrvPaletteRam          = Next; Next += 0x004000;
240 	DrvScroll0             = Next; Next += 0x000004;
241 	DrvScroll1             = Next; Next += 0x000004;
242 
243 	RamEnd                 = Next;
244 
245 	DrvSprites             = Next; Next += 0x4000 * 16 * 16;
246 	DrvPalette             = (UINT32*)Next; Next += 0x04000 * sizeof(UINT32);
247 
248 	MemEnd                 = Next;
249 
250 	return 0;
251 }
252 
DrvDoOkiBank(UINT8 Bank)253 static void DrvDoOkiBank(UINT8 Bank)
254 {
255 	DrvOkiBank = Bank;
256 	MSM6295SetBank(0, MSM6295ROM + (0x10000 * DrvOkiBank), 0x30000, 0x3ffff);
257 }
258 
DrvDoReset()259 static INT32 DrvDoReset()
260 {
261 	SekOpen(0);
262 	SekReset();
263 	SekClose();
264 
265 	MSM6295Reset(0);
266 	DrvDoOkiBank(0);
267 
268 	BlmbyPotWheel = 0;
269 	DrvToggle = 0;
270 
271 	return 0;
272 }
273 
Blmbycar68KReadByte(UINT32 a)274 static UINT8 __fastcall Blmbycar68KReadByte(UINT32 a)
275 {
276 	switch (a) {
277 		case 0x700006: {
278 			return 0x00;
279 		}
280 
281 		case 0x700009: {
282 			DrvToggle ^= 0x08;
283 			if (DrvIsWatrball) {
284 				return DrvToggle & 0xff;
285 			}
286 			return ((BlmbyPotWheel & 0x80) ? 0x04 : 0x00) | (DrvToggle & 0x08);
287 		}
288 
289 		case 0x70000f: {
290 			return MSM6295Read(0);
291 		}
292 
293 		default: {
294 			bprintf(PRINT_NORMAL, _T("68K Read byte => %06X\n"), a);
295 		}
296 	}
297 
298 	return 0;
299 }
300 
Blmbycar68KWriteByte(UINT32 a,UINT8 d)301 static void __fastcall Blmbycar68KWriteByte(UINT32 a, UINT8 d)
302 {
303 	if (a >= 0x100000 && a <= 0x103fff) {
304 		// ???
305 		return;
306 	}
307 
308 	switch (a) {
309 		case 0x70000a: {
310 			// nop
311 			return;
312 		}
313 
314 		case 0x70000d: {
315 			DrvDoOkiBank(d & 0x0f);
316 			return;
317 		}
318 
319 		default: {
320 			bprintf(PRINT_NORMAL, _T("68K Write byte => %06X, %02X\n"), a, d);
321 		}
322 	}
323 }
324 
Blmbycar68KReadWord(UINT32 a)325 static UINT16 __fastcall Blmbycar68KReadWord(UINT32 a)
326 {
327 	switch (a) {
328 		case 0x700000: {
329 			return (DrvDip[1] << 8) | DrvDip[0];
330 		}
331 
332 		case 0x700002: {
333 			return (DrvInput[1] << 8) | DrvInput[0];
334 		}
335 
336 		default: {
337 			bprintf(PRINT_NORMAL, _T("68K Read word => %06X\n"), a);
338 		}
339 	}
340 
341 	return 0;
342 }
343 
Blmbycar68KWriteWord(UINT32 a,UINT16 d)344 static void __fastcall Blmbycar68KWriteWord(UINT32 a, UINT16 d)
345 {
346 	if (a >= 0x108000 && a <= 0x10bfff) {
347 		// ???
348 		return;
349 	}
350 
351 	switch (a) {
352 		case 0x000020:
353 		case 0x000022:
354 			return; // ?
355 
356 		case 0x10c000:
357 		case 0x10c002: {
358 			UINT16 *RAM = (UINT16*)DrvScroll1;
359 			RAM[(a - 0x10c000) >> 1] = BURN_ENDIAN_SWAP_INT16(d);
360 			return;
361 		}
362 
363 		case 0x10c004:
364 		case 0x10c006: {
365 			UINT16 *RAM = (UINT16*)DrvScroll0;
366 			RAM[(a - 0x10c004) >> 1] = BURN_ENDIAN_SWAP_INT16(d);
367 			return;
368 		}
369 
370 		case 0x70000e: {
371 			MSM6295Write(0, d & 0xff);
372 			return;
373 		}
374 
375 		default: {
376 			bprintf(PRINT_NORMAL, _T("68K Write word => %06X, %04X\n"), a, d);
377 		}
378 	}
379 }
380 
381 static INT32 SpritePlaneOffsets[4]   = { RGN_FRAC(0x200000,3,4),RGN_FRAC(0x200000,2,4),RGN_FRAC(0x200000,1,4),RGN_FRAC(0x200000,0,4) };
382 static INT32 SpriteXOffsets[16]      = { STEP8(0,1), STEP8(8*8*2,1) };
383 static INT32 SpriteYOffsets[16]      = { STEP8(0,8), STEP8(8*8*1,8) };
384 
DrvInit()385 static INT32 DrvInit()
386 {
387 	INT32 nRet = 0, nLen;
388 
389 	Mem = NULL;
390 	MemIndex();
391 	nLen = MemEnd - (UINT8 *)0;
392 	if ((Mem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
393 	memset(Mem, 0, nLen);
394 	MemIndex();
395 
396 	DrvTempRom = (UINT8 *)BurnMalloc(0x200000);
397 
398 	nRet = BurnLoadRom(Drv68KRom + 0x000001, 0, 2); if (nRet != 0) return 1;
399 	nRet = BurnLoadRom(Drv68KRom + 0x000000, 1, 2); if (nRet != 0) return 1;
400 
401 	nRet = BurnLoadRom(DrvTempRom + 0x000000, 2, 1); if (nRet != 0) return 1;
402 	nRet = BurnLoadRom(DrvTempRom + 0x080000, 3, 1); if (nRet != 0) return 1;
403 	nRet = BurnLoadRom(DrvTempRom + 0x100000, 4, 1); if (nRet != 0) return 1;
404 	nRet = BurnLoadRom(DrvTempRom + 0x180000, 5, 1); if (nRet != 0) return 1;
405 	GfxDecode(0x4000, 4, 16, 16, SpritePlaneOffsets, SpriteXOffsets, SpriteYOffsets, 0x100, DrvTempRom, DrvSprites);
406 
407 	nRet = BurnLoadRom(MSM6295ROM + 0x000000, 6, 1); if (nRet != 0) return 1;
408 	if (!DrvIsWatrball) { nRet = BurnLoadRom(MSM6295ROM + 0x080000, 7, 1); if (nRet != 0) return 1; }
409 
410 	BurnFree(DrvTempRom);
411 
412 	if (DrvEncrypted) {
413 		UINT16 *RAM = (UINT16*)Drv68KRom;
414 		for (INT32 i = 0; i < 0x80000; i++) {
415 			UINT16 x = BURN_ENDIAN_SWAP_INT16(RAM[i]);
416 			x = (x & ~0x0606) | ((x & 0x0202) << 1) | ((x & 0x0404) >> 1);
417 			RAM[i] = BURN_ENDIAN_SWAP_INT16(x);
418 		}
419 	}
420 
421 	SekInit(0, 0x68000);
422 	SekOpen(0);
423 	SekMapMemory(Drv68KRom           , 0x000000, 0x0fffff, MAP_ROM);
424 	SekMapMemory(DrvVRam1            , 0x104000, 0x105fff, MAP_RAM);
425 	SekMapMemory(DrvVRam0            , 0x106000, 0x107fff, MAP_RAM);
426 	SekMapMemory(DrvPaletteRam       , 0x200000, 0x203fff, MAP_RAM);
427 	SekMapMemory(DrvPaletteRam       , 0x204000, 0x207fff, MAP_RAM); // mirror
428 	SekMapMemory(Drv68KRam + 0x000000, 0x440000, 0x441fff, MAP_RAM);
429 	SekMapMemory(DrvSpriteRam        , 0x444000, 0x445fff, MAP_RAM);
430 	SekMapMemory(Drv68KRam + 0x002000, 0xfec000, 0xfeffff, MAP_RAM);
431 	SekSetReadWordHandler(0, Blmbycar68KReadWord);
432 	SekSetWriteWordHandler(0, Blmbycar68KWriteWord);
433 	SekSetReadByteHandler(0, Blmbycar68KReadByte);
434 	SekSetWriteByteHandler(0, Blmbycar68KWriteByte);
435 	SekClose();
436 
437 	MSM6295Init(0, 1056000 / 132, 0);
438 	MSM6295SetRoute(0, 1.00, BURN_SND_ROUTE_BOTH);
439 	MSM6295SetBank(0, MSM6295ROM, 0, 0x3ffff);
440 
441 	GenericTilesInit();
442 
443 	DrvDoReset();
444 
445 	return 0;
446 }
447 
BlmbycarInit()448 static INT32 BlmbycarInit()
449 {
450 	DrvEncrypted = 1;
451 
452 	return DrvInit();
453 }
454 
WatrballInit()455 static INT32 WatrballInit()
456 {
457 	DrvIsWatrball = 1;
458 
459 	return DrvInit();
460 }
461 
DrvExit()462 static INT32 DrvExit()
463 {
464 	SekExit();
465 
466 	MSM6295Exit(0);
467 
468 	GenericTilesExit();
469 
470 	BurnFree(Mem);
471 
472 	DrvEncrypted = 0;
473 	DrvIsWatrball = 0;
474 	BlmbyPotWheel = 0;
475 	DrvOkiBank = 0;
476 	DrvToggle = 0;
477 
478 	return 0;
479 }
480 
pal4bit(UINT8 bits)481 static inline UINT8 pal4bit(UINT8 bits)
482 {
483 	bits &= 0x0f;
484 	return (bits << 4) | bits;
485 }
486 
CalcCol(UINT16 nColour)487 inline static UINT32 CalcCol(UINT16 nColour)
488 {
489 	INT32 r, g, b;
490 
491 	r = pal4bit(nColour >> 4);
492 	g = pal4bit(nColour >> 0);
493 	b = pal4bit(nColour >> 8);
494 
495 	return BurnHighCol(r, g, b, 0);
496 }
497 
DrvCalcPalette()498 static void DrvCalcPalette()
499 {
500 	INT32 i;
501 	UINT16* ps;
502 	UINT32* pd;
503 
504 	for (i = 0, ps = (UINT16*)DrvPaletteRam, pd = DrvPalette; i < 0x2000; i++, ps++, pd++) {
505 		*pd = CalcCol(BURN_ENDIAN_SWAP_INT16(*ps));
506 	}
507 }
508 
DrvRenderBgLayer(INT32 RenderCategory)509 static void DrvRenderBgLayer(INT32 RenderCategory)
510 {
511 	INT32 mx, my, Attr, Code, Colour, x, y, TileIndex = 0, xFlip, yFlip, Category;
512 
513 	UINT16 *RAM = (UINT16*)DrvVRam0;
514 	UINT16 *ScrollRAM = (UINT16*)DrvScroll0;
515 
516 	for (my = 0; my < 32; my++) {
517 		for (mx = 0; mx < 64; mx++) {
518 			Code = BURN_ENDIAN_SWAP_INT16(RAM[(TileIndex << 1) + 0]);
519 			Attr = BURN_ENDIAN_SWAP_INT16(RAM[(TileIndex << 1) + 1]);
520 			Colour = Attr & 0x1f;
521 			xFlip = (Attr >> 6) & 0x01;
522 			yFlip = (Attr >> 6) & 0x02;
523 			Category = (Attr >> 5) & 0x01;
524 
525 			if (Category == RenderCategory) {
526 				x = 16 * mx;
527 				y = 16 * my;
528 
529 				x -= BURN_ENDIAN_SWAP_INT16(ScrollRAM[1]) & 0x3ff;
530 				y -= BURN_ENDIAN_SWAP_INT16(ScrollRAM[0]) & 0x1ff;
531 				if (x < -16) x += 1024;
532 				if (y < -16) y += 512;
533 
534 				if (DrvIsWatrball) y -= 16;
535 
536 				Draw16x16Tile(pTransDraw, Code, x, y, xFlip, yFlip, Colour, 4, 0, DrvSprites);
537 			}
538 
539 			TileIndex++;
540 		}
541 	}
542 }
543 
DrvRenderFgLayer(INT32 RenderCategory)544 static void DrvRenderFgLayer(INT32 RenderCategory)
545 {
546 	INT32 mx, my, Attr, Code, Colour, x, y, TileIndex = 0, xFlip, yFlip, Category;
547 
548 	UINT16 *RAM = (UINT16*)DrvVRam1;
549 	UINT16 *ScrollRAM = (UINT16*)DrvScroll1;
550 
551 	for (my = 0; my < 32; my++) {
552 		for (mx = 0; mx < 64; mx++) {
553 			Code = BURN_ENDIAN_SWAP_INT16(RAM[(TileIndex << 1) + 0]);
554 			Attr = BURN_ENDIAN_SWAP_INT16(RAM[(TileIndex << 1) + 1]);
555 			Colour = Attr & 0x1f;
556 			xFlip = (Attr >> 6) & 0x01;
557 			yFlip = (Attr >> 6) & 0x02;
558 			Category = (Attr >> 5) & 0x01;
559 
560 			if (Category == RenderCategory) {
561 				x = 16 * mx;
562 				y = 16 * my;
563 
564 				x -= (BURN_ENDIAN_SWAP_INT16(ScrollRAM[1]) + 5) & 0x3ff;
565 				y -= (BURN_ENDIAN_SWAP_INT16(ScrollRAM[0]) + 1) & 0x1ff;
566 				if (x < -16) x += 1024;
567 				if (y < -16) y += 512;
568 
569 				if (DrvIsWatrball) y -= 16;
570 
571 				Draw16x16MaskTile(pTransDraw, Code, x, y, xFlip, yFlip, Colour, 4, 0, 0, DrvSprites);
572 			}
573 
574 			TileIndex++;
575 		}
576 	}
577 }
578 
DrawSprites(INT32 priority)579 static void DrawSprites(INT32 priority)
580 {
581 	UINT16 *spriteram = (UINT16*)DrvSpriteRam;
582 
583 	for (INT32 i = 6/2; i < (0x1000 - 6)/2; i += 4)
584 	{
585 		INT32 sx = spriteram[i+3] & 0x01ff;
586 		INT32 sy = spriteram[i+0];
587 		sy   = 0xf0 - ((sy & 0xff)  - (sy & 0x100));
588 
589 		INT32 number = spriteram[i+1] & 0x3fff;
590 		INT32 color = 0x20 + (spriteram[i+2] & 0x000f);
591 		INT32 color_effect = (spriteram[i+3] & 0x4000) >> 14;
592 		INT32 attr = (spriteram[i+2] & 0xfe00) >> 9;
593 		INT32 xflip = attr & 0x20;
594 		INT32 yflip = attr & 0x40;
595 
596 		if (spriteram[i+0] & 0x8000) break;
597 
598 		if (((~color >> 3) & 1) != priority) continue;
599 
600 		if (DrvIsWatrball) sy -= 16;
601 
602 		if (!color_effect) {
603 			Draw16x16MaskTile(pTransDraw, number, sx - 0x0f, sy, xflip, yflip, color, 4, 0, 0, DrvSprites);
604 		} else {
605 			UINT8 *gfx_src = DrvSprites + ((number & 0x3fff) * 16 * 16);
606 
607 			for (INT32 py = 0; py < 16; py++)
608 			{
609 				INT32 ypos = ((sy + py) & 0x1ff);
610 				UINT16 *srcy = pTransDraw + (ypos * nScreenWidth);
611 
612 				INT32 gfx_py = yflip ? (16 - 1 - py) : py;
613 
614 				if ((ypos < 0) || (ypos >= nScreenHeight)) continue;
615 
616 				for (INT32 px = 0; px < 16; px++)
617 				{
618 					INT32 xpos = (((sx + px) & 0x3ff) - 0x0f) & 0x3ff;
619 					UINT16 *pixel = srcy + xpos;
620 					INT32 src_color = *pixel;
621 
622 					INT32 gfx_px = xflip ? (16 - 1 - px) : px;
623 					INT32 gfx_pen = gfx_src[16*gfx_py + gfx_px];
624 
625 					if ((gfx_pen < 8) || (gfx_pen >= 16)) continue;
626 					if ((xpos < 0) || (xpos >= nScreenWidth)) continue;
627 
628 					*pixel = src_color + (gfx_pen - 8) * 0x400;
629 				}
630 			}
631 		}
632 	}
633 }
634 
DrvDraw()635 static INT32 DrvDraw()
636 {
637 	BurnTransferClear();
638 	DrvCalcPalette();
639 	if (nBurnLayer & 0x01) DrvRenderBgLayer(0);
640 	if (nBurnLayer & 0x02) DrvRenderBgLayer(1);
641 	if (nBurnLayer & 0x04) DrvRenderFgLayer(0);
642 	if (nSpriteEnable & 0x01) DrawSprites(0);
643 	if (nBurnLayer & 0x08) DrvRenderFgLayer(1);
644 	if (nSpriteEnable & 0x02) DrawSprites(1);
645 	BurnTransferCopy(DrvPalette);
646 
647 	return 0;
648 }
649 
DrvFrame()650 static INT32 DrvFrame()
651 {
652 	INT32 nCyclesTotal = 10000000 / 60;
653 
654 	if (DrvReset) DrvDoReset();
655 
656 	DrvMakeInputs();
657 
658 	SekNewFrame();
659 	SekOpen(0);
660 	SekRun(nCyclesTotal);
661 	SekSetIRQLine(1, CPU_IRQSTATUS_AUTO);
662 	SekClose();
663 
664 	if (pBurnSoundOut) MSM6295Render(0, pBurnSoundOut, nBurnSoundLen);
665 
666 	if (pBurnDraw) DrvDraw();
667 
668 	return 0;
669 }
670 
DrvScan(INT32 nAction,INT32 * pnMin)671 static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
672 {
673 	struct BurnArea ba;
674 
675 	if (pnMin != NULL) {
676 		*pnMin = 0x029717;
677 	}
678 
679 	if (nAction & ACB_MEMORY_RAM) {
680 		memset(&ba, 0, sizeof(ba));
681 		ba.Data	  = RamStart;
682 		ba.nLen	  = RamEnd-RamStart;
683 		ba.szName = "All Ram";
684 		BurnAcb(&ba);
685 	}
686 
687 	if (nAction & ACB_DRIVER_DATA) {
688 		SekScan(nAction);
689 		MSM6295Scan(nAction, pnMin);
690 
691 		SCAN_VAR(BlmbyPotWheel);
692 		SCAN_VAR(DrvOkiBank);
693 		SCAN_VAR(DrvToggle);
694 
695 		if (nAction & ACB_WRITE) {
696 			DrvDoOkiBank(DrvOkiBank);
697 		}
698 	}
699 
700 	return 0;
701 }
702 
703 struct BurnDriver BurnDrvBlmbycar = {
704 	"blmbycar", NULL, NULL, NULL, "1994",
705 	"Blomby Car\0", NULL, "ABM & Gecas", "Miscellaneous",
706 	NULL, NULL, NULL, NULL,
707 	BDF_GAME_WORKING, 2, HARDWARE_MISC_POST90S, GBF_RACING, 0,
708 	NULL, DrvRomInfo, DrvRomName, NULL, NULL, NULL, NULL, DrvInputInfo, DrvDIPInfo,
709 	BlmbycarInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
710 	NULL, 0x2000, 384, 256, 4, 3
711 };
712 
713 struct BurnDriver BurnDrvBlmbycaru = {
714 	"blmbycaru", "blmbycar", NULL, NULL, "1994",
715 	"Blomby Car (not encrypted)\0", NULL, "ABM & Gecas", "Miscellaneous",
716 	NULL, NULL, NULL, NULL,
717 	BDF_GAME_WORKING | BDF_CLONE, 2, HARDWARE_MISC_POST90S, GBF_RACING, 0,
718 	NULL, DrvuRomInfo, DrvuRomName, NULL, NULL, NULL, NULL, DrvInputInfo, DrvDIPInfo,
719 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
720 	NULL, 0x2000, 384, 256, 4, 3
721 };
722 
723 struct BurnDriver BurnDrvWatrball = {
724 	"watrball", NULL, NULL, NULL, "1996",
725 	"Water Balls\0", NULL, "ABM", "Miscellaneous",
726 	NULL, NULL, NULL, NULL,
727 	BDF_GAME_WORKING, 2, HARDWARE_MISC_POST90S, GBF_PUZZLE, 0,
728 	NULL, WatrballRomInfo, WatrballRomName, NULL, NULL, NULL, NULL, DrvInputInfo, WatrballDIPInfo,
729 	WatrballInit, DrvExit, DrvFrame, DrvDraw, DrvScan,
730 	NULL, 0x2000, 384, 240, 4, 3
731 };
732