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 = ®data[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