dev_sgi_gbe.cc Source File

Back to the index.

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

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13