/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (hide annotations)
Mon Oct 8 16:22:11 2007 UTC (16 years, 6 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 dpavlin 32 /*
2 dpavlin 34 * Copyright (C) 2006-2007 Anders Gavare. All rights reserved.
3 dpavlin 32 *
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 dpavlin 40 * $Id: dev_pvr.c,v 1.21 2007/04/28 09:19:52 debug Exp $
29 dpavlin 32 *
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 dpavlin 34 #define PVR_MARGIN 16
77 dpavlin 32
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 dpavlin 34 /* BRDCOLR: */
106     int border_updated;
107 dpavlin 32 /* 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 dpavlin 34 /* Make sure to redraw border on geometry changes. */
166     d->border_updated = 1;
167    
168 dpavlin 32 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 dpavlin 34 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 dpavlin 32 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 dpavlin 34 d->border_updated = 1;
551 dpavlin 32 }
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 dpavlin 34 /* 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 dpavlin 32 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 dpavlin 34 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 dpavlin 32
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 dpavlin 34 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 dpavlin 32
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 dpavlin 34 /* 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 dpavlin 32 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 dpavlin 40 size_t i;
1123 dpavlin 32
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 dpavlin 34 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 dpavlin 32
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