1 // Q-Bert emu-layer for FB Alpha by dink, based on the MAME driver by Fabrice Frances & Nicola Salmoria.
2 
3 #include "tiles_generic.h"
4 #include "driver.h"
5 #include "nec_intf.h"
6 #include "m6502_intf.h"
7 #include "bitswap.h"
8 #include "dac.h"
9 #include "samples.h"
10 
11 //#define QBERT_SOUND_DEBUG
12 
13 static UINT8 *AllMem;
14 static UINT8 *MemEnd;
15 static UINT8 *AllRam;
16 static UINT8 *RamEnd;
17 static UINT8 *DrvV20ROM;
18 static UINT8 *Drv6502ROM;
19 static UINT8 *DrvV20RAM;
20 static UINT8 *Drv6502RAM;
21 static UINT8 *DrvVideoRAM;
22 static UINT8 *DrvCharRAM;
23 static UINT8 *DrvSpriteRAM;
24 static UINT8 *DrvPaletteRAM;
25 static UINT8 *DrvCharGFX;
26 static UINT8 *DrvSpriteGFX;
27 static UINT8 *DrvNVRAM;
28 static UINT8 *DrvDummyROM;
29 
30 static UINT8 *riot_regs;
31 static UINT8 *riot_ram;
32 
33 static UINT8 *background_prio;
34 static UINT8 *spritebank;
35 static UINT8 *soundlatch;
36 static UINT8 *soundcpu_do_nmi;
37 
38 static char  *vtqueue;
39 static UINT8 *vtqueuepos;
40 static UINT32 *vtqueuetime;
41 static UINT8  *knocker_prev;
42 
43 static UINT32 *DrvPalette;
44 static UINT8 DrvRecalc;
45 
46 static UINT8 DrvJoy1[8];
47 static UINT8 DrvJoy2[8];
48 static UINT8 DrvFakeInput[8]; // fake inputs for rotate buttons
49 
50 static UINT8 DrvDip[2] = { 0, 0  };
51 static UINT8 DrvInput[5];
52 static UINT8 DrvReset;
53 
54 static UINT8 game_type = 0; // 0 = qbert, 6 = qbertcub, 4 = mplanets
55 
56 static UINT32 nRotateTime[2]  = { 0, 0 };
57 
58 static struct BurnInputInfo QbertInputList[] = {
59 	{"P1 Coin",		BIT_DIGITAL,	DrvJoy1 + 2,	"p1 coin"   },
60 	{"P1 Start",	BIT_DIGITAL,	DrvJoy1 + 0,	"p1 start"  },
61 	{"P1 Up",		BIT_DIGITAL,	DrvJoy2 + 2,	"p1 up"     },
62 	{"P1 Down",		BIT_DIGITAL,	DrvJoy2 + 3,	"p1 down"   },
63 	{"P1 Left",		BIT_DIGITAL,	DrvJoy2 + 1,	"p1 left"   },
64 	{"P1 Right",	BIT_DIGITAL,	DrvJoy2 + 0,	"p1 right"  },
65 
66 	{"P2 Coin",		BIT_DIGITAL,	DrvJoy1 + 3,	"p2 coin"   },
67 	{"P2 Start",	BIT_DIGITAL,	DrvJoy1 + 1,	"p2 start"  },
68 	{"P2 Up",		BIT_DIGITAL,	DrvJoy2 + 6,	"p2 up"     },
69 	{"P2 Down",		BIT_DIGITAL,	DrvJoy2 + 7,	"p2 down"   },
70 	{"P2 Left",		BIT_DIGITAL,	DrvJoy2 + 5,	"p2 left"   },
71 	{"P2 Right",	BIT_DIGITAL,	DrvJoy2 + 4,	"p2 right"  },
72 
73 	{"Reset",		BIT_DIGITAL,	&DrvReset,	    "reset"     },
74 	{"Select",		BIT_DIGITAL,	DrvJoy1 + 7,    "select"    },
75 	{"Dip A",		BIT_DIPSWITCH,	DrvDip + 0,     "dip"       },
76 	{"Dip B",		BIT_DIPSWITCH,	DrvDip + 1,     "dip"       },
77 };
78 
79 STDINPUTINFO(Qbert)
80 
81 
82 static struct BurnDIPInfo QbertDIPList[]=
83 {
84 	{0x0e, 0xff, 0xff, 0x02, NULL		        },
85 	{0x0f, 0xff, 0xff, 0x40, NULL	            },
86 
87 	{0   , 0xfe, 0   ,    2, "Demo Sounds"		},
88 	{0x0e, 0x01, 0x01, 0x01, "Off"		        },
89 	{0x0e, 0x01, 0x01, 0x00, "On"	            },
90 
91 	{0   , 0xfe, 0   ,    2, "Kicker"		    },
92 	{0x0e, 0x01, 0x02, 0x00, "Off"		        },
93 	{0x0e, 0x01, 0x02, 0x02, "On"		        },
94 
95 	{0   , 0xfe, 0   ,    2, "Cabinet"		    },
96 	{0x0e, 0x01, 0x04, 0x00, "Upright"		    },
97 	{0x0e, 0x01, 0x04, 0x04, "Cocktail"		    },
98 
99 	{0   , 0xfe, 0   ,    2, "Auto Round Advance (Cheat)" },
100 	{0x0e, 0x01, 0x08, 0x00, "Off"		        },
101 	{0x0e, 0x01, 0x08, 0x08, "On"		        },
102 
103 	{0   , 0xfe, 0   ,    2, "Free Play"		},
104 	{0x0e, 0x01, 0x10, 0x00, "Off"		        },
105 	{0x0e, 0x01, 0x10, 0x10, "On"		        },
106 
107 	{0   , 0xfe, 0   ,    2, "SW5"		        },
108 	{0x0e, 0x01, 0x20, 0x00, "Off"		        },
109 	{0x0e, 0x01, 0x20, 0x20, "On"		        },
110 
111 	{0   , 0xfe, 0   ,    2, "SW7"		        },
112 	{0x0e, 0x01, 0x40, 0x00, "Off"		        },
113 	{0x0e, 0x01, 0x40, 0x40, "On"		        },
114 
115 	{0   , 0xfe, 0   ,    2, "SW8"		        },
116 	{0x0e, 0x01, 0x80, 0x00, "Off"		        },
117 	{0x0e, 0x01, 0x80, 0x80, "On"		        },
118 
119 	{0   , 0xfe, 0   ,    2, "Service"	        },
120 	{0x0f, 0x01, 0x40, 0x40, "Off"		        },
121 	{0x0f, 0x01, 0x40, 0x00, "On"		        },
122 };
123 
124 STDDIPINFO(Qbert)
125 
126 static struct BurnInputInfo MplanetsInputList[] = {
127 	{"P1 Coin",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 coin"   },
128 	{"P1 Start",	BIT_DIGITAL,	DrvJoy2 + 5,	"p1 start"  },
129 	{"P1 Up",		BIT_DIGITAL,	DrvJoy2 + 0,	"p1 up"     },
130 	{"P1 Down",		BIT_DIGITAL,	DrvJoy2 + 2,	"p1 down"   },
131 	{"P1 Left",		BIT_DIGITAL,	DrvJoy2 + 3,	"p1 left"   },
132 	{"P1 Right",	BIT_DIGITAL,	DrvJoy2 + 1,	"p1 right"  },
133 	{"P1 Button 1",	BIT_DIGITAL,	DrvJoy2 + 4,	"p1 fire 1" },
134 	{"P1 Button 2",	BIT_DIGITAL,	DrvJoy2 + 7,	"p1 fire 2" },
135 	{"Rotate Left", BIT_DIGITAL,    DrvFakeInput + 0, "p1 rotate left" },
136 	{"Rotate Right",BIT_DIGITAL,    DrvFakeInput + 1, "p1 rotate right" },
137 
138 	{"Reset",		BIT_DIGITAL,	&DrvReset,      "reset"     },
139 	{"Select",		BIT_DIGITAL,	DrvJoy1 + 6,    "select"    },
140 	{"Dip A",		BIT_DIPSWITCH,	DrvDip + 0,     "dip"       },
141 	{"Dip B",		BIT_DIPSWITCH,	DrvDip + 1,     "dip"       },
142 };
143 
144 STDINPUTINFO(Mplanets)
145 
146 
147 static struct BurnDIPInfo MplanetsDIPList[]=
148 {
149 	{0x0C, 0xff, 0xff, 0x00, NULL		        },
150 	{0x0D, 0xff, 0xff, 0x80, NULL	            },
151 
152 	{0   , 0xfe, 0   ,    2, "Demo Sounds"		},
153 	{0x0C, 0x01, 0x01, 0x01, "Off"		        },
154 	{0x0C, 0x01, 0x01, 0x00, "On"		        },
155 
156 	{0   , 0xfe, 0   ,    2, "Bonus Life"		},
157 	{0x0C, 0x01, 0x02, 0x00, "10000"		    },
158 	{0x0C, 0x01, 0x02, 0x02, "12000"		    },
159 
160 	{0   , 0xfe, 0   ,    2, "Allow Round Select" },
161 	{0x0C, 0x01, 0x08, 0x00, "No"		        },
162 	{0x0C, 0x01, 0x08, 0x08, "Yes"		        },
163 
164 	{0   , 0xfe, 0   ,    4, "Coinage"		    },
165 	{0x0C, 0x01, 0x14, 0x04, "2 Coins 1 Credit"	},
166 	{0x0C, 0x01, 0x14, 0x00, "1 Coin  1 Credit"	},
167 	{0x0C, 0x01, 0x14, 0x10, "1 Coin  2 Credits" },
168 	{0x0C, 0x01, 0x14, 0x14, "Free Play"		},
169 
170 	{0   , 0xfe, 0   ,    2, "Lives"		    },
171 	{0x0C, 0x01, 0x20, 0x00, "3"		        },
172 	{0x0C, 0x01, 0x20, 0x20, "5"		        },
173 
174 	{0   , 0xfe, 0   ,    4, "Difficulty"		},
175 	{0x0C, 0x01, 0xc0, 0x40, "Easy"		        },
176 	{0x0C, 0x01, 0xc0, 0x00, "Medium"		    },
177 	{0x0C, 0x01, 0xc0, 0x80, "Hard"		        },
178 	{0x0C, 0x01, 0xc0, 0xc0, "Hardest"		    },
179 
180 	{0   , 0xfe, 0   ,    2, "Service"	        },
181 	{0x0D, 0x01, 0x80, 0x80, "Off"		        },
182 	{0x0D, 0x01, 0x80, 0x00, "On"		        },
183 };
184 
185 STDDIPINFO(Mplanets)
186 
187 static struct BurnInputInfo QbertqubInputList[] = {
188 	{"P1 Coin",		BIT_DIGITAL,	DrvJoy1 + 3,	"p1 coin"   },
189 	{"P1 Start",	BIT_DIGITAL,	DrvJoy1 + 0,	"p1 start"  },
190 	{"P1 Up",		BIT_DIGITAL,	DrvJoy2 + 2,	"p1 up"     },
191 	{"P1 Down",		BIT_DIGITAL,	DrvJoy2 + 3,	"p1 down"   },
192 	{"P1 Left",		BIT_DIGITAL,	DrvJoy2 + 1,	"p1 left"   },
193 	{"P1 Right",	BIT_DIGITAL,	DrvJoy2 + 0,	"p1 right"  },
194 
195 	{"Reset",		BIT_DIGITAL,	&DrvReset,      "reset"     },
196 	{"Select",		BIT_DIGITAL,	DrvJoy1 + 7,    "select"    },
197 	{"Dip A",		BIT_DIPSWITCH,	DrvDip + 0,     "dip"       },
198 	{"Dip B",		BIT_DIPSWITCH,	DrvDip + 1,     "dip"       },
199 };
200 
201 STDINPUTINFO(Qbertqub)
202 
203 static struct BurnDIPInfo QbertqubDIPList[]=
204 {
205 	{0x08, 0xff, 0xff, 0x00, NULL		        },
206 	{0x09, 0xff, 0xff, 0x40, NULL	            },
207 
208 	{0   , 0xfe, 0   ,    2, "Demo Sounds"		},
209 	{0x08, 0x01, 0x08, 0x08, "Off"		        },
210 	{0x08, 0x01, 0x08, 0x00, "On"		        },
211 
212 	{0   , 0xfe, 0   ,    13, "Coinage"		    },
213 	{0x08, 0x01, 0x35, 0x24, "A 2/1 B 2/1"		},
214 	{0x08, 0x01, 0x35, 0x14, "A 1/1 B 4/1"		},
215 	{0x08, 0x01, 0x35, 0x30, "A 1/1 B 3/1"		},
216 	{0x08, 0x01, 0x35, 0x10, "A 1/1 B 2/1"		},
217 	{0x08, 0x01, 0x35, 0x00, "A 1/1 B 1/1"		},
218 	{0x08, 0x01, 0x35, 0x11, "A 2/3 B 2/1"		},
219 	{0x08, 0x01, 0x35, 0x15, "A 1/2 B 3/1"		},
220 	{0x08, 0x01, 0x35, 0x20, "A 1/2 B 2/1"		},
221 	{0x08, 0x01, 0x35, 0x21, "A 1/2 B 1/1"		},
222 	{0x08, 0x01, 0x35, 0x31, "A 1/2 B 1/5"		},
223 	{0x08, 0x01, 0x35, 0x04, "A 1/3 B 2/1"		},
224 	{0x08, 0x01, 0x35, 0x05, "A 1/3 B 1/1"		},
225 	{0x08, 0x01, 0x35, 0x35, "Free Play"		},
226 
227 	{0   , 0xfe, 0   ,    2, "1st Bonus Life"	},
228 	{0x08, 0x01, 0x02, 0x00, "10000"		    },
229 	{0x08, 0x01, 0x02, 0x02, "15000"		    },
230 
231 	{0   , 0xfe, 0   ,    2, "Additional Bonus Life" },
232 	{0x08, 0x01, 0x40, 0x00, "20000"		    },
233 	{0x08, 0x01, 0x40, 0x40, "25000"		    },
234 
235 	{0   , 0xfe, 0   ,    2, "Difficulty"		},
236 	{0x08, 0x01, 0x80, 0x00, "Normal"		    },
237 	{0x08, 0x01, 0x80, 0x80, "Hard"		        },
238 
239 	{0   , 0xfe, 0   ,    2, "Service"	        },
240 	{0x09, 0x01, 0x40, 0x40, "Off"		        },
241 	{0x09, 0x01, 0x40, 0x00, "On"		        },
242 
243 };
244 
STDDIPINFO(Qbertqub)245 STDDIPINFO(Qbertqub)
246 
247 static UINT8 dialRotation(int addy) {
248 	if (nRotateTime[addy] > nCurrentFrame) nRotateTime[addy] = 0; // Bugfix: no rotate after savestate
249 
250 	if (DrvFakeInput[0] && (nCurrentFrame > nRotateTime[addy]+2)) {
251 		nRotateTime[addy] = nCurrentFrame;
252 
253 		return 0xfe;
254     }
255     if (DrvFakeInput[1] && (nCurrentFrame > nRotateTime[addy]+2)) {
256         nRotateTime[addy] = nCurrentFrame;
257 
258 		return 2;
259     }
260 
261 	return 0;
262 }
263 
gottlieb_paletteram_w(UINT16 offset,UINT8 data)264 static void gottlieb_paletteram_w(UINT16 offset, UINT8 data)
265 {
266 	INT32 bit0, bit1, bit2, bit3;
267 	INT32 r, g, b, val;
268 
269 	DrvPaletteRAM[offset] = data;
270 
271 	/* red component */
272 
273 	val = DrvPaletteRAM[offset | 1];
274 
275 	bit0 = (val >> 0) & 0x01;
276 	bit1 = (val >> 1) & 0x01;
277 	bit2 = (val >> 2) & 0x01;
278 	bit3 = (val >> 3) & 0x01;
279 
280 	r = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
281 
282 	/* green component */
283 
284 	val = DrvPaletteRAM[offset & ~1];
285 
286 	bit0 = (val >> 4) & 0x01;
287 	bit1 = (val >> 5) & 0x01;
288 	bit2 = (val >> 6) & 0x01;
289 	bit3 = (val >> 7) & 0x01;
290 
291 	g = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
292 
293 	/* blue component */
294 
295 	val = DrvPaletteRAM[offset & ~1];
296 
297 	bit0 = (val >> 0) & 0x01;
298 	bit1 = (val >> 1) & 0x01;
299 	bit2 = (val >> 2) & 0x01;
300 	bit3 = (val >> 3) & 0x01;
301 
302 	b = 0x10 * bit0 + 0x21 * bit1 + 0x46 * bit2 + 0x88 * bit3;
303 
304 	DrvPalette[offset / 2] = BurnHighCol(r, g, b, 0);
305 }
306 
qbert_palette()307 static void qbert_palette()
308 {
309 	for (INT32 i = 0; i < 0x20; i++) {
310 		gottlieb_paletteram_w(i, DrvPaletteRAM[i]);
311 	}
312 }
313 
314 static void gottlieb_sh_w(UINT16 offset, UINT8 data); //forward!
315 static void qbert_knocker(UINT8 knock);
316 
main_write(UINT32 address,UINT8 data)317 static void __fastcall main_write(UINT32 address, UINT8 data)
318 {
319 	address &= 0xffff;
320 
321 	if ((address & 0xff00) == 0x3700) address &= ~0x700; // mirror handling
322 	if ((address & 0xfc00) == 0x3c00) address &= ~0x400;
323 	if ((address & 0xffe0) == 0x57e0) address &= ~0x7e0;
324 	if ((address & 0xffff) == 0x5ff8) address &= ~0x7f8;
325 
326 	if (/*address >= 0x0000 &&*/ address <= 0x0fff) {
327 		DrvNVRAM[address - 0x0000] = data;
328 		return;
329 	}
330 
331 	if (address >= 0x1000 && address <= 0x2fff) {
332 		//bprintf(0, _T("drw."));
333 		DrvDummyROM[address - 0x1000] = data;
334 		return;
335 	}
336 
337 	if (address >= 0x3000 && address <= 0x30ff) {
338 		DrvSpriteRAM[address - 0x3000] = data;
339 		return;
340 	}
341 
342 	if (address >= 0x3800 && address <= 0x3bff) {
343 		DrvVideoRAM[address - 0x3800] = data;
344 		return;
345 	}
346 
347 	if (address >= 0x4000 && address <= 0x4fff) {
348 		DrvCharRAM[address - 0x4000] = data;
349 		return;
350 	}
351 
352 	if (address >= 0x5000 && address <= 0x501f) {
353 		gottlieb_paletteram_w(address - 0x5000, data);
354 		return;
355 	}
356 
357 	switch (address)
358 	{
359 		case 0x5802: gottlieb_sh_w(address, data); return;
360 		case 0x5803: {
361 			*background_prio = data & 0x01;
362 			qbert_knocker(data >> 5 & 1);
363 			if (game_type == 6) // qbertqub only
364 				*spritebank = (data & 0x10) >> 4;
365 			return;
366 		}
367 	}
368 }
369 
main_read(UINT32 address)370 static UINT8 __fastcall main_read(UINT32 address)
371 {
372 	address &= 0xffff;
373 
374 	if (address >= 0x6000 && address <= 0xffff) {
375 		return DrvV20ROM[address - 0x6000];
376 	}
377 
378 	if (/*address >= 0x0000 &&*/ address <= 0x0fff) {
379 		return DrvNVRAM[address - 0x0000];
380 	}
381 
382 	if (address >= 0x1000 && address <= 0x2fff) {
383 		//bprintf(0, _T("drr."));
384 		return DrvDummyROM[address - 0x1000];
385 	}
386 
387 	if ((address & 0xff00) == 0x3700) address &= ~0x700;
388 	if ((address & 0xfc00) == 0x3c00) address &= ~0x400;
389 	if ((address & 0xffe0) == 0x57e0) address &= ~0x7e0;
390 	if ((address & 0xffff) == 0x5ff8) address &= ~0x7f8;
391 
392 	if (address >= 0x3000 && address <= 0x30ff) {
393 		return DrvSpriteRAM[address - 0x3000];
394 	}
395 
396 	if (address >= 0x3800 && address <= 0x3bff) {
397 		return DrvVideoRAM[address - 0x3800];
398 	}
399 
400 	if (address >= 0x4000 && address <= 0x4fff) {
401 		return DrvCharRAM[address - 0x4000];
402 	}
403 
404 	if (address >= 0x5000 && address <= 0x501f) {
405 		return DrvPaletteRAM[address - 0x5000];
406 	}
407 
408 
409 	switch (address)
410 	{
411 		case 0x5800: return DrvDip[0];
412 		case 0x5801: return DrvInput[0] | DrvDip[1]; // DrvDip[1] (fake-dip) for service mode.
413 		case 0x5803: return dialRotation(0);
414 		case 0x5804: return DrvInput[1];
415 	}
416 
417 	return 0;
418 }
419 
qbert_knocker(UINT8 knock)420 static void qbert_knocker(UINT8 knock)
421 {
422 	if (knock & ~*knocker_prev)
423 		BurnSamplePlay(44);
424 	*knocker_prev = knock;
425 }
426 
gottlieb_sh_w(UINT16,UINT8 data)427 static void gottlieb_sh_w(UINT16 /*offset*/, UINT8 data)
428 {
429 	static INT32 random_offset = rand()&7;
430 	data &= 0x3f;
431 
432 	if ((data & 0x0f) != 0xf) {
433 #ifdef QBERT_SOUND_DEBUG
434 		bprintf(0, _T("data %X.."), data ^ 0x3f);
435 #endif
436 		switch (data ^ 0x3f) { // qbert sample player
437 			case 17:
438 			case 18:
439 			case 19:
440 			case 20:
441 			case 21:
442 				BurnSamplePlay(((data^0x3f)-17)*8+random_offset);
443 				random_offset = (random_offset+1)&7;
444 				break;
445 			case 22:
446 				BurnSamplePlay(40);
447 				break;
448 			case 23:
449 				BurnSamplePlay(41);
450 				break;
451 			case 28:
452 				BurnSamplePlay(42); // Hello, I'm turned on.
453 				break;
454 			case 36:
455 				BurnSamplePlay(43); // Bye-Bye
456 				break;
457 		}
458 
459 		*soundlatch = data;
460 
461 		M6502SetIRQLine(0, CPU_IRQSTATUS_ACK);
462 		M6502Run(10); //CPU_IRQSTATUS_AUTO no workie
463 		M6502SetIRQLine(0, CPU_IRQSTATUS_NONE);
464 	}
465 }
466 
gottlieb_riot_r(UINT16 offset)467 static UINT8 gottlieb_riot_r(UINT16 offset)
468 {
469     switch (offset & 0x1f) {
470 	case 0: /* port A */
471 		return *soundlatch ^ 0xff; /* invert command */
472 	case 2: /* port B */
473 		return 0x40; /* say that PB6 is 1 (test SW1 not pressed) */
474 	case 5: /* interrupt register */
475 		return 0x40; /* say that edge detected on PA7 */
476 	default:
477 		return riot_regs[offset & 0x1f];
478     }
479 }
480 
blank_queue()481 static void blank_queue()
482 {
483 #ifdef QBERT_SOUND_DEBUG
484 	bprintf(0, _T("BLANK!{%X}.."), *vtqueuetime);
485 #endif
486 	*vtqueuepos = 0;
487 	memset(vtqueue, 0, 0x20);
488 	*vtqueuetime = GetCurrentFrame();
489 }
490 
add_to_queue(UINT8 data)491 static void add_to_queue(UINT8 data)
492 {
493 	if (*vtqueuepos > 0x20-1 || (UINT32)GetCurrentFrame() > *vtqueuetime+2)
494 		blank_queue();
495 	vtqueue[(*vtqueuepos)++] = data;
496 }
497 
check_queue()498 static UINT8 check_queue()
499 {
500 	if (*vtqueuepos == 24 && !strncmp("\xC1\xE4\xFF\xE7\xE8\xD2\xFC\xFC\xFC\xFC\xFC\xEA\xFF\xF6\xD6\xF3\xD5\xC5\xF5\xF2\xE1\xDB\xF2\xC0", vtqueue, 24)) {
501 		blank_queue(); // "Hello, I'm turned on."
502 		return 1;
503 	}
504 
505 	return 0;
506 }
507 
audio_write(UINT16 address,UINT8 data)508 static void audio_write(UINT16 address, UINT8 data)
509 {
510 	address &= 0x7fff; // 15bit addressing
511 
512 	if (address >= 0x7000 && address <= 0x7fff) {
513 		bprintf(0, _T("write to audio ROM @ %X."), address);
514 		Drv6502ROM[address - 0x7000] = data;
515 	}
516 
517 	if (/*address >= 0x0000 &&*/ address <= 0x01ff) {
518 		riot_ram[address & 0x7f] = data;
519 	}
520 
521 	if (address >= 0x0200 && address <= 0x03ff) {
522 		riot_regs[address & 0x1f] = data;
523 	}
524 
525 	switch (address)
526 	{
527 		case 0x1fff:
528 		case 0x1000: {
529 			DACWrite(0, data);
530 			return;
531 		}
532 		case 0x2000: {
533 			add_to_queue(data);
534 #ifdef QBERT_SOUND_DEBUG
535 			bprintf(0, _T("\\x%X"), data); //save
536 #endif
537 			switch (check_queue()) {
538 				case 1: BurnSamplePlay(42);	break; // Say Hello
539 			}
540 			*soundcpu_do_nmi = 1;
541 			return;
542 		}
543 	}
544 }
545 
audio_read(UINT16 address)546 static UINT8 audio_read(UINT16 address)
547 {
548 	address &= 0x7fff; // 15bit addressing
549 
550 	if (address >= 0x7000 && address <= 0x7fff) {
551 		return Drv6502ROM[address - 0x7000];
552 	}
553 
554 	if (/*address >= 0x0000 &&*/ address <= 0x01ff) {
555 		return riot_ram[address&0x7f];
556 	}
557 
558 	if (address >= 0x0200 && address <= 0x03ff) {
559 		return gottlieb_riot_r(address - 0x200);
560 	}
561 
562 	return 0;
563 }
564 
DrvSyncDAC()565 static INT32 DrvSyncDAC()
566 {
567 	return (INT32)(float)(nBurnSoundLen * (M6502TotalCycles() / ((3579545.0000/4) / (nBurnFPS / 100.0000))));
568 }
569 
DrvDoReset()570 static INT32 DrvDoReset()
571 {
572 	memset (AllRam, 0, RamEnd - AllRam);
573 
574 	VezOpen(0);
575 	VezReset();
576 	VezClose();
577 
578 	M6502Open(0);
579 	M6502Reset();
580 	M6502Close();
581 
582 	DACReset();
583 	BurnSampleReset();
584 
585 	nRotateTime[0] = 0;
586 	nRotateTime[1] = 0;
587 
588 	return 0;
589 }
590 
591 
MemIndex()592 static INT32 MemIndex()
593 {
594 	UINT8 *Next; Next = AllMem;
595 
596 	DrvV20ROM		= Next; Next += 0x10000;
597 	Drv6502ROM		= Next; Next += 0x10000;
598 
599 	DrvPalette		= (UINT32*)Next; Next += 0x10 * sizeof(UINT32);
600 	DrvCharGFX      = Next; Next += 0x40000;
601 	DrvSpriteGFX    = Next; Next += 0x40000;
602 
603 	DrvNVRAM        = Next; Next += 0x01000; // Keep in ROM section.
604 
605 	AllRam			= Next;
606 
607 	DrvV20RAM		= Next; Next += 0x01000;
608 	Drv6502RAM		= Next; Next += 0x01000;
609 
610 	DrvVideoRAM		= Next; Next += 0x00400;
611 	DrvCharRAM		= Next; Next += 0x01000;
612 	DrvSpriteRAM	= Next; Next += 0x00100;
613 	DrvPaletteRAM	= Next; Next += 0x00040;
614 	DrvDummyROM     = Next; Next += 0x02000; // it's RAM, too.
615 
616 	riot_regs       = Next; Next += 0x00020;
617 	riot_ram        = Next; Next += 0x00200;
618 
619 	vtqueuepos      = Next; Next += 0x00001;
620 	vtqueuetime     = (UINT32 *)Next; Next += 0x00004;
621 	vtqueue         = (char *)Next; Next += 0x00020;
622 	knocker_prev    = Next; Next += 0x00001;
623 
624 	background_prio = Next; Next += 0x00001;
625 	spritebank      = Next; Next += 0x00001;
626 	soundlatch      = Next; Next += 0x00001;
627 	soundcpu_do_nmi = Next; Next += 0x00001;
628 
629 	RamEnd			= Next;
630 	MemEnd			= Next;
631 
632 	return 0;
633 }
634 
DrvInit()635 static INT32 DrvInit()
636 {
637 	INT32 c8PlaneOffsets[4] = { 0, 1, 2, 3 };
638 	INT32 c8XOffsets[8] = { 0, 4, 8, 12, 16, 20, 24, 28 };
639 	INT32 c8YOffsets[8] = { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 };
640 
641 	INT32 c16PlaneOffsets[4] = { RGN_FRAC(((game_type == 6) ? 0x10000 : 0x8000), 0, 4), RGN_FRAC(((game_type == 6) ? 0x10000 : 0x8000), 1, 4), RGN_FRAC(((game_type == 6) ? 0x10000 : 0x8000), 2, 4), RGN_FRAC(((game_type == 6) ? 0x10000 : 0x8000), 3, 4) };
642 	INT32 c16XOffsets[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
643 	INT32 c16YOffsets[16] = { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16, 8*16, 9*16, 10*16, 11*16, 12*16, 13*16, 14*16, 15*16 };
644 	INT32 roffset = 0;
645 
646 	AllMem = NULL;
647 	MemIndex();
648 	INT32 nLen = MemEnd - (UINT8 *)0;
649 	if ((AllMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
650 	memset(AllMem, 0, nLen);
651 	MemIndex();
652 
653 	{   // Load ROMS parse GFX
654 		UINT8 *DrvTempRom = (UINT8 *)BurnMalloc(0x40000);
655 		memset(DrvTempRom, 0, 0x40000);
656 		{
657 			if (game_type == 0) { // qbert
658 				if (BurnLoadRom(DrvV20ROM + 0x4000, 0, 1)) return 1;
659 				if (BurnLoadRom(DrvV20ROM + 0x6000, 1, 1)) return 1;
660 				if (BurnLoadRom(DrvV20ROM + 0x8000, 2, 1)) return 1;
661 			}
662 			if (game_type == 4) { // mplanets
663 				if (BurnLoadRom(DrvV20ROM + 0x0000, 0, 1)) return 1;
664 				if (BurnLoadRom(DrvV20ROM + 0x2000, 1, 1)) return 1;
665 				if (BurnLoadRom(DrvV20ROM + 0x4000, 2, 1)) return 1;
666 				if (BurnLoadRom(DrvV20ROM + 0x6000, 3, 1)) return 1;
667 				if (BurnLoadRom(DrvV20ROM + 0x8000, 4, 1)) return 1;
668 				roffset = 2;
669 			}
670 			if (game_type == 6) { // qbertqub
671 				if (BurnLoadRom(DrvV20ROM + 0x2000, 0, 1)) return 1;
672 				if (BurnLoadRom(DrvV20ROM + 0x4000, 1, 1)) return 1;
673 				if (BurnLoadRom(DrvV20ROM + 0x6000, 2, 1)) return 1;
674 				if (BurnLoadRom(DrvV20ROM + 0x8000, 3, 1)) return 1;
675 				roffset = 1;
676 			}
677 
678 			if (BurnLoadRom(Drv6502ROM + 0x0000, 3 + roffset, 1)) return 1;
679 			if (BurnLoadRom(Drv6502ROM + 0x0800, 4 + roffset, 1)) return 1;
680 
681 			// load & decode 8x8 tiles
682 			memset(DrvTempRom, 0, 0x40000);
683 			if (BurnLoadRom(DrvTempRom + 0x0000, 5 + roffset, 1)) return 1;
684 			if (BurnLoadRom(DrvTempRom + 0x1000, 6 + roffset, 1)) return 1;
685 			GfxDecode(0x100, 4, 8, 8, c8PlaneOffsets, c8XOffsets, c8YOffsets, 0x100, DrvTempRom, DrvCharGFX);
686 
687 			// load & decode 16x16 tiles
688 			memset(DrvTempRom, 0, 0x40000);
689 			if (game_type == 6) { // qbertqub
690 				if (BurnLoadRom(DrvTempRom + 0x0000, 7 + roffset, 1)) return 1;
691 				if (BurnLoadRom(DrvTempRom + 0x4000, 8 + roffset, 1)) return 1;
692 				if (BurnLoadRom(DrvTempRom + 0x8000, 9 + roffset, 1)) return 1;
693 				if (BurnLoadRom(DrvTempRom + 0xc000, 10 + roffset, 1)) return 1;
694 				GfxDecode(0x200 /*((0x10000*8)/4)/(16*16))*/, 4, 16, 16, c16PlaneOffsets, c16XOffsets, c16YOffsets, 0x100, DrvTempRom, DrvSpriteGFX);
695 			} else {
696 				if (BurnLoadRom(DrvTempRom + 0x0000, 7 + roffset, 1)) return 1;
697 				if (BurnLoadRom(DrvTempRom + 0x2000, 8 + roffset, 1)) return 1;
698 				if (BurnLoadRom(DrvTempRom + 0x4000, 9 + roffset, 1)) return 1;
699 				if (BurnLoadRom(DrvTempRom + 0x6000, 10 + roffset, 1)) return 1;
700 				GfxDecode(0x100 /*((0x8000*8)/4)/(16*16))*/, 4, 16, 16, c16PlaneOffsets, c16XOffsets, c16YOffsets, 0x100, DrvTempRom, DrvSpriteGFX);
701 			}
702 		}
703 		BurnFree(DrvTempRom);
704 	}
705 
706 	VezInit(0, V20_TYPE);
707 	VezOpen(0);
708 
709 	memset(DrvNVRAM, 0xff, 0x1000); // Init NVRAM
710 
711 	//VezMapArea(0x01000, 0x02fff, 0, DrvDummyROM); // ROM for reactor and 3stooges, used as RAM for all other games.
712 	//VezMapArea(0x01000, 0x02fff, 1, DrvDummyROM); // note: moved to main_read() / main_write()
713 	//VezMapArea(0x01000, 0x02fff, 2, DrvDummyROM);
714 	VezSetReadHandler(main_read);
715 	VezSetWriteHandler(main_write);
716 
717 	VezClose();
718 
719 	M6502Init(0, TYPE_M6502);
720 	M6502Open(0);
721 	M6502SetWriteHandler(audio_write);
722 	M6502SetReadHandler(audio_read);
723 	M6502SetReadOpArgHandler(audio_read);
724 	M6502SetReadOpHandler(audio_read);
725 	M6502Close();
726 
727 	BurnSampleInit(0);
728 	BurnSampleSetAllRoutesAllSamples(0.30, BURN_SND_ROUTE_BOTH);
729 
730 	DACInit(0, 0, 1, DrvSyncDAC);
731 	DACSetRoute(0, 0.35, BURN_SND_ROUTE_BOTH);
732 
733 	GenericTilesInit();
734 
735 	DrvDoReset();
736 
737 	return 0;
738 }
739 
740 
DrvExit()741 static INT32 DrvExit()
742 {
743 	GenericTilesExit();
744 
745 	VezExit();
746 	M6502Exit();
747 	DACExit();
748 	BurnSampleExit();
749 
750 	BurnFree(AllMem);
751 
752 	game_type = 0;
753 
754 	return 0;
755 }
756 
757 
RenderTileCPMP(INT32 code,INT32 color,INT32 sx,INT32 sy,INT32 flipx,INT32 flipy,INT32 width,INT32 height,INT32 offset,INT32,UINT8 * gfxrom)758 static void RenderTileCPMP(INT32 code, INT32 color, INT32 sx, INT32 sy, INT32 flipx, INT32 flipy, INT32 width, INT32 height, INT32 offset, INT32 /*mode*/, UINT8 *gfxrom)
759 {
760 	UINT16 *dest = pTransDraw;
761 	UINT8 *gfx = gfxrom;
762 
763 	INT32 flip = 0;
764 	if (flipy) flip |= (height - 1) * width;
765 	if (flipx) flip |= width - 1;
766 
767 	gfx += code * width * height;
768 
769 	for (INT32 y = 0; y < height; y++, sy++) {
770 		if (sy < 0 || sy >= nScreenHeight) continue;
771 
772 		for (INT32 x = 0; x < width; x++, sx++) {
773 			if (sx < 0 || sx >= nScreenWidth) continue; // blank out the top and bottom 16 pixels for status
774 
775 			INT32 pxl = gfx[((y * width) + x) ^ flip];
776 
777 			if (!pxl) continue; // transparency
778 
779 			dest[sy * nScreenWidth + sx] = pxl | (color << 4) | offset;
780 		}
781 		sx -= width;
782 	}
783 }
784 
785 
draw_sprites()786 static void draw_sprites()
787 {
788 	for (INT32 offs = 0; offs < 0x100 - 8; offs += 4)	{
789 		INT32 sx = ((DrvSpriteRAM[offs + 1]) - 4) + ((game_type == 4) ? 7 : 0); // mplanets has weird sx/sy offsets
790 		INT32 sy = ((DrvSpriteRAM[offs]) - 13) - ((game_type == 4) ? 4 : 0);    // apparent in the hiscore table.
791 		INT32 code = (255 ^ DrvSpriteRAM[offs + 2]) + 256 * *spritebank;
792 
793 		if (DrvSpriteRAM[offs] || DrvSpriteRAM[offs + 1])
794 			Render16x16Tile_Mask_Clip(pTransDraw, code, sx, sy, 0, 4, 0, 0x00, DrvSpriteGFX);
795 	}
796 }
797 
draw_bg()798 static void draw_bg()
799 {
800 	INT32 hflip = 0, vflip = 0;
801 	for (INT32 offs = 0x3ff; offs >= 0; offs--)
802 	{
803 		INT32 sx = offs % 32;
804 		INT32 sy = offs / 32;
805 
806 		if (hflip) sx = 31 - sx;
807 		if (vflip) sy = 29 - sy;
808 
809 		INT32 code = DrvVideoRAM[offs];
810 		INT32 color = 0;
811 
812 		sx = 8 * sx;
813 		sy = 8 * sy;
814 		if (sx >= nScreenWidth) continue;
815 		if (sy >= nScreenHeight) continue;
816 
817 		RenderTileCPMP(code, color, sx, sy, hflip, vflip, 8, 8, 0, 0, DrvCharGFX);
818 	}
819 }
820 
DrvDraw()821 static INT32 DrvDraw()
822 {
823 	if (DrvRecalc) {
824 		qbert_palette();
825 		DrvRecalc = 0;
826 	}
827 
828 	BurnTransferClear();
829 
830 	if (nBurnLayer & 2 && !*background_prio) draw_bg();
831 	if (nBurnLayer & 4) draw_sprites();
832 	if (nBurnLayer & 2 &&  *background_prio) draw_bg();
833 
834 	BurnTransferCopy(DrvPalette);
835 
836 	return 0;
837 }
838 
DrvMakeInputs()839 static void DrvMakeInputs()
840 {
841 	// Reset Inputs (all active HIGH)
842 	DrvInput[0] = 0;
843 	DrvInput[1] = 0;
844 
845 	// Compile Digital Inputs
846 	for (INT32 i = 0; i < 8; i++) {
847 		DrvInput[0] |= (DrvJoy1[i] & 1) << i;
848 		DrvInput[1] |= (DrvJoy2[i] & 1) << i;
849 	}
850 }
851 
DrvFrame()852 static INT32 DrvFrame()
853 {
854 	if (DrvReset) {
855 		DrvDoReset();
856 	}
857 
858 	DrvMakeInputs();
859 	M6502NewFrame();
860 
861 	INT32 nInterleave = 256;
862 	INT32 nCyclesTotalVez = 5000000 / 60;
863 	INT32 nCyclesTotal6502 = (3579545 / 4) / 60;
864 
865 	VezOpen(0);
866 	M6502Open(0);
867 	for (INT32 i = 0; i < nInterleave; i++) {
868 		M6502Run(nCyclesTotal6502 / nInterleave);
869 		if (*soundcpu_do_nmi) {
870 			M6502SetIRQLine(M6502_INPUT_LINE_NMI, CPU_IRQSTATUS_AUTO);
871 			*soundcpu_do_nmi = 0;
872 		}
873 
874 		VezRun(nCyclesTotalVez / nInterleave);
875 		if (i == (nInterleave - 1))
876 			VezSetIRQLineAndVector(0x20, 0xff, CPU_IRQSTATUS_AUTO);
877 	}
878 	VezClose();
879 	M6502Close();
880 
881 	if (pBurnSoundOut) {
882 		BurnSampleRender(pBurnSoundOut, nBurnSoundLen);
883 		DACUpdate(pBurnSoundOut, nBurnSoundLen);
884 	}
885 
886 	if (pBurnDraw) {
887 		DrvDraw();
888 	}
889 
890 	return 0;
891 }
892 
DrvScan(INT32 nAction,INT32 * pnMin)893 static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
894 {
895 	struct BurnArea ba;
896 
897 	if (pnMin) {
898 		*pnMin = 0x029735;
899 	}
900 
901 	if (nAction & ACB_VOLATILE) {
902 		memset(&ba, 0, sizeof(ba));
903 		ba.Data	  = AllRam;
904 		ba.nLen	  = RamEnd - AllRam;
905 		ba.szName = "All Ram";
906 		BurnAcb(&ba);
907 
908 		memset(&ba, 0, sizeof(ba));     // savestates get f*cked up, because NVRAM is also used
909 		ba.Data		= DrvNVRAM;         // as regular memory, to fix that we will scan it both here
910 		ba.nLen		= 0x1000;           // and in the NVRAM section.
911 		ba.szName	= "SSNVRAM";        // note: this is separate from "All Ram" so it doesn't get trashed in DrvDoReset();
912 		BurnAcb(&ba);
913 
914 		VezScan(nAction);
915 		M6502Scan(nAction);
916 
917 		DACScan(nAction, pnMin);
918 		BurnSampleScan(nAction, pnMin);
919 	}
920 
921 	if (nAction & ACB_NVRAM) {
922 		memset(&ba, 0, sizeof(ba));
923 		ba.Data		= DrvNVRAM;
924 		ba.nLen		= 0x1000;
925 		ba.szName	= "NV RAM";
926 		BurnAcb(&ba);
927 	}
928 
929 	return 0;
930 }
931 
932 static struct BurnSampleInfo qbertSampleDesc[] = {
933 #if !defined (ROM_VERIFY)
934 	{"fx_17a", SAMPLE_NOLOOP },
935 	{"fx_17b", SAMPLE_NOLOOP },
936 	{"fx_17c", SAMPLE_NOLOOP },
937 	{"fx_17d", SAMPLE_NOLOOP },
938 	{"fx_17e", SAMPLE_NOLOOP },
939 	{"fx_17f", SAMPLE_NOLOOP },
940 	{"fx_17g", SAMPLE_NOLOOP },
941 	{"fx_17h", SAMPLE_NOLOOP },
942 	{"fx_18a", SAMPLE_NOLOOP },
943 	{"fx_18b", SAMPLE_NOLOOP },
944 	{"fx_18c", SAMPLE_NOLOOP },
945 	{"fx_18d", SAMPLE_NOLOOP },
946 	{"fx_18e", SAMPLE_NOLOOP },
947 	{"fx_18f", SAMPLE_NOLOOP },
948 	{"fx_18g", SAMPLE_NOLOOP },
949 	{"fx_18h", SAMPLE_NOLOOP },
950 	{"fx_19a", SAMPLE_NOLOOP },
951 	{"fx_19b", SAMPLE_NOLOOP },
952 	{"fx_19c", SAMPLE_NOLOOP },
953 	{"fx_19d", SAMPLE_NOLOOP },
954 	{"fx_19e", SAMPLE_NOLOOP },
955 	{"fx_19f", SAMPLE_NOLOOP },
956 	{"fx_19g", SAMPLE_NOLOOP },
957 	{"fx_19h", SAMPLE_NOLOOP },
958 	{"fx_20a", SAMPLE_NOLOOP },
959 	{"fx_20b", SAMPLE_NOLOOP },
960 	{"fx_20c", SAMPLE_NOLOOP },
961 	{"fx_20d", SAMPLE_NOLOOP },
962 	{"fx_20e", SAMPLE_NOLOOP },
963 	{"fx_20f", SAMPLE_NOLOOP },
964 	{"fx_20g", SAMPLE_NOLOOP },
965 	{"fx_20h", SAMPLE_NOLOOP },
966 	{"fx_21a", SAMPLE_NOLOOP },
967 	{"fx_21b", SAMPLE_NOLOOP },
968 	{"fx_21c", SAMPLE_NOLOOP },
969 	{"fx_21d", SAMPLE_NOLOOP },
970 	{"fx_21e", SAMPLE_NOLOOP },
971 	{"fx_21f", SAMPLE_NOLOOP },
972 	{"fx_21g", SAMPLE_NOLOOP },
973 	{"fx_21h", SAMPLE_NOLOOP },
974 	{"fx_22",  SAMPLE_NOLOOP },
975 	{"fx_23",  SAMPLE_NOLOOP },
976 	{"fx_28",  SAMPLE_NOLOOP },
977 	{"fx_36",  SAMPLE_NOLOOP },
978 #endif
979 	{"knocker", SAMPLE_NOLOOP },
980 	{"", 0 }
981 };
982 
983 STD_SAMPLE_PICK(qbert)
984 STD_SAMPLE_FN(qbert)
985 
986 // Q*bert (US set 1)
987 
988 static struct BurnRomInfo qbertRomDesc[] = {
989 	{ "qb-rom2.bin",	0x2000, 0xfe434526, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
990 	{ "qb-rom1.bin",	0x2000, 0x55635447, 1 | BRF_PRG | BRF_ESS }, //  1
991 	{ "qb-rom0.bin",	0x2000, 0x8e318641, 1 | BRF_PRG | BRF_ESS }, //  2
992 
993 	{ "qb-snd1.bin",	0x0800, 0x15787c07, 2 | BRF_PRG | BRF_ESS }, //  3 audiocpu
994 	{ "qb-snd2.bin",	0x0800, 0x58437508, 2 | BRF_PRG | BRF_ESS }, //  4
995 
996 	{ "qb-bg0.bin",		0x1000, 0x7a9ba824, 3 | BRF_GRA }, //  5 bgtiles
997 	{ "qb-bg1.bin",		0x1000, 0x22e5b891, 3 | BRF_GRA }, //  6
998 
999 	{ "qb-fg3.bin",		0x2000, 0xdd436d3a, 4 | BRF_GRA }, //  7 sprites
1000 	{ "qb-fg2.bin",		0x2000, 0xf69b9483, 4 | BRF_GRA }, //  8
1001 	{ "qb-fg1.bin",		0x2000, 0x224e8356, 4 | BRF_GRA }, //  9
1002 	{ "qb-fg0.bin",		0x2000, 0x2f695b85, 4 | BRF_GRA }, // 10
1003 };
1004 
1005 STD_ROM_PICK(qbert)
1006 STD_ROM_FN(qbert)
1007 
1008 struct BurnDriver BurnDrvQbert = {
1009 	"qbert", NULL, NULL, "qbert", "1982",
1010 	"Q*bert (US set 1)\0", NULL, "Gottlieb", "Miscellaneous",
1011 	NULL, NULL, NULL, NULL,
1012 	BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0,
1013 	NULL, qbertRomInfo, qbertRomName, NULL, NULL, qbertSampleInfo, qbertSampleName, QbertInputInfo, QbertDIPInfo,
1014 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x10,
1015 	240, 256, 3, 4
1016 };
1017 
1018 
1019 // Q*bert (US set 2)
1020 
1021 static struct BurnRomInfo qbertaRomDesc[] = {
1022 	{ "qrom_2.bin",		0x2000, 0xb54a8ffc, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
1023 	{ "qrom_1.bin",		0x2000, 0x19d924e3, 1 | BRF_PRG | BRF_ESS }, //  1
1024 	{ "qrom_0.bin",		0x2000, 0x2e7fad1b, 1 | BRF_PRG | BRF_ESS }, //  2
1025 
1026 	{ "qb-snd1.bin",	0x0800, 0x15787c07, 2 | BRF_PRG | BRF_ESS }, //  3 audiocpu
1027 	{ "qb-snd2.bin",	0x0800, 0x58437508, 2 | BRF_PRG | BRF_ESS }, //  4
1028 
1029 	{ "qb-bg0.bin",		0x1000, 0x7a9ba824, 3 | BRF_GRA }, //  5 bgtiles
1030 	{ "qb-bg1.bin",		0x1000, 0x22e5b891, 3 | BRF_GRA }, //  6
1031 
1032 	{ "qb-fg3.bin",		0x2000, 0xdd436d3a, 4 | BRF_GRA }, //  7 sprites
1033 	{ "qb-fg2.bin",		0x2000, 0xf69b9483, 4 | BRF_GRA }, //  8
1034 	{ "qb-fg1.bin",		0x2000, 0x224e8356, 4 | BRF_GRA }, //  9
1035 	{ "qb-fg0.bin",		0x2000, 0x2f695b85, 4 | BRF_GRA }, // 10
1036 };
1037 
1038 STD_ROM_PICK(qberta)
1039 STD_ROM_FN(qberta)
1040 
1041 struct BurnDriver BurnDrvQberta = {
1042 	"qberta", "qbert", NULL, "qbert", "1982",
1043 	"Q*bert (US set 2)\0", NULL, "Gottlieb", "Miscellaneous",
1044 	NULL, NULL, NULL, NULL,
1045 	BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0,
1046 	NULL, qbertaRomInfo, qbertaRomName, NULL, NULL, qbertSampleInfo, qbertSampleName, QbertInputInfo, QbertDIPInfo,
1047 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x10,
1048 	240, 256, 3, 4
1049 };
1050 
1051 
1052 // Q*bert (Japan)
1053 
1054 static struct BurnRomInfo qbertjRomDesc[] = {
1055 	{ "qbj-rom2.bin",	0x2000, 0x67bb1cb2, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
1056 	{ "qbj-rom1.bin",	0x2000, 0xc61216e7, 1 | BRF_PRG | BRF_ESS }, //  1
1057 	{ "qbj-rom0.bin",	0x2000, 0x69679d5c, 1 | BRF_PRG | BRF_ESS }, //  2
1058 
1059 	{ "qb-snd1.bin",	0x0800, 0x15787c07, 2 | BRF_PRG | BRF_ESS }, //  3 audiocpu
1060 	{ "qb-snd2.bin",	0x0800, 0x58437508, 2 | BRF_PRG | BRF_ESS }, //  4
1061 
1062 	{ "qb-bg0.bin",		0x1000, 0x7a9ba824, 3 | BRF_GRA }, //  5 bgtiles
1063 	{ "qb-bg1.bin",		0x1000, 0x22e5b891, 3 | BRF_GRA }, //  6
1064 
1065 	{ "qb-fg3.bin",		0x2000, 0xdd436d3a, 4 | BRF_GRA }, //  7 sprites
1066 	{ "qb-fg2.bin",		0x2000, 0xf69b9483, 4 | BRF_GRA }, //  8
1067 	{ "qb-fg1.bin",		0x2000, 0x224e8356, 4 | BRF_GRA }, //  9
1068 	{ "qb-fg0.bin",		0x2000, 0x2f695b85, 4 | BRF_GRA }, // 10
1069 };
1070 
1071 STD_ROM_PICK(qbertj)
1072 STD_ROM_FN(qbertj)
1073 
1074 struct BurnDriver BurnDrvQbertj = {
1075 	"qbertj", "qbert", NULL, "qbert", "1982",
1076 	"Q*bert (Japan)\0", NULL, "Gottlieb (Konami license)", "Miscellaneous",
1077 	NULL, NULL, NULL, NULL,
1078 	BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0,
1079 	NULL, qbertjRomInfo, qbertjRomName, NULL, NULL, qbertSampleInfo, qbertSampleName, QbertInputInfo, QbertDIPInfo,
1080 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x10,
1081 	240, 256, 3, 4
1082 };
1083 
1084 
1085 // Mello Yello Q*bert
1086 
1087 static struct BurnRomInfo myqbertRomDesc[] = {
1088 	{ "mqb-rom2.bin",	0x2000, 0x6860f957, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
1089 	{ "mqb-rom1.bin",	0x2000, 0x11f0a4e4, 1 | BRF_PRG | BRF_ESS }, //  1
1090 	{ "mqb-rom0.bin",	0x2000, 0x12a90cb2, 1 | BRF_PRG | BRF_ESS }, //  2
1091 
1092 	{ "mqb-snd1.bin",	0x0800, 0x495ffcd2, 2 | BRF_PRG | BRF_ESS }, //  3 audiocpu
1093 	{ "mqb-snd2.bin",	0x0800, 0x9bbaa945, 2 | BRF_PRG | BRF_ESS }, //  4
1094 
1095 	{ "qb-bg0.bin",		0x1000, 0x7a9ba824, 3 | BRF_GRA }, //  5 bgtiles
1096 	{ "qb-bg1.bin",		0x1000, 0x22e5b891, 3 | BRF_GRA }, //  6
1097 
1098 	{ "mqb-fg3.bin",	0x2000, 0x8b5d0852, 4 | BRF_GRA }, //  7 sprites
1099 	{ "mqb-fg2.bin",	0x2000, 0x823f1e57, 4 | BRF_GRA }, //  8
1100 	{ "mqb-fg1.bin",	0x2000, 0x05343ae6, 4 | BRF_GRA }, //  9
1101 	{ "mqb-fg0.bin",	0x2000, 0xabc71bdd, 4 | BRF_GRA }, // 10
1102 };
1103 
1104 STD_ROM_PICK(myqbert)
1105 STD_ROM_FN(myqbert)
1106 
1107 struct BurnDriver BurnDrvMyqbert = {
1108 	"myqbert", "qbert", NULL, "qbert", "1982",
1109 	"Mello Yello Q*bert\0", NULL, "Gottlieb", "Miscellaneous",
1110 	NULL, NULL, NULL, NULL,
1111 	BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0,
1112 	NULL, myqbertRomInfo, myqbertRomName, NULL, NULL, qbertSampleInfo, qbertSampleName, QbertInputInfo, QbertDIPInfo,
1113 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x10,
1114 	240, 256, 3, 4
1115 };
1116 
DrvInitMplanets()1117 static INT32 DrvInitMplanets()
1118 {
1119 	game_type = 4;
1120 
1121 	return DrvInit();
1122 }
1123 
1124 
1125 // Faster, Harder, More Challenging Q*bert (prototype)
1126 
1127 static struct BurnRomInfo sqbertRomDesc[] = {
1128 	{ "qb-rom2.bin",	0x2000, 0x1e3d4038, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
1129 	{ "qb-rom1.bin",	0x2000, 0xeaf3076c, 1 | BRF_PRG | BRF_ESS }, //  1
1130 	{ "qb-rom0.bin",	0x2000, 0x61260a7e, 1 | BRF_PRG | BRF_ESS }, //  2
1131 
1132 	{ "qb-snd1.bin",	0x0800, 0x15787c07, 2 | BRF_PRG | BRF_ESS }, //  3 audiocpu
1133 	{ "qb-snd2.bin",	0x0800, 0x58437508, 2 | BRF_PRG | BRF_ESS }, //  4
1134 
1135 	{ "qb-bg0.bin",		0x1000, 0xc3118eef, 3 | BRF_GRA }, //  5 bgtiles
1136 	{ "qb-bg1.bin",		0x1000, 0x4f6d8075, 3 | BRF_GRA }, //  6
1137 
1138 	{ "qb-fg3.bin",		0x2000, 0xee595eda, 4 | BRF_GRA }, //  7 sprites
1139 	{ "qb-fg2.bin",		0x2000, 0x59884c78, 4 | BRF_GRA }, //  8
1140 	{ "qb-fg1.bin",		0x2000, 0x2a60e3ad, 4 | BRF_GRA }, //  9
1141 	{ "qb-fg0.bin",		0x2000, 0xb11ad9d8, 4 | BRF_GRA }, // 10
1142 };
1143 
1144 STD_ROM_PICK(sqbert)
1145 STD_ROM_FN(sqbert)
1146 
1147 struct BurnDriver BurnDrvSqbert = {
1148 	"sqbert", NULL, NULL, "qbert", "1983",
1149 	"Faster, Harder, More Challenging Q*bert (prototype)\0", NULL, "Mylstar", "Miscellaneous",
1150 	NULL, NULL, NULL, NULL,
1151 	BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0,
1152 	NULL, sqbertRomInfo, sqbertRomName, NULL, NULL, qbertSampleInfo, qbertSampleName, QbertInputInfo, QbertDIPInfo,
1153 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x10,
1154 	240, 256, 3, 4
1155 };
1156 
1157 // Mad Planets
1158 
1159 static struct BurnRomInfo mplanetsRomDesc[] = {
1160 	{ "rom4.c16",		0x2000, 0x5402077f, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
1161 	{ "rom3.c14-15",	0x2000, 0x5d18d740, 1 | BRF_PRG | BRF_ESS }, //  1
1162 	{ "rom2.c13-14",	0x2000, 0x960c3bb1, 1 | BRF_PRG | BRF_ESS }, //  2
1163 	{ "rom1.c12-13",	0x2000, 0xeb515f10, 1 | BRF_PRG | BRF_ESS }, //  3
1164 	{ "rom0.c11-12",	0x2000, 0x74de78aa, 1 | BRF_PRG | BRF_ESS }, //  4
1165 
1166 	{ "snd1",		    0x0800, 0x453193a1, 2 | BRF_PRG | BRF_ESS }, //  5 audiocpu
1167 	{ "snd2",		    0x0800, 0xf5ffc98f, 2 | BRF_PRG | BRF_ESS }, //  6
1168 
1169 	{ "bg0.e11-12",		0x1000, 0x709aa24c, 3 | BRF_GRA }, //  7 bgtiles
1170 	{ "bg1.e13",		0x1000, 0x4921e345, 3 | BRF_GRA }, //  8
1171 
1172 	{ "fg3.k7-8",		0x2000, 0xc990b39f, 4 | BRF_GRA }, //  9 sprites
1173 	{ "fg2.k6",		    0x2000, 0x735e2522, 4 | BRF_GRA }, // 10
1174 	{ "fg1.k5",		    0x2000, 0x6456cc1c, 4 | BRF_GRA }, // 11
1175 	{ "fg0.k4",		    0x2000, 0xa920e325, 4 | BRF_GRA }, // 12
1176 };
1177 
1178 STD_ROM_PICK(mplanets)
1179 STD_ROM_FN(mplanets)
1180 
1181 struct BurnDriver BurnDrvMplanets = {
1182 	"mplanets", NULL, NULL, NULL, "1983",
1183 	"Mad Planets\0", NULL, "Gottlieb", "Miscellaneous",
1184 	NULL, NULL, NULL, NULL,
1185 	BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL | BDF_ORIENTATION_FLIPPED, 2, HARDWARE_MISC_PRE90S, GBF_SHOOT, 0,
1186 	NULL, mplanetsRomInfo, mplanetsRomName, NULL, NULL, NULL, NULL, MplanetsInputInfo, MplanetsDIPInfo,
1187 	DrvInitMplanets, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x10,
1188 	240, 256, 3, 4
1189 };
1190 
1191 
1192 // Mad Planets (UK)
1193 
1194 static struct BurnRomInfo mplanetsukRomDesc[] = {
1195 	{ "mpt_rom4.bin",	0x2000, 0xcd88e23c, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
1196 	{ "mpt_rom3.bin",	0x2000, 0xdc355b2d, 1 | BRF_PRG | BRF_ESS }, //  1
1197 	{ "mpt_rom2.bin",	0x2000, 0x846ddc23, 1 | BRF_PRG | BRF_ESS }, //  2
1198 	{ "mpt_rom1.bin",	0x2000, 0x94d67b87, 1 | BRF_PRG | BRF_ESS }, //  3
1199 	{ "mpt_rom0.bin",	0x2000, 0xa9e30ad2, 1 | BRF_PRG | BRF_ESS }, //  4
1200 
1201 	{ "mpt_snd1.bin",	0x0800, 0x453193a1, 2 | BRF_PRG | BRF_ESS }, //  5 audiocpu
1202 	{ "mpt_snd2.bin",	0x0800, 0xf5ffc98f, 2 | BRF_PRG | BRF_ESS }, //  6
1203 
1204 	{ "mpt_bg0.bin",	0x1000, 0x709aa24c, 3 | BRF_GRA }, //  7 bgtiles
1205 	{ "mpt_bg1.bin",	0x1000, 0x4921e345, 3 | BRF_GRA }, //  8
1206 
1207 	{ "mpt_fg3.bin",	0x2000, 0xc990b39f, 4 | BRF_GRA }, //  9 sprites
1208 	{ "mpt_fg2.bin",	0x2000, 0x735e2522, 4 | BRF_GRA }, // 10
1209 	{ "mpt_fg1.bin",	0x2000, 0x6456cc1c, 4 | BRF_GRA }, // 11
1210 	{ "mpt_fg0.bin",	0x2000, 0xa920e325, 4 | BRF_GRA }, // 12
1211 };
1212 
1213 STD_ROM_PICK(mplanetsuk)
1214 STD_ROM_FN(mplanetsuk)
1215 
1216 struct BurnDriver BurnDrvMplanetsuk = {
1217 	"mplanetsuk", "mplanets", NULL, NULL, "1983",
1218 	"Mad Planets (UK)\0", NULL, "Gottlieb (Taitel license)", "Miscellaneous",
1219 	NULL, NULL, NULL, NULL,
1220 	BDF_GAME_WORKING | BDF_CLONE | BDF_ORIENTATION_VERTICAL | BDF_ORIENTATION_FLIPPED, 2, HARDWARE_MISC_PRE90S, GBF_SHOOT, 0,
1221 	NULL, mplanetsukRomInfo, mplanetsukRomName, NULL, NULL, NULL, NULL, MplanetsInputInfo, MplanetsDIPInfo,
1222 	DrvInitMplanets, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x10,
1223 	240, 256, 3, 4
1224 };
1225 
DrvInitCube()1226 static INT32 DrvInitCube()
1227 {
1228 	game_type = 6;
1229 
1230 	return DrvInit();
1231 }
1232 
1233 // Q*bert's Qubes
1234 
1235 static struct BurnRomInfo qbertqubRomDesc[] = {
1236 	{ "qq-rom3.bin",	0x2000, 0xc4dbdcd7, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
1237 	{ "qq-rom2.bin",	0x2000, 0x21a6c6cc, 1 | BRF_PRG | BRF_ESS }, //  1
1238 	{ "qq-rom1.bin",	0x2000, 0x63e6c43d, 1 | BRF_PRG | BRF_ESS }, //  2
1239 	{ "qq-rom0.bin",	0x2000, 0x8ddbe438, 1 | BRF_PRG | BRF_ESS }, //  3
1240 
1241 	{ "qq-snd1.bin",	0x0800, 0xe704b450, 2 | BRF_PRG | BRF_ESS }, //  4 audiocpu
1242 	{ "qq-snd2.bin",	0x0800, 0xc6a98bf8, 2 | BRF_PRG | BRF_ESS }, //  5
1243 
1244 	{ "qq-bg0.bin",		0x1000, 0x050badde, 3 | BRF_GRA }, //  6 bgtiles
1245 	{ "qq-bg1.bin",		0x1000, 0x8875902f, 3 | BRF_GRA }, //  7
1246 
1247 	{ "qq-fg3.bin",		0x4000, 0x91a949cc, 4 | BRF_GRA }, //  8 sprites
1248 	{ "qq-fg2.bin",		0x4000, 0x782d9431, 4 | BRF_GRA }, //  9
1249 	{ "qq-fg1.bin",		0x4000, 0x71c3ac4c, 4 | BRF_GRA }, // 10
1250 	{ "qq-fg0.bin",		0x4000, 0x6192853f, 4 | BRF_GRA }, // 11
1251 };
1252 
1253 STD_ROM_PICK(qbertqub)
1254 STD_ROM_FN(qbertqub)
1255 
1256 struct BurnDriver BurnDrvQbertqub = {
1257 	"qbertqub", NULL, NULL, "qbert", "1983",
1258 	"Q*bert's Qubes\0", NULL, "Mylstar", "Miscellaneous",
1259 	NULL, NULL, NULL, NULL,
1260 	BDF_GAME_WORKING | BDF_ORIENTATION_VERTICAL, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0,
1261 	NULL, qbertqubRomInfo, qbertqubRomName, NULL, NULL, qbertSampleInfo, qbertSampleName, QbertqubInputInfo, QbertqubDIPInfo,
1262 	DrvInitCube, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x10,
1263 	240, 256, 3, 4
1264 };
1265 
1266