/[gxemul]/trunk/src/devices/dev_pvr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_pvr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (show annotations)
Mon Oct 8 16:22:11 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 31632 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1539 2007/05/01 04:03:51 debug Exp $
20070415	Landisk PCLOCK should be 33.33 MHz, not 50 MHz. (This makes
		the clock run at correct speed.)
		FINALLY found and fixed the bug which caused OpenBSD/landisk
		to randomly bug out: an &-sign was missing in the special case
		handling of FPSCR in the 'LDS.L @Rm+,FPSCR' instruction.
		Adding similar special case handling for 'LDC.L @Rm+,SR'
		(calling sh_update_sr() instead of just loading).
		Implementing the 'FCNVSD FPUL,DRn' and 'FCNVDS DRm,FPUL'
		SuperH instructions.
		The 'LDC Rm,SR' instruction now immediately breaks out of the
		dyntrans loop if an interrupt is to be triggered.
20070416	In memory_rw.c, if mapping a page as writable, make sure to
		invalidate code translations even if the data access was a
		read.
		Minor SuperH updates.
20070418	Removing the dummy M68K emulation mode.
		Minor SH update (turning unnecessary sts_mach_rn, sts_macl_rn,
		and sts_pr_rn instruction handlers into mov_rm_rn).
20070419	Beginning to add a skeleton for an M88K mode: Adding a hack to
		allow OpenBSD/m88k a.out binaries to be loaded, and disassembly
		of a few simple 88K instructions.
		Commenting out the 'LDC Rm,SR' fix from a few days ago, because
		it made Linux/dreamcast bug out.
		Adding a hack to dev_sh4.c (an extra translation cache
		invalidation), which allows OpenBSD/landisk to boot ok after
		an install. Upgrading the Landisk machine mode to stable,
		updating documentation, etc.
20070420	Experimenting with adding a PCI controller (pcic) to dev_sh4.
		Adding a dummy Realtek 8139C+ skeleton device (dev_rtl8139c).
		Implementing the first M88K instructions (br, or[.u] imm), and
		adding disassembly of some more instructions.
20070421	Continuing a little on dev_rtl8139c.
20070422	Implementing the 9346 EEPROM "read" command for dev_rtl8139c.
		Finally found and fixed an old bug in the log n symbol search
		(it sometimes missed symbols). Debug trace (-i, -t etc) should
		now show more symbols. :-)
