1 // license:BSD-3-Clause
2 // copyright-holders:Ville Linde
3 
4 // Konami 0000057714 "GCU" 2D Graphics Chip
5 
6 #include "emu.h"
7 #include "k057714.h"
8 #include "screen.h"
9 
10 
11 #define DUMP_VRAM 0
12 #define PRINT_GCU 0
13 #define PRINT_CMD_EXEC 0
14 
15 
16 DEFINE_DEVICE_TYPE(K057714, k057714_device, "k057714", "k057714_device GCU")
17 
k057714_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)18 k057714_device::k057714_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
19 	: device_t(mconfig, K057714, tag, owner, clock)
20 	, m_irq(*this)
21 {
22 }
23 
device_start()24 void k057714_device::device_start()
25 {
26 	m_irq.resolve_safe();
27 
28 	m_vram = std::make_unique<uint32_t[]>(0x2000000/4);
29 	memset(m_vram.get(), 0, 0x2000000);
30 }
31 
device_reset()32 void k057714_device::device_reset()
33 {
34 	m_vram_read_addr = 0;
35 	m_command_fifo0_ptr = 0;
36 	m_command_fifo1_ptr = 0;
37 	m_vram_fifo0_addr = 0;
38 	m_vram_fifo1_addr = 0;
39 
40 	m_fb_origin_x = 0;
41 	m_fb_origin_y = 0;
42 
43 	m_reg_6c = 0;
44 
45 	for (auto & elem : m_frame)
46 	{
47 		elem.base = 0;
48 		elem.width = 0;
49 		elem.height = 0;
50 	}
51 }
52 
device_stop()53 void k057714_device::device_stop()
54 {
55 #if DUMP_VRAM
56 	char filename[200];
57 	sprintf(filename, "%s_vram.bin", basetag());
58 	printf("dumping %s\n", filename);
59 	FILE *file = fopen(filename, "wb");
60 	int i;
61 
62 	for (i=0; i < 0x2000000/4; i++)
63 	{
64 		fputc((m_vram[i] >> 24) & 0xff, file);
65 		fputc((m_vram[i] >> 16) & 0xff, file);
66 		fputc((m_vram[i] >> 8) & 0xff, file);
67 		fputc((m_vram[i] >> 0) & 0xff, file);
68 	}
69 
70 	fclose(file);
71 #endif
72 }
73 
74 
read(offs_t offset)75 uint32_t k057714_device::read(offs_t offset)
76 {
77 	int reg = offset * 4;
78 
79 	// VRAM Read
80 	if (reg >= 0x80 && reg < 0x100)
81 	{
82 		return m_vram[m_vram_read_addr + offset - 0x20];
83 	}
84 
85 	switch (reg)
86 	{
87 		case 0x78:      // GCU Status
88 			/* ppd checks bits 0x0041 of the upper halfword on interrupt */
89 			return 0xffff0005;
90 
91 		default:
92 			break;
93 	}
94 
95 	return 0xffffffff;
96 }
97 
write(offs_t offset,uint32_t data,uint32_t mem_mask)98 void k057714_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
99 {
100 	int reg = offset * 4;
101 
102 	switch (reg)
103 	{
104 		case 0x10:
105 			/* IRQ clear/enable; ppd writes bit off then on in response to interrupt */
106 			/* it enables bits 0x41, but 0x01 seems to be the one it cares about */
107 			if (ACCESSING_BITS_16_31 && (data & 0x00010000) == 0)
108 			{
109 				if (!m_irq.isnull())
110 				{
111 					m_irq(CLEAR_LINE);
112 				}
113 			}
114 			if (ACCESSING_BITS_0_15)
115 			{
116 				m_layer_select = data;
117 #if PRINT_GCU
118 				printf("%s_w: %02X, %08X, %08X\n", basetag(), reg, data, mem_mask);
119 #endif
120 			}
121 			break;
122 
123 		case 0x14:      // ?
124 			break;
125 
126 		case 0x18:      // ?
127 			break;
128 
129 		case 0x1c:      // set to 1 on "media bus" access
130 			if ((data >> 16) == 1)
131 			{
132 				m_ext_fifo_count = 0;
133 				m_ext_fifo_line = 0;
134 			}
135 			break;
136 
137 		case 0x20:      // Framebuffer 0 Origin(?)
138 			if (ACCESSING_BITS_16_31)
139 				m_frame[0].y = (data >> 16) & 0xffff;
140 			if (ACCESSING_BITS_0_15)
141 				m_frame[0].x = data & 0xffff;
142 			break;
143 
144 		case 0x24:      // Framebuffer 1 Origin(?)
145 			if (ACCESSING_BITS_16_31)
146 				m_frame[1].y = (data >> 16) & 0xffff;
147 			if (ACCESSING_BITS_0_15)
148 				m_frame[1].x = data & 0xffff;
149 			break;
150 
151 		case 0x28:      // Framebuffer 2 Origin(?)
152 			if (ACCESSING_BITS_16_31)
153 				m_frame[2].y = (data >> 16) & 0xffff;
154 			if (ACCESSING_BITS_0_15)
155 				m_frame[2].x = data & 0xffff;
156 			break;
157 
158 		case 0x2c:      // Framebuffer 3 Origin(?)
159 			if (ACCESSING_BITS_16_31)
160 				m_frame[3].y = (data >> 16) & 0xffff;
161 			if (ACCESSING_BITS_0_15)
162 				m_frame[3].x = data & 0xffff;
163 			break;
164 
165 		case 0x30:      // Framebuffer 0 Dimensions
166 			if (ACCESSING_BITS_16_31)
167 				m_frame[0].height = (data >> 16) & 0xffff;
168 			if (ACCESSING_BITS_0_15)
169 				m_frame[0].width = data & 0xffff;
170 #if PRINT_GCU
171 			printf("%s FB0 Dimensions: W %04X, H %04X\n", basetag(), data & 0xffff, (data >> 16) & 0xffff);
172 #endif
173 			break;
174 
175 		case 0x34:      // Framebuffer 1 Dimensions
176 			if (ACCESSING_BITS_16_31)
177 				m_frame[1].height = (data >> 16) & 0xffff;
178 			if (ACCESSING_BITS_0_15)
179 				m_frame[1].width = data & 0xffff;
180 #if PRINT_GCU
181 			printf("%s FB1 Dimensions: W %04X, H %04X\n", basetag(), data & 0xffff, (data >> 16) & 0xffff);
182 #endif
183 			break;
184 
185 		case 0x38:      // Framebuffer 2 Dimensions
186 			if (ACCESSING_BITS_16_31)
187 				m_frame[2].height = (data >> 16) & 0xffff;
188 			if (ACCESSING_BITS_0_15)
189 				m_frame[2].width = data & 0xffff;
190 #if PRINT_GCU
191 			printf("%s FB2 Dimensions: W %04X, H %04X\n", basetag(), data & 0xffff, (data >> 16) & 0xffff);
192 #endif
193 			break;
194 
195 		case 0x3c:      // Framebuffer 3 Dimensions
196 			if (ACCESSING_BITS_16_31)
197 				m_frame[3].height = (data >> 16) & 0xffff;
198 			if (ACCESSING_BITS_0_15)
199 				m_frame[3].width = data & 0xffff;
200 #if PRINT_GCU
201 			printf("%s FB3 Dimensions: W %04X, H %04X\n", basetag(), data & 0xffff, (data >> 16) & 0xffff);
202 #endif
203 			break;
204 
205 		case 0x40:      // Framebuffer 0 Base
206 			m_frame[0].base = data;
207 #if PRINT_GCU
208 			printf("%s FB0 Base: %08X\n", basetag(), data);
209 #endif
210 			break;
211 
212 		case 0x44:      // Framebuffer 1 Base
213 			m_frame[1].base = data;
214 #if PRINT_GCU
215 			printf("%s FB1 Base: %08X\n", basetag(), data);
216 #endif
217 			break;
218 
219 		case 0x48:      // Framebuffer 2 Base
220 			m_frame[2].base = data;
221 #if PRINT_GCU
222 			printf("%s FB2 Base: %08X\n", basetag(), data);
223 #endif
224 			break;
225 
226 		case 0x4c:      // Framebuffer 3 Base
227 			m_frame[3].base = data;
228 #if PRINT_GCU
229 			printf("%s FB3 Base: %08X\n", basetag(), data);
230 #endif
231 			break;
232 
233 		case 0x54:
234 			if (ACCESSING_BITS_16_31)
235 				m_ext_fifo_num_lines = data >> 16;
236 			if (ACCESSING_BITS_0_15)
237 				m_ext_fifo_width = data & 0xffff;
238 			break;
239 
240 		case 0x58:
241 			m_ext_fifo_addr = (data & 0xffffff);
242 			break;
243 
244 		case 0x5c:      // VRAM Read Address
245 			m_vram_read_addr = (data & 0xffffff) / 2;
246 			break;
247 
248 		case 0x60:      // VRAM Port 0 Write Address
249 			m_vram_fifo0_addr = (data & 0xffffff) / 2;
250 			break;
251 
252 		case 0x68:      // VRAM Port 0/1 Mode
253 			if (ACCESSING_BITS_16_31)
254 				m_vram_fifo0_mode = data >> 16;
255 			if (ACCESSING_BITS_0_15)
256 				m_vram_fifo1_mode = data & 0xffff;
257 			break;
258 
259 		case 0x70:      // VRAM Port 0 Write FIFO
260 			if (m_vram_fifo0_mode & 0x100)
261 			{
262 				// write to command fifo
263 				m_command_fifo0[m_command_fifo0_ptr] = data;
264 				m_command_fifo0_ptr++;
265 
266 				// execute when filled
267 				if (m_command_fifo0_ptr >= 4)
268 				{
269 					//printf("GCU FIFO0 exec: %08X %08X %08X %08X\n", m_command_fifo0[0], m_command_fifo0[1], m_command_fifo0[2], m_command_fifo0[3]);
270 					execute_command(m_command_fifo0);
271 					m_command_fifo0_ptr = 0;
272 				}
273 			}
274 			else
275 			{
276 				// write to VRAM fifo
277 				m_vram[m_vram_fifo0_addr] = data;
278 				m_vram_fifo0_addr++;
279 			}
280 			break;
281 
282 		case 0x64:      // VRAM Port 1 Write Address
283 			m_vram_fifo1_addr = (data & 0xffffff) / 2;
284 			break;
285 
286 		case 0x74:      // VRAM Port 1 Write FIFO
287 			if (m_vram_fifo1_mode & 0x100)
288 			{
289 				// write to command fifo
290 				m_command_fifo1[m_command_fifo1_ptr] = data;
291 				m_command_fifo1_ptr++;
292 
293 				// execute when filled
294 				if (m_command_fifo1_ptr >= 4)
295 				{
296 					//printf("GCU FIFO1 exec: %08X %08X %08X %08X\n", m_command_fifo1[0], m_command_fifo1[1], m_command_fifo1[2], m_command_fifo1[3]);
297 					execute_command(m_command_fifo1);
298 					m_command_fifo1_ptr = 0;
299 				}
300 			}
301 			else
302 			{
303 				// write to VRAM fifo
304 				m_vram[m_vram_fifo1_addr] = data;
305 				m_vram_fifo1_addr++;
306 			}
307 			break;
308 
309 		case 0x6c:
310 			if (ACCESSING_BITS_0_15)
311 			{
312 				m_reg_6c = data & 0xffff;
313 			}
314 			break;
315 
316 		default:
317 			//printf("%s_w: %02X, %08X, %08X\n", basetag(), reg, data, mem_mask);
318 			break;
319 	}
320 }
321 
fifo_w(offs_t offset,uint32_t data,uint32_t mem_mask)322 void k057714_device::fifo_w(offs_t offset, uint32_t data, uint32_t mem_mask)
323 {
324 	if (ACCESSING_BITS_16_31)
325 	{
326 		if (m_ext_fifo_count != 0)      // first access is a dummy write
327 		{
328 			int count = m_ext_fifo_count - 1;
329 			uint32_t addr = (((m_ext_fifo_addr >> 10) + m_ext_fifo_line) * 1024) + count;
330 
331 			if ((count & 1) == 0)
332 			{
333 				m_vram[addr >> 1] &= 0x0000ffff;
334 				m_vram[addr >> 1] |= (data & 0xffff0000);
335 			}
336 			else
337 			{
338 				m_vram[addr >> 1] &= 0xffff0000;
339 				m_vram[addr >> 1] |= (data >> 16);
340 			}
341 		}
342 		m_ext_fifo_count++;
343 
344 		if (m_ext_fifo_count > m_ext_fifo_width+1)
345 		{
346 			m_ext_fifo_line++;
347 			m_ext_fifo_count = 0;
348 		}
349 	}
350 }
351 
draw_frame(int frame,bitmap_ind16 & bitmap,const rectangle & cliprect,bool inverse_trans)352 void k057714_device::draw_frame(int frame, bitmap_ind16 &bitmap, const rectangle &cliprect, bool inverse_trans)
353 {
354 	int height = m_frame[frame].height;
355 	int width = m_frame[frame].width;
356 
357 	if (width == 0 || height == 0)
358 		return;
359 
360 	uint16_t *vram16 = (uint16_t*)m_vram.get();
361 
362 	int fb_pitch = 1024;
363 
364 	uint16_t trans_value = inverse_trans ? 0x8000 : 0x0000;
365 
366 	if (m_frame[frame].y + height > cliprect.max_y)
367 		height = cliprect.max_y - m_frame[frame].y;
368 	if (m_frame[frame].x + width > cliprect.max_x)
369 		width = cliprect.max_x - m_frame[frame].x;
370 
371 	for (int j = 0; j < height; j++)
372 	{
373 		uint16_t *const d = &bitmap.pix(j + m_frame[frame].y, m_frame[frame].x);
374 		int li = (j * fb_pitch);
375 		for (int i = 0; i < width; i++)
376 		{
377 			uint16_t pix = vram16[(m_frame[frame].base + li + i) ^ NATIVE_ENDIAN_VALUE_LE_BE(1, 0)];
378 			if ((pix & 0x8000) != trans_value) {
379 				d[i] = pix & 0x7fff;
380 			}
381 		}
382 	}
383 }
384 
draw(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)385 int k057714_device::draw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
386 {
387 	int width = m_frame[0].width;
388 	int height = m_frame[0].height;
389 
390 	if (width != 0 && height != 0)
391 	{
392 		rectangle visarea = screen.visible_area();
393 		if ((visarea.max_x+1) != width || (visarea.max_y+1) != height)
394 		{
395 			visarea.max_x = width-1;
396 			visarea.max_y = height-1;
397 			screen.configure(width, height, visarea, screen.frame_period().attoseconds());
398 		}
399 	}
400 
401 	bitmap.fill(0, cliprect);
402 
403 	bool inverse_trans = false;
404 
405 	// most likely wrong, inverse transparency is only used by kbm
406 	if ((m_reg_6c & 0xf) != 0)
407 		inverse_trans = true;
408 
409 	draw_frame((m_layer_select >> 8) & 3, bitmap, cliprect, inverse_trans);
410 	draw_frame((m_layer_select >> 10) & 3, bitmap, cliprect, inverse_trans);
411 	draw_frame((m_layer_select >> 12) & 3, bitmap, cliprect, inverse_trans);
412 	draw_frame((m_layer_select >> 14) & 3, bitmap, cliprect, inverse_trans);
413 
414 	return 0;
415 }
416 
draw_object(uint32_t * cmd)417 void k057714_device::draw_object(uint32_t *cmd)
418 {
419 	// 0x00: xxx----- -------- -------- --------   command (5)
420 	// 0x00: ---x---- -------- -------- --------   0: absolute coordinates
421 	//                                             1: relative coordinates from framebuffer origin
422 	// 0x00: ----xx-- -------- -------- --------   ?
423 	// 0x00: -------- xxxxxxxx xxxxxxxx xxxxxxxx   object data address in vram
424 
425 	// 0x01: -------- -------- ------xx xxxxxxxx   object x
426 	// 0x01: -------- xxxxxxxx xxxxxx-- --------   object y
427 	// 0x01: -----x-- -------- -------- --------   object x flip
428 	// 0x01: ----x--- -------- -------- --------   object y flip
429 	// 0x01: --xx---- -------- -------- --------   object alpha enable (different blend modes?)
430 	// 0x01: -x------ -------- -------- --------   object transparency enable (?)
431 	// 0x01: x------- -------- -------- --------   inverse transparency? (used by kbm)
432 
433 	// 0x02: -------- -------- ------xx xxxxxxxx   object width
434 	// 0x02: -------- -----xxx xxxxxx-- --------   object x scale
435 	// 0x02: xxxxx--- -------- -------- --------   ?
436 	// 0x02: -----xxx xx------ -------- --------   translucency
437 	// 0x02: -------- --xxx--- -------- --------   ?
438 
439 	// 0x03: -------- -------- ------xx xxxxxxxx   object height
440 	// 0x03: -------- -----xxx xxxxxx-- --------   object y scale
441 	// 0x03: xxxxx--- -------- -------- --------   ?
442 	// 0x03: -----xxx xx------ -------- --------   ?
443 	// 0x03: -------- --xxx--- -------- --------   ?
444 
445 	int x = cmd[1] & 0x3ff;
446 	int y = (cmd[1] >> 10) & 0x3fff;
447 	int width = (cmd[2] & 0x3ff) + 1;
448 	int height = (cmd[3] & 0x3ff)  + 1;
449 	int xscale = (cmd[2] >> 10) & 0x1ff;
450 	int yscale = (cmd[3] >> 10) & 0x1ff;
451 	bool xflip = (cmd[1] & 0x04000000) ? true : false;
452 	bool yflip = (cmd[1] & 0x08000000) ? true : false;
453 	bool alpha_enable = (cmd[1] & 0x30000000) ? true : false;
454 	bool trans_enable = (cmd[1] & 0xc0000000) ? true : false;
455 	uint32_t address = cmd[0] & 0xffffff;
456 	int alpha_level = (cmd[2] >> 22) & 0x1f;
457 	bool relative_coords = (cmd[0] & 0x10000000) ? true : false;
458 
459 	uint16_t trans_value = (cmd[1] & 0x80000000) ? 0x0000 : 0x8000;
460 
461 	if (relative_coords)
462 	{
463 		x += m_fb_origin_x;
464 		y += m_fb_origin_y;
465 	}
466 
467 	uint16_t *vram16 = (uint16_t*)m_vram.get();
468 
469 	if (xscale == 0 || yscale == 0)
470 	{
471 		return;
472 	}
473 
474 #if PRINT_CMD_EXEC
475 	printf("%s Draw Object %08X, x %d, y %d, w %d, h %d, sx: %f, sy: %f [%08X %08X %08X %08X]\n", basetag(), address, x, y, width, height, (float)(xscale) / 64.0f, (float)(yscale) / 64.0f, cmd[0], cmd[1], cmd[2], cmd[3]);
476 #endif
477 
478 	width = (((width * 65536) / xscale) * 64) / 65536;
479 	height = (((height * 65536) / yscale) * 64) / 65536;
480 
481 	int fb_width = m_frame[0].width;
482 	int fb_height = m_frame[0].height;
483 
484 	if (width > fb_width)
485 		width = fb_width;
486 	if (height > fb_height)
487 		height = fb_height;
488 
489 	int fb_pitch = 1024;
490 
491 	int v = 0;
492 	for (int j=0; j < height; j++)
493 	{
494 		int index;
495 		int xinc;
496 		uint32_t fbaddr = ((j+y) * fb_pitch) + x;
497 
498 		if (yflip)
499 		{
500 			index = address + ((height - 1 - (v >> 6)) * 1024);
501 		}
502 		else
503 		{
504 			index = address + ((v >> 6) * 1024);
505 		}
506 
507 		if (xflip)
508 		{
509 			fbaddr += width;
510 			xinc = -1;
511 		}
512 		else
513 		{
514 			xinc = 1;
515 		}
516 
517 		int u = 0;
518 		for (int i=0; i < width; i++)
519 		{
520 			uint16_t pix = vram16[((index + (u >> 6)) ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)) & 0xffffff];
521 			bool draw = !trans_enable || (trans_enable && ((pix & 0x8000) == trans_value));
522 			if (alpha_enable)
523 			{
524 				if (draw)
525 				{
526 					if ((pix & 0x7fff) != 0)
527 					{
528 						uint16_t srcpix = vram16[fbaddr ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)];
529 
530 						uint32_t sr = (srcpix >> 10) & 0x1f;
531 						uint32_t sg = (srcpix >>  5) & 0x1f;
532 						uint32_t sb = (srcpix >>  0) & 0x1f;
533 						uint32_t r = (pix >> 10) & 0x1f;
534 						uint32_t g = (pix >>  5) & 0x1f;
535 						uint32_t b = (pix >>  0) & 0x1f;
536 
537 						sr += (r * alpha_level) >> 4;
538 						sg += (g * alpha_level) >> 4;
539 						sb += (b * alpha_level) >> 4;
540 
541 						if (sr > 0x1f) sr = 0x1f;
542 						if (sg > 0x1f) sg = 0x1f;
543 						if (sb > 0x1f) sb = 0x1f;
544 
545 						vram16[fbaddr ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = (sr << 10) | (sg << 5) | sb | (pix & 0x8000);
546 					}
547 				}
548 			}
549 			else
550 			{
551 				if (draw)
552 				{
553 					vram16[fbaddr ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = (pix & 0xffff);
554 				}
555 			}
556 
557 			fbaddr += xinc;
558 			u += xscale;
559 		}
560 
561 		v += yscale;
562 	}
563 }
564 
fill_rect(uint32_t * cmd)565 void k057714_device::fill_rect(uint32_t *cmd)
566 {
567 	// 0x00: xxx----- -------- -------- --------       command (4)
568 	// 0x00: ---x---- -------- -------- --------   0: absolute coordinates
569 	//                                             1: relative coordinates from framebuffer origin
570 	// 0x00: ----xx-- -------- -------- --------   ?
571 	// 0x00: -------- -------- ------xx xxxxxxxx   width
572 	// 0x00: -------- ----xxxx xxxxxx-- --------   height
573 
574 	// 0x01: -------- -------- ------xx xxxxxxxx   x
575 	// 0x01: -------- xxxxxxxx xxxxxx-- --------   y
576 	// 0x01: ---x---- -------- -------- --------   ?
577 
578 	// 0x02: xxxxxxxx xxxxxxxx -------- --------   fill pattern pixel 0
579 	// 0x02: -------- -------- xxxxxxxx xxxxxxxx   fill pattern pixel 1
580 
581 	// 0x03: xxxxxxxx xxxxxxxx -------- --------   fill pattern pixel 2
582 	// 0x03: -------- -------- xxxxxxxx xxxxxxxx   fill pattern pixel 3
583 
584 	int x = cmd[1] & 0x3ff;
585 	int y = (cmd[1] >> 10) & 0x3fff;
586 	int width = (cmd[0] & 0x3ff) + 1;
587 	int height = ((cmd[0] >> 10) & 0x3ff) + 1;
588 	bool relative_coords = (cmd[0] & 0x10000000) ? true : false;
589 
590 	if (relative_coords)
591 	{
592 		x += m_fb_origin_x;
593 		y += m_fb_origin_y;
594 	}
595 
596 	uint16_t color[4];
597 	color[0] = (cmd[2] >> 16);
598 	color[1] = (cmd[2] & 0xffff);
599 	color[2] = (cmd[3] >> 16);
600 	color[3] = (cmd[3] & 0xffff);
601 
602 #if PRINT_CMD_EXEC
603 	printf("%s Fill Rect x %d, y %d, w %d, h %d, %08X %08X [%08X %08X %08X %08X]\n", basetag(), x, y, width, height, cmd[2], cmd[3], cmd[0], cmd[1], cmd[2], cmd[3]);
604 #endif
605 
606 	int x1 = x;
607 	int x2 = x + width;
608 	int y1 = y;
609 	int y2 = y + height;
610 
611 	uint16_t *vram16 = (uint16_t*)m_vram.get();
612 
613 	int fb_pitch = 1024;
614 
615 	for (int j=y1; j < y2; j++)
616 	{
617 		uint32_t fbaddr = j * fb_pitch;
618 		for (int i=x1; i < x2; i++)
619 		{
620 			vram16[(fbaddr+i) ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = color[i&3];
621 		}
622 	}
623 }
624 
draw_character(uint32_t * cmd)625 void k057714_device::draw_character(uint32_t *cmd)
626 {
627 	// 0x00: xxx----- -------- -------- --------   command (7)
628 	// 0x00: ---x---- -------- -------- --------   0: absolute coordinates
629 	//                                             1: relative coordinates from framebuffer base (unverified, should be same as other operations)
630 	// 0x00: -------- xxxxxxxx xxxxxxxx xxxxxxxx   character data address in vram
631 
632 	// 0x01: -------- -------- ------xx xxxxxxxx   character x
633 	// 0x01: -------- xxxxxxxx xxxxxx-- --------   character y
634 	// 0x01: -------x -------- -------- --------   double height
635 	// 0x01: --x----- -------- -------- --------   ?
636 	// 0x01: -x------ -------- -------- --------   transparency enable
637 
638 	// 0x02: xxxxxxxx xxxxxxxx -------- --------   color 0
639 	// 0x02: -------- -------- xxxxxxxx xxxxxxxx   color 1
640 
641 	// 0x03: xxxxxxxx xxxxxxxx -------- --------   color 2
642 	// 0x03: -------- -------- xxxxxxxx xxxxxxxx   color 3
643 
644 	int x = cmd[1] & 0x3ff;
645 	int y = (cmd[1] >> 10) & 0x3fff;
646 	uint32_t address = cmd[0] & 0xffffff;
647 	uint16_t color[4];
648 	bool relative_coords = (cmd[0] & 0x10000000) ? true : false;
649 	bool double_height = (cmd[1] & 0x01000000) ? true : false;
650 	bool trans_enable = (cmd[1] & 0x40000000) ? true : false;
651 
652 	if (relative_coords)
653 	{
654 		x += m_fb_origin_x;
655 		y += m_fb_origin_y;
656 	}
657 
658 	color[0] = cmd[2] >> 16;
659 	color[1] = cmd[2] & 0xffff;
660 	color[2] = cmd[3] >> 16;
661 	color[3] = cmd[3] & 0xffff;
662 
663 #if PRINT_CMD_EXEC
664 	printf("%s Draw Char %08X, x %d, y %d [%08X %08X %08X %08X]\n", basetag(), address, x, y, cmd[0], cmd[1], cmd[2], cmd[3]);
665 #endif
666 
667 	uint16_t *vram16 = (uint16_t*)m_vram.get();
668 	int fb_pitch = 1024;
669 	int height = double_height ? 16 : 8;
670 
671 	for (int j=0; j < height; j++)
672 	{
673 		uint32_t fbaddr = (y+j) * fb_pitch;
674 		uint16_t line = vram16[address ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)];
675 
676 		address += 4;
677 
678 		for (int i=0; i < 8; i++)
679 		{
680 			int p = (line >> ((7-i) * 2)) & 3;
681 			bool draw = !trans_enable || (trans_enable && (color[p] & 0x8000));
682 			if (draw)
683 				vram16[(fbaddr+x+i) ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = color[p];
684 		}
685 	}
686 }
687 
fb_config(uint32_t * cmd)688 void k057714_device::fb_config(uint32_t *cmd)
689 {
690 	// 0x00: xxx----- -------- -------- --------   command (3)
691 
692 	// 0x01: -------- -------- -------- --------   unused?
693 
694 	// 0x02: -------- -------- ------xx xxxxxxxx   Framebuffer Origin X
695 
696 	// 0x03: -------- -------- --xxxxxx xxxxxxxx   Framebuffer Origin Y
697 
698 #if PRINT_CMD_EXEC
699 	printf("%s FB Config %08X %08X %08X %08X\n", basetag(), cmd[0], cmd[1], cmd[2], cmd[3]);
700 #endif
701 
702 	m_fb_origin_x = cmd[2] & 0x3ff;
703 	m_fb_origin_y = cmd[3] & 0x3fff;
704 }
705 
execute_display_list(uint32_t addr)706 void k057714_device::execute_display_list(uint32_t addr)
707 {
708 	bool end = false;
709 
710 	int counter = 0;
711 
712 #if PRINT_CMD_EXEC
713 	printf("%s Exec Display List %08X\n", basetag(), addr);
714 #endif
715 
716 	addr /= 2;
717 	while (!end && counter < 0x1000 && addr < (0x2000000/4))
718 	{
719 		uint32_t *cmd = &m_vram[addr];
720 		addr += 4;
721 
722 		int command = (cmd[0] >> 29) & 0x7;
723 
724 		switch (command)
725 		{
726 			case 0:     // NOP?
727 				break;
728 
729 			case 1:     // Execute display list
730 				execute_display_list(cmd[0] & 0xffffff);
731 				break;
732 
733 			case 2:     // End of display list
734 				end = true;
735 				break;
736 
737 			case 3:     // Framebuffer config
738 				fb_config(cmd);
739 				break;
740 
741 			case 4:     // Fill rectangle
742 				fill_rect(cmd);
743 				break;
744 
745 			case 5:     // Draw object
746 				draw_object(cmd);
747 				break;
748 
749 			case 6:
750 			case 7:     // Draw 8x8 character (2 bits per pixel)
751 				draw_character(cmd);
752 				break;
753 
754 			default:
755 				printf("GCU Unknown command %08X %08X %08X %08X\n", cmd[0], cmd[1], cmd[2], cmd[3]);
756 				break;
757 		}
758 		counter++;
759 	};
760 }
761 
execute_command(uint32_t * cmd)762 void k057714_device::execute_command(uint32_t* cmd)
763 {
764 	int command = (cmd[0] >> 29) & 0x7;
765 
766 #if PRINT_CMD_EXEC
767 	printf("%s Exec Command %08X, %08X, %08X, %08X\n", basetag(), cmd[0], cmd[1], cmd[2], cmd[3]);
768 #endif
769 
770 	switch (command)
771 	{
772 		case 0:     // NOP?
773 			break;
774 
775 		case 1:     // Execute display list
776 			execute_display_list(cmd[0] & 0xffffff);
777 			break;
778 
779 		case 2:     // End of display list
780 			break;
781 
782 		case 3:     // Framebuffer config
783 			fb_config(cmd);
784 			break;
785 
786 		case 4:     // Fill rectangle
787 			fill_rect(cmd);
788 			break;
789 
790 		case 5:     // Draw object
791 			draw_object(cmd);
792 			break;
793 
794 		case 6:
795 		case 7:     // Draw 8x8 character (2 bits per pixel)
796 			draw_character(cmd);
797 			break;
798 
799 		default:
800 			printf("GCU Unknown command %08X %08X %08X %08X\n", cmd[0], cmd[1], cmd[2], cmd[3]);
801 			break;
802 	}
803 }
804