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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 12449 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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.28 2005/10/26 14:37:04 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 if (writeflag == MEM_WRITE)
209 idata = memory_readmax64(cpu, data, len);
210
211 #ifdef GBE_DEBUG
212 if (writeflag == MEM_WRITE)
213 debug("[ sgi_gbe: DEBUG: write to address 0x%llx, data=0x%llx ]\n", (long long)relative_addr, (long long)idata);
214 #endif
215
216 switch (relative_addr) {
217
218 case 0x0:
219 if (writeflag == MEM_WRITE)
220 d->control = idata;
221 else
222 odata = d->control;
223 break;
224
225 case 0x4:
226 if (writeflag == MEM_WRITE)
227 d->dotclock = idata;
228 else
229 odata = d->dotclock;
230 break;
231
232 case 0x8: /* i2c? */
233 /*
234 * "CRT I2C control".
235 *
236 * I'm not sure what this does. It isn't really commented
237 * in the linux sources. The IP32 prom writes the values
238 * 0x03, 0x01, and then 0x00 to this address, and then
239 * reads back a value.
240 */
241 if (writeflag == MEM_WRITE) {
242 d->i2c = idata;
243 } else {
244 odata = d->i2c;
245 odata |= 1; /* ? The IP32 prom wants this? */
246 }
247 break;
248
249 case 0x10: /* i2cfp, flat panel control */
250 if (writeflag == MEM_WRITE) {
251 d->i2cfp = idata;
252 } else {
253 odata = d->i2cfp;
254 odata |= 1; /* ? The IP32 prom wants this? */
255 }
256 break;
257
258 case 0x10000: /* vt_xy, according to Linux */
259 if (writeflag == MEM_WRITE)
260 d->freeze = idata & ((uint32_t)1<<31)? 1 : 0;
261 else {
262 /* bit 31 = freeze, 23..12 = cury, 11.0 = curx */
263 odata = ((random() % (d->yres + 10)) << 12)
264 + (random() % (d->xres + 10)) + (d->freeze? ((uint32_t)1 << 31) : 0);
265 odata = random(); /* testhack for the ip32 prom */
266 }
267 break;
268
269 case 0x10004: /* vt_xymax, according to Linux */
270 odata = ((d->yres-1) << 12) + d->xres-1; /* ... 12 bits maxy, 12 bits maxx. */
271 break;
272
273 case 0x10034: /* vt_hpixen, according to Linux */
274 odata = (0 << 12) + d->xres-1; /* ... 12 bits on, 12 bits off. */
275 break;
276
277 case 0x10038: /* vt_vpixen, according to Linux */
278 odata = (0 << 12) + d->yres-1; /* ... 12 bits on, 12 bits off. */
279 break;
280
281 case 0x20004:
282 odata = random(); /* IP32 prom test hack. TODO */
283 /* IRIX wants 0x20, it seems. */
284 if (random() & 1)
285 odata = 0x20;
286 break;
287
288 case 0x30000: /* normal plane ctrl 0 */
289 /* bit 15 = fifo reset, 14..13 = depth, 12..5 = tile width, 4..0 = rhs */
290 if (writeflag == MEM_WRITE) {
291 d->plane0ctrl = idata;
292 d->bitdepth = 8 << ((d->plane0ctrl >> 13) & 3);
293 debug("[ sgi_gbe: setting color depth to %i bits ]\n", d->bitdepth);
294 if (d->bitdepth != 8)
295 fatal("sgi_gbe: warning: bitdepth %i not really implemented yet\n", d->bitdepth);
296 } else
297 odata = d->plane0ctrl;
298 break;
299
300 case 0x30008: /* normal plane ctrl 2 */
301 odata = random(); /* IP32 prom test hack. TODO */
302 /* IRIX wants 0x20, it seems. */
303 if (random() & 1)
304 odata = 0x20;
305 break;
306
307 case 0x3000c: /* normal plane ctrl 3 */
308 /* Writes to 3000c should be readable back at 30008? At least bit 0 (dma) */
309 /* ctrl 3: Bits 31..9 = tile table pointer bits, Bit 1 = linear, Bit 0 = dma */
310 if (writeflag == MEM_WRITE) {
311 d->frm_control = idata;
312 debug("[ sgi_gbe: frm_control = 0x%08x ]\n", d->frm_control);
313 } else
314 odata = d->frm_control;
315 break;
316
317 case 0x40000:
318 odata = random(); /* IP32 prom test hack. TODO */
319 /* IRIX wants 0x20, it seems. */
320 if (random() & 1)
321 odata = 0x20;
322 break;
323
324 /*
325 * Linux/sgimips seems to write color palette data to offset 0x50000 - 0x503xx,
326 * and gamma correction data to 0x60000 - 0x603ff, as 32-bit values at addresses
327 * divisible by 4 (formated as 0xrrggbb00).
328 *
329 * sgio2fb: initializing
330 * sgio2fb: I/O at 0xffffffffb6000000
331 * sgio2fb: tiles at ffffffffa2ef5000
332 * sgio2fb: framebuffer at ffffffffa1000000
333 * sgio2fb: 8192kB memory
334 * Console: switching to colour frame buffer device 80x30
335 */
336
337 default:
338 /* Gamma correction: */
339 if (relative_addr >= 0x60000 && relative_addr <= 0x603ff) {
340 /* ignore gamma correction for now */
341 break;
342 }
343
344 /* RGB Palette: */
345 if (relative_addr >= 0x50000 && relative_addr <= 0x503ff) {
346 int color_nr, r, g, b;
347 int old_r, old_g, old_b;
348
349 color_nr = (relative_addr & 0x3ff) / 4;
350 r = (idata >> 24) & 0xff;
351 g = (idata >> 16) & 0xff;
352 b = (idata >> 8) & 0xff;
353
354 old_r = d->fb_data->rgb_palette[color_nr * 3 + 0];
355 old_g = d->fb_data->rgb_palette[color_nr * 3 + 1];
356 old_b = d->fb_data->rgb_palette[color_nr * 3 + 2];
357
358 d->fb_data->rgb_palette[color_nr * 3 + 0] = r;
359 d->fb_data->rgb_palette[color_nr * 3 + 1] = g;
360 d->fb_data->rgb_palette[color_nr * 3 + 2] = b;
361
362 if (r != old_r || g != old_g || b != old_b) {
363 /* If the palette has been changed, the entire image needs to be redrawn... :-/ */
364 d->fb_data->update_x1 = 0;
365 d->fb_data->update_x2 = d->fb_data->xsize - 1;
366 d->fb_data->update_y1 = 0;
367 d->fb_data->update_y2 = d->fb_data->ysize - 1;
368 }
369 break;
370 }
371
372 if (writeflag == MEM_WRITE)
373 debug("[ sgi_gbe: unimplemented write to address 0x%llx, data=0x%llx ]\n", (long long)relative_addr, (long long)idata);
374 else
375 debug("[ sgi_gbe: unimplemented read from address 0x%llx ]\n", (long long)relative_addr);
376 }
377
378 if (writeflag == MEM_READ) {
379 #ifdef GBE_DEBUG
380 debug("[ sgi_gbe: DEBUG: read from address 0x%llx: 0x%llx ]\n", (long long)relative_addr, (long long)odata);
381 #endif
382 memory_writemax64(cpu, data, len, odata);
383 }
384
385 return 1;
386 }
387
388
389 /*
390 * dev_sgi_gbe_init():
391 */
392 void dev_sgi_gbe_init(struct machine *machine, struct memory *mem,
393 uint64_t baseaddr)
394 {
395 struct sgi_gbe_data *d;
396
397 d = malloc(sizeof(struct sgi_gbe_data));
398 if (d == NULL) {
399 fprintf(stderr, "out of memory\n");
400 exit(1);
401 }
402 memset(d, 0, sizeof(struct sgi_gbe_data));
403
404 /* 640x480 for Linux: */
405 d->xres = GBE_DEFAULT_XRES;
406 d->yres = GBE_DEFAULT_YRES;
407 d->bitdepth = 8;
408 d->control = 0x20aa000; /* or 0x00000001? */
409
410 /* 1280x1024 for booting the O2's PROM: */
411 d->xres = 1280; d->yres = 1024;
412
413 d->fb_data = dev_fb_init(machine, mem, FAKE_GBE_FB_ADDRESS,
414 VFB_GENERIC, d->xres, d->yres, d->xres, d->yres, 8, "SGI GBE");
415 set_grayscale_palette(d->fb_data, 256);
416
417 memory_device_register(mem, "sgi_gbe", baseaddr, DEV_SGI_GBE_LENGTH,
418 dev_sgi_gbe_access, d, MEM_DEFAULT, NULL);
419 machine_add_tickfunction(machine, dev_sgi_gbe_tick, d, 18);
420 }
421

  ViewVC Help
Powered by ViewVC 1.1.26