20070423	Continuing a little on M88K disassembly.
20070428	Fixing a memset arg order bug in src/net/net.c (thanks to
		Nigel Horne for noticing the bug).
		Applying parts of a patch from Carl van Schaik to clear out
		bottom bits of MIPS addresses more correctly, when using large
		page sizes, and doing some other minor cleanup/refactoring.
		Fixing a couple of warnings given by gcc with the -W option (a
		few more warnings than just plain -Wall).
		Reducing SuperH dyntrans physical address space from 64-bit to
		32-bit (since SH5/SH64 isn't imlemented yet anyway).
		Adding address-to-symbol annotation to a few more instructions
		in the SuperH instruction trace output.
		Beginning regression testing for the next release.
		Reverting the value of SCIF_DELAYED_TX_VALUE from 1 to 2,
		because OpenBSD/landisk may otherwise hang randomly.
20070429	The ugly hack/workaround to get OpenBSD/landisk booting without
		crashing does NOT work anymore (with the April 21 snapshot
		of OpenBSD/landisk). Strangely enough, removing the hack
		completely causes OpenBSD/landisk to work (!).
		More regression testing (re-testing everything SuperH-related,
		and some other things).
		Cobalt interrupts were actually broken; fixing by commenting
		out the DEC21143s in the Cobalt machine.
20070430	More regression testing.
20070501	Updating the OpenBSD/landisk install instructions to use
		4.1 instead of the current snapshot.
		GAAAH! OpenBSD/landisk 4.1 _needs_ the ugly hack/workaround;
		reintroducing it again. (The 4.1 kernel is actually from
		2007-03-11.)
		Simplifying the NetBSD/evbarm install instructions a bit.
		More regression testing.

==============  RELEASE 0.4.5.1  ==============


1 /*
2 * Copyright (C) 2006-2007 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 * $Id: dev_pvr.c,v 1.21 2007/04/28 09:19:52 debug Exp $
29 *
30 * PowerVR CLX2 (Graphics controller used in the Dreamcast). Implemented by
31 * reading http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt and
32 * http://mc.pp.se/dc/pvr.html, source code of various demos and KalistOS,
33 * and doing a lot of 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 * Color clipping.
43 * Wire-frame when running on a host without XGL?
44 *
45 * Multiple lists of various kinds (6?).
46 * Lists growing downwards!
47 * Pixel clip for rendering.
48 * Real Rendering, using OpenGL if possible.
49 * Tile bins... with 6 pointers for each tile (?)
50 * PVR DMA.
51 */
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56
57 #include "cpu.h"
58 #include "device.h"
59 #include "devices.h"
60 #include "float_emul.h"
61 #include "machine.h"
62 #include "memory.h"
63 #include "misc.h"
64 #include "timer.h"
65
66 #include "dreamcast_pvr.h"
67 #include "dreamcast_sysasicvar.h"
68
69
70 #define debug fatal
71
72 #define INTERNAL_FB_ADDR 0x300000000ULL
73 #define PVR_FB_TICK_SHIFT 19
74
75 #define PVR_VBLANK_HZ 60.0
76 #define PVR_MARGIN 16
77
78 struct pvr_data {
79 struct vfb_data *fb;
80 int fb_update_x1;
81 int fb_update_y1;
82 int fb_update_x2;
83 int fb_update_y2;
84
85 struct timer *vblank_timer;
86 int vblank_interrupts_pending;
87
88 /* PVR registers: */
89 uint32_t reg[PVRREG_REGSIZE / sizeof(uint32_t)];
90
91 /* Calculated by pvr_geometry_updated(): */
92 int xsize, ysize;
93 int bytes_per_pixel;
94
95 /* Cached values (from registers): */
96 /* DIWMODE: */
97 int clock_double;
98 int strip_buffer_enabled;
99 int strip_length;
100 int argb8888_threshold;
101 int extend;
102 int pixelmode;
103 int line_double;
104 int display_enabled;
105 /* BRDCOLR: */
106 int border_updated;
107 /* SYNCCONF: */
108 int video_enabled;
109 int broadcast_standard;
110 int interlaced;
111 int h_sync_positive;
112 int v_sync_positive;
113 /* TILEBUF_SIZE: */
114 int tilebuf_xsize;
115 int tilebuf_ysize;
116
117 /* Tile Accelerator Command: */
118 uint32_t ta[64 / sizeof(uint32_t)];
119
120 uint8_t *vram;
121 uint8_t *vram_alt;
122 };
123
124 struct pvr_data_alt {
125 struct pvr_data *d;
126 };
127
128
129 #define REG(x) (d->reg[(x)/sizeof(uint32_t)])
130 #define DEFAULT_WRITE REG(relative_addr) = idata;
131
132
133 /*
134 * pvr_fb_invalidate():
135 */
136 static void pvr_fb_invalidate(struct pvr_data *d, int start, int stop)
137 {
138 d->fb_update_x1 = d->fb_update_y1 = 0;
139 d->fb_update_x2 = d->xsize - 1;
140 d->fb_update_y2 = d->ysize - 1;
141 }
142
143
144 /*
145 * pvr_vblank_timer_tick():
146 *
147 * This function is called PVR_VBLANK_HZ times per real-world second. Its job
148 * is to fake vertical retrace interrupts.
149 */
150 static void pvr_vblank_timer_tick(struct timer *t, void *extra)
151 {
152 struct pvr_data *d = (struct pvr_data *) extra;
153 d->vblank_interrupts_pending ++;
154 }
155
156
157 /*
158 * pvr_geometry_updated():
159 *
160 * This function should be called every time a register is written to which
161 * affects the framebuffer geometry (size, bit-depth, starting position, etc).
162 */
163 static void pvr_geometry_updated(struct pvr_data *d)
164 {
165 /* Make sure to redraw border on geometry changes. */
166 d->border_updated = 1;
167
168 d->xsize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK;
169 d->ysize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK;
170
171 /* E.g. 319x479 => 320x480 */
172 d->xsize = (d->xsize + 1) * sizeof(uint32_t);
173 d->ysize ++;
174
175 switch (d->pixelmode) {
176 case 0:
177 case 1: d->bytes_per_pixel = 2; break;
178 case 2: d->bytes_per_pixel = 3; break;
179 case 3: d->bytes_per_pixel = 4; break;
180 }
181
182 d->xsize /= d->bytes_per_pixel;
183
184 if (REG(PVRREG_DIWCONF) & DIWCONF_LR)
185 d->xsize /= 2;
186
187 if (d->line_double)
188 d->ysize /= 2;
189
190 /* Only show geometry debug message if output is enabled: */
191 if (!d->video_enabled || !d->display_enabled)
192 return;
193
194 debug("[ pvr_geometry_updated: %i x %i, ", d->xsize, d->ysize);
195
196 switch (d->pixelmode) {
197 case 0: debug("RGB0555 (16-bit)"); break;
198 case 1: debug("RGB565 (16-bit)"); break;
199 case 2: debug("RGB888 (24-bit)"); break;
200 case 3: debug("RGB0888 (32-bit)"); break;
201 }
202
203 debug(" ]\n");
204 }
205
206
207 /* Ugly quick-hack: */
208 static void line(struct pvr_data *d, int x1, int y1, int x2, int y2)
209 {
210 int fb_base = REG(PVRREG_FB_RENDER_ADDR1);
211 int i;
212 for (i=0; i<256; i++) {
213 int px = (i * x2 + (256-i) * x1) >> 8;
214 int py = (i * y2 + (256-i) * y1) >> 8;
215 if (px > 0 && py > 0 && px < d->xsize && py < d->ysize) {
216 d->vram[fb_base + (px + py * d->xsize)*
217 d->bytes_per_pixel] = 255;
218 d->vram[fb_base + (px + py * d->xsize)*
219 d->bytes_per_pixel + 1] = 255;
220 }
221 }
222 }
223
224
225 /*
226 * pvr_render():
227 *
228 * Render from the Object Buffer to the framebuffer.
229 *
230 * TODO: This function is totally bogus so far, the format of the Object
231 * Buffer is just a quick made-up hack to see if it works at all.
232 */
233 static void pvr_render(struct cpu *cpu, struct pvr_data *d)
234 {
235 int ob_ofs = REG(PVRREG_OB_ADDR);
236 int fb_base = REG(PVRREG_FB_RENDER_ADDR1);
237 int wf_point_nr, texture = 0;
238 int wf_x[4], wf_y[4];
239
240 debug("[ pvr_render: rendering to FB offset 0x%x ]\n", fb_base);
241
242 /* Clear all pixels first: */
243 /* TODO */
244 memset(d->vram + fb_base, 0, d->xsize * d->ysize * d->bytes_per_pixel);
245
246 wf_point_nr = 0;
247
248 for (;;) {
249 uint8_t cmd = d->vram[ob_ofs];
250
251 if (cmd == 0)
252 break;
253 else if (cmd == 1) {
254 int16_t px = d->vram[ob_ofs+2] + d->vram[ob_ofs+3]*256;
255 int16_t py = d->vram[ob_ofs+4] + d->vram[ob_ofs+5]*256;
256
257 wf_x[wf_point_nr] = px;
258 wf_y[wf_point_nr] = py;
259
260 wf_point_nr ++;
261 if (wf_point_nr == 4) {
262 #if 1
263 line(d, wf_x[0], wf_y[0], wf_x[1], wf_y[1]);
264 line(d, wf_x[0], wf_y[0], wf_x[2], wf_y[2]);
265 line(d, wf_x[1], wf_y[1], wf_x[3], wf_y[3]);
266 line(d, wf_x[2], wf_y[2], wf_x[3], wf_y[3]);
267 wf_point_nr = 0;
268 wf_x[0] = wf_x[2]; wf_y[0] = wf_y[2];
269 wf_x[1] = wf_x[3]; wf_y[1] = wf_y[3];
270 #else
271 draw_texture(d, wf_x[0], wf_y[0],
272 wf_x[1], wf_y[1],
273 wf_x[2], wf_y[2],
274 wf_x[3], wf_y[3], texture);
275 #endif
276 }
277
278 } else if (cmd == 2) {
279 wf_point_nr = 0;
280 texture = d->vram[ob_ofs+4] + (d->vram[ob_ofs+5]
281 << 8) + (d->vram[ob_ofs+6] << 16) +
282 (d->vram[ob_ofs+7] << 24);
283 texture <<= 3;
284 texture &= 0x7fffff;
285 printf("TEXTURE = %x\n", texture);
286 } else {
287 fatal("pvr_render: internal error, unknown cmd\n");
288 }
289
290 ob_ofs += sizeof(uint64_t);
291 }
292
293 SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_RENDERDONE);
294 }
295
296
297 /*
298 * pvr_reset_ta():
299 *
300 * Reset the Tile Accelerator.
301 */
302 static void pvr_reset_ta(struct pvr_data *d)
303 {
304 REG(PVRREG_DIWCONF) = DIWCONF_MAGIC;
305 }
306
307
308 /*
309 * pvr_reset():
310 *
311 * Reset the PVR.
312 */
313 static void pvr_reset(struct pvr_data *d)
314 {
315 /* TODO */
316 }
317
318
319 /*
320 * pvr_ta_init():
321 *
322 * Initialize the Tile Accelerator. This makes the TA ready to receive
323 * commands (via address 0x10000000).
324 */
325 static void pvr_ta_init(struct cpu *cpu, struct pvr_data *d)
326 {
327 REG(PVRREG_TA_OPB_POS) = REG(PVRREG_TA_OPB_START);
328 REG(PVRREG_TA_OB_POS) = REG(PVRREG_TA_OB_START);
329 }
330
331
332 /*
333 * pvr_ta_command():
334 *
335 * Read a command (e.g. parts of a polygon primitive) from d->ta[], and output
336 * "compiled commands" into the Object list and Object Pointer list.
337 */
338 static void pvr_ta_command(struct cpu *cpu, struct pvr_data *d, int list_ofs)
339 {
340 int ob_ofs;
341 int16_t x, y;
342 uint32_t *ta = &d->ta[list_ofs];
343
344 #if 0
345 /* Dump the Tile Accelerator command for debugging: */
346 {
347 int i;
348 fatal("TA cmd:");
349 for (i=0; i<8; i++)
350 fatal(" %08x", (int) ta[i]);
351 fatal("\n");
352 }
353 #endif
354
355 /*
356 * TODO: REWRITE!!!
357 *
358 * THis is just a quick hack to see if I can get out at least
359 * the pixel coordinates.
360 */
361
362 {
363 struct ieee_float_value fx, fy;
364 ieee_interpret_float_value(ta[1], &fx, IEEE_FMT_S);
365 ieee_interpret_float_value(ta[2], &fy, IEEE_FMT_S);
366 x = fx.f; y = fy.f;
367 }
368
369 ob_ofs = REG(PVRREG_TA_OB_POS);
370
371 switch (ta[0] >> 28) {
372 case 0x8:
373 d->vram[ob_ofs + 0] = 2;
374 d->vram[ob_ofs + 4] = ta[3];
375 d->vram[ob_ofs + 5] = ta[3] >> 8;
376 d->vram[ob_ofs + 6] = ta[3] >> 16;
377 d->vram[ob_ofs + 7] = ta[3] >> 24;
378 REG(PVRREG_TA_OB_POS) = ob_ofs + sizeof(uint64_t);
379 break;
380 case 0xe:
381 case 0xf:
382 /* Point. */
383 d->vram[ob_ofs + 0] = 1;
384 d->vram[ob_ofs + 2] = x & 255;
385 d->vram[ob_ofs + 3] = x >> 8;
386 d->vram[ob_ofs + 4] = y & 255;
387 d->vram[ob_ofs + 5] = y >> 8;
388 REG(PVRREG_TA_OB_POS) = ob_ofs + sizeof(uint64_t);
389 break;
390 case 0x0:
391 if (ta[1] == 0) {
392 /* End of list. */
393 uint32_t opb_cfg = REG(PVRREG_TA_OPB_CFG);
394 d->vram[ob_ofs + 0] = 0;
395 REG(PVRREG_TA_OB_POS) = ob_ofs + sizeof(uint64_t);
396 if (opb_cfg & TA_OPB_CFG_OPAQUEPOLY_MASK)
397 SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_OPAQUEDONE);
398 if (opb_cfg & TA_OPB_CFG_OPAQUEMOD_MASK)
399 SYSASIC_TRIGGER_EVENT(
400 SYSASIC_EVENT_OPAQUEMODDONE);
401 if (opb_cfg & TA_OPB_CFG_TRANSPOLY_MASK)
402 SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_TRANSDONE);
403 if (opb_cfg & TA_OPB_CFG_TRANSMOD_MASK)
404 SYSASIC_TRIGGER_EVENT(
405 SYSASIC_EVENT_TRANSMODDONE);
406 if (opb_cfg & TA_OPB_CFG_PUNCHTHROUGH_MASK)
407 SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_PVR_PTDONE);
408 }
409 break;
410 case 2: /* Ignore for now. */
411 case 3: /* Ignore for now. */
412 /* TODO */
413 break;
414 default:fatal("Unimplemented top TA nibble %i\n", ta[0] >> 28);
415 exit(1);
416 }
417 }
418
419
420 DEVICE_ACCESS(pvr_ta)
421 {
422 struct pvr_data *d = (struct pvr_data *) extra;
423 uint64_t idata = 0, odata = 0;
424
425 if (writeflag == MEM_WRITE) {
426 idata = memory_readmax64(cpu, data, len);
427
428 /* Write to the tile accelerator command buffer: */
429 d->ta[relative_addr / sizeof(uint32_t)] = idata;
430
431 /* Execute the command, after a complete write: */
432 if (relative_addr == 0x1c)
433 pvr_ta_command(cpu, d, 0);
434 if (relative_addr == 0x3c)
435 pvr_ta_command(cpu, d, 8);
436 } else {
437 odata = d->ta[relative_addr / sizeof(uint32_t)];
438 memory_writemax64(cpu, data, len, odata);
439 }
440
441 return 1;
442 }
443
444
445 DEVICE_ACCESS(pvr)
446 {
447 struct pvr_data *d = (struct pvr_data *) extra;
448 uint64_t idata = 0, odata = 0;
449
450 if (writeflag == MEM_WRITE)
451 idata = memory_readmax64(cpu, data, len);
452
453 /* Default read action: Read from reg[]: */
454 if (writeflag == MEM_READ)
455 odata = d->reg[relative_addr / sizeof(uint32_t)];
456
457 /* Fog table access: */
458 if (relative_addr >= PVRREG_FOG_TABLE &&
459 relative_addr < PVRREG_FOG_TABLE + PVR_FOG_TABLE_SIZE) {
460 if (writeflag == MEM_WRITE)
461 DEFAULT_WRITE;
462 goto return_ok;
463 }
464
465 switch (relative_addr) {
466
467 case PVRREG_ID:
468 /* ID for Set 5.xx versions of the Dreamcast, according
469 to http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt: */
470 odata = 0x17fd11db;
471 break;
472
473 case PVRREG_REVISION:
474 /* Revision 1.1, for Dreamcast Set 5.2x. */
475 odata = 0x00000011;
476 break;
477
478 case PVRREG_RESET:
479 if (writeflag == MEM_WRITE) {
480 if (idata != 0) {
481 debug("[ pvr: RESET ");
482 if (idata & PVR_RESET_PVR)
483 pvr_reset(d);
484 if (idata & PVR_RESET_TA)
485 pvr_reset_ta(d);
486 debug("]\n");
487 }
488 idata = 0;
489 DEFAULT_WRITE;
490 }
491 break;
492
493 case PVRREG_STARTRENDER:
494 if (writeflag == MEM_WRITE) {
495 debug("[ pvr: STARTRENDER ]\n");
496 pvr_render(cpu, d);
497 } else {
498 fatal("[ pvr: huh? read from STARTRENDER ]\n");
499 }
500 break;
501
502 case PVRREG_OB_ADDR:
503 if (writeflag == MEM_WRITE) {
504 debug("[ pvr: OB_ADDR set to 0x%08"PRIx32" ]\n",
505 (uint32_t)(idata & PVR_OB_ADDR_MASK));
506 /* if (idata & ~PVR_OB_ADDR_MASK) {
507 fatal("[ pvr: OB_ADDR: Fatal error: Unknown"
508 " bits set: 0x%08"PRIx32" ]\n",
509 (uint32_t)(idata & ~PVR_OB_ADDR_MASK));
510 exit(1);
511 }
512 idata &= PVR_OB_ADDR_MASK;
513 */
514 DEFAULT_WRITE;
515 }
516 break;
517
518 case PVRREG_TILEBUF_ADDR:
519 if (writeflag == MEM_WRITE) {
520 debug("[ pvr: TILEBUF_ADDR set to 0x%08"PRIx32" ]\n",
521 (uint32_t)(idata & PVR_TILEBUF_ADDR_MASK));
522 if (idata & ~PVR_TILEBUF_ADDR_MASK)
523 fatal("[ pvr: TILEBUF_ADDR: WARNING: Unknown"
524 " bits set: 0x%08"PRIx32" ]\n",
525 (uint32_t)(idata & ~PVR_TILEBUF_ADDR_MASK));
526 idata &= PVR_TILEBUF_ADDR_MASK;
527 DEFAULT_WRITE;
528 }
529 break;
530
531 case PVRREG_SPANSORT:
532 if (writeflag == MEM_WRITE) {
533 debug("[ pvr: SPANSORT: ");
534 if (idata & PVR_SPANSORT_SPAN0)
535 debug("SPAN0 ");
536 if (idata & PVR_SPANSORT_SPAN1)
537 debug("SPAN1 ");
538 if (idata & PVR_SPANSORT_TSP_CACHE_ENABLE)
539 debug("TSP_CACHE_ENABLE ");
540 debug("]\n");
541 DEFAULT_WRITE;
542 }
543 break;
544
545 case PVRREG_BRDCOLR:
546 if (writeflag == MEM_WRITE) {
547 debug("[ pvr: BRDCOLR set to 0x%06"PRIx32" ]\n",
548 (int)idata);
549 DEFAULT_WRITE;
550 d->border_updated = 1;
551 }
552 break;
553
554 case PVRREG_DIWMODE:
555 if (writeflag == MEM_WRITE) {
556 d->clock_double = idata & DIWMODE_C_MASK? 1:0;
557 d->strip_buffer_enabled = idata & DIWMODE_SE_MASK? 1:0;
558 d->strip_length = (idata & DIWMODE_SL_MASK)
559 >> DIWMODE_SL_SHIFT;
560 d->argb8888_threshold = (idata & DIWMODE_TH_MASK)
561 >> DIWMODE_TH_SHIFT;
562 d->extend = (idata & DIWMODE_EX_MASK)
563 >> DIWMODE_EX_SHIFT;
564 d->pixelmode = (idata & DIWMODE_COL_MASK)
565 >> DIWMODE_COL_SHIFT;
566 d->line_double = idata & DIWMODE_SD_MASK? 1:0;
567 d->display_enabled = idata & DIWMODE_DE_MASK? 1:0;
568
569 debug("[ pvr: DIWMODE set to: ");
570 debug("clock_double=%i, ", d->clock_double);
571 debug("strip_buffer_enabled=%i, ",
572 d->strip_buffer_enabled);
573 debug("strip_length=%i, ", d->strip_length);
574 debug("argb8888_threshold=%i, ", d->argb8888_threshold);
575 debug("extend=0x%x, ", d->extend);
576 debug("pixelmode=");
577 switch (d->pixelmode) {
578 case 0: debug("RGB0555 (16-bit)"); break;
579 case 1: debug("RGB565 (16-bit)"); break;
580 case 2: debug("RGB888 (24-bit)"); break;
581 case 3: debug("RGB0888 (32-bit)"); break;
582 }
583 debug(", line_double=%i, ", d->line_double);
584 debug("display_enabled=%i", d->display_enabled);
585 debug(" ]\n");
586
587 DEFAULT_WRITE;
588 pvr_geometry_updated(d);
589 pvr_fb_invalidate(d, -1, -1);
590 }
591 break;
592
593 case PVRREG_DIWSIZE:
594 if (writeflag == MEM_WRITE) {
595 debug("[ pvr: DIWSIZE set to modulo=%i, "
596 "width=%i, height=%i ]\n", (int)
597 ((idata >> DIWSIZE_MODULO_SHIFT) & DIWSIZE_MASK),
598 (int)((idata >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK),
599 (int)((idata >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK));
600 DEFAULT_WRITE;
601 pvr_geometry_updated(d);
602 pvr_fb_invalidate(d, -1, -1);
603 }
604 break;
605
606 case PVRREG_FB_RENDER_ADDR1:
607 if (writeflag == MEM_WRITE) {
608 debug("[ pvr: FB_RENDER_ADDR1 set to 0x%08"PRIx32
609 " ]\n", (int) idata);
610 DEFAULT_WRITE;
611 }
612 break;
613
614 case PVRREG_FB_RENDER_ADDR2:
615 if (writeflag == MEM_WRITE) {
616 debug("[ pvr: FB_RENDER_ADDR2 set to 0x%08"PRIx32
617 " ]\n", (int) idata);
618 DEFAULT_WRITE;
619 }
620 break;
621
622 case PVRREG_VRAM_CFG1:
623 if (writeflag == MEM_WRITE) {
624 debug("[ pvr: VRAM_CFG1 set to 0x%08"PRIx32,
625 (int) idata);
626 if (idata != VRAM_CFG1_GOOD_REFRESH_VALUE)
627 fatal("{ VRAM_CFG1 = 0x%08"PRIx32" is not "
628 "yet implemented! }", (int) idata);
629 debug(" ]\n");
630 DEFAULT_WRITE;
631 }
632 break;
633
634 case PVRREG_VRAM_CFG2:
635 if (writeflag == MEM_WRITE) {
636 debug("[ pvr: VRAM_CFG2 set to 0x%08"PRIx32,
637 (int) idata);
638 if (idata != VRAM_CFG2_UNKNOWN_MAGIC)
639 fatal("{ VRAM_CFG2 = 0x%08"PRIx32" is not "
640 "yet implemented! }", (int) idata);
641 debug(" ]\n");
642 DEFAULT_WRITE;
643 }
644 break;
645
646 case PVRREG_VRAM_CFG3:
647 if (writeflag == MEM_WRITE) {
648 debug("[ pvr: VRAM_CFG3 set to 0x%08"PRIx32,
649 (int) idata);
650 if (idata != VRAM_CFG3_UNKNOWN_MAGIC)
651 fatal("{ VRAM_CFG3 = 0x%08"PRIx32" is not "
652 "yet implemented! }", (int) idata);
653 debug(" ]\n");
654 DEFAULT_WRITE;
655 }
656 break;
657
658 case PVRREG_FOG_TABLE_COL:
659 if (writeflag == MEM_WRITE) {
660 debug("[ pvr: FOG_TABLE_COL set to 0x%08"PRIx32" ]\n",
661 (int) idata);
662 DEFAULT_WRITE;
663 }
664 break;
665
666 case PVRREG_FOG_VERTEX_COL:
667 if (writeflag == MEM_WRITE) {
668 debug("[ pvr: FOG_VERTEX_COL set to 0x%08"PRIx32" ]\n",
669 (int) idata);
670 DEFAULT_WRITE;
671 }
672 break;
673
674 case PVRREG_FB_RENDER_MODULO:
675 if (writeflag == MEM_WRITE) {
676 debug("[ pvr: PVRREG_FB_RENDER_MODULO set to %i ]\n",
677 (int) idata);
678 /* TODO */
679 DEFAULT_WRITE;
680 }
681 break;
682
683 case PVRREG_DIWADDRL:
684 if (writeflag == MEM_WRITE) {
685 debug("[ pvr: DIWADDRL set to 0x%08"PRIx32" ]\n",
686 (int) idata);
687 pvr_fb_invalidate(d, -1, -1);
688 DEFAULT_WRITE;
689 }
690 break;
691
692 case PVRREG_DIWADDRS:
693 if (writeflag == MEM_WRITE) {
694 debug("[ pvr: DIWADDRS set to 0x%08"PRIx32" ]\n",
695 (int) idata);
696 pvr_fb_invalidate(d, -1, -1);
697 DEFAULT_WRITE;
698 }
699 break;
700
701 case PVRREG_RASEVTPOS:
702 if (writeflag == MEM_WRITE) {
703 debug("[ pvr: RASEVTPOS pos1=%i pos2=%i ]\n",
704 (int)((idata & RASEVTPOS_POS1_MASK)
705 >> RASEVTPOS_POS1_SHIFT),
706 (int)(idata & RASEVTPOS_POS2_MASK));
707 DEFAULT_WRITE;
708 }
709 break;
710
711 case PVRREG_SYNCCONF:
712 if (writeflag == MEM_WRITE) {
713 d->video_enabled = idata & SYNCCONF_VO_MASK? 1:0;
714 d->broadcast_standard = (idata & SYNCCONF_BC_MASK)
715 >> SYNCCONF_BC_SHIFT;
716 d->interlaced = idata & SYNCCONF_I_MASK? 1:0;
717 d->h_sync_positive = idata & SYNCCONF_HP_MASK? 1:0;
718 d->v_sync_positive = idata & SYNCCONF_VP_MASK? 1:0;
719
720 debug("[ pvr: SYNCCONF set to: ");
721 debug("video_enabled=%i, ", d->video_enabled);
722 switch (d->broadcast_standard) {
723 case SYNCCONF_BC_VGA: debug("VGA"); break;
724 case SYNCCONF_BC_NTSC: debug("NTSC"); break;
725 case SYNCCONF_BC_PAL: debug("PAL"); break;
726 default: debug("*UNKNOWN*"); break;
727 }
728 debug(", interlaced=%i, ", d->interlaced);
729 debug("hsync=%i, ", d->h_sync_positive);
730 debug("vsync=%i ]\n", d->v_sync_positive);
731
732 DEFAULT_WRITE;
733 pvr_geometry_updated(d);
734 pvr_fb_invalidate(d, -1, -1);
735 }
736 break;
737
738 case PVRREG_BRDHORZ:
739 if (writeflag == MEM_WRITE) {
740 debug("[ pvr: BRDHORZ start=%i stop=%i ]\n",
741 (int)((idata & BRDHORZ_START_MASK)
742 >> BRDHORZ_START_SHIFT),
743 (int)(idata & BRDHORZ_STOP_MASK));
744 DEFAULT_WRITE;
745 }
746 break;
747
748 case PVRREG_SYNCSIZE:
749 if (writeflag == MEM_WRITE) {
750 debug("[ pvr: SYNCSIZE v=%i h=%i ]\n",
751 (int)((idata & SYNCSIZE_V_MASK)
752 >> SYNCSIZE_V_SHIFT),
753 (int)(idata & SYNCSIZE_H_MASK));
754 DEFAULT_WRITE;
755 }
756 break;
757
758 case PVRREG_BRDVERT:
759 if (writeflag == MEM_WRITE) {
760 debug("[ pvr: BRDVERT start=%i stop=%i ]\n",
761 (int)((idata & BRDVERT_START_MASK)
762 >> BRDVERT_START_SHIFT),
763 (int)(idata & BRDVERT_STOP_MASK));
764 DEFAULT_WRITE;
765 }
766 break;
767
768 case PVRREG_DIWCONF:
769 if (writeflag == MEM_WRITE) {
770 if ((idata & DIWCONF_MAGIC_MASK) !=
771 DIWCONF_MAGIC && (idata & DIWCONF_MAGIC_MASK)
772 != 0) {
773 fatal("PVRREG_DIWCONF magic not set to "
774 "Magic value. 0x%08x\n", (int)idata);
775 exit(1);
776 }
777 if (idata & DIWCONF_BLANK)
778 debug("[ pvr: PVRREG_DIWCONF: BLANK: TODO ]\n");
779
780 DEFAULT_WRITE;
781 pvr_geometry_updated(d);
782 }
783 break;
784
785 case PVRREG_DIWHSTRT:
786 if (writeflag == MEM_WRITE) {
787 debug("[ pvr: DIWHSTRT hpos=%i ]\n",
788 (int)(idata & DIWVSTRT_HPOS_MASK));
789 DEFAULT_WRITE;
790 }
791 break;
792
793 case PVRREG_DIWVSTRT:
794 if (writeflag == MEM_WRITE) {
795 debug("[ pvr: DIWVSTRT v2=%i v1=%i ]\n",
796 (int)((idata & DIWVSTRT_V2_MASK)
797 >> DIWVSTRT_V2_SHIFT),
798 (int)(idata & DIWVSTRT_V1_MASK));
799 DEFAULT_WRITE;
800 }
801 break;
802
803 case PVRREG_SYNC_STAT:
804 /* TODO. Ugly hack, but it works: */
805 odata = random();
806 break;
807
808 case PVRREG_TA_OPB_START:
809 if (writeflag == MEM_WRITE) {
810 if (idata & ~TA_OPB_START_MASK) {
811 fatal("[ pvr: UNEXPECTED bits in "
812 "TA_OPB_START: 0x%08x ]\n", (int)idata);
813 exit(1);
814 }
815 idata &= TA_OPB_START_MASK;
816 debug("[ pvr: TA_OPB_START set to 0x%x ]\n",
817 (int) idata);
818 DEFAULT_WRITE;
819 }
820 break;
821
822 case PVRREG_TA_OB_START:
823 if (writeflag == MEM_WRITE) {
824 if (idata & ~TA_OB_START_MASK) {
825 fatal("[ pvr: UNEXPECTED bits in "
826 "TA_OB_START: 0x%08x ]\n", (int)idata);
827 exit(1);
828 }
829 idata &= TA_OB_START_MASK;
830 debug("[ pvr: TA_OB_START set to 0x%x ]\n",
831 (int) idata);
832 DEFAULT_WRITE;
833 }
834 break;
835
836 case PVRREG_TA_OPB_END:
837 if (writeflag == MEM_WRITE) {
838 idata &= TA_OPB_END_MASK;
839 debug("[ pvr: TA_OPB_END set to 0x%x ]\n",
840 (int) idata);
841 DEFAULT_WRITE;
842 }
843 break;
844
845 case PVRREG_TA_OB_END:
846 if (writeflag == MEM_WRITE) {
847 idata &= TA_OB_END_MASK;
848 debug("[ pvr: TA_OB_END set to 0x%x ]\n",
849 (int) idata);
850 DEFAULT_WRITE;
851 }
852 break;
853
854 case PVRREG_TA_OPB_POS:
855 if (writeflag == MEM_WRITE) {
856 idata &= TA_OPB_POS_MASK;
857 debug("[ pvr: TA_OPB_POS set to 0x%x ]\n",
858 (int) idata);
859 DEFAULT_WRITE;
860 }
861 break;
862
863 case PVRREG_TA_OB_POS:
864 if (writeflag == MEM_WRITE) {
865 idata &= TA_OB_POS_MASK;
866 debug("[ pvr: TA_OB_POS set to 0x%x ]\n",
867 (int) idata);
868 DEFAULT_WRITE;
869 }
870 break;
871
872 case PVRREG_TILEBUF_SIZE:
873 if (writeflag == MEM_WRITE) {
874 d->tilebuf_ysize = (idata & TILEBUF_SIZE_HEIGHT_MASK)
875 >> TILEBUF_SIZE_HEIGHT_SHIFT;
876 d->tilebuf_xsize = idata & TILEBUF_SIZE_WIDTH_MASK;
877 d->tilebuf_xsize ++; d->tilebuf_ysize ++;
878 debug("[ pvr: TILEBUF_SIZE set to %i x %i ]\n",
879 d->tilebuf_xsize, d->tilebuf_ysize);
880 DEFAULT_WRITE;
881 }
882 break;
883
884 case PVRREG_TA_INIT:
885 if (writeflag == MEM_WRITE) {
886 debug("[ pvr: TA_INIT ]\n");
887
888 if (idata & PVR_TA_INIT)
889 pvr_ta_init(cpu, d);
890
891 if (idata != PVR_TA_INIT && idata != 0)
892 fatal("{ TA_INIT = 0x%08"PRIx32" is not "
893 "yet implemented! }", (int) idata);
894
895 /* Always reset to 0. */
896 idata = 0;
897 DEFAULT_WRITE;
898 }
899 break;
900
901 default:if (writeflag == MEM_READ) {
902 fatal("[ pvr: read from UNIMPLEMENTED addr 0x%x ]\n",
903 (int)relative_addr);
904 } else {
905 fatal("[ pvr: write to UNIMPLEMENTED addr 0x%x: 0x%x"
906 " ]\n", (int)relative_addr, (int)idata);
907 DEFAULT_WRITE;
908 }
909 }
910
911 return_ok:
912 if (writeflag == MEM_READ)
913 memory_writemax64(cpu, data, len, odata);
914
915 return 1;
916 }
917
918
919 static void extend_update_region(struct pvr_data *d, uint64_t low,
920 uint64_t high)
921 {
922 int vram_ofs = REG(PVRREG_DIWADDRL);
923 int bytes_per_line = d->xsize * d->bytes_per_pixel;
924
925 low -= vram_ofs;
926 high -= vram_ofs;
927
928 /* Access inside visible part of VRAM? */
929 if ((int64_t)high >= 0 && (int64_t)low <
930 bytes_per_line * d->ysize) {
931 int new_y1, new_y2;
932
933 d->fb_update_x1 = 0;
934 d->fb_update_x2 = d->xsize - 1;
935
936 /* Calculate which line the low and high addresses
937 correspond to: */
938 new_y1 = low / bytes_per_line;
939 new_y2 = high / bytes_per_line + 1;
940
941 if (d->fb_update_y1 < 0 || new_y1 < d->fb_update_y1)
942 d->fb_update_y1 = new_y1;
943 if (d->fb_update_y2 < 0 || new_y2 > d->fb_update_y2)
944 d->fb_update_y2 = new_y2;
945
946 if (d->fb_update_y2 >= d->ysize)
947 d->fb_update_y2 = d->ysize - 1;
948 }
949 }
950
951
952 DEVICE_TICK(pvr_fb)
953 {
954 struct pvr_data *d = extra;
955 uint64_t high, low = (uint64_t)(int64_t) -1;
956 int vram_ofs = REG(PVRREG_DIWADDRL), pixels_to_copy;
957 int y, bytes_per_line = d->xsize * d->bytes_per_pixel;
958 int fb_ofs, p;
959 uint8_t *fb = (uint8_t *) d->fb->framebuffer;
960 uint8_t *vram = (uint8_t *) d->vram;
961
962
963 /*
964 * Vertical retrace interrupts:
965 *
966 * TODO: Maybe it would be even more realistic to have the timer run
967 * at, say, 60*4 = 240 Hz, and have the following events:
968 *
969 * (tick & 3) == 0 SYSASIC_EVENT_VBLINT
970 * (tick & 3) == 1 SYSASIC_EVENT_PVR_SCANINT1
971 * (tick & 3) == 2 nothing
972 * (tick & 3) == 3 SYSASIC_EVENT_PVR_SCANINT2
973 */
974
975 if (d->vblank_interrupts_pending > 0) {
976 SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_VBLINT);
977 SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_PVR_SCANINT1);
978 SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_PVR_SCANINT2);
979
980 /* TODO: For now, I don't care about missed interrupts: */
981 d->vblank_interrupts_pending = 0;
982 }
983
984
985 /*
986 * Framebuffer update:
987 */
988
989 /* Border changed? */
990 if (d->border_updated) {
991 /* Fill border with border color: */
992 int rgb = REG(PVRREG_BRDCOLR), addr = 0;
993 int x, y, b = rgb & 0xff, g = (rgb >> 8) & 0xff, r = rgb >> 16;
994 int skiplen = (d->fb->xsize-2*PVR_MARGIN) * d->fb->bit_depth/8;
995
996 for (y=0; y<d->fb->ysize; y++) {
997 int xskip = y < PVR_MARGIN || y >=
998 d->fb->ysize - PVR_MARGIN? -1 : PVR_MARGIN;
999 for (x=0; x<d->fb->xsize; x++) {
1000 if (x == xskip) {
1001 x = d->fb->xsize - PVR_MARGIN;
1002 addr += skiplen;
1003 }
1004 fb[addr] = r;
1005 fb[addr+1] = g;
1006 fb[addr+2] = b;
1007 addr += 3;
1008 }
1009 }
1010
1011 /* Full redraw of the framebuffer: */
1012 d->fb->update_x1 = 0; d->fb->update_x2 = d->fb->xsize - 1;
1013 d->fb->update_y1 = 0; d->fb->update_y2 = d->fb->ysize - 1;
1014 }
1015
1016 memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high);
1017 if ((int64_t)low != -1)
1018 extend_update_region(d, low, high);
1019
1020 if (d->fb_update_x1 == -1)
1021 return;
1022
1023 /* Copy (part of) the VRAM to the framebuffer: */
1024 if (d->fb_update_x2 >= d->xsize)
1025 d->fb_update_x2 = d->xsize - 1;
1026 if (d->fb_update_y2 >= d->ysize)
1027 d->fb_update_y2 = d->ysize - 1;
1028
1029 vram_ofs += d->fb_update_y1 * bytes_per_line;
1030 vram_ofs += d->fb_update_x1 * d->bytes_per_pixel;
1031 pixels_to_copy = (d->fb_update_x2 - d->fb_update_x1 + 1);
1032 fb_ofs = (d->fb_update_y1 + PVR_MARGIN) * d->fb->bytes_per_line;
1033 fb_ofs += (d->fb_update_x1 + PVR_MARGIN) * d->fb->bit_depth / 8;
1034
1035 /* Copy the actual pixels: (Four manually inlined, for speed.) */
1036
1037 switch (d->pixelmode) {
1038 case 0: /* RGB0555 (16-bit) */
1039 for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
1040 int fo = fb_ofs, vo = vram_ofs;
1041 for (p=0; p<pixels_to_copy; p++) {
1042 /* 0rrrrrgg(high) gggbbbbb(low) */
1043 fb[fo] = (vram[vo+1] << 1) & 0xf8;
1044 fb[fo+1] = ((vram[vo] >> 2) & 0x38) +
1045 (vram[vo+1] << 6);
1046 fb[fo+2] = (vram[vo] & 0x1f) << 3;
1047 fo += 3; vo += 2;
1048 }
1049 vram_ofs += bytes_per_line;
1050 fb_ofs += d->fb->bytes_per_line;
1051 }
1052 break;
1053
1054 case 1: /* RGB565 (16-bit) */
1055 for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
1056 int fo = fb_ofs, vo = vram_ofs;
1057 for (p=0; p<pixels_to_copy; p++) {
1058 /* rrrrrggg(high) gggbbbbb(low) */
1059 fb[fo] = vram[vo+1] & 0xf8;
1060 fb[fo+1] = ((vram[vo] >> 3) & 0x1c) +
1061 (vram[vo+1] << 5);
1062 fb[fo+2] = (vram[vo] & 0x1f) << 3;
1063 fo += 3; vo += 2;
1064 }
1065 vram_ofs += bytes_per_line;
1066 fb_ofs += d->fb->bytes_per_line;
1067 }
1068 break;
1069
1070 case 2: /* RGB888 (24-bit) */
1071 for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
1072 /* TODO: Reverse colors, like in the 32-bit case? */
1073 memcpy(fb+fb_ofs, vram+vram_ofs, 3*pixels_to_copy);
1074 vram_ofs += bytes_per_line;
1075 fb_ofs += d->fb->bytes_per_line;
1076 }
1077 break;
1078
1079 case 3: /* RGB0888 (32-bit) */
1080 for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) {
1081 int fo = fb_ofs, vo = vram_ofs;
1082 for (p=0; p<pixels_to_copy; p++) {
1083 fb[fo] = vram[vo+2];
1084 fb[fo+1] = vram[vo+1];
1085 fb[fo+2] = vram[vo+0];
1086 fo += 3; vo += 4;
1087 }
1088 vram_ofs += bytes_per_line;
1089 fb_ofs += d->fb->bytes_per_line;
1090 }
1091 break;
1092 }
1093
1094 /*
1095 * Extend the real framebuffer to encompass the area
1096 * just written to:
1097 */
1098
1099 /* Offset to take the margin into account first... */
1100 d->fb_update_x1 += PVR_MARGIN; d->fb_update_y1 += PVR_MARGIN;
1101 d->fb_update_x2 += PVR_MARGIN; d->fb_update_y2 += PVR_MARGIN;
1102
1103 if (d->fb_update_x1 < d->fb->update_x1 || d->fb->update_x1 < 0)
1104 d->fb->update_x1 = d->fb_update_x1;
1105 if (d->fb_update_x2 > d->fb->update_x2 || d->fb->update_x2 < 0)
1106 d->fb->update_x2 = d->fb_update_x2;
1107 if (d->fb_update_y1 < d->fb->update_y1 || d->fb->update_y1 < 0)
1108 d->fb->update_y1 = d->fb_update_y1;
1109 if (d->fb_update_y2 > d->fb->update_y2 || d->fb->update_y2 < 0)
1110 d->fb->update_y2 = d->fb_update_y2;
1111
1112 /* Clear the PVR's update region: */
1113 d->fb_update_x1 = d->fb_update_x2 =
1114 d->fb_update_y1 = d->fb_update_y2 = -1;
1115 }
1116
1117
1118 DEVICE_ACCESS(pvr_vram_alt)
1119 {
1120 struct pvr_data_alt *d_alt = extra;
1121 struct pvr_data *d = d_alt->d;
1122 size_t i;
1123
1124 if (writeflag == MEM_READ) {
1125 /* Copy from real vram: */
1126 for (i=0; i<len; i++) {
1127 int addr = relative_addr + i;
1128 addr = ((addr & 4) << 20) | (addr & 3)
1129 | ((addr & 0x7ffff8) >> 1);
1130 data[i] = d->vram[addr];
1131 }
1132 return 1;
1133 }
1134
1135 /*
1136 * Convert writes to alternative VRAM, into normal writes:
1137 */
1138
1139 for (i=0; i<len; i++) {
1140 int addr = relative_addr + i;
1141 addr = ((addr & 4) << 20) | (addr & 3)
1142 | ((addr & 0x7ffff8) >> 1);
1143 d->vram[addr] = data[i];
1144 }
1145
1146 return 1;
1147 }
1148
1149
1150 DEVICE_ACCESS(pvr_vram)
1151 {
1152 struct pvr_data *d = extra;
1153
1154 if (writeflag == MEM_READ) {
1155 memcpy(data, d->vram + relative_addr, len);
1156 return 1;
1157 }
1158
1159 /*
1160 * Write to VRAM:
1161 *
1162 * Calculate which part of the framebuffer this write corresponds to,
1163 * if any, and increase the update region to encompass the written
1164 * memory range.
1165 */
1166
1167 memcpy(d->vram + relative_addr, data, len);
1168 extend_update_region(d, relative_addr, relative_addr + len - 1);
1169
1170 return 1;
1171 }
1172
1173
1174 DEVINIT(pvr)
1175 {
1176 struct machine *machine = devinit->machine;
1177 struct pvr_data *d = malloc(sizeof(struct pvr_data));
1178 struct pvr_data_alt *d_alt = malloc(sizeof(struct pvr_data_alt));
1179 if (d == NULL) {
1180 fprintf(stderr, "out of memory\n");
1181 exit(1);
1182 }
1183 memset(d, 0, sizeof(struct pvr_data));
1184 memset(d_alt, 0, sizeof(struct pvr_data_alt));
1185
1186 d_alt->d = d;
1187
1188 memory_device_register(machine->memory, devinit->name,
1189 PVRREG_REGSTART, PVRREG_REGSIZE, dev_pvr_access, d,
1190 DM_DEFAULT, NULL);
1191
1192 /* 8 MB video RAM: */
1193 d->vram = zeroed_alloc(8 * 1048576);
1194 memory_device_register(machine->memory, "pvr_vram", 0x05000000,
1195 8 * 1048576, dev_pvr_vram_access, (void *)d,
1196 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK
1197 | DM_READS_HAVE_NO_SIDE_EFFECTS, d->vram);
1198
1199 /* 8 MB video RAM, when accessed at 0xa4000000: */
1200 d->vram_alt = zeroed_alloc(8 * 1048576);
1201 memory_device_register(machine->memory, "pvr_alt_vram", 0x04000000,
1202 8 * 1048576, dev_pvr_vram_alt_access, (void *)d_alt,
1203 DM_DEFAULT, NULL);
1204
1205 memory_device_register(machine->memory, "pvr_ta",
1206 0x10000000, sizeof(d->ta), dev_pvr_ta_access, d, DM_DEFAULT, NULL);
1207
1208 d->xsize = 640;
1209 d->ysize = 480;
1210 d->pixelmode = 1; /* RGB565 */
1211 d->bytes_per_pixel = 2;
1212
1213 d->fb = dev_fb_init(machine, machine->memory, INTERNAL_FB_ADDR,
1214 VFB_GENERIC, d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2,
1215 d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2,
1216 24, "Dreamcast PVR");
1217
1218 d->vblank_timer = timer_add(PVR_VBLANK_HZ, pvr_vblank_timer_tick, d);
1219
1220 pvr_reset(d);
1221 pvr_reset_ta(d);
1222
1223 machine_add_tickfunction(machine, dev_pvr_fb_tick, d,
1224 PVR_FB_TICK_SHIFT, 0.0);
1225
1226 return 1;
1227 }
1228

  ViewVC Help
Powered by ViewVC 1.1.26