1 // FB Alpha pengadvb arcade driver module based on hap's mame driver
2 
3 #include "tiles_generic.h"
4 #include "z80_intf.h"
5 #include "tms9928a.h"
6 #include "8255ppi.h"
7 #include "bitswap.h"
8 #include "ay8910.h"
9 
10 static UINT8 *AllMem	= NULL;
11 static UINT8 *MemEnd	= NULL;
12 static UINT8 *AllRam	= NULL;
13 static UINT8 *RamEnd	= NULL;
14 static UINT8 *maincpu	= NULL;
15 static UINT8 *game	= NULL;
16 static UINT8 *main_mem	= NULL;
17 
18 static UINT8 DrvInputs[2];
19 static UINT8 DrvJoy1[8];
20 static UINT8 DrvJoy2[8];
21 static UINT8 DrvReset;
22 static UINT8 DrvNMI;
23 
24 static UINT8 msxmode = 0;
25 static UINT8 mem_map = 0;
26 static UINT8 mem_banks[4];
27 
28 static struct BurnInputInfo PengadvbInputList[] = {
29 	{"P1 Coin",		BIT_DIGITAL,	DrvJoy2 + 0,	"p1 coin"	},
30 	{"P1 Up",		BIT_DIGITAL,	DrvJoy1 + 0,	"p1 up"		},
31 	{"P1 Down",		BIT_DIGITAL,	DrvJoy1 + 1,	"p1 down"	},
32 	{"P1 Left",		BIT_DIGITAL,	DrvJoy1 + 2,	"p1 left"	},
33 	{"P1 Right",		BIT_DIGITAL,	DrvJoy1 + 3,	"p1 right"	},
34 	{"P1 Button 1",		BIT_DIGITAL,	DrvJoy1 + 4,	"p1 fire 1"	},
35 	{"P1 Button 2",		BIT_DIGITAL,	DrvJoy1 + 5,	"p1 fire 2"	},
36 
37 	{"Reset",		BIT_DIGITAL,	&DrvReset,	"reset"	},
38 };
39 
STDINPUTINFO(Pengadvb)40 STDINPUTINFO(Pengadvb)
41 
42 static void __fastcall msx_write_port(UINT16 port, UINT8 data)
43 {
44 	port &= 0xff;
45 	switch (port)
46 	{
47 		case 0x98:
48 			TMS9928AWriteVRAM(data);
49 		return;
50 
51 		case 0x99:
52 			TMS9928AWriteRegs(data);
53 		return;
54 
55 		case 0xa0:
56 			AY8910Write(0, 0, data);
57 		break;
58 
59 		case 0xa1:
60 			AY8910Write(0, 1, data);
61 		break;
62 
63 		case 0xa8:
64 		case 0xa9:
65 		case 0xaa:
66 		case 0xab:
67 			ppi8255_w(0, port & 3, data);
68 		return;
69 	}
70 
71 	//bprintf(0, _T("port[%X] data[%X],"), port, data);
72 }
73 
msx_read_port(UINT16 port)74 static UINT8 __fastcall msx_read_port(UINT16 port)
75 {
76 	port &= 0xff;
77 
78 	switch (port)
79 	{
80 		case 0x98:
81 			return TMS9928AReadVRAM();
82 
83 		case 0x99:
84 			return TMS9928AReadRegs();
85 
86 		case 0xa2:
87 			return AY8910Read(0);
88 
89 		case 0xa8:
90 		case 0xa9:
91 		case 0xaa:
92 		case 0xab:
93 		    return ppi8255_r(0, port & 3);
94 	}
95 
96 	//bprintf(0, _T("port[%X],"), port);
97 
98 	return 0;
99 }
100 
mem_map_banks()101 static void mem_map_banks()
102 {
103 	int slot_select;
104 
105 	// page 0
106 	slot_select = (mem_map >> 0) & 0x03;
107 	switch(slot_select)
108 	{
109 		case 0:
110 			{
111 				ZetMapMemory(maincpu, 0x0000, 0x3fff, MAP_READ | MAP_FETCH);
112 				break;
113 			}
114 		case 1:
115 		case 2:
116 		case 3:
117 			{
118 				ZetUnmapMemory(0x0000, 0x3fff, MAP_READ | MAP_FETCH);
119 				break;
120 			}
121 	}
122 
123 	// page 1
124 	slot_select = (mem_map >> 2) & 0x03;
125 	switch(slot_select)
126 	{
127 		case 0:
128 		{
129 			ZetMapMemory(maincpu + 0x4000, 0x4000, 0x5fff, MAP_READ | MAP_FETCH);
130 			ZetMapMemory(maincpu + 0x6000, 0x6000, 0x7fff, MAP_READ | MAP_FETCH);
131 			break;
132 		}
133 		case 1:
134 		{
135 			ZetMapMemory(game + mem_banks[0]*0x2000, 0x4000, 0x5fff, MAP_READ | MAP_FETCH);
136 			ZetMapMemory(game + mem_banks[1]*0x2000, 0x6000, 0x7fff, MAP_READ | MAP_FETCH);
137 			break;
138 		}
139 		case 2:
140 		case 3:
141 			{
142 				ZetUnmapMemory(0x4000, 0x7fff, MAP_READ | MAP_FETCH);
143 			break;
144 		}
145 	}
146 
147 	// page 2
148 	slot_select = (mem_map >> 4) & 0x03;
149 	switch(slot_select)
150 	{
151 		case 1:
152 		{
153 			ZetMapMemory(game + mem_banks[2]*0x2000, 0x8000, 0x9fff, MAP_READ | MAP_FETCH);
154 			ZetMapMemory(game + mem_banks[3]*0x2000, 0xa000, 0xbfff, MAP_READ | MAP_FETCH);
155 			break;
156 		}
157 		case 0:
158 		case 2:
159 		case 3:
160 		{
161 			ZetUnmapMemory(0x8000, 0xbfff, MAP_READ | MAP_FETCH);
162 			break;
163 		}
164 	}
165 
166 	// page 3
167 	slot_select = (mem_map >> 6) & 0x03;
168 
169 	switch(slot_select)
170 	{
171 		case 0:
172 		case 1:
173 		case 2:
174 		{
175 			ZetUnmapMemory(0xc000, 0xffff, MAP_READ | MAP_FETCH);
176 			break;
177 		}
178 		case 3:
179 		{
180 			ZetMapMemory(main_mem, 0xc000, 0xffff, MAP_READ | MAP_FETCH);
181 			break;
182 		}
183 	}
184 
185 }
186 
sg1000_ppi8255_portB_read()187 static UINT8 sg1000_ppi8255_portB_read()
188 {
189 	if ((ppi8255_r(0, 2) & 0x0f) == 0)
190 		return DrvInputs[1];
191 
192 	return 0xff;
193 
194 }
195 
sg1000_ppi8255_portA_write(UINT8 data)196 static void sg1000_ppi8255_portA_write(UINT8 data)
197 {
198 	mem_map = data;
199 	mem_map_banks();
200 }
201 
202 static UINT8 msx_input_mask = 0;
203 
ay8910portAread(UINT32)204 static UINT8 ay8910portAread(UINT32 /*offset*/)
205 {
206 	return DrvInputs[0];
207 }
208 
ay8910portBwrite(UINT32,UINT32 data)209 static void ay8910portBwrite(UINT32 /*offset*/, UINT32 data)
210 {
211 	/* PSG reg 15, writes 0 at coin insert, 0xff at boot and game over */
212 	msx_input_mask = data;
213 }
214 
vdp_interrupt(INT32 state)215 static void vdp_interrupt(INT32 state)
216 {
217 	ZetSetIRQLine(0, state ? CPU_IRQSTATUS_ACK : CPU_IRQSTATUS_NONE);
218 }
219 
DrvDoReset()220 static INT32 DrvDoReset()
221 {
222 	memset (AllRam, 0, RamEnd - AllRam);
223 
224 	ZetOpen(0);
225 	ZetReset();
226 	TMS9928AReset();
227 	mem_map = 0;
228 	mem_banks[0] = mem_banks[1] = mem_banks[2] = mem_banks[3] = 0;
229 	mem_map_banks();
230 	ZetClose();
231 
232 	AY8910Reset(0);
233 
234 	return 0;
235 }
236 
MemIndex()237 static INT32 MemIndex()
238 {
239 	UINT8 *Next; Next = AllMem;
240 
241 	maincpu		= Next; Next += 0x020000;
242 	game		= Next; Next += 0x020000;
243 
244 	AllRam		= Next;
245 
246 	main_mem	= Next; Next += 0x010400;
247 
248 	RamEnd		= Next;
249 
250 	MemEnd		= Next;
251 
252 	return 0;
253 }
254 
msx_write(UINT16 address,UINT8 data)255 static void __fastcall msx_write(UINT16 address, UINT8 data)
256 {
257 	if (address >= 0xc000)
258 	{
259 		int slot_select = (mem_map >> 6) & 0x03;
260 
261 		if ( slot_select == 3 )
262 		{
263 			main_mem[address - 0xc000] = data;
264 		}
265 	}
266 	else
267 	{
268 		switch(address)
269 		{
270 			case 0x4000: mem_banks[0] = data; mem_map_banks(); break;
271 			case 0x6000: mem_banks[1] = data; mem_map_banks(); break;
272 			case 0x8000: mem_banks[2] = data; mem_map_banks(); break;
273 			case 0xa000: mem_banks[3] = data; mem_map_banks(); break;
274 		}
275 	}
276 	//bprintf(0, _T("a[%X] d[%X],"), address, data);
277 }
278 
msx_read(UINT16)279 static UINT8 __fastcall msx_read(UINT16 /*address*/)
280 {
281 	//bprintf(0, _T("a[%X],"), address);
282 	return 0;
283 }
284 
pengadvb_decrypt(UINT8 * mem,INT32 memsize)285 static void pengadvb_decrypt(UINT8 *mem, INT32 memsize)
286 {
287 	UINT8 *buf;
288 	int i;
289 
290 	// data lines swap
291 	for ( i = 0; i < memsize; i++ )
292 	{
293 		mem[i] = BITSWAP08(mem[i],7,6,5,3,4,2,1,0);
294 	}
295 
296 	// address line swap
297 	buf = (UINT8 *)BurnMalloc(memsize);
298 	memcpy(buf, mem, memsize);
299 	for ( i = 0; i < memsize; i++ )
300 	{
301 		mem[i] = buf[BITSWAP24(i,23,22,21,20,19,18,17,16,15,14,13,5,11,10,9,8,7,6,12,4,3,2,1,0)];
302 	}
303 	BurnFree(buf);
304 }
305 
DrvInit()306 static INT32 DrvInit()
307 {
308 	AllMem = NULL;
309 	MemIndex();
310 	INT32 nLen = MemEnd - (UINT8 *)0;
311 	if ((AllMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
312 	memset(AllMem, 0, nLen);
313 	MemIndex();
314 
315 	{
316 		if (BurnLoadRom(maincpu, 0, 1)) return 1;
317 
318 		if (msxmode) {
319 			if (BurnLoadRom(game + 0x00000, 1, 1)) return 1;
320 		} else {
321 			if (BurnLoadRom(game + 0x00000, 1, 1)) return 1;
322 			if (BurnLoadRom(game + 0x08000, 2, 1)) return 1;
323 			if (BurnLoadRom(game + 0x10000, 3, 1)) return 1;
324 			if (BurnLoadRom(game + 0x18000, 4, 1)) return 1;
325 			pengadvb_decrypt(game, 0x20000);
326 			//FILE * f = fopen("c:\\penga.rom", "wb+");
327 			//fwrite(game, 1, 0x20000, f);
328 			//fclose(f);
329 		}
330 
331 		pengadvb_decrypt(maincpu, 0x8000);
332 	}
333 
334 	ZetInit(0);
335 	ZetOpen(0);
336 
337 	ZetSetOutHandler(msx_write_port);
338 	ZetSetInHandler(msx_read_port);
339 	ZetSetWriteHandler(msx_write);
340 	ZetSetReadHandler(msx_read);
341 	ZetClose();
342 
343 	AY8910Init(0, 3579545/2, 0);
344 	AY8910SetPorts(0, ay8910portAread, NULL, NULL, ay8910portBwrite);
345 	AY8910SetAllRoutes(0, 0.50, BURN_SND_ROUTE_BOTH);
346 
347 	TMS9928AInit(TMS99x8A, 0x4000, 0, 0, vdp_interrupt);
348 
349 	ppi8255_init(1);
350 	ppi8255_set_read_ports(0, NULL, sg1000_ppi8255_portB_read, NULL);
351 	ppi8255_set_write_ports(0, sg1000_ppi8255_portA_write, NULL, NULL);
352 
353 	DrvDoReset();
354 
355 	return 0;
356 }
357 
DrvExit()358 static INT32 DrvExit()
359 {
360 	TMS9928AExit();
361 	ZetExit();
362 	AY8910Exit(0);
363 	ppi8255_exit();
364 
365 	BurnFree (AllMem);
366 	AllMem = NULL;
367 
368 	msxmode = 0;
369 
370 	return 0;
371 }
372 
DrvFrame()373 static INT32 DrvFrame()
374 {
375 	static UINT8 lastnmi = 0;
376 
377 	if (DrvReset) {
378 		DrvDoReset();
379 	}
380 
381 	{ // Compile Inputs
382 		memset (DrvInputs, 0xff, 2);
383 		for (INT32 i = 0; i < 8; i++) {
384 			DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
385 			if (i==6 || i==7)
386 				DrvInputs[1] ^= (DrvJoy1[i] & 1) << i;
387 			else
388 				DrvInputs[1] ^= (DrvJoy2[i] & 1) << i;
389 		}
390 	}
391 
392 	INT32 nInterleave = 256;
393 	INT32 nCyclesTotal[1] = { 3579545 / 60 };
394 	INT32 nCyclesDone[1] = { 0 };
395 	INT32 nSoundBufferPos = 0;
396 
397 	ZetOpen(0);
398 
399 	if (DrvNMI && !lastnmi) {
400 		ZetNmi();
401 		lastnmi = DrvNMI;
402 	} else lastnmi = DrvNMI;
403 
404 	for (INT32 i = 0; i < nInterleave; i++)
405 	{
406 		nCyclesDone[0] += ZetRun(nCyclesTotal[0] / nInterleave);
407 
408 		TMS9928AScanline(i);
409 
410 		// Render Sound Segment
411 		if (pBurnSoundOut) {
412 			INT32 nSegmentLength = nBurnSoundLen / nInterleave;
413 			INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
414 			AY8910Render(pSoundBuf, nSegmentLength);
415 			nSoundBufferPos += nSegmentLength;
416 		}
417 	}
418 
419 	ZetClose();
420 
421 	// Make sure the buffer is entirely filled.
422 	if (pBurnSoundOut) {
423 		INT32 nSegmentLength = nBurnSoundLen - nSoundBufferPos;
424 		INT16* pSoundBuf = pBurnSoundOut + (nSoundBufferPos << 1);
425 		if (nSegmentLength) {
426 			AY8910Render(pSoundBuf, nSegmentLength);
427 		}
428 	}
429 
430 	if (pBurnDraw) {
431 		TMS9928ADraw();
432 	}
433 
434 	return 0;
435 }
436 
DrvScan(INT32 nAction,INT32 * pnMin)437 static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
438 {
439 	struct BurnArea ba;
440 
441 	if (pnMin) {
442 		*pnMin = 0x029708;
443 	}
444 
445 	if (nAction & ACB_VOLATILE) {
446 		memset(&ba, 0, sizeof(ba));
447 
448 		ba.Data	  = AllRam;
449 		ba.nLen	  = RamEnd - AllRam;
450 		ba.szName = "All Ram";
451 		BurnAcb(&ba);
452 
453 		ZetScan(nAction);
454 		AY8910Scan(nAction, pnMin);
455 		TMS9928AScan(nAction, pnMin);
456 	}
457 
458 	return 0;
459 }
460 
461 
462 // Penguin Adventure (bootleg of MSX version)
463 
464 static struct BurnRomInfo pengadvbRomDesc[] = {
465 	{ "rom.u5",	0x8000, 0xd21950d2, 1 | BRF_PRG | BRF_ESS }, //  0 maincpu
466 
467 	{ "rom.u7",	0x8000, 0xd4b4a4a4, 2 | BRF_GRA },           //  1 game
468 	{ "rom.u8",	0x8000, 0xeada2232, 2 | BRF_GRA },           //  2
469 	{ "rom.u9",	0x8000, 0x6478c561, 2 | BRF_GRA },           //  3
470 	{ "rom.u10",	0x8000, 0x5c48360f, 2 | BRF_GRA },           //  4
471 };
472 
473 STD_ROM_PICK(pengadvb)
474 STD_ROM_FN(pengadvb)
475 
476 struct BurnDriver BurnDrvPengadvb = {
477 	"pengadvb", NULL, NULL, NULL, "1988",
478 	"Penguin Adventure (bootleg of MSX version)\0", NULL, "bootleg (Screen) / Konami", "Miscellaneous",
479 	NULL, NULL, NULL, NULL,
480 	BDF_GAME_WORKING, 2, HARDWARE_MISC_PRE90S, GBF_ACTION, 0,
481 	NULL, pengadvbRomInfo, pengadvbRomName, NULL, NULL, NULL, NULL, PengadvbInputInfo, NULL,
482 	DrvInit, DrvExit, DrvFrame, TMS9928ADraw, DrvScan, NULL, TMS9928A_PALETTE_SIZE,
483 	272, 216, 4, 3
484 };
485