1 // FB Alpha Knuckle Bash 2 driver module
2 // Driver and emulation by Jan Klaassen
3 
4 #include "toaplan.h"
5 // Knuckle Bash 2
6 
7 static UINT8 DrvButton[8] = {0, 0, 0, 0, 0, 0, 0, 0};
8 static UINT8 DrvJoy1[8] = {0, 0, 0, 0, 0, 0, 0, 0};
9 static UINT8 DrvJoy2[8] = {0, 0, 0, 0, 0, 0, 0, 0};
10 static UINT8 DrvInput[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
11 
12 static UINT8 DrvReset = 0;
13 static UINT8 bDrawScreen;
14 static bool bVBlank;
15 
16 static INT32 nPreviousOkiBank;
17 
18 static struct BurnRomInfo kbash2RomDesc[] = {
19 	{ "mecat-m",	0x080000, 0xbd2263c6, BRF_ESS | BRF_PRG }, //  0 CPU #0 code
20 
21 	{ "mecat-34",	0x400000, 0x6be7b37e, BRF_GRA },	   //  1 GP9001 Tile data
22 	{ "mecat-12",	0x400000, 0x49e46b1f, BRF_GRA },	   //  2
23 
24 	{ "mecat-s",	0x080000, 0x3eb7adf4, BRF_SND },	   //  3 oki1
25 
26 	{ "eprom",	0x040000, 0x31115cb9, BRF_SND },	   //  4 oki2
27 
28 	{ "050917-10",	0x010000, 0x6b213183, BRF_OPT },	   //  5 WTF is this?
29 };
30 
31 STD_ROM_PICK(kbash2)
32 STD_ROM_FN(kbash2)
33 
34 static struct BurnInputInfo Kbash2InputList[] = {
35 	{"P1 Coin",		BIT_DIGITAL,	DrvButton + 3,	"p1 coin"},
36 	{"P1 Start",		BIT_DIGITAL,	DrvButton + 5,	"p1 start"},
37 	{"P1 Up",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 up"},
38 	{"P1 Down",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 down"},
39 	{"P1 Left",		BIT_DIGITAL,	DrvJoy1 + 2,	"p1 left"},
40 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 3,	"p1 right"},
41 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 4,	"p1 fire 1"},
42 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy1 + 5,	"p1 fire 2"},
43 	{"P1 Button 3",		BIT_DIGITAL,	DrvJoy1 + 6,	"p1 fire 3"},
44 
45 	{"P2 Coin",		BIT_DIGITAL,	DrvButton + 4,	"p2 coin"},
46 	{"P2 Start",		BIT_DIGITAL,	DrvButton + 6,	"p2 start"},
47 	{"P2 Up",		BIT_DIGITAL,	DrvJoy2 + 0,	"p2 up"},
48 	{"P2 Down",		BIT_DIGITAL,	DrvJoy2 + 1,	"p2 down"},
49 	{"P2 Left",		BIT_DIGITAL,	DrvJoy2 + 2,	"p2 left"},
50 	{"P2 Right",		BIT_DIGITAL,	DrvJoy2 + 3,	"p2 right"},
51 	{"P2 Button 1",		BIT_DIGITAL,	DrvJoy2 + 4,	"p2 fire 1"},
52 	{"P2 Button 2",		BIT_DIGITAL,	DrvJoy2 + 5,	"p2 fire 2"},
53 	{"P2 Button 3",		BIT_DIGITAL,	DrvJoy2 + 6,	"p2 fire 3"},
54 
55 	{"Reset",		BIT_DIGITAL,	&DrvReset,	"reset"},
56 	{"Service",		BIT_DIGITAL,	DrvButton + 0,	"service"},
57 	{"Tilt",		BIT_DIGITAL,	DrvButton + 1,	"tilt"},
58 	{"Dip A",		BIT_DIPSWITCH,	DrvInput + 3,	"dip"},
59 	{"Dip B",		BIT_DIPSWITCH,	DrvInput + 4,	"dip"},
60 	{"Dip C",		BIT_DIPSWITCH,	DrvInput + 5,	"dip"},
61 };
62 
63 STDINPUTINFO(Kbash2)
64 
65 static struct BurnDIPInfo Kbash2DIPList[]=
66 {
67 	{0x15, 0xff, 0xff, 0x00, NULL		},
68 	{0x16, 0xff, 0xff, 0x00, NULL		},
69 	{0x17, 0xff, 0xff, 0x06, NULL		},
70 
71 	{0   , 0xfe, 0   ,    2, "Continue Mode"		},
72 	{0x15, 0x01, 0x01, 0x00, "Normal"		},
73 	{0x15, 0x01, 0x01, 0x01, "Discount"		},
74 
75 	{0   , 0xfe, 0   ,    2, "Flip Screen"		},
76 	{0x15, 0x01, 0x02, 0x00, "Off"		},
77 	{0x15, 0x01, 0x02, 0x02, "On"		},
78 
79 	{0   , 0xfe, 0   ,    2, "Service Mode"		},
80 	{0x15, 0x01, 0x04, 0x00, "Off"		},
81 	{0x15, 0x01, 0x04, 0x04, "On"		},
82 
83 	{0   , 0xfe, 0   ,    2, "Demo Sounds"		},
84 	{0x15, 0x01, 0x08, 0x08, "Off"		},
85 	{0x15, 0x01, 0x08, 0x00, "On"		},
86 
87 	{0   , 0xfe, 0   ,    7, "Coin A"		},
88 	{0x15, 0x01, 0x30, 0x30, "4 Coins 1 Credits"		},
89 	{0x15, 0x01, 0x30, 0x20, "3 Coins 1 Credits"		},
90 	{0x15, 0x01, 0x30, 0x10, "2 Coins 1 Credits"		},
91 	{0x15, 0x01, 0x30, 0x20, "2 Coins 1 Credits"		},
92 	{0x15, 0x01, 0x30, 0x00, "1 Coin  1 Credits"		},
93 	{0x15, 0x01, 0x30, 0x30, "2 Coins 3 Credits"		},
94 	{0x15, 0x01, 0x30, 0x10, "1 Coin  2 Credits"		},
95 
96 	{0   , 0xfe, 0   ,    8, "Coin B"		},
97 	{0x15, 0x01, 0xc0, 0x80, "2 Coins 1 Credits"		},
98 	{0x15, 0x01, 0xc0, 0x00, "1 Coin  1 Credits"		},
99 	{0x15, 0x01, 0xc0, 0xc0, "2 Coins 3 Credits"		},
100 	{0x15, 0x01, 0xc0, 0x40, "1 Coin  2 Credits"		},
101 	{0x15, 0x01, 0xc0, 0x00, "1 Coin  2 Credits"		},
102 	{0x15, 0x01, 0xc0, 0x40, "1 Coin  3 Credits"		},
103 	{0x15, 0x01, 0xc0, 0x80, "1 Coin  4 Credits"		},
104 	{0x15, 0x01, 0xc0, 0xc0, "1 Coin  6 Credits"		},
105 
106 	{0   , 0xfe, 0   ,    4, "Difficulty"		},
107 	{0x16, 0x01, 0x03, 0x03, "Hardest"		},
108 	{0x16, 0x01, 0x03, 0x02, "Hard"		},
109 	{0x16, 0x01, 0x03, 0x00, "Medium"		},
110 	{0x16, 0x01, 0x03, 0x01, "Easy"		},
111 
112 	{0   , 0xfe, 0   ,    4, "Bonus Life"		},
113 	{0x16, 0x01, 0x0c, 0x0c, "None"		},
114 	{0x16, 0x01, 0x0c, 0x08, "200k only"		},
115 	{0x16, 0x01, 0x0c, 0x04, "100k only"		},
116 	{0x16, 0x01, 0x0c, 0x00, "100k and 400k"		},
117 
118 	{0   , 0xfe, 0   ,    4, "Lives"		},
119 	{0x16, 0x01, 0x30, 0x30, "1"		},
120 	{0x16, 0x01, 0x30, 0x00, "2"		},
121 	{0x16, 0x01, 0x30, 0x20, "3"		},
122 	{0x16, 0x01, 0x30, 0x10, "4"		},
123 
124 	{0   , 0xfe, 0   ,    2, "Invulnerability"		},
125 	{0x16, 0x01, 0x40, 0x00, "Off"		},
126 	{0x16, 0x01, 0x40, 0x40, "On"		},
127 
128 	{0   , 0xfe, 0   ,    2, "Allow Continue"		},
129 	{0x16, 0x01, 0x80, 0x80, "No"		},
130 	{0x16, 0x01, 0x80, 0x00, "Yes"		},
131 
132 	{0   , 0xfe, 0   ,    7, "Territory"		},
133 	{0x17, 0x01, 0x0f, 0x00, "Japan (Taito Corp license)"		},
134 	{0x17, 0x01, 0x0f, 0x0e, "South East Asia"		},
135 	{0x17, 0x01, 0x0f, 0x06, "South East Asia (Charterfield license)"		},
136 	{0x17, 0x01, 0x0f, 0x0b, "Korea"		},
137 	{0x17, 0x01, 0x0f, 0x03, "Korea (Unite license)"		},
138 	{0x17, 0x01, 0x0f, 0x04, "Hong Kong"		},
139 	{0x17, 0x01, 0x0f, 0x05, "Taiwan"		},
140 };
141 
142 STDDIPINFO(Kbash2)
143 
144 static UINT8 *Mem = NULL, *MemEnd = NULL;
145 static UINT8 *RamStart, *RamEnd;
146 static UINT8 *Rom01;
147 static UINT8 *Ram01, *RamPal, *RamSnd;
148 static UINT8 *RomSnd;
149 
150 static INT32 nColCount = 0x0800;
151 
152 // This routine is called first to determine how much memory is needed (MemEnd-(UINT8 *)0),
153 // and then afterwards to set up all the pointers
MemIndex()154 static INT32 MemIndex()
155 {
156 	UINT8 *Next; Next = Mem;
157 	Rom01		= Next; Next += 0x080000;		// 68000 ROM
158 	MSM6295ROM	= Next;
159 	RomSnd		= Next; Next += 0x140000;
160 	GP9001ROM[0]= Next; Next += nGP9001ROMSize[0];	// GP9001 tile data
161 	RamStart	= Next;
162 	Ram01		= Next; Next += 0x004000;		// CPU #0 work RAM
163 	RamPal		= Next; Next += 0x001000;		// palette
164 	RamSnd		= Next; Next += 0x000100;		// sound work-ram
165 	GP9001RAM[0]= Next; Next += 0x004000;
166 	GP9001Reg[0]= (UINT16*)Next; Next += 0x0100 * sizeof(UINT16);
167 	RamEnd		= Next;
168 	ToaPalette	= (UINT32 *)Next; Next += nColCount * sizeof(UINT32);
169 	MemEnd		= Next;
170 
171 	return 0;
172 }
173 
oki_set_bank(INT32 bank)174 static void oki_set_bank(INT32 bank)
175 {
176 	bank &= 1;
177 	if (nPreviousOkiBank != bank) {
178 		nPreviousOkiBank = bank;
179 		memcpy (RomSnd + 0x000000, RomSnd + 0x40000 + (bank * 0x40000), 0x40000);
180 	}
181 }
182 
183 // Scan ram
DrvScan(INT32 nAction,INT32 * pnMin)184 static INT32 DrvScan(INT32 nAction,INT32 *pnMin)
185 {
186 	struct BurnArea ba;
187 
188 	if (pnMin) {						// Return minimum compatible version
189 		*pnMin = 0x020997;
190 	}
191 	if (nAction & ACB_VOLATILE) {		// Scan volatile ram
192 		memset(&ba, 0, sizeof(ba));
193 		ba.Data		= RamStart;
194 		ba.nLen		= RamEnd-RamStart;
195 		ba.szName	= "All Ram";
196 		BurnAcb(&ba);
197 
198 		SekScan(nAction);				// scan 68000 states
199 
200 		MSM6295Scan(nAction, pnMin);
201 
202 		ToaScanGP9001(nAction, pnMin);
203 
204 		SCAN_VAR(nPreviousOkiBank);
205 	}
206 
207 	if (nAction & ACB_WRITE) {
208 		INT32 nBank = nPreviousOkiBank;
209 		nPreviousOkiBank = -1;
210 		oki_set_bank(nBank);
211 	}
212 
213 	return 0;
214 }
215 
LoadRoms()216 static INT32 LoadRoms()
217 {
218 	// Load 68000 ROM
219 	BurnLoadRom(Rom01, 0, 1);
220 
221 	// Load GP9001 tile data
222 	ToaLoadGP9001Tiles(GP9001ROM[0], 1, 2, nGP9001ROMSize[0]);
223 
224 	if (BurnLoadRom(RomSnd + 0x040000, 3, 1)) return 1;
225 	if (BurnLoadRom(RomSnd + 0x100000, 4, 1)) return 1;
226 
227 	return 0;
228 }
229 
kbash2ReadByte(UINT32 sekAddress)230 static UINT8 __fastcall kbash2ReadByte(UINT32 sekAddress)
231 {
232 	switch (sekAddress) {
233 
234 		case 0x200005:								// Dipswitch 1
235 			return DrvInput[3];
236 		case 0x200009:								// Dipswitch 2
237 			return DrvInput[4];
238 		case 0x20000d:								// Dipswitch 3 - Territory
239 			return DrvInput[5];
240 
241 		case 0x200011:								// Player 1 Input
242 			return DrvInput[0];
243 		case 0x200015:			   					// Player 2 Input
244 			return DrvInput[1];
245 		case 0x200019:								// System...
246 			return DrvInput[2];
247 
248 		case 0x200021:
249 			return MSM6295Read(1);
250 
251 		case 0x200025:
252 			return MSM6295Read(0);
253 
254 		case 0x20002D:
255 			return ToaScanlineRegister();
256 
257 		case 0x30000d:								// VBlank
258 			return ToaVBlankRegister();
259 
260 //		default:
261 //			printf("Attempt to read byte value of location %x\n", sekAddress);
262 	}
263 
264 	return 0;
265 }
266 
kbash2ReadWord(UINT32 sekAddress)267 static UINT16 __fastcall kbash2ReadWord(UINT32 sekAddress)
268 {
269 	switch (sekAddress) {
270 
271 		case 0x200004:								// Dipswitch 1
272 			return DrvInput[3];
273 		case 0x200008:								// Dipswitch 2
274 			return DrvInput[4];
275 		case 0x20000c:								// Dipswitch 3 - Territory
276 			return DrvInput[5];
277 
278 		case 0x200010:								// Player 1 Input
279 			return DrvInput[0];
280 		case 0x200014:			   					// Player 2 Input
281 			return DrvInput[1];
282 		case 0x200018:								// System...
283 			return DrvInput[2];
284 
285 		case 0x200020:
286 			return MSM6295Read(1);
287 
288 		case 0x200024:
289 			return MSM6295Read(0);
290 
291 		case 0x20002c:
292 			return ToaScanlineRegister();
293 
294 		case 0x300004:
295 			return ToaGP9001ReadRAM_Hi(0);
296 		case 0x300006:
297 			return ToaGP9001ReadRAM_Lo(0);
298 
299 		case 0x30000C:								// VBlank
300 			return ToaVBlankRegister();
301 
302 //		default:
303 //			printf("Attempt to read word value of location %x\n", sekAddress);
304 	}
305 
306 	return 0;
307 }
308 
kbash2WriteByte(UINT32 sekAddress,UINT8 byteValue)309 static void __fastcall kbash2WriteByte(UINT32 sekAddress, UINT8 byteValue)
310 {
311 	switch (sekAddress) {
312 		case 0x200021:
313 			MSM6295Write(1, byteValue);
314 		return;
315 
316 		case 0x200025:
317 			MSM6295Write(0, byteValue);
318 		return;
319 
320 		case 0x200029:
321 			oki_set_bank(byteValue);
322 		return;
323 
324 //		default:
325 //			printf("Attempt to write byte value %x to location %x\n", byteValue, sekAddress);
326 	}
327 }
328 
kbash2WriteWord(UINT32 sekAddress,UINT16 wordValue)329 static void __fastcall kbash2WriteWord(UINT32 sekAddress, UINT16 wordValue)
330 {
331 	switch (sekAddress) {
332 		case 0x300000:								// Set GP9001 VRAM address-pointer
333 			ToaGP9001SetRAMPointer(wordValue);
334 			break;
335 
336 		case 0x300004:
337 			ToaGP9001WriteRAM(wordValue, 0);
338 			break;
339 		case 0x300006:
340 			ToaGP9001WriteRAM(wordValue, 0);
341 			break;
342 
343 		case 0x300008:
344 			ToaGP9001SelectRegister(wordValue);
345 			break;
346 
347 		case 0x30000C:
348 			ToaGP9001WriteRegister(wordValue);
349 			break;
350 
351 //		default:
352 //			printf("Attempt to write word value %x to location %x\n", wordValue, sekAddress);
353 	}
354 }
355 
DrvDoReset()356 static INT32 DrvDoReset()
357 {
358 	SekOpen(0);
359 	SekReset();
360 	SekClose();
361 
362 	MSM6295Reset();
363 
364 	nPreviousOkiBank = -1;
365 	oki_set_bank(0);
366 
367 	return 0;
368 }
369 
DrvInit()370 static INT32 DrvInit()
371 {
372 	INT32 nLen;
373 
374 #ifdef DRIVER_ROTATION
375 	bToaRotateScreen = false;
376 #endif
377 
378 	nGP9001ROMSize[0] = 0x800000;
379 
380 	// Find out how much memory is needed
381 	Mem = NULL;
382 	MemIndex();
383 	nLen = MemEnd - (UINT8 *)0;
384 	if ((Mem = (UINT8 *)BurnMalloc(nLen)) == NULL) {
385 		return 1;
386 	}
387 	memset(Mem, 0, nLen);										// blank all memory
388 	MemIndex();													// Index the allocated memory
389 
390 	// Load the roms into memory
391 	if (LoadRoms()) {
392 		return 1;
393 	}
394 
395 	{
396 		SekInit(0, 0x68000);								// Allocate 68000
397 		SekOpen(0);
398 		SekMapMemory(Rom01,		0x000000, 0x07FFFF, MAP_ROM);
399 		SekMapMemory(Ram01,		0x100000, 0x103FFF, MAP_RAM);
400 		SekMapMemory(RamSnd,	0x104000, 0x1040FF, MAP_RAM);
401 		SekMapMemory(RamPal,		0x400000, 0x400FFF, MAP_RAM);
402 		SekSetReadWordHandler(0, 	kbash2ReadWord);
403 		SekSetReadByteHandler(0, 	kbash2ReadByte);
404 		SekSetWriteWordHandler(0, 	kbash2WriteWord);
405 		SekSetWriteByteHandler(0, 	kbash2WriteByte);
406 
407 		SekClose();
408 	}
409 
410 	MSM6295Init(0, 1000000 / 132, 1);
411 	MSM6295Init(1, 1000000 / 132, 1);
412 	MSM6295SetRoute(0, 1.00, BURN_SND_ROUTE_BOTH);
413 	MSM6295SetRoute(1, 1.00, BURN_SND_ROUTE_BOTH);
414 
415 	nSpriteYOffset = 0x0011;
416 
417 	nLayer0XOffset = -0x01D6;
418 	nLayer1XOffset = -0x01D8;
419 	nLayer2XOffset = -0x01DA;
420 
421 	ToaInitGP9001();
422 
423 	nToaPalLen = nColCount;
424 	ToaPalSrc = RamPal;
425 	ToaPalInit();
426 
427 	bDrawScreen = true;
428 
429 	DrvDoReset();			// Reset machine
430 	return 0;
431 }
432 
DrvExit()433 static INT32 DrvExit()
434 {
435 	ToaPalExit();
436 
437 	ToaExitGP9001();
438 	SekExit();				// Deallocate 68000s
439 
440 	MSM6295Exit();
441 
442 	BurnFree(Mem);
443 
444 	return 0;
445 }
446 
DrvDraw()447 static INT32 DrvDraw()
448 {
449 	ToaClearScreen(0);
450 
451 	if (bDrawScreen) {
452 		ToaGetBitmap();
453 		ToaRenderGP9001();					// Render GP9001 graphics
454 	}
455 
456 	ToaPalUpdate();							// Update the palette
457 
458 	return 0;
459 }
460 
CheckSleep(INT32)461 inline static INT32 CheckSleep(INT32)
462 {
463 	return 0;
464 }
465 
DrvFrame()466 static INT32 DrvFrame()
467 {
468 	INT32 nInterleave = 4;
469 
470 	if (DrvReset) {														// Reset machine
471 		DrvDoReset();
472 	}
473 
474 	// Compile digital inputs
475 	DrvInput[0] = 0x00;													// Buttons
476 	DrvInput[1] = 0x00;													// Player 1
477 	DrvInput[2] = 0x00;													// Player 2
478 	for (INT32 i = 0; i < 8; i++) {
479 		DrvInput[0] |= (DrvJoy1[i] & 1) << i;
480 		DrvInput[1] |= (DrvJoy2[i] & 1) << i;
481 		DrvInput[2] |= (DrvButton[i] & 1) << i;
482 	}
483 	ToaClearOpposites(&DrvInput[0]);
484 	ToaClearOpposites(&DrvInput[1]);
485 
486 	SekNewFrame();
487 
488 	nCyclesTotal[0] = (INT32)((INT64)16000000 * nBurnCPUSpeedAdjust / (0x0100 * 60));
489 	nCyclesDone[0] = 0;
490 
491 	SekOpen(0);
492 
493 	SekSetCyclesScanline(nCyclesTotal[0] / 262);
494 	nToaCyclesDisplayStart = nCyclesTotal[0] - ((nCyclesTotal[0] * (TOA_VBLANK_LINES + 240)) / 262);
495 	nToaCyclesVBlankStart = nCyclesTotal[0] - ((nCyclesTotal[0] * TOA_VBLANK_LINES) / 262);
496 	bVBlank = false;
497 
498 	for (INT32 i = 0; i < nInterleave; i++) {
499     	INT32 nCurrentCPU;
500 		INT32 nNext;
501 
502 		// Run 68000
503 		nCurrentCPU = 0;
504 		nNext = (i + 1) * nCyclesTotal[nCurrentCPU] / nInterleave;
505 
506 
507 		// Trigger VBlank interrupt
508 		if (!bVBlank && nNext > nToaCyclesVBlankStart) {
509 			if (nCyclesDone[nCurrentCPU] < nToaCyclesVBlankStart) {
510 				nCyclesSegment = nToaCyclesVBlankStart - nCyclesDone[nCurrentCPU];
511 				nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
512 			}
513 
514 			bVBlank = true;
515 
516 			ToaBufferGP9001Sprites();
517 
518 			// Trigger VBlank interrupt
519 			SekSetIRQLine(4, CPU_IRQSTATUS_AUTO);
520 		}
521 
522 		nCyclesSegment = nNext - nCyclesDone[nCurrentCPU];
523 		if (bVBlank || (!CheckSleep(nCurrentCPU))) {					// See if this CPU is busywaiting
524 			nCyclesDone[nCurrentCPU] += SekRun(nCyclesSegment);
525 		} else {
526 			nCyclesDone[nCurrentCPU] += SekIdle(nCyclesSegment);
527 		}
528 
529 	}
530 
531 	if (pBurnSoundOut) {
532 		memset (pBurnSoundOut, 0, nBurnSoundLen * 2 * sizeof(INT16));
533 		MSM6295Render(pBurnSoundOut, nBurnSoundLen);
534 	}
535 
536 	SekClose();
537 
538 	if (pBurnDraw) {
539 		DrvDraw();												// Draw screen if needed
540 	}
541 
542 	return 0;
543 }
544 
545 struct BurnDriver BurnDrvKbash2 = {
546 	"kbash2", NULL, NULL, NULL, "1999",
547 	"Knuckle Bash 2 (bootleg)\0", NULL, "bootleg", "Toaplan GP9001 based",
548 	L"Knuckle Bash 2\0Knuckle Bash \u30CA\u30C3\u30AF\u30EB\u30D0\u30C3\u30B7\u30E5 \uFF12 (bootleg)\0", NULL, NULL, NULL,
549 	BDF_GAME_WORKING | BDF_BOOTLEG, 2, HARDWARE_TOAPLAN_68K_ONLY, GBF_SCRFIGHT, 0,
550 	NULL, kbash2RomInfo, kbash2RomName, NULL, NULL, NULL, NULL, Kbash2InputInfo, Kbash2DIPInfo,
551 	DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &ToaRecalcPalette, 0x800,
552 	320, 240, 4, 3
553 };
554