1 // license:BSD-3-Clause
2 // copyright-holders:R. Belmont, Acho A. Tang, Phil Stroffolino, Olivier Galibert
3 /*
4  * video/konamigx.cpp - Konami GX video hardware (here there be dragons, and achocode)
5  *
6  */
7 
8 #include "emu.h"
9 #include "video/k053250.h"
10 #include "includes/konamigx.h"
11 
12 
13 //#define GX_DEBUG
14 #define VERBOSE 0
15 
16 
17 static inline void set_color_555(palette_device &palette, pen_t color, int rshift, int gshift, int bshift, uint16_t data);
18 
19 
konamigx_precache_registers(void)20 void konamigx_state::konamigx_precache_registers(void)
21 {
22 	// (see sprite color coding scheme on p.46 & 47)
23 	static const int coregmasks[5] = {0xf,0xe,0xc,0x8,0x0};
24 	static const int coregshifts[5]= {4,5,6,7,8};
25 	int i;
26 
27 	i = m_k055673->k053247_read_register(0x8/2);
28 	m_k053247_vrcbk[0] = (i & 0x000f) << 14;
29 	m_k053247_vrcbk[1] = (i & 0x0f00) << 6;
30 	i = m_k055673->k053247_read_register(0xa/2);
31 	m_k053247_vrcbk[2] = (i & 0x000f) << 14;
32 	m_k053247_vrcbk[3] = (i & 0x0f00) << 6;
33 
34 	// COREG == OBJSET2+1C == bit8-11 of OPSET ??? (see p.50 last table, needs p.49 to confirm)
35 	m_k053247_opset = m_k055673->k053247_read_register(0xc/2);
36 
37 	i = m_k053247_opset & 7; if (i > 4) i = 4;
38 
39 	m_k053247_coreg = m_k055673->k053247_read_register(0xc/2)>>8 & 0xf;
40 	m_k053247_coreg =(m_k053247_coreg & coregmasks[i]) << 12;
41 
42 	m_k053247_coregshift = coregshifts[i];
43 
44 	m_opri     = m_k055555->K055555_read_register(K55_PRIINP_8);
45 	m_oinprion = m_k055555->K055555_read_register(K55_OINPRI_ON);
46 	m_vcblk[0] = m_k055555->K055555_read_register(K55_PALBASE_A);
47 	m_vcblk[1] = m_k055555->K055555_read_register(K55_PALBASE_B);
48 	m_vcblk[2] = m_k055555->K055555_read_register(K55_PALBASE_C);
49 	m_vcblk[3] = m_k055555->K055555_read_register(K55_PALBASE_D);
50 	m_vcblk[4] = m_k055555->K055555_read_register(K55_PALBASE_SUB1);
51 	m_vcblk[5] = m_k055555->K055555_read_register(K55_PALBASE_SUB2);
52 	m_ocblk    = m_k055555->K055555_read_register(K55_PALBASE_OBJ);
53 	m_vinmix   = m_k055555->K055555_read_register(K55_BLEND_ENABLES);
54 	m_vmixon   = m_k055555->K055555_read_register(K55_VINMIX_ON);
55 	m_osinmix  = m_k055555->K055555_read_register(K55_OSBLEND_ENABLES);
56 	m_osmixon  = m_k055555->K055555_read_register(K55_OSBLEND_ON);
57 }
58 
K053247GX_combine_c18(int attrib)59 inline int konamigx_state::K053247GX_combine_c18(int attrib) // (see p.46)
60 {
61 	int c18;
62 
63 	c18 = (attrib & 0xff)<<m_k053247_coregshift | m_k053247_coreg;
64 
65 	if (m_gx_wrport2 & 4) c18 &= 0x3fff; else
66 	if (!(m_gx_wrport2 & 8)) c18 = (c18 & 0x3fff) | (attrib<<6 & 0xc000);
67 
68 	return(c18);
69 }
70 
K055555GX_decode_objcolor(int c18)71 inline int konamigx_state::K055555GX_decode_objcolor(int c18) // (see p.59 7.2.2)
72 {
73 	int ocb, opon;
74 
75 	opon  = m_oinprion<<8 | 0xff;
76 	ocb   = (m_ocblk & 7) << 10;
77 	c18  &= opon;
78 	ocb  &=~opon;
79 
80 	return((ocb | c18) >> m_k053247_coregshift);
81 }
82 
K055555GX_decode_inpri(int c18)83 inline int konamigx_state::K055555GX_decode_inpri(int c18) // (see p.59 7.2.2)
84 {
85 	int op = m_opri;
86 
87 	c18 >>= 8;
88 	op   &= m_oinprion;
89 	c18  &=~m_oinprion;
90 
91 	return(c18 | op);
92 }
93 
K055673_CB_MEMBER(konamigx_state::type2_sprite_callback)94 K055673_CB_MEMBER(konamigx_state::type2_sprite_callback)
95 {
96 	int num = *code;
97 	int c18 = *color;
98 
99 	*code = m_k053247_vrcbk[num>>14] | (num & 0x3fff);
100 	c18 = K053247GX_combine_c18(c18);
101 	*color = K055555GX_decode_objcolor(c18);
102 	*priority_mask = K055555GX_decode_inpri(c18);
103 }
104 
K055673_CB_MEMBER(konamigx_state::dragoonj_sprite_callback)105 K055673_CB_MEMBER(konamigx_state::dragoonj_sprite_callback)
106 {
107 	int num, op, pri, c18;
108 
109 	num = *code;
110 	*code = m_k053247_vrcbk[num>>14] | (num & 0x3fff);
111 
112 	c18  = pri = *color;
113 	op   = m_opri;
114 	pri  = (pri & 0x200) ? 4 : pri>>4 & 0xf;
115 	op  &= m_oinprion;
116 	pri &=~m_oinprion;
117 	*priority_mask = pri | op;
118 
119 	c18 = K053247GX_combine_c18(c18);
120 	*color = K055555GX_decode_objcolor(c18);
121 }
122 
K055673_CB_MEMBER(konamigx_state::salmndr2_sprite_callback)123 K055673_CB_MEMBER(konamigx_state::salmndr2_sprite_callback)
124 {
125 	int num, op, pri, c18;
126 
127 	num = *code;
128 	*code = m_k053247_vrcbk[num>>14] | (num & 0x3fff);
129 
130 	c18  = pri = *color;
131 	op   = m_opri;
132 	pri  = pri>>4 & 0x3f;
133 	op  &= m_oinprion;
134 	pri &=~m_oinprion;
135 	*priority_mask = pri | op;
136 
137 	c18 = K053247GX_combine_c18(c18);
138 	*color = K055555GX_decode_objcolor(c18);
139 }
140 
K055673_CB_MEMBER(konamigx_state::le2_sprite_callback)141 K055673_CB_MEMBER(konamigx_state::le2_sprite_callback)
142 {
143 	int num, op, pri;
144 
145 	num = *code;
146 	*code = m_k053247_vrcbk[num>>14] | (num & 0x3fff);
147 
148 	pri = *color;
149 	*color &= 0x1f;
150 
151 	op   = m_opri;
152 	pri &= 0xf0;
153 	op  &= m_oinprion;
154 	pri &=~m_oinprion;
155 	*priority_mask = pri | op;
156 }
157 
K055555GX_decode_vmixcolor(int layer,int * color)158 int konamigx_state::K055555GX_decode_vmixcolor(int layer, int *color) // (see p.62 7.2.6 and p.27 3.3)
159 {
160 	int vcb, shift, pal, vmx, von, pl45, emx;
161 
162 	vcb    =  m_vcblk[layer]<<6;
163 	shift  =  layer<<1;
164 	pal    =  *color;
165 	vmx    =  m_vinmix>>shift & 3;
166 	von    =  m_vmixon>>shift & 3;
167 	emx    =  pl45 = pal>>4 & 3;
168 	pal   &=  0xf;
169 	pl45  &=  von;
170 	vmx   &=  von;
171 	pl45 <<=  4;
172 	emx   &= ~von;
173 	pal   |=  pl45;
174 	emx   |=  vmx;
175 	pal   |=  vcb;
176 
177 	//if (m_gx_le2_textcolour_hack)
178 	//  if (layer==0)
179 	//      pal |= 0x1c0;
180 
181 	if (von == 3) emx = -1; // invalidate external mix code if all bits are from internal
182 	*color =  pal;
183 
184 	return(emx);
185 }
186 
187 #ifdef UNUSED_FUNCTION
K055555GX_decode_osmixcolor(int layer,int * color)188 int K055555GX_decode_osmixcolor(int layer, int *color) // (see p.63, p.49-50 and p.27 3.3)
189 {
190 	int scb, shift, pal, osmx, oson, pl45, emx;
191 
192 	shift  =  layer<<1;
193 	pal    =  *color;
194 	osmx   =  m_osinmix>>shift & 3;
195 	oson   =  m_osmixon>>shift & 3;
196 
197 	if (layer)
198 	{
199 		// layer 1-3 are external tile layers
200 		scb    =  m_vcblk[layer+3]<<6;
201 		emx    =  pl45 = pal>>4 & 3;
202 		pal   &=  0xf;
203 		pl45  &=  oson;
204 		osmx  &=  oson;
205 		pl45 <<=  4;
206 		emx   &= ~oson;
207 		pal   |=  pl45;
208 		emx   |=  osmx;
209 		pal   |=  scb;
210 
211 		if (oson == 3) emx = -1; // invalidate external mix code if all bits are from internal
212 		*color =  pal;
213 	}
214 	else
215 	{
216 		// layer 0 is the sprite layer with different attributes decode; detail on p.49 (missing)
217 		emx   = 0; // k053247_read_register(??)>>? & 3;
218 		osmx &= oson;
219 		emx  &=~oson;
220 		emx  |= osmx;
221 	}
222 
223 	return(emx);
224 }
225 #endif
226 
wipezbuf(int noshadow)227 void konamigx_state::wipezbuf(int noshadow)
228 {
229 	const rectangle &visarea = m_screen->visible_area();
230 
231 	int w = visarea.width();
232 	int h = visarea.height();
233 
234 	uint8_t *zptr = m_gx_objzbuf;
235 	int ecx = h;
236 
237 	do { memset(zptr, -1, w); zptr += GX_ZBUFW; } while (--ecx);
238 
239 	if (!noshadow)
240 	{
241 		zptr = m_gx_shdzbuf.get();
242 		w <<= 1;
243 		ecx = h;
244 		do { memset(zptr, -1, w); zptr += (GX_ZBUFW<<1); } while (--ecx);
245 	}
246 }
247 
248 /*
249  * Sprite Format
250  * ------------------
251  *
252  * Word | Bit(s)           | Use
253  * -----+-fedcba9876543210-+----------------
254  *   0  | x--------------- | active (show this sprite)
255  *   0  | -x-------------- | maintain aspect ratio (when set, zoom y acts on both axis)
256  *   0  | --x------------- | flip y
257  *   0  | ---x------------ | flip x
258  *   0  | ----xxxx-------- | sprite size (see below)
259  *   0  | --------xxxxxxxx | zcode
260  *   1  | xxxxxxxxxxxxxxxx | sprite code
261  *   2  | ------xxxxxxxxxx | y position
262  *   3  | ------xxxxxxxxxx | x position
263  *   4  | xxxxxxxxxxxxxxxx | zoom y (0x40 = normal, <0x40 = enlarge, >0x40 = reduce)
264  *   5  | xxxxxxxxxxxxxxxx | zoom x (0x40 = normal, <0x40 = enlarge, >0x40 = reduce)
265  *   6  | x--------------- | mirror y (top half is drawn as mirror image of the bottom)
266  *   6  | -x-------------- | mirror x (right half is drawn as mirror image of the left)
267  *   6  | --xx------------ | reserved (sprites with these two bits set don't seem to be graphics data at all)
268  *   6  | ----xx---------- | shadow code: 0=off, 0x400=preset1, 0x800=preset2, 0xc00=preset3
269  *   6  | ------xx-------- | effect code: flicker, upper palette, full shadow...etc. (game dependent)
270  *   6  | --------xxxxxxxx | "color", but depends on external connections (implies priority)
271  *   7  | xxxxxxxxxxxxxxxx | game dependent
272  *
273  * shadow enables transparent shadows. Note that it applies to the last sprite pen ONLY.
274  * The rest of the sprite remains normal.
275  */
276 #define GX_MAX_SPRITES 512*2
277 #define GX_MAX_LAYERS  6
278 #define GX_MAX_OBJECTS (GX_MAX_SPRITES + GX_MAX_LAYERS)
279 
280 static struct GX_OBJ { int order, offs, code, color; } *gx_objpool;
281 
konamigx_mixer_init(screen_device & screen,int objdma)282 void konamigx_state::konamigx_mixer_init(screen_device &screen, int objdma)
283 {
284 	m_gx_objdma = 0;
285 	m_gx_primode = 0;
286 
287 	m_gx_objzbuf = &screen.priority().pix(0);
288 	m_gx_shdzbuf = std::make_unique<uint8_t[]>(GX_ZBUFSIZE);
289 	gx_objpool = auto_alloc_array(machine(), struct GX_OBJ, GX_MAX_OBJECTS);
290 
291 	m_k054338->export_config(&m_K054338_shdRGB);
292 
293 	if (objdma)
294 	{
295 		m_gx_spriteram = auto_alloc_array(machine(), uint16_t, 0x2000/2);
296 		m_gx_objdma = 1;
297 	}
298 	else
299 		m_k055673->k053247_get_ram(&m_gx_spriteram);
300 
301 	m_palette->set_shadow_dRGB32(3,-80,-80,-80, 0);
302 	m_k054338->invert_alpha(1);
303 }
304 
konamigx_mixer_primode(int mode)305 void konamigx_state::konamigx_mixer_primode(int mode)
306 {
307 	m_gx_primode = mode;
308 }
309 
konamigx_objdma(void)310 void konamigx_state::konamigx_objdma(void)
311 {
312 	uint16_t* k053247_ram;
313 	m_k055673->k053247_get_ram(&k053247_ram);
314 
315 	if (m_gx_objdma && m_gx_spriteram && k053247_ram) memcpy(m_gx_spriteram, k053247_ram, 0x1000);
316 }
317 
konamigx_mixer(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect,tilemap_t * sub1,int sub1flags,tilemap_t * sub2,int sub2flags,int mixerflags,bitmap_ind16 * extra_bitmap,int rushingheroes_hack)318 void konamigx_state::konamigx_mixer(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect,
319 					tilemap_t *sub1, int sub1flags,
320 					tilemap_t *sub2, int sub2flags,
321 					int mixerflags, bitmap_ind16 *extra_bitmap, int rushingheroes_hack)
322 {
323 	int objbuf[GX_MAX_OBJECTS];
324 	int shadowon[3], shdpri[3], layerid[6], layerpri[6];
325 
326 	struct GX_OBJ *objpool, *objptr;
327 	int cltc_shdpri, /*prflp,*/ disp;
328 
329 	// buffer can move when it's resized, so refresh the pointer
330 	m_gx_objzbuf = &screen.priority().pix(0);
331 
332 	// abort if object database failed to initialize
333 	objpool = gx_objpool;
334 	if (!objpool) return;
335 
336 	// clear screen with backcolor and update flicker pulse
337 	if (m_gx_wrport1_0 & 0x20)
338 		m_k054338->fill_backcolor(bitmap,
339 									cliprect,
340 									m_palette->pens() + (m_k055555->K055555_read_register(0) << 9),
341 									m_k055555->K055555_read_register(1));
342 	else
343 		m_k054338->fill_solid_bg(bitmap, cliprect);
344 
345 	// abort if video has been disabled
346 	disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
347 	if (!disp) return;
348 	cltc_shdpri = m_k054338->register_r(K338_REG_CONTROL);
349 
350 
351 	if (!rushingheroes_hack) // Slam Dunk 2 never sets this.  It's either part of the protection, or type4 doesn't use it
352 	{
353 		if (!(cltc_shdpri & K338_CTL_KILL)) return;
354 	}
355 
356 
357 	// demote shadows by one layer when this bit is set??? (see p.73 8.6)
358 	cltc_shdpri &= K338_CTL_SHDPRI;
359 
360 	// wipe z-buffer
361 	if (mixerflags & GXMIX_NOZBUF)
362 		mixerflags |= GXMIX_NOSHADOW;
363 	else
364 		wipezbuf(mixerflags & GXMIX_NOSHADOW);
365 
366 	// cache global parameters
367 	konamigx_precache_registers();
368 
369 	// init OBJSET2 and mixer parameters (see p.51 and chapter 7)
370 	layerid[0] = 0; layerid[1] = 1; layerid[2] = 2; layerid[3] = 3; layerid[4] = 4; layerid[5] = 5;
371 
372 
373 	// invert layer priority when this flag is set (not used by any GX game?)
374 	//prflp = K055555_read_register(K55_CONTROL) & K55_CTL_FLIPPRI;
375 
376 	layerpri[0] = m_k055555->K055555_read_register(K55_PRIINP_0);
377 	layerpri[1] = m_k055555->K055555_read_register(K55_PRIINP_3);
378 	layerpri[3] = m_k055555->K055555_read_register(K55_PRIINP_7);
379 	layerpri[4] = m_k055555->K055555_read_register(K55_PRIINP_9);
380 	layerpri[5] = m_k055555->K055555_read_register(K55_PRIINP_10);
381 
382 	int shdprisel;
383 
384 	if (m_gx_primode == -1)
385 	{
386 		// Lethal Enforcer hack (requires pixel color comparison)
387 		layerpri[2] = m_k055555->K055555_read_register(K55_PRIINP_3) + 0x20;
388 		shdprisel = 0x3f;
389 	}
390 	else
391 	{
392 		layerpri[2] = m_k055555->K055555_read_register(K55_PRIINP_6);
393 		shdprisel = m_k055555->K055555_read_register(K55_SHD_PRI_SEL);
394 	}
395 
396 	// SHDPRISEL filters shadows by different priority comparison methods (UNIMPLEMENTED, see detail on p.66)
397 	if (!(shdprisel & 0x03)) shadowon[0] = 0;
398 	if (!(shdprisel & 0x0c)) shadowon[1] = 0;
399 	if (!(shdprisel & 0x30)) shadowon[2] = 0;
400 
401 	shdpri[0]   = m_k055555->K055555_read_register(K55_SHAD1_PRI);
402 	shdpri[1]   = m_k055555->K055555_read_register(K55_SHAD2_PRI);
403 	shdpri[2]   = m_k055555->K055555_read_register(K55_SHAD3_PRI);
404 
405 	int spri_min = 0;
406 
407 	shadowon[2] = shadowon[1] = shadowon[0] = 0;
408 
409 	int k = 0;
410 	if (!(mixerflags & GXMIX_NOSHADOW))
411 	{
412 		int i,j;
413 		// only enable shadows beyond a +/-7 RGB threshold
414 		for (j=0,i=0; i<3; j+=3,i++)
415 		{
416 			k = m_K054338_shdRGB[j  ]; if (k < -7 || k > 7) { shadowon[i] = 1; continue; }
417 			k = m_K054338_shdRGB[j+1]; if (k < -7 || k > 7) { shadowon[i] = 1; continue; }
418 			k = m_K054338_shdRGB[j+2]; if (k < -7 || k > 7) { shadowon[i] = 1; }
419 		}
420 
421 		// SHDON specifies layers on which shadows can be projected (see detail on p.65 7.2.8)
422 		int temp = m_k055555->K055555_read_register(K55_SHD_ON);
423 		for (i=0; i<4; i++) if (!(temp>>i & 1) && spri_min < layerpri[i]) spri_min = layerpri[i]; // HACK
424 
425 		// update shadows status
426 		m_k054338->update_all_shadows(rushingheroes_hack, *m_palette);
427 	}
428 
429 	// pre-sort layers
430 	for (int j=0; j<5; j++)
431 	{
432 		int temp1 = layerpri[j];
433 		for (int i=j+1; i<6; i++)
434 		{
435 			int temp2 = layerpri[i];
436 			if ((uint32_t)temp1 <= (uint32_t)temp2)
437 			{
438 				layerpri[i] = temp1; layerpri[j] = temp1 = temp2;
439 				temp2 = layerid[i]; layerid[i] = layerid[j]; layerid[j] = temp2;
440 			}
441 		}
442 	}
443 
444 	// build object database and create indices
445 	objptr = objpool;
446 	int nobj = 0;
447 
448 	for (int i=5; i>=0; i--)
449 	{
450 		int offs;
451 
452 		int code = layerid[i];
453 		switch (code)
454 		{
455 			/*
456 			    Background layers are represented by negative offset values as follow:
457 
458 			    0+ : normal sprites
459 			    -1 : tile layer A - D
460 			    -2 : K053936 ROZ+ layer 1
461 			    -3 : K053936 ROZ+ layer 2
462 			    -4 : K053250 LVC layer 1
463 			    -5 : K053250 LVC layer 2
464 			*/
465 			case 4 :
466 				offs = -128;
467 				if (sub1flags & 0xf) { if (sub1flags & GXSUB_K053250) offs = -4; else if (sub1) offs = -2; }
468 			break;
469 			case 5 :
470 				offs = -128;
471 				if (sub2flags & 0xf) { if (sub2flags & GXSUB_K053250) offs = -5; else if (sub2) offs = -3; }
472 				if (extra_bitmap) offs = -3;
473 			break;
474 			default: offs = -1;
475 		}
476 
477 		if (offs != -128)
478 		{
479 			objptr->order = layerpri[i]<<24;
480 			objptr->code  = code;
481 			objptr->offs = offs;
482 			objptr++;
483 
484 			objbuf[nobj] = nobj;
485 			nobj++;
486 		}
487 	}
488 
489 //  i = j = 0xff;
490 	int l = 0;
491 
492 	u32 start_addr = m_type3_spriteram_bank ? 0x800 : 0;
493 	u32 end_addr = start_addr + 0x800;
494 
495 
496 	for (int offs=start_addr; offs<end_addr; offs+=8)
497 	{
498 		int pri = 0;
499 
500 		if (!(m_gx_spriteram[offs] & 0x8000)) continue;
501 
502 		int zcode = m_gx_spriteram[offs] & 0xff;
503 
504 		// invert z-order when opset_pri is set (see p.51 OPSET PRI)
505 		if (m_k053247_opset & 0x10) zcode = 0xff - zcode;
506 
507 		int code  = m_gx_spriteram[offs+1];
508 		int color = k = m_gx_spriteram[offs+6];
509 		l     = m_gx_spriteram[offs+7];
510 
511 		m_k055673->m_k053247_cb(&code, &color, &pri);
512 
513 		/*
514 		    shadow = shadow code
515 		    spri   = shadow priority
516 		    temp1  = add solid object
517 		    temp2  = solid pens draw mode
518 		    temp3  = add shadow object
519 		    temp4  = shadow pens draw mode
520 		*/
521 		int temp4 = 0;
522 		int temp3 = 0;
523 		int temp2 = 0;
524 		int temp1 = 0;
525 		int spri = 0;
526 		int shadow = 0;
527 
528 		if (color & K055555_FULLSHADOW)
529 		{
530 			shadow = 3; // use default intensity and color
531 			spri = pri; // retain host priority
532 			temp3 = 1; // add shadow
533 			temp4 = 5; // draw full shadow
534 		}
535 		else
536 		{
537 			shadow = k>>10 & 3;
538 			if (shadow) // object has shadow?
539 			{
540 				int k053246_objset1 = m_k055673->k053246_read_register(5);
541 				if (shadow != 1 || k053246_objset1 & 0x20)
542 				{
543 					shadow--;
544 					temp1 = 1; // add solid
545 					temp2 = 1; // draw partial solid
546 					if (shadowon[shadow])
547 					{
548 						temp3 = 1; // add shadow
549 						temp4 = 4; // draw partial shadow
550 					}
551 				}
552 				else
553 				{
554 					// drop the entire sprite to shadow if its shadow code is 1 and SD0EN is off (see p.48)
555 					shadow = 0;
556 					if (!shadowon[0]) continue;
557 					temp3 = 1; // add shadow
558 					temp4 = 5; // draw full shadow
559 				}
560 			}
561 			else
562 			{
563 				temp1 = 1; // add solid
564 				temp2 = 0; // draw full solid
565 			}
566 
567 			if (temp1)
568 			{
569 				// tag sprite for alpha blending
570 				if (color>>K055555_MIXSHIFT & 3) temp2 |= 2;
571 			}
572 
573 			if (temp3)
574 			{
575 				// determine shadow priority
576 				spri = (m_k053247_opset & 0x20) ? pri : shdpri[shadow]; // (see p.51 OPSET SDSEL)
577 			}
578 		}
579 
580 		switch (m_gx_primode & 0xf)
581 		{
582 			// Dadandarn zcode suppression
583 			case  1:
584 				zcode = 0;
585 			break;
586 
587 			// Daisukiss bad shadow filter
588 			case  4:
589 				if (k & 0x3000 || k == 0x0800) continue;
590 
591 			// Tokkae shadow masking (INACCURATE)
592 			case  5:
593 				if (spri < spri_min) spri = spri_min;
594 			break;
595 		}
596 
597 		/*
598 		    default sort order:
599 		    fedcba9876543210fedcba9876543210
600 		    xxxxxxxx------------------------ (priority)
601 		    --------xxxxxxxx---------------- (zcode)
602 		    ----------------xxxxxxxx-------- (offset)
603 		    ------------------------xxxx---- (shadow mode)
604 		    ----------------------------xxxx (shadow code)
605 		*/
606 		if (temp1)
607 		{
608 			// add objects with solid or alpha pens
609 			int order = pri<<24 | zcode<<16 | offs<<(8-3) | temp2<<4;
610 			objptr->order = order;
611 			objptr->offs  = offs;
612 			objptr->code  = code;
613 			objptr->color = color;
614 			objptr++;
615 
616 			objbuf[nobj] = nobj;
617 			nobj++;
618 		}
619 
620 		if (temp3 && !(color & K055555_SKIPSHADOW) && !(mixerflags & GXMIX_NOSHADOW))
621 		{
622 			// add objects with shadows if enabled
623 			int order = spri<<24 | zcode<<16 | offs<<(8-3) | temp4<<4 | shadow;
624 			objptr->order = order;
625 			objptr->offs  = offs;
626 			objptr->code  = code;
627 			objptr->color = color;
628 			objptr++;
629 
630 			objbuf[nobj] = nobj;
631 			nobj++;
632 		}
633 	}
634 
635 	// sort objects in decending order (SLOW)
636 	k = nobj;
637 	l = nobj - 1;
638 
639 	for (int j=0; j<l; j++)
640 	{
641 		int temp1 = objbuf[j];
642 		int temp2 = objpool[temp1].order;
643 		for (int i=j+1; i<k; i++)
644 		{
645 			int temp3 = objbuf[i];
646 			int temp4 = objpool[temp3].order;
647 			if ((uint32_t)temp2 <= (uint32_t)temp4) { temp2 = temp4; objbuf[i] = temp1; objbuf[j] = temp1 = temp3; }
648 		}
649 	}
650 
651 
652 	konamigx_mixer_draw(screen,bitmap,cliprect,sub1,sub1flags,sub2,sub2flags,mixerflags,extra_bitmap,rushingheroes_hack,
653 		objpool,
654 		objbuf,
655 		nobj
656 		);
657 }
658 
gx_draw_basic_tilemaps(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect,int mixerflags,int code)659 void konamigx_state::gx_draw_basic_tilemaps(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, int code)
660 {
661 	int temp1,temp2,temp3,temp4;
662 	int i = code<<1;
663 	int j = mixerflags>>i & 3;
664 	int k = 0;
665 
666 	int disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
667 	if (disp & (1<<code))
668 	{
669 		if (j == GXMIX_BLEND_NONE)  { temp1 = 0xff; temp2 = temp3 = 0; } else
670 		if (j == GXMIX_BLEND_FORCE) { temp1 = 0x00; temp2 = mixerflags>>(i+16); temp3 = 3; }
671 		else
672 		{
673 			temp1 = m_vinmix;
674 			temp2 = m_vinmix>>i & 3;
675 			temp3 = m_vmixon>>i & 3;
676 		}
677 
678 		/* blend layer only when:
679 		    1) m_vinmix != 0xff
680 		    2) its internal mix code is set
681 		    3) all mix code bits are internal(overridden until tile blending has been implemented)
682 		    4) 0 > alpha < 255;
683 		*/
684 		if (temp1!=0xff && temp2 /*&& temp3==3*/)
685 		{
686 			temp4 = m_k054338->set_alpha_level(temp2);
687 
688 			if (temp4 <= 0) return;
689 			if (temp4 < 255) k = TILEMAP_DRAW_ALPHA(temp4);
690 		}
691 
692 		if (mixerflags & 1<<(code+12)) k |= K056382_DRAW_FLAG_FORCE_XYSCROLL;
693 
694 		m_k056832->m_tilemap_draw(screen, bitmap, cliprect, code, k, 0);
695 	}
696 }
697 
gx_draw_basic_extended_tilemaps_1(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect,int mixerflags,int code,tilemap_t * sub1,int sub1flags,int rushingheroes_hack,int offs)698 void konamigx_state::gx_draw_basic_extended_tilemaps_1(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, int code, tilemap_t *sub1, int sub1flags, int rushingheroes_hack, int offs)
699 {
700 	int temp1,temp2,temp3,temp4;
701 	int i = code<<1;
702 	int j = mixerflags>>i & 3;
703 	int k = 0;
704 
705 	int disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
706 	if ((disp & K55_INP_SUB1) || (rushingheroes_hack))
707 	{
708 		int alpha = 255;
709 
710 		if (j == GXMIX_BLEND_NONE)  { temp1 = 0xff; temp2 = temp3 = 0; } else
711 		if (j == GXMIX_BLEND_FORCE) { temp1 = 0x00; temp2 = mixerflags>>24; temp3 = 3; }
712 		else
713 		{
714 			temp1 = m_osinmix;
715 			temp2 = m_osinmix>>2 & 3;
716 			temp3 = m_osmixon>>2 & 3;
717 		}
718 
719 		if (temp1!=0xff && temp2 /*&& temp3==3*/)
720 		{
721 			alpha = temp4 = m_k054338->set_alpha_level(temp2);
722 
723 			if (temp4 <= 0) return;
724 			if (temp4 < 255) k = 1;
725 		}
726 
727 		int l = sub1flags & 0xf;
728 
729 		if (offs == -2)
730 		{
731 			int pixeldouble_output = 0;
732 			const rectangle &visarea = screen.visible_area();
733 			int width = visarea.width();
734 
735 			if (width>512) // vsnetscr case
736 				pixeldouble_output = 1;
737 
738 			K053936GP_0_zoom_draw(machine(), bitmap, cliprect, sub1, l, k, alpha, pixeldouble_output, m_k053936_0_ctrl_16, m_k053936_0_linectrl_16, m_k053936_0_ctrl, m_k053936_0_linectrl, *m_palette);
739 		}
740 		else
741 		{
742 			m_k053250_1->draw(bitmap, cliprect, m_vcblk[4]<<l, 0, screen.priority(), 0);
743 		}
744 	}
745 }
746 
gx_draw_basic_extended_tilemaps_2(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect,int mixerflags,int code,tilemap_t * sub2,int sub2flags,bitmap_ind16 * extra_bitmap,int offs)747 void konamigx_state::gx_draw_basic_extended_tilemaps_2(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int mixerflags, int code, tilemap_t *sub2, int sub2flags, bitmap_ind16 *extra_bitmap, int offs)
748 {
749 	int temp1,temp2,temp3,temp4;
750 	int i = code<<1;
751 	int j = mixerflags>>i & 3;
752 
753 	int disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
754 	if (disp & K55_INP_SUB2)
755 	{
756 		//int alpha = 255;
757 		if (j == GXMIX_BLEND_NONE)  { temp1 = 0xff; temp2 = temp3 = 0; } else
758 		if (j == GXMIX_BLEND_FORCE) { temp1 = 0x00; temp2 = mixerflags>>26; temp3 = 3; }
759 		else
760 		{
761 			temp1 = m_osinmix;
762 			temp2 = m_osinmix>>4 & 3;
763 			temp3 = m_osmixon>>4 & 3;
764 		}
765 
766 		if (temp1!=0xff && temp2 /*&& temp3==3*/)
767 		{
768 			//alpha =
769 			temp4 = m_k054338->set_alpha_level(temp2);
770 
771 			if (temp4 <= 0) return;
772 			//if (temp4 < 255) k = 1;
773 		}
774 
775 		int l = sub2flags & 0xf;
776 
777 		if (offs == -3)
778 		{
779 			if (extra_bitmap) // soccer superstars roz layer
780 			{
781 				int width = screen.width();
782 				int height = screen.height();
783 				pen_t const *const paldata = m_palette->pens();
784 
785 				// the output size of the roz layer has to be doubled horizontally
786 				// so that it aligns with the sprites and normal tilemaps.  This appears
787 				// to be done as a post-processing / mixing step effect
788 				//
789 				// - todo, use the pixeldouble_output I just added for vsnet instead?
790 				for (int yy=0;yy<height;yy++)
791 				{
792 					uint16_t const *const src = &extra_bitmap->pix(yy);
793 					uint32_t *const dst = &bitmap.pix(yy);
794 					int shiftpos = 0;
795 					for (int xx=0;xx<width;xx+=2)
796 					{
797 						uint16_t dat = src[(((xx/2)+shiftpos))%width];
798 						if (dat&0xff)
799 							dst[xx+1] = dst[xx] = paldata[dat];
800 					}
801 				}
802 			}
803 			else
804 			{
805 			//  int pixeldouble_output = 0;
806 			//  K053936GP_1_zoom_draw(machine, bitmap, cliprect, sub2, l, k, alpha, pixeldouble_output);
807 			}
808 		}
809 		else
810 			m_k053250_2->draw(bitmap, cliprect, m_vcblk[5]<<l, 0, screen.priority(), 0);
811 	}
812 }
813 
konamigx_mixer_draw(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect,tilemap_t * sub1,int sub1flags,tilemap_t * sub2,int sub2flags,int mixerflags,bitmap_ind16 * extra_bitmap,int rushingheroes_hack,struct GX_OBJ * objpool,int * objbuf,int nobj)814 void konamigx_state::konamigx_mixer_draw(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect,
815 					tilemap_t *sub1, int sub1flags,
816 					tilemap_t *sub2, int sub2flags,
817 					int mixerflags, bitmap_ind16 *extra_bitmap, int rushingheroes_hack,
818 
819 					/* passed from above function */
820 					struct GX_OBJ *objpool,
821 					int *objbuf,
822 					int nobj
823 					)
824 {
825 	// traverse draw list
826 	int disp = m_k055555->K055555_read_register(K55_INPUT_ENABLES);
827 
828 	for (int count=0; count<nobj; count++)
829 	{
830 		struct GX_OBJ *objptr = objpool + objbuf[count];
831 		int order  = objptr->order;
832 		int offs   = objptr->offs;
833 		int code   = objptr->code;
834 		int color  = objptr->color;
835 
836 		/* entries >=0 in our list are sprites */
837 		if (offs >= 0)
838 		{
839 			if (!(disp & K55_INP_OBJ)) continue;
840 
841 			int drawmode = order>>4 & 0xf;
842 
843 			int alpha = 255;
844 			int pri = 0;
845 			int zcode = -1; // negative zcode values turn off z-buffering
846 
847 			if (drawmode & 2)
848 			{
849 				alpha = color>>K055555_MIXSHIFT & 3;
850 				if (alpha) alpha = m_k054338->set_alpha_level(alpha);
851 				if (alpha <= 0) continue;
852 			}
853 			color &= K055555_COLORMASK;
854 
855 			if (drawmode >= 4) m_palette->set_shadow_mode(order & 0x0f);
856 
857 			if (!(mixerflags & GXMIX_NOZBUF))
858 			{
859 				zcode = order>>16 & 0xff;
860 				pri = order>>24 & 0xff;
861 			}
862 
863 
864 
865 
866 			m_k055673->k053247_draw_single_sprite_gxcore(bitmap, cliprect,
867 				m_gx_objzbuf, m_gx_shdzbuf.get(), code, m_gx_spriteram, offs,
868 				color, alpha, drawmode, zcode, pri,
869 				/* non-gx only */
870 				0,0,nullptr,nullptr,0
871 				);
872 		}
873 		/* the rest are tilemaps of various kinda */
874 		else
875 		{
876 			switch (offs)
877 			{
878 				case -1:
879 					gx_draw_basic_tilemaps(screen, bitmap, cliprect, mixerflags, code);
880 					continue;
881 				case -2:
882 				case -4:
883 					gx_draw_basic_extended_tilemaps_1(screen, bitmap, cliprect, mixerflags, code, sub1, sub1flags, rushingheroes_hack, offs);
884 				continue;
885 				case -3:
886 				case -5:
887 					gx_draw_basic_extended_tilemaps_2(screen, bitmap, cliprect, mixerflags, code, sub2, sub2flags, extra_bitmap, offs);
888 				continue;
889 			}
890 			continue;
891 		}
892 
893 
894 
895 	}
896 }
897 
898 
899 /* Run and Gun 2 / Rushing Heroes */
TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac_tile_info)900 TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac_tile_info)
901 {
902 	int tileno, colour, col, flip = 0;
903 	if (tile_index&1)
904 	{
905 		tileno = m_psacram[tile_index/2] & 0x00001fff;
906 		col    =(m_psacram[tile_index/2] & 0x00002000)>>13;
907 		if      (m_psacram[tile_index/2] & 0x00004000) flip |= TILE_FLIPX;
908 		if      (m_psacram[tile_index/2] & 0x00008000) flip |= TILE_FLIPY;
909 
910 	}
911 	else
912 	{
913 		tileno = (m_psacram[tile_index/2] & 0x1fff0000)>>16;
914 		col    = (m_psacram[tile_index/2] & 0x20000000)>>29;
915 		if       (m_psacram[tile_index/2] & 0x40000000) flip |= TILE_FLIPX;
916 		if       (m_psacram[tile_index/2] & 0x80000000) flip |= TILE_FLIPY;
917 
918 	}
919 
920 	colour = (m_psac_colorbase << 4) + col;
921 
922 	tileinfo.set(0, tileno, colour, TILE_FLIPYX(flip));
923 }
924 
925 
type3_bank_w(offs_t offset,uint8_t data)926 void konamigx_state::type3_bank_w(offs_t offset, uint8_t data)
927 {
928 	// other bits are used for something...
929 
930 	if (offset == 0)
931 	{
932 		m_type3_psac2_bank = (data & 0x10) >> 4;
933 		// swap sprite display bank for left/right screens
934 		// bit 6 works for soccerss, doesn't for type4 (where they never enable it)
935 		// so the best candidate is bit 0
936 		//m_type3_spriteram_bank = (data & 0x40) >> 6;
937 		m_type3_spriteram_bank = (data & 0x01);
938 	}
939 	else
940 		logerror("Write to type3 bank %02x address %02x\n",offset, data);
941 
942 	/* handle this by creating 2 roz tilemaps instead, otherwise performance dies completely on dual screen mode
943 	if (m_konamigx_type3_psac2_actual_bank!=m_konamigx_type3_psac2_actual_last_bank)
944 	{
945 	    m_gx_psac_tilemap->mark_all_dirty();
946 	    m_konamigx_type3_psac2_actual_last_bank = m_konamigx_type3_psac2_actual_bank;
947 	}
948 	*/
949 }
950 
951 
952 
953 /* Soccer Superstars (tile and flip bits now TRUSTED) */
TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac3_tile_info)954 TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac3_tile_info)
955 {
956 	int tileno, colour, flip;
957 	uint8_t *tmap = memregion("gfx4")->base();
958 
959 	int base_index = tile_index;
960 
961 //  if (m_konamigx_type3_psac2_actual_bank)
962 //      base_index+=0x20000/2;
963 
964 
965 	tileno =  tmap[base_index*2] | ((tmap[(base_index*2)+1] & 0x0f)<<8);
966 	colour = (tmap[(base_index*2)+1]&0xc0)>>6;
967 
968 	flip = 0;
969 	if (tmap[(base_index*2)+1] & 0x20) flip |= TILE_FLIPY;
970 	if (tmap[(base_index*2)+1] & 0x10) flip |= TILE_FLIPX;
971 
972 	tileinfo.set(0, tileno, colour, flip);
973 }
974 
TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac3_alt_tile_info)975 TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac3_alt_tile_info)
976 {
977 	int tileno, colour, flip;
978 	uint8_t *tmap = memregion("gfx4")->base()+0x20000;
979 
980 	int base_index = tile_index;
981 
982 //  if (m_konamigx_type3_psac2_actual_bank)
983 //      base_index+=0x20000/2;
984 
985 
986 	tileno =  tmap[base_index*2] | ((tmap[(base_index*2)+1] & 0x0f)<<8);
987 	colour = (tmap[(base_index*2)+1]&0xc0)>>6;
988 
989 	flip = 0;
990 	if (tmap[(base_index*2)+1] & 0x20) flip |= TILE_FLIPY;
991 	if (tmap[(base_index*2)+1] & 0x10) flip |= TILE_FLIPX;
992 
993 	tileinfo.set(0, tileno, colour, flip);
994 }
995 
996 
997 /* PSAC4 */
998 /* these tilemaps are weird in both format and content, one of them
999    doesn't really look like it should be displayed? - it's height data */
TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac1a_tile_info)1000 TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac1a_tile_info)
1001 {
1002 	int tileno, colour, flipx,flipy;
1003 	int flip;
1004 	flip=0;
1005 	colour = 0;
1006 
1007 	tileno = (m_psacram[tile_index*2] & 0x00003fff)>>0;
1008 
1009 	// scanrows
1010 	//flipx  = (m_psacram[tile_index*2+1] & 0x00800000)>>23;
1011 	//flipy  = (m_psacram[tile_index*2+1] & 0x00400000)>>22;
1012 	// scancols
1013 	flipy  = (m_psacram[tile_index*2+1] & 0x00800000)>>23;
1014 	flipx  = (m_psacram[tile_index*2+1] & 0x00400000)>>22;
1015 
1016 	if (flipx) flip |= TILE_FLIPX;
1017 	if (flipy) flip |= TILE_FLIPY;
1018 
1019 	tileinfo.set(1, tileno, colour, flip);
1020 }
1021 
TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac1b_tile_info)1022 TILE_GET_INFO_MEMBER(konamigx_state::get_gx_psac1b_tile_info)
1023 {
1024 	int tileno, colour, flipx,flipy;
1025 	int flip;
1026 	flip=0;
1027 
1028 	colour = 0;
1029 	tileno = (m_psacram[tile_index*2+1] & 0x00003fff)>>0;
1030 
1031 	// scanrows
1032 	//flipx  = (m_psacram[tile_index*2+1] & 0x00800000)>>23;
1033 	//flipy  = (m_psacram[tile_index*2+1] & 0x00400000)>>22;
1034 	// scancols
1035 	flipy  = (m_psacram[tile_index*2+1] & 0x00200000)>>21;
1036 	flipx  = (m_psacram[tile_index*2+1] & 0x00100000)>>20;
1037 
1038 	if (flipx) flip |= TILE_FLIPX;
1039 	if (flipy) flip |= TILE_FLIPY;
1040 
1041 	tileinfo.set(0, tileno, colour, flip);
1042 }
1043 
K056832_CB_MEMBER(konamigx_state::type2_tile_callback)1044 K056832_CB_MEMBER(konamigx_state::type2_tile_callback)
1045 {
1046 	int d = *code;
1047 
1048 	*code = (m_gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
1049 	K055555GX_decode_vmixcolor(layer, color);
1050 }
1051 
K056832_CB_MEMBER(konamigx_state::alpha_tile_callback)1052 K056832_CB_MEMBER(konamigx_state::alpha_tile_callback)
1053 {
1054 	int mixcode;
1055 	int d = *code;
1056 
1057 	mixcode = K055555GX_decode_vmixcolor(layer, color);
1058 
1059 	if (mixcode < 0)
1060 		*code = (m_gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
1061 	else
1062 	{
1063 		/* save mixcode and mark tile alpha (unimplemented) */
1064 		// Daisu-Kiss stage presentation
1065 		// Sexy Parodius level 3b
1066 		*code =  (m_gx_tilebanks[(d & 0xe000)>>13]<<13) + (d & 0x1fff);
1067 
1068 		if (VERBOSE)
1069 			popmessage("skipped alpha tile(layer=%d mix=%d)", layer, mixcode);
1070 	}
1071 }
1072 
1073 /*
1074 > bits 8-13 are the low priority bits
1075 > i.e. pri 0-5
1076 > pri 6-7 can be either 1, bits 14,15 or bits 16,17
1077 > contro.bit 2 being 0 forces the 1
1078 > when control.bit 2 is 1, control.bit 3 selects between the two
1079 > 0 selects 16,17
1080 > that gives you the entire 8 bits of the sprite priority
1081 > ok, lemme see if I've got this.  bit2 = 0 means the top bits are 11, bit2=1 means the top bits are bits 14/15 (of the whatever word?) else
1082 +16+17?
1083 > bit3=1 for the second
1084 
1085  *   6  | ---------xxxxxxx | "color", but depends on external connections
1086 
1087 
1088 > there are 8 color lines entering the 5x5
1089 > that means the palette is 4 bits, not 5 as you currently have
1090 > the bits 4-9 are the low priority bits
1091 > bits 10/11 or 12/13 are the two high priority bits, depending on the control word
1092 > and bits 14/15 are the shadow bits
1093 > mix0/1 and brit0/1 come from elsewhere
1094 > they come from the '673 all right, but not from word 6
1095 > and in fact the top address bits are highly suspect
1096 > only 18 of the address bits go to the roms
1097 > the next 2 go to cai0/1 and the next 4 to bk0-3
1098 > (the '246 indexes the roms, the '673 reads the result)
1099 > the roms are 64 bits wide
1100 > so, well, the top bits of the code are suspicious
1101 */
1102 
common_init()1103 void konamigx_state::common_init()
1104 {
1105 	konamigx_mixer_init(*m_screen, 0);
1106 
1107 	for (int i = 0; i < 8; i++)
1108 	{
1109 		m_gx_tilebanks[i] = m_gx_oldbanks[i] = 0;
1110 	}
1111 
1112 	save_pointer(NAME(m_gx_spriteram), 0x800);
1113 	save_item(NAME(m_gx_tilebanks));
1114 	save_item(NAME(m_k053247_vrcbk));
1115 	save_item(NAME(m_k053247_coreg));
1116 	save_item(NAME(m_k053247_coregshift));
1117 	save_item(NAME(m_k053247_opset));
1118 	save_item(NAME(m_opri));
1119 	save_item(NAME(m_oinprion));
1120 	save_item(NAME(m_vcblk));
1121 	save_item(NAME(m_ocblk));
1122 	save_item(NAME(m_vinmix));
1123 	save_item(NAME(m_vmixon));
1124 	save_item(NAME(m_osinmix));
1125 	save_item(NAME(m_osmixon));
1126 
1127 	m_gx_tilemode = 0;
1128 
1129 	m_gx_rozenable = 0;
1130 	m_gx_specialrozenable = 0;
1131 	m_gx_rushingheroes_hack = 0;
1132 
1133 	// Documented relative offsets of non-flipped games are (-2, 0, 2, 3),(0, 0, 0, 0).
1134 	// (+ve values move layers to the right and -ve values move layers to the left)
1135 	// In most cases only a constant is needed to add to the X offsets to yield correct
1136 	// displacement. This should be done by the CCU but the CRT timings have not been
1137 	// figured out.
1138 	m_k056832->set_layer_offs(0, -2, 0);
1139 	m_k056832->set_layer_offs(1,  0, 0);
1140 	m_k056832->set_layer_offs(2,  2, 0);
1141 	m_k056832->set_layer_offs(3,  3, 0);
1142 
1143 	m_konamigx_has_dual_screen = 0;
1144 	m_konamigx_current_frame = 0;
1145 }
1146 
1147 
VIDEO_START_MEMBER(konamigx_state,konamigx_5bpp)1148 VIDEO_START_MEMBER(konamigx_state, konamigx_5bpp)
1149 {
1150 	common_init();
1151 
1152 	if (!strcmp(machine().system().name,"tbyahhoo"))
1153 		m_gx_tilemode = 1;
1154 	else if (!strcmp(machine().system().name,"crzcross") || !strcmp(machine().system().name,"puzldama"))
1155 		konamigx_mixer_primode(5);
1156 	else if (!strcmp(machine().system().name,"daiskiss"))
1157 		konamigx_mixer_primode(4);
1158 }
1159 
VIDEO_START_MEMBER(konamigx_state,dragoonj)1160 VIDEO_START_MEMBER(konamigx_state, dragoonj)
1161 {
1162 	common_init();
1163 
1164 	m_k056832->set_layer_offs(0, -2+1, 0);
1165 	m_k056832->set_layer_offs(1,  0+1, 0);
1166 	m_k056832->set_layer_offs(2,  2+1, 0);
1167 	m_k056832->set_layer_offs(3,  3+1, 0);
1168 }
1169 
VIDEO_START_MEMBER(konamigx_state,le2)1170 VIDEO_START_MEMBER(konamigx_state, le2)
1171 {
1172 	common_init();
1173 
1174 	konamigx_mixer_primode(-1); // swapped layer B and C priorities?
1175 }
1176 
VIDEO_START_MEMBER(konamigx_state,konamigx_6bpp)1177 VIDEO_START_MEMBER(konamigx_state, konamigx_6bpp)
1178 {
1179 	common_init();
1180 	konamigx_mixer_primode(5);
1181 }
1182 
VIDEO_START_MEMBER(konamigx_state,konamigx_type3)1183 VIDEO_START_MEMBER(konamigx_state, konamigx_type3)
1184 {
1185 	int width = m_screen->width();
1186 	int height = m_screen->height();
1187 
1188 	m_dualscreen_left_tempbitmap = std::make_unique<bitmap_rgb32>( width, height);
1189 	m_dualscreen_right_tempbitmap = std::make_unique<bitmap_rgb32>( width, height);
1190 
1191 	common_init();
1192 
1193 	m_gx_psac_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac3_tile_info)), TILEMAP_SCAN_COLS,  16, 16, 256, 256);
1194 	m_gx_psac_tilemap_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac3_alt_tile_info)), TILEMAP_SCAN_COLS,  16, 16, 256, 256);
1195 
1196 	m_gx_rozenable = 0;
1197 	m_gx_specialrozenable = 2;
1198 
1199 
1200 	/* set up tile layers */
1201 	m_type3_roz_temp_bitmap = std::make_unique<bitmap_ind16>(width, height);
1202 
1203 
1204 	//m_gx_psac_tilemap->set_flip(TILEMAP_FLIPX| TILEMAP_FLIPY);
1205 
1206 	K053936_wraparound_enable(0, 1);
1207 //  K053936GP_set_offset(0, -30, -1);
1208 	K053936_set_offset(0, -30, +1);
1209 
1210 	m_k056832->set_layer_offs(0,  -52, 0);
1211 	m_k056832->set_layer_offs(1,  -48, 0);
1212 	m_k056832->set_layer_offs(2,  -48, 0);
1213 	m_k056832->set_layer_offs(3,  -48, 0);
1214 
1215 	m_konamigx_has_dual_screen = 1;
1216 	m_konamigx_palformat = 1;
1217 }
1218 
VIDEO_START_MEMBER(konamigx_state,konamigx_type4)1219 VIDEO_START_MEMBER(konamigx_state, konamigx_type4)
1220 {
1221 	int width = m_screen->width();
1222 	int height = m_screen->height();
1223 
1224 	m_dualscreen_left_tempbitmap = std::make_unique<bitmap_rgb32>( width, height);
1225 	m_dualscreen_right_tempbitmap = std::make_unique<bitmap_rgb32>( width, height);
1226 
1227 	common_init();
1228 
1229 	m_gx_psac_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac_tile_info)), TILEMAP_SCAN_COLS,  16, 16, 128, 128);
1230 	m_gx_rozenable = 0;
1231 	m_gx_specialrozenable = 3;
1232 
1233 	m_k056832->set_layer_offs(0,  -27, 0);
1234 	m_k056832->set_layer_offs(1,  -25, 0);
1235 	m_k056832->set_layer_offs(2,  -24, 0);
1236 	m_k056832->set_layer_offs(3,  -22, 0);
1237 
1238 	K053936_wraparound_enable(0, 0);
1239 	K053936GP_set_offset(0, -36, 1);
1240 
1241 	m_gx_rushingheroes_hack = 1;
1242 	m_konamigx_has_dual_screen = 1;
1243 	m_konamigx_palformat = 0;
1244 
1245 }
1246 
VIDEO_START_MEMBER(konamigx_state,konamigx_type4_vsn)1247 VIDEO_START_MEMBER(konamigx_state, konamigx_type4_vsn)
1248 {
1249 	int width = m_screen->width();
1250 	int height = m_screen->height();
1251 
1252 	m_dualscreen_left_tempbitmap = std::make_unique<bitmap_rgb32>( width, height);
1253 	m_dualscreen_right_tempbitmap = std::make_unique<bitmap_rgb32>( width, height);
1254 
1255 	common_init();
1256 
1257 	m_gx_psac_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac_tile_info)), TILEMAP_SCAN_COLS,  16, 16, 128, 128);
1258 	m_gx_rozenable = 0;
1259 	m_gx_specialrozenable = 3;
1260 
1261 	m_k056832->set_layer_offs(0,  -52, 0);
1262 	m_k056832->set_layer_offs(1,  -48, 0);
1263 	m_k056832->set_layer_offs(2,  -48, 0);
1264 	m_k056832->set_layer_offs(3,  -48, 0);
1265 
1266 	K053936_wraparound_enable(0, 1); // wraparound doesn't work properly with the custom drawing function anyway, see the crowd in vsnet and rushhero
1267 	K053936GP_set_offset(0, -30, 0);
1268 
1269 	m_gx_rushingheroes_hack = 1;
1270 	m_konamigx_has_dual_screen = 1;
1271 	m_konamigx_palformat = 0;
1272 }
1273 
VIDEO_START_MEMBER(konamigx_state,konamigx_type4_sd2)1274 VIDEO_START_MEMBER(konamigx_state, konamigx_type4_sd2)
1275 {
1276 	int width = m_screen->width();
1277 	int height = m_screen->height();
1278 
1279 	m_dualscreen_left_tempbitmap = std::make_unique<bitmap_rgb32>( width, height);
1280 	m_dualscreen_right_tempbitmap = std::make_unique<bitmap_rgb32>( width, height);
1281 
1282 	common_init();
1283 
1284 	m_gx_psac_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac_tile_info)), TILEMAP_SCAN_COLS,  16, 16, 128, 128);
1285 	m_gx_rozenable = 0;
1286 	m_gx_specialrozenable = 3;
1287 
1288 
1289 	m_k056832->set_layer_offs(0,  -29, -1);
1290 	m_k056832->set_layer_offs(1,  -27, -1);
1291 	m_k056832->set_layer_offs(2,  -26, -1);
1292 	m_k056832->set_layer_offs(3,  -24, -1);
1293 
1294 
1295 	K053936_wraparound_enable(0, 0);
1296 	K053936GP_set_offset(0, -36, -1);
1297 
1298 	m_gx_rushingheroes_hack = 1;
1299 	m_konamigx_has_dual_screen = 1;
1300 	m_konamigx_palformat = 0;
1301 
1302 }
1303 
VIDEO_START_MEMBER(konamigx_state,opengolf)1304 VIDEO_START_MEMBER(konamigx_state, opengolf)
1305 {
1306 	common_init();
1307 
1308 	m_k056832->set_layer_offs(0, -2+1, 0);
1309 	m_k056832->set_layer_offs(1,  0+1, 0);
1310 	m_k056832->set_layer_offs(2,  2+1, 0);
1311 	m_k056832->set_layer_offs(3,  3+1, 0);
1312 
1313 	m_gx_psac_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac1a_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 128, 128);
1314 	m_gx_psac_tilemap2 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac1b_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 128, 128);
1315 
1316 	// transparency will be handled manually in post-processing
1317 	//m_gx_psac_tilemap->set_transparent_pen(0);
1318 	//m_gx_psac_tilemap2->set_transparent_pen(0);
1319 
1320 	m_gx_rozenable = 0;
1321 	m_gx_specialrozenable = 1;
1322 
1323 	m_gxtype1_roz_dstbitmap =  std::make_unique<bitmap_ind16>(512,512); // BITMAP_FORMAT_IND16 because we NEED the raw pen data for post-processing
1324 	m_gxtype1_roz_dstbitmap2 = std::make_unique<bitmap_ind16>(512,512); // BITMAP_FORMAT_IND16 because we NEED the raw pen data for post-processing
1325 
1326 
1327 	m_gxtype1_roz_dstbitmapclip.set(0, 512-1, 0, 512-1);
1328 
1329 
1330 	K053936_wraparound_enable(0, 1);
1331 	K053936GP_set_offset(0, 0, 0);
1332 
1333 	// urgh.. the priority bitmap is global, and because our temp bitmaps are bigger than the screen, this causes issues.. so just allocate something huge
1334 	// until there is a better solution, or priority bitmap can be specified manually.
1335 	m_screen->priority().allocate(2048,2048);
1336 
1337 }
1338 
VIDEO_START_MEMBER(konamigx_state,racinfrc)1339 VIDEO_START_MEMBER(konamigx_state, racinfrc)
1340 {
1341 	common_init();
1342 
1343 	m_k056832->set_layer_offs(0, -2+1, -16);
1344 	m_k056832->set_layer_offs(1,  0+1, -16);
1345 	m_k056832->set_layer_offs(2,  2+1, -16);
1346 	m_k056832->set_layer_offs(3,  3+1, -16);
1347 
1348 	m_gx_psac_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac1a_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 128, 128);
1349 	m_gx_psac_tilemap2 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(konamigx_state::get_gx_psac1b_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 128, 128);
1350 
1351 	// transparency will be handled manually in post-processing
1352 	//m_gx_psac_tilemap->set_transparent_pen(0);
1353 	//m_gx_psac_tilemap2->set_transparent_pen(0);
1354 
1355 	m_gx_rozenable = 0;
1356 	m_gx_specialrozenable = 1;
1357 
1358 	m_gxtype1_roz_dstbitmap =  std::make_unique<bitmap_ind16>(512,512); // BITMAP_FORMAT_IND16 because we NEED the raw pen data for post-processing
1359 	m_gxtype1_roz_dstbitmap2 = std::make_unique<bitmap_ind16>(512,512); // BITMAP_FORMAT_IND16 because we NEED the raw pen data for post-processing
1360 
1361 
1362 	m_gxtype1_roz_dstbitmapclip.set(0, 512-1, 0, 512-1);
1363 
1364 
1365 	K053936_wraparound_enable(0, 1);
1366 	K053936GP_set_offset(0, 0, 0);
1367 
1368 	// urgh.. the priority bitmap is global, and because our temp bitmaps are bigger than the screen, this causes issues.. so just allocate something huge
1369 	// until there is a better solution, or priority bitmap can be specified manually.
1370 	m_screen->priority().allocate(2048,2048);
1371 
1372 
1373 }
1374 
screen_update_konamigx(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1375 uint32_t konamigx_state::screen_update_konamigx(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1376 {
1377 	int i, newbank, newbase, dirty, unchained;
1378 
1379 	/* if any banks are different from last render, we need to flush the planes */
1380 	for (dirty = 0, i = 0; i < 8; i++)
1381 	{
1382 		newbank = m_gx_tilebanks[i];
1383 		if (m_gx_oldbanks[i] != newbank) { m_gx_oldbanks[i] = newbank; dirty = 1; }
1384 	}
1385 
1386 	if (m_gx_tilemode == 0)
1387 	{
1388 		// driver approximates tile update in mode 0 for speed
1389 		unchained = m_k056832->get_layer_association();
1390 		for (i=0; i<4; i++)
1391 		{
1392 			newbase = m_k055555->K055555_get_palette_index(i)<<6;
1393 			if (m_layer_colorbase[i] != newbase)
1394 			{
1395 				m_layer_colorbase[i] = newbase;
1396 
1397 				if (unchained)
1398 					m_k056832->mark_plane_dirty(i);
1399 				else
1400 					dirty = 1;
1401 			}
1402 		}
1403 	}
1404 	else
1405 	{
1406 		// altK056832 does all the tracking in mode 1 for accuracy (Twinbee needs this)
1407 	}
1408 
1409 	// sub2 is PSAC colorbase on GX
1410 	if (m_gx_rozenable)
1411 	{
1412 		m_last_psac_colorbase = m_psac_colorbase;
1413 		m_psac_colorbase = m_k055555->K055555_get_palette_index(6);
1414 
1415 		if (m_psac_colorbase != m_last_psac_colorbase)
1416 		{
1417 			m_gx_psac_tilemap->mark_all_dirty();
1418 			if (m_gx_rozenable == 3)
1419 			{
1420 				m_gx_psac_tilemap2->mark_all_dirty();
1421 			}
1422 		}
1423 	}
1424 
1425 	if (dirty) m_k056832->mark_all_tilemaps_dirty();
1426 
1427 	// Type-1
1428 	if (m_gx_specialrozenable == 1)
1429 	{
1430 		//K053936_0_zoom_draw(screen, *m_gxtype1_roz_dstbitmap, m_gxtype1_roz_dstbitmapclip,m_gx_psac_tilemap, 0,0,0); // height data
1431 		K053936_0_zoom_draw(screen, *m_gxtype1_roz_dstbitmap2,m_gxtype1_roz_dstbitmapclip,m_gx_psac_tilemap2,0,0,0); // colour data (+ some voxel height data?)
1432 	}
1433 
1434 
1435 
1436 	if (m_gx_specialrozenable==3)
1437 	{
1438 		konamigx_mixer(screen, bitmap, cliprect, m_gx_psac_tilemap, GXSUB_8BPP,nullptr,0,  0, nullptr, m_gx_rushingheroes_hack);
1439 	}
1440 	// todo: fix so that it works with the mixer without crashing(!)
1441 	else if (m_gx_specialrozenable == 2)
1442 	{
1443 		// we're going to throw half of this away anyway in post-process, so only render what's needed
1444 		rectangle temprect;
1445 		temprect = cliprect;
1446 		temprect.max_x = cliprect.min_x+320;
1447 
1448 		if (m_type3_psac2_bank == 1) K053936_0_zoom_draw(screen, *m_type3_roz_temp_bitmap, temprect,m_gx_psac_tilemap_alt, 0,0,0); // soccerss playfield
1449 		else K053936_0_zoom_draw(screen, *m_type3_roz_temp_bitmap, temprect,m_gx_psac_tilemap, 0,0,0); // soccerss playfield
1450 
1451 
1452 		konamigx_mixer(screen, bitmap, cliprect, nullptr, 0, nullptr, 0, 0, m_type3_roz_temp_bitmap.get(), m_gx_rushingheroes_hack);
1453 	}
1454 	else
1455 	{
1456 		konamigx_mixer(screen, bitmap, cliprect, nullptr, 0, nullptr, 0, 0, nullptr, m_gx_rushingheroes_hack);
1457 	}
1458 
1459 
1460 
1461 	/* Hack! draw type-1 roz layer here for testing purposes only */
1462 	if (m_gx_specialrozenable == 1)
1463 	{
1464 		pen_t const *const paldata = m_palette->pens();
1465 
1466 		// hack, draw the roz tilemap if W is held
1467 		if ( machine().input().code_pressed(KEYCODE_W) )
1468 		{
1469 			// make it flicker, to compare positioning
1470 			//if (screen.frame_number() & 1)
1471 			{
1472 				for (int y=0;y<256;y++)
1473 				{
1474 					//uint32_t *const dst = &bitmap.pix(y);
1475 					// ths K053936 rendering should probably just be flipped
1476 					// this is just kludged to align the racing force 2d logo
1477 					uint16_t const *const src = &m_gxtype1_roz_dstbitmap2->pix(y);
1478 					//uint16_t const *const src = &m_gxtype1_roz_dstbitmap->pix(y);
1479 
1480 					uint32_t *const dst = &bitmap.pix((256+16)-y);
1481 
1482 					for (int x=0;x<512;x++)
1483 					{
1484 						uint16_t const dat = src[x];
1485 						dst[x] = paldata[dat];
1486 					}
1487 				}
1488 			}
1489 
1490 		}
1491 
1492 	}
1493 
1494 	return 0;
1495 }
1496 
screen_update_konamigx_left(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1497 uint32_t konamigx_state::screen_update_konamigx_left(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1498 {
1499 	/* the video gets demuxed by a board which plugs into the jamma connector */
1500 	m_konamigx_current_frame^=1;
1501 
1502 	if (m_konamigx_current_frame==1)
1503 	{
1504 		int offset=0;
1505 
1506 		if (m_konamigx_palformat==1)
1507 		{
1508 			for (offset=0;offset<0x4000/4;offset++)
1509 			{
1510 				uint32_t coldat = m_generic_paletteram_32[offset];
1511 
1512 				set_color_555(*m_palette, offset*2, 0, 5, 10,coldat >> 16);
1513 				set_color_555(*m_palette, offset*2+1, 0, 5, 10,coldat & 0xffff);
1514 			}
1515 		}
1516 		else
1517 		{
1518 			for (offset=0;offset<0x8000/4;offset++)
1519 			{
1520 				int r,g,b;
1521 
1522 				r = (m_generic_paletteram_32[offset] >>16) & 0xff;
1523 				g = (m_generic_paletteram_32[offset] >> 8) & 0xff;
1524 				b = (m_generic_paletteram_32[offset] >> 0) & 0xff;
1525 
1526 				m_palette->set_pen_color(offset,rgb_t(r,g,b));
1527 			}
1528 		}
1529 
1530 		screen_update_konamigx( screen, downcast<bitmap_rgb32 &>(*m_dualscreen_left_tempbitmap), cliprect);
1531 		copybitmap(bitmap, *m_dualscreen_left_tempbitmap, 0, 0, 0, 0, cliprect);
1532 	}
1533 	else
1534 	{
1535 		copybitmap(bitmap, *m_dualscreen_left_tempbitmap, 0, 0, 0, 0, cliprect);
1536 	}
1537 
1538 	return 0;
1539 }
1540 
screen_update_konamigx_right(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1541 uint32_t konamigx_state::screen_update_konamigx_right(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1542 {
1543 	if (m_konamigx_current_frame==1)
1544 	{
1545 		copybitmap(bitmap, *m_dualscreen_right_tempbitmap, 0, 0, 0, 0, cliprect);
1546 	}
1547 	else
1548 	{
1549 		int offset=0;
1550 
1551 		if (m_konamigx_palformat==1)
1552 		{
1553 			for (offset=0;offset<0x4000/4;offset++)
1554 			{
1555 				uint32_t coldat = m_subpaletteram32[offset];
1556 
1557 				set_color_555(*m_palette, offset*2, 0, 5, 10,coldat >> 16);
1558 				set_color_555(*m_palette, offset*2+1, 0, 5, 10,coldat & 0xffff);
1559 			}
1560 		}
1561 		else
1562 		{
1563 			for (offset=0;offset<0x8000/4;offset++)
1564 			{
1565 				int r,g,b;
1566 
1567 				r = (m_subpaletteram32[offset] >>16) & 0xff;
1568 				g = (m_subpaletteram32[offset] >> 8) & 0xff;
1569 				b = (m_subpaletteram32[offset] >> 0) & 0xff;
1570 
1571 				m_palette->set_pen_color(offset,rgb_t(r,g,b));
1572 			}
1573 		}
1574 
1575 		screen_update_konamigx(screen, downcast<bitmap_rgb32 &>(*m_dualscreen_right_tempbitmap), cliprect);
1576 		copybitmap(bitmap, *m_dualscreen_right_tempbitmap, 0, 0, 0, 0, cliprect);
1577 	}
1578 
1579 	return 0;
1580 }
1581 
set_color_555(palette_device & palette,pen_t color,int rshift,int gshift,int bshift,uint16_t data)1582 static inline void set_color_555(palette_device &palette, pen_t color, int rshift, int gshift, int bshift, uint16_t data)
1583 {
1584 	palette.set_pen_color(color, pal5bit(data >> rshift), pal5bit(data >> gshift), pal5bit(data >> bshift));
1585 }
1586 
1587 #ifdef UNUSED_FUNCTION
1588 // main monitor for type 3
konamigx_555_palette_w(offs_t offset,uint32_t data,uint32_t mem_mask)1589 void konamigx_state::konamigx_555_palette_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1590 {
1591 	uint32_t coldat;
1592 	COMBINE_DATA(&m_generic_paletteram_32[offset]);
1593 
1594 	coldat = m_generic_paletteram_32[offset];
1595 
1596 	set_color_555(*m_palette, offset*2, 0, 5, 10,coldat >> 16);
1597 	set_color_555(*m_palette, offset*2+1, 0, 5, 10,coldat & 0xffff);
1598 }
1599 
1600 // sub monitor for type 3
konamigx_555_palette2_w(offs_t offset,uint32_t data,uint32_t mem_mask)1601 void konamigx_state::konamigx_555_palette2_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1602 {
1603 	uint32_t coldat;
1604 	COMBINE_DATA(&m_subpaletteram32[offset]);
1605 	coldat = m_subpaletteram32[offset];
1606 
1607 	offset += (0x4000/4);
1608 
1609 	set_color_555(*m_palette, offset*2, 0, 5, 10,coldat >> 16);
1610 	set_color_555(*m_palette, offset*2+1, 0, 5, 10,coldat & 0xffff);
1611 }
1612 #endif
1613 
konamigx_tilebank_w(offs_t offset,uint32_t data,uint32_t mem_mask)1614 void konamigx_state::konamigx_tilebank_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1615 {
1616 	if (ACCESSING_BITS_24_31)
1617 		m_gx_tilebanks[offset*4] = (data>>24)&0xff;
1618 	if (ACCESSING_BITS_16_23)
1619 		m_gx_tilebanks[offset*4+1] = (data>>16)&0xff;
1620 	if (ACCESSING_BITS_8_15)
1621 		m_gx_tilebanks[offset*4+2] = (data>>8)&0xff;
1622 	if (ACCESSING_BITS_0_7)
1623 		m_gx_tilebanks[offset*4+3] = data&0xff;
1624 }
1625 
1626 // type 1 RAM-based PSAC tilemap
konamigx_t1_psacmap_w(offs_t offset,uint32_t data,uint32_t mem_mask)1627 void konamigx_state::konamigx_t1_psacmap_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1628 {
1629 	COMBINE_DATA(&m_psacram[offset]);
1630 	m_gx_psac_tilemap->mark_tile_dirty(offset/2);
1631 	m_gx_psac_tilemap2->mark_tile_dirty(offset/2);
1632 }
1633 
1634 // type 4 RAM-based PSAC tilemap
konamigx_t4_psacmap_w(offs_t offset,uint32_t data,uint32_t mem_mask)1635 void konamigx_state::konamigx_t4_psacmap_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1636 {
1637 	COMBINE_DATA(&m_psacram[offset]);
1638 
1639 	m_gx_psac_tilemap->mark_tile_dirty(offset*2);
1640 	m_gx_psac_tilemap->mark_tile_dirty((offset*2)+1);
1641 }
1642