/[gxemul]/upstream/0.4.5.1/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 /upstream/0.4.5.1/src/devices/dev_pvr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 41 - (hide annotations)
Mon Oct 8 16:22:20 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 31632 byte(s)
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