1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli,Acho A. Tang, R. Belmont
3 
4 // K052109
5 
6 #include "tiles_generic.h"
7 #include "konamiic.h"
8 
9 static UINT8 *K052109Ram = NULL;
10 
11 typedef void (*K052109_Callback)(INT32 Layer, INT32 Bank, INT32 *Code, INT32 *Colour, INT32 *xFlip, INT32 *Priority);
12 static K052109_Callback K052109Callback;
13 static INT32 K052109ScrollX[3];
14 static INT32 K052109ScrollY[3];
15 static UINT8 K052109ScrollCtrl;
16 static UINT8 K052109CharRomBank[4];
17 static UINT8 K052109CharRomBank2[4];
18 INT32 K052109RMRDLine;
19 static UINT8 K052109RomSubBank;
20 static UINT32 K052109RomMask;
21 static UINT8 *K052109Rom;
22 static UINT32 K052109RomExpMask;
23 static UINT8 *K052109RomExp;
24 
25 static INT32 K052109FlipEnable;
26 INT32 K052109_irq_enabled;
27 
28 static INT32 K052109ScrollXOff[3];
29 static INT32 K052109ScrollYOff[3];
30 
31 static INT32 K052109EnableRows[3];
32 static INT32 K052109EnableLine[3];
33 static INT32 K052109ScrollRows[3][256];
34 static INT32 K052109EnableCols[3];
35 static INT32 K052109ScrollCols[3][64];
36 
37 static INT32 has_extra_video_ram = 0; // xmen kludge
38 
update_scroll_one(INT32 nLayer,INT32 control,INT32 ram_offset)39 static void update_scroll_one(INT32 nLayer, INT32 control, INT32 ram_offset)
40 {
41 	K052109EnableLine[nLayer] = 0;
42 	K052109EnableRows[nLayer] = 1;
43 	K052109EnableCols[nLayer] = 1;
44 
45 	UINT8 *sourceram = K052109Ram + ram_offset;
46 
47 	if ((control & 0x03) == 0x02 || (control & 0x03) == 0x03)
48 	{
49 		K052109EnableLine[nLayer] = 1;
50 
51 		K052109EnableRows[nLayer] = 256;
52 
53 		INT32 andval = ((control & 0x03) == 0x02) ? 0xfff8 : 0xffff;
54 		UINT8 *scrollram = &sourceram[0x1a00];
55 		INT32 yscroll = sourceram[0x180c];
56 
57 		if (nLayer == 2 && (control & 0x03) == 0x02 && K052109ScrollCtrl == 0x70) {
58 			yscroll = sourceram[0x1823]; // hack for suratk 2nd boss rotating star field
59 		}
60 
61 		for (INT32 offs = 0; offs < 256; offs++)
62 		{
63 			INT32 xscroll = scrollram[2 * (offs & andval) + 0] + 256 * scrollram[2 * (offs & andval) + 1];
64 			K052109ScrollRows[nLayer][(offs + yscroll)&0xff] = xscroll - 6;
65 		}
66 
67 		K052109EnableCols[nLayer] = 1;
68 		K052109ScrollCols[nLayer][0] = yscroll;
69 	}
70 	else if ((control & 0x04) == 0x04)
71 	{
72 	//	K052109EnableLine[nLayer] = 1;
73 
74 		UINT8 *scrollram = &sourceram[0x1800];
75 		INT32 xscroll = (sourceram[0x1a00] + 256 * sourceram[0x1a01]) - 6;
76 
77 		K052109EnableCols[nLayer] = 64;
78 		for (INT32 offs = 0; offs < 512/8; offs++)
79 		{
80 			K052109ScrollCols[nLayer][(((offs*8)+xscroll)&0x1f8)/8] = scrollram[offs];
81 		}
82 
83 		K052109EnableRows[nLayer] = 1;
84 		K052109ScrollRows[nLayer][0] = K052109ScrollX[nLayer] = xscroll;
85 	}
86 	else
87 	{
88 		K052109EnableRows[nLayer] = K052109EnableCols[nLayer] = 1;
89 		K052109ScrollX[nLayer] = (sourceram[0x1a00] + 256 * sourceram[0x1a01]) - 6;
90 		K052109ScrollY[nLayer] = sourceram[0x180c];
91 	}
92 }
93 
K052109UpdateScroll()94 void K052109UpdateScroll()
95 {
96 	update_scroll_one(1, K052109ScrollCtrl >> 0, 0x0000);
97 	update_scroll_one(2, K052109ScrollCtrl >> 3, 0x2000);
98 }
99 
K052109AdjustScroll(INT32 x,INT32 y)100 void K052109AdjustScroll(INT32 x, INT32 y)
101 {
102 	for (INT32 i = 0; i < 3; i++) {
103 		K052109ScrollXOff[i] = x;
104 		K052109ScrollYOff[i] = y;
105 	}
106 }
107 
K052109RenderLayerLineScroll(INT32 nLayer,INT32 Flags,INT32 Priority)108 void K052109RenderLayerLineScroll(INT32 nLayer, INT32 Flags, INT32 Priority)
109 {
110 	INT32 Category = Flags & 0xff;
111 	INT32 Opaque = (Flags >> 16) & 1;
112 
113 	UINT32 *dst = konami_bitmap32;
114 	UINT8 *pdst = konami_priority_bitmap;
115 
116 	INT32 ram_offset = nLayer * 0x800;
117 
118 	INT32 rowdiv = 256 / K052109EnableRows[nLayer];
119 
120 	for (INT32 y = 0; y < nScreenHeight; y++)
121 	{
122 		for (INT32 x = 0; x < nScreenWidth + 8; x+=8)
123 		{
124 			INT32 yy = (y + (K052109ScrollCols[nLayer][0] + K052109ScrollYOff[nLayer] + 16)) & 0xff;
125 			INT32 xx = (x + (K052109ScrollRows[nLayer][yy/rowdiv] + K052109ScrollXOff[nLayer] + 104)) & 0x1ff;
126 
127 			INT32 TileIndex = (xx/8) + ((yy/8)*64);
128 
129 			INT32 Colour = K052109Ram[TileIndex + ram_offset];
130 			INT32 Code = K052109Ram[TileIndex + 0x2000 + ram_offset] + (K052109Ram[TileIndex + 0x4000 + ram_offset] << 8);
131 
132 			INT32 Bank = K052109CharRomBank[(Colour & 0x0c) >> 2];
133 			if (has_extra_video_ram) Bank = (Colour & 0x0c) >> 2;	// kludge for X-Men
134 
135 			Colour = (Colour & 0xf3) | ((Bank & 0x03) << 2);
136 			Bank >>= 2;
137 
138 			INT32 yFlip = Colour & 0x02;
139 			INT32 xFlip = 0;
140 			INT32 Prio = 0;
141 
142 			K052109Callback(nLayer, Bank, &Code, &Colour, &xFlip, &Prio);
143 
144 			if (Prio != Category && Category) continue;
145 
146 			if (xFlip && !(K052109FlipEnable & 1)) xFlip = 0;
147 			if (yFlip && !(K052109FlipEnable & 2)) yFlip = 0;
148 
149 			UINT8 *src = K052109RomExp + ((Code & K052109RomExpMask) * 0x40) + ((yFlip ? (~yy & 7) : (yy & 7)) * 8);
150 			UINT32 *pal = konami_palette32 + (Colour * 16);
151 
152 			if (xFlip) xFlip = 0x07;
153 
154 			INT32 xv = xx & 0x07;
155 
156 			for (INT32 dx = 0; dx < 8; dx++)
157 			{
158 				if ((x+dx-xv) < 0 || (x+dx-xv) >= nScreenWidth) continue;
159 
160 				INT32 pxl = src[dx^xFlip];
161 				if (!Opaque && !pxl) continue;
162 
163 				dst[x+dx-xv] = pal[pxl];
164 				pdst[x+dx-xv] = Priority;
165 			}
166 		}
167 
168 		pdst += nScreenWidth;
169 		dst += nScreenWidth;
170 	}
171 }
172 
K052109RenderLayer(INT32 nLayer,INT32 Flags,INT32 Priority)173 void K052109RenderLayer(INT32 nLayer, INT32 Flags, INT32 Priority)
174 {
175 	nLayer &= 0x03;
176 
177 	// Row and line scroll.
178 	if (K052109EnableLine[nLayer]) {
179 		K052109RenderLayerLineScroll(nLayer, Flags, Priority);
180 		return;
181 	}
182 
183 	INT32 EnableCategory = Flags & 0x100;
184 	INT32 Category = Flags & 0xff;
185 
186 	INT32 Opaque = (Flags >> 16) & 1;
187 	INT32 ram_offset = nLayer * 0x800;
188 
189 	INT32 mx, my, Bank, Code, Colour, x, y, xFlip = 0, yFlip, TileIndex = 0;
190 
191 	for (my = 0; my < 32; my++) {
192 		for (mx = 0; mx < 64; mx++) {
193 			TileIndex = (my << 6) | mx;
194 
195 			Colour = K052109Ram[TileIndex + ram_offset];
196 			Code = K052109Ram[TileIndex + 0x2000 + ram_offset] + (K052109Ram[TileIndex + 0x4000 + ram_offset] << 8);
197 
198 			Bank = K052109CharRomBank[(Colour & 0x0c) >> 2];
199 			if (has_extra_video_ram) Bank = (Colour & 0x0c) >> 2;	// kludge for X-Men
200 
201 			Colour = (Colour & 0xf3) | ((Bank & 0x03) << 2);
202 			Bank >>= 2;
203 
204 			yFlip = Colour & 0x02;
205 
206 			INT32 Prio = 0;
207 
208 			K052109Callback(nLayer, Bank, &Code, &Colour, &xFlip, &Prio);
209 
210 			if (Prio != Category && EnableCategory) continue;
211 
212 			if (xFlip && !(K052109FlipEnable & 1)) xFlip = 0;
213 			if (yFlip && !(K052109FlipEnable & 2)) yFlip = 0;
214 
215 			x = 8 * mx;
216 			y = 8 * my;
217 
218 			INT32 scrollx = K052109ScrollX[nLayer] + K052109ScrollXOff[nLayer];
219 			INT32 scrolly = K052109ScrollYOff[nLayer];
220 
221 			x -= (scrollx + 104) & 0x1ff;
222 			if (x < -7) x += 512;
223 
224 			if (K052109EnableCols[nLayer] == 64) {
225 				scrolly += K052109ScrollCols[nLayer][((mx*8)&0x1ff)/8];
226 			} else {
227 				scrolly += K052109ScrollY[nLayer];
228 			}
229 
230 			y -= (scrolly + 16) & 0xff;
231 			if (y < -7) y += 256;
232 
233 			if (x >= nScreenWidth || y >= nScreenHeight) continue;
234 
235 			{
236 				UINT32 *dst = konami_bitmap32 + y * nScreenWidth + x;
237 				UINT8 *pri = konami_priority_bitmap + y * nScreenWidth + x;
238 				UINT8 *gfx = K052109RomExp + (Code & K052109RomExpMask) * 0x40;
239 
240 				INT32 flip = 0;
241 				if (xFlip) flip |= 0x07;
242 				if (yFlip) flip |= 0x38;
243 
244 				UINT32 *pal = konami_palette32 + (Colour * 16);
245 				INT32 trans = (Opaque) ? 0xffff : 0;
246 
247 				for (INT32 yy = 0; yy < 8; yy++, y++)
248 				{
249 					if (y >= 0 && y < nScreenHeight)
250 					{
251 						for (INT32 xx = 0; xx < 8; xx++)
252 						{
253 							if ((x+xx) >= 0 && (x+xx) < nScreenWidth)
254 							{
255 								INT32 pxl = gfx[((yy*8)+xx)^flip];
256 
257 								if (pxl != trans)
258 								{
259 									dst[xx] = pal[pxl];
260 									pri[xx] = Priority;
261 								}
262 							}
263 						}
264 					}
265 
266 					dst += nScreenWidth;
267 					pri += nScreenWidth;
268 				}
269 			}
270 		}
271 	}
272 }
273 
K052109Read(UINT32 Offset)274 UINT8 K052109Read(UINT32 Offset)
275 {
276 	if (Offset > 0x5fff) return 0;
277 
278 	if (K052109RMRDLine) {
279 		INT32 Flags = 0;
280 		INT32 Code = (Offset & 0x1fff) >> 5;
281 		INT32 Colour = K052109RomSubBank;
282 		INT32 Bank  =  K052109CharRomBank[(Colour & 0x0c) >> 2] >> 2;
283 			  Bank |= (K052109CharRomBank2[(Colour & 0x0c) >> 2] >> 2);
284 
285 		if (has_extra_video_ram)
286 			Code |= Colour << 8;	/* kludge for X-Men */
287 		else
288 			K052109Callback(0, Bank, &Code, &Colour, &Flags, &Flags /*actually priority*/);
289 
290 		INT32 Addr = (Code << 5) + (Offset & 0x1f);
291 		Addr &= K052109RomMask;
292 
293 		return K052109Rom[Addr];
294 	}
295 
296 	return K052109Ram[Offset];
297 }
298 
K052109Write(UINT32 Offset,UINT8 Data)299 void K052109Write(UINT32 Offset, UINT8 Data)
300 {
301 	if (Offset > 0x5fff) return;
302 
303 	K052109Ram[Offset] = Data;
304 
305 	if (Offset >= 0x4000) has_extra_video_ram = 1;  /* kludge for X-Men */
306 
307 	if ((Offset & 0x1fff) >= 0x1800) {
308 		switch (Offset) {
309 			case 0x1c80: {
310 				K052109ScrollCtrl = Data;
311 				return;
312 			}
313 
314 			case 0x1d00: {
315 				K052109_irq_enabled = Data & 0x04;
316 				return;
317 			}
318 
319 			case 0x1d80: {
320 				K052109CharRomBank[0] = Data & 0x0f;
321 				K052109CharRomBank[1] = (Data >> 4) & 0x0f;
322 				return;
323 			}
324 
325 			case 0x1e00: // Normal..
326 			case 0x3e00: // Suprise Attack
327 			{
328 				K052109RomSubBank = Data;
329 				return;
330 			}
331 
332 			case 0x1e80: {
333 				// flip
334 				K052109FlipEnable = ((Data & 0x06) >> 1);
335 				return;
336 			}
337 
338 			case 0x1f00: {
339 				K052109CharRomBank[2] = Data & 0x0f;
340 				K052109CharRomBank[3] = (Data >> 4) & 0x0f;
341 				return;
342 			}
343 
344 			case 0x3d80: // Surprise Attack (rom test)
345 			{
346 //				K052109CharRomBank2[0];
347 //				K052109CharRomBank2[1];
348 				return;
349 			}
350 
351 			case 0x3f00: // Surprise Attack (rom test)
352 			{
353 //				K052109CharRomBank2[2];
354 //				K052109CharRomBank2[3];
355 				return;
356 			}
357 
358 			case 0x180c:
359 			case 0x180d:
360 			case 0x1a00:
361 			case 0x1a01:
362 			case 0x380c:
363 			case 0x380d:
364 			case 0x3a00:
365 			case 0x3a01: {
366 				// Scroll Writes
367 				return;
368 			}
369 
370 			case 0x1c00: {
371 				//???
372 				return;
373 			}
374 		}
375 	}
376 }
377 
K052109SetCallback(void (* Callback)(INT32 Layer,INT32 Bank,INT32 * Code,INT32 * Colour,INT32 * xFlip,INT32 * Priority))378 void K052109SetCallback(void (*Callback)(INT32 Layer, INT32 Bank, INT32 *Code, INT32 *Colour, INT32 *xFlip, INT32 *Priority))
379 {
380 	K052109Callback = Callback;
381 }
382 
K052109Reset()383 void K052109Reset()
384 {
385 	memset(K052109ScrollX, 0, 3 * sizeof(INT32));
386 	memset(K052109ScrollY, 0, 3 * sizeof(INT32));
387 	K052109ScrollCtrl = 0;
388 	memset(K052109CharRomBank, 0, 4);
389 	memset(K052109CharRomBank2,0, 4);
390 	K052109RMRDLine = 0;
391 	K052109RomSubBank = 0;
392 	K052109_irq_enabled = 0;
393 	memset (K052109Ram, 0, 0x6000);
394 
395 	memset (K052109EnableRows, 0, 3 * sizeof(INT32));
396 	memset (K052109EnableLine, 0, 3 * sizeof(INT32));
397 	memset (K052109ScrollRows, 0, 256 * 3 * sizeof(INT32));
398 	memset (K052109EnableCols, 0, 3 * sizeof(INT32));
399 	memset (K052109ScrollCols, 0, 64 * 3 * sizeof(INT32));
400 }
401 
K052109GfxDecode(UINT8 * src,UINT8 * dst,INT32 nLen)402 void K052109GfxDecode(UINT8 *src, UINT8 *dst, INT32 nLen)
403 {
404 	INT32 Plane[4] = { STEP4(24, -8) };
405 	INT32 XOffs[8] = { STEP8(0, 1) };
406 	INT32 YOffs[8] = { STEP8(0, 32) };
407 
408 	GfxDecode((nLen * 2) / (8 * 8), 4, 8, 8, Plane, XOffs, YOffs, 0x100, src, dst);
409 }
410 
K052109Init(UINT8 * pRomSrc,UINT8 * pRomSrcExp,UINT32 RomMask)411 void K052109Init(UINT8 *pRomSrc, UINT8 *pRomSrcExp, UINT32 RomMask)
412 {
413 	K052109Ram = (UINT8*)BurnMalloc(0x6000);
414 
415 	K052109RomMask = RomMask;
416 	K052109RomExpMask = (RomMask * 2) / (8 * 8);
417 
418 	K052109Rom = pRomSrc;
419 	K052109RomExp = pRomSrcExp;
420 
421 	KonamiIC_K052109InUse = 1;
422 
423 	for (INT32 i = 0; i < 3; i++) {
424 		K052109ScrollXOff[i]=0;
425 		K052109ScrollYOff[i]=0;
426 	}
427 
428 	KonamiAllocateBitmaps();
429 
430 	has_extra_video_ram = 0;
431 }
432 
K052109Exit()433 void K052109Exit()
434 {
435 	BurnFree(K052109Ram);
436 
437 	K052109Callback = NULL;
438 	K052109RomMask = 0;
439 	K052109Rom = NULL;
440 
441 	memset(K052109ScrollX, 0, sizeof(K052109ScrollX));
442 	memset(K052109ScrollY, 0, sizeof(K052109ScrollY));
443 	K052109ScrollCtrl = 0;
444 	memset(K052109CharRomBank, 0, 4);
445 	K052109RMRDLine = 0;
446 	K052109RomSubBank = 0;
447 	K052109FlipEnable = 0;
448 	K052109_irq_enabled = 0;
449 
450 	has_extra_video_ram = 0;
451 }
452 
K052109Scan(INT32 nAction)453 void K052109Scan(INT32 nAction)
454 {
455 	struct BurnArea ba;
456 
457 	if (nAction & ACB_MEMORY_RAM) {
458 		memset(&ba, 0, sizeof(ba));
459 		ba.Data	  = K052109Ram;
460 		ba.nLen	  = 0x6000;
461 		ba.szName = "K052109 Ram";
462 		BurnAcb(&ba);
463 	}
464 
465 	if (nAction & ACB_DRIVER_DATA) {
466 		SCAN_VAR(K052109ScrollX);
467 		SCAN_VAR(K052109ScrollY);
468 		SCAN_VAR(K052109ScrollCtrl);
469 		SCAN_VAR(K052109CharRomBank);
470 		SCAN_VAR(K052109CharRomBank2);
471 		SCAN_VAR(K052109RMRDLine);
472 		SCAN_VAR(K052109RomSubBank);
473 		SCAN_VAR(K052109FlipEnable);
474 		SCAN_VAR(K052109_irq_enabled);
475 		SCAN_VAR(has_extra_video_ram);
476 
477 		SCAN_VAR(K052109EnableRows);
478 		SCAN_VAR(K052109EnableLine);
479 		SCAN_VAR(K052109ScrollRows);
480 		SCAN_VAR(K052109EnableCols);
481 		SCAN_VAR(K052109ScrollCols);
482 
483 	}
484 }
485