/[gxemul]/upstream/0.3.1/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.1/devices/dev_sgi_gbe.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26