dev_pvr.cc Source File

Back to the index.

dev_pvr.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2018 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? Endianness?
801  int index8bpp = d->vram[addr];
802  char* base = (char*)&d->reg[PVRREG_PALETTE / sizeof(uint32_t)];
803  uint16_t c16 = *((uint16_t*)(void*)base + index8bpp);
804  uint16_t c32 = *((uint32_t*)(void*)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 
1422  // TODO: endianness
1423  uint32_t *p = (uint32_t*) (d->vram + tilebuf);
1424 
1425  fatal("PVR tile buffer debug dump:\n");
1426  p -= 24;
1427  for (int i = 0; i < 24; ++i)
1428  fatal(" %08x", *p++);
1429 
1430  fatal("\n%i x %i tiles:\n", d->tilebuf_xsize, d->tilebuf_ysize);
1431 
1432  for (int x = 0; x < d->tilebuf_xsize; ++x)
1433  {
1434  for (int y = 0; y < d->tilebuf_ysize; ++y)
1435  {
1436  fatal(" Tile %i,%i:", x, y);
1437  for (int i = 0; i < 6; ++i)
1438  fatal(" %08x", *p++);
1439  fatal("\n");
1440  }
1441  }
1442 }
1443 
1444 
1445 /*
1446  * pvr_ta_command():
1447  *
1448  * Someone has written a [complete] 32-byte or 64-byte command to the Tile
1449  * Accelerator memory area. The real hardware probably outputs
1450  * "compiled commands" into the Object list and Object Pointer list.
1451  * For now, just put all the commands in a plain array, and then later execute
1452  * them in pvr_render().
1453  */
1454 static void pvr_ta_command(struct cpu *cpu, struct pvr_data *d, int list_ofs)
1455 {
1456  uint32_t *ta = &d->ta[list_ofs];
1457 
1458 #ifdef TA_DEBUG
1459  /* Dump the Tile Accelerator command for debugging: */
1460  {
1461  int i;
1462  fatal("TA cmd:");
1463  for (i = 0; i < 8; ++i)
1464  fatal(" %08x", (int) ta[i]);
1465  fatal("\n");
1466  }
1467 #endif
1468 
1469  // ob_ofs = REG(PVRREG_TA_OB_POS);
1470  // REG(PVRREG_TA_OB_POS) = ob_ofs + sizeof(uint64_t);
1471 
1472  if (d->ta_commands == NULL) {
1473  d->allocated_ta_commands = 2048;
1474  d->ta_commands = (uint32_t *) malloc(64 * d->allocated_ta_commands);
1475  d->n_ta_commands = 0;
1476  }
1477 
1478  if (d->n_ta_commands + 1 >= d->allocated_ta_commands) {
1479  d->allocated_ta_commands *= 2;
1480  d->ta_commands = (uint32_t *) realloc(d->ta_commands, 64 * d->allocated_ta_commands);
1481  }
1482 
1483  // Hack: I don't understand yet what separates a 32-byte transfer
1484  // vs two individual 32-byte transfers vs a 64-byte transfer.
1485  // TODO: For now, really only support 32-byte transfers... :(
1486  memcpy(d->ta_commands + 16 * d->n_ta_commands, ta, 32);
1487  memset(d->ta_commands + 16 * d->n_ta_commands + 8, 0, 32);
1488  d->n_ta_commands ++;
1489 
1490  // We need to keep track of the current list type though, and respond
1491  // with an event once we reach an end_of_list command. All other
1492  // commands are handled in pvr_render() for now.
1493  int cmd = (ta[0] >> 29) & 7;
1494  if (cmd == 0) {
1495  // cmd 0: end of list
1496  uint32_t opb_cfg = REG(PVRREG_TA_OPB_CFG);
1497 
1498  if (d->current_list_type == 0 && opb_cfg & TA_OPB_CFG_OPAQUEPOLY_MASK)
1500  if (d->current_list_type == 1 && opb_cfg & TA_OPB_CFG_OPAQUEMOD_MASK)
1502  if (d->current_list_type == 2 && opb_cfg & TA_OPB_CFG_TRANSPOLY_MASK)
1504  if (d->current_list_type == 3 && opb_cfg & TA_OPB_CFG_TRANSMOD_MASK)
1506  if (d->current_list_type == 4 && opb_cfg & TA_OPB_CFG_PUNCHTHROUGH_MASK)
1508  } else if (cmd == 4) {
1509  // cmd 4: polygon or modifier volume
1510  d->current_list_type = (ta[0] >> 24) & 7;
1511  }
1512 }
1513 
1514 
1516 {
1517  struct pvr_data *d = (struct pvr_data *) extra;
1518  uint64_t idata = 0, odata = 0;
1519 
1520  if (len != sizeof(uint32_t)) {
1521  fatal("pvr_ta access len = %i: TODO\n", (int) len);
1522  exit(1);
1523  }
1524 
1525  // Tile Accelerator commands can be sent to 0x10000000 through
1526  // 0x107fffff, it seems, but the SH4 store queues only have 64 bytes.
1527  relative_addr &= (sizeof(d->ta) - 1);
1528 
1529  if (writeflag == MEM_WRITE) {
1530  idata = memory_readmax64(cpu, data, len);
1531 #if 0
1532  fatal("[ pvr_ta: WRITE addr=%08x value=%08x ]\n",
1533  (int)relative_addr, (int)idata);
1534 #endif
1535 
1536  /* Write to the tile accelerator command buffer: */
1537  d->ta[relative_addr / sizeof(uint32_t)] = idata;
1538 
1539  // Execute the command, after a complete write.
1540  // (Note: This assumes that commands are written from low
1541  // address to high.)
1542  if (relative_addr == 0x1c)
1543  pvr_ta_command(cpu, d, 0);
1544  if (relative_addr == 0x3c)
1545  pvr_ta_command(cpu, d, 8);
1546  } else {
1547  odata = d->ta[relative_addr / sizeof(uint32_t)];
1548  memory_writemax64(cpu, data, len, odata);
1549 #if 1
1550  fatal("[ pvr_ta: READ addr=%08x value=%08x ]\n", (int)relative_addr, (int)odata);
1551 #endif
1552  }
1553 
1554  return 1;
1555 }
1556 
1557 
1559 {
1560  struct pvr_data *d = (struct pvr_data *) extra;
1561  uint64_t idata = 0, odata = 0;
1562 
1563  if (writeflag == MEM_WRITE)
1564  idata = memory_readmax64(cpu, data, len);
1565 
1566  /* Default read action: Read from reg[]: */
1567  if (writeflag == MEM_READ)
1568  odata = d->reg[relative_addr / sizeof(uint32_t)];
1569 
1570  /* Fog table access: */
1571  if (relative_addr >= PVRREG_FOG_TABLE &&
1572  relative_addr < PVRREG_FOG_TABLE + PVR_FOG_TABLE_SIZE) {
1573  if (writeflag == MEM_WRITE)
1574  DEFAULT_WRITE;
1575  goto return_ok;
1576  }
1577 
1578  /* Palette access: */
1579  if (relative_addr >= PVRREG_PALETTE &&
1580  relative_addr < PVRREG_PALETTE + PVR_PALETTE_SIZE) {
1581  if (writeflag == MEM_WRITE)
1582  DEFAULT_WRITE;
1583  goto return_ok;
1584  }
1585 
1586  switch (relative_addr) {
1587 
1588  case PVRREG_ID:
1589  /* ID for Set 5.xx versions of the Dreamcast, according
1590  to http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt: */
1591  odata = 0x17fd11db;
1592  break;
1593 
1594  case PVRREG_REVISION:
1595  /* Revision 1.1, for Dreamcast Set 5.2x. */
1596  odata = 0x00000011;
1597  break;
1598 
1599  case PVRREG_RESET:
1600  if (writeflag == MEM_WRITE) {
1601  if (idata != 0) {
1602  debug("[ pvr: RESET ");
1603  if (idata & PVR_RESET_PVR)
1604  pvr_reset(d);
1605  if (idata & PVR_RESET_TA)
1606  pvr_reset_ta(d);
1607  debug("]\n");
1608  }
1609  idata = 0;
1610  DEFAULT_WRITE;
1611  }
1612  break;
1613 
1614  case PVRREG_STARTRENDER:
1615  if (writeflag == MEM_WRITE) {
1616  debug("[ pvr: STARTRENDER ]\n");
1617  pvr_render(cpu, d);
1618  } else {
1619  fatal("[ pvr: huh? read from STARTRENDER ]\n");
1620  exit(1);
1621  }
1622  break;
1623 
1624  case PVRREG_OB_ADDR:
1625  if (writeflag == MEM_WRITE) {
1626  debug("[ pvr: OB_ADDR set to 0x%08" PRIx32" ]\n",
1627  (uint32_t)(idata & PVR_OB_ADDR_MASK));
1628  if (idata & ~PVR_OB_ADDR_MASK) {
1629  fatal("[ pvr: OB_ADDR: Fatal error: Unknown"
1630  " bits set: 0x%08" PRIx32" ]\n",
1631  (uint32_t)(idata & ~PVR_OB_ADDR_MASK));
1632  exit(1);
1633  }
1634  idata &= PVR_OB_ADDR_MASK;
1635  DEFAULT_WRITE;
1636  }
1637  break;
1638 
1639  case PVRREG_TILEBUF_ADDR:
1640  if (writeflag == MEM_WRITE) {
1641  debug("[ pvr: TILEBUF_ADDR set to 0x%08" PRIx32" ]\n",
1642  (uint32_t)(idata & PVR_TILEBUF_ADDR_MASK));
1643  if (idata & ~PVR_TILEBUF_ADDR_MASK) {
1644  fatal("[ pvr: TILEBUF_ADDR: Unknown"
1645  " bits set: 0x%08" PRIx32" ]\n",
1646  (uint32_t)(idata & ~PVR_TILEBUF_ADDR_MASK));
1647  exit(1);
1648  }
1649  idata &= PVR_TILEBUF_ADDR_MASK;
1650  DEFAULT_WRITE;
1651  pvr_tilebuf_debugdump(d);
1652  }
1653  break;
1654 
1655  case PVRREG_SPANSORT:
1656  if (writeflag == MEM_WRITE) {
1657  debug("[ pvr: SPANSORT: ");
1658  if (idata & PVR_SPANSORT_SPAN0)
1659  debug("SPAN0 ");
1660  if (idata & PVR_SPANSORT_SPAN1)
1661  debug("SPAN1 ");
1662  if (idata & PVR_SPANSORT_TSP_CACHE_ENABLE)
1663  debug("TSP_CACHE_ENABLE ");
1664  debug("]\n");
1665  DEFAULT_WRITE;
1666  }
1667  break;
1668 
1669  case PVRREG_BRDCOLR:
1670  if (writeflag == MEM_WRITE) {
1671  debug("[ pvr: BRDCOLR set to 0x%06" PRIx32" ]\n",
1672  (int)idata);
1673  DEFAULT_WRITE;
1674  d->border_updated = 1;
1675  }
1676  break;
1677 
1678  case PVRREG_DIWMODE:
1679  if (writeflag == MEM_WRITE) {
1680  d->clock_double = idata & DIWMODE_C_MASK? 1:0;
1681  d->strip_buffer_enabled = idata & DIWMODE_SE_MASK? 1:0;
1682  d->strip_length = (idata & DIWMODE_SL_MASK)
1683  >> DIWMODE_SL_SHIFT;
1684  d->argb8888_threshold = (idata & DIWMODE_TH_MASK)
1685  >> DIWMODE_TH_SHIFT;
1686  d->extend = (idata & DIWMODE_EX_MASK)
1687  >> DIWMODE_EX_SHIFT;
1688  d->pixelmode = (idata & DIWMODE_COL_MASK)
1689  >> DIWMODE_COL_SHIFT;
1690  d->line_double = idata & DIWMODE_SD_MASK? 1:0;
1691  d->display_enabled = idata & DIWMODE_DE_MASK? 1:0;
1692 
1693  debug("[ pvr: DIWMODE set to: ");
1694  debug("clock_double=%i, ", d->clock_double);
1695  debug("strip_buffer_enabled=%i, ",
1697  debug("strip_length=%i, ", d->strip_length);
1698  debug("argb8888_threshold=%i, ", d->argb8888_threshold);
1699  debug("extend=0x%x, ", d->extend);
1700  debug("pixelmode=");
1701  switch (d->pixelmode) {
1702  case 0: debug("RGB0555 (16-bit)"); break;
1703  case 1: debug("RGB565 (16-bit)"); break;
1704  case 2: debug("RGB888 (24-bit)"); break;
1705  case 3: debug("RGB0888 (32-bit)"); break;
1706  }
1707  debug(", line_double=%i, ", d->line_double);
1708  debug("display_enabled=%i", d->display_enabled);
1709  debug(" ]\n");
1710 
1711  DEFAULT_WRITE;
1713  pvr_fb_invalidate(d, -1, -1);
1714  }
1715  break;
1716 
1717  case PVRREG_DIWSIZE:
1718  if (writeflag == MEM_WRITE) {
1719  debug("[ pvr: DIWSIZE set to modulo=%i, "
1720  "width=%i, height=%i ]\n", (int)
1721  ((idata >> DIWSIZE_MODULO_SHIFT) & DIWSIZE_MASK),
1722  (int)((idata >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK),
1723  (int)((idata >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK));
1724  DEFAULT_WRITE;
1726  pvr_fb_invalidate(d, -1, -1);
1727  }
1728  break;
1729 
1731  if (writeflag == MEM_WRITE) {
1732  debug("[ pvr: FB_RENDER_ADDR1 set to 0x%08" PRIx32
1733  " ]\n", (int) idata);
1734  DEFAULT_WRITE;
1735  }
1736  break;
1737 
1739  if (writeflag == MEM_WRITE) {
1740  debug("[ pvr: FB_RENDER_ADDR2 set to 0x%08" PRIx32
1741  " ]\n", (int) idata);
1742  DEFAULT_WRITE;
1743  }
1744  break;
1745 
1746  case PVRREG_FB_CLIP_X:
1747  if (writeflag == MEM_WRITE) {
1748  debug("[ pvr: FB_CLIP_X set to min=%i, "
1749  "max=%i ]\n", (int) (idata & FB_CLIP_XY_MIN_MASK),
1750  (int) ((idata & FB_CLIP_XY_MAX_MASK)
1751  >> FB_CLIP_XY_MAX_SHIFT));
1752  DEFAULT_WRITE;
1754  pvr_fb_invalidate(d, -1, -1);
1755  }
1756  break;
1757 
1758  case PVRREG_FB_CLIP_Y:
1759  if (writeflag == MEM_WRITE) {
1760  debug("[ pvr: FB_CLIP_Y set to min=%i, "
1761  "max=%i ]\n", (int) (idata & FB_CLIP_XY_MIN_MASK),
1762  (int) ((idata & FB_CLIP_XY_MAX_MASK)
1763  >> FB_CLIP_XY_MAX_SHIFT));
1764  DEFAULT_WRITE;
1766  pvr_fb_invalidate(d, -1, -1);
1767  }
1768  break;
1769 
1770  case PVRREG_SHADOW:
1771  if (writeflag == MEM_WRITE) {
1772  debug("[ pvr: SHADOW set to enable=%i, "
1773  "intensity=%i ]\n",
1774  (int) (idata & SHADOW_ENABLE? 1 : 0),
1775  (int) (idata & SHADOW_INTENSITY_MASK));
1776  DEFAULT_WRITE;
1778  pvr_fb_invalidate(d, -1, -1);
1779  }
1780  break;
1781 
1782  case PVRREG_OBJECT_CLIP:
1783  if (writeflag == MEM_WRITE) {
1784  debug("[ pvr: OBJECT_CLIP 0x%08x ]\n", (int)idata);
1785  DEFAULT_WRITE;
1786  }
1787  break;
1788 
1789  case PVRREG_OB_CFG:
1790  if (writeflag == MEM_WRITE) {
1791  debug("[ pvr: OB_CFG 0x%08x ]\n", (int)idata);
1792  DEFAULT_WRITE;
1793  }
1794  break;
1795 
1796  case PVRREG_UNKNOWN_80:
1797  if (writeflag == MEM_WRITE) {
1798  debug("[ pvr: UNKNOWN_80 0x%08x ]\n", (int)idata);
1799  DEFAULT_WRITE;
1800  }
1801  break;
1802 
1803  case PVRREG_UNKNOWN_84:
1804  if (writeflag == MEM_WRITE) {
1805  debug("[ pvr: UNKNOWN_84 0x%08x ]\n", (int)idata);
1806  DEFAULT_WRITE;
1807  }
1808  break;
1809 
1810  case PVRREG_BGPLANE_Z:
1811  if (writeflag == MEM_WRITE) {
1812  debug("[ pvr: BGPLANE_Z 0x%08x ]\n", (int)idata);
1813  DEFAULT_WRITE;
1814  }
1815  break;
1816 
1817  case PVRREG_BGPLANE_CFG:
1818  if (writeflag == MEM_WRITE) {
1819  debug("[ pvr: BGPLANE_CFG 0x%08x ]\n", (int)idata);
1820  DEFAULT_WRITE;
1821  }
1822  break;
1823 
1824  case PVRREG_ISP_CFG:
1825  if (writeflag == MEM_WRITE) {
1826  debug("[ pvr: ISP_CFG 0x%08x ]\n", (int)idata);
1827  DEFAULT_WRITE;
1828  }
1829  break;
1830 
1831  case PVRREG_VRAM_CFG1:
1832  if (writeflag == MEM_WRITE) {
1833  debug("[ pvr: VRAM_CFG1 set to 0x%08" PRIx32,
1834  (int) idata);
1835  if (idata != VRAM_CFG1_GOOD_REFRESH_VALUE)
1836  fatal("{ VRAM_CFG1 = 0x%08" PRIx32" is not "
1837  "yet implemented! }", (int) idata);
1838  debug(" ]\n");
1839  DEFAULT_WRITE;
1840  }
1841  break;
1842 
1843  case PVRREG_VRAM_CFG2:
1844  if (writeflag == MEM_WRITE) {
1845  debug("[ pvr: VRAM_CFG2 set to 0x%08" PRIx32,
1846  (int) idata);
1847  if (idata != VRAM_CFG2_UNKNOWN_MAGIC)
1848  fatal("{ VRAM_CFG2 = 0x%08" PRIx32" is not "
1849  "yet implemented! }", (int) idata);
1850  debug(" ]\n");
1851  DEFAULT_WRITE;
1852  }
1853  break;
1854 
1855  case PVRREG_VRAM_CFG3:
1856  if (writeflag == MEM_WRITE) {
1857  debug("[ pvr: VRAM_CFG3 set to 0x%08" PRIx32,
1858  (int) idata);
1859  if (idata != VRAM_CFG3_UNKNOWN_MAGIC)
1860  fatal("{ VRAM_CFG3 = 0x%08" PRIx32" is not "
1861  "yet implemented! }", (int) idata);
1862  debug(" ]\n");
1863  DEFAULT_WRITE;
1864  }
1865  break;
1866 
1867  case PVRREG_FOG_TABLE_COL:
1868  // e.g. 0x007f7f7f
1869  if (writeflag == MEM_WRITE) {
1870  debug("[ pvr: FOG_TABLE_COL set to 0x%06" PRIx32" ]\n",
1871  (int) idata);
1872  DEFAULT_WRITE;
1873  }
1874  break;
1875 
1876  case PVRREG_FOG_VERTEX_COL:
1877  // e.g. 0x007f7f7f
1878  if (writeflag == MEM_WRITE) {
1879  debug("[ pvr: FOG_VERTEX_COL set to 0x%06" PRIx32" ]\n",
1880  (int) idata);
1881  DEFAULT_WRITE;
1882  }
1883  break;
1884 
1885  case PVRREG_FOG_DENSITY:
1886  // e.g. 0x0000ff07
1887  if (writeflag == MEM_WRITE) {
1888  debug("[ pvr: FOG_DENSITY set to 0x%08" PRIx32" ]\n",
1889  (int) idata);
1890  DEFAULT_WRITE;
1891  }
1892  break;
1893 
1894  case PVRREG_CLAMP_MAX:
1895  // e.g. 0xffffffff
1896  if (writeflag == MEM_WRITE) {
1897  debug("[ pvr: CLAMP_MAX set to 0x%06" PRIx32" ]\n",
1898  (int) idata);
1899  DEFAULT_WRITE;
1900  }
1901  break;
1902 
1903  case PVRREG_CLAMP_MIN:
1904  // e.g. 0x00000000
1905  if (writeflag == MEM_WRITE) {
1906  debug("[ pvr: CLAMP_MIN set to 0x%06" PRIx32" ]\n",
1907  (int) idata);
1908  DEFAULT_WRITE;
1909  }
1910  break;
1911 
1912  case PVRREG_FB_RENDER_CFG:
1913  if (writeflag == MEM_WRITE) {
1914  debug("[ pvr: PVRREG_FB_RENDER_CFG set to 0x%08x ]\n",
1915  (int) idata);
1916  /* TODO */
1917  DEFAULT_WRITE;
1918  }
1919  break;
1920 
1922  if (writeflag == MEM_WRITE) {
1923  debug("[ pvr: PVRREG_FB_RENDER_MODULO set to %i ]\n",
1924  (int) idata);
1925  /* TODO */
1926  DEFAULT_WRITE;
1927  }
1928  break;
1929 
1930  case PVRREG_DIWADDRL:
1931  if (writeflag == MEM_WRITE) {
1932  debug("[ pvr: DIWADDRL set to 0x%08" PRIx32" ]\n",
1933  (int) idata);
1934  pvr_fb_invalidate(d, -1, -1);
1935  DEFAULT_WRITE;
1936  }
1937  break;
1938 
1939  case PVRREG_DIWADDRS:
1940  if (writeflag == MEM_WRITE) {
1941  debug("[ pvr: DIWADDRS set to 0x%08" PRIx32" ]\n",
1942  (int) idata);
1943  pvr_fb_invalidate(d, -1, -1);
1944  DEFAULT_WRITE;
1945  }
1946  break;
1947 
1948  case PVRREG_HPOS_IRQ:
1949  DEFAULT_WRITE;
1950  break;
1951 
1952  case PVRREG_RASEVTPOS:
1953  if (writeflag == MEM_WRITE) {
1954  debug("[ pvr: RASEVTPOS pos1=%i pos2=%i ]\n",
1955  (int)((idata & RASEVTPOS_POS1_MASK)
1957  (int)(idata & RASEVTPOS_POS2_MASK));
1958  DEFAULT_WRITE;
1959  }
1960  break;
1961 
1962  case PVRREG_SYNCCONF:
1963  if (writeflag == MEM_WRITE) {
1964  d->video_enabled = idata & SYNCCONF_VO_MASK? 1:0;
1965  d->broadcast_standard = (idata & SYNCCONF_BC_MASK)
1966  >> SYNCCONF_BC_SHIFT;
1967  d->interlaced = idata & SYNCCONF_I_MASK? 1:0;
1968  d->h_sync_positive = idata & SYNCCONF_HP_MASK? 1:0;
1969  d->v_sync_positive = idata & SYNCCONF_VP_MASK? 1:0;
1970 
1971  debug("[ pvr: SYNCCONF set to: ");
1972  debug("video_enabled=%i, ", d->video_enabled);
1973  switch (d->broadcast_standard) {
1974  case SYNCCONF_BC_VGA: debug("VGA"); break;
1975  case SYNCCONF_BC_NTSC: debug("NTSC"); break;
1976  case SYNCCONF_BC_PAL: debug("PAL"); break;
1977  default: debug("*UNKNOWN*"); break;
1978  }
1979  debug(", interlaced=%i, ", d->interlaced);
1980  debug("hsync=%i, ", d->h_sync_positive);
1981  debug("vsync=%i ]\n", d->v_sync_positive);
1982 
1983  DEFAULT_WRITE;
1985  pvr_fb_invalidate(d, -1, -1);
1986  }
1987  break;
1988 
1989  case PVRREG_BRDHORZ:
1990  if (writeflag == MEM_WRITE) {
1991  debug("[ pvr: BRDHORZ start=%i stop=%i ]\n",
1992  (int)((idata & BRDHORZ_START_MASK)
1993  >> BRDHORZ_START_SHIFT),
1994  (int)(idata & BRDHORZ_STOP_MASK));
1995  DEFAULT_WRITE;
1996  }
1997  break;
1998 
1999  case PVRREG_SYNCSIZE:
2000  if (writeflag == MEM_WRITE) {
2001  debug("[ pvr: SYNCSIZE v=%i h=%i ]\n",
2002  (int)((idata & SYNCSIZE_V_MASK)
2003  >> SYNCSIZE_V_SHIFT),
2004  (int)(idata & SYNCSIZE_H_MASK));
2005  DEFAULT_WRITE;
2006  }
2007  break;
2008 
2009  case PVRREG_BRDVERT:
2010  if (writeflag == MEM_WRITE) {
2011  debug("[ pvr: BRDVERT start=%i stop=%i ]\n",
2012  (int)((idata & BRDVERT_START_MASK)
2013  >> BRDVERT_START_SHIFT),
2014  (int)(idata & BRDVERT_STOP_MASK));
2015  DEFAULT_WRITE;
2016  }
2017  break;
2018 
2019  case PVRREG_SYNCH_WIDTH:
2020  if (writeflag == MEM_WRITE) {
2021  debug("[ pvr: SYNCH_WIDTH 0x%08x ]\n", (int)idata);
2022  DEFAULT_WRITE;
2023  }
2024  break;
2025 
2026  case PVRREG_TSP_CFG:
2027  if (writeflag == MEM_WRITE) {
2028  debug("[ pvr: TSP_CFG 0x%08x ]\n", (int)idata);
2029  DEFAULT_WRITE;
2030  }
2031  break;
2032 
2033  case PVRREG_DIWCONF:
2034  if (writeflag == MEM_WRITE) {
2035  if ((idata & DIWCONF_MAGIC_MASK) !=
2036  DIWCONF_MAGIC && (idata & DIWCONF_MAGIC_MASK)
2037  != 0) {
2038  fatal("PVRREG_DIWCONF magic not set to "
2039  "Magic value. 0x%08x\n", (int)idata);
2040  exit(1);
2041  }
2042  if (idata & DIWCONF_BLANK)
2043  debug("[ pvr: PVRREG_DIWCONF: BLANK: TODO ]\n");
2044 
2045  DEFAULT_WRITE;
2047  }
2048  break;
2049 
2050  case PVRREG_DIWHSTRT:
2051  if (writeflag == MEM_WRITE) {
2052  int v = idata & DIWVSTRT_HPOS_MASK;
2053  debug("[ pvr: DIWHSTRT hpos=%i (%s) ]\n",
2054  v, v == 174? "PAL" :
2055  (v == 164? "NTSC" :
2056  (v == 144? "VGA" : "unknown!")));
2057  DEFAULT_WRITE;
2058  }
2059  break;
2060 
2061  case PVRREG_DIWVSTRT:
2062  if (writeflag == MEM_WRITE) {
2063  debug("[ pvr: DIWVSTRT v2=%i v1=%i ]\n",
2064  (int)((idata & DIWVSTRT_V2_MASK)
2065  >> DIWVSTRT_V2_SHIFT),
2066  (int)(idata & DIWVSTRT_V1_MASK));
2067  DEFAULT_WRITE;
2068  }
2069  break;
2070 
2071  case PVRREG_SCALER_CFG:
2072  if (writeflag == MEM_WRITE) {
2073  debug("[ pvr: SCALER_CFG 0x%08x ]\n", (int)idata);
2074  DEFAULT_WRITE;
2075  }
2076  break;
2077 
2078  case PVRREG_PALETTE_CFG:
2079  if (writeflag == MEM_WRITE) {
2080  debug("[ pvr: PALETTE_CFG 0x%08x ]\n", (int)idata);
2081  DEFAULT_WRITE;
2082  }
2083  break;
2084 
2085  case PVRREG_SYNC_STAT:
2086  /* TODO. Ugly hack, but it works: */
2087  odata = random();
2088  break;
2089 
2090  case PVRREG_MAGIC_110:
2091  if (writeflag == MEM_WRITE) {
2092  debug("[ pvr: MAGIC_110 set to 0x%08" PRIx32,
2093  (int) idata);
2094  if (idata != MAGIC_110_VALUE)
2095  fatal("{ MAGIC_110 = 0x%08" PRIx32" is not "
2096  "yet implemented! }", (int) idata);
2097  debug(" ]\n");
2098  DEFAULT_WRITE;
2099  }
2100  break;
2101 
2102  case PVRREG_TA_LUMINANCE:
2103  if (writeflag == MEM_WRITE) {
2104  debug("[ pvr: TA_LUMINANCE set to 0x%08" PRIx32" ]\n",
2105  (int) idata);
2106  DEFAULT_WRITE;
2107  }
2108  break;
2109 
2110  case PVRREG_TA_OPB_START:
2111  if (writeflag == MEM_WRITE) {
2112  if (idata & ~TA_OPB_START_MASK) {
2113  fatal("[ pvr: UNEXPECTED bits in "
2114  "TA_OPB_START: 0x%08x ]\n", (int)idata);
2115  exit(1);
2116  }
2117  idata &= TA_OPB_START_MASK;
2118  debug("[ pvr: TA_OPB_START set to 0x%x ]\n",
2119  (int) idata);
2120  DEFAULT_WRITE;
2121  }
2122  break;
2123 
2124  case PVRREG_TA_OB_START:
2125  if (writeflag == MEM_WRITE) {
2126  if (idata & ~TA_OB_START_MASK) {
2127  fatal("[ pvr: UNEXPECTED bits in "
2128  "TA_OB_START: 0x%08x ]\n", (int)idata);
2129  exit(1);
2130  }
2131  idata &= TA_OB_START_MASK;
2132  debug("[ pvr: TA_OB_START set to 0x%x ]\n",
2133  (int) idata);
2134  DEFAULT_WRITE;
2135  }
2136  break;
2137 
2138  case PVRREG_TA_OPB_END:
2139  if (writeflag == MEM_WRITE) {
2140  idata &= TA_OPB_END_MASK;
2141  debug("[ pvr: TA_OPB_END set to 0x%x ]\n",
2142  (int) idata);
2143  DEFAULT_WRITE;
2144  }
2145  break;
2146 
2147  case PVRREG_TA_OB_END:
2148  if (writeflag == MEM_WRITE) {
2149  idata &= TA_OB_END_MASK;
2150  debug("[ pvr: TA_OB_END set to 0x%x ]\n",
2151  (int) idata);
2152  DEFAULT_WRITE;
2153  }
2154  break;
2155 
2156  case PVRREG_TA_OPB_POS:
2157  if (writeflag == MEM_WRITE) {
2158  idata &= TA_OPB_POS_MASK;
2159  debug("[ pvr: TA_OPB_POS set to 0x%x ]\n",
2160  (int) idata);
2161  DEFAULT_WRITE;
2162  }
2163  break;
2164 
2165  case PVRREG_TA_OB_POS:
2166  if (writeflag == MEM_WRITE) {
2167  idata &= TA_OB_POS_MASK;
2168  debug("[ pvr: TA_OB_POS set to 0x%x ]\n",
2169  (int) idata);
2170  DEFAULT_WRITE;
2171  }
2172  break;
2173 
2174  case PVRREG_TA_OPL_INIT:
2175  if (writeflag == MEM_WRITE) {
2176  idata &= PVR_TA_OPL_INIT_MASK;
2177  debug("[ pvr: TA_OPL_INIT set to 0x%x ]\n",
2178  (int) idata);
2179  DEFAULT_WRITE;
2180  }
2181  break;
2182 
2183  case PVRREG_TILEBUF_SIZE:
2184  if (writeflag == MEM_WRITE) {
2188  d->tilebuf_xsize ++; d->tilebuf_ysize ++;
2189  debug("[ pvr: TILEBUF_SIZE set to %i x %i ]\n",
2190  d->tilebuf_xsize, d->tilebuf_ysize);
2191  DEFAULT_WRITE;
2192  }
2193  break;
2194 
2195  case PVRREG_TA_OPB_CFG:
2196  if (writeflag == MEM_WRITE) {
2197  debug("[ pvr: TA_OPB_CFG set to 0x%x ]\n",
2198  (int) idata);
2199  DEFAULT_WRITE;
2200  }
2201  break;
2202 
2203  case PVRREG_TA_INIT:
2204  if (writeflag == MEM_WRITE) {
2205  debug("[ pvr: TA_INIT ]\n");
2206 
2207  if (idata & PVR_TA_INIT)
2208  pvr_ta_init(cpu, d);
2209 
2210  if (idata != PVR_TA_INIT && idata != 0)
2211  fatal("{ TA_INIT = 0x%08" PRIx32" is not "
2212  "yet implemented! }", (int) idata);
2213 
2214  /* Always reset to 0. */
2215  idata = 0;
2216  DEFAULT_WRITE;
2217  }
2218  break;
2219 
2220  case PVRREG_YUV_STAT:
2221  // TODO. The "luftvarg" demo accesses this register.
2222  break;
2223 
2224  default:if (writeflag == MEM_READ) {
2225  fatal("[ pvr: read from UNIMPLEMENTED addr 0x%x ]\n",
2226  (int)relative_addr);
2227  } else {
2228  fatal("[ pvr: write to UNIMPLEMENTED addr 0x%x: 0x%x"
2229  " ]\n", (int)relative_addr, (int)idata);
2230  DEFAULT_WRITE;
2231  }
2232 
2233  exit(1);
2234  }
2235 
2236 return_ok:
2237  if (writeflag == MEM_READ)
2238  memory_writemax64(cpu, data, len, odata);
2239 
2240  return 1;
2241 }
2242 
2243 
2244 void pvr_extend_update_region(struct pvr_data *d, uint64_t low, uint64_t high)
2245 {
2246  int vram_ofs = REG(PVRREG_DIWADDRL);
2247  int bytes_per_line = d->xsize * d->bytes_per_pixel;
2248 
2249  low -= vram_ofs;
2250  high -= vram_ofs;
2251 
2252  /* Access inside visible part of VRAM? */
2253  if ((int64_t)high >= 0 && (int64_t)low <
2254  bytes_per_line * d->ysize) {
2255  int new_y1, new_y2;
2256 
2257  d->fb_update_x1 = 0;
2258  d->fb_update_x2 = d->xsize - 1;
2259 
2260  /* Calculate which line the low and high addresses
2261  correspond to: */
2262  new_y1 = low / bytes_per_line;
2263  new_y2 = high / bytes_per_line + 1;
2264 
2265  if (d->fb_update_y1 < 0 || new_y1 < d->fb_update_y1)
2266  d->fb_update_y1 = new_y1;
2267  if (d->fb_update_y2 < 0 || new_y2 > d->fb_update_y2)
2268  d->fb_update_y2 = new_y2;
2269 
2270  if (d->fb_update_y1 < 0)
2271  d->fb_update_y1 = 0;
2272  if (d->fb_update_y2 >= d->ysize)
2273  d->fb_update_y2 = d->ysize - 1;
2274  }
2275 }
2276 
2277 
2279 {
2280  struct pvr_data *d = (struct pvr_data *) extra;
2281  uint64_t high, low = (uint64_t)(int64_t) -1;
2282  int vram_ofs = REG(PVRREG_DIWADDRL), pixels_to_copy;
2283  int bytes_per_line = d->xsize * d->bytes_per_pixel;
2284  int fb_ofs, p;
2285  uint8_t *fb = (uint8_t *) d->fb->framebuffer;
2286  uint8_t *vram = (uint8_t *) d->vram;
2287 
2288 
2289  /*
2290  * Vertical retrace interrupts:
2291  *
2292  * TODO: Maybe it would be even more realistic to have the timer run
2293  * at, say, 60*4 = 240 Hz, and have the following events:
2294  *
2295  * (tick & 3) == 0 SYSASIC_EVENT_VBLINT
2296  * (tick & 3) == 1 SYSASIC_EVENT_PVR_SCANINT1
2297  * (tick & 3) == 2 nothing
2298  * (tick & 3) == 3 SYSASIC_EVENT_PVR_SCANINT2
2299  */
2300  if (d->vblank_interrupts_pending > 0) {
2302 
2305 
2306  // Is this needed?
2308 
2309  /* TODO: For now, I don't care about missed interrupts: */
2311  }
2312 
2313 
2314  /*
2315  * Framebuffer update:
2316  */
2317 
2318  /* Border changed? */
2319  if (d->border_updated) {
2320  /* Fill border with border color: */
2321  int rgb = REG(PVRREG_BRDCOLR), addr = 0;
2322  int x, y, b = rgb & 0xff, g = (rgb >> 8) & 0xff, r = rgb >> 16;
2323  int skiplen = (d->fb->xsize-2*PVR_MARGIN) * d->fb->bit_depth/8;
2324 
2325  for (y=0; y<d->fb->ysize; y++) {
2326  int xskip = y < PVR_MARGIN || y >=
2327  d->fb->ysize - PVR_MARGIN? -1 : PVR_MARGIN;
2328  for (x=0; x<d->fb->xsize; x++) {
2329  if (x == xskip) {
2330  x = d->fb->xsize - PVR_MARGIN;
2331  addr += skiplen;
2332  }
2333  fb[addr] = r;
2334  fb[addr+1] = g;
2335  fb[addr+2] = b;
2336  addr += 3;
2337  }
2338  }
2339 
2340  /* Full redraw of the framebuffer: */
2341  d->fb->update_x1 = 0; d->fb->update_x2 = d->fb->xsize - 1;
2342  d->fb->update_y1 = 0; d->fb->update_y2 = d->fb->ysize - 1;
2343  }
2344 
2345  memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high);
2346  if ((int64_t)low != -1)
2347  pvr_extend_update_region(d, low, high);
2348 
2349  if (d->fb_update_x1 == -1)
2350  return;
2351 
2352  /* Copy (part of) the VRAM to the framebuffer: */
2353  if (d->fb_update_x2 >= d->xsize)
2354  d->fb_update_x2 = d->xsize - 1;
2355  if (d->fb_update_y2 >= d->ysize)
2356  d->fb_update_y2 = d->ysize - 1;
2357 
2358  vram_ofs += d->fb_update_y1 * bytes_per_line;
2359  vram_ofs += d->fb_update_x1 * d->bytes_per_pixel;
2360  pixels_to_copy = (d->fb_update_x2 - d->fb_update_x1 + 1);
2361  fb_ofs = (d->fb_update_y1 + PVR_MARGIN) * d->fb->bytes_per_line;
2362  fb_ofs += (d->fb_update_x1 + PVR_MARGIN) * d->fb->bit_depth / 8;
2363 
2364  /* Copy the actual pixels: (Four manually inlined, for speed.) */
2365 
2366  switch (d->pixelmode) {
2367  case 0: /* RGB0555 (16-bit) */
2368  {
2369  int y;
2370  for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
2371  int fo = fb_ofs, vo = vram_ofs;
2372  for (p=0; p<pixels_to_copy; p++) {
2373  /* 0rrrrrgg(high) gggbbbbb(low) */
2374  fb[fo] = (vram[(vo+1)%VRAM_SIZE] << 1) & 0xf8;
2375  fb[fo+1] = ((vram[vo%VRAM_SIZE] >> 2) & 0x38) +
2376  (vram[(vo+1)%VRAM_SIZE] << 6);
2377  fb[fo+2] = (vram[vo%VRAM_SIZE] & 0x1f) << 3;
2378  fo += 3; vo += 2;
2379  }
2380 
2381  vram_ofs += bytes_per_line;
2382  fb_ofs += d->fb->bytes_per_line;
2383  }
2384  }
2385  break;
2386 
2387  case 1: /* RGB565 (16-bit) */
2388  {
2389  int y;
2390  for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
2391  int fo = fb_ofs, vo = vram_ofs;
2392  for (p=0; p<pixels_to_copy; p++) {
2393  /* rrrrrggg(high) gggbbbbb(low) */
2394  fb[fo] = vram[(vo+1)%VRAM_SIZE] & 0xf8;
2395  fb[fo+1] = ((vram[vo%VRAM_SIZE] >> 3) & 0x1c) +
2396  (vram[(vo+1)%VRAM_SIZE] << 5);
2397  fb[fo+2] = (vram[vo%VRAM_SIZE] & 0x1f) << 3;
2398  fo += 3; vo += 2;
2399  }
2400 
2401  vram_ofs += bytes_per_line;
2402  fb_ofs += d->fb->bytes_per_line;
2403  }
2404  }
2405  break;
2406 
2407  case 2: /* RGB888 (24-bit) */
2408  {
2409  int y;
2410  for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
2411  /* TODO: Reverse colors, like in the 32-bit case? */
2412  memcpy(fb+fb_ofs, vram+(vram_ofs%VRAM_SIZE), 3*pixels_to_copy);
2413  vram_ofs += bytes_per_line;
2414  fb_ofs += d->fb->bytes_per_line;
2415  }
2416  }
2417  break;
2418 
2419  case 3: /* RGB0888 (32-bit) */
2420  {
2421  int y;
2422  for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
2423  int fo = fb_ofs, vo = vram_ofs;
2424  for (p=0; p<pixels_to_copy; p++) {
2425  fb[fo] = vram[(vo+2)%VRAM_SIZE];
2426  fb[fo+1] = vram[(vo+1)%VRAM_SIZE];
2427  fb[fo+2] = vram[(vo+0)%VRAM_SIZE];
2428  fo += 3; vo += 4;
2429  }
2430 
2431  vram_ofs += bytes_per_line;
2432  fb_ofs += d->fb->bytes_per_line;
2433  }
2434  }
2435  break;
2436  }
2437 
2438  /*
2439  * Extend the real framebuffer to encompass the area
2440  * just written to:
2441  */
2442 
2443  /* Offset to take the margin into account first... */
2446 
2447  if (d->fb_update_x1 < d->fb->update_x1 || d->fb->update_x1 < 0)
2448  d->fb->update_x1 = d->fb_update_x1;
2449  if (d->fb_update_x2 > d->fb->update_x2 || d->fb->update_x2 < 0)
2450  d->fb->update_x2 = d->fb_update_x2;
2451  if (d->fb_update_y1 < d->fb->update_y1 || d->fb->update_y1 < 0)
2452  d->fb->update_y1 = d->fb_update_y1;
2453  if (d->fb_update_y2 > d->fb->update_y2 || d->fb->update_y2 < 0)
2454  d->fb->update_y2 = d->fb_update_y2;
2455 
2456  /* Clear the PVR's update region: */
2457  d->fb_update_x1 = d->fb_update_x2 =
2458  d->fb_update_y1 = d->fb_update_y2 = -1;
2459 }
2460 
2461 
2462 DEVICE_ACCESS(pvr_vram_alt)
2463 {
2464  struct pvr_data_alt *d_alt = (struct pvr_data_alt *) extra;
2465  struct pvr_data *d = d_alt->d;
2466  size_t i;
2467 
2468  if (writeflag == MEM_READ) {
2469  /* Copy from real vram: */
2470  for (i=0; i<len; i++) {
2471  int addr = relative_addr + i;
2472  addr = ((addr & 4) << 20) | (addr & 3)
2473  | ((addr & 0x7ffff8) >> 1);
2474  data[i] = d->vram[addr % VRAM_SIZE];
2475  }
2476  return 1;
2477  }
2478 
2479  // Writes are only allowed as 16-bit access or higher.
2480  if (len < sizeof(uint16_t))
2481  fatal("pvr_vram_alt: write of less than 16 bits attempted?\n");
2482 
2483  /*
2484  * Convert writes to alternative VRAM, into normal writes:
2485  */
2486 
2487  for (i=0; i<len; i++) {
2488  int addr = relative_addr + i;
2489  addr = ((addr & 4) << 20) | (addr & 3) | ((addr & 0x7ffff8) >> 1);
2490  // printf(" %08x => alt addr %08x: %02x\n", (int)(relative_addr + i), (int)addr, data[i]);
2491  d->vram[addr % VRAM_SIZE] = data[i];
2492 
2493  // TODO: This is probably ultra-slow. (Should not be called
2494  // for every _byte_.)
2495  pvr_extend_update_region(d, addr, addr);
2496  }
2497 
2498  return 1;
2499 }
2500 
2501 
2502 DEVICE_ACCESS(pvr_vram)
2503 {
2504  struct pvr_data *d = (struct pvr_data *) extra;
2505 
2506  // According to http://mc.pp.se/dc/pvr.html, reads of any size are
2507  // allowed.
2508  if (writeflag == MEM_READ) {
2509  memcpy(data, d->vram + relative_addr, len);
2510  return 1;
2511  }
2512 
2513  // However, writes are only allowed as 16-bit access or higher.
2514  if (len < sizeof(uint16_t))
2515  fatal("pvr_vram: write of less than 16 bits attempted?\n");
2516 
2517  /*
2518  * Write to VRAM:
2519  *
2520  * Calculate which part of the framebuffer this write corresponds to,
2521  * if any, and increase the update region to encompass the written
2522  * memory range.
2523  */
2524 
2525  memcpy(d->vram + relative_addr, data, len);
2526  pvr_extend_update_region(d, relative_addr, relative_addr + len - 1);
2527 
2528  return 1;
2529 }
2530 
2531 
2533 {
2534  struct machine *machine = devinit->machine;
2535  struct pvr_data *d;
2536  struct pvr_data_alt *d_alt;
2537 
2538  CHECK_ALLOCATION(d = (struct pvr_data *) malloc(sizeof(struct pvr_data)));
2539  memset(d, 0, sizeof(struct pvr_data));
2540 
2541  CHECK_ALLOCATION(d_alt = (struct pvr_data_alt *) malloc(sizeof(struct pvr_data_alt)));
2542  memset(d_alt, 0, sizeof(struct pvr_data_alt));
2543 
2544  d_alt->d = d;
2545 
2547  PVRREG_REGSTART, PVRREG_REGSIZE, dev_pvr_access, d,
2548  DM_DEFAULT, NULL);
2549 
2550  /* 8 MB video RAM: */
2551  d->vram = (uint8_t *) zeroed_alloc(VRAM_SIZE);
2552  memory_device_register(machine->memory, "pvr_vram", 0x05000000,
2553  VRAM_SIZE, dev_pvr_vram_access, (void *)d,
2555  | DM_READS_HAVE_NO_SIDE_EFFECTS, d->vram);
2556 
2557  /* 8 MB video RAM, when accessed at 0xa4000000: */
2558  memory_device_register(machine->memory, "pvr_alt_vram", 0x04000000,
2559  VRAM_SIZE, dev_pvr_vram_alt_access, (void *)d_alt,
2560  DM_DEFAULT, NULL);
2561 
2562  /* Tile Accelerator command area at 0x10000000: */
2563  memory_device_register(machine->memory, "pvr_ta",
2564  0x10000000, 0x800000, dev_pvr_ta_access, d, DM_DEFAULT, NULL);
2565 
2566  /* PVR2 DMA registers at 0x5f6800: */
2567  memory_device_register(machine->memory, "pvr_dma", 0x005f6800,
2568  PVR_DMA_MEMLENGTH, dev_pvr_dma_access, d, DM_DEFAULT, NULL);
2569 
2570  /* More DMA registers at 0x5f7c00: */
2571  memory_device_register(machine->memory, "pvr_dma_more", 0x005f7c00,
2572  PVR_DMA_MEMLENGTH, dev_pvr_dma_more_access, d, DM_DEFAULT, NULL);
2573 
2574  d->xsize = 640;
2575  d->ysize = 480;
2576  d->pixelmode = 1; /* RGB565 */
2577  d->bytes_per_pixel = 2;
2578 
2579  d->fb = dev_fb_init(machine, machine->memory, INTERNAL_FB_ADDR,
2580  VFB_GENERIC, d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2,
2581  d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2,
2582  24, "Dreamcast PVR");
2583 
2584  d->vblank_timer = timer_add(PVR_VBLANK_HZ, pvr_vblank_timer_tick, d);
2585 
2586  pvr_reset(d);
2587  pvr_reset_ta(d);
2588 
2589  machine_add_tickfunction(machine, dev_pvr_fb_tick, d,
2591 
2592  return 1;
2593 }
2594 
#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:2244
#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:2278
#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:1515
#define PVRREG_TILEBUF_ADDR
int video_enabled
Definition: dev_pvr.cc:126
DEVINIT(pvr)
Definition: dev_pvr.cc:2532
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
vmrs t
Definition: armreg.h:750
#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 Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13