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-2018 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 "Graphics Back End", graphics controller + framebuffer
29  *
30  * Guesswork, based on how Linux, NetBSD, and OpenBSD use the graphics on
31  * the SGI O2. Using NetBSD terminology (from crmfbreg.h):
32  *
33  * dev_sgi_re.cc:
34  * 0x15001000 rendering engine (TLBs)
35  * 0x15002000 drawing engine
36  * 0x15003000 memory transfer engine
37  * 0x15004000 status registers for drawing engine
38  *
39  * dev_sgi_gbe.cc:
40  * 0x16000000 crm (or GBE) framebuffer control / video output
41  *
42  * According to https://www.linux-mips.org/wiki/GBE, the GBE is also used in
43  * the SGI Visual Workstation.
44  */
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 
50 #include "console.h"
51 #include "cpu.h"
52 #include "devices.h"
53 #include "machine.h"
54 #include "memory.h"
55 #include "misc.h"
56 
57 #include "thirdparty/crmfbreg.h"
58 
59 
60 /* Let's hope nothing is there already... */
61 #define FAKE_GBE_FB_ADDRESS 0x380000000
62 
63 
64 // #define GBE_DEBUG
65 // #define debug fatal
66 
67 #define GBE_DEFAULT_XRES 1280
68 #define GBE_DEFAULT_YRES 1024
69 #define GBE_DEFAULT_BITDEPTH 8
70 
71 
72 struct sgi_gbe_data {
73  // CRM / GBE registers:
74  uint32_t ctrlstat; /* 0x00000 */
75  uint32_t dotclock; /* 0x00004 */
76  uint32_t i2c; /* 0x00008 */
77  uint32_t i2cfp; /* 0x00010 */
78 
79  uint32_t freeze; /* and xy */ /* 0x10000 */
80  uint32_t y_intr01; /* 0x10020 */
81  uint32_t y_intr23; /* 0x10024 */
82 
83  uint32_t ovr_tilesize; /* 0x20000 */
84  uint32_t ovr_control; /* 0x2000c */
85 
86  uint32_t tilesize; /* 0x30000 */
87  uint32_t frm_control; /* 0x3000c */
88 
89  uint32_t palette[32 * 256]; /* 0x50000 */
90 
91  uint32_t cursor_pos; /* 0x70000 */
92  uint32_t cursor_control; /* 0x70004 */
93  uint32_t cursor_cmap0; /* 0x70008 */
94  uint32_t cursor_cmap1; /* 0x7000c */
95  uint32_t cursor_cmap2; /* 0x70010 */
96  uint32_t cursor_bitmap[64]; /* 0x78000 */
97 
98  // Emulator's representation:
99  int xres, yres;
104  int bitdepth;
107  uint32_t selected_palette[256];
108  struct vfb_data *fb_data;
109 };
110 
111 
112 void get_rgb(struct sgi_gbe_data *d, uint32_t color, uint8_t* r, uint8_t* g, uint8_t* b)
113 {
114  // TODO: Don't switch on color_mode. For overlays, this is always
115  // 8-bit index mode!
116  switch (d->color_mode) {
117  case CRMFB_MODE_TYP_I8:
118  color &= 0xff;
119  *r = d->selected_palette[color] >> 24;
120  *g = d->selected_palette[color] >> 16;
121  *b = d->selected_palette[color] >> 8;
122  break;
123  case CRMFB_MODE_TYP_RG3B2: // Used by NetBSD console mode
124  *r = 255 * ((color >> 5) & 7) / 7;
125  *g = 255 * ((color >> 2) & 7) / 7;
126  *b = (color & 3) * 85;
127  break;
128  case CRMFB_MODE_TYP_RGB8: // Used by NetBSD's X11 server
129  *r = color >> 24;
130  *g = color >> 16;
131  *b = color >> 8;
132  break;
133  default:fatal("sgi gbe get_rgb(): unimplemented mode %i\n", d->color_mode);
134  exit(1);
135  }
136 }
137 
138 
139 void select_palette(struct sgi_gbe_data *d, int palette_nr)
140 {
141  memmove(&d->selected_palette[0],
142  &d->palette[256 * palette_nr],
143  256 * sizeof(uint32_t));
144 }
145 
146 
147 /*
148  * dev_sgi_gbe_tick():
149  *
150  * Every now and then, copy data from the framebuffer in normal ram
151  * to the actual framebuffer (which will then redraw the window).
152  *
153  * NOTE: This is very slow, even slower than the normal emulated framebuffer,
154  * which is already slow as it is.
155  *
156  * frm_control contains a pointer to an array of uint16_t. These numbers
157  * (when shifted 16 bits to the left) are pointers to the tiles. Tiles are
158  * 512x128 in 8-bit mode, 256x128 in 16-bit mode, and 128x128 in 32-bit mode.
159  *
160  * An exception is how Linux/O2 uses the framebuffer, in a "tweaked" mode
161  * which resembles linear mode. This code attempts to support both.
162  */
163 DEVICE_TICK(sgi_gbe)
164 {
165  struct sgi_gbe_data *d = (struct sgi_gbe_data *) extra;
166  uint64_t tiletable;
167  unsigned char buf[16384]; /* must be power of 2, at most 65536 */
168  int bytes_per_pixel = d->bitdepth / 8;
170 
171  if (!cpu->machine->x11_md.in_use)
172  return;
173 
174  // If not frozen...
175  if (!(d->freeze & 0x80000000)) {
176  // ... check if the guest OS wants interrupts based on Y:
177  if ((d->y_intr01 & CRMFB_INTR_0_MASK) != 0xfff000 ||
178  (d->y_intr01 & CRMFB_INTR_1_MASK) != 0xfff ||
179  (d->y_intr23 & CRMFB_INTR_2_MASK) != 0xfff000 ||
180  (d->y_intr23 & CRMFB_INTR_3_MASK) != 0xfff) {
181  fatal("[ sgi_gbe: WARNING: Y interrupts not yet implemented. ]\n");
182  }
183  }
184 
185  // printf("d->frm_control = %08x d->ovr_control = %08x\n", d->frm_control,d->ovr_control);
186 
187  // NetBSD's crmfbreg.h documents the tileptr as having a "9 bit shift",
188  // but IRIX seems to put a value ending in 0x......80 there, and the
189  // last part of that address seems to matter.
190  // TODO: Double-check this with the real hardware.
191 
192  if (d->ovr_control & CRMFB_DMA_ENABLE) {
193  tiletable = (d->ovr_control & 0xffffff80);
194  bytes_per_pixel = 1;
195  partial_pixels = d->ovr_partial_pixels;
196  width_in_tiles = d->ovr_width_in_tiles;
197  select_palette(d, 17); // TODO: is it always palette nr 17 for overlays?
198  } else if (d->frm_control & CRMFB_DMA_ENABLE) {
199  tiletable = (d->frm_control & 0xffffff80);
200  partial_pixels = d->partial_pixels;
201  width_in_tiles = d->width_in_tiles;
203  } else {
204  return;
205  }
206 
207 #ifdef GBE_DEBUG
208  fatal("[ sgi_gbe: dev_sgi_gbe_tick(): tiletable = 0x%llx, bytes_per_pixel = %i ]\n", (long long)tiletable,
209  bytes_per_pixel);
210 #endif
211 
212  if (tiletable == 0)
213  return;
214 
215  // Nr of tiles horizontally:
216  int w = width_in_tiles + (partial_pixels > 0 ? 1 : 0);
217 
218  // Actually, the number of tiles vertically is usually very few,
219  // but this algorithm will render "up to" 256 and abort as soon
220  // as the screen is filled instead. This makes it work for both
221  // Linux' "tweaked linear" mode and all the other guest OSes.
222  const int max_nr_of_tiles = 256;
223 
224  uint32_t tile[max_nr_of_tiles];
225  uint8_t alltileptrs[max_nr_of_tiles * sizeof(uint16_t)];
226 
227  cpu->memory_rw(cpu, cpu->mem, tiletable,
228  alltileptrs, sizeof(alltileptrs), MEM_READ,
230 
231  for (int i = 0; i < 256; ++i) {
232  tile[i] = (256 * alltileptrs[i*2] + alltileptrs[i*2+1]) << 16;
233 #ifdef GBE_DEBUG
234  if (tile[i] != 0)
235  printf("tile[%i] = 0x%08x\n", i, tile[i]);
236 #endif
237  }
238 
239  int screensize = d->xres * d->yres * 3;
240  int x = 0, y = 0;
241 
242  for (int tiley = 0; tiley < max_nr_of_tiles; ++tiley) {
243  for (int line = 0; line < 128; ++line) {
244  for (int tilex = 0; tilex < w; ++tilex) {
245  int tilenr = tilex + tiley * w;
246 
247  if (tilenr >= max_nr_of_tiles)
248  continue;
249 
250  uint32_t base = tile[tilenr];
251 
252  if (base == 0)
253  continue;
254 
255  // Read one line of up to 512 bytes from the tile.
256  int len = tilex < width_in_tiles ? 512 : (partial_pixels * bytes_per_pixel);
257 
258  cpu->memory_rw(cpu, cpu->mem, base + 512 * line,
259  buf, len, MEM_READ, NO_EXCEPTIONS | PHYSICAL);
260 
261  int fb_offset = (x + y * d->xres) * 3;
262  int fb_len = (len / bytes_per_pixel) * 3;
263 
264  if (fb_offset + fb_len > screensize) {
265  fb_len = screensize - fb_offset;
266  }
267 
268  if (fb_len <= 0) {
269  tiley = max_nr_of_tiles; // to break
270  tilex = w;
271  line = 128;
272  }
273 
274  uint8_t fb_buf[512 * 3];
275  int fb_i = 0;
276  for (int i = 0; i < 512; i+=bytes_per_pixel) {
277  uint32_t color;
278  if (bytes_per_pixel == 1)
279  color = buf[i];
280  else if (bytes_per_pixel == 2)
281  color = (buf[i]<<8) + buf[i+1];
282  else // if (bytes_per_pixel == 4)
283  color = (buf[i]<<24) + (buf[i+1]<<16)
284  + (buf[i+2]<<8)+buf[i+3];
285  get_rgb(d, color,
286  &fb_buf[fb_i],
287  &fb_buf[fb_i+1],
288  &fb_buf[fb_i+2]);
289  fb_i += 3;
290  }
291 
292  dev_fb_access(cpu, cpu->mem, fb_offset,
293  fb_buf, fb_len, MEM_WRITE, d->fb_data);
294 
295  x += len / bytes_per_pixel;
296  if (x >= d->xres) {
297  x -= d->xres;
298  ++y;
299  if (y >= d->yres) {
300  tiley = max_nr_of_tiles; // to break
301  tilex = w;
302  line = 128;
303  }
304  }
305  }
306  }
307  }
308 
309  if (d->cursor_control & CRMFB_CURSOR_ON) {
310  int16_t cx = d->cursor_pos & 0xffff;
311  int16_t cy = d->cursor_pos >> 16;
312 
314  uint8_t pixel[3];
315  pixel[0] = d->cursor_cmap0 >> 24;
316  pixel[1] = d->cursor_cmap0 >> 16;
317  pixel[2] = d->cursor_cmap0 >> 8;
318 
319  if (cx >= 0 && cx < d->xres) {
320  for (y = 0; y < d->yres; ++y)
321  dev_fb_access(cpu, cpu->mem, (cx + y * d->xres) * 3,
322  pixel, 3, MEM_WRITE, d->fb_data);
323  }
324 
325  // TODO: Rewrite as a single framebuffer block write?
326  if (cy >= 0 && cy < d->yres) {
327  for (x = 0; x < d->xres; ++x)
328  dev_fb_access(cpu, cpu->mem, (x + cy * d->xres) * 3,
329  pixel, 3, MEM_WRITE, d->fb_data);
330  }
331  } else {
332  uint8_t pixel[3];
333  int sx, sy;
334 
335  for (int dy = 0; dy < 32; ++dy) {
336  for (int dx = 0; dx < 32; ++dx) {
337  sx = cx + dx;
338  sy = cy + dy;
339 
340  if (sx < 0 || sx >= d->xres ||
341  sy < 0 || sy >= d->yres)
342  continue;
343 
344  int wordindex = dy*2 + (dx>>4);
345  uint32_t word = d->cursor_bitmap[wordindex];
346 
347  int color = (word >> ((15 - (dx&15))*2)) & 3;
348 
349  if (!color)
350  continue;
351 
352  if (color == 1) {
353  pixel[0] = d->cursor_cmap0 >> 24;
354  pixel[1] = d->cursor_cmap0 >> 16;
355  pixel[2] = d->cursor_cmap0 >> 8;
356  } else if (color == 2) {
357  pixel[0] = d->cursor_cmap1 >> 24;
358  pixel[1] = d->cursor_cmap1 >> 16;
359  pixel[2] = d->cursor_cmap1 >> 8;
360  } else {
361  pixel[0] = d->cursor_cmap2 >> 24;
362  pixel[1] = d->cursor_cmap2 >> 16;
363  pixel[2] = d->cursor_cmap2 >> 8;
364  }
365 
366  dev_fb_access(cpu, cpu->mem, (sx + sy * d->xres) * 3,
367  pixel, 3, MEM_WRITE, d->fb_data);
368  }
369  }
370  }
371  }
372 }
373 
374 
376 {
377  struct sgi_gbe_data *d = (struct sgi_gbe_data *) extra;
378  uint64_t idata = 0, odata = 0;
379 
380  if (writeflag == MEM_WRITE) {
381  idata = memory_readmax64(cpu, data, len);
382 
383 #ifdef GBE_DEBUG
384  fatal("[ sgi_gbe: DEBUG: write to address 0x%llx, data"
385  "=0x%llx ]\n", (long long)relative_addr, (long long)idata);
386 #endif
387  }
388 
389  switch (relative_addr) {
390 
391  case CRMFB_CTRLSTAT: // 0x0
392  if (writeflag == MEM_WRITE) {
393  debug("[ sgi_gbe: write to ctrlstat: 0x%08x ]\n", (int)idata);
394  d->ctrlstat = (idata & ~CRMFB_CTRLSTAT_CHIPID_MASK)
396  } else
397  odata = d->ctrlstat;
398  break;
399 
400  case CRMFB_DOTCLOCK: // 0x4
401  if (writeflag == MEM_WRITE)
402  d->dotclock = idata;
403  else
404  odata = d->dotclock;
405  break;
406 
407  case CRMFB_I2C_VGA: // 0x8
408  /*
409  * "CRT I2C control".
410  *
411  * I'm not sure what this does. It isn't really commented
412  * in the Linux sources. The IP32 PROM writes the values
413  * 0x03, 0x01, and then 0x00 to this address, and then
414  * reads back a value.
415  */
416  if (writeflag == MEM_WRITE) {
417  //if (!(d->i2c & CRMFB_I2C_SCL) &&
418  // (idata & CRMFB_I2C_SCL)) {
419  // fatal("vga i2c data: %i\n", idata & CRMFB_I2C_SDA);
420  //}
421 
422  d->i2c = idata;
423  } else {
424  odata = d->i2c;
425  odata |= 1; /* ? The IP32 prom wants this? */
426  }
427  break;
428 
429  case CRMFB_I2C_FP: // 0x10, i2cfp, flat panel control
430  if (writeflag == MEM_WRITE) {
431  //if (d->i2c & CRMFB_I2C_SCL &&
432  // !(idata & CRMFB_I2C_SCL)) {
433  // fatal("fp i2c data: %i\n", idata & CRMFB_I2C_SDA);
434  //}
435 
436  d->i2cfp = idata;
437  } else {
438  odata = d->i2cfp;
439  odata |= 1; /* ? The IP32 prom wants this? */
440  }
441  break;
442 
443  case CRMFB_DEVICE_ID: // 0x14
444  odata = CRMFB_DEVICE_ID_DEF;
445  break;
446 
447  case CRMFB_VT_XY: // 0x10000
448  if (writeflag == MEM_WRITE)
449  d->freeze = idata & 0x80000000;
450  else {
451  /*
452  * vt_xy, according to Linux:
453  *
454  * bit 31 = freeze, 23..12 = cury, 11.0 = curx
455  */
456  /* odata = ((random() % (d->yres + 10)) << 12)
457  + (random() % (d->xres + 10)) +
458  d->freeze; */
459 
460  /*
461  * Hack for IRIX/IP32. During startup, it waits for
462  * the value to be over 0x400 (in "gbeRun").
463  *
464  * Hack for the IP32 PROM: During startup, it waits
465  * for the value to be above 0x500 (I think).
466  */
467  odata = d->freeze | (random() & 1 ? 0x3ff : 0x501);
468  }
469  break;
470 
471  case CRMFB_VT_XYMAX: // 0x10004, vt_xymax, according to Linux & NetBSD
472  odata = ((d->yres-1) << 12) + d->xres-1;
473  /* ... 12 bits maxy, 12 bits maxx. */
474  break;
475 
476  case CRMFB_VT_VSYNC: // 0x10008
477  case CRMFB_VT_HSYNC: // 0x1000c
478  case CRMFB_VT_VBLANK: // 0x10010
479  case CRMFB_VT_HBLANK: // 0x10014
480  // TODO
481  break;
482 
483  case CRMFB_VT_FLAGS: // 0x10018
484  // OpenBSD/sgi writes to this register.
485  break;
486 
487  case CRMFB_VT_FRAMELOCK: // 0x1001c
488  // TODO.
489  break;
490 
491  case CRMFB_VT_INTR01: // 0x10020
492  if (writeflag == MEM_WRITE)
493  d->y_intr01 = idata;
494  break;
495 
496  case CRMFB_VT_INTR23: // 0x10024
497  if (writeflag == MEM_WRITE)
498  d->y_intr23 = idata;
499  break;
500 
501  case 0x10028: // 0x10028
502  case 0x1002c: // 0x1002c
503  case 0x10030: // 0x10030
504  // TODO: Unknown, written to by the PROM?
505  break;
506 
507  case CRMFB_VT_HPIX_EN: // 0x10034, vt_hpixen, according to Linux
508  odata = (0 << 12) + d->xres-1;
509  /* ... 12 bits on, 12 bits off. */
510  break;
511 
512  case CRMFB_VT_VPIX_EN: // 0x10038, vt_vpixen, according to Linux
513  odata = (0 << 12) + d->yres-1;
514  /* ... 12 bits on, 12 bits off. */
515  break;
516 
517  case CRMFB_VT_HCMAP: // 0x1003c
518  if (writeflag == MEM_WRITE) {
520  dev_fb_resize(d->fb_data, d->xres, d->yres);
521  }
522 
523  odata = (d->xres << CRMFB_VT_HCMAP_ON_SHIFT) + d->xres + 100;
524  break;
525 
526  case CRMFB_VT_VCMAP: // 0x10040
527  if (writeflag == MEM_WRITE) {
529  dev_fb_resize(d->fb_data, d->xres, d->yres);
530  }
531 
532  odata = (d->yres << CRMFB_VT_VCMAP_ON_SHIFT) + d->yres + 100;
533  break;
534 
535  case CRMFB_VT_DID_STARTXY: // 0x10044
536  case CRMFB_VT_CRS_STARTXY: // 0x10048
537  case CRMFB_VT_VC_STARTXY: // 0x1004c
538  // TODO
539  break;
540 
541  case CRMFB_OVR_WIDTH_TILE: // 0x20000
542  if (writeflag == MEM_WRITE) {
543  d->ovr_tilesize = idata;
544 
545  d->ovr_width_in_tiles = (idata >> CRMFB_FRM_TILESIZE_WIDTH_SHIFT) & 0xff;
546  d->ovr_partial_pixels = ((idata >> CRMFB_FRM_TILESIZE_RHS_SHIFT) & 0x1f) * 32;
547 
548  debug("[ sgi_gbe: OVR setting width in tiles = %i, partial pixels = %i ]\n",
550  } else
551  odata = d->ovr_tilesize;
552  break;
553 
554  case CRMFB_OVR_TILE_PTR: // 0x20004
555  odata = d->ovr_control ^ (random() & 1);
556  break;
557 
558  case CRMFB_OVR_CONTROL: // 0x20008
559  if (writeflag == MEM_WRITE)
560  d->ovr_control = idata;
561  else
562  odata = d->ovr_control;
563  break;
564 
565  case CRMFB_FRM_TILESIZE: // 0x30000:
566  if (writeflag == MEM_WRITE) {
567  d->tilesize = idata;
568 
569  d->bitdepth = 8 << ((d->tilesize >> CRMFB_FRM_TILESIZE_DEPTH_SHIFT) & 3);
570  d->width_in_tiles = (idata >> CRMFB_FRM_TILESIZE_WIDTH_SHIFT) & 0xff;
571  d->partial_pixels = ((idata >> CRMFB_FRM_TILESIZE_RHS_SHIFT) & 0x1f) * 32 * 8 / d->bitdepth;
572 
573  debug("[ sgi_gbe: setting color depth to %i bits, width in tiles = %i, partial pixels = %i ]\n",
575  } else
576  odata = d->tilesize;
577  break;
578 
579  case CRMFB_FRM_PIXSIZE: // 0x30004
580  if (writeflag == MEM_WRITE) {
581  debug("[ sgi_gbe: setting PIXSIZE to 0x%08x ]\n", (int)idata);
582  }
583  break;
584 
585  case 0x30008:
586  // TODO: Figure out exactly what the low bits do.
587  // Irix seems to want 0x20 to "sometimes" be on or off here.
588  odata = d->frm_control ^ (random() & 0x20);
589  break;
590 
591  case CRMFB_FRM_CONTROL: // 0x3000c
592  /*
593  * Writes to 3000c should be readable back at 30008?
594  * At least bit 0 (dma) ctrl 3.
595  */
596  if (writeflag == MEM_WRITE) {
597  d->frm_control = idata;
598  debug("[ sgi_gbe: frm_control = 0x%08x ]\n", d->frm_control);
599  } else
600  odata = d->frm_control;
601  break;
602 
603  case CRMFB_DID_PTR: // 0x40000
604  odata = random(); /* IP32 prom test hack. TODO */
605  /* IRIX wants 0x20, it seems. */
606  if (random() & 1)
607  odata = 0x20;
608  break;
609 
610  case CRMFB_DID_CONTROL: // 0x40004
611  // TODO
612  break;
613 
614  case CRMFB_CMAP_FIFO: // 0x58000
615  break;
616 
617  case CRMFB_CURSOR_POS: // 0x70000
618  if (writeflag == MEM_WRITE)
619  d->cursor_pos = idata;
620  else
621  odata = d->cursor_pos;
622  break;
623 
624  case CRMFB_CURSOR_CONTROL: // 0x70004
625  if (writeflag == MEM_WRITE)
626  d->cursor_control = idata;
627  else
628  odata = d->cursor_control;
629  break;
630 
631  case CRMFB_CURSOR_CMAP0: // 0x70008
632  if (writeflag == MEM_WRITE)
633  d->cursor_cmap0 = idata;
634  else
635  odata = d->cursor_cmap0;
636  break;
637 
638  case CRMFB_CURSOR_CMAP1: // 0x7000c
639  if (writeflag == MEM_WRITE)
640  d->cursor_cmap1 = idata;
641  else
642  odata = d->cursor_cmap1;
643  break;
644 
645  case CRMFB_CURSOR_CMAP2: // 0x70010
646  if (writeflag == MEM_WRITE)
647  d->cursor_cmap2 = idata;
648  else
649  odata = d->cursor_cmap2;
650  break;
651 
652  /*
653  * Linux/sgimips seems to write color palette data to offset 0x50000
654  * to 0x503xx, and gamma correction data to 0x60000 - 0x603ff, as
655  * 32-bit values at addresses divisible by 4 (formated as 0xrrggbb00).
656  *
657  * "sgio2fb: initializing
658  * sgio2fb: I/O at 0xffffffffb6000000
659  * sgio2fb: tiles at ffffffffa2ef5000
660  * sgio2fb: framebuffer at ffffffffa1000000
661  * sgio2fb: 8192kB memory
662  * Console: switching to colour frame buffer device 80x30"
663  *
664  * NetBSD's crmfb_set_palette, however, uses values in reverse, like this:
665  * val = (r << 8) | (g << 16) | (b << 24);
666  */
667 
668  default:
669  /* WID at 0x48000 .. 0x48000 + 4*31: */
670  if (relative_addr >= CRMFB_WID && relative_addr <= CRMFB_WID + 4 * 31) {
671  // TODO: Figure out how this really works. Why are
672  // there 32 such registers?
673  if (writeflag == MEM_WRITE) {
674  d->color_mode = (idata >> CRMFB_MODE_TYP_SHIFT) & 7;
675  d->cmap_select = (idata >> CRMFB_MODE_CMAP_SELECT_SHIFT) & 0x1f;
676  }
677 
678  break;
679  }
680 
681  /* RGB Palette at 0x50000 .. 0x57fff: */
682  if (relative_addr >= CRMFB_CMAP && relative_addr < CRMFB_CMAP + 256 * 32 * sizeof(uint32_t)) {
683  int color_index = (relative_addr - CRMFB_CMAP) >> 2;
684  if (writeflag == MEM_WRITE) {
685  int cmap = color_index >> 8;
686  d->palette[color_index] = idata;
687  if (cmap == d->cmap_select)
688  d->selected_palette[color_index] = idata;
689  } else {
690  odata = d->palette[color_index];
691  }
692  break;
693  }
694 
695  /* Gamma correction at 0x60000 .. 0x603ff: */
696  if (relative_addr >= CRMFB_GMAP && relative_addr <= CRMFB_GMAP + 0x3ff) {
697  /* ignore gamma correction for now */
698  break;
699  }
700 
701  /* Cursor bitmap at 0x78000 ..: */
702  if (relative_addr >= CRMFB_CURSOR_BITMAP && relative_addr <= CRMFB_CURSOR_BITMAP + 0xff) {
703  if (len != 4) {
704  printf("unimplemented CRMFB_CURSOR_BITMAP len %i\n", (int)len);
705  }
706 
707  int index = (relative_addr & 0xff) / 4;
708  if (writeflag == MEM_WRITE)
709  d->cursor_bitmap[index] = idata;
710  else
711  odata = d->cursor_bitmap[index];
712  break;
713  }
714 
715  if (writeflag == MEM_WRITE)
716  fatal("[ sgi_gbe: unimplemented write to address "
717  "0x%llx, data=0x%llx ]\n",
718  (long long)relative_addr, (long long)idata);
719  else
720  fatal("[ sgi_gbe: unimplemented read from address "
721  "0x%llx ]\n", (long long)relative_addr);
722  }
723 
724  if (writeflag == MEM_READ) {
725 #ifdef GBE_DEBUG
726  debug("[ sgi_gbe: DEBUG: read from address 0x%llx: 0x%llx ]\n",
727  (long long)relative_addr, (long long)odata);
728 #endif
729  memory_writemax64(cpu, data, len, odata);
730  }
731 
732  return 1;
733 }
734 
735 
736 void dev_sgi_gbe_init(struct machine *machine, struct memory *mem, uint64_t baseaddr)
737 {
738  struct sgi_gbe_data *d;
739 
740  CHECK_ALLOCATION(d = (struct sgi_gbe_data *) malloc(sizeof(struct sgi_gbe_data)));
741  memset(d, 0, sizeof(struct sgi_gbe_data));
742 
743  d->xres = GBE_DEFAULT_XRES;
744  d->yres = GBE_DEFAULT_YRES;
746 
747  // My O2 says 0x300ae001 here (while running).
755 
756  // Set a value in the interrupt register that will "never happen" by default.
757  d->y_intr01 = (0xfff << 12) | 0xfff;
758  d->y_intr23 = (0xfff << 12) | 0xfff;
759 
760  // Grayscale palette, most likely overwritten immediately by the
761  // guest operating system.
762  for (int i = 0; i < 256; ++i)
763  d->palette[i] = i * 0x01010100;
764 
765  d->fb_data = dev_fb_init(machine, mem, FAKE_GBE_FB_ADDRESS,
766  VFB_GENERIC, d->xres, d->yres, d->xres, d->yres, 24, "SGI GBE");
767 
768  memory_device_register(mem, "sgi_gbe", baseaddr, DEV_SGI_GBE_LENGTH,
769  dev_sgi_gbe_access, d, DM_DEFAULT, NULL);
770  machine_add_tickfunction(machine, dev_sgi_gbe_tick, d, 19);
771 }
772 
773 
#define CRMFB_CMAP_FIFO
Definition: crmfbreg.h:212
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
uint32_t tilesize
Definition: dev_sgi_gbe.cc:86
void fatal(const char *fmt,...)
Definition: main.cc:152
uint32_t cursor_cmap1
Definition: dev_sgi_gbe.cc:94
#define CRMFB_VT_XY
Definition: crmfbreg.h:90
#define CRMFB_VT_HPIX_EN
Definition: crmfbreg.h:133
#define DM_DEFAULT
Definition: memory.h:130
#define CRMFB_CURSOR_ON
Definition: crmfbreg.h:220
uint32_t y_intr01
Definition: dev_sgi_gbe.cc:80
#define CRMFB_DOTCLOCK
Definition: crmfbreg.h:67
#define CRMFB_WID
Definition: crmfbreg.h:195
void get_rgb(struct sgi_gbe_data *d, uint32_t color, uint8_t *r, uint8_t *g, uint8_t *b)
Definition: dev_sgi_gbe.cc:112
#define CRMFB_CURSOR_POS
Definition: crmfbreg.h:214
#define CRMFB_I2C_VGA
Definition: crmfbreg.h:78
uint32_t ovr_control
Definition: dev_sgi_gbe.cc:84
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 CRMFB_VT_CRS_STARTXY
Definition: crmfbreg.h:152
#define VFB_GENERIC
Definition: devices.h:190
struct memory * mem
Definition: cpu.h:362
uint32_t y_intr23
Definition: dev_sgi_gbe.cc:81
#define CRMFB_CURSOR_CMAP0
Definition: crmfbreg.h:222
#define CRMFB_HCMAP_ON_MASK
Definition: crmfbreg.h:142
#define CRMFB_VT_HCMAP
Definition: crmfbreg.h:140
uint32_t frm_control
Definition: dev_sgi_gbe.cc:87
#define CRMFB_FRM_TILESIZE
Definition: crmfbreg.h:170
#define CRMFB_VT_DID_STARTXY
Definition: crmfbreg.h:149
struct machine * machine
Definition: cpu.h:328
uint32_t ctrlstat
Definition: dev_sgi_gbe.cc:74
#define MEM_READ
Definition: memory.h:116
#define GBE_DEFAULT_YRES
Definition: dev_sgi_gbe.cc:68
#define CRMFB_CTRLSTAT_CHIPID_MASK
Definition: crmfbreg.h:39
#define CRMFB_INTR_0_MASK
Definition: crmfbreg.h:128
uint32_t cursor_control
Definition: dev_sgi_gbe.cc:92
#define CRMFB_CMAP
Definition: crmfbreg.h:210
#define CRMFB_CURSOR_CMAP2
Definition: crmfbreg.h:224
uint32_t palette[32 *256]
Definition: dev_sgi_gbe.cc:89
#define CRMFB_MODE_CMAP_SELECT_SHIFT
Definition: crmfbreg.h:206
#define CRMFB_DMA_ENABLE
Definition: crmfbreg.h:183
uint32_t cursor_cmap2
Definition: dev_sgi_gbe.cc:95
#define CRMFB_FRM_TILESIZE_DEPTH_SHIFT
Definition: crmfbreg.h:174
#define CRMFB_CTRLSTAT
Definition: crmfbreg.h:38
void select_palette(struct sgi_gbe_data *d, int palette_nr)
Definition: dev_sgi_gbe.cc:139
uint32_t i2c
Definition: dev_sgi_gbe.cc:76
#define CRMFB_VT_XYMAX
Definition: crmfbreg.h:94
#define CRMFB_MODE_TYP_SHIFT
Definition: crmfbreg.h:197
uint32_t cursor_bitmap[64]
Definition: dev_sgi_gbe.cc:96
#define CRMFB_VT_HBLANK
Definition: crmfbreg.h:105
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
#define CRMFB_CTRLSTAT_INTERNAL_PCLK
Definition: crmfbreg.h:65
DEVICE_ACCESS(sgi_gbe)
Definition: dev_sgi_gbe.cc:375
#define CRMFB_FRM_CONTROL
Definition: crmfbreg.h:184
struct vfb_data * fb_data
Definition: dev_sgi_gbe.cc:108
#define PHYSICAL
Definition: memory.h:126
#define CRMFB_VT_VPIX_EN
Definition: crmfbreg.h:136
#define CRMFB_MODE_TYP_RGB8
Definition: crmfbreg.h:203
#define CRMFB_CURSOR_CMAP1
Definition: crmfbreg.h:223
#define CRMFB_VT_FRAMELOCK
Definition: crmfbreg.h:120
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
uint32_t cursor_cmap0
Definition: dev_sgi_gbe.cc:93
uint32_t selected_palette[256]
Definition: dev_sgi_gbe.cc:107
u_short data
Definition: siireg.h:79
#define CRMFB_VT_FLAGS
Definition: crmfbreg.h:109
#define CRMFB_VT_HCMAP_ON_SHIFT
Definition: crmfbreg.h:143
int ovr_width_in_tiles
Definition: dev_sgi_gbe.cc:102
#define CRMFB_FRM_TILESIZE_RHS_SHIFT
Definition: crmfbreg.h:171
#define CRMFB_DEVICE_ID_DEF
Definition: crmfbreg.h:87
#define MEM_WRITE
Definition: memory.h:117
#define CRMFB_VT_VSYNC
Definition: crmfbreg.h:96
#define FAKE_GBE_FB_ADDRESS
Definition: dev_sgi_gbe.cc:61
#define CRMFB_OVR_TILE_PTR
Definition: crmfbreg.h:163
#define CRMFB_FRM_PIXSIZE
Definition: crmfbreg.h:179
int ovr_partial_pixels
Definition: dev_sgi_gbe.cc:103
#define CRMFB_VT_VC_STARTXY
Definition: crmfbreg.h:155
struct x11_md x11_md
Definition: machine.h:179
#define CRMFB_FRM_TILESIZE_WIDTH_SHIFT
Definition: crmfbreg.h:173
#define CRMFB_CTRLSTAT_GPIO6_INPUT
Definition: crmfbreg.h:54
#define GBE_DEFAULT_BITDEPTH
Definition: dev_sgi_gbe.cc:69
#define debug
Definition: dev_adb.cc:57
#define CRMFB_VT_INTR23
Definition: crmfbreg.h:129
#define CRMFB_I2C_FP
Definition: crmfbreg.h:84
Definition: cpu.h:326
#define CRMFB_INTR_2_MASK
Definition: crmfbreg.h:131
#define NO_EXCEPTIONS
Definition: memory.h:125
#define CRMFB_VCMAP_ON_MASK
Definition: crmfbreg.h:146
#define CRMFB_CURSOR_BITMAP
Definition: crmfbreg.h:225
#define CRMFB_INTR_1_MASK
Definition: crmfbreg.h:127
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 *)
void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize)
Definition: dev_fb.cc:123
#define GBE_DEFAULT_XRES
Definition: dev_sgi_gbe.cc:67
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
int in_use
Definition: machine.h:82
#define CRMFB_CTRLSTAT_GPIO5_INPUT
Definition: crmfbreg.h:52
#define CRMFB_CTRLSTAT_GPIO3_INPUT
Definition: crmfbreg.h:48
void dev_sgi_gbe_init(struct machine *machine, struct memory *mem, uint64_t baseaddr)
Definition: dev_sgi_gbe.cc:736
#define CRMFB_CURSOR_CONTROL
Definition: crmfbreg.h:219
#define CRMFB_MODE_TYP_I8
Definition: crmfbreg.h:198
#define CRMFB_OVR_CONTROL
Definition: crmfbreg.h:166
Definition: memory.h:75
#define CRMFB_VT_INTR01
Definition: crmfbreg.h:126
#define CRMFB_OVR_WIDTH_TILE
Definition: crmfbreg.h:159
#define CRMFB_MODE_TYP_RG3B2
Definition: crmfbreg.h:200
addr & if(addr >=0x24 &&page !=NULL)
DEVICE_TICK(sgi_gbe)
Definition: dev_sgi_gbe.cc:163
#define CRMFB_DID_PTR
Definition: crmfbreg.h:189
#define CRMFB_DID_CONTROL
Definition: crmfbreg.h:192
uint32_t freeze
Definition: dev_sgi_gbe.cc:79
void machine_add_tickfunction(struct machine *machine, void(*func)(struct cpu *, void *), void *extra, int clockshift)
Definition: machine.cc:280
#define CRMFB_INTR_3_MASK
Definition: crmfbreg.h:130
uint32_t dotclock
Definition: dev_sgi_gbe.cc:75
#define CRMFB_VT_VBLANK
Definition: crmfbreg.h:102
#define CRMFB_CTRLSTAT_GPIO4_SENSE
Definition: crmfbreg.h:49
#define CRMFB_DEVICE_ID
Definition: crmfbreg.h:86
#define CRMFB_VT_HSYNC
Definition: crmfbreg.h:99
#define CRMFB_CTRLSTAT_GPIO4_INPUT
Definition: crmfbreg.h:50
uint32_t cursor_pos
Definition: dev_sgi_gbe.cc:91
#define CRMFB_GMAP
Definition: crmfbreg.h:213
#define CRMFB_VT_VCMAP
Definition: crmfbreg.h:144
#define CRMFB_VT_VCMAP_ON_SHIFT
Definition: crmfbreg.h:147
uint32_t ovr_tilesize
Definition: dev_sgi_gbe.cc:83
#define CRMFB_CURSOR_CROSSHAIR
Definition: crmfbreg.h:221
uint32_t i2cfp
Definition: dev_sgi_gbe.cc:77
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 Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13