/[gxemul]/upstream/0.3.6.1/src/devices/dev_sgi_gbe.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.3.6.1/src/devices/dev_sgi_gbe.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (hide annotations)
Mon Oct 8 16:19:05 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 12419 byte(s)
0.3.6.1
1 dpavlin 4 /*
2     * Copyright (C) 2003-2005 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 dpavlin 14 * $Id: dev_sgi_gbe.c,v 1.27 2005/08/16 20:17:32 debug Exp $
29 dpavlin 4 *
30     * SGI "gbe", graphics controller. Framebuffer.
31     * Loosely inspired by Linux code.
32     */
33    
34     #include <stdio.h>
35     #include <stdlib.h>
36     #include <string.h>
37    
38     #include "console.h"
39     #include "cpu.h"
40     #include "devices.h"
41     #include "machine.h"
42     #include "memory.h"
43     #include "misc.h"
44    
45    
46     /* Let's hope nothing is there already... */
47     #define FAKE_GBE_FB_ADDRESS 0x38000000
48    
49     #define GBE_DEBUG
50 dpavlin 12 /* #define debug fatal */
51 dpavlin 4
52 dpavlin 14 #define MTE_TEST
53 dpavlin 12
54 dpavlin 4 #define GBE_DEFAULT_XRES 640
55     #define GBE_DEFAULT_YRES 480
56    
57    
58     struct sgi_gbe_data {
59     int xres, yres;
60    
61     uint32_t control; /* 0x00000 */
62     uint32_t dotclock; /* 0x00004 */
63     uint32_t i2c; /* 0x00008 */
64     uint32_t i2cfp; /* 0x00010 */
65     uint32_t plane0ctrl; /* 0x30000 */
66     uint32_t frm_control; /* 0x3000c */
67     int freeze;
68    
69     int bitdepth;
70     struct vfb_data *fb_data;
71     };
72    
73    
74     /*
75     * dev_sgi_gbe_tick():
76     *
77     * Every now and then, copy data from the framebuffer in normal ram
78     * to the actual framebuffer (which will then redraw the window).
79     * TODO: This is utterly slow, even slower than the normal framebuffer
80     * which is really slow as it is.
81     *
82     * frm_control (bits 31..9) is a pointer to an array of uint16_t.
83     * These numbers (when << 16 bits) are pointers to the tiles. Tiles are
84     * 512x128 in 8-bit mode, 256x128 in 16-bit mode, and 128x128 in 32-bit mode.
85     */
86     void dev_sgi_gbe_tick(struct cpu *cpu, void *extra)
87     {
88     struct sgi_gbe_data *d = extra;
89     int tile_nr = 0, on_screen = 1, xbase = 0, ybase = 0;
90     unsigned char tileptr_buf[sizeof(uint16_t)];
91     uint64_t tileptr, tiletable;
92     int lines_to_copy, pixels_per_line, y;
93 dpavlin 12 unsigned char buf[16384]; /* must be power of 2, at most 65536 */
94 dpavlin 4 int copy_len, copy_offset;
95     uint64_t old_fb_offset = 0;
96     int tweaked = 1;
97    
98 dpavlin 12 #ifdef MTE_TEST
99     return;
100     #endif
101    
102 dpavlin 4 /* debug("[ sgi_gbe: dev_sgi_gbe_tick() ]\n"); */
103    
104     tiletable = (d->frm_control & 0xfffffe00);
105     if (tiletable == 0)
106     on_screen = 0;
107 dpavlin 12 /*
108     tweaked = 0;
109     */
110 dpavlin 4 while (on_screen) {
111     /* Get pointer to a tile: */
112     cpu->memory_rw(cpu, cpu->mem, tiletable +
113     sizeof(tileptr_buf) * tile_nr,
114     tileptr_buf, sizeof(tileptr_buf), MEM_READ,
115     NO_EXCEPTIONS | PHYSICAL);
116     tileptr = 256 * tileptr_buf[0] + tileptr_buf[1];
117     /* TODO: endianness */
118     tileptr <<= 16;
119    
120     /* tileptr is now a physical address of a tile. */
121     debug("[ sgi_gbe: tile_nr = %2i, tileptr = 0x%08lx, xbase"
122     " = %4i, ybase = %4i ]\n", tile_nr, tileptr, xbase, ybase);
123    
124     if (tweaked) {
125     /* Tweaked (linear) mode: */
126    
127     /* Copy data from this 64KB physical RAM block to the framebuffer: */
128     /* NOTE: Copy it in smaller chunks than 64KB, in case the framebuffer
129     device can optimize away portions that aren't modified that way */
130     copy_len = sizeof(buf);
131     copy_offset = 0;
132    
133     while (on_screen && copy_offset < 65536) {
134     if (old_fb_offset + copy_len > d->xres * d->yres * d->bitdepth / 8) {
135     copy_len = d->xres * d->yres * d->bitdepth / 8 - old_fb_offset;
136     /* Stop after copying this block... */
137     on_screen = 0;
138     }
139    
140     /* debug("old_fb_offset = %08x copylen"
141     "=%i\n", old_fb_offset, copy_len); */
142    
143     cpu->memory_rw(cpu, cpu->mem, tileptr +
144     copy_offset, buf, copy_len, MEM_READ,
145     NO_EXCEPTIONS | PHYSICAL);
146     dev_fb_access(cpu, cpu->mem, old_fb_offset,
147     buf, copy_len, MEM_WRITE, d->fb_data);
148     copy_offset += sizeof(buf);
149     old_fb_offset += sizeof(buf);
150     }
151     } else {
152     /* This is for non-tweaked (tiled) mode. Not really tested
153     with correct image data, but might work: */
154    
155     lines_to_copy = 128;
156     if (ybase + lines_to_copy > d->yres)
157     lines_to_copy = d->yres - ybase;
158    
159     pixels_per_line = 512 * 8 / d->bitdepth;
160     if (xbase + pixels_per_line > d->xres)
161     pixels_per_line = d->xres - xbase;
162    
163     for (y=0; y<lines_to_copy; y++) {
164     cpu->memory_rw(cpu, cpu->mem, tileptr + 512 * y,
165     buf, pixels_per_line * d->bitdepth / 8,
166     MEM_READ, NO_EXCEPTIONS | PHYSICAL);
167 dpavlin 12 #if 0
168     {
169     int i;
170     for (i=0; i<pixels_per_line * d->bitdepth / 8; i++)
171     buf[i] ^= (random() & 0x20);
172     }
173     #endif
174 dpavlin 4 dev_fb_access(cpu, cpu->mem, ((ybase + y) *
175     d->xres + xbase) * d->bitdepth / 8,
176     buf, pixels_per_line * d->bitdepth / 8,
177     MEM_WRITE, d->fb_data);
178     }
179    
180     /* Go to next tile: */
181     xbase += (512 * 8 / d->bitdepth);
182     if (xbase >= d->xres) {
183     xbase = 0;
184     ybase += 128;
185     if (ybase >= d->yres)
186     on_screen = 0;
187     }
188     }
189    
190     /* Go to next tile: */
191     tile_nr ++;
192     }
193    
194     /* debug("[ sgi_gbe: dev_sgi_gbe_tick() end]\n"); */
195     }
196    
197    
198     /*
199     * dev_sgi_gbe_access():
200     */
201     int dev_sgi_gbe_access(struct cpu *cpu, struct memory *mem,
202     uint64_t relative_addr, unsigned char *data, size_t len,
203     int writeflag, void *extra)
204     {
205     struct sgi_gbe_data *d = extra;
206     uint64_t idata = 0, odata = 0;
207    
208     idata = memory_readmax64(cpu, data, len);
209    
210     #ifdef GBE_DEBUG
211     if (writeflag == MEM_WRITE)
212     debug("[ sgi_gbe: DEBUG: write to address 0x%llx, data=0x%llx ]\n", (long long)relative_addr, (long long)idata);
213     #endif
214    
215     switch (relative_addr) {
216    
217     case 0x0:
218     if (writeflag == MEM_WRITE)
219     d->control = idata;
220     else
221     odata = d->control;
222     break;
223    
224     case 0x4:
225     if (writeflag == MEM_WRITE)
226     d->dotclock = idata;
227     else
228     odata = d->dotclock;
229     break;
230    
231     case 0x8: /* i2c? */
232     /*
233     * "CRT I2C control".
234     *
235     * I'm not sure what this does. It isn't really commented
236     * in the linux sources. The IP32 prom writes the values
237     * 0x03, 0x01, and then 0x00 to this address, and then
238     * reads back a value.
239     */
240     if (writeflag == MEM_WRITE) {
241     d->i2c = idata;
242     } else {
243     odata = d->i2c;
244     odata |= 1; /* ? The IP32 prom wants this? */
245     }
246     break;
247    
248     case 0x10: /* i2cfp, flat panel control */
249     if (writeflag == MEM_WRITE) {
250     d->i2cfp = idata;
251     } else {
252     odata = d->i2cfp;
253     odata |= 1; /* ? The IP32 prom wants this? */
254     }
255     break;
256    
257     case 0x10000: /* vt_xy, according to Linux */
258     if (writeflag == MEM_WRITE)
259     d->freeze = idata & ((uint32_t)1<<31)? 1 : 0;
260     else {
261     /* bit 31 = freeze, 23..12 = cury, 11.0 = curx */
262     odata = ((random() % (d->yres + 10)) << 12)
263     + (random() % (d->xres + 10)) + (d->freeze? ((uint32_t)1 << 31) : 0);
264     odata = random(); /* testhack for the ip32 prom */
265     }
266     break;
267    
268     case 0x10004: /* vt_xymax, according to Linux */
269     odata = ((d->yres-1) << 12) + d->xres-1; /* ... 12 bits maxy, 12 bits maxx. */
270     break;
271    
272     case 0x10034: /* vt_hpixen, according to Linux */
273     odata = (0 << 12) + d->xres-1; /* ... 12 bits on, 12 bits off. */
274     break;
275    
276     case 0x10038: /* vt_vpixen, according to Linux */
277     odata = (0 << 12) + d->yres-1; /* ... 12 bits on, 12 bits off. */
278     break;
279    
280     case 0x20004:
281     odata = random(); /* IP32 prom test hack. TODO */
282     /* IRIX wants 0x20, it seems. */
283     if (random() & 1)
284     odata = 0x20;
285     break;
286    
287     case 0x30000: /* normal plane ctrl 0 */
288     /* bit 15 = fifo reset, 14..13 = depth, 12..5 = tile width, 4..0 = rhs */
289     if (writeflag == MEM_WRITE) {
290     d->plane0ctrl = idata;
291     d->bitdepth = 8 << ((d->plane0ctrl >> 13) & 3);
292     debug("[ sgi_gbe: setting color depth to %i bits ]\n", d->bitdepth);
293     if (d->bitdepth != 8)
294     fatal("sgi_gbe: warning: bitdepth %i not really implemented yet\n", d->bitdepth);
295     } else
296     odata = d->plane0ctrl;
297     break;
298    
299     case 0x30008: /* normal plane ctrl 2 */
300     odata = random(); /* IP32 prom test hack. TODO */
301     /* IRIX wants 0x20, it seems. */
302     if (random() & 1)
303     odata = 0x20;
304     break;
305    
306     case 0x3000c: /* normal plane ctrl 3 */
307     /* Writes to 3000c should be readable back at 30008? At least bit 0 (dma) */
308     /* ctrl 3: Bits 31..9 = tile table pointer bits, Bit 1 = linear, Bit 0 = dma */
309     if (writeflag == MEM_WRITE) {
310     d->frm_control = idata;
311     debug("[ sgi_gbe: frm_control = 0x%08x ]\n", d->frm_control);
312     } else
313     odata = d->frm_control;
314     break;
315    
316     case 0x40000:
317     odata = random(); /* IP32 prom test hack. TODO */
318     /* IRIX wants 0x20, it seems. */
319     if (random() & 1)
320     odata = 0x20;
321     break;
322    
323     /*
324     * Linux/sgimips seems to write color palette data to offset 0x50000 - 0x503xx,
325     * and gamma correction data to 0x60000 - 0x603ff, as 32-bit values at addresses
326     * divisible by 4 (formated as 0xrrggbb00).
327     *
328     * sgio2fb: initializing
329     * sgio2fb: I/O at 0xffffffffb6000000
330     * sgio2fb: tiles at ffffffffa2ef5000
331     * sgio2fb: framebuffer at ffffffffa1000000
332     * sgio2fb: 8192kB memory
333     * Console: switching to colour frame buffer device 80x30
334     */
335    
336     default:
337     /* Gamma correction: */
338     if (relative_addr >= 0x60000 && relative_addr <= 0x603ff) {
339     /* ignore gamma correction for now */
340     break;
341     }
342    
343     /* RGB Palette: */
344     if (relative_addr >= 0x50000 && relative_addr <= 0x503ff) {
345     int color_nr, r, g, b;
346     int old_r, old_g, old_b;
347    
348     color_nr = (relative_addr & 0x3ff) / 4;
349     r = (idata >> 24) & 0xff;
350     g = (idata >> 16) & 0xff;
351     b = (idata >> 8) & 0xff;
352    
353     old_r = d->fb_data->rgb_palette[color_nr * 3 + 0];
354     old_g = d->fb_data->rgb_palette[color_nr * 3 + 1];
355     old_b = d->fb_data->rgb_palette[color_nr * 3 + 2];
356    
357     d->fb_data->rgb_palette[color_nr * 3 + 0] = r;
358     d->fb_data->rgb_palette[color_nr * 3 + 1] = g;
359     d->fb_data->rgb_palette[color_nr * 3 + 2] = b;
360    
361     if (r != old_r || g != old_g || b != old_b) {
362     /* If the palette has been changed, the entire image needs to be redrawn... :-/ */
363     d->fb_data->update_x1 = 0;
364     d->fb_data->update_x2 = d->fb_data->xsize - 1;
365     d->fb_data->update_y1 = 0;
366     d->fb_data->update_y2 = d->fb_data->ysize - 1;
367     }
368     break;
369     }
370    
371     if (writeflag == MEM_WRITE)
372     debug("[ sgi_gbe: unimplemented write to address 0x%llx, data=0x%llx ]\n", (long long)relative_addr, (long long)idata);
373     else
374     debug("[ sgi_gbe: unimplemented read from address 0x%llx ]\n", (long long)relative_addr);
375     }
376    
377     if (writeflag == MEM_READ) {
378     #ifdef GBE_DEBUG
379     debug("[ sgi_gbe: DEBUG: read from address 0x%llx: 0x%llx ]\n", (long long)relative_addr, (long long)odata);
380     #endif
381     memory_writemax64(cpu, data, len, odata);
382     }
383    
384     return 1;
385     }
386    
387    
388     /*
389     * dev_sgi_gbe_init():
390     */
391     void dev_sgi_gbe_init(struct machine *machine, struct memory *mem,
392     uint64_t baseaddr)
393     {
394     struct sgi_gbe_data *d;
395    
396     d = malloc(sizeof(struct sgi_gbe_data));
397     if (d == NULL) {
398     fprintf(stderr, "out of memory\n");
399     exit(1);
400     }
401     memset(d, 0, sizeof(struct sgi_gbe_data));
402 dpavlin 14
403     /* 640x480 for Linux: */
404 dpavlin 4 d->xres = GBE_DEFAULT_XRES;
405     d->yres = GBE_DEFAULT_YRES;
406     d->bitdepth = 8;
407     d->control = 0x20aa000; /* or 0x00000001? */
408 dpavlin 14
409     /* 1280x1024 for booting the O2's PROM: */
410     d->xres = 1280; d->yres = 1024;
411    
412 dpavlin 4 d->fb_data = dev_fb_init(machine, mem, FAKE_GBE_FB_ADDRESS,
413 dpavlin 12 VFB_GENERIC, d->xres, d->yres, d->xres, d->yres, 8, "SGI GBE");
414 dpavlin 4 set_grayscale_palette(d->fb_data, 256);
415    
416     memory_device_register(mem, "sgi_gbe", baseaddr, DEV_SGI_GBE_LENGTH,
417     dev_sgi_gbe_access, d, MEM_DEFAULT, NULL);
418     machine_add_tickfunction(machine, dev_sgi_gbe_tick, d, 18);
419     }
420    

  ViewVC Help
Powered by ViewVC 1.1.26