dev_pvr.cc Source File

Back to the index.

dev_pvr.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2014 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * COMMENT: PowerVR CLX2 (graphics controller used in the Dreamcast)
29  *
30  * Implemented by reading http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt and
31  * http://mc.pp.se/dc/pvr.html, source code of various demos and KallistiOS,
32  * attempting to run the PROM from my own Dreamcast, and doing a lot of
33  * guessing.
34  *
35  * TODO: Almost everything
36  *
37  * x) Change resolution during runtime (PAL/NTSC/???)
38  *
39  * x) Lots of work on the 3D "Tile Accelerator" engine.
40  * Recognize commands and turn into OpenGL or similar
41  * commands on the host?
42  * Wire-frame when running on a host without XGL?
43  *
44  * Multiple lists of various kinds (6?).
45  * Lists growing downwards!
46  * Pixel clip for rendering.
47  * Real Rendering, using OpenGL if possible.
48  * Tile bins... with 6 pointers for each tile (?)
49  * PVR DMA.
50  * Textures.
51  * ...
52  */
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #include "cpu.h"
59 #include "device.h"
60 #include "devices.h"
61 #include "float_emul.h"
62 #include "machine.h"
63 #include "memory.h"
64 #include "misc.h"
65 #include "timer.h"
66 
69 
70 
71 /* For debugging: */
72 //#define DEBUG_RENDER_AS_WIRE_FRAME // Renders 3-corner textured polygons as wire-frame
73 //#define TA_DEBUG // Dumps TA commands
74 //#define debug fatal // Dumps debug even without -v.
75 
76 #define INTERNAL_FB_ADDR 0x300000000ULL
77 #define PVR_FB_TICK_SHIFT 18
78 
79 #define PVR_VBLANK_HZ 60.0
80 
81 #define PVR_MARGIN 16
82 
83 #define VRAM_SIZE (8*1048576)
84 
85 /* DMA: */
86 #define PVR_DMA_MEMLENGTH 0x100
87 #define N_PVR_DMA_REGS (PVR_DMA_MEMLENGTH / sizeof(uint32_t))
88 
89 #define PVR_ADDR 0x00
90 #define PVR_COUNT 0x04
91 #define PVR_MODE 0x08
92 #define PVR_LMMODE0 0x84
93 #define PVR_LMMODE1 0x88
94 
95 
96 struct pvr_data {
97  struct vfb_data *fb;
102 
105 
106  /* PVR registers: */
107  uint32_t reg[PVRREG_REGSIZE / sizeof(uint32_t)];
108 
109  /* Calculated by pvr_geometry_updated(): */
110  int xsize, ysize;
112 
113  /* Cached values (from registers): */
114  /* DIWMODE: */
119  int extend;
123  /* BRDCOLR: */
125  /* SYNCCONF: */
131  /* TILEBUF_SIZE: */
134 
135  /* Current Tile Accelerator Command (64 bytes): */
136  uint32_t ta[64 / sizeof(uint32_t)];
137 
138  /* Stored list of TA commands: */
140  uint32_t *ta_commands;
143 
144  /* Video RAM and Z information: */
145  uint8_t *vram;
146  double *vram_z;
147 
148  /* DMA registers: */
151 };
152 
153 struct pvr_data_alt {
154  struct pvr_data *d;
155 };
156 
157 
158 #define REG(x) (d->reg[(x)/sizeof(uint32_t)])
159 #define DEFAULT_WRITE REG(relative_addr) = idata;
160 
161 
162 /* Forward declaration. */
163 DEVICE_ACCESS(pvr_ta);
164 
165 
166 void pvr_dma_transfer(struct cpu *cpu, struct pvr_data *d)
167 {
168  const int channel = 2;
169  uint32_t sar = cpu->cd.sh.dmac_sar[channel] & 0x1fffffff;
170  uint32_t dar = cpu->cd.sh.dmac_dar[channel] & 0x1fffffff;
171  uint32_t count = cpu->cd.sh.dmac_tcr[channel] & 0x1fffffff;
172  uint32_t chcr = cpu->cd.sh.dmac_chcr[channel];
173  int transmit_size = 1;
174  int src_delta = 0, dst_delta = 0;
175  int cause_interrupt = chcr & CHCR_IE;
176 
177 #if 0
178  // Dump all SH4 DMA channels, for debugging:
179  for (int dmaChannel = 0; dmaChannel < 4; ++dmaChannel)
180  {
181  fatal("{# dma channel %i: sar=%08x dar=%08x count=%08x chcr=%08x #}\n",
182  dmaChannel,
183  cpu->cd.sh.dmac_sar[dmaChannel],
184  cpu->cd.sh.dmac_dar[dmaChannel],
185  cpu->cd.sh.dmac_tcr[dmaChannel],
186  cpu->cd.sh.dmac_chcr[dmaChannel]);
187  }
188 #endif
189 
190  /* DMAC not enabled? */
191  if (!(chcr & CHCR_TD)) {
192  fatal("pvr_dma_transfer: SH4 dma not enabled?\n");
193  exit(1);
194  }
195 
196  /* Transfer End already set? Then don't transfer again. */
197  if (chcr & CHCR_TE)
198  return;
199 
200  /* Special case: 0 means 16777216: */
201  if (count == 0)
202  count = 16777216;
203 
204  switch (chcr & CHCR_TS) {
205  case CHCR_TS_8BYTE: transmit_size = 8; break;
206  case CHCR_TS_1BYTE: transmit_size = 1; break;
207  case CHCR_TS_2BYTE: transmit_size = 2; break;
208  case CHCR_TS_4BYTE: transmit_size = 4; break;
209  case CHCR_TS_32BYTE: transmit_size = 32; break;
210  default: fatal("Unimplemented transmit size?! CHCR[%i] = 0x%08x\n",
211  channel, chcr);
212  exit(1);
213  }
214 
215  switch (chcr & CHCR_DM) {
216  case CHCR_DM_FIXED: dst_delta = 0; break;
217  case CHCR_DM_INCREMENTED: dst_delta = 1; break;
218  case CHCR_DM_DECREMENTED: dst_delta = -1; break;
219  default: fatal("Unimplemented destination delta?! CHCR[%i] = 0x%08x\n",
220  channel, chcr);
221  exit(1);
222  }
223 
224  switch (chcr & CHCR_SM) {
225  case CHCR_SM_FIXED: src_delta = 0; break;
226  case CHCR_SM_INCREMENTED: src_delta = 1; break;
227  case CHCR_SM_DECREMENTED: src_delta = -1; break;
228  default: fatal("Unimplemented source delta?! CHCR[%i] = 0x%08x\n",
229  channel, chcr);
230  exit(1);
231  }
232 
233  src_delta *= transmit_size;
234  dst_delta *= transmit_size;
235 
236  switch (chcr & CHCR_RS) {
237  case 0x200:
238  dar = d->dma_reg[PVR_ADDR / sizeof(uint32_t)];
239 
240  if (dar != 0x10000000) {
241  //fatal("[ NOTE: DMA to non-TA: dar=%08x (delta %i), sar=%08x (delta %i) ]\n",
242  // (int)dar, (int)dst_delta, (int)sar, (int)src_delta);
243  dar = 0x04000000 | (dar & 0x007fffff);
244  if (dst_delta == 0)
245  dst_delta = src_delta;
246 
247  uint8_t *buf = (uint8_t*) malloc(transmit_size);
248  while (count > 0) {
249  // printf("sar = %08x dar = %08x\n", (int)sar, (int)dar);
250 
251  cpu->memory_rw(cpu, cpu->mem, sar, buf,
252  transmit_size, MEM_READ, NO_EXCEPTIONS | PHYSICAL);
253  // for (int i = 0; i < transmit_size; ++i)
254  // printf("%02x ", buf[i]);
255  // printf("\n");
256 
257  cpu->memory_rw(cpu, cpu->mem, dar, buf,
258  transmit_size, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
259 
260  count --;
261  sar += src_delta;
262  dar += dst_delta;
263  }
264 
265  free(buf);
266 
267  break;
268  } else {
269  while (count > 0) {
270  unsigned char buf[sizeof(uint32_t)];
271  int ofs;
272  size_t chunksize = transmit_size;
273 
274  if (chunksize > sizeof(uint32_t))
275  chunksize = sizeof(uint32_t);
276 
277  for (ofs = 0; ofs < transmit_size; ofs += chunksize) {
278  cpu->memory_rw(cpu, cpu->mem, sar + ofs, buf,
279  chunksize, MEM_READ, NO_EXCEPTIONS | PHYSICAL);
280 
281  dev_pvr_ta_access(cpu, cpu->mem, ofs, buf, chunksize,
282  MEM_WRITE, d);
283  }
284 
285  count --;
286  sar += src_delta;
287  }
288  }
289 
290  // Transfer End. TODO: _EXACTLY_ what happens at the end of
291  // a transfer?
292  cpu->cd.sh.dmac_chcr[channel] |= CHCR_TE;
293  cpu->cd.sh.dmac_chcr[channel] &= ~CHCR_TD;
294  cpu->cd.sh.dmac_sar[channel] = sar;
295  cpu->cd.sh.dmac_tcr[channel] = count;
296 
297  // d->dma_reg[PVR_ADDR / sizeof(uint32_t)] = ???;
298  d->dma_reg[PVR_COUNT / sizeof(uint32_t)] = 0;
299 
301 
302  break;
303  default:
304  fatal("Unimplemented SH4 RS DMAC: 0x%08x (PVR)\n",
305  (int) (chcr & CHCR_RS));
306  exit(1);
307  }
308 
309  if (cause_interrupt) {
310  fatal("TODO: pvr sh4 dmac interrupt!\n");
311  exit(1);
312  }
313 }
314 
315 
317 {
318  struct pvr_data *d = (struct pvr_data *) extra;
319  uint64_t idata = 0, odata = 0;
320 
321  if (writeflag == MEM_WRITE)
322  idata = memory_readmax64(cpu, data, len);
323 
324  /* Default read: */
325  if (writeflag == MEM_READ)
326  odata = d->dma_reg[relative_addr / sizeof(uint32_t)];
327 
328  switch (relative_addr) {
329 
330  case PVR_ADDR:
331  if (writeflag == MEM_WRITE) {
332  debug("[ pvr_dma: ADDR set to 0x%08x ]\n",
333  (int) idata);
334  }
335  break;
336 
337  case PVR_COUNT:
338  if (writeflag == MEM_WRITE) {
339  debug("[ pvr_dma: COUNT set to 0x%08x ]\n",
340  (int) idata);
341  }
342  break;
343 
344  case PVR_MODE:
345  if (writeflag == MEM_WRITE) {
346  debug("[ pvr_dma: MODE set to 0x%08x ]\n",
347  (int) idata);
348  if (idata != 0) {
349  pvr_dma_transfer(cpu, d);
350  idata = 0;
351  }
352  }
353  break;
354 
355  /* These are written to by the Dreamcast ROM, but I have not
356  found them documented anywhere. */
357  case 0x10:
358  case 0x14:
359  if (writeflag == MEM_WRITE && idata != 0x0cff0000) {
360  fatal("[ pvr_dma: TODO: unknown_0x%02x set to "
361  "0x%08x ]\n", (int) relative_addr, (int) idata);
362  exit(1);
363  }
364  break;
365 
366  case 0x18:
367  case 0x1c:
368  case 0x20:
369  case 0x40:
370  case 0x44:
371  case 0x48:
372  case 0x4c:
373  if (writeflag == MEM_WRITE && idata != 0) {
374  fatal("[ pvr_dma: TODO: unknown_0x%02x set to "
375  "0x%08x ]\n", (int) relative_addr, (int) idata);
376  exit(1);
377  }
378  break;
379 
380  case PVR_LMMODE0: /* 0x84 */
381  if (writeflag == MEM_WRITE && idata != 0) {
382  fatal("[ pvr_dma: TODO: LMMODE0 set to "
383  "0x%08x ]\n", (int) idata);
384  exit(1);
385  }
386  break;
387 
388  case PVR_LMMODE1: /* 0x88 */
389  if (writeflag == MEM_WRITE && idata != 0) {
390  fatal("[ pvr_dma: TODO: LMMODE1 set to "
391  "0x%08x ]\n", (int) idata);
392  exit(1);
393  }
394  break;
395 
396  case 0x8c:
397  if (writeflag == MEM_WRITE) {
398  fatal("[ pvr_dma: write to 0x8c: TODO ]\n");
399  exit(1);
400  } else {
401  /* 0x20 means G2 DMA in progress? */
402  /* 0x11 = mask which has to do with AICA */
403  odata = 0x11 * (random() & 1);
404  }
405  break;
406 
407  case 0x9c:
408  if (writeflag == MEM_WRITE && idata != 0) {
409  fatal("[ pvr_dma: TODO: unknown_0x%02x set to "
410  "0x%08x ]\n", (int) relative_addr, (int) idata);
411  exit(1);
412  }
413  break;
414 
415  case 0xa0:
416  if (writeflag == MEM_WRITE && idata != 0x80000000) {
417  fatal("[ pvr_dma: TODO: unknown_0x%02x set to "
418  "0x%08x ]\n", (int) relative_addr, (int) idata);
419  exit(1);
420  }
421  break;
422 
423  case 0xa4:
424  case 0xac:
425  if (writeflag == MEM_WRITE && idata != 0) {
426  fatal("[ pvr_dma: TODO: unknown_0x%02x set to "
427  "0x%08x ]\n", (int) relative_addr, (int) idata);
428  exit(1);
429  }
430  break;
431 
432  default:if (writeflag == MEM_READ) {
433  fatal("[ pvr_dma: read from addr 0x%x ]\n",
434  (int)relative_addr);
435  } else {
436  fatal("[ pvr_dma: write to addr 0x%x: 0x%x ]\n",
437  (int)relative_addr, (int)idata);
438  }
439 
440  exit(1);
441  }
442 
443  /* Default write: */
444  if (writeflag == MEM_WRITE)
445  d->dma_reg[relative_addr / sizeof(uint32_t)] = idata;
446 
447  if (writeflag == MEM_READ)
448  memory_writemax64(cpu, data, len, odata);
449 
450  return 1;
451 }
452 
453 
454 DEVICE_ACCESS(pvr_dma_more)
455 {
456  struct pvr_data *d = (struct pvr_data *) extra;
457  uint64_t idata = 0, odata = 0;
458 
459  if (writeflag == MEM_WRITE)
460  idata = memory_readmax64(cpu, data, len);
461 
462  /* Default read: */
463  if (writeflag == MEM_READ)
464  odata = d->dma_more_reg[relative_addr / sizeof(uint32_t)];
465 
466  switch (relative_addr) {
467 
468  case 0x00: // 0x04ff0000
469  case 0x04: // 0x0cff0000
470  case 0x08: // 0x00000020
471  case 0x0c: // 0x00000000
472  case 0x10: // 0x00000000
473  case 0x80: // 0x67027f00
474  break;
475 
476  case 0x14:
477  case 0x18:
478  if (writeflag == MEM_WRITE && idata != 0)
479  {
480  fatal("PVR other DMA mode (?):\n");
481  fatal("0x00: %08x\n", d->dma_more_reg[0x00/4]);
482  fatal("0x04: %08x\n", d->dma_more_reg[0x04/4]);
483  fatal("0x08: %08x\n", d->dma_more_reg[0x08/4]);
484  fatal("0x0c: %08x\n", d->dma_more_reg[0x0c/4]);
485  fatal("0x10: %08x\n", d->dma_more_reg[0x10/4]);
486  fatal("0x14: %08x\n", d->dma_more_reg[0x14/4]);
487  exit(1);
488  }
489  break;
490 
491  default:if (writeflag == MEM_READ) {
492  fatal("[ pvr_dma_more: read from addr 0x%x ]\n",
493  (int)relative_addr);
494  } else {
495  fatal("[ pvr_dma_more: write to addr 0x%x: 0x%x ]\n",
496  (int)relative_addr, (int)idata);
497  }
498 
499  exit(1);
500  }
501 
502  /* Default write: */
503  if (writeflag == MEM_WRITE)
504  d->dma_more_reg[relative_addr / sizeof(uint32_t)] = idata;
505 
506  if (writeflag == MEM_READ)
507  memory_writemax64(cpu, data, len, odata);
508 
509  return 1;
510 }
511 
512 
513 /*
514  * pvr_fb_invalidate():
515  */
516 void pvr_fb_invalidate(struct pvr_data *d, int start, int stop)
517 {
518  d->fb_update_x1 = d->fb_update_y1 = 0;
519  d->fb_update_x2 = d->xsize - 1;
520  d->fb_update_y2 = d->ysize - 1;
521 }
522 
523 
524 /*
525  * pvr_vblank_timer_tick():
526  *
527  * This function is called PVR_VBLANK_HZ times per real-world second. Its job
528  * is to fake vertical retrace interrupts.
529  */
530 static void pvr_vblank_timer_tick(struct timer *t, void *extra)
531 {
532  struct pvr_data *d = (struct pvr_data *) extra;
534 }
535 
536 
537 /*
538  * pvr_geometry_updated():
539  *
540  * This function should be called every time a register is written to which
541  * affects the framebuffer geometry (size, bit-depth, starting position, etc).
542  */
544 {
545  int old_xsize = d->xsize, old_ysize = d->ysize, oldbpp = d->bytes_per_pixel;
546 
547  /* Make sure to redraw border on geometry changes. */
548  d->border_updated = 1;
549 
552 
553  /* E.g. 319x479 => 320x480 */
554  d->xsize = (d->xsize + 1) * sizeof(uint32_t);
555  d->ysize ++;
556 
557  switch (d->pixelmode) {
558  case 0:
559  case 1: d->bytes_per_pixel = 2; break;
560  case 2: d->bytes_per_pixel = 3; break;
561  case 3: d->bytes_per_pixel = 4; break;
562  }
563 
564  d->xsize /= d->bytes_per_pixel;
565 
567  d->xsize /= 2;
568 
569  if (d->line_double)
570  d->ysize /= 2;
571 
572  bool settingsChanged = d->xsize != old_xsize ||
573  d->ysize != old_ysize ||
574  d->bytes_per_pixel != oldbpp;
575 
576  if (!settingsChanged)
577  return;
578 
579  /* Scrap Z buffer if we have one. */
580  if (d->vram_z == NULL) {
581  free(d->vram_z);
582  d->vram_z = NULL;
583  }
584 
585  /* Only show geometry debug message if output is enabled: */
586  if (!d->video_enabled || !d->display_enabled)
587  return;
588 
589  debug("[ pvr_geometry_updated: %i x %i, ", d->xsize, d->ysize);
590 
591  switch (d->pixelmode) {
592  case 0: debug("RGB0555 (16-bit)"); break;
593  case 1: debug("RGB565 (16-bit)"); break;
594  case 2: debug("RGB888 (24-bit)"); break;
595  case 3: debug("RGB0888 (32-bit)"); break;
596  }
597 
598  debug(" ]\n");
599 }
600 
601 
602 #ifdef DEBUG_RENDER_AS_WIRE_FRAME
603 /* Ugly quick-hack: */
604 static void line(struct pvr_data *d, int x1, int y1, int x2, int y2)
605 {
606  int fb_base = REG(PVRREG_FB_RENDER_ADDR1);
607  int i;
608  for (i=0; i<256; i++) {
609  int px = (i * x2 + (256-i) * x1) >> 8;
610  int py = (i * y2 + (256-i) * y1) >> 8;
611  if (px > 0 && py > 0 && px < d->xsize && py < d->ysize) {
612  int ofs = fb_base + (px + py * d->xsize) *
613  d->bytes_per_pixel;
614  d->vram[(ofs+0) % VRAM_SIZE] = 255;
615  d->vram[(ofs+1) % VRAM_SIZE] = 255;
616  }
617  }
618 }
619 #endif
620 
621 
622 // Ugly quick-hack z-buffer line drawer, for triangles.
623 // Assumes 16-bit color.
624 static void simpleline(struct pvr_data *d, int y, double x1, double x2,
625  double z1, double z2, double r1, double r2, double g1, double g2,
626  double b1, double b2)
627 {
628  if (y < 0 || y >= d->ysize || (x1 < 0 && x2 < 0)
629  || (x1 >= d->xsize && x2 >= d->xsize))
630  return;
631 
632  int fb_base = REG(PVRREG_FB_RENDER_ADDR1);
633  if (x1 > x2) {
634  double tmpf = x1; x1 = x2; x2 = tmpf;
635  tmpf = z1; z1 = z2; z2 = tmpf;
636  tmpf = r1; r1 = r2; r2 = tmpf;
637  tmpf = g1; g1 = g2; g2 = tmpf;
638  tmpf = b1; b1 = b2; b2 = tmpf;
639  }
640 
641  // uint32_t fogDensity = REG(PVRREG_FOG_DENSITY);
642  // double scale_factor = 255.0; // TODO: take fogDensity into account.
643  // uint32_t fogColor = REG(PVRREG_FOG_TABLE_COL);
644  // int fog_r = (fogColor >> 16) & 255;
645  // int fog_g = (fogColor >> 8) & 255;
646  // int fog_b = fogColor & 255;
647 
648  double dz12 = (x2 - x1 != 0) ? ( (double)(z2 - z1) / (double)(x2 - x1) ) : 0;
649  double dr12 = (x2 - x1 != 0) ? ( (double)(r2 - r1) / (double)(x2 - x1) ) : 0;
650  double dg12 = (x2 - x1 != 0) ? ( (double)(g2 - g1) / (double)(x2 - x1) ) : 0;
651  double db12 = (x2 - x1 != 0) ? ( (double)(b2 - b1) / (double)(x2 - x1) ) : 0;
652  double z = z1, r = r1, g = g1, b = b1;
653  for (int x = x1; x <= x2; ++x) {
654  if (x > 0 && x < d->xsize) {
655  int ofs = x + y * d->xsize;
656  if (d->vram_z[ofs] <= z) {
657  d->vram_z[ofs] = z;
658 
659  // z = 1/w
660  // int v = z * scale_factor;
661  // printf("z=%f v=%i\n", z, v);
662  // if (v < 0) v = 0;
663  // if (v > 255) v = 255;
664  // v >>= 1;
665 
666  // int fogvalues = d->reg[PVRREG_FOG_TABLE / sizeof(uint32_t) + v];
667  // printf("fogv = %04x\n", fogvalues);
668 
669  // NOTE/TODO: Hardcoded for 565 pixelformat.
670  int ri = r, gi = g, bi = b;
671  // int a = (fogvalues >> 8) & 255;
672  // ri = ((fog_r * a) + (ri * (255 - a))) >> 8;
673  // gi = ((fog_g * a) + (gi * (255 - a))) >> 8;
674  // bi = ((fog_b * a) + (bi * (255 - a))) >> 8;
675 
676  if (ri < 0) ri = 0; if (ri > 255) ri = 255;
677  if (gi < 0) gi = 0; if (gi > 255) gi = 255;
678  if (bi < 0) bi = 0; if (bi > 255) bi = 255;
679  int color = ((ri >> 3) << 11) + ((gi >> 2) << 5) + (bi >> 3);
680 
681  int fbofs = fb_base + ofs * d->bytes_per_pixel;
682  d->vram[(fbofs+0) % VRAM_SIZE] = color & 255;
683  d->vram[(fbofs+1) % VRAM_SIZE] = color >> 8;
684  }
685  }
686 
687  z += dz12; r += dr12; g += dg12; b += db12;
688  }
689 }
690 
691 static void texturedline(struct pvr_data *d,
692  int texture_pixelformat, bool twiddled, int stride,
693  int texture, int texture_xsize, int texture_ysize,
694  int y, int x1, int x2, double z1, double z2,
695  double u1, double u2, double v1, double v2)
696 {
697  if (y < 0 || y >= d->ysize || (x1 < 0 && x2 < 0)
698  || (x1 >= d->xsize && x2 >= d->xsize))
699  return;
700 
701  int fb_base = REG(PVRREG_FB_RENDER_ADDR1);
702  if (x1 > x2) {
703  int tmp = x1; x1 = x2; x2 = tmp;
704  double tmpf = z1; z1 = z2; z2 = tmpf;
705  tmpf = u1; u1 = u2; u2 = tmpf;
706  tmpf = v1; v1 = v2; v2 = tmpf;
707  }
708 
709  int bytesperpixel = 2;
710 
711  switch (texture_pixelformat)
712  {
713  case 0: // ARGB1555
714  case 1: // RGB565
715  case 2: // ARGB4444
716  bytesperpixel = 2;
717  break;
718  case 6: // 8-bit palette
719  bytesperpixel = 1;
720  break;
721  default:
722  // TODO
723  break;
724  }
725 
726  int palette_cfg = d->reg[PVRREG_PALETTE_CFG / sizeof(uint32_t)] & PVR_PALETTE_CFG_MODE_MASK;
727 
728  double dz12 = (x2 - x1 != 0) ? ( (double)(z2 - z1) / (double)(x2 - x1) ) : 0;
729  double du12 = (x2 - x1 != 0) ? ( (double)(u2 - u1) / (double)(x2 - x1) ) : 0;
730  double dv12 = (x2 - x1 != 0) ? ( (double)(v2 - v1) / (double)(x2 - x1) ) : 0;
731 
732  double z = z1, u = u1, v = v1;
733 
734  for (int x = x1; x <= x2; ++x) {
735  if (x > 0 && x < d->xsize) {
736  int ofs = x + y * d->xsize;
737  if (d->vram_z[ofs] <= z) {
738  d->vram_z[ofs] = z;
739 
740  int fbofs = fb_base + ofs * d->bytes_per_pixel;
741 
742  // Get color from texture:
743  int texturex = u * texture_xsize;
744  texturex &= (texture_xsize-1);
745  int texturey = v * texture_ysize;
746  texturey &= (texture_ysize-1);
747 
748  int textureofs;
749  if (twiddled) {
750  texturex =
751  (texturex&1)|((texturex&2)<<1)|((texturex&4)<<2)|((texturex&8)<<3)|((texturex&16)<<4)|
752  ((texturex&32)<<5)|((texturex&64)<<6)|((texturex&128)<<7)|((texturex&256)<<8)|((texturex&512)<<9);
753  texturey =
754  (texturey&1)|((texturey&2)<<1)|((texturey&4)<<2)|((texturey&8)<<3)|((texturey&16)<<4)|
755  ((texturey&32)<<5)|((texturey&64)<<6)|((texturey&128)<<7)|((texturey&256)<<8)|((texturey&512)<<9);
756  textureofs = texturex * 2 + texturey;
757  } else {
758  if (stride > 0)
759  textureofs = texturex + texturey * stride;
760  else
761  textureofs = texturex + texturey * texture_xsize;
762  }
763 
764  textureofs *= bytesperpixel; // 2 bytes per pixel.
765 
766  int addr = texture + textureofs;
767  addr = ((addr & 4) << 20) | (addr & 3) | ((addr & 0x7ffff8) >> 1);
768 
769  int a = 255, r = 64, g = 64, b = 64;
770  switch (texture_pixelformat)
771  {
772  case 0: // ARGB1555:
773  {
774  int color = d->vram[addr] + (d->vram[addr+1] << 8);
775  a = (color >> 15) & 0x1 ? 255 : 0;
776  r = (color >> 10) & 0x1f;
777  g = ((color >> 5) & 0x1f) << 1;
778  b = (color) & 0x1f;
779  }
780  break;
781  case 1: // RGB565:
782  {
783  int color = d->vram[addr] + (d->vram[addr+1] << 8);
784  r = (color >> 11) & 0x1f;
785  g = (color >> 5) & 0x3f;
786  b = (color) & 0x1f;
787  }
788  break;
789  case 2: // ARGB4444:
790  {
791  int color = d->vram[addr] + (d->vram[addr+1] << 8);
792  a = ((color >> 12) & 15) * 0x11;
793  r = ((color >> 8) & 15) << 1;
794  g = ((color >> 4) & 15) << 2;
795  b = ((color) & 15) << 1;
796  }
797  break;
798  case 6:
799  {
800  // TODO: multiple palette banks?
801  int index8bpp = d->vram[addr];
802  char* base = (char*)&d->reg[PVRREG_PALETTE / sizeof(uint32_t)];
803  uint16_t c16 = *((uint16_t*)base + index8bpp);
804  uint16_t c32 = *((uint32_t*)base + index8bpp);
805  switch (palette_cfg) {
807  a = (c16 >> 15) & 0x1 ? 255 : 0;
808  r = (c16 >> 10) & 0x1f;
809  g = ((c16 >> 5) & 0x1f) << 1;
810  b = (c16) & 0x1f;
811  break;
813  r = (c16 >> 11) & 0x1f;
814  g = (c16 >> 5) & 0x3f;
815  b = (c16) & 0x1f;
816  break;
818  a = ((c16 >> 12) & 15) * 0x11;
819  r = ((c16 >> 8) & 15) << 1;
820  g = ((c16 >> 4) & 15) << 2;
821  b = ((c16) & 15) << 1;
822  break;
824  a = (c32 >> 24) & 255;
825  r = ((c32 >> 16) & 255) >> 3;
826  g = ((c32 >> 8) & 255) >> 2;
827  b = ((c32) & 255) >> 3;
828  break;
829  }
830  }
831  break;
832  default:
833  fatal("pvr: unimplemented texture_pixelformat %i\n", texture_pixelformat);
834  exit(1);
835  }
836 
837  if (a == 255)
838  {
839  // Output as RGB565:
840  // TODO: Support other formats.
841  int color = (r << 11) + (g << 5) + (b);
842  d->vram[(fbofs+0) % VRAM_SIZE] = color & 255;
843  d->vram[(fbofs+1) % VRAM_SIZE] = color >> 8;
844  } else if (a > 0) {
845  int oldcolor = d->vram[(fbofs+0) % VRAM_SIZE];
846  oldcolor += (d->vram[(fbofs+1) % VRAM_SIZE] << 8);
847  int oldr = (oldcolor >> 11) & 0x1f;
848  int oldg = (oldcolor >> 5) & 0x3f;
849  int oldb = (oldcolor) & 0x1f;
850  r = (a * r + oldr * (255 - a)) / 255;
851  g = (a * g + oldg * (255 - a)) / 255;
852  b = (a * b + oldb * (255 - a)) / 255;
853  int color = (r << 11) + (g << 5) + (b);
854  d->vram[(fbofs+0) % VRAM_SIZE] = color & 255;
855  d->vram[(fbofs+1) % VRAM_SIZE] = color >> 8;
856  }
857  }
858  }
859 
860  z += dz12;
861  u += du12;
862  v += dv12;
863  }
864 }
865 
866 
867 // Slow software rendering, for debugging:
868 static void pvr_render_triangle(struct pvr_data *d,
869  int x1, int y1, double z1, int r1, int g1, int b1,
870  int x2, int y2, double z2, int r2, int g2, int b2,
871  int x3, int y3, double z3, int r3, int g3, int b3)
872 {
873  // Easiest if 1, 2, 3 are in order top to bottom.
874  if (y2 < y1) {
875  int tmp = x1; x1 = x2; x2 = tmp;
876  tmp = y1; y1 = y2; y2 = tmp;
877  tmp = r1; r1 = r2; r2 = tmp;
878  tmp = g1; g1 = g2; g2 = tmp;
879  tmp = b1; b1 = b2; b2 = tmp;
880  double tmpf = z1; z1 = z2; z2 = tmpf;
881  }
882 
883  if (y3 < y1) {
884  int tmp = x1; x1 = x3; x3 = tmp;
885  tmp = y1; y1 = y3; y3 = tmp;
886  tmp = r1; r1 = r3; r3 = tmp;
887  tmp = g1; g1 = g3; g3 = tmp;
888  tmp = b1; b1 = b3; b3 = tmp;
889  double tmpf = z1; z1 = z3; z3 = tmpf;
890  }
891 
892  if (y3 < y2) {
893  int tmp = x2; x2 = x3; x3 = tmp;
894  tmp = y2; y2 = y3; y3 = tmp;
895  tmp = r2; r2 = r3; r3 = tmp;
896  tmp = g2; g2 = g3; g3 = tmp;
897  tmp = b2; b2 = b3; b3 = tmp;
898  double tmpf = z2; z2 = z3; z3 = tmpf;
899  }
900 
901  if (y3 < 0 || y1 >= d->ysize)
902  return;
903 
904  double dx12 = (y2-y1 != 0) ? ( (x2 - x1) / (double)(y2 - y1) ) : 0.0;
905  double dx13 = (y3-y1 != 0) ? ( (x3 - x1) / (double)(y3 - y1) ) : 0.0;
906  double dx23 = (y3-y2 != 0) ? ( (x3 - x2) / (double)(y3 - y2) ) : 0.0;
907 
908  double dz12 = (y2-y1 != 0) ? ( (z2 - z1) / (double)(y2 - y1) ) : 0.0;
909  double dz13 = (y3-y1 != 0) ? ( (z3 - z1) / (double)(y3 - y1) ) : 0.0;
910  double dz23 = (y3-y2 != 0) ? ( (z3 - z2) / (double)(y3 - y2) ) : 0.0;
911 
912  double dr12 = (y2-y1 != 0) ? ( (r2 - r1) / (double)(y2 - y1) ) : 0.0;
913  double dr13 = (y3-y1 != 0) ? ( (r3 - r1) / (double)(y3 - y1) ) : 0.0;
914  double dr23 = (y3-y2 != 0) ? ( (r3 - r2) / (double)(y3 - y2) ) : 0.0;
915 
916  double dg12 = (y2-y1 != 0) ? ( (g2 - g1) / (double)(y2 - y1) ) : 0.0;
917  double dg13 = (y3-y1 != 0) ? ( (g3 - g1) / (double)(y3 - y1) ) : 0.0;
918  double dg23 = (y3-y2 != 0) ? ( (g3 - g2) / (double)(y3 - y2) ) : 0.0;
919 
920  double db12 = (y2-y1 != 0) ? ( (b2 - b1) / (double)(y2 - y1) ) : 0.0;
921  double db13 = (y3-y1 != 0) ? ( (b3 - b1) / (double)(y3 - y1) ) : 0.0;
922  double db23 = (y3-y2 != 0) ? ( (b3 - b2) / (double)(y3 - y2) ) : 0.0;
923 
924  double startx = x1, startz = z1, startr = r1, startg = g1, startb = b1;
925  double stopx = x1, stopz = z1, stopr = r1, stopg = g1, stopb = b1;
926  for (int y = y1; y < y2; ++y)
927  {
928  simpleline(d, y, startx, stopx, startz, stopz, startr, stopr, startg, stopg, startb, stopb);
929  startx += dx13; startz += dz13; startr += dr13; startg += dg13; startb += db13;
930  stopx += dx12; stopz += dz12; stopr += dr12; stopg += dg12; stopb += db12;
931  }
932 
933  stopx = x2; stopz = z2; stopr = r2; stopg = g2; stopb = b2;
934  for (int y = y2; y < y3; ++y)
935  {
936  simpleline(d, y, startx, stopx, startz, stopz, startr, stopr, startg, stopg, startb, stopb);
937  startx += dx13; startz += dz13; startr += dr13; startg += dg13; startb += db13;
938  stopx += dx23; stopz += dz23; stopr += dr23; stopg += dg23; stopb += db23;
939  }
940 
941 #ifdef DEBUG_RENDER_AS_WIRE_FRAME
942  // Wire-frame test:
943  line(d, x1, y1, x2, y2);
944  line(d, x1, y1, x3, y3);
945  line(d, x2, y2, x3, y3);
946 #endif
947 }
948 
949 
950 // Slow software rendering, for debugging:
951 static void pvr_render_triangle_textured(struct pvr_data *d,
952  int texture_pixelformat, bool twiddled, int stride,
953  int texture, int texture_xsize, int texture_ysize,
954  int x1, int y1, double z1, double u1, double v1,
955  int x2, int y2, double z2, double u2, double v2,
956  int x3, int y3, double z3, double u3, double v3)
957 {
958  // Easiest if 1, 2, 3 are in order top to bottom.
959  if (y2 < y1) {
960  int tmp = x1; x1 = x2; x2 = tmp;
961  tmp = y1; y1 = y2; y2 = tmp;
962  double tmpf = z1; z1 = z2; z2 = tmpf;
963  tmpf = u1; u1 = u2; u2 = tmpf;
964  tmpf = v1; v1 = v2; v2 = tmpf;
965  }
966 
967  if (y3 < y1) {
968  int tmp = x1; x1 = x3; x3 = tmp;
969  tmp = y1; y1 = y3; y3 = tmp;
970  double tmpf = z1; z1 = z3; z3 = tmpf;
971  tmpf = u1; u1 = u3; u3 = tmpf;
972  tmpf = v1; v1 = v3; v3 = tmpf;
973  }
974 
975  if (y3 < y2) {
976  int tmp = x2; x2 = x3; x3 = tmp;
977  tmp = y2; y2 = y3; y3 = tmp;
978  double tmpf = z2; z2 = z3; z3 = tmpf;
979  tmpf = u2; u2 = u3; u3 = tmpf;
980  tmpf = v2; v2 = v3; v3 = tmpf;
981  }
982 
983  if (y3 < 0 || y1 >= d->ysize)
984  return;
985 
986  double dx12 = (y2-y1 != 0) ? ( (x2 - x1) / (double)(y2 - y1) ) : 0.0;
987  double dx13 = (y3-y1 != 0) ? ( (x3 - x1) / (double)(y3 - y1) ) : 0.0;
988  double dx23 = (y3-y2 != 0) ? ( (x3 - x2) / (double)(y3 - y2) ) : 0.0;
989 
990  double dz12 = (y2-y1 != 0) ? ( (z2 - z1) / (double)(y2 - y1) ) : 0.0;
991  double dz13 = (y3-y1 != 0) ? ( (z3 - z1) / (double)(y3 - y1) ) : 0.0;
992  double dz23 = (y3-y2 != 0) ? ( (z3 - z2) / (double)(y3 - y2) ) : 0.0;
993 
994  double du12 = (y2-y1 != 0) ? ( (u2 - u1) / (double)(y2 - y1) ) : 0.0;
995  double du13 = (y3-y1 != 0) ? ( (u3 - u1) / (double)(y3 - y1) ) : 0.0;
996  double du23 = (y3-y2 != 0) ? ( (u3 - u2) / (double)(y3 - y2) ) : 0.0;
997 
998  double dv12 = (y2-y1 != 0) ? ( (v2 - v1) / (double)(y2 - y1) ) : 0.0;
999  double dv13 = (y3-y1 != 0) ? ( (v3 - v1) / (double)(y3 - y1) ) : 0.0;
1000  double dv23 = (y3-y2 != 0) ? ( (v3 - v2) / (double)(y3 - y2) ) : 0.0;
1001 
1002  double startx = x1, startz = z1, startu = u1, startv = v1;
1003  double stopx = x1, stopz = z1, stopu = u1, stopv = v1;
1004 
1005  for (int y = y1; y < y2; ++y)
1006  {
1007  texturedline(d, texture_pixelformat, twiddled, stride, texture, texture_xsize, texture_ysize, y, startx, stopx, startz, stopz, startu, stopu, startv, stopv);
1008  startx += dx13; startz += dz13; startu += du13; startv += dv13;
1009  stopx += dx12; stopz += dz12; stopu += du12; stopv += dv12;
1010  }
1011 
1012  stopx = x2; stopz = z2; stopu = u2; stopv = v2;
1013  for (int y = y2; y < y3; ++y)
1014  {
1015  texturedline(d, texture_pixelformat, twiddled, stride, texture, texture_xsize, texture_ysize, y, startx, stopx, startz, stopz, startu, stopu, startv, stopv);
1016  startx += dx13; startz += dz13; startu += du13; startv += dv13;
1017  stopx += dx23; stopz += dz23; stopu += du23; stopv += dv23;
1018  }
1019 
1020 #ifdef DEBUG_RENDER_AS_WIRE_FRAME
1021  // Wire-frame test:
1022  line(d, x1, y1, x2, y2);
1023  line(d, x1, y1, x3, y3);
1024  line(d, x2, y2, x3, y3);
1025 #endif
1026 }
1027 
1028 
1029 static void pvr_clear_ta_commands(struct pvr_data* d)
1030 {
1031  d->n_ta_commands = 0;
1032 }
1033 
1034 
1035 /*
1036  * pvr_render():
1037  *
1038  * Render from the Object Buffer to the framebuffer.
1039  *
1040  * TODO: This function is totally bogus so far, the format of the Object
1041  * Buffer is just a quick made-up hack to see if it works at all.
1042  */
1043 void pvr_render(struct cpu *cpu, struct pvr_data *d)
1044 {
1045  int fb_render_cfg = REG(PVRREG_FB_RENDER_CFG);
1046  int fb_base = REG(PVRREG_FB_RENDER_ADDR1);
1047 
1048  if ((fb_render_cfg & FB_RENDER_CFG_RENDER_MODE_MASK) != 0x1) {
1049  printf("pvr: only RGB565 rendering has been implemented\n");
1050  exit(1);
1051  }
1052 
1053  // Settings for the current polygon being rendered:
1054  // Word 0:
1055  int listtype = 0;
1056  int striplength = 0;
1057  int clipmode;
1058  int modifier;
1059  int modifier_mode;
1060  int color_type = 0;
1061  bool texture = false;
1062  bool specular;
1063  bool shading;
1064  bool uv_format;
1065 
1066  // Word 1:
1067  int depthmode;
1068  int cullingmode = 0;
1069  bool zwrite;
1070  bool texture1;
1071  bool specular1;
1072  bool shading1;
1073  bool uv_format1;
1074  bool dcalcexact;
1075 
1076  // Word 2:
1077  int fog = 0;
1078  int texture_usize = 0, texture_vsize = 0;
1079 
1080  // Word 3:
1081  bool texture_mipmap = false;
1082  bool texture_vq_compression = false;
1083  int texture_pixelformat = 0;
1084  bool texture_twiddled = false;
1085  bool texture_stride = false;
1086  uint32_t textureAddr = 0;
1087 
1088  int vertex_index = 0;
1089  int wf_x[4], wf_y[4]; double wf_z[4], wf_u[4], wf_v[4];
1090  int wf_r[4], wf_g[4], wf_b[4];
1091 
1092  double baseRed = 0.0, baseGreen = 0.0, baseBlue = 0.0;
1093 
1094  debug("[ pvr_render: rendering to FB offset 0x%x, "
1095  "%i Tile Accelerator commands ]\n", fb_base, d->n_ta_commands);
1096 
1097  /*
1098  * Clear all pixels first.
1099  * TODO: Maybe only clear the specific tiles that are in use by
1100  * the tile accelerator?
1101  * TODO: What background color to use? See KOS' pvr_misc.c for
1102  * how KOS sets the background.
1103  */
1104  memset(d->vram + fb_base, 0x00, d->xsize * d->ysize * d->bytes_per_pixel);
1105 
1106  /* Clear Z as well: */
1107  if (d->vram_z == NULL) {
1108  d->vram_z = (double*) malloc(sizeof(double) * d->xsize * d->ysize);
1109  }
1110 
1111  uint32_t bgplaneZ = REG(PVRREG_BGPLANE_Z);
1112  struct ieee_float_value backgroundz;
1113  ieee_interpret_float_value(bgplaneZ, &backgroundz, IEEE_FMT_S);
1114  for (int q = 0; q < d->xsize * d->ysize; ++q)
1115  d->vram_z[q] = backgroundz.f;
1116 
1117  // Using names from http://www.ludd.luth.se/~jlo/dc/ta-intro.txt.
1118  for (size_t index = 0; index < d->n_ta_commands; ++index) {
1119  // list points to 8 or 16 words.
1120  uint32_t* list = &d->ta_commands[index * 16];
1121  int cmd = (list[0] >> 29) & 7;
1122 
1123  switch (cmd)
1124  {
1125  case 0: // END_OF_LIST
1126  // Interrupt event already triggered in pvr_ta_command().
1127 #ifdef TA_DEBUG
1128  fatal("\nTA end_of_list (list type %i)\n", d->current_list_type);
1129 #endif
1130  break;
1131 
1132  case 1: // USER_CLIP
1133  // TODO: Ignoring for now.
1134  break;
1135 
1136  case 4: // polygon or modifier volume
1137  {
1138  vertex_index = 0;
1139 
1140  // List Word 0:
1141  listtype = (list[0] >> 24) & 7;
1142  striplength = (list[0] >> 18) & 3;
1143  striplength = striplength == 2 ? 4 : (
1144  striplength == 3 ? 6 : (striplength + 1));
1145  clipmode = (list[0] >> 16) & 3;
1146  modifier = (list[0] >> 7) & 1;
1147  modifier_mode = (list[0] >> 6) & 1;
1148  color_type = (list[0] >> 4) & 3;
1149  texture = list[0] & 8;
1150  specular = list[0] & 4;
1151  shading = list[0] & 2;
1152  uv_format = list[0] & 1;
1153 
1154 #ifdef TA_DEBUG
1155  fatal("\nTA polygon listtype %i, ", listtype);
1156  fatal("striplength %i, ", striplength);
1157  fatal("clipmode %i, ", clipmode);
1158  fatal("modifier %i, ", modifier);
1159  fatal("modifier_mode %i,\n", modifier_mode);
1160  fatal(" color_type %i, ", color_type);
1161  fatal("texture %s, ", texture ? "TRUE" : "false");
1162  fatal("specular %s, ", specular ? "TRUE" : "false");
1163  fatal("shading %s, ", shading ? "TRUE" : "false");
1164  fatal("uv_format %s\n", uv_format ? "TRUE" : "false");
1165 #endif
1166 
1167  // List Word 1:
1168  depthmode = (list[1] >> 29) & 7;
1169  cullingmode = (list[1] >> 27) & 3;
1170  zwrite = ! ((list[1] >> 26) & 1);
1171  texture1 = (list[1] >> 25) & 1;
1172  specular1 = (list[1] >> 24) & 1;
1173  shading1 = (list[1] >> 23) & 1;
1174  uv_format1 = (list[1] >> 22) & 1;
1175  dcalcexact = (list[1] >> 20) & 1;
1176 
1177 #ifdef TA_DEBUG
1178  fatal(" depthmode %i, ", depthmode);
1179  fatal("cullingmode %i, ", cullingmode);
1180  fatal("zwrite %s, ", zwrite ? "TRUE" : "false");
1181  fatal("texture1 %s\n", texture1 ? "TRUE" : "false");
1182  fatal(" specular1 %s, ", specular1 ? "TRUE" : "false");
1183  fatal("shading1 %s, ", shading1 ? "TRUE" : "false");
1184  fatal("uv_format1 %s, ", uv_format1 ? "TRUE" : "false");
1185  fatal("dcalcexact %s\n", dcalcexact ? "TRUE" : "false");
1186 #endif
1187 
1188  if (!zwrite) {
1189  fatal("pvr: no zwrite? not implemented yet.\n");
1190  exit(1);
1191  }
1192 
1193  // For now, trust texture and ignore texture1.
1194  // if (texture != texture1) {
1195  // fatal("pvr: texture != texture1. what to do?\n");
1196  // exit(1);
1197  // }
1198 
1199  // List Word 2:
1200  // TODO: srcblend (31-29)
1201  // TODO: dstblend (28-26)
1202  // TODO: srcmode (25)
1203  // TODO: dstmode (24)
1204  fog = (list[2] >> 22) & 3;
1205  // TODO: clamp (21)
1206  // TODO: alpha (20)
1207  // TODO: texture alpha (19)
1208  // TODO: uv flip (18-17)
1209  // TODO: uv clamp (16-15)
1210  // TODO: filter (14-12)
1211  // TODO: mipmap (11-8)
1212  // TODO: texture shading (7-6)
1213  texture_usize = 8 << ((list[2] >> 3) & 7);
1214  texture_vsize = 8 << (list[2] & 7);
1215 
1216  // List Word 3:
1217  texture_mipmap = (list[3] >> 31) & 1;
1218  texture_vq_compression = (list[3] >> 30) & 1;
1219  texture_pixelformat = (list[3] >> 27) & 7;
1220  texture_twiddled = ! ((list[3] >> 26) & 1);
1221  texture_stride = (list[3] >> 25) & 1;
1222  textureAddr = (list[3] << 3) & 0x7fffff;
1223 
1224 #ifdef TA_DEBUG
1225  fatal(" texture: mipmap %s, ", texture_mipmap ? "TRUE" : "false");
1226  fatal("vq_compression %s, ", texture_vq_compression ? "TRUE" : "false");
1227  fatal("pixelformat %i, ", texture_pixelformat);
1228  fatal("twiddled %s\n", texture_twiddled ? "TRUE" : "false");
1229  fatal(" stride %s, ", texture_stride ? "TRUE" : "false");
1230  fatal("textureAddr 0x%08x\n", textureAddr);
1231 #endif
1232 
1233  if (fog != 2)
1234  fatal("[ pvr: fog type %i not yet implemented ]\n", fog);
1235 
1236  if (texture_vq_compression) {
1237  fatal("pvr: texture_vq_compression not supported yet\n");
1238  // exit(1);
1239  }
1240 
1241  struct ieee_float_value r, g, b;
1242  ieee_interpret_float_value(list[5], &r, IEEE_FMT_S);
1243  ieee_interpret_float_value(list[6], &g, IEEE_FMT_S);
1244  ieee_interpret_float_value(list[7], &b, IEEE_FMT_S);
1245  baseRed = r.f * 255;
1246  baseGreen = g.f * 255;
1247  baseBlue = b.f * 255;
1248  // printf("rgb = %f %f %f\n", r.f, g.f, b.f);
1249  break;
1250  }
1251 
1252  case 7: // vertex
1253  {
1254  // MAJOR TODO:
1255  // How to select which one of the 18 (!) types listed
1256  // in http://www.ludd.luth.se/~jlo/dc/ta-intro.txt to
1257  // use?
1258  if (listtype != 0 && listtype != 2 && listtype != 4)
1259  break;
1260 
1261  bool eos = (list[0] >> 28) & 1;
1262 
1263  struct ieee_float_value fx, fy, fz, u, v, extra1, extra2;
1264  ieee_interpret_float_value(list[1], &fx, IEEE_FMT_S);
1265  ieee_interpret_float_value(list[2], &fy, IEEE_FMT_S);
1266  ieee_interpret_float_value(list[3], &fz, IEEE_FMT_S);
1267  wf_x[vertex_index] = fx.f;
1268  wf_y[vertex_index] = fy.f;
1269  wf_z[vertex_index] = fz.f;
1270 
1271 #ifdef TA_DEBUG
1272  fatal("TA vertex %f %f %f%s\n", fx.f, fy.f, fz.f,
1273  eos ? " end_of_strip" : "");
1274 #endif
1275 
1276  if (texture) {
1277  ieee_interpret_float_value(list[4], &u, IEEE_FMT_S);
1278  ieee_interpret_float_value(list[5], &v, IEEE_FMT_S);
1279  wf_u[vertex_index] = u.f;
1280  wf_v[vertex_index] = v.f;
1281  } else {
1282  if (color_type == 0) {
1283  wf_r[vertex_index] = (list[6] >> 16) & 255;
1284  wf_g[vertex_index] = (list[6] >> 8) & 255;
1285  wf_b[vertex_index] = (list[6]) & 255;
1286  } else if (color_type == 1) {
1287  ieee_interpret_float_value(list[5], &v, IEEE_FMT_S);
1288  ieee_interpret_float_value(list[6], &extra1, IEEE_FMT_S);
1289  ieee_interpret_float_value(list[7], &extra2, IEEE_FMT_S);
1290  wf_r[vertex_index] = v.f * 255;
1291  wf_g[vertex_index] = extra1.f * 255;
1292  wf_b[vertex_index] = extra2.f * 255;
1293  } else if (color_type == 2) {
1294  ieee_interpret_float_value(list[6], &extra1, IEEE_FMT_S);
1295  wf_r[vertex_index] = extra1.f * baseRed;
1296  wf_g[vertex_index] = extra1.f * baseGreen;
1297  wf_b[vertex_index] = extra1.f * baseBlue;
1298  } else {
1299  // "Intensity from previous face". TODO. Red for now.
1300  wf_r[vertex_index] = 255;
1301  wf_g[vertex_index] = 0;
1302  wf_b[vertex_index] = 0;
1303  }
1304  }
1305 
1306  vertex_index ++;
1307 
1308  if (vertex_index >= 3) {
1309  int modulo_mask = REG(PVRREG_TSP_CFG) & TSP_CFG_MODULO_MASK;
1310 
1311  float crossProduct =
1312  ((wf_x[1] - wf_x[0])*(wf_y[2] - wf_y[0])) -
1313  ((wf_y[1] - wf_y[0])*(wf_x[2] - wf_x[0]));
1314 
1315  // Hm. TODO: Instead of flipping back and forth between
1316  // clockwise and counter-clockwise culling, perhaps there
1317  // is some smarter way of assigning the three points
1318  // instead of 012 => 12x...?
1319  bool culled = false;
1320  if (cullingmode == 2) {
1321  if (crossProduct < 0)
1322  culled = true;
1323  cullingmode = 3;
1324  } else if (cullingmode == 3) {
1325  if (crossProduct > 0)
1326  culled = true;
1327  cullingmode = 2;
1328  }
1329 
1330  if (!culled) {
1331  if (texture)
1332  pvr_render_triangle_textured(d,
1333  texture_pixelformat, texture_twiddled, texture_stride ? (32*modulo_mask) : 0,
1334  textureAddr, texture_usize, texture_vsize,
1335  wf_x[0], wf_y[0], wf_z[0], wf_u[0], wf_v[0],
1336  wf_x[1], wf_y[1], wf_z[1], wf_u[1], wf_v[1],
1337  wf_x[2], wf_y[2], wf_z[2], wf_u[2], wf_v[2]);
1338  else
1339  pvr_render_triangle(d,
1340  wf_x[0], wf_y[0], wf_z[0], wf_r[0], wf_g[0], wf_b[0],
1341  wf_x[1], wf_y[1], wf_z[1], wf_r[1], wf_g[1], wf_b[1],
1342  wf_x[2], wf_y[2], wf_z[2], wf_r[2], wf_g[2], wf_b[2]);
1343  }
1344 
1345  if (eos) {
1346  // End of strip.
1347  vertex_index = 0;
1348  } else {
1349  // Not a closing vertex, then move points 1 and 2
1350  // into slots 0 and 1, so that the stripe can continue.
1351  vertex_index = 2;
1352  wf_x[0] = wf_x[1]; wf_y[0] = wf_y[1]; wf_z[0] = wf_z[1];
1353  wf_u[0] = wf_u[1]; wf_v[0] = wf_v[1];
1354  wf_r[0] = wf_r[1]; wf_g[0] = wf_g[1]; wf_b[0] = wf_b[1];
1355 
1356  wf_x[1] = wf_x[2]; wf_y[1] = wf_y[2]; wf_z[1] = wf_z[2];
1357  wf_u[1] = wf_u[2]; wf_v[1] = wf_v[2];
1358  wf_r[1] = wf_r[2]; wf_g[1] = wf_g[2]; wf_b[1] = wf_b[2];
1359  }
1360  }
1361  break;
1362  }
1363 
1364  default:
1365  fatal("pvr_render: unimplemented list cmd %i\n", cmd);
1366  exit(1);
1367  }
1368  }
1369 
1370  pvr_clear_ta_commands(d);
1371 
1372  // TODO: RENDERDONE is 2. How about other events?
1374 }
1375 
1376 
1377 /*
1378  * pvr_reset_ta():
1379  *
1380  * Reset the Tile Accelerator.
1381  */
1382 static void pvr_reset_ta(struct pvr_data *d)
1383 {
1385  pvr_clear_ta_commands(d);
1386 }
1387 
1388 
1389 /*
1390  * pvr_reset():
1391  *
1392  * Reset the PVR.
1393  */
1394 static void pvr_reset(struct pvr_data *d)
1395 {
1396  /* TODO */
1397 }
1398 
1399 
1400 /*
1401  * pvr_ta_init():
1402  *
1403  * Initialize the Tile Accelerator. This makes the TA ready to receive
1404  * commands (via address 0x10000000).
1405  */
1406 void pvr_ta_init(struct cpu *cpu, struct pvr_data *d)
1407 {
1410 }
1411 
1412 
1413 static void pvr_tilebuf_debugdump(struct pvr_data *d)
1414 {
1415  return;
1416 
1417  // According to Marcus Comstedt's "tatest":
1418  // 24 word header (before the TILEBUF_ADDR pointer), followed by
1419  // 6 words for each tile.
1420  uint32_t tilebuf = REG(PVRREG_TILEBUF_ADDR) & PVR_TILEBUF_ADDR_MASK;
1421  uint32_t *p = (uint32_t*) (d->vram + tilebuf);
1422 
1423  fatal("PVR tile buffer debug dump:\n");
1424  p -= 24;
1425  for (int i = 0; i < 24; ++i)
1426  fatal(" %08x", *p++);
1427 
1428  fatal("\n%i x %i tiles:\n", d->tilebuf_xsize, d->tilebuf_ysize);
1429 
1430  for (int x = 0; x < d->tilebuf_xsize; ++x)
1431  {
1432  for (int y = 0; y < d->tilebuf_ysize; ++y)
1433  {
1434  fatal(" Tile %i,%i:", x, y);
1435  for (int i = 0; i < 6; ++i)
1436  fatal(" %08x", *p++);
1437  fatal("\n");
1438  }
1439  }
1440 }
1441 
1442 
1443 /*
1444  * pvr_ta_command():
1445  *
1446  * Someone has written a [complete] 32-byte or 64-byte command to the Tile
1447  * Accelerator memory area. The real hardware probably outputs
1448  * "compiled commands" into the Object list and Object Pointer list.
1449  * For now, just put all the commands in a plain array, and then later execute
1450  * them in pvr_render().
1451  */
1452 static void pvr_ta_command(struct cpu *cpu, struct pvr_data *d, int list_ofs)
1453 {
1454  uint32_t *ta = &d->ta[list_ofs];
1455 
1456 #ifdef TA_DEBUG
1457  /* Dump the Tile Accelerator command for debugging: */
1458  {
1459  int i;
1460  fatal("TA cmd:");
1461  for (i = 0; i < 8; ++i)
1462  fatal(" %08x", (int) ta[i]);
1463  fatal("\n");
1464  }
1465 #endif
1466 
1467  // ob_ofs = REG(PVRREG_TA_OB_POS);
1468  // REG(PVRREG_TA_OB_POS) = ob_ofs + sizeof(uint64_t);
1469 
1470  if (d->ta_commands == NULL) {
1471  d->allocated_ta_commands = 2048;
1472  d->ta_commands = (uint32_t *) malloc(64 * d->allocated_ta_commands);
1473  d->n_ta_commands = 0;
1474  }
1475 
1476  if (d->n_ta_commands + 1 >= d->allocated_ta_commands) {
1477  d->allocated_ta_commands *= 2;
1478  d->ta_commands = (uint32_t *) realloc(d->ta_commands, 64 * d->allocated_ta_commands);
1479  }
1480 
1481  // Hack: I don't understand yet what separates a 32-byte transfer
1482  // vs two individual 32-byte transfers vs a 64-byte transfer.
1483  // TODO: For now, really only support 32-byte transfers... :(
1484  memcpy(d->ta_commands + 16 * d->n_ta_commands, ta, 32);
1485  memset(d->ta_commands + 16 * d->n_ta_commands + 8, 0, 32);
1486  d->n_ta_commands ++;
1487 
1488  // We need to keep track of the current list type though, and respond
1489  // with an event once we reach an end_of_list command. All other
1490  // commands are handled in pvr_render() for now.
1491  int cmd = (ta[0] >> 29) & 7;
1492  if (cmd == 0) {
1493  // cmd 0: end of list
1494  uint32_t opb_cfg = REG(PVRREG_TA_OPB_CFG);
1495 
1496  if (d->current_list_type == 0 && opb_cfg & TA_OPB_CFG_OPAQUEPOLY_MASK)
1498  if (d->current_list_type == 1 && opb_cfg & TA_OPB_CFG_OPAQUEMOD_MASK)
1500  if (d->current_list_type == 2 && opb_cfg & TA_OPB_CFG_TRANSPOLY_MASK)
1502  if (d->current_list_type == 3 && opb_cfg & TA_OPB_CFG_TRANSMOD_MASK)
1504  if (d->current_list_type == 4 && opb_cfg & TA_OPB_CFG_PUNCHTHROUGH_MASK)
1506  } else if (cmd == 4) {
1507  // cmd 4: polygon or modifier volume
1508  d->current_list_type = (ta[0] >> 24) & 7;
1509  }
1510 }
1511 
1512 
1514 {
1515  struct pvr_data *d = (struct pvr_data *) extra;
1516  uint64_t idata = 0, odata = 0;
1517 
1518  if (len != sizeof(uint32_t)) {
1519  fatal("pvr_ta access len = %i: TODO\n", (int) len);
1520  exit(1);
1521  }
1522 
1523  // Tile Accelerator commands can be sent to 0x10000000 through
1524  // 0x107fffff, it seems, but the SH4 store queues only have 64 bytes.
1525  relative_addr &= (sizeof(d->ta) - 1);
1526 
1527  if (writeflag == MEM_WRITE) {
1528  idata = memory_readmax64(cpu, data, len);
1529 #if 0
1530  fatal("[ pvr_ta: WRITE addr=%08x value=%08x ]\n",
1531  (int)relative_addr, (int)idata);
1532 #endif
1533 
1534  /* Write to the tile accelerator command buffer: */
1535  d->ta[relative_addr / sizeof(uint32_t)] = idata;
1536 
1537  // Execute the command, after a complete write.
1538  // (Note: This assumes that commands are written from low
1539  // address to high.)
1540  if (relative_addr == 0x1c)
1541  pvr_ta_command(cpu, d, 0);
1542  if (relative_addr == 0x3c)
1543  pvr_ta_command(cpu, d, 8);
1544  } else {
1545  odata = d->ta[relative_addr / sizeof(uint32_t)];
1546  memory_writemax64(cpu, data, len, odata);
1547 #if 1
1548  fatal("[ pvr_ta: READ addr=%08x value=%08x ]\n", (int)relative_addr, (int)odata);
1549 #endif
1550  }
1551 
1552  return 1;
1553 }
1554 
1555 
1557 {
1558  struct pvr_data *d = (struct pvr_data *) extra;
1559  uint64_t idata = 0, odata = 0;
1560 
1561  if (writeflag == MEM_WRITE)
1562  idata = memory_readmax64(cpu, data, len);
1563 
1564  /* Default read action: Read from reg[]: */
1565  if (writeflag == MEM_READ)
1566  odata = d->reg[relative_addr / sizeof(uint32_t)];
1567 
1568  /* Fog table access: */
1569  if (relative_addr >= PVRREG_FOG_TABLE &&
1570  relative_addr < PVRREG_FOG_TABLE + PVR_FOG_TABLE_SIZE) {
1571  if (writeflag == MEM_WRITE)
1572  DEFAULT_WRITE;
1573  goto return_ok;
1574  }
1575 
1576  /* Palette access: */
1577  if (relative_addr >= PVRREG_PALETTE &&
1578  relative_addr < PVRREG_PALETTE + PVR_PALETTE_SIZE) {
1579  if (writeflag == MEM_WRITE)
1580  DEFAULT_WRITE;
1581  goto return_ok;
1582  }
1583 
1584  switch (relative_addr) {
1585 
1586  case PVRREG_ID:
1587  /* ID for Set 5.xx versions of the Dreamcast, according
1588  to http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt: */
1589  odata = 0x17fd11db;
1590  break;
1591 
1592  case PVRREG_REVISION:
1593  /* Revision 1.1, for Dreamcast Set 5.2x. */
1594  odata = 0x00000011;
1595  break;
1596 
1597  case PVRREG_RESET:
1598  if (writeflag == MEM_WRITE) {
1599  if (idata != 0) {
1600  debug("[ pvr: RESET ");
1601  if (idata & PVR_RESET_PVR)
1602  pvr_reset(d);
1603  if (idata & PVR_RESET_TA)
1604  pvr_reset_ta(d);
1605  debug("]\n");
1606  }
1607  idata = 0;
1608  DEFAULT_WRITE;
1609  }
1610  break;
1611 
1612  case PVRREG_STARTRENDER:
1613  if (writeflag == MEM_WRITE) {
1614  debug("[ pvr: STARTRENDER ]\n");
1615  pvr_render(cpu, d);
1616  } else {
1617  fatal("[ pvr: huh? read from STARTRENDER ]\n");
1618  exit(1);
1619  }
1620  break;
1621 
1622  case PVRREG_OB_ADDR:
1623  if (writeflag == MEM_WRITE) {
1624  debug("[ pvr: OB_ADDR set to 0x%08" PRIx32" ]\n",
1625  (uint32_t)(idata & PVR_OB_ADDR_MASK));
1626  if (idata & ~PVR_OB_ADDR_MASK) {
1627  fatal("[ pvr: OB_ADDR: Fatal error: Unknown"
1628  " bits set: 0x%08" PRIx32" ]\n",
1629  (uint32_t)(idata & ~PVR_OB_ADDR_MASK));
1630  exit(1);
1631  }
1632  idata &= PVR_OB_ADDR_MASK;
1633  DEFAULT_WRITE;
1634  }
1635  break;
1636 
1637  case PVRREG_TILEBUF_ADDR:
1638  if (writeflag == MEM_WRITE) {
1639  debug("[ pvr: TILEBUF_ADDR set to 0x%08" PRIx32" ]\n",
1640  (uint32_t)(idata & PVR_TILEBUF_ADDR_MASK));
1641  if (idata & ~PVR_TILEBUF_ADDR_MASK) {
1642  fatal("[ pvr: TILEBUF_ADDR: Unknown"
1643  " bits set: 0x%08" PRIx32" ]\n",
1644  (uint32_t)(idata & ~PVR_TILEBUF_ADDR_MASK));
1645  exit(1);
1646  }
1647  idata &= PVR_TILEBUF_ADDR_MASK;
1648  DEFAULT_WRITE;
1649  pvr_tilebuf_debugdump(d);
1650  }
1651  break;
1652 
1653  case PVRREG_SPANSORT:
1654  if (writeflag == MEM_WRITE) {
1655  debug("[ pvr: SPANSORT: ");
1656  if (idata & PVR_SPANSORT_SPAN0)
1657  debug("SPAN0 ");
1658  if (idata & PVR_SPANSORT_SPAN1)
1659  debug("SPAN1 ");
1660  if (idata & PVR_SPANSORT_TSP_CACHE_ENABLE)
1661  debug("TSP_CACHE_ENABLE ");
1662  debug("]\n");
1663  DEFAULT_WRITE;
1664  }
1665  break;
1666 
1667  case PVRREG_BRDCOLR:
1668  if (writeflag == MEM_WRITE) {
1669  debug("[ pvr: BRDCOLR set to 0x%06" PRIx32" ]\n",
1670  (int)idata);
1671  DEFAULT_WRITE;
1672  d->border_updated = 1;
1673  }
1674  break;
1675 
1676  case PVRREG_DIWMODE:
1677  if (writeflag == MEM_WRITE) {
1678  d->clock_double = idata & DIWMODE_C_MASK? 1:0;
1679  d->strip_buffer_enabled = idata & DIWMODE_SE_MASK? 1:0;
1680  d->strip_length = (idata & DIWMODE_SL_MASK)
1681  >> DIWMODE_SL_SHIFT;
1682  d->argb8888_threshold = (idata & DIWMODE_TH_MASK)
1683  >> DIWMODE_TH_SHIFT;
1684  d->extend = (idata & DIWMODE_EX_MASK)
1685  >> DIWMODE_EX_SHIFT;
1686  d->pixelmode = (idata & DIWMODE_COL_MASK)
1687  >> DIWMODE_COL_SHIFT;
1688  d->line_double = idata & DIWMODE_SD_MASK? 1:0;
1689  d->display_enabled = idata & DIWMODE_DE_MASK? 1:0;
1690 
1691  debug("[ pvr: DIWMODE set to: ");
1692  debug("clock_double=%i, ", d->clock_double);
1693  debug("strip_buffer_enabled=%i, ",
1695  debug("strip_length=%i, ", d->strip_length);
1696  debug("argb8888_threshold=%i, ", d->argb8888_threshold);
1697  debug("extend=0x%x, ", d->extend);
1698  debug("pixelmode=");
1699  switch (d->pixelmode) {
1700  case 0: debug("RGB0555 (16-bit)"); break;
1701  case 1: debug("RGB565 (16-bit)"); break;
1702  case 2: debug("RGB888 (24-bit)"); break;
1703  case 3: debug("RGB0888 (32-bit)"); break;
1704  }
1705  debug(", line_double=%i, ", d->line_double);
1706  debug("display_enabled=%i", d->display_enabled);
1707  debug(" ]\n");
1708 
1709  DEFAULT_WRITE;
1711  pvr_fb_invalidate(d, -1, -1);
1712  }
1713  break;
1714 
1715  case PVRREG_DIWSIZE:
1716  if (writeflag == MEM_WRITE) {
1717  debug("[ pvr: DIWSIZE set to modulo=%i, "
1718  "width=%i, height=%i ]\n", (int)
1719  ((idata >> DIWSIZE_MODULO_SHIFT) & DIWSIZE_MASK),
1720  (int)((idata >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK),
1721  (int)((idata >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK));
1722  DEFAULT_WRITE;
1724  pvr_fb_invalidate(d, -1, -1);
1725  }
1726  break;
1727 
1729  if (writeflag == MEM_WRITE) {
1730  debug("[ pvr: FB_RENDER_ADDR1 set to 0x%08" PRIx32
1731  " ]\n", (int) idata);
1732  DEFAULT_WRITE;
1733  }
1734  break;
1735 
1737  if (writeflag == MEM_WRITE) {
1738  debug("[ pvr: FB_RENDER_ADDR2 set to 0x%08" PRIx32
1739  " ]\n", (int) idata);
1740  DEFAULT_WRITE;
1741  }
1742  break;
1743 
1744  case PVRREG_FB_CLIP_X:
1745  if (writeflag == MEM_WRITE) {
1746  debug("[ pvr: FB_CLIP_X set to min=%i, "
1747  "max=%i ]\n", (int) (idata & FB_CLIP_XY_MIN_MASK),
1748  (int) ((idata & FB_CLIP_XY_MAX_MASK)
1749  >> FB_CLIP_XY_MAX_SHIFT));
1750  DEFAULT_WRITE;
1752  pvr_fb_invalidate(d, -1, -1);
1753  }
1754  break;
1755 
1756  case PVRREG_FB_CLIP_Y:
1757  if (writeflag == MEM_WRITE) {
1758  debug("[ pvr: FB_CLIP_Y set to min=%i, "
1759  "max=%i ]\n", (int) (idata & FB_CLIP_XY_MIN_MASK),
1760  (int) ((idata & FB_CLIP_XY_MAX_MASK)
1761  >> FB_CLIP_XY_MAX_SHIFT));
1762  DEFAULT_WRITE;
1764  pvr_fb_invalidate(d, -1, -1);
1765  }
1766  break;
1767 
1768  case PVRREG_SHADOW:
1769  if (writeflag == MEM_WRITE) {
1770  debug("[ pvr: SHADOW set to enable=%i, "
1771  "intensity=%i ]\n",
1772  (int) (idata & SHADOW_ENABLE? 1 : 0),
1773  (int) (idata & SHADOW_INTENSITY_MASK));
1774  DEFAULT_WRITE;
1776  pvr_fb_invalidate(d, -1, -1);
1777  }
1778  break;
1779 
1780  case PVRREG_OBJECT_CLIP:
1781  if (writeflag == MEM_WRITE) {
1782  debug("[ pvr: OBJECT_CLIP 0x%08x ]\n", (int)idata);
1783  DEFAULT_WRITE;
1784  }
1785  break;
1786 
1787  case PVRREG_OB_CFG:
1788  if (writeflag == MEM_WRITE) {
1789  debug("[ pvr: OB_CFG 0x%08x ]\n", (int)idata);
1790  DEFAULT_WRITE;
1791  }
1792  break;
1793 
1794  case PVRREG_UNKNOWN_80:
1795  if (writeflag == MEM_WRITE) {
1796  debug("[ pvr: UNKNOWN_80 0x%08x ]\n", (int)idata);
1797  DEFAULT_WRITE;
1798  }
1799  break;
1800 
1801  case PVRREG_UNKNOWN_84:
1802  if (writeflag == MEM_WRITE) {
1803  debug("[ pvr: UNKNOWN_84 0x%08x ]\n", (int)idata);
1804  DEFAULT_WRITE;
1805  }
1806  break;
1807 
1808  case PVRREG_BGPLANE_Z:
1809  if (writeflag == MEM_WRITE) {
1810  debug("[ pvr: BGPLANE_Z 0x%08x ]\n", (int)idata);
1811  DEFAULT_WRITE;
1812  }
1813  break;
1814 
1815  case PVRREG_BGPLANE_CFG:
1816  if (writeflag == MEM_WRITE) {
1817  debug("[ pvr: BGPLANE_CFG 0x%08x ]\n", (int)idata);
1818  DEFAULT_WRITE;
1819  }
1820  break;
1821 
1822  case PVRREG_ISP_CFG:
1823  if (writeflag == MEM_WRITE) {
1824  debug("[ pvr: ISP_CFG 0x%08x ]\n", (int)idata);
1825  DEFAULT_WRITE;
1826  }
1827  break;
1828 
1829  case PVRREG_VRAM_CFG1:
1830  if (writeflag == MEM_WRITE) {
1831  debug("[ pvr: VRAM_CFG1 set to 0x%08" PRIx32,
1832  (int) idata);
1833  if (idata != VRAM_CFG1_GOOD_REFRESH_VALUE)
1834  fatal("{ VRAM_CFG1 = 0x%08" PRIx32" is not "
1835  "yet implemented! }", (int) idata);
1836  debug(" ]\n");
1837  DEFAULT_WRITE;
1838  }
1839  break;
1840 
1841  case PVRREG_VRAM_CFG2:
1842  if (writeflag == MEM_WRITE) {
1843  debug("[ pvr: VRAM_CFG2 set to 0x%08" PRIx32,
1844  (int) idata);
1845  if (idata != VRAM_CFG2_UNKNOWN_MAGIC)
1846  fatal("{ VRAM_CFG2 = 0x%08" PRIx32" is not "
1847  "yet implemented! }", (int) idata);
1848  debug(" ]\n");
1849  DEFAULT_WRITE;
1850  }
1851  break;
1852 
1853  case PVRREG_VRAM_CFG3:
1854  if (writeflag == MEM_WRITE) {
1855  debug("[ pvr: VRAM_CFG3 set to 0x%08" PRIx32,
1856  (int) idata);
1857  if (idata != VRAM_CFG3_UNKNOWN_MAGIC)
1858  fatal("{ VRAM_CFG3 = 0x%08" PRIx32" is not "
1859  "yet implemented! }", (int) idata);
1860  debug(" ]\n");
1861  DEFAULT_WRITE;
1862  }
1863  break;
1864 
1865  case PVRREG_FOG_TABLE_COL:
1866  // e.g. 0x007f7f7f
1867  if (writeflag == MEM_WRITE) {
1868  debug("[ pvr: FOG_TABLE_COL set to 0x%06" PRIx32" ]\n",
1869  (int) idata);
1870  DEFAULT_WRITE;
1871  }
1872  break;
1873 
1874  case PVRREG_FOG_VERTEX_COL:
1875  // e.g. 0x007f7f7f
1876  if (writeflag == MEM_WRITE) {
1877  debug("[ pvr: FOG_VERTEX_COL set to 0x%06" PRIx32" ]\n",
1878  (int) idata);
1879  DEFAULT_WRITE;
1880  }
1881  break;
1882 
1883  case PVRREG_FOG_DENSITY:
1884  // e.g. 0x0000ff07
1885  if (writeflag == MEM_WRITE) {
1886  debug("[ pvr: FOG_DENSITY set to 0x%08" PRIx32" ]\n",
1887  (int) idata);
1888  DEFAULT_WRITE;
1889  }
1890  break;
1891 
1892  case PVRREG_CLAMP_MAX:
1893  // e.g. 0xffffffff
1894  if (writeflag == MEM_WRITE) {
1895  debug("[ pvr: CLAMP_MAX set to 0x%06" PRIx32" ]\n",
1896  (int) idata);
1897  DEFAULT_WRITE;
1898  }
1899  break;
1900 
1901  case PVRREG_CLAMP_MIN:
1902  // e.g. 0x00000000
1903  if (writeflag == MEM_WRITE) {
1904  debug("[ pvr: CLAMP_MIN set to 0x%06" PRIx32" ]\n",
1905  (int) idata);
1906  DEFAULT_WRITE;
1907  }
1908  break;
1909 
1910  case PVRREG_FB_RENDER_CFG:
1911  if (writeflag == MEM_WRITE) {
1912  debug("[ pvr: PVRREG_FB_RENDER_CFG set to 0x%08x ]\n",
1913  (int) idata);
1914  /* TODO */
1915  DEFAULT_WRITE;
1916  }
1917  break;
1918 
1920  if (writeflag == MEM_WRITE) {
1921  debug("[ pvr: PVRREG_FB_RENDER_MODULO set to %i ]\n",
1922  (int) idata);
1923  /* TODO */
1924  DEFAULT_WRITE;
1925  }
1926  break;
1927 
1928  case PVRREG_DIWADDRL:
1929  if (writeflag == MEM_WRITE) {
1930  debug("[ pvr: DIWADDRL set to 0x%08" PRIx32" ]\n",
1931  (int) idata);
1932  pvr_fb_invalidate(d, -1, -1);
1933  DEFAULT_WRITE;
1934  }
1935  break;
1936 
1937  case PVRREG_DIWADDRS:
1938  if (writeflag == MEM_WRITE) {
1939  debug("[ pvr: DIWADDRS set to 0x%08" PRIx32" ]\n",
1940  (int) idata);
1941  pvr_fb_invalidate(d, -1, -1);
1942  DEFAULT_WRITE;
1943  }
1944  break;
1945 
1946  case PVRREG_HPOS_IRQ:
1947  DEFAULT_WRITE;
1948  break;
1949 
1950  case PVRREG_RASEVTPOS:
1951  if (writeflag == MEM_WRITE) {
1952  debug("[ pvr: RASEVTPOS pos1=%i pos2=%i ]\n",
1953  (int)((idata & RASEVTPOS_POS1_MASK)
1955  (int)(idata & RASEVTPOS_POS2_MASK));
1956  DEFAULT_WRITE;
1957  }
1958  break;
1959 
1960  case PVRREG_SYNCCONF:
1961  if (writeflag == MEM_WRITE) {
1962  d->video_enabled = idata & SYNCCONF_VO_MASK? 1:0;
1963  d->broadcast_standard = (idata & SYNCCONF_BC_MASK)
1964  >> SYNCCONF_BC_SHIFT;
1965  d->interlaced = idata & SYNCCONF_I_MASK? 1:0;
1966  d->h_sync_positive = idata & SYNCCONF_HP_MASK? 1:0;
1967  d->v_sync_positive = idata & SYNCCONF_VP_MASK? 1:0;
1968 
1969  debug("[ pvr: SYNCCONF set to: ");
1970  debug("video_enabled=%i, ", d->video_enabled);
1971  switch (d->broadcast_standard) {
1972  case SYNCCONF_BC_VGA: debug("VGA"); break;
1973  case SYNCCONF_BC_NTSC: debug("NTSC"); break;
1974  case SYNCCONF_BC_PAL: debug("PAL"); break;
1975  default: debug("*UNKNOWN*"); break;
1976  }
1977  debug(", interlaced=%i, ", d->interlaced);
1978  debug("hsync=%i, ", d->h_sync_positive);
1979  debug("vsync=%i ]\n", d->v_sync_positive);
1980 
1981  DEFAULT_WRITE;
1983  pvr_fb_invalidate(d, -1, -1);
1984  }
1985  break;
1986 
1987  case PVRREG_BRDHORZ:
1988  if (writeflag == MEM_WRITE) {
1989  debug("[ pvr: BRDHORZ start=%i stop=%i ]\n",
1990  (int)((idata & BRDHORZ_START_MASK)
1991  >> BRDHORZ_START_SHIFT),
1992  (int)(idata & BRDHORZ_STOP_MASK));
1993  DEFAULT_WRITE;
1994  }
1995  break;
1996 
1997  case PVRREG_SYNCSIZE:
1998  if (writeflag == MEM_WRITE) {
1999  debug("[ pvr: SYNCSIZE v=%i h=%i ]\n",
2000  (int)((idata & SYNCSIZE_V_MASK)
2001  >> SYNCSIZE_V_SHIFT),
2002  (int)(idata & SYNCSIZE_H_MASK));
2003  DEFAULT_WRITE;
2004  }
2005  break;
2006 
2007  case PVRREG_BRDVERT:
2008  if (writeflag == MEM_WRITE) {
2009  debug("[ pvr: BRDVERT start=%i stop=%i ]\n",
2010  (int)((idata & BRDVERT_START_MASK)
2011  >> BRDVERT_START_SHIFT),
2012  (int)(idata & BRDVERT_STOP_MASK));
2013  DEFAULT_WRITE;
2014  }
2015  break;
2016 
2017  case PVRREG_SYNCH_WIDTH:
2018  if (writeflag == MEM_WRITE) {
2019  debug("[ pvr: SYNCH_WIDTH 0x%08x ]\n", (int)idata);
2020  DEFAULT_WRITE;
2021  }
2022  break;
2023 
2024  case PVRREG_TSP_CFG:
2025  if (writeflag == MEM_WRITE) {
2026  debug("[ pvr: TSP_CFG 0x%08x ]\n", (int)idata);
2027  DEFAULT_WRITE;
2028  }
2029  break;
2030 
2031  case PVRREG_DIWCONF:
2032  if (writeflag == MEM_WRITE) {
2033  if ((idata & DIWCONF_MAGIC_MASK) !=
2034  DIWCONF_MAGIC && (idata & DIWCONF_MAGIC_MASK)
2035  != 0) {
2036  fatal("PVRREG_DIWCONF magic not set to "
2037  "Magic value. 0x%08x\n", (int)idata);
2038  exit(1);
2039  }
2040  if (idata & DIWCONF_BLANK)
2041  debug("[ pvr: PVRREG_DIWCONF: BLANK: TODO ]\n");
2042 
2043  DEFAULT_WRITE;
2045  }
2046  break;
2047 
2048  case PVRREG_DIWHSTRT:
2049  if (writeflag == MEM_WRITE) {
2050  int v = idata & DIWVSTRT_HPOS_MASK;
2051  debug("[ pvr: DIWHSTRT hpos=%i (%s) ]\n",
2052  v, v == 174? "PAL" :
2053  (v == 164? "NTSC" :
2054  (v == 144? "VGA" : "unknown!")));
2055  DEFAULT_WRITE;
2056  }
2057  break;
2058 
2059  case PVRREG_DIWVSTRT:
2060  if (writeflag == MEM_WRITE) {
2061  debug("[ pvr: DIWVSTRT v2=%i v1=%i ]\n",
2062  (int)((idata & DIWVSTRT_V2_MASK)
2063  >> DIWVSTRT_V2_SHIFT),
2064  (int)(idata & DIWVSTRT_V1_MASK));
2065  DEFAULT_WRITE;
2066  }
2067  break;
2068 
2069  case PVRREG_SCALER_CFG:
2070  if (writeflag == MEM_WRITE) {
2071  debug("[ pvr: SCALER_CFG 0x%08x ]\n", (int)idata);
2072  DEFAULT_WRITE;
2073  }
2074  break;
2075 
2076  case PVRREG_PALETTE_CFG:
2077  if (writeflag == MEM_WRITE) {
2078  debug("[ pvr: PALETTE_CFG 0x%08x ]\n", (int)idata);
2079  DEFAULT_WRITE;
2080  }
2081  break;
2082 
2083  case PVRREG_SYNC_STAT:
2084  /* TODO. Ugly hack, but it works: */
2085  odata = random();
2086  break;
2087 
2088  case PVRREG_MAGIC_110:
2089  if (writeflag == MEM_WRITE) {
2090  debug("[ pvr: MAGIC_110 set to 0x%08" PRIx32,
2091  (int) idata);
2092  if (idata != MAGIC_110_VALUE)
2093  fatal("{ MAGIC_110 = 0x%08" PRIx32" is not "
2094  "yet implemented! }", (int) idata);
2095  debug(" ]\n");
2096  DEFAULT_WRITE;
2097  }
2098  break;
2099 
2100  case PVRREG_TA_LUMINANCE:
2101  if (writeflag == MEM_WRITE) {
2102  debug("[ pvr: TA_LUMINANCE set to 0x%08" PRIx32" ]\n",
2103  (int) idata);
2104  DEFAULT_WRITE;
2105  }
2106  break;
2107 
2108  case PVRREG_TA_OPB_START:
2109  if (writeflag == MEM_WRITE) {
2110  if (idata & ~TA_OPB_START_MASK) {
2111  fatal("[ pvr: UNEXPECTED bits in "
2112  "TA_OPB_START: 0x%08x ]\n", (int)idata);
2113  exit(1);
2114  }
2115  idata &= TA_OPB_START_MASK;
2116  debug("[ pvr: TA_OPB_START set to 0x%x ]\n",
2117  (int) idata);
2118  DEFAULT_WRITE;
2119  }
2120  break;
2121 
2122  case PVRREG_TA_OB_START:
2123  if (writeflag == MEM_WRITE) {
2124  if (idata & ~TA_OB_START_MASK) {
2125  fatal("[ pvr: UNEXPECTED bits in "
2126  "TA_OB_START: 0x%08x ]\n", (int)idata);
2127  exit(1);
2128  }
2129  idata &= TA_OB_START_MASK;
2130  debug("[ pvr: TA_OB_START set to 0x%x ]\n",
2131  (int) idata);
2132  DEFAULT_WRITE;
2133  }
2134  break;
2135 
2136  case PVRREG_TA_OPB_END:
2137  if (writeflag == MEM_WRITE) {
2138  idata &= TA_OPB_END_MASK;
2139  debug("[ pvr: TA_OPB_END set to 0x%x ]\n",
2140  (int) idata);
2141  DEFAULT_WRITE;
2142  }
2143  break;
2144 
2145  case PVRREG_TA_OB_END:
2146  if (writeflag == MEM_WRITE) {
2147  idata &= TA_OB_END_MASK;
2148  debug("[ pvr: TA_OB_END set to 0x%x ]\n",
2149  (int) idata);
2150  DEFAULT_WRITE;
2151  }
2152  break;
2153 
2154  case PVRREG_TA_OPB_POS:
2155  if (writeflag == MEM_WRITE) {
2156  idata &= TA_OPB_POS_MASK;
2157  debug("[ pvr: TA_OPB_POS set to 0x%x ]\n",
2158  (int) idata);
2159  DEFAULT_WRITE;
2160  }
2161  break;
2162 
2163  case PVRREG_TA_OB_POS:
2164  if (writeflag == MEM_WRITE) {
2165  idata &= TA_OB_POS_MASK;
2166  debug("[ pvr: TA_OB_POS set to 0x%x ]\n",
2167  (int) idata);
2168  DEFAULT_WRITE;
2169  }
2170  break;
2171 
2172  case PVRREG_TA_OPL_INIT:
2173  if (writeflag == MEM_WRITE) {
2174  idata &= PVR_TA_OPL_INIT_MASK;
2175  debug("[ pvr: TA_OPL_INIT set to 0x%x ]\n",
2176  (int) idata);
2177  DEFAULT_WRITE;
2178  }
2179  break;
2180 
2181  case PVRREG_TILEBUF_SIZE:
2182  if (writeflag == MEM_WRITE) {
2186  d->tilebuf_xsize ++; d->tilebuf_ysize ++;
2187  debug("[ pvr: TILEBUF_SIZE set to %i x %i ]\n",
2188  d->tilebuf_xsize, d->tilebuf_ysize);
2189  DEFAULT_WRITE;
2190  }
2191  break;
2192 
2193  case PVRREG_TA_OPB_CFG:
2194  if (writeflag == MEM_WRITE) {
2195  debug("[ pvr: TA_OPB_CFG set to 0x%x ]\n",
2196  (int) idata);
2197  DEFAULT_WRITE;
2198  }
2199  break;
2200 
2201  case PVRREG_TA_INIT:
2202  if (writeflag == MEM_WRITE) {
2203  debug("[ pvr: TA_INIT ]\n");
2204 
2205  if (idata & PVR_TA_INIT)
2206  pvr_ta_init(cpu, d);
2207 
2208  if (idata != PVR_TA_INIT && idata != 0)
2209  fatal("{ TA_INIT = 0x%08" PRIx32" is not "
2210  "yet implemented! }", (int) idata);
2211 
2212  /* Always reset to 0. */
2213  idata = 0;
2214  DEFAULT_WRITE;
2215  }
2216  break;
2217 
2218  case PVRREG_YUV_STAT:
2219  // TODO. The "luftvarg" demo accesses this register.
2220  break;
2221 
2222  default:if (writeflag == MEM_READ) {
2223  fatal("[ pvr: read from UNIMPLEMENTED addr 0x%x ]\n",
2224  (int)relative_addr);
2225  } else {
2226  fatal("[ pvr: write to UNIMPLEMENTED addr 0x%x: 0x%x"
2227  " ]\n", (int)relative_addr, (int)idata);
2228  DEFAULT_WRITE;
2229  }
2230 
2231  exit(1);
2232  }
2233 
2234 return_ok:
2235  if (writeflag == MEM_READ)
2236  memory_writemax64(cpu, data, len, odata);
2237 
2238  return 1;
2239 }
2240 
2241 
2242 void pvr_extend_update_region(struct pvr_data *d, uint64_t low, uint64_t high)
2243 {
2244  int vram_ofs = REG(PVRREG_DIWADDRL);
2245  int bytes_per_line = d->xsize * d->bytes_per_pixel;
2246 
2247  low -= vram_ofs;
2248  high -= vram_ofs;
2249 
2250  /* Access inside visible part of VRAM? */
2251  if ((int64_t)high >= 0 && (int64_t)low <
2252  bytes_per_line * d->ysize) {
2253  int new_y1, new_y2;
2254 
2255  d->fb_update_x1 = 0;
2256  d->fb_update_x2 = d->xsize - 1;
2257 
2258  /* Calculate which line the low and high addresses
2259  correspond to: */
2260  new_y1 = low / bytes_per_line;
2261  new_y2 = high / bytes_per_line + 1;
2262 
2263  if (d->fb_update_y1 < 0 || new_y1 < d->fb_update_y1)
2264  d->fb_update_y1 = new_y1;
2265  if (d->fb_update_y2 < 0 || new_y2 > d->fb_update_y2)
2266  d->fb_update_y2 = new_y2;
2267 
2268  if (d->fb_update_y1 < 0)
2269  d->fb_update_y1 = 0;
2270  if (d->fb_update_y2 >= d->ysize)
2271  d->fb_update_y2 = d->ysize - 1;
2272  }
2273 }
2274 
2275 
2277 {
2278  struct pvr_data *d = (struct pvr_data *) extra;
2279  uint64_t high, low = (uint64_t)(int64_t) -1;
2280  int vram_ofs = REG(PVRREG_DIWADDRL), pixels_to_copy;
2281  int bytes_per_line = d->xsize * d->bytes_per_pixel;
2282  int fb_ofs, p;
2283  uint8_t *fb = (uint8_t *) d->fb->framebuffer;
2284  uint8_t *vram = (uint8_t *) d->vram;
2285 
2286 
2287  /*
2288  * Vertical retrace interrupts:
2289  *
2290  * TODO: Maybe it would be even more realistic to have the timer run
2291  * at, say, 60*4 = 240 Hz, and have the following events:
2292  *
2293  * (tick & 3) == 0 SYSASIC_EVENT_VBLINT
2294  * (tick & 3) == 1 SYSASIC_EVENT_PVR_SCANINT1
2295  * (tick & 3) == 2 nothing
2296  * (tick & 3) == 3 SYSASIC_EVENT_PVR_SCANINT2
2297  */
2298  if (d->vblank_interrupts_pending > 0) {
2300 
2303 
2304  // Is this needed?
2306 
2307  /* TODO: For now, I don't care about missed interrupts: */
2309  }
2310 
2311 
2312  /*
2313  * Framebuffer update:
2314  */
2315 
2316  /* Border changed? */
2317  if (d->border_updated) {
2318  /* Fill border with border color: */
2319  int rgb = REG(PVRREG_BRDCOLR), addr = 0;
2320  int x, y, b = rgb & 0xff, g = (rgb >> 8) & 0xff, r = rgb >> 16;
2321  int skiplen = (d->fb->xsize-2*PVR_MARGIN) * d->fb->bit_depth/8;
2322 
2323  for (y=0; y<d->fb->ysize; y++) {
2324  int xskip = y < PVR_MARGIN || y >=
2325  d->fb->ysize - PVR_MARGIN? -1 : PVR_MARGIN;
2326  for (x=0; x<d->fb->xsize; x++) {
2327  if (x == xskip) {
2328  x = d->fb->xsize - PVR_MARGIN;
2329  addr += skiplen;
2330  }
2331  fb[addr] = r;
2332  fb[addr+1] = g;
2333  fb[addr+2] = b;
2334  addr += 3;
2335  }
2336  }
2337 
2338  /* Full redraw of the framebuffer: */
2339  d->fb->update_x1 = 0; d->fb->update_x2 = d->fb->xsize - 1;
2340  d->fb->update_y1 = 0; d->fb->update_y2 = d->fb->ysize - 1;
2341  }
2342 
2343  memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high);
2344  if ((int64_t)low != -1)
2345  pvr_extend_update_region(d, low, high);
2346 
2347  if (d->fb_update_x1 == -1)
2348  return;
2349 
2350  /* Copy (part of) the VRAM to the framebuffer: */
2351  if (d->fb_update_x2 >= d->xsize)
2352  d->fb_update_x2 = d->xsize - 1;
2353  if (d->fb_update_y2 >= d->ysize)
2354  d->fb_update_y2 = d->ysize - 1;
2355 
2356  vram_ofs += d->fb_update_y1 * bytes_per_line;
2357  vram_ofs += d->fb_update_x1 * d->bytes_per_pixel;
2358  pixels_to_copy = (d->fb_update_x2 - d->fb_update_x1 + 1);
2359  fb_ofs = (d->fb_update_y1 + PVR_MARGIN) * d->fb->bytes_per_line;
2360  fb_ofs += (d->fb_update_x1 + PVR_MARGIN) * d->fb->bit_depth / 8;
2361 
2362  /* Copy the actual pixels: (Four manually inlined, for speed.) */
2363 
2364  switch (d->pixelmode) {
2365  case 0: /* RGB0555 (16-bit) */
2366  {
2367  int y;
2368  for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
2369  int fo = fb_ofs, vo = vram_ofs;
2370  for (p=0; p<pixels_to_copy; p++) {
2371  /* 0rrrrrgg(high) gggbbbbb(low) */
2372  fb[fo] = (vram[(vo+1)%VRAM_SIZE] << 1) & 0xf8;
2373  fb[fo+1] = ((vram[vo%VRAM_SIZE] >> 2) & 0x38) +
2374  (vram[(vo+1)%VRAM_SIZE] << 6);
2375  fb[fo+2] = (vram[vo%VRAM_SIZE] & 0x1f) << 3;
2376  fo += 3; vo += 2;
2377  }
2378 
2379  vram_ofs += bytes_per_line;
2380  fb_ofs += d->fb->bytes_per_line;
2381  }
2382  }
2383  break;
2384 
2385  case 1: /* RGB565 (16-bit) */
2386  {
2387  int y;
2388  for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
2389  int fo = fb_ofs, vo = vram_ofs;
2390  for (p=0; p<pixels_to_copy; p++) {
2391  /* rrrrrggg(high) gggbbbbb(low) */
2392  fb[fo] = vram[(vo+1)%VRAM_SIZE] & 0xf8;
2393  fb[fo+1] = ((vram[vo%VRAM_SIZE] >> 3) & 0x1c) +
2394  (vram[(vo+1)%VRAM_SIZE] << 5);
2395  fb[fo+2] = (vram[vo%VRAM_SIZE] & 0x1f) << 3;
2396  fo += 3; vo += 2;
2397  }
2398 
2399  vram_ofs += bytes_per_line;
2400  fb_ofs += d->fb->bytes_per_line;
2401  }
2402  }
2403  break;
2404 
2405  case 2: /* RGB888 (24-bit) */
2406  {
2407  int y;
2408  for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
2409  /* TODO: Reverse colors, like in the 32-bit case? */
2410  memcpy(fb+fb_ofs, vram+(vram_ofs%VRAM_SIZE), 3*pixels_to_copy);
2411  vram_ofs += bytes_per_line;
2412  fb_ofs += d->fb->bytes_per_line;
2413  }
2414  }
2415  break;
2416 
2417  case 3: /* RGB0888 (32-bit) */
2418  {
2419  int y;
2420  for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
2421  int fo = fb_ofs, vo = vram_ofs;
2422  for (p=0; p<pixels_to_copy; p++) {
2423  fb[fo] = vram[(vo+2)%VRAM_SIZE];
2424  fb[fo+1] = vram[(vo+1)%VRAM_SIZE];
2425  fb[fo+2] = vram[(vo+0)%VRAM_SIZE];
2426  fo += 3; vo += 4;
2427  }
2428 
2429  vram_ofs += bytes_per_line;
2430  fb_ofs += d->fb->bytes_per_line;
2431  }
2432  }
2433  break;
2434  }
2435 
2436  /*
2437  * Extend the real framebuffer to encompass the area
2438  * just written to:
2439  */
2440 
2441  /* Offset to take the margin into account first... */
2444 
2445  if (d->fb_update_x1 < d->fb->update_x1 || d->fb->update_x1 < 0)
2446  d->fb->update_x1 = d->fb_update_x1;
2447  if (d->fb_update_x2 > d->fb->update_x2 || d->fb->update_x2 < 0)
2448  d->fb->update_x2 = d->fb_update_x2;
2449  if (d->fb_update_y1 < d->fb->update_y1 || d->fb->update_y1 < 0)
2450  d->fb->update_y1 = d->fb_update_y1;
2451  if (d->fb_update_y2 > d->fb->update_y2 || d->fb->update_y2 < 0)
2452  d->fb->update_y2 = d->fb_update_y2;
2453 
2454  /* Clear the PVR's update region: */
2455  d->fb_update_x1 = d->fb_update_x2 =
2456  d->fb_update_y1 = d->fb_update_y2 = -1;
2457 }
2458 
2459 
2460 DEVICE_ACCESS(pvr_vram_alt)
2461 {
2462  struct pvr_data_alt *d_alt = (struct pvr_data_alt *) extra;
2463  struct pvr_data *d = d_alt->d;
2464  size_t i;
2465 
2466  if (writeflag == MEM_READ) {
2467  /* Copy from real vram: */
2468  for (i=0; i<len; i++) {
2469  int addr = relative_addr + i;
2470  addr = ((addr & 4) << 20) | (addr & 3)
2471  | ((addr & 0x7ffff8) >> 1);
2472  data[i] = d->vram[addr % VRAM_SIZE];
2473  }
2474  return 1;
2475  }
2476 
2477  // Writes are only allowed as 16-bit access or higher.
2478  if (len < sizeof(uint16_t))
2479  fatal("pvr_vram_alt: write of less than 16 bits attempted?\n");
2480 
2481  /*
2482  * Convert writes to alternative VRAM, into normal writes:
2483  */
2484 
2485  for (i=0; i<len; i++) {
2486  int addr = relative_addr + i;
2487  addr = ((addr & 4) << 20) | (addr & 3) | ((addr & 0x7ffff8) >> 1);
2488  // printf(" %08x => alt addr %08x: %02x\n", (int)(relative_addr + i), (int)addr, data[i]);
2489  d->vram[addr % VRAM_SIZE] = data[i];
2490 
2491  // TODO: This is probably ultra-slow. (Should not be called
2492  // for every _byte_.)
2493  pvr_extend_update_region(d, addr, addr);
2494  }
2495 
2496  return 1;
2497 }
2498 
2499 
2500 DEVICE_ACCESS(pvr_vram)
2501 {
2502  struct pvr_data *d = (struct pvr_data *) extra;
2503 
2504  // According to http://mc.pp.se/dc/pvr.html, reads of any size are
2505  // allowed.
2506  if (writeflag == MEM_READ) {
2507  memcpy(data, d->vram + relative_addr, len);
2508  return 1;
2509  }
2510 
2511  // However, writes are only allowed as 16-bit access or higher.
2512  if (len < sizeof(uint16_t))
2513  fatal("pvr_vram: write of less than 16 bits attempted?\n");
2514 
2515  /*
2516  * Write to VRAM:
2517  *
2518  * Calculate which part of the framebuffer this write corresponds to,
2519  * if any, and increase the update region to encompass the written
2520  * memory range.
2521  */
2522 
2523  memcpy(d->vram + relative_addr, data, len);
2524  pvr_extend_update_region(d, relative_addr, relative_addr + len - 1);
2525 
2526  return 1;
2527 }
2528 
2529 
2531 {
2532  struct machine *machine = devinit->machine;
2533  struct pvr_data *d;
2534  struct pvr_data_alt *d_alt;
2535 
2536  CHECK_ALLOCATION(d = (struct pvr_data *) malloc(sizeof(struct pvr_data)));
2537  memset(d, 0, sizeof(struct pvr_data));
2538 
2539  CHECK_ALLOCATION(d_alt = (struct pvr_data_alt *) malloc(sizeof(struct pvr_data_alt)));
2540  memset(d_alt, 0, sizeof(struct pvr_data_alt));
2541 
2542  d_alt->d = d;
2543 
2545  PVRREG_REGSTART, PVRREG_REGSIZE, dev_pvr_access, d,
2546  DM_DEFAULT, NULL);
2547 
2548  /* 8 MB video RAM: */
2549  d->vram = (uint8_t *) zeroed_alloc(VRAM_SIZE);
2550  memory_device_register(machine->memory, "pvr_vram", 0x05000000,
2551  VRAM_SIZE, dev_pvr_vram_access, (void *)d,
2553  | DM_READS_HAVE_NO_SIDE_EFFECTS, d->vram);
2554 
2555  /* 8 MB video RAM, when accessed at 0xa4000000: */
2556  memory_device_register(machine->memory, "pvr_alt_vram", 0x04000000,
2557  VRAM_SIZE, dev_pvr_vram_alt_access, (void *)d_alt,
2558  DM_DEFAULT, NULL);
2559 
2560  /* Tile Accelerator command area at 0x10000000: */
2561  memory_device_register(machine->memory, "pvr_ta",
2562  0x10000000, 0x800000, dev_pvr_ta_access, d, DM_DEFAULT, NULL);
2563 
2564  /* PVR2 DMA registers at 0x5f6800: */
2565  memory_device_register(machine->memory, "pvr_dma", 0x005f6800,
2566  PVR_DMA_MEMLENGTH, dev_pvr_dma_access, d, DM_DEFAULT, NULL);
2567 
2568  /* More DMA registers at 0x5f7c00: */
2569  memory_device_register(machine->memory, "pvr_dma_more", 0x005f7c00,
2570  PVR_DMA_MEMLENGTH, dev_pvr_dma_more_access, d, DM_DEFAULT, NULL);
2571 
2572  d->xsize = 640;
2573  d->ysize = 480;
2574  d->pixelmode = 1; /* RGB565 */
2575  d->bytes_per_pixel = 2;
2576 
2577  d->fb = dev_fb_init(machine, machine->memory, INTERNAL_FB_ADDR,
2578  VFB_GENERIC, d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2,
2579  d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2,
2580  24, "Dreamcast PVR");
2581 
2582  d->vblank_timer = timer_add(PVR_VBLANK_HZ, pvr_vblank_timer_tick, d);
2583 
2584  pvr_reset(d);
2585  pvr_reset_ta(d);
2586 
2587  machine_add_tickfunction(machine, dev_pvr_fb_tick, d,
2589 
2590  return 1;
2591 }
2592 
#define PVR_SPANSORT_SPAN0
#define CHCR_TS_1BYTE
Definition: sh4_dmacreg.h:129
#define IEEE_FMT_S
Definition: float_emul.h:43
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
void * zeroed_alloc(size_t s)
Definition: memory.cc:118
void pvr_extend_update_region(struct pvr_data *d, uint64_t low, uint64_t high)
Definition: dev_pvr.cc:2242
#define SYNCCONF_BC_PAL
#define CHCR_RS
Definition: sh4_dmacreg.h:125
void fatal(const char *fmt,...)
Definition: main.cc:152
size_t allocated_ta_commands
Definition: dev_pvr.cc:141
#define PVRREG_CLAMP_MIN
#define DIWMODE_TH_SHIFT
#define DM_DEFAULT
Definition: memory.h:130
#define SYNCSIZE_V_MASK
#define DIWSIZE_LPF_SHIFT
#define PVRREG_VRAM_CFG1
#define PVRREG_SYNCSIZE
#define PVRREG_SCALER_CFG
int tilebuf_xsize
Definition: dev_pvr.cc:132
int ysize
Definition: dev_pvr.cc:110
#define PVR_PALETTE_CFG_MODE_ARGB1555
#define BRDHORZ_START_SHIFT
int update_x2
Definition: devices.h:220
#define PVRREG_SYNCH_WIDTH
#define PVR_PALETTE_CFG_MODE_ARGB8888
uint32_t * ta_commands
Definition: dev_pvr.cc:140
#define SYNCCONF_HP_MASK
#define SYNCCONF_VP_MASK
#define PVRREG_SHADOW
#define PVRREG_REGSTART
Definition: dreamcast_pvr.h:78
#define PVRREG_ISP_CFG
#define PVRREG_BGPLANE_CFG
#define DIWSIZE_MODULO_SHIFT
#define TA_OPB_CFG_TRANSPOLY_MASK
#define PVRREG_DIWSIZE
#define RASEVTPOS_POS2_MASK
struct vfb_data * dev_fb_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize, int xsize, int ysize, int bit_depth, const char *name)
Definition: dev_fb.cc:834
#define CHCR_TE
Definition: sh4_dmacreg.h:135
#define PVRREG_FB_CLIP_Y
#define DIWMODE_EX_MASK
char * name
Definition: device.h:43
#define TA_OPB_CFG_PUNCHTHROUGH_MASK
#define PVRREG_TA_OB_END
#define DIWCONF_BLANK
void pvr_fb_invalidate(struct pvr_data *d, int start, int stop)
Definition: dev_pvr.cc:516
#define PVR_MARGIN
Definition: dev_pvr.cc:81
#define PVR_FB_TICK_SHIFT
Definition: dev_pvr.cc:77
#define TA_OB_END_MASK
union cpu::@1 cd
int bit_depth
Definition: devices.h:206
#define VFB_GENERIC
Definition: devices.h:190
struct memory * mem
Definition: cpu.h:362
int xsize
Definition: devices.h:204
#define CHCR_DM
Definition: sh4_dmacreg.h:117
#define SYNCCONF_VO_MASK
#define PVRREG_FOG_TABLE_COL
#define PVR_ADDR
Definition: dev_pvr.cc:89
#define PVRREG_ID
Definition: dreamcast_pvr.h:83
uint32_t dmac_sar[N_SH4_DMA_CHANNELS]
Definition: cpu_sh.h:164
#define TA_OPB_CFG_OPAQUEPOLY_MASK
uint8_t * vram
Definition: dev_pvr.cc:145
#define VRAM_SIZE
Definition: dev_pvr.cc:83
#define MEM_READ
Definition: memory.h:116
#define PVRREG_UNKNOWN_84
#define PVR_PALETTE_SIZE
#define PVR_PALETTE_CFG_MODE_ARGB4444
#define DIWMODE_COL_SHIFT
struct memory * memory
Definition: machine.h:126
int display_enabled
Definition: dev_pvr.cc:122
#define BRDVERT_STOP_MASK
#define PVRREG_SPANSORT
#define TILEBUF_SIZE_HEIGHT_MASK
#define SYNCCONF_BC_MASK
#define TA_OB_START_MASK
#define DIWMODE_SL_SHIFT
#define PVRREG_SYNC_STAT
void ieee_interpret_float_value(uint64_t x, struct ieee_float_value *fvp, int fmt)
Definition: float_emul.cc:49
int vblank_interrupts_pending
Definition: dev_pvr.cc:104
#define DIWMODE_COL_MASK
#define PVRREG_FOG_VERTEX_COL
#define SYNCCONF_BC_SHIFT
#define PVRREG_FB_RENDER_MODULO
#define SYSASIC_TRIGGER_EVENT(e)
#define SYNCCONF_I_MASK
#define SYSASIC_EVENT_VBLINT
#define TA_OPB_END_MASK
#define PVRREG_RASEVTPOS
#define TA_OPB_CFG_OPAQUEMOD_MASK
int update_y1
Definition: devices.h:220
Definition: timer.cc:45
#define RASEVTPOS_POS1_MASK
#define TILEBUF_SIZE_HEIGHT_SHIFT
#define PVRREG_MAGIC_110
#define PVRREG_CLAMP_MAX
#define TA_OPB_POS_MASK
#define SYNCCONF_BC_NTSC
#define PVRREG_DIWADDRS
int border_updated
Definition: dev_pvr.cc:124
int extend
Definition: dev_pvr.cc:119
int fb_update_x1
Definition: dev_pvr.cc:98
struct pvr_data * d
Definition: dev_pvr.cc:154
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
#define BRDVERT_START_SHIFT
#define DIWVSTRT_V1_MASK
#define PVR_SPANSORT_TSP_CACHE_ENABLE
#define PVRREG_DIWADDRL
int broadcast_standard
Definition: dev_pvr.cc:127
#define PVRREG_UNKNOWN_80
#define SYSASIC_EVENT_RENDERDONE
#define DIWVSTRT_V2_MASK
#define PVR_LMMODE1
Definition: dev_pvr.cc:93
#define PHYSICAL
Definition: memory.h:126
#define PVRREG_TA_INIT
#define PVRREG_STARTRENDER
Definition: dreamcast_pvr.h:95
#define SYSASIC_EVENT_TRANSMODDONE
int current_list_type
Definition: dev_pvr.cc:139
double * vram_z
Definition: dev_pvr.cc:146
#define CHCR_IE
Definition: sh4_dmacreg.h:134
#define PVR_LMMODE0
Definition: dev_pvr.cc:92
#define DIWMODE_SL_MASK
#define SYSASIC_EVENT_PVR_PTDONE
int(* memory_rw)(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags)
Definition: cpu.h:365
#define PVRREG_OBJECT_CLIP
#define PVRREG_OB_ADDR
Definition: dreamcast_pvr.h:97
#define DM_READS_HAVE_NO_SIDE_EFFECTS
Definition: memory.h:133
u_short data
Definition: siireg.h:79
#define TILEBUF_SIZE_WIDTH_MASK
#define PVRREG_BRDHORZ
int pixelmode
Definition: dev_pvr.cc:120
uint32_t dma_reg[N_PVR_DMA_REGS]
Definition: dev_pvr.cc:149
int bytes_per_line
Definition: devices.h:212
int fb_update_y1
Definition: dev_pvr.cc:99
#define PVRREG_REVISION
Definition: dreamcast_pvr.h:85
uint32_t dmac_chcr[N_SH4_DMA_CHANNELS]
Definition: cpu_sh.h:167
void pvr_geometry_updated(struct pvr_data *d)
Definition: dev_pvr.cc:543
#define SYSASIC_EVENT_PVR_DMA
#define MAGIC_110_VALUE
int fb_update_x2
Definition: dev_pvr.cc:100
#define DIWVSTRT_HPOS_MASK
struct timer * timer_add(double freq, void(*timer_tick)(struct timer *timer, void *extra), void *extra)
Definition: timer.cc:75
#define CHCR_SM
Definition: sh4_dmacreg.h:121
#define INTERNAL_FB_ADDR
Definition: dev_pvr.cc:76
#define BRDVERT_START_MASK
#define PVRREG_FOG_DENSITY
#define TA_OB_POS_MASK
int update_x1
Definition: devices.h:220
uint32_t reg[PVRREG_REGSIZE/sizeof(uint32_t)]
Definition: dev_pvr.cc:107
DEVICE_TICK(pvr_fb)
Definition: dev_pvr.cc:2276
#define CHCR_TS_32BYTE
Definition: sh4_dmacreg.h:132
#define PVR_VBLANK_HZ
Definition: dev_pvr.cc:79
#define CHCR_TD
Definition: sh4_dmacreg.h:136
#define DM_DYNTRANS_WRITE_OK
Definition: memory.h:132
#define CHCR_TS
Definition: sh4_dmacreg.h:127
#define PVR_DMA_MEMLENGTH
Definition: dev_pvr.cc:86
#define DIWMODE_SE_MASK
#define MEM_WRITE
Definition: memory.h:117
#define CHCR_TS_4BYTE
Definition: sh4_dmacreg.h:131
#define TA_OPB_CFG_TRANSMOD_MASK
#define DIWSIZE_DPL_SHIFT
#define DIWSIZE_MASK
void pvr_ta_init(struct cpu *cpu, struct pvr_data *d)
Definition: dev_pvr.cc:1406
#define BRDHORZ_STOP_MASK
#define SYNCCONF_BC_VGA
#define SYSASIC_EVENT_TRANSDONE
#define PVR_TILEBUF_ADDR_MASK
#define SHADOW_INTENSITY_MASK
#define CHCR_SM_DECREMENTED
Definition: sh4_dmacreg.h:124
int strip_length
Definition: dev_pvr.cc:117
Definition: device.h:40
#define DEFAULT_WRITE
Definition: dev_pvr.cc:159
#define PVRREG_OB_CFG
#define TSP_CFG_MODULO_MASK
void pvr_dma_transfer(struct cpu *cpu, struct pvr_data *d)
Definition: dev_pvr.cc:166
int fb_update_y2
Definition: dev_pvr.cc:101
uint32_t addr
#define PVRREG_DIWVSTRT
#define PVR_SPANSORT_SPAN1
#define debug
Definition: dev_adb.cc:57
#define FB_RENDER_CFG_RENDER_MODE_MASK
#define SYNCSIZE_H_MASK
#define TA_OPB_START_MASK
#define SYSASIC_EVENT_PVR_SCANINT2
#define SYSASIC_EVENT_OPAQUEDONE
Definition: cpu.h:326
uint32_t dmac_dar[N_SH4_DMA_CHANNELS]
Definition: cpu_sh.h:165
#define FB_CLIP_XY_MAX_MASK
int tilebuf_ysize
Definition: dev_pvr.cc:133
#define PVRREG_DIWHSTRT
struct machine * machine
Definition: device.h:41
#define NO_EXCEPTIONS
Definition: memory.h:125
#define DIWVSTRT_V2_SHIFT
#define PVRREG_TA_OPB_END
uint32_t dmac_tcr[N_SH4_DMA_CHANNELS]
Definition: cpu_sh.h:166
#define DIWCONF_MAGIC_MASK
#define SYSASIC_EVENT_OPAQUEMODDONE
int argb8888_threshold
Definition: dev_pvr.cc:118
#define SYSASIC_EVENT_PVR_SCANINT1
#define PVRREG_RESET
Definition: dreamcast_pvr.h:90
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
#define PVRREG_FB_CLIP_X
#define FB_CLIP_XY_MIN_MASK
#define PVRREG_BRDVERT
#define PVRREG_PALETTE_CFG
unsigned char * framebuffer
Definition: devices.h:231
#define DIWCONF_MAGIC
struct vfb_data * fb
Definition: dev_pvr.cc:97
#define PVR_FOG_TABLE_SIZE
#define PVR_OB_ADDR_MASK
#define PVRREG_DIWCONF
#define PVR_TA_INIT
#define CHCR_DM_DECREMENTED
Definition: sh4_dmacreg.h:120
#define PVR_RESET_PVR
Definition: dreamcast_pvr.h:92
void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition: memory.cc:339
struct timer * vblank_timer
Definition: dev_pvr.cc:103
#define DM_DYNTRANS_OK
Definition: memory.h:131
DEVICE_ACCESS(pvr_ta)
Definition: dev_pvr.cc:1513
#define PVRREG_TILEBUF_ADDR
int video_enabled
Definition: dev_pvr.cc:126
DEVINIT(pvr)
Definition: dev_pvr.cc:2530
int interlaced
Definition: dev_pvr.cc:128
#define PVRREG_TILEBUF_SIZE
#define N_PVR_DMA_REGS
Definition: dev_pvr.cc:87
void memory_device_dyntrans_access(struct cpu *, struct memory *mem, void *extra, uint64_t *low, uint64_t *high)
Definition: memory.cc:264
#define DIWMODE_DE_MASK
#define DIWMODE_EX_SHIFT
#define CHCR_SM_FIXED
Definition: sh4_dmacreg.h:122
#define PVRREG_BGPLANE_Z
#define PVR_MODE
Definition: dev_pvr.cc:91
uint32_t dma_more_reg[N_PVR_DMA_REGS]
Definition: dev_pvr.cc:150
int bytes_per_pixel
Definition: dev_pvr.cc:111
#define PVRREG_SYNCCONF
int v_sync_positive
Definition: dev_pvr.cc:130
addr & if(addr >=0x24 &&page !=NULL)
int h_sync_positive
Definition: dev_pvr.cc:129
#define VRAM_CFG1_GOOD_REFRESH_VALUE
uint32_t ta[64/sizeof(uint32_t)]
Definition: dev_pvr.cc:136
#define PVR_TA_OPL_INIT_MASK
int xsize
Definition: dev_pvr.cc:110
#define PVR_PALETTE_CFG_MODE_MASK
#define PVRREG_DIWMODE
#define PVRREG_FB_RENDER_CFG
#define CHCR_TS_8BYTE
Definition: sh4_dmacreg.h:128
#define PVRREG_REGSIZE
Definition: dreamcast_pvr.h:80
void machine_add_tickfunction(struct machine *machine, void(*func)(struct cpu *, void *), void *extra, int clockshift)
Definition: machine.cc:280
#define RASEVTPOS_POS1_SHIFT
size_t n_ta_commands
Definition: dev_pvr.cc:142
#define CHCR_DM_INCREMENTED
Definition: sh4_dmacreg.h:119
int clock_double
Definition: dev_pvr.cc:115
#define PVR_RESET_TA
Definition: dreamcast_pvr.h:91
#define DIWMODE_TH_MASK
#define CHCR_TS_2BYTE
Definition: sh4_dmacreg.h:130
#define REG(x)
Definition: dev_pvr.cc:158
#define CHCR_SM_INCREMENTED
Definition: sh4_dmacreg.h:123
#define PVRREG_TA_OPB_CFG
#define PVRREG_FB_RENDER_ADDR2
#define DIWMODE_C_MASK
int line_double
Definition: dev_pvr.cc:121
#define PVRREG_TA_OB_POS
#define PVRREG_TA_OB_START
#define PVRREG_PALETTE
#define PVRREG_BRDCOLR
int update_y2
Definition: devices.h:220
#define PVRREG_YUV_STAT
#define PVRREG_TA_OPB_START
#define PVRREG_VRAM_CFG2
#define SYNCSIZE_V_SHIFT
#define CHCR_DM_FIXED
Definition: sh4_dmacreg.h:118
#define PVRREG_TA_LUMINANCE
#define PVRREG_TSP_CFG
#define BRDHORZ_START_MASK
struct sh_cpu sh
Definition: cpu.h:445
#define DIWCONF_LR
#define PVR_COUNT
Definition: dev_pvr.cc:90
#define VRAM_CFG2_UNKNOWN_MAGIC
#define PVRREG_FB_RENDER_ADDR1
#define PVRREG_HPOS_IRQ
#define PVRREG_TA_OPL_INIT
#define PVR_PALETTE_CFG_MODE_RGB565
#define PVRREG_FOG_TABLE
#define FB_CLIP_XY_MAX_SHIFT
void pvr_render(struct cpu *cpu, struct pvr_data *d)
Definition: dev_pvr.cc:1043
#define DIWMODE_SD_MASK
int ysize
Definition: devices.h:205
#define VRAM_CFG3_UNKNOWN_MAGIC
int strip_buffer_enabled
Definition: dev_pvr.cc:116
#define SHADOW_ENABLE
#define PVRREG_VRAM_CFG3
#define PVRREG_TA_OPB_POS

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13