1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /*************************************************************************
4 
5     Midway Zeus2 Video
6 
7 **************************************************************************/
8 #include "emu.h"
9 #include "zeus2.h"
10 
11 #include <algorithm>
12 
13 
14 #define LOG_REGS         1
15 // Setting ALWAYS_LOG_FIFO will always log the fifo versus having to hold 'L'
16 #define ALWAYS_LOG_FIFO  0
17 
18 /*************************************
19 *  Constructor
20 *************************************/
zeus2_renderer(zeus2_device * state)21 zeus2_renderer::zeus2_renderer(zeus2_device *state)
22 	: poly_manager<float, zeus2_poly_extra_data, 4, 10000>(state->machine())
23 	, m_state(state)
24 {
25 }
26 
27 DEFINE_DEVICE_TYPE(ZEUS2, zeus2_device, "zeus2", "Midway Zeus2")
28 
zeus2_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)29 zeus2_device::zeus2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
30 	: device_t(mconfig, ZEUS2, tag, owner, clock)
31 	, device_video_interface(mconfig, *this)
32 	, m_vblank(*this), m_irq(*this), m_atlantis(0)
33 {
34 }
35 
36 /*************************************
37 *  Display interrupt generation
38 *************************************/
39 
TIMER_CALLBACK_MEMBER(zeus2_device::display_irq_off)40 TIMER_CALLBACK_MEMBER(zeus2_device::display_irq_off)
41 {
42 	m_vblank(CLEAR_LINE);
43 
44 	//attotime vblank_period = screen().time_until_pos(m_zeusbase[0x37] & 0xffff);
45 
46 	///* if zero, adjust to next frame, otherwise we may get stuck in an infinite loop */
47 	//if (vblank_period == attotime::zero)
48 	//  vblank_period = screen().frame_period();
49 	//vblank_timer->adjust(vblank_period);
50 	vblank_timer->adjust(screen().time_until_vblank_start());
51 	//machine().scheduler().timer_set(attotime::from_hz(30000000), timer_expired_delegate(FUNC(zeus2_device::display_irq), this));
52 }
53 
TIMER_CALLBACK_MEMBER(zeus2_device::display_irq)54 TIMER_CALLBACK_MEMBER(zeus2_device::display_irq)
55 {
56 	m_vblank(ASSERT_LINE);
57 	/* set a timer for the next off state */
58 	//machine().scheduler().timer_set(screen().time_until_pos(0), timer_expired_delegate(FUNC(zeus2_device::display_irq_off), this), 0, this);
59 	machine().scheduler().timer_set(screen().time_until_vblank_end(), timer_expired_delegate(FUNC(zeus2_device::display_irq_off), this), 0, this);
60 	//machine().scheduler().timer_set(attotime::from_hz(30000000), timer_expired_delegate(FUNC(zeus2_device::display_irq_off), this));
61 }
62 
TIMER_CALLBACK_MEMBER(zeus2_device::int_timer_callback)63 TIMER_CALLBACK_MEMBER(zeus2_device::int_timer_callback)
64 {
65 	//m_maincpu->set_input_line(2, ASSERT_LINE);
66 	m_irq(ASSERT_LINE);
67 }
68 
69 /*************************************
70  *  Video startup
71  *************************************/
72 
73 
device_start()74 void zeus2_device::device_start()
75 {
76 	/* allocate memory for "wave" RAM */
77 	m_waveram = std::make_unique<uint32_t[]>(WAVERAM0_WIDTH * WAVERAM0_HEIGHT * 8/4);
78 	m_frameColor = std::make_unique<uint32_t[]>(WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 2);
79 	m_frameDepth = std::make_unique<int32_t[]>(WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 2);
80 
81 	/* initialize polygon engine */
82 	poly = std::make_unique<zeus2_renderer>(this);
83 
84 	m_vblank.resolve_safe();
85 	m_irq.resolve_safe();
86 
87 	/* we need to cleanup on exit */
88 	//machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&zeus2_device::exit_handler2, this));
89 
90 	int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(zeus2_device::int_timer_callback), this));
91 
92 	vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(zeus2_device::display_irq), this));
93 
94 	//printf("%s\n", machine().system().name);
95 	// Set system type
96 	if (strcmp(machine().system().name, "thegrid") == 0 || strcmp(machine().system().name, "thegrida") == 0) {
97 		m_system = THEGRID;
98 	}
99 	else if (strcmp(machine().system().name, "crusnexo") == 0) {
100 		m_system = CRUSNEXO;
101 	}
102 	else {
103 		m_system = MWSKINS;
104 	}
105 
106 	/* save states */
107 	save_item(NAME(m_atlantis));
108 	save_item(NAME(m_zeusbase));
109 	save_item(NAME(m_renderRegs));
110 	// poly
111 	save_item(NAME(zeus_cliprect.min_x));
112 	save_item(NAME(zeus_cliprect.max_x));
113 	save_item(NAME(zeus_cliprect.min_y));
114 	save_item(NAME(zeus_cliprect.max_y));
115 	save_item(NAME(m_palSize));
116 	save_item(NAME(zeus_matrix));
117 	save_item(NAME(zeus_trans));
118 	save_item(NAME(zeus_light));
119 	save_item(NAME(zeus_texbase));
120 	save_item(NAME(zeus_quad_size));
121 	save_item(NAME(m_useZOffset));
122 	save_pointer(NAME(m_waveram), WAVERAM0_WIDTH * WAVERAM0_HEIGHT * 8 / 4);
123 	save_pointer(NAME(m_frameColor), WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 2);
124 	save_pointer(NAME(m_frameDepth), WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 2);
125 	save_item(NAME(m_pal_table));
126 	// m_ucode
127 	save_item(NAME(m_curUCodeSrc));
128 	save_item(NAME(m_curPalTableSrc));
129 	save_item(NAME(m_texmodeReg));
130 	// int_timer
131 	// vblank_timer
132 	// yoffs
133 	// texel_width
134 	// zbase
135 	save_item(NAME(m_system));
136 	save_item(NAME(zeus_fifo));
137 	save_item(NAME(zeus_fifo_words));
138 	save_item(NAME(m_fill_color));
139 	save_item(NAME(m_fill_depth));
140 	save_item(NAME(m_yScale));
141 }
142 
device_reset()143 void zeus2_device::device_reset()
144 {
145 	memset(m_zeusbase, 0, sizeof(m_zeusbase[0]) * 0x80);
146 	memset(m_renderRegs, 0, sizeof(m_renderRegs[0]) * 0x50);
147 
148 	m_curUCodeSrc = 0;
149 	m_curPalTableSrc = 0;
150 	m_palSize = 0;
151 	zbase = 32.0f;
152 	m_yScale = 0;
153 	yoffs = 0x1dc000;
154 	//yoffs = 0x00040000;
155 	texel_width = 256;
156 	zeus_fifo_words = 0;
157 	m_fill_color = 0;
158 	m_fill_depth = 0;
159 	m_texmodeReg = 0;
160 	zeus_trans[3] = 0.0f;
161 	m_useZOffset = false;
162 }
163 #if DUMP_WAVE_RAM
164 #include <iostream>
165 #include <fstream>
166 #endif
device_stop()167 void zeus2_device::device_stop()
168 {
169 #if DUMP_WAVE_RAM
170 	std::string fileName = "waveram_";
171 	fileName += machine().system().name;
172 	fileName += ".bin";
173 	std::ofstream myfile;
174 	myfile.open(fileName.c_str(), std::ios::out | std::ios::trunc | std::ios::binary);
175 
176 	if (myfile.is_open())
177 		myfile.write((char *)m_waveram.get(), WAVERAM0_WIDTH * WAVERAM0_HEIGHT * 2 * sizeof(uint32_t));
178 	myfile.close();
179 #endif
180 
181 #if TRACK_REG_USAGE
182 {
183 	reg_info *info;
184 	int regnum;
185 
186 	for (regnum = 0; regnum < 0x80; regnum++)
187 	{
188 		printf("Register %02X\n", regnum);
189 		if (regread_count[regnum] == 0)
190 			printf("\tNever read\n");
191 		else
192 			printf("\tRead %d times\n", regread_count[regnum]);
193 
194 		if (regwrite_count[regnum] == 0)
195 			printf("\tNever written\n");
196 		else
197 		{
198 			printf("\tWritten %d times\n", regwrite_count[regnum]);
199 			for (info = regdata[regnum]; info != nullptr; info = info->next)
200 				printf("\t%08X\n", info->value);
201 		}
202 	}
203 
204 	for (regnum = 0; regnum < 0x100; regnum++)
205 		if (subregwrite_count[regnum] != 0)
206 		{
207 			printf("Sub-Register %02X (%d writes)\n", regnum, subregwrite_count[regnum]);
208 			for (info = subregdata[regnum]; info != nullptr; info = info->next)
209 				printf("\t%08X\n", info->value);
210 		}
211 }
212 #endif
213 
214 }
215 
216 
217 
218 /*************************************
219  *
220  *  Video update
221  *
222  *************************************/
223 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)224 uint32_t zeus2_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
225 {
226 	// Wait until configuration is completed before transfering anything
227 	if (!(m_zeusbase[0x10] & 0x20))
228 		return 0;
229 
230 	int x, y;
231 
232 	//if (machine().input().code_pressed(KEYCODE_DOWN)) { zbase += machine().input().code_pressed(KEYCODE_LSHIFT) ? 0x10 : 1; popmessage("Zbase = %f", (double)zbase); }
233 	//if (machine().input().code_pressed(KEYCODE_UP)) { zbase -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 0x10 : 1; popmessage("Zbase = %f", (double)zbase); }
234 
235 	/* normal update case */
236 	//if (!machine().input().code_pressed(KEYCODE_W))
237 	if (1)
238 	{
239 		for (y = cliprect.min_y; y <= cliprect.max_y; y++)
240 		{
241 			uint32_t *colorptr = &m_frameColor[frame_addr_from_xy(0, y, false)];
242 			std::copy(colorptr + cliprect.min_x, colorptr + cliprect.max_x + 1, &bitmap.pix(y, cliprect.min_x));
243 		}
244 	}
245 
246 	/* waveram drawing case */
247 	else
248 	{
249 		const void *base;
250 
251 		if (machine().input().code_pressed(KEYCODE_DOWN)) yoffs += machine().input().code_pressed(KEYCODE_LSHIFT) ? 0x1000 : 40;
252 		if (machine().input().code_pressed(KEYCODE_UP)) yoffs -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 0x1000 : 40;
253 		if (machine().input().code_pressed(KEYCODE_LEFT) && texel_width > 4) { texel_width >>= 1; while (machine().input().code_pressed(KEYCODE_LEFT)) ; }
254 		if (machine().input().code_pressed(KEYCODE_RIGHT) && texel_width < 512) { texel_width <<= 1; while (machine().input().code_pressed(KEYCODE_RIGHT)) ; }
255 
256 		if (yoffs < 0) yoffs = 0;
257 		if (1) {
258 			//base = waveram0_ptr_from_expanded_addr(yoffs << 8);
259 			//base = waveram0_ptr_from_expanded_addr(yoffs);
260 			base = WAVERAM_BLOCK0(yoffs);
261 		}
262 		else
263 			base = (void *)&m_frameColor[yoffs << 6];
264 
265 		int xoffs = screen.visible_area().min_x;
266 		for (y = cliprect.min_y; y <= cliprect.max_y; y++)
267 		{
268 			uint32_t *const dest = &bitmap.pix(y);
269 			for (x = cliprect.min_x; x <= cliprect.max_x; x++)
270 			{
271 				if (1) {
272 					uint8_t tex = get_texel_8bit_4x2((uint64_t *)base, y, x, texel_width);
273 					dest[x] = (tex << 16) | (tex << 8) | tex;
274 				}
275 				else {
276 					dest[x] = ((uint32_t *)(base))[((y * WAVERAM1_WIDTH)) + x - xoffs];
277 				}
278 			}
279 		}
280 		popmessage("offs = %06X base = %08X", yoffs, base);
281 	}
282 
283 	return 0;
284 }
285 
286 
287 
288 /*************************************
289  *
290  *  Core read handler
291  *
292  *************************************/
293 
zeus2_r(offs_t offset)294 uint32_t zeus2_device::zeus2_r(offs_t offset)
295 {
296 	int logit = (offset != 0x00 && offset != 0x01 &&
297 		offset != 0x18 && offset != 0x19 && offset != 0x48 && offset != 0x49
298 		&& offset != 0x54 && offset != 0x58 && offset != 0x59 && offset != 0x5a
299 		);
300 	logit &= LOG_REGS;
301 	uint32_t result = m_zeusbase[offset];
302 #if TRACK_REG_USAGE
303 	regread_count[offset]++;
304 #endif
305 
306 	switch (offset)
307 	{
308 		case 0x00:
309 			// STATUS0
310 			// 0x20 IFIFO Empty
311 			// 0x80 IFIFO Full
312 			result = 0x20;
313 			break;
314 
315 		case 0x01:
316 			// STATUS1
317 			// 0x00000004 VBLANK
318 			// 0x40000000 Slave Error
319 			// 0x80000000 Master Error
320 			// 0x00000010 DP_ACTIVE
321 			// 0x00000020 TP_ACTIVE
322 			// 0x00000040 RP_ACTIVE
323 			// 0x00040000 EXPY_ACTIVE0
324 			// 0x00080000 EXPY_ACTIVE1
325 			/* bit  $000C0070 are tested in a loop until 0 */
326 			/* bits $00080000 is tested in a loop until 0 */
327 			/* bit  $00000004 is tested for toggling; probably VBLANK */
328 			result = 0x00;
329 			if (screen().vblank())
330 				result |= 0x04;
331 			break;
332 
333 		case 0x07:
334 			/* this is needed to pass the self-test in thegrid */
335 			result = 0x10451998;
336 			break;
337 
338 		case 0x18:
339 			// IFIFO Read Counter
340 			break;
341 
342 		case 0x19:
343 			// MFIFO Read Counter
344 			break;
345 
346 		case 0x54:
347 			// VCOUNT upper 16 bits
348 			//result = (screen().vpos() << 16) | screen().vpos();
349 			result = (screen().vpos() << 16);
350 			break;
351 	}
352 
353 	if (logit)
354 		logerror("%s:zeus2_r(%02X) = %08X\n", machine().describe_context(), offset, result);
355 
356 	return result;
357 }
358 
359 
360 
361 /*************************************
362  *
363  *  Core write handler
364  *
365  *************************************/
366 
zeus2_w(offs_t offset,uint32_t data)367 void zeus2_device::zeus2_w(offs_t offset, uint32_t data)
368 {
369 	int logit = (offset != 0x08 &&
370 					 offset != 0x18 && offset != 0x19 && (offset != 0x20 || data != 0) &&
371 					 offset != 0x35 && offset != 0x36 && offset != 0x37 &&
372 					 offset != 0x48 && offset != 0x49 && offset != 0x40 && offset != 0x41 && offset != 0x4e &&
373 					 offset != 0x50 && offset != 0x51 && offset != 0x57 && offset != 0x58 && offset != 0x59 && offset != 0x5a && offset != 0x5e
374 		);
375 	logit &= LOG_REGS;
376 	if (logit)
377 		logerror("%s:zeus2_w", machine().describe_context());
378 	zeus2_register32_w(offset, data, logit);
379 }
380 
381 
382 
383 /*************************************
384  *
385  *  Handle register writes
386  *
387  *************************************/
388 
zeus2_register32_w(offs_t offset,uint32_t data,int logit)389 void zeus2_device::zeus2_register32_w(offs_t offset, uint32_t data, int logit)
390 {
391 	uint32_t oldval = m_zeusbase[offset];
392 
393 #if TRACK_REG_USAGE
394 regwrite_count[offset]++;
395 if (regdata_count[offset] < 256)
396 {
397 	reg_info **tailptr;
398 
399 	for (tailptr = &regdata[offset]; *tailptr != nullptr; tailptr = &(*tailptr)->next)
400 		if ((*tailptr)->value == data)
401 			break;
402 	if (*tailptr == nullptr)
403 	{
404 		*tailptr = alloc_or_die(reg_info);
405 		(*tailptr)->next = nullptr;
406 		(*tailptr)->value = data;
407 		regdata_count[offset]++;
408 	}
409 }
410 #endif
411 
412 	/* writes to register $CC need to force a partial update */
413 //  if ((offset & ~1) == 0xcc)
414 //      screen().update_partial(screen().vpos());
415 
416 	/* always write to low word? */
417 	m_zeusbase[offset] = data;
418 
419 	/* log appropriately */
420 	if (logit) {
421 		logerror("(%02X) = %08X", offset, data);
422 	}
423 	/* handle the update */
424 	zeus2_register_update(offset, oldval, logit);
425 }
426 
427 
428 
429 /*************************************
430  *
431  *  Update state after a register write
432  *
433  *************************************/
434 
zeus2_register_update(offs_t offset,uint32_t oldval,int logit)435 void zeus2_device::zeus2_register_update(offs_t offset, uint32_t oldval, int logit)
436 {
437 	/* handle the writes; only trigger on low accesses */
438 	switch (offset)
439 	{
440 	case 0x08:
441 		zeus_fifo[zeus_fifo_words++] = m_zeusbase[0x08];
442 		if (zeus2_fifo_process(zeus_fifo, zeus_fifo_words))
443 			zeus_fifo_words = 0;
444 
445 		/* set the interrupt signal to indicate we can handle more */
446 		// Not sure how much to time to put here
447 		int_timer->adjust(attotime::from_usec(20));
448 		break;
449 
450 	case 0x10:
451 		// BITS 11 - 10 COL SIZE / BANK FOR WR1
452 		// BITS 9 - 8   COL SIZE / BANK FOR WR0
453 		if (logit) logerror("\tSys Setup");
454 		if (m_zeusbase[0x10] & 0x20)
455 		{
456 			m_yScale = (((m_zeusbase[0x39] >> 16) & 0xfff) < 0x100) ? 0 : 1;
457 			int hor = ((m_zeusbase[0x34] & 0xffff) - (m_zeusbase[0x33] >> 16)) << m_yScale;
458 			int ver = ((m_zeusbase[0x35] & 0xffff) + 1) << m_yScale;
459 			popmessage("reg[30]: %08X Screen: %dH X %dV yScale: %d", m_zeusbase[0x30], hor, ver, m_yScale);
460 			int vtotal = (m_zeusbase[0x37] & 0xffff) << m_yScale;
461 			int htotal = (m_zeusbase[0x34] >> 16) << m_yScale;
462 			//rectangle visarea((m_zeusbase[0x33] >> 16) << m_yScale, htotal - 1, 0, (m_zeusbase[0x35] & 0xffff) << m_yScale);
463 			rectangle visarea(0, hor - 1, 0, ver - 1);
464 			screen().configure(htotal, vtotal, visarea, HZ_TO_ATTOSECONDS(ZEUS2_VIDEO_CLOCK / 4.0 / (htotal * vtotal)));
465 			zeus_cliprect = visarea;
466 			zeus_cliprect.max_x -= zeus_cliprect.min_x;
467 			zeus_cliprect.min_x = 0;
468 			// Startup vblank timer
469 			vblank_timer->adjust(attotime::from_usec(1));
470 		}
471 		break;
472 
473 	case 0x11:
474 		if (logit) logerror("\tHost Interface Setup");
475 		break;
476 
477 	case 0x12:
478 		if (logit) logerror("\tPLL Setup");
479 		break;
480 
481 	case 0x13:
482 		if (logit) logerror("\tZeus Test Out");
483 		break;
484 
485 	case 0x20:
486 		zeus2_pointer_write(m_zeusbase[0x20] >> 24, (m_zeusbase[0x20] & 0xffffff), logit);
487 		break;
488 
489 	case 0x22:
490 		if (logit) logerror("\tRend Setup 0");
491 		break;
492 
493 	case 0x23:
494 		if (logit) logerror("\tRend Setup 1");
495 		break;
496 
497 	case 0x24:
498 		// 0x601 == test mode
499 		if (logit) logerror("\tRend Setup 4");
500 		break;
501 
502 	case 0x2a:
503 		// 0x000000c0 = bilinear off
504 		if (logit) logerror("\tRend Force Off");
505 		break;
506 
507 	case 0x2b:
508 		if (logit) logerror("\tRend Force On");
509 		break;
510 
511 	case 0x2c:
512 		if (logit) logerror("\tRend AE Flag");
513 		break;
514 
515 	case 0x2d:
516 		if (logit) logerror("\tRend AF Flag");
517 		break;
518 
519 	case 0x2f:
520 		if (logit) logerror("\tPixel Proc Setup");
521 		break;
522 
523 
524 	case 0x30:
525 		if (logit) logerror("\tCRT Controller Setup = %08X", m_zeusbase[offset]);
526 		break;
527 
528 	case 0x31:
529 		if (logit) logerror("\tDotClk Sel 1 : DotClk Sel 2 = %08X", m_zeusbase[offset]);
530 		break;
531 	case 0x32:
532 		if (logit) logerror("\tHSync End = %i HSync Start = %i", (m_zeusbase[offset] >> 16), m_zeusbase[offset] & 0xffff);
533 		break;
534 	case 0x33:
535 		if (logit) logerror("\tHBlank End = %i Update Start = %i", (m_zeusbase[offset] >> 16), m_zeusbase[offset] & 0xffff);
536 		break;
537 	case 0x34:
538 		if (logit) logerror("\tHTotal = %i HBlank Start = %i", (m_zeusbase[offset] >> 16), m_zeusbase[offset] & 0xffff);
539 		break;
540 	case 0x35:
541 		if (logit) logerror("\tVSync Start = %i VBlank Start = %i", (m_zeusbase[offset] >> 16), m_zeusbase[offset] & 0xffff);
542 		break;
543 	case 0x36:
544 		if (logit) logerror("\tVTotal = %i VSync End = %i", (m_zeusbase[offset] >> 16), m_zeusbase[offset] & 0xffff);
545 		break;
546 	case 0x37:
547 		if (logit) logerror("\tVTotal = %i", m_zeusbase[offset]);
548 		break;
549 	case 0x38:
550 	{
551 		uint32_t temp = m_zeusbase[0x38];
552 		m_zeusbase[0x38] = oldval;
553 		screen().update_partial(screen().vpos());
554 		log_fifo = machine().input().code_pressed(KEYCODE_L) | ALWAYS_LOG_FIFO;
555 		m_zeusbase[0x38] = temp;
556 	}
557 	break;
558 	case 0x39:
559 		if (logit) logerror("\tLine Length = %i FIFO AF = %i FIFO AE = %i", (m_zeusbase[offset] >> 16) & 0xfff, (m_zeusbase[offset] >> 8) & 0xff, m_zeusbase[offset] & 0xff);
560 		break;
561 
562 	case 0x40: case 0x41: case 0x48: case 0x49: case 0x4e:
563 		if (offset == 0x41) {
564 			// mwskinsa (atlantis) writes 0xffffffff and expects 0x1fff03ff to be read back
565 			m_zeusbase[0x41] &= 0x1fff03ff;
566 		}
567 		/*
568 		m_zeusbase[0x4e] :
569 		    bit 0 - 1 : which register triggers write through
570 		    bit 3 : enable write through via these registers
571 		    bit 4 : seems to be set during reads, when 0x41 is used for latching
572 		    bit 6 : enable autoincrement on write through
573 		*/
574 		if ((offset & 0xf) == (m_zeusbase[0x4e] & 0xf)) {
575 			// If the address is auto-increment then don't load new value
576 			// In reality address is latched by a write to 0x40
577 			if (offset == 0x41 && (m_zeusbase[0x4e] & 0x40)) {
578 				m_zeusbase[0x41] = oldval;
579 			}
580 
581 			int code = (m_zeusbase[0x40] >> 16) & 0xf;
582 			switch (code) {
583 			case 0:
584 				// NOP
585 				break;
586 			case 1:
587 				// Special mode register write
588 				//if (logit)
589 				logerror("\t-- Special Mode Write: [4e]: %08X [40]: %08X [41]: %08x [48]: %08x [49]: %08x\n", code, m_zeusbase[0x4e], m_zeusbase[0x40], m_zeusbase[0x41], m_zeusbase[0x48], m_zeusbase[0x49]);
590 				break;
591 			case 2:
592 			{
593 				/* Read waveram0 */
594 				//if ((m_zeusbase[0x4e] & 0x20))
595 				//{
596 				const void *src = waveram0_ptr_from_expanded_addr(m_zeusbase[0x41]);
597 				m_zeusbase[0x48] = WAVERAM_READ32(src, 0);
598 				m_zeusbase[0x49] = WAVERAM_READ32(src, 1);
599 
600 				if (m_zeusbase[0x4e] & 0x40)
601 				{
602 					m_zeusbase[0x41]++;
603 					m_zeusbase[0x41] += (m_zeusbase[0x41] & 0x400) << 6;
604 					m_zeusbase[0x41] &= ~0xfc00;
605 				}
606 				//}
607 			}
608 			break;
609 			case 4:
610 			{
611 				// Load pal table from RGB555
612 				if (logit)
613 					logerror("\t-- pal table rgb555 load: control: %08X addr: %08X", m_zeusbase[0x40], m_zeusbase[0x41]);
614 				poly->wait("PAL_TABLE_WRITE");
615 				// blocknum = (addr % WAVERAM0_WIDTH) + ((addr >> 16) % WAVERAM0_HEIGHT) * WAVERAM0_WIDTH;
616 				m_curPalTableSrc = (m_zeusbase[0x41] % WAVERAM0_WIDTH) + ((m_zeusbase[0x41] >> 16) % WAVERAM0_HEIGHT) * WAVERAM0_WIDTH;
617 				void *dataPtr = waveram0_ptr_from_expanded_addr(m_zeusbase[0x41]);
618 				load_pal_table(dataPtr, m_zeusbase[0x40], 0, logit);
619 			}
620 			break;
621 			case 5:
622 			{
623 				//if (m_zeusbase[0x41] == 0x266) {
624 				//  logit = 1;
625 				//  log_fifo = 1;
626 				//}
627 				// Zeus microcode burst from waveram
628 				if (logit)
629 					logerror("\t-- ucode load: control: %08X addr: %08X", m_zeusbase[0x40], m_zeusbase[0x41]);
630 				// Load ucode from waveram
631 				poly->wait("UCODE_LOAD");
632 				void *dataPtr = waveram0_ptr_from_expanded_addr(m_zeusbase[0x41]);
633 				load_ucode(dataPtr, m_zeusbase[0x40], logit);
634 				if (((m_zeusbase[0x40] >> 24) & 0xff) >= 0xc0) {
635 					// Light table load
636 					if (logit) logerror("\t-- light table loaded");
637 				}
638 				else {
639 					m_curUCodeSrc = m_zeusbase[0x41];
640 					m_useZOffset = false;
641 					// Zeus Quad Size
642 					if (m_system == THEGRID) {
643 						switch (m_curUCodeSrc) {
644 						case 0x000000037:
645 							// pm4dl: mfifo quads dynamic light
646 							zeus_quad_size = 14;
647 							if (logit) logerror(" pm4dl quad size %d\n", zeus_quad_size);
648 							break;
649 						case 0x0000000b3:
650 							// pm4sl: mfifo quads static light
651 							zeus_quad_size = 12;
652 							if (logit) logerror(" pm4sl quad size %d\n", zeus_quad_size);
653 							break;
654 						case 0x00000015d:
655 							// pm4nl: mfifo quads no light
656 							m_useZOffset = true;
657 							zeus_quad_size = 10;
658 							if (logit) logerror(" pm4nl quad size %d\n", zeus_quad_size);
659 							break;
660 						case 0x0000001d5:
661 							// pm4nluv: mfifo quads no light (tga and uv variants)
662 							m_useZOffset = true;
663 							zeus_quad_size = 10;
664 							if (logit) logerror(" pm4nluv pm4nl_tga quad size %d\n", zeus_quad_size);
665 							break;
666 						case 0x000000266:
667 							// pm3dli: mfifo trimesh dynamic light interpolation
668 							zeus_quad_size = 8;
669 							if (logit) logerror(" pm3dli quad size %d\n", zeus_quad_size);
670 							break;
671 						case 0x0000002e9:
672 							// px3sl: xfifo trimesh static light
673 							zeus_quad_size = 10;
674 							if (logit) logerror(" px3sl quad size %d\n", zeus_quad_size);
675 							break;
676 						case 0x000000343:
677 							// blit24: The Grid direct rendering
678 							// Really should be 128 but this works
679 							zeus_quad_size = 512;
680 							if (logit) logerror(" blit24 quad size %d\n", zeus_quad_size);
681 							break;
682 						default:
683 							zeus_quad_size = 10;
684 							logerror(" unknown quad size from source [41]=%08X\n", m_curUCodeSrc);
685 							break;
686 						}
687 					}
688 					else if (m_system == CRUSNEXO) {
689 						switch (m_curUCodeSrc) {
690 						case 0x0000000c0:
691 							zeus_quad_size = 10;
692 							if (logit) logerror(" c0 quad size %d\n", zeus_quad_size);
693 							break;
694 						case 0x000000136:
695 							zeus_quad_size = 14;
696 							if (logit) logerror(" 136 quad size %d\n", zeus_quad_size);
697 							break;
698 						case 0x0000001ba:
699 							zeus_quad_size = 10;
700 							if (logit) logerror(" 1ba quad size %d\n", zeus_quad_size);
701 							break;
702 						case 0x00000022b:
703 							zeus_quad_size = 12;
704 							if (logit) logerror(" 22b quad size %d\n", zeus_quad_size);
705 							break;
706 						case 0x00000029b:
707 							zeus_quad_size = 12;
708 							if (logit) logerror(" 29b quad size %d\n", zeus_quad_size);
709 							break;
710 						case 0x000000324:
711 							zeus_quad_size = 12;
712 							if (logit) logerror(" 324 quad size %d\n", zeus_quad_size);
713 							break;
714 						default:
715 							zeus_quad_size = 10;
716 							logerror(" unknown quad size from source [41]=%08X\n", m_curUCodeSrc);
717 							break;
718 						}
719 
720 					}
721 					else {
722 						switch (m_curUCodeSrc) {
723 						case 0x000000000:
724 							zeus_quad_size = 14;
725 							if (logit) logerror(" 00 quad size %d\n", zeus_quad_size);
726 							break;
727 						case 0x00000002d:
728 							zeus_quad_size = 14;
729 							if (logit) logerror(" 2d quad size %d\n", zeus_quad_size);
730 							break;
731 						case 0x0000001aa:
732 							// Direct frame buffer access, render data is rgb565
733 							zeus_quad_size = 14;
734 							if (logit) logerror(" 1aa quad size %d\n", zeus_quad_size);
735 							break;
736 						default:
737 							zeus_quad_size = 14;
738 							logerror(" unknown quad size from source [41]=%08X\n", m_curUCodeSrc);
739 							break;
740 						}
741 
742 					}
743 				}
744 				if (1 && logit) {
745 					uint32_t *wavePtr = (uint32_t*)waveram0_ptr_from_expanded_addr(m_zeusbase[0x41]);
746 					uint32_t waveData;
747 					int size = m_zeusbase[0x40] & 0xff;
748 					logerror("\n Setup size=%d [40]=%08X [41]=%08X [4e]=%08X\n", zeus_quad_size, m_zeusbase[0x40], m_zeusbase[0x41], m_zeusbase[0x4e]);
749 					for (int i = 0; i <= size; ++i) {
750 						if (m_zeusbase[0x41] < 0xc0) {
751 							waveData = wavePtr[1];
752 							logerror(" %08X", waveData);
753 							waveData = wavePtr[0];
754 							logerror("%08X", waveData);
755 						}
756 						else {
757 							waveData = wavePtr[0];
758 							logerror(" %08X", waveData);
759 							waveData = wavePtr[1];
760 							logerror(" %08X", waveData);
761 						}
762 						wavePtr += 2;
763 						if (0 && (i + 1) % 16 == 0)
764 							logerror("\n");
765 					}
766 				}
767 			}
768 			break;
769 			//case 6: {
770 			//  // Zeus model fifo burst from waveram
771 			//}
772 			//break;
773 			case 9:
774 			{
775 				// Waveram Write
776 				void *dest = waveram0_ptr_from_expanded_addr(m_zeusbase[0x41]);
777 				WAVERAM_WRITE32(dest, 0, m_zeusbase[0x48]);
778 				WAVERAM_WRITE32(dest, 1, m_zeusbase[0x49]);
779 				if (logit)
780 					logerror("\t[41]=%08X [4E]=%08X", m_zeusbase[0x41], m_zeusbase[0x4e]);
781 
782 				if (m_zeusbase[0x4e] & 0x40)
783 				{
784 					m_zeusbase[0x41]++;
785 					m_zeusbase[0x41] += (m_zeusbase[0x41] & 0x400) << 6;
786 					m_zeusbase[0x41] &= ~0xfc00;
787 				}
788 			}
789 			break;
790 			default:
791 			{
792 				//if (logit)
793 				logerror("\t-- unknown code (%d): [4e]: %08X [40]: %08X [41]: %08x [48]: %08x [49]: %08x\n", code, m_zeusbase[0x4e], m_zeusbase[0x40], m_zeusbase[0x41], m_zeusbase[0x48], m_zeusbase[0x49]);
794 			}
795 			break;
796 			}
797 		}
798 		break;
799 
800 	case 0x50: case 0x51: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5e:
801 		// m_zeusbase[0x5e]:
802 		// bits 3:0 select which offset triggers an access
803 		// bit 4:   clear error
804 		// bit 5:   24 bit (1) / 32 bit mode (0)
805 		// bit 6:   enable autoincrement wave address
806 		// bit 7    autoincrement desination address?
807 		// bit 8    autoincrement row/col address by 1 (0) or 2 (1)
808 		if ((offset & 0xf) == (m_zeusbase[0x5e] & 0xf)) {
809 
810 			int code = (m_zeusbase[0x50] >> 16) & 0xf;
811 
812 			// If the address is auto-increment then don't load new value
813 			// In reality address is latched by a write to 0x50
814 			if (offset == 0x51 && (m_zeusbase[0x5e] & 0x40)) {
815 				m_zeusbase[0x51] = oldval;
816 			}
817 
818 			switch (code) {
819 			case 0:
820 				// NOP
821 				break;
822 			case 1:
823 				// SGRAM Special Mode Register Write
824 				if (m_zeusbase[0x51] == 0x00200000) {
825 					// SGRAM Mask Register
826 					if ((m_zeusbase[0x58] & m_zeusbase[0x59] & m_zeusbase[0x5a]) != 0xffffffff)
827 						logerror("zeus2_register_update: Warning! Mask Register not equal to 0xffffffff\n");
828 				}
829 				if (m_zeusbase[0x51] == 0x00400000) {
830 					// SGRAM Color Register
831 					m_fill_color = m_zeusbase[0x58] & 0xffffff;
832 					m_fill_depth = ((m_zeusbase[0x5a] & 0xffff) << 8) | (m_zeusbase[0x58] >> 24);
833 					//m_fill_depth = -1;
834 					if (m_zeusbase[0x58] != m_zeusbase[0x59])
835 						logerror("zeus2_register_update: Warning! Different fill colors are set.\n");
836 					if (logit)
837 						logerror(" -- Setting fill color = %06X depth = %06X ", m_fill_color, m_fill_depth);
838 				}
839 				break;
840 			case 0x2:
841 				frame_read();
842 				break;
843 			case 0x8:
844 			{
845 				// Fast clear
846 				// Atlantis: 0x00983FFF => clear entire frame buffer, 0x00981FFF => clear one frame
847 				// crusnexo: 0x007831FF => clear one frame
848 				// thegrid:  0x008831FF => clear one frame
849 				// thegrid:  0x0079FFFF => clear entire frame buffer at 51=0 then 51=00800000, only seen at initial tests in thegrid
850 				uint32_t addr = frame_addr_from_phys_addr(m_zeusbase[0x51]);
851 				uint32_t numPixels = (m_zeusbase[0x50] & 0xffff) + 1;
852 				numPixels *= 0x10;
853 				if (m_zeusbase[0x50] & 0x10000) {
854 					addr = 0x0;
855 					numPixels = WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 8;
856 					printf("Clearing buffer: numPixels: %08X addr: %08X reg50: %08X\n", numPixels, addr, m_zeusbase[0x50]);
857 				}
858 				if (logit)
859 					logerror(" -- Clearing buffer: numPixels: %08X addr: %08X reg51: %08X", numPixels, addr, m_zeusbase[0x51]);
860 				for (int count = 0; count < numPixels; count++) {
861 					// Crusn wraps the frame buffer during fill so need to mask address
862 					m_frameColor[(addr + count) & (WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 2 - 1)] = m_fill_color;
863 					m_frameDepth[(addr + count) & (WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 2 - 1)] = m_fill_depth;
864 				}
865 			}
866 			break;
867 			case 0x9:
868 			{
869 				// Fast fill from local regs
870 				uint32_t numDWords = (m_zeusbase[0x50] & 0xffff) + 1;
871 				// Set autoincrement
872 				if (numDWords>1)
873 					m_zeusbase[0x5e] |= 0x40;
874 				if (logit && numDWords > 1)
875 					logerror(" -- Filling buffer: numDWords: %08X addr: %08X reg50: %08X reg5e: %08X\n", numDWords, m_zeusbase[0x51], m_zeusbase[0x50], m_zeusbase[0x5e]);
876 				for (int dword = 0; dword < numDWords; dword++)
877 					frame_write();
878 			}
879 			break;
880 			default:
881 				logerror("unknown code = %x offset = %x", code, offset);
882 				break;
883 			}
884 		}
885 		break;
886 
887 		// 0x60, 0x61, 0x62 Translation matrix, set using fifo command
888 
889 	case 0x60: case 0x61: case 0x62: case 0x63:
890 		zeus_trans[offset & 3] = convert_float(m_zeusbase[offset]);
891 		if (logit)
892 			logerror("\tMAC Trans%d = %8.2f", offset & 3, reinterpret_cast<float&>(m_zeusbase[offset]));
893 		break;
894 
895 	case 0x64:
896 		if (logit)
897 			logerror("\tMAC Offset");
898 		break;
899 
900 	case 0x65:
901 		if (logit)
902 			logerror("\tMAC Offset");
903 		break;
904 
905 	case 0x66:
906 		if (logit)
907 			logerror("\tMultiply Offset");
908 		break;
909 
910 	case 0x67:
911 		if (logit)
912 			logerror("\tMath MAC Setup");
913 		break;
914 
915 	case 0x68:
916 		if (logit)
917 			logerror("\tALU Float Offset");
918 		break;
919 
920 	case 0x6A:
921 		if (logit)
922 			logerror("\tALU RegC X_OFF = %8.2f", reinterpret_cast<float&>(m_zeusbase[offset]));
923 		break;
924 
925 	case 0x6B:
926 		if (logit)
927 			logerror("\tALU RegD Y_OFF = %8.2f", reinterpret_cast<float&>(m_zeusbase[offset]));
928 		break;
929 
930 	case 0x6c:
931 		if (logit)
932 			logerror("\tALU Inv Offset");
933 		break;
934 
935 	case 0x6f:
936 		if (logit)
937 			logerror("\tLight Table Setup Page: %02X Mask: %02X", (m_zeusbase[offset] >> 8) & 0xff, m_zeusbase[offset] & 0xff);
938 		break;
939 
940 	case 0x76:
941 		if (logit)
942 			logerror("\tMath Comp Reg0 XClip = %8.2f", reinterpret_cast<float&>(m_zeusbase[offset]));
943 		break;
944 
945 	case 0x77:
946 		if (logit)
947 			logerror("\tMath Comp Reg1 YClip = %8.2f", reinterpret_cast<float&>(m_zeusbase[offset]));
948 		break;
949 
950 	case 0x78:
951 		if (logit)
952 			logerror("\tMath Comp Reg2 ZClip = %8.2f", reinterpret_cast<float&>(m_zeusbase[offset]));
953 		break;
954 
955 	case 0x79:
956 		if (logit)
957 			logerror("\tMath Comp Reg3 YRange = %8.2f", reinterpret_cast<float&>(m_zeusbase[offset]));
958 		break;
959 
960 	case 0x7a:
961 		if (logit)
962 			logerror("\tMath Conditional Branch Setup");
963 		break;
964 
965 	case 0x7c:
966 		if (logit)
967 			logerror("\tMath Compare Setup 1");
968 		break;
969 
970 	case 0x7D:
971 		if (logit)
972 			logerror("\tMath FIFO AF / AE Input FIFO AF / AE");
973 		break;
974 
975 	case 0x7f:
976 		if (logit)
977 			logerror("\tMath Setup Reg");
978 		break;
979 
980 	}
981 	if (logit)
982 		logerror("\n");
983 }
984 
985 /*************************************
986 *  Load pal table from waveram
987 *************************************/
load_pal_table(void * wavePtr,uint32_t ctrl,int type,int logit)988 void zeus2_device::load_pal_table(void *wavePtr, uint32_t ctrl, int type, int logit)
989 {
990 	int count = ctrl & 0xffff;
991 	m_palSize = (count + 1) * 4;
992 	uint32_t addr = (ctrl >> 24) << 1;
993 	uint32_t *tablePtr = &m_pal_table[addr];
994 	if (type == 0) {
995 		// Convert from RGB555
996 		uint16_t *src = (uint16_t*)wavePtr;
997 		for (int i = 0; i <= count; ++i) {
998 			*tablePtr++ = conv_rgb555_to_rgb32(*src++);
999 			*tablePtr++ = conv_rgb555_to_rgb32(*src++);
1000 			*tablePtr++ = conv_rgb555_to_rgb32(*src++);
1001 			*tablePtr++ = conv_rgb555_to_rgb32(*src++);
1002 		}
1003 	}
1004 	else {
1005 		// Raw Copy
1006 		uint32_t *src = (uint32_t*)wavePtr;
1007 		for (int i = 0; i <= count; ++i) {
1008 			*tablePtr++ = *src++;
1009 			*tablePtr++ = *src++;
1010 		}
1011 	}
1012 	if (logit) {
1013 		logerror("\ntable: ");
1014 		tablePtr = &m_pal_table[addr];
1015 		for (int i = 0; i < (count+1)*4; ++i) {
1016 			logerror(" %08X", *tablePtr++);
1017 			if (0 && (i + 1) % 16 == 0)
1018 				logerror("\n");
1019 		}
1020 		logerror("\n");
1021 	}
1022 }
1023 /*************************************
1024 *  Load microcode from waveram
1025 *************************************/
load_ucode(void * wavePtr,uint32_t ctrl,int logit)1026 void zeus2_device::load_ucode(void *wavePtr, uint32_t ctrl, int logit)
1027 {
1028 	int count = ctrl & 0xffff;
1029 	uint32_t addr = (ctrl >> 24) << 1;
1030 	uint32_t *src = (uint32_t*)wavePtr;
1031 	uint32_t *tablePtr = &m_ucode[addr];
1032 	for (int i = 0; i <= count; ++i) {
1033 		*tablePtr++ = *src++;
1034 		*tablePtr++ = *src++;
1035 	}
1036 }
1037 
1038 /*************************************
1039  *
1040  *  Process the FIFO
1041  *
1042  *************************************/
1043 
zeus2_pointer_write(uint8_t which,uint32_t value,int logit)1044 void zeus2_device::zeus2_pointer_write(uint8_t which, uint32_t value, int logit)
1045 {
1046 #if TRACK_REG_USAGE
1047 subregwrite_count[which]++;
1048 if (subregdata_count[which] < 256)
1049 {
1050 	reg_info **tailptr;
1051 
1052 	for (tailptr = &subregdata[which]; *tailptr != nullptr; tailptr = &(*tailptr)->next)
1053 		if ((*tailptr)->value == value)
1054 			break;
1055 	if (*tailptr == nullptr)
1056 	{
1057 		*tailptr = alloc_or_die(reg_info);
1058 		(*tailptr)->next = nullptr;
1059 		(*tailptr)->value = value;
1060 		subregdata_count[which]++;
1061 	}
1062 }
1063 #endif
1064 	if (which<0x50)
1065 		m_renderRegs[which] = value;
1066 
1067 	switch (which)
1068 	{
1069 		case 0x01:
1070 			// Limit to 12 bits
1071 			m_renderRegs[which] &= 0xfff;
1072 			zeus_cliprect.max_x = m_renderRegs[which];
1073 			if (logit)
1074 				logerror("\t(R%02X) = %4i Rend XClip", which & 0xfff, value);
1075 			break;
1076 
1077 		case 0x02:
1078 			// Limit to 12 bits
1079 			m_renderRegs[which] &= 0xfff;
1080 			zeus_cliprect.max_y = m_renderRegs[which];
1081 			if (logit)
1082 				logerror("\t(R%02X) = %4i Rend YClip", which & 0xfff, value);
1083 			break;
1084 
1085 		case 0x03:
1086 			if (logit)
1087 				logerror("\t(R%02X) = %06x Rend XOffset", which, value);
1088 			break;
1089 
1090 		case 0x04:
1091 			if (logit)
1092 				logerror("\t(R%02X) = %06x Rend YOffset", which, value);
1093 			break;
1094 
1095 		case 0x05:
1096 			zeus_texbase = value % (WAVERAM0_HEIGHT * WAVERAM0_WIDTH);
1097 			if (logit)
1098 				logerror("\t(R%02X)  texbase = %06x", which, zeus_texbase);
1099 			break;
1100 
1101 		case 0x07:
1102 			if (logit)
1103 				logerror("\t(R%02X)  Texel Mask = %06x", which, value);
1104 			break;
1105 
1106 		case 0x08:
1107 			{
1108 				//int blockNum = ((m_renderRegs[0x9] >> 16) * 1024 + (m_renderRegs[0x9] & 0xffff));
1109 				int blockNum = m_renderRegs[0x9];
1110 				void *dataPtr = (void *)(&m_waveram[blockNum * 2]);
1111 				if (logit)
1112 					logerror("\t(R%02X) = %06x PAL Control Load Table Byte Addr = %08X", which, value, blockNum * 8);
1113 				m_curPalTableSrc = m_renderRegs[0x9];
1114 				load_pal_table(dataPtr, m_renderRegs[0x8], 0, logit);
1115 			}
1116 			break;
1117 
1118 		case 0x09:
1119 			if (logit) logerror("\t(R%02X) = %06x PAL Addr", which, value);
1120 			break;
1121 
1122 		case 0x0a:
1123 			if (logit) logerror("\t(R%02X) = %4i Pixel ALU IntA", which, value);
1124 			break;
1125 
1126 		case 0x0b:
1127 			if (logit) logerror("\t(R%02X) = %4i Pixel ALU IntB (Obj Light Color)", which, value);
1128 			break;
1129 
1130 		case 0x0c:
1131 			if (logit) logerror("\t(R%02X) = %4i Pixel ALU IntC (Translucency FG)", which, value);
1132 			break;
1133 
1134 		case 0x0d:
1135 			if (logit) logerror("\t(R%02X) = %4i Pixel ALU IntD (Translucency BG)", which, value);
1136 			break;
1137 
1138 		case 0x11:
1139 			if (logit) logerror("\t(R%02X)  Texel Setup = %06x", which, value);
1140 			break;
1141 
1142 		case 0x12:
1143 			if (logit) logerror("\t(R%02X)  Pixel FIFO Setup = %06x", which, value);
1144 			break;
1145 
1146 		case 0x14:
1147 			if (logit) logerror("\t(R%02X) = %06x ZBuf Control", which, value);
1148 			break;
1149 
1150 		case 0x15:
1151 			//m_zbufmin = value & 0xffffff;
1152 			if (logit) logerror("\t(R%02X) = %06X ZBuf Min", which, value);
1153 			break;
1154 
1155 		case 0x40:
1156 			// 0x004000 no shading
1157 			// 0x024004 gouraud shading
1158 			if (logit) logerror("\t(R%02X) = %06x Pixel ALU Control", which, value);
1159 			break;
1160 
1161 		case 0xff:
1162 			// Reset???
1163 			if (logit) logerror("\tRender Reset");
1164 			break;
1165 
1166 		default:
1167 			if (logit) logerror("\t(R%02X) = %06x", which, value);
1168 			break;
1169 
1170 
1171 #if 0
1172 		case 0x0c:
1173 		case 0x0d:
1174 			// These seem to have something to do with blending.
1175 			// There are fairly unique 0x0C,0x0D pairs for various things:
1176 			// Car reflection on initial screen: 0x40, 0x00
1177 			// Additively-blended "flares": 0xFA, 0xFF
1178 			// Car windshields (and drivers, apparently): 0x82, 0x7D
1179 			// Other minor things: 0xA4, 0x100
1180 			break;
1181 #endif
1182 	}
1183 }
1184 
1185 /*************************************
1186  *  Process the FIFO
1187  *************************************/
1188 
zeus2_fifo_process(const uint32_t * data,int numwords)1189 bool zeus2_device::zeus2_fifo_process(const uint32_t *data, int numwords)
1190 {
1191 	int dataoffs = 0;
1192 
1193 	// Increment ififo counter
1194 	m_zeusbase[0x18]++;
1195 
1196 	/* handle logging */
1197 	switch (data[0] >> 24)
1198 	{
1199 		// 0x00: write 32-bit value to low registers
1200 	case 0x00:
1201 		// Ignore the all zeros commmand
1202 		if (((data[0] >> 16) & 0x7f) == 0x0) {
1203 			if (log_fifo && (data[0] & 0xfff) != 0x2c0)
1204 				log_fifo_command(data, numwords, " -- ignored\n");
1205 			return true;
1206 		}
1207 		// Drop through to 0x05 command
1208 	/* 0x05: write 32-bit value to low registers */
1209 	case 0x05:
1210 		if (numwords < 2)
1211 			return false;
1212 		if (log_fifo)
1213 			log_fifo_command(data, numwords, " -- reg32");
1214 		if (((data[0] >> 16) & 0x7f) != 0x08)
1215 			zeus2_register32_w((data[0] >> 16) & 0x7f, data[1], log_fifo);
1216 		break;
1217 
1218 		/* 0x08: set matrix and point (thegrid) */
1219 		case 0x08:
1220 			if (numwords < 14)
1221 				return false;
1222 			zeus_trans[3] = convert_float(data[1]);
1223 			dataoffs = 1;
1224 
1225 		/* 0x07: set matrix and point (crusnexo) */
1226 		case 0x07:
1227 			if (numwords < 13)
1228 				return false;
1229 
1230 			/* extract the matrix from the raw data */
1231 			zeus_matrix[0][0] = convert_float(data[dataoffs + 1]);
1232 			zeus_matrix[0][1] = convert_float(data[dataoffs + 2]);
1233 			zeus_matrix[0][2] = convert_float(data[dataoffs + 3]);
1234 			zeus_matrix[1][0] = convert_float(data[dataoffs + 4]);
1235 			zeus_matrix[1][1] = convert_float(data[dataoffs + 5]);
1236 			zeus_matrix[1][2] = convert_float(data[dataoffs + 6]);
1237 			zeus_matrix[2][0] = convert_float(data[dataoffs + 7]);
1238 			zeus_matrix[2][1] = convert_float(data[dataoffs + 8]);
1239 			zeus_matrix[2][2] = convert_float(data[dataoffs + 9]);
1240 
1241 			/* extract the translation point from the raw data */
1242 			zeus_trans[0] = convert_float(data[dataoffs + 10]);
1243 			zeus_trans[1] = convert_float(data[dataoffs + 11]);
1244 			zeus_trans[2] = convert_float(data[dataoffs + 12]);
1245 
1246 			if (log_fifo)
1247 			{
1248 				log_fifo_command(data, numwords, "\n");
1249 				logerror("\t\tmatrix ( %8.2f %8.2f %8.2f ) ( %8.2f %8.2f %8.2f ) ( %8.2f %8.2f %8.2f )\n\t\ttrans_vector %8.2f %8.2f %8.5f %8.2f\n",
1250 						(double) zeus_matrix[0][0], (double) zeus_matrix[0][1], (double) zeus_matrix[0][2],
1251 						(double) zeus_matrix[1][0], (double) zeus_matrix[1][1], (double) zeus_matrix[1][2],
1252 						(double) zeus_matrix[2][0], (double) zeus_matrix[2][1], (double) zeus_matrix[2][2],
1253 						(double) zeus_trans[0], (double) zeus_trans[1], (double) zeus_trans[2], (double)zeus_trans[3]);
1254 			}
1255 			break;
1256 
1257 		/* 0x15: set point only (thegrid) */
1258 		/* 0x16: set point only (crusnexo) */
1259 		// 0x10: atlantis
1260 		case 0x10:
1261 		case 0x15:
1262 		case 0x16:
1263 			if (numwords < 4)
1264 				return false;
1265 
1266 			/* extract the translation point from the raw data */
1267 			zeus_trans[0] = convert_float(data[1]);
1268 			zeus_trans[1] = convert_float(data[2]);
1269 			zeus_trans[2] = convert_float(data[3]);
1270 
1271 			if (log_fifo)
1272 			{
1273 				log_fifo_command(data, numwords, "\n");
1274 				logerror("\t\ttrans_vector %8.2f %8.2f %8.2f %8.2f\n",
1275 					(double)zeus_trans[0], (double)zeus_trans[1], (double)zeus_trans[2], (double)zeus_trans[3]);
1276 			}
1277 			break;
1278 
1279 		// 0x1c: thegrid (3 words)
1280 		// 0x14: atlantis
1281 		case 0x14:
1282 		case 0x1c:
1283 			if (m_system == THEGRID) {
1284 				if (numwords < 3)
1285 					return false;
1286 				zeus_light[1] = convert_float(data[1]);
1287 				zeus_light[2] = convert_float(data[2]);
1288 				if (log_fifo)
1289 				{
1290 					log_fifo_command(data, numwords, " -- Set static fade\n");
1291 					logerror("\t\tlight_vector %8.2f %8.2f %8.2f\n",
1292 						(double)zeus_light[0], (double)zeus_light[1], (double)zeus_light[2]);
1293 				}
1294 				break;
1295 			}
1296 		// 0x1b: thegrid
1297 		// 0x1c: crusnexo (4 words)
1298 		case 0x1b:
1299 			if (numwords < 4)
1300 				return false;
1301 			/* extract the translation point from the raw data */
1302 			zeus_light[0] = convert_float(data[1]);
1303 			zeus_light[1] = convert_float(data[2]);
1304 			zeus_light[2] = convert_float(data[3]);
1305 			if (log_fifo)
1306 			{
1307 				log_fifo_command(data, numwords, " -- Set light vector\n");
1308 				logerror("\t\tlight_vector %8.2f %8.2f %8.2f\n",
1309 					(double)zeus_light[0], (double)zeus_light[1], (double)zeus_light[2]);
1310 
1311 			}
1312 			break;
1313 
1314 		// thegrid
1315 		case 0x1d:
1316 			if (numwords < 2)
1317 				return false;
1318 			zeus_light[2] = convert_float(data[1]);
1319 			if (log_fifo)
1320 			{
1321 				log_fifo_command(data, numwords, " -- Set zoffset\n");
1322 				logerror("\t\tdata %8.5f\n", (double)convert_float(data[1]));
1323 			}
1324 			break;
1325 
1326 		/* 0x23: render model in waveram (thegrid) */
1327 		/* 0x24: render model in waveram (crusnexo) */
1328 		// 0x17: ??? (atlantis)
1329 		case 0x17:
1330 		case 0x23:
1331 		case 0x24:
1332 			if (numwords < 2)
1333 				return false;
1334 			if (log_fifo)
1335 				log_fifo_command(data, numwords, "");
1336 			zeus2_draw_model(data[1], data[0] & 0xffff, log_fifo);
1337 			break;
1338 
1339 		// 0x2d; set direct render pixels location (atlantis)
1340 		case 0x2d:
1341 			if (numwords < 2)
1342 				return false;
1343 			if (log_fifo)
1344 				log_fifo_command(data, numwords, "\n");
1345 			// Need to figure how the 0x40 gets there
1346 			m_zeusbase[0x5e] = (data[0] << 16) | 0x40;
1347 			m_zeusbase[0x51] = data[1];
1348 			//zeus2_draw_model(data[1], data[0] & 0xff, log_fifo);
1349 			break;
1350 
1351 		/* 0x31: sync pipeline? (thegrid) */
1352 		/* 0x32: sync pipeline? (crusnexo) */
1353 		// 0x25 ?? (atlantis)
1354 		case 0x25:
1355 		case 0x31:
1356 		case 0x32:
1357 			poly->wait("REND_WAIT");
1358 			if (log_fifo)
1359 				log_fifo_command(data, numwords, " wait for renderer idle \n");
1360 			break;
1361 
1362 		/* 0x38: direct render quad (crusnexo) */
1363 		// 0x38: direct write to frame buffer (atlantis)
1364 		case 0x38:
1365 			if (m_curUCodeSrc == 0x1aa) {
1366 				if (numwords < 3)
1367 					return false;
1368 				// mwskins direct write to frame buffer
1369 				m_zeusbase[0x58] = conv_rgb555_to_rgb32((uint16_t)data[1]);
1370 				m_zeusbase[0x59] = conv_rgb555_to_rgb32((uint16_t)(data[1] >> 16));
1371 				frame_write();
1372 				m_zeusbase[0x58] = conv_rgb555_to_rgb32((uint16_t)data[2]);
1373 				m_zeusbase[0x59] = conv_rgb555_to_rgb32((uint16_t)(data[2] >> 16));
1374 				frame_write();
1375 				if (((m_zeusbase[0x51] & 0xff) == 2) && log_fifo)
1376 					log_fifo_command(data, numwords, "\n");
1377 			}
1378 			else if (numwords < 12) {
1379 				return false;
1380 				//print_fifo_command(data, numwords, "\n");
1381 				if (log_fifo)
1382 					log_fifo_command(data, numwords, "\n");
1383 			}
1384 			break;
1385 
1386 			// thegrid
1387 		case 0xb7:
1388 			if (numwords < 2)
1389 				return false;
1390 			if (log_fifo)
1391 			{
1392 				log_fifo_command(data, numwords, " -- Set interp factor\n");
1393 				logerror("\t\tdata %8.5f\n", (double)convert_float(data[1]));
1394 			}
1395 			break;
1396 
1397 		default:
1398 			if (1 || data[0] != 0x2c0)
1399 			{
1400 				printf("Unknown command %08X\n", data[0]);
1401 				if (log_fifo)
1402 					log_fifo_command(data, numwords, "\n");
1403 			}
1404 			break;
1405 	}
1406 	return true;
1407 }
1408 
1409 /*************************************
1410  *  Draw a model in waveram
1411  *************************************/
1412 
zeus2_draw_model(uint32_t baseaddr,uint16_t count,int logit)1413 void zeus2_device::zeus2_draw_model(uint32_t baseaddr, uint16_t count, int logit)
1414 {
1415 	uint32_t databuffer[512];
1416 	int databufcount = 0;
1417 	int model_done = false;
1418 	uint32_t texdata = 0;
1419 
1420 	if (logit)
1421 		logerror(" -- model @ %08X, len %04X, palSrc %08x, rendSrc %08x\n", baseaddr, count, m_curPalTableSrc, m_curUCodeSrc);
1422 
1423 	if (count > 0xc800)
1424 		fatalerror("Extreme count\n");
1425 
1426 	while (baseaddr != 0 && !model_done)
1427 	{
1428 		const void *base = waveram0_ptr_from_expanded_addr(baseaddr);
1429 		int curoffs;
1430 
1431 		/* reset the objdata address */
1432 		baseaddr = 0;
1433 
1434 		/* loop until we run out of data */
1435 		for (curoffs = 0; curoffs <= count; curoffs++)
1436 		{
1437 			int countneeded = 2;
1438 			uint8_t cmd;
1439 
1440 			/* accumulate 2 words of data */
1441 			databuffer[databufcount++] = WAVERAM_READ32(base, curoffs * 2 + 0);
1442 			databuffer[databufcount++] = WAVERAM_READ32(base, curoffs * 2 + 1);
1443 
1444 			/* if this is enough, process the command */
1445 			cmd = databuffer[0] >> 24;
1446 
1447 			if ((cmd == 0x38) || (cmd == 0x2d) || (cmd == 0xa7) || (cmd == 0xaf)) {
1448 				countneeded = zeus_quad_size;
1449 			}
1450 			if (databufcount == countneeded)
1451 			{
1452 				// Increment mfifo counter
1453 				m_zeusbase[0x19] += databufcount;
1454 
1455 				/* handle logging of the command */
1456 				if (logit)
1457 				{
1458 					if (cmd != 0x00 || (cmd == 0x00 && curoffs == count)) {
1459 						logerror("\t");
1460 						// Limit logging to 16 words
1461 						for (int offs = 0; offs < databufcount && offs < 16; offs++)
1462 							logerror("%08X ", databuffer[offs]);
1463 						logerror("-- ");
1464 					}
1465 				}
1466 
1467 				/* handle the command */
1468 				switch (cmd)
1469 				{
1470 					case 0x00: // crusnexo
1471 						if (logit && curoffs == count)
1472 							logerror(" end cmd 00\n");
1473 					case 0x21:  /* thegrid */
1474 					case 0x22:  /* crusnexo */
1475 					{
1476 						// Sets 0x68 (uv float offset) and texture line and mode
1477 						// In reality this sets internal registers that are used in the
1478 						// zeus2 microcode to set these registers
1479 						m_zeusbase[0x68] = (databuffer[0] >> 16) & 0xff;
1480 						texdata = databuffer[1];
1481 						if (logit)
1482 								logerror(" (0x68)=%02X texMode=%08X\n", m_zeusbase[0x68], texdata);
1483 					}
1484 						break;
1485 
1486 					case 0x31:  /* thegrid */
1487 						poly->wait("REND_WAIT");
1488 						if (logit)
1489 							logerror("wait for renderer not active\n");
1490 						break;
1491 
1492 					case 0x29:  // atlantis
1493 					case 0x35:  /* thegrid */
1494 					case 0x36:  /* crusnexo */
1495 						if (logit)
1496 							logerror("reg32");
1497 						zeus2_register32_w((databuffer[0] >> 16) & 0x7f, databuffer[1], logit);
1498 						break;
1499 
1500 					case 0x2d:  // atlantis
1501 						poly->zeus2_draw_quad(databuffer, texdata, logit);
1502 						break;
1503 
1504 					case 0x38:  /* crusnexo/thegrid */
1505 						if (m_system==THEGRID && m_curUCodeSrc==0x00000343) {
1506 							if (logit)
1507 								logerror("direct write [57]=%08X [51]==%08X\n", m_zeusbase[0x57], m_zeusbase[0x51]);
1508 							// Direct write to frame buffer
1509 							for (int subIndex = 0; subIndex < zeus_quad_size / 2; ++subIndex) {
1510 								m_zeusbase[0x5a] = databuffer[subIndex * 2 + 1] & 0xffffff;
1511 								m_zeusbase[0x58] = databuffer[subIndex * 2 + 0] & 0xffffff;
1512 								frame_write();
1513 							}
1514 						}
1515 						else {
1516 							poly->zeus2_draw_quad(databuffer, texdata, logit);
1517 						}
1518 						break;
1519 
1520 					// thegrid: triangle mesh, pm3dli
1521 					case 0xa7:
1522 					case 0xaf:
1523 						if (1 || logit)
1524 							logerror(" unknown triangle data\n");
1525 						break;
1526 
1527 					default:
1528 						if (logit)
1529 							logerror("unknown model data\n");
1530 						break;
1531 				}
1532 
1533 				/* reset the count */
1534 				databufcount = 0;
1535 			}
1536 		}
1537 		// Log unused data
1538 		if (databufcount != 0) {
1539 			if (logit)
1540 			{
1541 				logerror("\t");
1542 				for (int offs = 0; offs < databufcount; offs++)
1543 					logerror("%08X ", databuffer[offs]);
1544 				logerror("-- Unused data\n");
1545 			}
1546 		}
1547 	}
1548 }
1549 
1550 /*************************************
1551  *  Draw a quad
1552  *************************************/
zeus2_draw_quad(const uint32_t * databuffer,uint32_t texdata,int logit)1553 void zeus2_renderer::zeus2_draw_quad(const uint32_t *databuffer, uint32_t texdata, int logit)
1554 {
1555 	z2_poly_vertex vert[4];
1556 
1557 	if (logit) {
1558 		m_state->logerror("quad %d", m_state->zeus_quad_size);
1559 #if PRINT_TEX_INFO
1560 		m_state->logerror(" %s\n", m_state->tex_info());
1561 #else
1562 		m_state->logerror("\n");
1563 #endif
1564 	}
1565 	//if (machine().input().code_pressed(KEYCODE_Q) && (m_state->m_renderRegs[0x5] != 0x1fdf00)) return;
1566 	//if (machine().input().code_pressed(KEYCODE_E) && (m_state->m_renderRegs[0x5] != 0x07f540)) return;
1567 	//if (machine().input().code_pressed(KEYCODE_R) && (m_state->m_renderRegs[0x5] != 0x081580)) return;
1568 	//if (machine().input().code_pressed(KEYCODE_T) && (m_state->m_renderRegs[0x5] != 0x14db00)) return;
1569 	//if (machine().input().code_pressed(KEYCODE_Y) && (m_state->m_renderRegs[0x5] != 0x14d880)) return;
1570 	//if (machine().input().code_pressed(KEYCODE_Q) && (texdata & 0xffff) == 0x119) return;
1571 	//if (machine().input().code_pressed(KEYCODE_E) && (texdata & 0xffff) == 0x01d) return;
1572 	//if (machine().input().code_pressed(KEYCODE_R) && (texdata & 0xffff) == 0x11d) return;
1573 	//if (machine().input().code_pressed(KEYCODE_T) && (texdata & 0xffff) == 0x05d) return;
1574 	//if (machine().input().code_pressed(KEYCODE_Y) && (texdata & 0xffff) == 0x0dd) return;
1575 	//if (machine().input().code_pressed(KEYCODE_U) && (texdata & 0xffff) == 0x119) return;
1576 	//if (machine().input().code_pressed(KEYCODE_I) && (texdata & 0xffff) == 0x119) return;
1577 	//if (machine().input().code_pressed(KEYCODE_O) && (texdata & 0xffff) == 0x119) return;
1578 	//if (machine().input().code_pressed(KEYCODE_L) && (texdata & 0x100)) return;
1579 	//if (m_state->m_texmodeReg != 0x9b) return;
1580 
1581 	// PZr = (PZ * M22) + (PY * M21) + (PX * M20) + 0
1582 	// AZp = (AZ * M22) + (AY * M21) + (AX * M20) + TZ
1583 	// AYp = (AZ * M12) + (AY * M11) + (AX * M10) + TY
1584 	// AXp = (AZ * M02) + (AY * M01) + (AX * M00) + TX
1585 
1586 	// Fast HSR Removal
1587 	if (1)
1588 	{
1589 		float PZr;
1590 
1591 		int8_t normal[3];
1592 		normal[0] = databuffer[0] >> 0;
1593 		normal[1] = databuffer[0] >> 8;
1594 		normal[2] = databuffer[0] >> 16;
1595 
1596 		PZr = normal[0] * m_state->zeus_matrix[2][0] + normal[1] * m_state->zeus_matrix[2][1] + normal[2] * m_state->zeus_matrix[2][2] + m_state->zeus_trans[3];
1597 
1598 		//m_state->logerror("norm: %i %i %i PZr: %f\n", normal[0], normal[1], normal[2], PZr);
1599 		if (PZr >= 0)
1600 			return;
1601 	}
1602 
1603 	/* extract raw x,y,z */
1604 	if (m_state->m_atlantis) {
1605 			// Atlantis quad 14
1606 		texdata = databuffer[1];
1607 		vert[0].x = (int16_t)databuffer[2];
1608 		vert[0].y = (int16_t)databuffer[3];
1609 		vert[0].p[0] = (int16_t)databuffer[4];
1610 		vert[0].p[1] = ((databuffer[5] >> 0) & 0xff);
1611 		vert[0].p[2] = ((databuffer[5] >> 8) & 0xff);
1612 
1613 		vert[1].x = (int16_t)(databuffer[2] >> 16);
1614 		vert[1].y = (int16_t)(databuffer[3] >> 16);
1615 		vert[1].p[0] = (int16_t)(databuffer[4] >> 16);
1616 		vert[1].p[1] = ((databuffer[5] >> 16) & 0xff);
1617 		vert[1].p[2] = ((databuffer[5] >> 24) & 0xff);
1618 
1619 		vert[2].x = (int16_t)databuffer[6];
1620 		vert[2].y = (int16_t)databuffer[7];
1621 		vert[2].p[0] = (int16_t)databuffer[8];
1622 		vert[2].p[1] = ((databuffer[9] >> 0) & 0xff);
1623 		vert[2].p[2] = ((databuffer[9] >> 8) & 0xff);
1624 
1625 		vert[3].x = (int16_t)(databuffer[6] >> 16);
1626 		vert[3].y = (int16_t)(databuffer[7] >> 16);
1627 		vert[3].p[0] = (int16_t)(databuffer[8] >> 16);
1628 		vert[3].p[1] = ((databuffer[9] >> 16) & 0xff);
1629 		vert[3].p[2] = ((databuffer[9] >> 24) & 0xff);
1630 	}
1631 	else {
1632 		//printf("R40: %06X\n", m_state->m_renderRegs[0x40]);
1633 		vert[0].x = (int16_t)databuffer[2];
1634 		vert[0].y = (int16_t)databuffer[3];
1635 		vert[0].p[0] = (int16_t)databuffer[6];
1636 		vert[0].p[1] = (databuffer[1] >> 0) & 0x3ff;
1637 		vert[0].p[2] = (databuffer[1] >> 16) & 0x3ff;
1638 
1639 		vert[1].x = (int16_t)(databuffer[2] >> 16);
1640 		vert[1].y = (int16_t)(databuffer[3] >> 16);
1641 		vert[1].p[0] = (int16_t)(databuffer[6] >> 16);
1642 		vert[1].p[1] = (databuffer[4] >> 0) & 0x3ff;
1643 		vert[1].p[2] = (databuffer[4] >> 10) & 0x3ff;
1644 
1645 		vert[2].x = (int16_t)databuffer[8];
1646 		vert[2].y = (int16_t)databuffer[9];
1647 		vert[2].p[0] = (int16_t)databuffer[7];
1648 		vert[2].p[1] = (databuffer[4] >> 20) & 0x3ff;
1649 		vert[2].p[2] = (databuffer[5] >> 0) & 0x3ff;
1650 
1651 		vert[3].x = (int16_t)(databuffer[8] >> 16);
1652 		vert[3].y = (int16_t)(databuffer[9] >> 16);
1653 		vert[3].p[0] = (int16_t)(databuffer[7] >> 16);
1654 		vert[3].p[1] = (databuffer[5] >> 10) & 0x3ff;
1655 		vert[3].p[2] = (databuffer[5] >> 20) & 0x3ff;
1656 	}
1657 	int unknown[8];
1658 	float unknownFloat[4];
1659 	if (m_state->zeus_quad_size == 14) {
1660 		// buffer 10-13 ???? 00000000 1FF7FC00 00000000 1FF7FC00 -- mwskinsa quad 14
1661 		/* 10:13 16 bit coordinates */
1662 		unknown[0] = (int16_t)databuffer[10];
1663 		unknown[1] = (int16_t)(databuffer[10] >> 16);
1664 		unknown[2] = (int16_t)databuffer[11];
1665 		unknown[3] = (int16_t)(databuffer[11] >> 16);
1666 		unknown[4] = (int16_t)databuffer[12];
1667 		unknown[5] = (int16_t)(databuffer[12] >> 16);
1668 		unknown[6] = (int16_t)databuffer[13];
1669 		unknown[7] = (int16_t)(databuffer[13] >> 16);
1670 		unknownFloat[0] = m_state->convert_float(databuffer[10]);
1671 		unknownFloat[1] = m_state->convert_float(databuffer[11]);
1672 		unknownFloat[2] = m_state->convert_float(databuffer[12]);
1673 		unknownFloat[3] = m_state->convert_float(databuffer[13]);
1674 	}
1675 
1676 	int logextra = 0;
1677 
1678 	int intScale = m_state->m_zeusbase[0x66] - 0x8e;
1679 	float fScale = pow(2.0f, intScale);
1680 	int intUVScale = m_state->m_zeusbase[0x68] - 0x9d;
1681 	float uvScale = pow(2.0f, intUVScale);
1682 	for (int i = 0; i < 4; i++)
1683 	{
1684 		float x = vert[i].x;
1685 		float y = vert[i].y;
1686 		float z = vert[i].p[0];
1687 		if (1) {
1688 		  x *= fScale;
1689 		  y *= fScale;
1690 		  z *= fScale;
1691 		}
1692 #if PRINT_TEX_INFO
1693 		if (logit && i == 0) {
1694 			m_state->check_tex(texdata, z, m_state->zeus_matrix[2][2], m_state->zeus_trans[2]);
1695 		}
1696 #endif
1697 		vert[i].x =    x * m_state->zeus_matrix[0][0] + y * m_state->zeus_matrix[0][1] + z * m_state->zeus_matrix[0][2];
1698 		vert[i].y =    x * m_state->zeus_matrix[1][0] + y * m_state->zeus_matrix[1][1] + z * m_state->zeus_matrix[1][2];
1699 		vert[i].p[0] = x * m_state->zeus_matrix[2][0] + y * m_state->zeus_matrix[2][1] + z * m_state->zeus_matrix[2][2];
1700 
1701 		vert[i].x += m_state->zeus_trans[0];
1702 		vert[i].y += m_state->zeus_trans[1];
1703 		vert[i].p[0] += m_state->zeus_trans[2];
1704 
1705 		//vert[i].p[1] += ((texdata >> 8) & 0x1) ? 1.0f : 0.0f;
1706 		vert[i].p[1] *= uvScale;
1707 		vert[i].p[2] *= uvScale;
1708 		vert[i].p[2] += (texdata >> 16);
1709 		vert[i].p[1] *= 256.0f;
1710 		vert[i].p[2] *= 256.0f;
1711 
1712 
1713 
1714 		if (logextra & logit)
1715 		{
1716 			m_state->logerror("\t\t(%f,%f,%f) (%02X,%02X)\n",
1717 				(double)vert[i].x, (double)vert[i].y, (double)vert[i].p[0],
1718 				(int)(vert[i].p[1] / 256.0f), (int)(vert[i].p[2] / 256.0f));
1719 		}
1720 	}
1721 	if (0 && logextra & logit && m_state->zeus_quad_size == 14) {
1722 		m_state->logerror("unknown: int16: %d %d %d %d %d %d %d %d float: %f %f %f %f\n",
1723 			unknown[0], unknown[1], unknown[2], unknown[3], unknown[4], unknown[5], unknown[6], unknown[7],
1724 			unknownFloat[0], unknownFloat[1], unknownFloat[2], unknownFloat[3]);
1725 	}
1726 
1727 	// Z Clipping, done before clamp to 0
1728 	float clipVal = reinterpret_cast<float&>(m_state->m_zeusbase[0x78]);
1729 	for (int i = 0; i < 4; i++)
1730 	{
1731 		if (vert[i].p[0] < clipVal)
1732 			return;
1733 	}
1734 
1735 	float xOrigin = reinterpret_cast<float&>(m_state->m_zeusbase[0x6a]);
1736 	float yOrigin = reinterpret_cast<float&>(m_state->m_zeusbase[0x6b]);
1737 
1738 	// crusn seems to use a different z scale
1739 	float zRound = (m_state->m_system == m_state->CRUSNEXO) ? 2.0f : 0.5f;
1740 
1741 	float oozBase = 1 << m_state->m_zeusbase[0x6c];
1742 	float ooz;
1743 	for (int i = 0; i < 4; i++)
1744 	{
1745 		// Clamp to zero if negative
1746 		if (vert[i].p[0] < 0)
1747 			vert[i].p[0] = 0.0f;
1748 
1749 		ooz = oozBase / (vert[i].p[0] + zRound);
1750 
1751 		if (1) {
1752 			//vert[i].p[0] += reinterpret_cast<float&>(m_state->m_zeusbase[0x63]);
1753 			vert[i].x *= ooz;
1754 			vert[i].y *= ooz;
1755 			//vert[i].p[0] = ooz;
1756 		}
1757 
1758 		vert[i].x += xOrigin;
1759 		vert[i].y += yOrigin;
1760 		// The Grid adds zoffset for objects with no light
1761 		if (m_state->m_useZOffset)
1762 			vert[i].p[0] += m_state->zeus_light[2];
1763 
1764 		//clipvert[i].p[0] *= 65536.0f * 16.0f;
1765 		vert[i].p[0] *= 4096.0f * 1.0f;  // 12.12
1766 
1767 		if (logextra & logit)
1768 			m_state->logerror("\t\t\tTranslated=(%f,%f, %f) scale = %f\n", (double)vert[i].x, (double)vert[i].y, (double)vert[i].p[0], ooz);
1769 	}
1770 	// Slow HSR
1771 	// ((AYs - BYs) * (BXs - CXs)) - ((AXs - BXs) * (BYs - CYs))
1772 	if (1) {
1773 		float slowHSR = ((vert[0].y - vert[1].y) * (vert[1].x - vert[2].x) - (vert[0].x - vert[1].x) * (vert[1].y - vert[2].y));
1774 		if (slowHSR >= 0)
1775 			return;
1776 	}
1777 
1778 	zeus2_poly_extra_data& extra = this->object_data_alloc();
1779 
1780 	extra.ucode_src = m_state->m_curUCodeSrc;
1781 	extra.tex_src = m_state->zeus_texbase;
1782 	int texmode = texdata & 0xffff;
1783 	extra.texwidth = 0x20 << ((texmode >> 2) & 3);
1784 	extra.solidcolor = 0;//m_zeusbase[0x00] & 0x7fff;
1785 	extra.transcolor = (texmode & 0x180) ? 0 : 0x100;
1786 	extra.texbase = WAVERAM_BLOCK0_EXT(m_state->zeus_texbase);
1787 	extra.depth_min_enable = true;// (m_state->m_renderRegs[0x14] & 0x008000);
1788 	extra.zbuf_min = int32_t((m_state->m_renderRegs[0x15]) << 8) >> 8;
1789 	//extra.zbuf_min = m_state->m_renderRegs[0x15];
1790 	extra.depth_test_enable = !(m_state->m_renderRegs[0x14] & 0x000020);
1791 	//extra.depth_test_enable &= !(m_state->m_renderRegs[0x14] & 0x008000);
1792 	extra.depth_write_enable = !(m_state->m_renderRegs[0x14] & 0x001000);
1793 	extra.depth_clear_enable = (m_state->m_renderRegs[0x14] & 0x000c00);
1794 	// 021e0e = blend with texture alpha for type 2, 020202 blend src / dst alpha
1795 	extra.blend_enable = ((m_state->m_renderRegs[0x40] == 0x020202) || (m_state->m_renderRegs[0x40] == 0x021e0e && (texmode & 0x3) == 2));
1796 	extra.srcAlpha = m_state->m_renderRegs[0x0c];
1797 	extra.dstAlpha = m_state->m_renderRegs[0x0d];
1798 	extra.texture_alpha = false;
1799 	extra.texture_rgb555 = false;
1800 	switch (texmode & 0x3) {
1801 	case 0:
1802 		extra.get_texel = m_state->get_texel_4bit_2x2;
1803 		extra.texwidth >>= 1;
1804 		break;
1805 	case 1:
1806 		extra.get_texel = m_state->get_texel_8bit_4x2;
1807 		break;
1808 	case 2:
1809 		// Seems to select texture with embedded alpha
1810 		if (texmode & 0x80) {
1811 			// Texel , Alpha
1812 			extra.get_texel = m_state->get_texel_8bit_2x2_alpha;
1813 			extra.texture_alpha = true;
1814 			extra.get_alpha = m_state->get_alpha_8bit_2x2_alpha;
1815 			extra.depth_test_enable = false;
1816 			extra.depth_write_enable = false;
1817 		}
1818 		else {
1819 			extra.texture_rgb555 = true;
1820 		}
1821 		break;
1822 	default:
1823 		m_state->logerror("unknown texel type");
1824 		extra.get_texel = m_state->get_texel_8bit_2x2;
1825 		break;
1826 	}
1827 
1828 	//if (numverts == 3)
1829 	//  render_triangle(m_state->zeus_cliprect, render_delegate(&zeus2_renderer::render_poly_8bit, this), 4, vert[0], vert[1], vert[2]);
1830 	render_polygon<4>(m_state->zeus_cliprect, render_delegate(&zeus2_renderer::render_poly_8bit, this), 4, vert);
1831 }
1832 
1833 
1834 
1835 /*************************************
1836 *  Rasterizers
1837 *************************************/
1838 
render_poly_8bit(int32_t scanline,const extent_t & extent,const zeus2_poly_extra_data & object,int threadid)1839 void zeus2_renderer::render_poly_8bit(int32_t scanline, const extent_t& extent, const zeus2_poly_extra_data& object, int threadid)
1840 {
1841 	int32_t curz = extent.param[0].start;
1842 	int32_t curu = extent.param[1].start;
1843 	int32_t curv = extent.param[2].start;
1844 	//  int32_t curi = extent.param[3].start;
1845 	int32_t dzdx = extent.param[0].dpdx;
1846 	int32_t dudx = extent.param[1].dpdx;
1847 	int32_t dvdx = extent.param[2].dpdx;
1848 	//  int32_t didx = extent.param[3].dpdx;
1849 	const void *texbase = object.texbase;
1850 	//const void *palbase = object.palbase;
1851 	uint16_t transcolor = object.transcolor;
1852 	int32_t srcAlpha = object.srcAlpha;
1853 	int32_t dstAlpha = object.dstAlpha;
1854 	bool depth_write_enable = object.depth_write_enable;
1855 	int texwidth = object.texwidth;
1856 	int x;
1857 
1858 	uint32_t addr = m_state->frame_addr_from_xy(0, scanline, true);
1859 	int32_t *depthptr = &m_state->m_frameDepth[addr];
1860 	uint32_t *colorptr = &m_state->m_frameColor[addr];
1861 	int32_t curDepthVal;
1862 
1863 	for (x = extent.startx; x < extent.stopx; x++)
1864 	{
1865 		if (object.depth_clear_enable) {
1866 			//curDepthVal = object.zbuf_min;
1867 			curDepthVal = 0xffffff;
1868 		} else if (object.depth_min_enable) {
1869 			curDepthVal = curz + object.zbuf_min;
1870 		}
1871 		else {
1872 			curDepthVal = curz;
1873 		}
1874 		//if (curz < object.zbuf_min)
1875 		//  curDepthVal = object.zbuf_min;
1876 		//else
1877 		//  curDepthVal = curz;
1878 		if (curDepthVal < 0)
1879 			curDepthVal = 0;
1880 		bool depth_pass = true;
1881 		if (object.depth_test_enable) {
1882 			if (curDepthVal > depthptr[x])
1883 				depth_pass = false;
1884 		}
1885 		if (depth_pass) {
1886 			int u0 = (curu >> 8);// &(texwidth - 1);
1887 			int v0 = (curv >> 8);// &255;
1888 			int u1 = (u0 + 1);
1889 			int v1 = (v0 + 1);
1890 			if (object.texture_rgb555) {
1891 				// Rendering for textures with direct color
1892 				rgb_t srcColor = m_state->get_rgb555(texbase, v0, u0, texwidth);
1893 				colorptr[x] = srcColor;
1894 			}
1895 			else if (object.texture_alpha) {
1896 				// Rendering for textures with embedded alpha
1897 				// To bilinear filter or not to bilinear filter
1898 				if (0) {
1899 					// Add rounding
1900 					u0 += (curu >> 7) & 1;
1901 					v0 += (curv >> 7) & 1;
1902 					uint8_t texel0 = object.get_texel(texbase, v0, u0, texwidth);
1903 					srcAlpha = object.get_alpha(texbase, v0, u0, texwidth);
1904 					if (srcAlpha != 0) {
1905 						rgb_t srcColor = m_state->m_pal_table[texel0];
1906 						rgb_t dstColor = colorptr[x];
1907 						dstAlpha = 0xff - srcAlpha;
1908 						srcColor.scale8(srcAlpha);
1909 						srcColor += dstColor.scale8(dstAlpha);
1910 						colorptr[x] = srcColor;
1911 						if (depth_write_enable)
1912 							depthptr[x] = curDepthVal; // Should limit to 24 bits
1913 					}
1914 				}
1915 				else {
1916 					uint8_t texel0 = object.get_texel(texbase, v0, u0, texwidth);
1917 					uint8_t texel1 = object.get_texel(texbase, v0, u1, texwidth);
1918 					uint8_t texel2 = object.get_texel(texbase, v1, u0, texwidth);
1919 					uint8_t texel3 = object.get_texel(texbase, v1, u1, texwidth);
1920 					uint8_t alpha0 = object.get_alpha(texbase, v0, u0, texwidth);
1921 					uint8_t alpha1 = object.get_alpha(texbase, v0, u1, texwidth);
1922 					uint8_t alpha2 = object.get_alpha(texbase, v1, u0, texwidth);
1923 					uint8_t alpha3 = object.get_alpha(texbase, v1, u1, texwidth);
1924 					if (1)
1925 					{
1926 						// Calculate source alpha
1927 						//srcAlpha = ((uint32_t)alpha0 + (uint32_t)alpha1 + (uint32_t)alpha2 + (uint32_t)alpha3) >> 2;
1928 						uint32_t uFactor = curu & 0xff;
1929 						uint32_t vFactor = curv & 0xff;
1930 						srcAlpha = ((alpha0 * (256 - uFactor) + alpha1 * (uFactor)) * (256 - vFactor) + (alpha2 * (256 - uFactor) + alpha3 * (uFactor)) * (vFactor)) >> 16;
1931 						if (srcAlpha != 0) {
1932 							uint32_t color0 = m_state->m_pal_table[texel0];
1933 							uint32_t color1 = m_state->m_pal_table[texel1];
1934 							uint32_t color2 = m_state->m_pal_table[texel2];
1935 							uint32_t color3 = m_state->m_pal_table[texel3];
1936 							rgb_t filtered = rgbaint_t::bilinear_filter(color0, color1, color2, color3, curu, curv);
1937 							rgb_t dstColor = colorptr[x];
1938 							dstAlpha = 0x100 - srcAlpha;
1939 							filtered.scale8(srcAlpha);
1940 							filtered += dstColor.scale8(dstAlpha);
1941 							colorptr[x] = filtered;
1942 							if (depth_write_enable)
1943 								depthptr[x] = curDepthVal; // Should limit to 24 bits
1944 						}
1945 					}
1946 				}
1947 			// Rendering for textures with no transparent color
1948 			} else if (1 || transcolor == 0x100) {
1949 				uint8_t texel0 = object.get_texel(texbase, v0, u0, texwidth);
1950 				uint8_t texel1 = object.get_texel(texbase, v0, u1, texwidth);
1951 				uint8_t texel2 = object.get_texel(texbase, v1, u0, texwidth);
1952 				uint8_t texel3 = object.get_texel(texbase, v1, u1, texwidth);
1953 				if ((texel0 != transcolor) && (texel1 != transcolor) && (texel2 != transcolor) && (texel3 != transcolor))
1954 				//if (1)
1955 				{
1956 					uint32_t color0 = m_state->m_pal_table[texel0];
1957 					uint32_t color1 = m_state->m_pal_table[texel1];
1958 					uint32_t color2 = m_state->m_pal_table[texel2];
1959 					uint32_t color3 = m_state->m_pal_table[texel3];
1960 					rgb_t srcColor = rgbaint_t::bilinear_filter(color0, color1, color2, color3, curu, curv);
1961 					if (object.blend_enable) {
1962 						// Need to check if this is correct or use incoming dstAlpha
1963 						//dstAlpha = 0x100 - srcAlpha;
1964 
1965 						// If src alpha is 256 don't blend
1966 						if (1 || srcAlpha != 0x100) {
1967 							rgb_t dstColor = colorptr[x];
1968 							if (srcAlpha != 0x100)
1969 								srcColor.scale8(srcAlpha);
1970 							if (dstAlpha == 0x100)
1971 								srcColor += dstColor;
1972 							else
1973 								srcColor += dstColor.scale8(dstAlpha);
1974 						}
1975 						// If src alpha is 0 don't write
1976 						if (srcAlpha != 0x00) {
1977 							colorptr[x] = srcColor;
1978 							if (depth_write_enable)
1979 								depthptr[x] = curDepthVal; // Should limit to 24 bits
1980 						}
1981 					}
1982 					else {
1983 						colorptr[x] = srcColor;
1984 						if (depth_write_enable)
1985 							depthptr[x] = curDepthVal; // Should limit to 24 bits
1986 					}
1987 				}
1988 			// Rendering for textures with transparent color
1989 			//} else {
1990 			//  // Add rounding
1991 			//  u0 += (curu >> 7) & 1;
1992 			//  v0 += (curv >> 7) & 1;
1993 			//  uint8_t texel0 = object.get_texel(texbase, v0, u0, texwidth);
1994 			//  if (texel0 != transcolor) {
1995 			//      uint32_t color0 = m_state->m_pal_table[texel0];
1996 			//      colorptr[x] = color0;
1997 			//      if (object.depth_write_enable)
1998 			//          depthptr[x] = curz; // Should limit to 24 bits
1999 			//  }
2000 			}
2001 		}
2002 		curz += dzdx;
2003 		curu += dudx;
2004 		curv += dvdx;
2005 		//      curi += didx;
2006 	}
2007 }
2008 
2009 /*************************************
2010  *  Debugging tools
2011  *************************************/
2012 
log_fifo_command(const uint32_t * data,int numwords,const char * suffix)2013 void zeus2_device::log_fifo_command(const uint32_t *data, int numwords, const char *suffix)
2014 {
2015 	int wordnum;
2016 	logerror("Zeus cmd %02X :", data[0] >> 24);
2017 	for (wordnum = 0; wordnum < numwords; wordnum++)
2018 		logerror(" %08X", data[wordnum]);
2019 	logerror("%s", suffix);
2020 }
2021 
print_fifo_command(const uint32_t * data,int numwords,const char * suffix)2022 void zeus2_device::print_fifo_command(const uint32_t *data, int numwords, const char *suffix)
2023 {
2024 	int wordnum;
2025 	printf("Zeus cmd %02X :", data[0] >> 24);
2026 	for (wordnum = 0; wordnum < numwords; wordnum++)
2027 		printf(" %08X", data[wordnum]);
2028 	printf("%s", suffix);
2029 }
2030 
log_render_info(uint32_t texdata)2031 void zeus2_device::log_render_info(uint32_t texdata)
2032 {
2033 	logerror("-- RMode0 R40 = %08X texdata = %08X", m_renderRegs[0x40], texdata);
2034 	logerror("\n-- RMode1 ");
2035 	for (int i = 1; i <= 0x9; ++i)
2036 		logerror(" R%02X=%06X", i, m_renderRegs[i]);
2037 	for (int i = 0xa; i <= 0x15; ++i)
2038 		logerror(" R%02X=%06X", i, m_renderRegs[i]);
2039 	logerror("\n-- RMode2 ");
2040 	for (int i = 0x63; i <= 0x6f; ++i)
2041 		logerror(" %02X=%08X", i, m_zeusbase[i]);
2042 	logerror("\n");
2043 }
2044 
2045 #if PRINT_TEX_INFO
2046 #include <iomanip>
2047 
check_tex(uint32_t & texmode,float & zObj,float & zMat,float & zOff)2048 void zeus2_device::check_tex(uint32_t &texmode, float &zObj, float &zMat, float &zOff)
2049 {
2050 	if (tex_map.count(zeus_texbase) == 0) {
2051 		std::string infoStr;
2052 		std::stringstream infoStream;
2053 		infoStream << "tex=0x" << std::setw(8) << std::setfill('0') << std::hex << zeus_texbase << " ";
2054 		//infoStream << "pal=0x" << std::setw(4) << std::setfill('0') << (m_curPalTableSrc >> 16) << ", 0x" << std::setw(4) << (m_curPalTableSrc & 0xffff) << " ";
2055 		infoStream << "pal=0x" << std::setw(8) << std::setfill('0') << m_curPalTableSrc << " ";
2056 		infoStream << "texdata=" << std::setw(8) << std::hex << texmode << " ";
2057 		infoStream << "68(uvFloat)=" << std::setw(2) << std::hex << m_zeusbase[0x68] << " ";
2058 		infoStream << "(6c)=" << m_zeusbase[0x6c] << " ";
2059 		infoStream << "(63)=" << std::setw(6) << std::dec << reinterpret_cast<float&>(m_zeusbase[0x63]) << " ";
2060 		//infoStream << "zObj=" << std::setw(6) << std::dec << zObj << " ";
2061 		//infoStream << "zMat=" << std::setw(6) << std::dec << zMat << " ";
2062 		infoStream << "zOff=" << std::setw(6) << std::dec << zOff << " ";
2063 		infoStream << "R40=" << std::setw(6) << std::hex << m_renderRegs[0x40] << " ";
2064 		infoStream << "R14=" << m_renderRegs[0x14] << " ";
2065 		infoStream << "R15=" << m_renderRegs[0x15] << " ";
2066 		//infoStream << "R0A=" << std::setw(2) << m_renderRegs[0x0a] << " ";
2067 		infoStream << "R0B(LC)=" << std::setw(6) << m_renderRegs[0x0b] << " ";
2068 		infoStream << "R0C(FGD)=" << std::setw(3) << m_renderRegs[0x0c] << " ";
2069 		infoStream << "R0D(BGD)=" << std::setw(3) << m_renderRegs[0x0d] << " ";
2070 		infoStr += infoStream.str();
2071 		infoStr += tex_info();
2072 
2073 		tex_map.insert(std::pair<uint32_t, std::string>(zeus_texbase, infoStr));
2074 		osd_printf_info("%s\n", infoStr);
2075 	}
2076 }
2077 
tex_info(void)2078 std::string zeus2_device::tex_info(void)
2079 {
2080 	std::string retVal;
2081 	if (m_system == CRUSNEXO) {
2082 		switch (zeus_texbase) {
2083 		// crusnexo
2084 		case 0x01fc00:      retVal = "credits / insert coin"; break;
2085 		case 0x1dc000:      retVal = "copywrite text"; break;
2086 		case 0x0e7400:      retVal = "tire"; break;
2087 		case 0x0e8800:      retVal = "star behind tire"; break;
2088 		case 0x0e6800:      retVal = "crusn exotica text"; break;
2089 		case 0x02a400:      retVal = "Yellow Letters / Numbers"; break;
2090 		case 0x1fd000:      retVal = "Star burst in license plate screen"; break;
2091 		case 0x1e9800:      retVal = "Red Letter in license plate screen"; break;
2092 		case 0x0c1c00:      retVal = "Car parts"; break;
2093 		case 0x0006f000:    retVal = "license plate background"; break;
2094 		case 0x0006f400:    retVal = "blue on white license plate names"; break;
2095 		case 0x00047800:    retVal = "baby body"; break;
2096 		case 0x000e7000:    retVal = "crusn exotica yellow glow"; break;
2097 		case 0x0002b000:    retVal = "blue crusn stencil behind leader list"; break;
2098 		case 0x001f4800:    retVal = "number keypad"; break;
2099 		case 0x001e7800:    retVal = "register now logo"; break;
2100 		case 0x001e5000:    retVal = "blue start game / enter code / earn miles"; break;
2101 		case 0x0001c800:    retVal = "black letters silver back track select / crusn"; break;
2102 		case 0x001df400:    retVal = "first place / free race logo"; break;
2103 		case 0x001ddc00:    retVal = "secret car logo"; break;
2104 		case 0x0006e800:    retVal = "???"; break;
2105 		case 0x001f1c00:    retVal = "black 0-9 on silver background"; break;
2106 		case 0x001ec800:    retVal = "black on silver holland/amazon/sahara"; break;
2107 		case 0x001f7800:    retVal = "license plate background white"; break;
2108 		case 0x001f7000:    retVal = "red Hot Times writing"; break;
2109 		case 0x001eb000:    retVal = "black numbers 0-10 on silver background"; break;
2110 		case 0x00100800:    retVal = "sunset and stars sky background"; break;
2111 		case 0x00108c00:    retVal = "asphalt surface"; break;
2112 		case 0x0010c000:    retVal = "wood surface?"; break;
2113 		case 0x0010e400:    retVal = "palm tree"; break;
2114 		case 0x00118c00:    retVal = "highway green signs"; break;
2115 		case 0x000f6400:    retVal = "glowing feather?"; break;
2116 		case 0x00112c00:    retVal = "fancy street lamps"; break;
2117 		case 0x00032400:    retVal = "lady driver body"; break;
2118 		case 0x000b5400:    retVal = "blue firebird car"; break;
2119 		case 0x00089c00:    retVal = "brown hummer car"; break;
2120 		case 0x00110c00:    retVal = "oak tree"; break;
2121 		case 0x00115400:    retVal = "welcome to las vegas sign"; break;
2122 		case 0x000f3c00:    retVal = "star or headlight?"; break;
2123 		case 0x00127400:    retVal = "another (lod) star or headlight?"; break;
2124 		default: retVal = "Unknown"; break;
2125 		}
2126 	}
2127 	else if (m_system == MWSKINS) {
2128 		switch (zeus_texbase) {
2129 		// mwskinsa
2130 		case 0x1fdf00:      retVal = "Skins Tip Box, s=256"; break;
2131 		case 0x07f540:      retVal = "Left main intro"; break;
2132 		case 0x081580:      retVal = "Right main intro"; break;
2133 		case 0x14db00:      retVal = "silver letter b, s=64"; break;
2134 		case 0x14d880:      retVal = "letter a"; break;
2135 		case 0x14e000:      retVal = "letter d"; break;
2136 		case 0x0014dd80:    retVal = "silver letter c, s=64"; break;
2137 		case 0x0014fb80:    retVal = "silver letter o, s=64"; break;
2138 		case 0x0014ec80:    retVal = "silver letter i, s=64"; break;
2139 		case 0x0014f900:    retVal = "silver letter n, s=64"; break;
2140 		case 0x00150580:    retVal = "silver letter s, s=64"; break;
2141 		case 0x00150800:    retVal = "silver letter t, s=64"; break;
2142 		case 0x00150300:    retVal = "silver letter r, s=64"; break;
2143 		case 0x0014e780:    retVal = "silver letter g, s=64"; break;
2144 		case 0x00153280:    retVal = "silver letter C, s=64"; break;
2145 		case 0x0014e280:    retVal = "silver letter e, s=64"; break;
2146 		case 0x0014b800:    retVal = "silver letter O, s=64"; break;
2147 		case 0x00152d80:    retVal = "silver letter A, s=64"; break;
2148 		case 0x0014f680:    retVal = "silver letter m, s=64"; break;
2149 		case 0x00142b40:    retVal = "Black Screen?"; break;
2150 		case 0x00004740:    retVal = "picture bridge over water, s=256"; break;
2151 		case 0x00005c80:    retVal = "picture water shore, s=256"; break;
2152 		case 0x000030c0:    retVal = "left leaderboard background graphics, s=256"; break;
2153 		case 0x00003c00:    retVal = "right leaderboard background graphics, s=256"; break;
2154 		case 0x00040bc0:    retVal = "extreme mode, s=128, t=8alpha"; break;
2155 		case 0x001602a0:    retVal = "photo black hat, sunglasses, gautee, s=64, t=8"; break;
2156 		case 0x00091630:    retVal = "photo wild eye guy, s=64"; break;
2157 		case 0x00159d80:    retVal = "white M s=32, t=4"; break;
2158 		case 0x0015a080:    retVal = "white 9 s=32, t=4"; break;
2159 		case 0x00159f00:    retVal = "white P s=32, t=4"; break;
2160 		case 0x00145a40:    retVal = "white crossbar? s=32, t=4"; break;
2161 		case 0x00145c40:    retVal = "white crossbar2? s=32, t=4"; break;
2162 		case 0x00159300:    retVal = "white _ s=32, t=4"; break;
2163 		case 0x00158d00:    retVal = "white 1 s=32, t=4"; break;
2164 		case 0x00158e80:    retVal = "white 4 s=32, t=4"; break;
2165 		case 0x0001c080:    retVal = "scorecard background, s=256, t=8alpha"; break;
2166 		default: retVal = "Unknown"; break;
2167 		}
2168 	}
2169 	else {
2170 		switch (zeus_texbase) {
2171 		// thegrid
2172 		case 0x000116c8:    retVal = "letter L, s=16, t=4a"; break;
2173 		case 0x00011668:    retVal = "letter O, s=16, t=4a"; break;
2174 		case 0x00011828:    retVal = "letter A, s=16, t=4a"; break;
2175 		case 0x000117c8:    retVal = "letter D, s=16, t=4a"; break;
2176 		case 0x00011728:    retVal = "letter I, s=16, t=4a"; break;
2177 		case 0x00011688:    retVal = "letter N, s=16, t=4a"; break;
2178 		case 0x00011768:    retVal = "letter G, s=16, t=4a"; break;
2179 		case 0x00155b40:    retVal = "green 1010, s=256, t=8"; break;
2180 		case 0x0014db80:    retVal = "The Grid logo, s=256, t=8alpha"; break;
2181 		case 0x0014f280:    retVal = "Searching fo, s=256, t=8alpha"; break;
2182 		case 0x00150500:    retVal = "or, s=64, t=8alpha"; break;
2183 		case 0x000c4400:    retVal = "P, s=32, t=8alpha"; break;
2184 		case 0x000c3ba0:    retVal = "U, s=32, t=8alpha"; break;
2185 		case 0x000c3c00:    retVal = "S, s=32, t=8alpha"; break;
2186 		case 0x000c3c60:    retVal = "H, s=32, t=8alpha"; break;
2187 		case 0x000c39c0:    retVal = "T, s=32, t=8alpha"; break;
2188 		case 0x000c4c70:    retVal = "A, s=32, t=8alpha"; break;
2189 		case 0x000c4070:    retVal = "R, s=32, t=8alpha"; break;
2190 		case 0x000c4460:    retVal = "O, s=32, t=8alpha"; break;
2191 		case 0x000c47a0:    retVal = "E, s=32, t=8alpha"; break;
2192 		case 0x000c48f0:    retVal = "C, s=32, t=8alpha"; break;
2193 		case 0x000c3de0:    retVal = "V, s=32, t=8alpha"; break;
2194 		case 0x000c4650:    retVal = "I, s=32, t=8alpha"; break;
2195 		case 0x000c3a20:    retVal = "N, s=32, t=8alpha"; break;
2196 		case 0x000c4fd0:    retVal = "0, s=32, t=8alpha"; break;
2197 		case 0x000c4290:    retVal = "., s=32, t=8alpha"; break;
2198 		case 0x000c4f70:    retVal = "2, s=32, t=8alpha"; break;
2199 		case 0x000c5030:    retVal = "1, s=32, t=8alpha"; break;
2200 		case 0x000c3ec0:    retVal = "/, s=32, t=8alpha"; break;
2201 		case 0x000c4df0:    retVal = "6, s=32, t=8alpha"; break;
2202 		case 0x00150d00:    retVal = "System 1, s=128, t=8"; break;
2203 		case 0x00151360:    retVal = "System 2, s=128, t=8"; break;
2204 		case 0x001519c0:    retVal = "System 3, s=128, t=8"; break;
2205 		case 0x00152020:    retVal = "System 4, s=128, t=8"; break;
2206 		case 0x00152680:    retVal = "System 5, s=128, t=8"; break;
2207 		case 0x00152ce0:    retVal = "System 6, s=128, t=8"; break;
2208 		case 0x001509c0:    retVal = "READY!, s=128, t=8alpha"; break;
2209 		case 0x000c2d10:    retVal = "6, s=32, t=8alpha"; break;
2210 		case 0x000c30d0:    retVal = "0, s=32, t=8alpha"; break;
2211 		case 0x000c2db0:    retVal = "5, s=32, t=8alpha"; break;
2212 		case 0x000c2b30:    retVal = "9, s=32, t=8alpha"; break;
2213 		case 0x000c2bd0:    retVal = "8, s=32, t=8alpha"; break;
2214 		case 0x000c2c70:    retVal = "7, s=32, t=8alpha"; break;
2215 		case 0x000c2e50:    retVal = "4, s=32, t=8alpha"; break;
2216 		case 0x000c2ef0:    retVal = "3, s=32, t=8alpha"; break;
2217 		case 0x000c2f90:    retVal = "2, s=32, t=8alpha"; break;
2218 		case 0x000c3030:    retVal = "1, s=32, t=8alpha"; break;
2219 		case 0x0014fb80:    retVal = "Brownish circle, s=64, t=8_4x2"; break;
2220 		case 0x0014fd80:    retVal = "Midsize Dark circle rainbow edge, s=256, t=8_4x2"; break;
2221 		case 0x00150580:    retVal = "Dark circle rainbow edge, s=256, t=8_4x2"; break;
2222 		case 0x00012fb0:    retVal = "Red dots, s=16, t=4_2x2"; break;
2223 		case 0x0013b500:    retVal = "Flash with purple outer edge, s=128, t=8_alpha"; break;
2224 		case 0x001c6220:    retVal = "Yellow console?, s=128, t=8_4x2"; break;
2225 		case 0x001c58e0:    retVal = "White/Red Fabric?, s=128, t=8_4x2"; break;
2226 		case 0x001c8b10:    retVal = "White Fabric with yellow band LOD0?, s=64, t=8_4x2"; break;
2227 		case 0x001c6880:    retVal = "White Fabric with yellow band LOD1?, s=128, t=8_4x2"; break;
2228 		case 0x001c76e0:    retVal = "Chiller face, s=128, t=8_4x2"; break;
2229 		case 0x0018cc80:    retVal = "Green grid square 10101, s=256, t=8_4x2"; break;
2230 		case 0x00187780:    retVal = "Left logo The Grid, s=256, t=8_alpha"; break;
2231 		case 0x0018a200:    retVal = "Right logo the Grid, s=256, t=8_alpha"; break;
2232 		case 0x0003cc00:    retVal = "CREDITS, s=256, t=8_alpha"; break;
2233 		case 0x0003e780:    retVal = "INSERT COINS, s=256, t=8_alpha"; break;
2234 		case 0x0003fe00:    retVal = "White 1, s=32, t=8_alpha"; break;
2235 		case 0x0003fbc0:    retVal = "White 2, s=64, t=8_alpha"; break;
2236 		case 0x0003d580:    retVal = "PRESS START, s=256, t=8_alpha"; break;
2237 		//case 0x00154740:    retVal = "Chiller Face, s=128, t=16rgb"; break;
2238 		//case 0x00153340:    retVal = "Ike Face, s=128, t=16rgb"; break;
2239 		case 0x00154740:    retVal = "Just Play, s=256, t=8_4x2"; break;
2240 		case 0x00153340:    retVal = "Enter Name, s=256, t=8_4x2"; break;
2241 		case 0x00130d00:    retVal = "Cyrus highlight screen, s=128, t=8_4x2"; break;
2242 		case 0x00139700:    retVal = "Green Welcome To, s=128, t=4_2x2"; break;
2243 		case 0x0012f300:    retVal = "More people in stands, s=64, t=8_4x2"; break;
2244 		case 0x0012fd00:    retVal = "Even more people in stands, s=64, t=8_4x2"; break;
2245 		case 0x0003ff20:    retVal = "0, s=64, t=8_alpha"; break;
2246 		case 0x00130300:    retVal = "People in stands, s=64, t=8_4x2"; break;
2247 		case 0x0007c8e0:    retVal = "Greenish blob, s=64, t=8_alpha"; break;
2248 		case 0x0015c940:    retVal = "Red +"; break;
2249 		case 0x0015bf40:    retVal = "Blue circle with green outline"; break;
2250 		case 0x0015c740:    retVal = "Radiation symbol"; break;
2251 		case 0x0015cb80:    retVal = "Grey square"; break;
2252 		case 0x0015d380:    retVal = "Green circle inside grey square"; break;
2253 		case 0x00159f40:    retVal = "Shinny green square"; break;
2254 		case 0x001a6340:    retVal = "Yellow ski tip"; break;
2255 		case 0x001a65a0:    retVal = "Metal vest"; break;
2256 		case 0x001a6a00:    retVal = "Head hole metal vest"; break;
2257 		case 0x001a6b70:    retVal = "Yellow WES badge"; break;
2258 		case 0x001a6140:    retVal = "Backwards Yellow WES badge"; break;
2259 		case 0x001a6d70:    retVal = "Maybe stomach"; break;
2260 		case 0x001a6e60:    retVal = "Maybe back"; break;
2261 		case 0x001a6f20:    retVal = "Hand with black glove"; break;
2262 		case 0x001a7090:    retVal = "Wes Face"; break;
2263 		case 0x001a72c0:    retVal = "Dark red strip"; break;
2264 		case 0x001a7340:    retVal = "Wes shoulder pad"; break;
2265 		case 0x001a7460:    retVal = "Orange circle"; break;
2266 		case 0x001a5e20:    retVal = "Wes belt"; break;
2267 		case 0x001a5f40:    retVal = "Wes orange strip on side"; break;
2268 		case 0x001a7770:    retVal = "Grey something"; break;
2269 		case 0x001a74e0:    retVal = "Grey maybe top of boot"; break;
2270 		case 0x001a76e0:    retVal = "Grey hexagon"; break;
2271 		case 0x001a7800:    retVal = "Belt pouches"; break;
2272 		case 0x0015a340:    retVal = "Green shinny block"; break;
2273 		default: retVal = "Unknown"; break;
2274 		}
2275 	}
2276 	return retVal;
2277 }
2278 #endif
2279