/[gxemul]/upstream/0.3.6/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

Contents of /upstream/0.3.6/src/devices/dev_sgi_gbe.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations)
Mon Oct 8 16:18:56 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 12419 byte(s)
0.3.6
1 /*
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 * $Id: dev_sgi_gbe.c,v 1.27 2005/08/16 20:17:32 debug Exp $
29 *
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 /* #define debug fatal */
51
52 #define MTE_TEST
53
54 #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 unsigned char buf[16384]; /* must be power of 2, at most 65536 */
94 int copy_len, copy_offset;
95 uint64_t old_fb_offset = 0;
96 int tweaked = 1;
97
98 #ifdef MTE_TEST
99 return;
100 #endif
101
102 /* debug("[ sgi_gbe: dev_sgi_gbe_tick() ]\n"); */
103
104 tiletable = (d->frm_control & 0xfffffe00);
105 if (tiletable == 0)
106 on_screen = 0;
107 /*
108 tweaked = 0;
109 */
110 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 #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 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
403 /* 640x480 for Linux: */
404 d->xres = GBE_DEFAULT_XRES;
405 d->yres = GBE_DEFAULT_YRES;
406 d->bitdepth = 8;
407 d->control = 0x20aa000; /* or 0x00000001? */
408
409 /* 1280x1024 for booting the O2's PROM: */
410 d->xres = 1280; d->yres = 1024;
411
412 d->fb_data = dev_fb_init(machine, mem, FAKE_GBE_FB_ADDRESS,
413 VFB_GENERIC, d->xres, d->yres, d->xres, d->yres, 8, "SGI GBE");
414 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