dev_sgi_re.cc Source File

Back to the index.

dev_sgi_re.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 O2 "Rendering Engine"
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 (THIS FILE):
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 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 
47 #include "console.h"
48 #include "cpu.h"
49 #include "devices.h"
50 #include "machine.h"
51 #include "memory.h"
52 #include "misc.h"
53 
54 #include "thirdparty/crmfbreg.h"
55 #include "thirdparty/sgi_gl.h"
56 
57 
58 struct sgi_re_data {
59  // Rendering engine registers:
60  uint16_t re_tlb_a[256];
61  uint16_t re_tlb_b[256];
62  uint16_t re_tlb_c[256];
63  uint16_t re_tex[112];
64  // todo: clip_ids registers.
65  uint32_t re_linear_a[32];
66  uint32_t re_linear_b[32];
67 
68  // Drawing engine registers:
69  uint32_t de_reg[DEV_SGI_DE_LENGTH / sizeof(uint32_t)];
70 
71  // Memory transfer engine registers:
72  uint32_t mte_reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
73 };
74 
75 
76 /*
77  * horrible_getputpixel():
78  *
79  * This routine gets/puts a pixel in one of the tiles, from the perspective of
80  * the rendering/drawing engine. Given x and y, it figures out which tile
81  * number it is, and then finally does a slow read/write to get/put the pixel
82  * at the correct sub-coordinates within the tile.
83  *
84  * Tiles are always 512 _bytes_ wide, and 128 pixels high. For 32-bit color
85  * modes, for example, that means 128 x 128 pixels.
86  *
87  * For "linear" modes, y is ignored and x is an offset to select which linear
88  * TLB entry to use.
89  */
90 void horrible_getputpixel(bool put, struct cpu* cpu, struct sgi_re_data* d,
91  int x, int y, uint32_t* color, int mode)
92 {
93  uint32_t color_mode = mode & DE_MODE_TYPE_MASK;
94  int bufdepth = 1 << ((mode >> 8) & 3);
95 
96  // dst_mode (see NetBSD's crmfbreg.h):
97  // #define DE_MODE_TLB_A 0x00000000
98  // #define DE_MODE_TLB_B 0x00000400
99  // #define DE_MODE_TLB_C 0x00000800
100  // #define DE_MODE_LIN_A 0x00001000
101  // #define DE_MODE_LIN_B 0x00001400
102  uint32_t tlb_mode = (mode >> 10) & 0x7;
103  bool linear = tlb_mode > 3;
104 
105  if (!linear && (x < 0 || y < 0 || x >= 2048 || y >= 2048))
106  return;
107 
108  int tilewidth_in_pixels = 512 / bufdepth;
109 
110  int tile_nr_x = x / tilewidth_in_pixels;
111  int tile_nr_y = y >> 7;
112 
113  unsigned int tile_nr = tile_nr_y * 16 + tile_nr_x;
114 
115  y &= 127;
116  int xofs = (x % tilewidth_in_pixels) * bufdepth;
117  int ofs = 512 * y + xofs;
118 
119  uint32_t tileptr = 0;
120 
121  switch (tlb_mode) {
122  case 0: tileptr = d->re_tlb_a[tile_nr] << 16;
123  break;
124  case 1: tileptr = d->re_tlb_b[tile_nr] << 16;
125  break;
126  case 2: tileptr = d->re_tlb_c[tile_nr] << 16;
127  break;
128  case 4: tile_nr = x >> 12;
129  if (tile_nr >= 32)
130  return;
131  tileptr = 0x80000000 | (d->re_linear_a[tile_nr] << 12);
132  ofs = x & 4095;
133  // TODO... probably not correct!
134  // printf("tileptr = %08x x = %i y = %i tile_nr = %i ofs = %i\n", tileptr, x, y, tile_nr, ofs);
135  break;
136  default:fatal("unimplemented dst_mode %i for horrible_getputpixel (%s), x=%i y=%i\n",
137  mode, put ? "put" : "get", x, y);
138  // exit(1);
139  *color = random();
140  return;
141  }
142 
143  // The highest bit seems to be set for a "valid" tile pointer.
144  if (!(tileptr & 0x80000000)) {
145  //printf("dst_mode %i, tile_nr = %i, tileptr = 0x%llx\n", dst_mode, tile_nr, (long long)tileptr);
146  //fatal("sgi gbe horrible_getputpixel: unexpected non-set high bit of tileptr?\n");
147  //exit(1);
148  return;
149  }
150 
151  tileptr &= ~0x80000000;
152 
153  uint8_t buf[4];
154  if (put) {
155  switch (color_mode) {
156  case DE_MODE_TYPE_CI:
157  buf[0] = *color;
158  break;
159  case DE_MODE_TYPE_RGB:
160  buf[0] = *color >> 24;
161  buf[1] = *color >> 16;
162  buf[2] = *color >> 8;
163  buf[3] = 0;
164  break;
165  case DE_MODE_TYPE_RGBA:
166  buf[0] = *color >> 24;
167  buf[1] = *color >> 16;
168  buf[2] = *color >> 8;
169  buf[3] = *color;
170  break;
171  case DE_MODE_TYPE_ABGR:
172  buf[0] = *color;
173  buf[1] = *color >> 8;
174  buf[2] = *color >> 16;
175  buf[3] = *color >> 24;
176  break;
177  default:buf[0] = random();
178  buf[1] = random();
179  buf[2] = random();
180  buf[3] = random();
181  // TODO.
182  fatal("[ put: color mode = 0x%x ]\n", color_mode);
183  }
184 
185  cpu->memory_rw(cpu, cpu->mem, tileptr + ofs,
186  buf, bufdepth, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
187  } else {
188  cpu->memory_rw(cpu, cpu->mem, tileptr + ofs,
189  buf, bufdepth, MEM_READ, NO_EXCEPTIONS | PHYSICAL);
190 
191  switch (color_mode) {
192  case DE_MODE_TYPE_CI:
193  *color = buf[0];
194  break;
195  case DE_MODE_TYPE_RGB:
196  *color = (buf[1] << 24) + (buf[2] << 16) + (buf[3] << 8);
197  break;
198  case DE_MODE_TYPE_RGBA:
199  *color = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
200  break;
201  case DE_MODE_TYPE_ABGR:
202  *color = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
203  break;
204  default:// Read "raw" 32-bit value:
205  *color = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
206  fatal("[ get: color mode = 0x%x ]\n", color_mode);
207  }
208  }
209 }
210 
211 
212 /*
213  * SGI "re", NetBSD sources describes it as a "rendering engine".
214  */
215 
217 {
218  struct sgi_re_data *d = (struct sgi_re_data *) extra;
219  uint64_t idata = 0, odata = 0;
220 
221  idata = memory_readmax64(cpu, data, len);
222 
223  relative_addr += 0x1000;
224 
225  if (relative_addr >= CRIME_RE_TLB_A && relative_addr < CRIME_RE_TLB_B) {
226  if (len != 8) {
227  fatal("TODO: unimplemented len=%i for CRIME_RE_TLB_A\n", len);
228  exit(1);
229  }
230 
231  if (writeflag == MEM_WRITE) {
232  int tlbi = ((relative_addr & 0x1ff) >> 1) & 0xff;
233  for (size_t hwi = 0; hwi < len; hwi += sizeof(uint16_t)) {
234  d->re_tlb_a[tlbi] = data[hwi]*256 + data[hwi+1];
235  debug("d->re_tlb_a[%i] = 0x%04x\n", tlbi, d->re_tlb_a[tlbi]);
236  tlbi++;
237  }
238  } else {
239  fatal("TODO: read from CRIME_RE_TLB_A\n");
240  exit(1);
241  }
242  } else if (relative_addr >= CRIME_RE_TLB_B && relative_addr < CRIME_RE_TLB_C) {
243  if (len != 8) {
244  fatal("TODO: unimplemented len=%i for CRIME_RE_TLB_B\n", len);
245  exit(1);
246  }
247 
248  if (writeflag == MEM_WRITE) {
249  int tlbi = ((relative_addr & 0x1ff) >> 1) & 0xff;
250  for (size_t hwi = 0; hwi < len; hwi += sizeof(uint16_t)) {
251  d->re_tlb_b[tlbi] = data[hwi]*256 + data[hwi+1];
252  debug("d->re_tlb_b[%i] = 0x%04x\n", tlbi, d->re_tlb_b[tlbi]);
253  tlbi++;
254  }
255  } else {
256  fatal("TODO: read from CRIME_RE_TLB_B\n");
257  exit(1);
258  }
259  } else if (relative_addr >= CRIME_RE_TLB_C && relative_addr < CRIME_RE_TLB_C + 0x200) {
260  if (len != 8) {
261  fatal("TODO: unimplemented len=%i for CRIME_RE_TLB_C\n", len);
262  exit(1);
263  }
264 
265  if (writeflag == MEM_WRITE) {
266  int tlbi = ((relative_addr & 0x1ff) >> 1) & 0xff;
267  for (size_t hwi = 0; hwi < len; hwi += sizeof(uint16_t)) {
268  d->re_tlb_c[tlbi] = data[hwi]*256 + data[hwi+1];
269  debug("d->re_tlb_c[%i] = 0x%04x\n", tlbi, d->re_tlb_c[tlbi]);
270  tlbi++;
271  }
272  } else {
273  fatal("TODO: read from CRIME_RE_TLB_C\n");
274  exit(1);
275  }
276  } else if (relative_addr >= CRIME_RE_TEX && relative_addr < CRIME_RE_TEX + 0xe0) {
277  if (len != 8) {
278  fatal("TODO: unimplemented len=%i for CRIME_RE_TEX\n", len);
279  exit(1);
280  }
281 
282  if (writeflag == MEM_WRITE) {
283  int tlbi = ((relative_addr & 0xff) >> 3) & 0xff;
284  for (size_t hwi = 0; hwi < len; hwi += sizeof(uint16_t)) {
285  d->re_tex[tlbi] = data[hwi]*256 + data[hwi+1];
286  debug("d->re_tex[%i] = 0x%04x\n", tlbi, d->re_tex[tlbi]);
287  tlbi++;
288  }
289  } else {
290  fatal("TODO: read from CRIME_RE_TEX\n");
291  exit(1);
292  }
293  } else if (relative_addr >= CRIME_RE_LINEAR_A && relative_addr < CRIME_RE_LINEAR_A + 0x80) {
294  if (len != 8) {
295  fatal("TODO: unimplemented len=%i for CRIME_RE_LINEAR_A\n", len);
296  exit(1);
297  }
298 
299  if (writeflag == MEM_WRITE) {
300  /*
301  * Very interesting. NetBSD writes stuff such as:
302  *
303  * CRIME_RE_LINEAR_A IDATA = 8000173080001731
304  * CRIME_RE_LINEAR_A IDATA = 8000173280001733
305  * CRIME_RE_LINEAR_A IDATA = 8000173480001735
306  * ...
307  *
308  * but the PROM writes something which looks like wrongly
309  * 32-bit sign-extended words:
310  *
311  * CRIME_RE_LINEAR_A IDATA = ffffffff80040001
312  * CRIME_RE_LINEAR_A IDATA = ffffffff80040003
313  * CRIME_RE_LINEAR_A IDATA = ffffffff80040005
314  * ...
315  *
316  * followed by
317  * [ sgi_mte: STARTING TRANSFER: mode=0x00000011
318  * dst0=0x0000000040000000, dst1=0x0000000040007fff
319  * (length 0x8000), dst_y_step=0 bg=0x0, bytemask=0xffffffff ]
320  *
321  * indicating that it really meant to put both 0x80040000
322  * and 0x80040001 into the first LINEAR_A entry.
323  *
324  * The first guess would be a bug in the implementation of
325  * one or more instructions in the emulator while coming up
326  * with those values, but debugging the PROM so far has NOT
327  * revealed any such bug. It may even be that the PROM code
328  * is buggy (?) and never really set the LINEAR entries
329  * correctly. Perhaps the hardware simply ignores the
330  * weird values and does not fill it (using the MTE)
331  * when asked to.
332  */
333  // printf("CRIME_RE_LINEAR_A IDATA = %016llx\n", (long long)idata);
334  int tlbi = ((relative_addr & 0x7f) >> 2) & 0x1f;
335  d->re_linear_a[tlbi] = idata >> 32ULL;
336  d->re_linear_a[tlbi+1] = idata;
337  debug("[ d->re_linear_a[%i] = 0x%08x, [%i] = 0x%08x ]\n",
338  tlbi, d->re_linear_a[tlbi], tlbi+1, d->re_linear_a[tlbi+1]);
339  } else {
340  fatal("TODO: read from CRIME_RE_LINEAR_A\n");
341  exit(1);
342  }
343  } else if (relative_addr >= CRIME_RE_LINEAR_B && relative_addr < CRIME_RE_LINEAR_B + 0x80) {
344  if (len != 8) {
345  fatal("TODO: unimplemented len=%i for CRIME_RE_LINEAR_B\n", len);
346  exit(1);
347  }
348 
349  if (writeflag == MEM_WRITE) {
350  int tlbi = ((relative_addr & 0x7f) >> 2) & 0x1f;
351  d->re_linear_b[tlbi] = idata >> 32ULL;
352  d->re_linear_b[tlbi+1] = idata;
353  debug("[ d->re_linear_b[%i] = 0x%08x, [%i] = 0x%08x ]\n",
354  tlbi, d->re_linear_b[tlbi], tlbi+1, d->re_linear_b[tlbi+1]);
355  } else {
356  fatal("TODO: read from CRIME_RE_LINEAR_B\n");
357  exit(1);
358  }
359  } else {
360  if (writeflag == MEM_WRITE)
361  fatal("[ sgi_re: unimplemented write to "
362  "address 0x%llx, data=0x%016llx ]\n",
363  (long long)relative_addr, (long long)idata);
364  else
365  fatal("[ sgi_re: unimplemented read from address"
366  " 0x%llx ]\n", (long long)relative_addr);
367  exit(1);
368  }
369 
370  if (writeflag == MEM_READ)
371  memory_writemax64(cpu, data, len, odata);
372 
373  return 1;
374 }
375 
376 
377 /*
378  * dev_sgi_re_init():
379  */
380 void dev_sgi_re_init(struct machine *machine, struct memory *mem, uint64_t baseaddr)
381 {
382  struct sgi_re_data *d;
383 
384  CHECK_ALLOCATION(d = (struct sgi_re_data *) malloc(sizeof(struct sgi_re_data)));
385  memset(d, 0, sizeof(struct sgi_re_data));
386 
387  memory_device_register(mem, "sgi_re", baseaddr + 0x1000, DEV_SGI_RE_LENGTH,
388  dev_sgi_re_access, d, DM_DEFAULT, NULL);
389 
390  dev_sgi_de_init(mem, baseaddr + 0x2000, d);
391  dev_sgi_mte_init(mem, baseaddr + 0x3000, d);
392  dev_sgi_de_status_init(mem, baseaddr + 0x4000, d);
393 }
394 
395 
396 
397 /****************************************************************************/
398 
399 /*
400  * SGI "de", NetBSD sources describes it as a "drawing engine".
401  */
402 
403 void draw_primitive(struct cpu* cpu, struct sgi_re_data *d)
404 {
405  uint32_t op = d->de_reg[(CRIME_DE_PRIMITIVE - 0x2000) / sizeof(uint32_t)];
406  uint32_t drawmode = d->de_reg[(CRIME_DE_DRAWMODE - 0x2000) / sizeof(uint32_t)];
407  uint32_t dst_mode = d->de_reg[(CRIME_DE_MODE_DST - 0x2000) / sizeof(uint32_t)];
408  uint32_t src_mode = d->de_reg[(CRIME_DE_MODE_SRC - 0x2000) / sizeof(uint32_t)];
409  uint32_t fg = d->de_reg[(CRIME_DE_FG - 0x2000) / sizeof(uint32_t)];
410  uint32_t bg = d->de_reg[(CRIME_DE_BG - 0x2000) / sizeof(uint32_t)];
411  uint32_t rop = d->de_reg[(CRIME_DE_ROP - 0x2000) / sizeof(uint32_t)];
412 
413  uint32_t stipple_mode = d->de_reg[(CRIME_DE_STIPPLE_MODE - 0x2000) / sizeof(uint32_t)];
414  uint32_t pattern = d->de_reg[(CRIME_DE_STIPPLE_PAT - 0x2000) / sizeof(uint32_t)];
415  int nr_of_bits_to_strip_to_the_left = (stipple_mode >> DE_STIP_STRTIDX_SHIFT) & 31;
416  int nr_of_bits_to_strip_to_the_right = 31 - ((stipple_mode >> DE_STIP_MAXIDX_SHIFT) & 31);
417  pattern >>= nr_of_bits_to_strip_to_the_right;
418  pattern <<= nr_of_bits_to_strip_to_the_right;
419  pattern <<= nr_of_bits_to_strip_to_the_left;
420 
421  int nr_of_bits_in_the_middle = 32 - nr_of_bits_to_strip_to_the_left - nr_of_bits_to_strip_to_the_right;
422 
423  if (stipple_mode & 0xe0e0ffff)
424  fatal("[ sgi_de: UNIMPLEMENTED stipple_mode bits: 0x%08x ]\n", stipple_mode);
425 
426  uint32_t x1 = (d->de_reg[(CRIME_DE_X_VERTEX_0 - 0x2000) / sizeof(uint32_t)] >> 16) & 0x7ff;
427  uint32_t y1 = d->de_reg[(CRIME_DE_X_VERTEX_0 - 0x2000) / sizeof(uint32_t)]& 0x7ff;
428  uint32_t x2 = (d->de_reg[(CRIME_DE_X_VERTEX_1 - 0x2000) / sizeof(uint32_t)] >> 16) & 0x7ff;
429  uint32_t y2 = d->de_reg[(CRIME_DE_X_VERTEX_1 - 0x2000) / sizeof(uint32_t)]& 0x7ff;
430  size_t x, y;
431 
432  debug("[ sgi_de: STARTING DRAWING COMMAND: op = 0x%08x,"
433  " drawmode=0x%x src_mode=0x%x dst_mode=0x%x x1=%i y1=%i"
434  " x2=%i y2=%i fg=0x%x bg=0x%x pattern=0x%08x ]\n",
435  op, drawmode, src_mode, dst_mode, x1, y1, x2, y2, fg, bg, pattern);
436 
437  // bufdepth = 1, 2, or 4.
438  // int dst_bufdepth = 1 << ((dst_mode >> 8) & 3);
439  int src_bufdepth = 1 << ((src_mode >> 8) & 3);
440 
441  bool src_is_linear = false;
442  int src_x = -1, src_y = -1;
443  int32_t step_x = 0;
444  if (drawmode & DE_DRAWMODE_XFER_EN) {
445  uint32_t addr_src = d->de_reg[(CRIME_DE_XFER_ADDR_SRC - 0x2000) / sizeof(uint32_t)];
446  uint32_t strd_src = d->de_reg[(CRIME_DE_XFER_STRD_SRC - 0x2000) / sizeof(uint32_t)];
447  step_x = d->de_reg[(CRIME_DE_XFER_STEP_X - 0x2000) / sizeof(uint32_t)];
448  int32_t step_y = d->de_reg[(CRIME_DE_XFER_STEP_Y - 0x2000) / sizeof(uint32_t)];
449  uint32_t addr_dst = d->de_reg[(CRIME_DE_XFER_ADDR_DST - 0x2000) / sizeof(uint32_t)];
450  uint32_t strd_dst = d->de_reg[(CRIME_DE_XFER_STRD_DST - 0x2000) / sizeof(uint32_t)];
451 
452  src_is_linear = ((src_mode & 0x00001c00) >> 10) > 3;
453 
454  if (src_is_linear) {
455  src_x = addr_src;
456  src_y = 0;
457  } else {
458  src_x = (addr_src >> 16) & 0x7ff;
459  src_y = addr_src & 0x7ff;
460  }
461 
462  if (step_x != src_bufdepth || (step_y != 0 && step_y != 1)) {
463  fatal("[ sgi_de: unimplemented XFER addr_src=0x%x src_bufdepth=%i "
464  "strd_src=0x%x step_x=0x%x step_y=0x%x "
465  "addr_dst=0x%x strd_dst=0x%x ]\n",
466  addr_src, src_bufdepth, strd_src, step_x, step_y, addr_dst, strd_dst);
467 
468  // exit(1);
469  }
470  }
471 
472  if (!(drawmode & DE_DRAWMODE_PLANEMASK)) {
473  printf("!DE_DRAWMODE_PLANEMASK: TODO\n");
474  }
475 
476  if ((drawmode & DE_DRAWMODE_BYTEMASK) != DE_DRAWMODE_BYTEMASK) {
477  printf("not all DE_DRAWMODE_BYTEMASK set: TODO\n");
478  }
479 
480  // primitive rendering direction (not for Lines? and presumably
481  // not for Points either :-)
482  int dx = op & DE_PRIM_RL ? -1 : 1;
483  int dy = op & DE_PRIM_TB ? 1 : -1;
484 
485  uint16_t saved_src_x = src_x;
486 
487  /*
488  * Drawing is limited to 2048 x 2048 pixel space.
489  *
490  * TODO: MAYBE it is really -2048 to 2027, i.e. 12 bits of
491  * pixel space. Perhaps it is possible to figure out
492  * experimentally some day, e.g. by drawing lines from
493  * -10,10 to 500,20 and see whether the real hardware
494  * interprets -10 as -10 or 0x800 - 10.
495  */
496  uint16_t endx = (x2 + dx) & 0x7ff;
497  uint16_t endy = (y2 + dy) & 0x7ff;
498 
499  int lx = abs((int)(x2 - x1)), ly = abs((int)(y2 - y1));
500  int linelen = lx > ly ? lx : ly;
501 
502  switch (op & 0xff000000) {
503  case DE_PRIM_LINE:
504  if (drawmode & DE_DRAWMODE_XFER_EN)
505  fatal("[ sgi_de: XFER_EN for LINE op? ]\n");
506 
507  // The PROM uses width 32, but NetBSD documents it as "half pixels".
508  // if ((op & DE_PRIM_LINE_WIDTH_MASK) != 2)
509  // fatal("[ sgi_de: LINE_WIDTH_MASK = %i ]\n", op & DE_PRIM_LINE_WIDTH_MASK);
510 
511  if (linelen == 0)
512  linelen ++;
513 
514  for (int i = 0; i < ((op & DE_PRIM_LINE_SKIP_END)? linelen : linelen+1); ++i) {
515  x = (x2 * i + x1 * (linelen-i)) / linelen;
516  y = (y2 * i + y1 * (linelen-i)) / linelen;
517 
518  uint32_t color = fg;
519  uint32_t oldcolor = fg;
520 
521  if (drawmode & DE_DRAWMODE_ROP && rop != OPENGL_LOGIC_OP_COPY)
522  horrible_getputpixel(false, cpu, d,
523  x, y, &oldcolor, dst_mode);
524 
525  bool draw = true;
526  if (drawmode & DE_DRAWMODE_LINE_STIP) {
527  if (drawmode & DE_DRAWMODE_OPAQUE_STIP)
528  color = (pattern & 0x80000000UL) ? fg : bg;
529  else
530  draw = (pattern & 0x80000000UL)? true : false;
531  }
532 
533  // Raster-OP.
534  // TODO: Other ops.
535  // TODO: Should this be before or after other things?
536  if (drawmode & DE_DRAWMODE_ROP) {
537  switch (rop) {
539  // color = color;
540  break;
541  case OPENGL_LOGIC_OP_XOR:
542  color = oldcolor ^ color;
543  break;
545  color = 0xffffffff - oldcolor;
546  break;
547  default:{
548  static char rop_used[256];
549  static bool first = true;
550 
551  if (first) {
552  memset(rop_used, 0, sizeof(rop_used));
553  first = false;
554  }
555  if (!rop_used[rop & 255]) {
556  rop_used[rop & 255] = 1;
557  fatal("[ sgi_de: LINE: rop[0x%02x] used! ]\n", rop & 255);
558  }
559 
560  if (rop >> 8) {
561  fatal("[ sgi_de: LINE: rop > 255: 0x%08x ]\n", rop);
562  }
563  }
564  }
565  }
566 
567  if (draw)
568  horrible_getputpixel(true, cpu, d,
569  x, y, &color, dst_mode);
570 
571  // Rotate the stipple pattern:
572  pattern = (pattern << 1) | (pattern >> (nr_of_bits_in_the_middle-1));
573  }
574  break;
575 
576  case DE_PRIM_RECTANGLE:
577  for (y = y1; y != endy; y = (y + dy) & 0x7ff) {
578  src_x = saved_src_x;
579  for (x = x1; x != endx; x = (x + dx) & 0x7ff) {
580  uint32_t color = fg;
581  uint32_t oldcolor = fg;
582 
583  if (drawmode & DE_DRAWMODE_ROP && rop != OPENGL_LOGIC_OP_COPY)
584  horrible_getputpixel(false, cpu, d,
585  x, y, &oldcolor, dst_mode);
586 
587  // Pixel colors copied from another source.
588  // (OpenBSD draws characters using this mechanism.)
589  if (drawmode & DE_DRAWMODE_XFER_EN)
590  horrible_getputpixel(false, cpu, d,
591  src_x, src_y, &color, src_mode);
592 
593  bool draw = true;
594  if (drawmode & DE_DRAWMODE_POLY_STIP) {
595  if (drawmode & DE_DRAWMODE_OPAQUE_STIP)
596  color = (pattern & 0x80000000UL) ? fg : bg;
597  else
598  draw = (pattern & 0x80000000UL)? true : false;
599  }
600 
601  // Raster-OP.
602  // TODO: Other ops.
603  // TODO: Should this be before or after other things?
604  if (drawmode & DE_DRAWMODE_ROP) {
605  switch (rop) {
607  // color = color;
608  break;
609  case OPENGL_LOGIC_OP_XOR:
610  color = oldcolor ^ color;
611  break;
613  color = 0xffffffff - oldcolor;
614  break;
615  default:{
616  static char rop_used[256];
617  static bool first = true;
618 
619  if (first) {
620  memset(rop_used, 0, sizeof(rop_used));
621  first = false;
622  }
623  if (!rop_used[rop & 255]) {
624  rop_used[rop & 255] = 1;
625  fatal("[ sgi_de: RECT: rop[0x%02x] used! ]\n", rop & 255);
626  }
627 
628  if (rop >> 8) {
629  fatal("[ sgi_de: RECT: rop > 255: 0x%08x ]\n", rop);
630  }
631  }
632  }
633  }
634 
635  if (draw)
636  horrible_getputpixel(true, cpu, d,
637  x, y, &color, dst_mode);
638 
639  // Rotate the stipple pattern:
640  pattern = (pattern << 1) | (pattern >> (nr_of_bits_in_the_middle-1));
641 
642  if (src_is_linear)
643  src_x += step_x;
644  else
645  src_x = (src_x + dx) & 0x7ff;
646  }
647 
648  src_y = (src_y + dy) & 0x7ff;
649  }
650  break;
651 
652  default:fatal("[ sgi_de: UNIMPLEMENTED drawing op = 0x%08x,"
653  " x1=%i y1=%i x2=%i y2=%i fg=0x%x bg=0x%x pattern=0x%08x ]\n",
654  op, x1, y1, x2, y2, fg, bg, pattern);
655  exit(1);
656  }
657 }
658 
660 {
661  struct sgi_re_data *d = (struct sgi_re_data *) extra;
662  uint64_t idata = 0, odata = 0;
663  int regnr;
664  bool startFlag = relative_addr & CRIME_DE_START ? true : false;
665 
666  relative_addr &= ~CRIME_DE_START;
667 
668  idata = memory_readmax64(cpu, data, len);
669  regnr = relative_addr / sizeof(uint32_t);
670 
671  relative_addr += 0x2000;
672 
673  /*
674  * Treat all registers as read/write, by default. Sometimes these
675  * are accessed as 32-bit words, sometimes as 64-bit words to access
676  * two adjacent registers in one operation.
677  */
678  if (len == 8) {
679  if (writeflag == MEM_WRITE) {
680  d->de_reg[regnr] = idata >> 32ULL;
681  d->de_reg[regnr+1] = idata;
682  } else
683  odata = ((uint64_t)d->de_reg[regnr] << 32ULL) +
684  d->de_reg[regnr+1];
685  } else if (len == 4) {
686  if (writeflag == MEM_WRITE)
687  d->de_reg[regnr] = idata;
688  else
689  odata = d->de_reg[regnr];
690  } else {
691  fatal("sgi_de: len = %i not implemented\n", len);
692  exit(1);
693  }
694 
695  switch (relative_addr) {
696 
697  case CRIME_DE_MODE_SRC:
698  debug("[ sgi_de: %s CRIME_DE_MODE_SRC: 0x%016llx ]\n",
699  writeflag == MEM_WRITE ? "write to" : "read from",
700  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
701  break;
702 
703  case CRIME_DE_MODE_DST:
704  debug("[ sgi_de: %s CRIME_DE_MODE_DST: 0x%016llx ]\n",
705  writeflag == MEM_WRITE ? "write to" : "read from",
706  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
707  break;
708 
709  case CRIME_DE_CLIPMODE:
710  debug("[ sgi_de: %s CRIME_DE_CLIPMODE: 0x%016llx ]\n",
711  writeflag == MEM_WRITE ? "write to" : "read from",
712  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
713  if (writeflag == MEM_WRITE && idata != 0)
714  fatal("[ sgi_de: TODO: non-zero CRIME_DE_CLIPMODE: 0x%016llx ]\n", idata);
715  break;
716 
717  case CRIME_DE_DRAWMODE:
718  debug("[ sgi_de: %s CRIME_DE_DRAWMODE: 0x%016llx ]\n",
719  writeflag == MEM_WRITE ? "write to" : "read from",
720  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
721  break;
722 
723  case CRIME_DE_SCRMASK0:
724  debug("[ sgi_de: %s CRIME_DE_SCRMASK0: 0x%016llx ]\n",
725  writeflag == MEM_WRITE ? "write to" : "read from",
726  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
727  if (writeflag == MEM_WRITE && idata != 0)
728  fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK0: 0x%016llx ]\n", idata);
729  break;
730 
731  case CRIME_DE_SCRMASK1:
732  debug("[ sgi_de: %s CRIME_DE_SCRMASK1: 0x%016llx ]\n",
733  writeflag == MEM_WRITE ? "write to" : "read from",
734  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
735  if (writeflag == MEM_WRITE && idata != 0)
736  fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK1: 0x%016llx ]\n", idata);
737  break;
738 
739  case CRIME_DE_SCRMASK2:
740  debug("[ sgi_de: %s CRIME_DE_SCRMASK2: 0x%016llx ]\n",
741  writeflag == MEM_WRITE ? "write to" : "read from",
742  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
743  if (writeflag == MEM_WRITE && idata != 0)
744  fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK2: 0x%016llx ]\n", idata);
745  break;
746 
747  case CRIME_DE_SCRMASK3:
748  debug("[ sgi_de: %s CRIME_DE_SCRMASK3: 0x%016llx ]\n",
749  writeflag == MEM_WRITE ? "write to" : "read from",
750  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
751  if (writeflag == MEM_WRITE && idata != 0)
752  fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK3: 0x%016llx ]\n", idata);
753  break;
754 
755  case CRIME_DE_SCRMASK4:
756  debug("[ sgi_de: %s CRIME_DE_SCRMASK4: 0x%016llx ]\n",
757  writeflag == MEM_WRITE ? "write to" : "read from",
758  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
759  if (writeflag == MEM_WRITE && idata != 0)
760  fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK4: 0x%016llx ]\n", idata);
761  break;
762 
763  case CRIME_DE_SCISSOR:
764  debug("[ sgi_de: %s CRIME_DE_SCISSOR: 0x%016llx ]\n",
765  writeflag == MEM_WRITE ? "write to" : "read from",
766  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
767  if (writeflag == MEM_WRITE && idata != 0)
768  fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCISSOR: 0x%016llx ]\n", idata);
769  break;
770 
771  case CRIME_DE_SCISSOR + 4:
772  // NetBSD writes 0x3fff3fff here. "High" part of SCISSOR register?
773  debug("[ sgi_de: %s CRIME_DE_SCISSOR+4: 0x%016llx ]\n",
774  writeflag == MEM_WRITE ? "write to" : "read from",
775  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
776  if (writeflag == MEM_WRITE && idata != 0x3fff3fff)
777  fatal("[ sgi_de: TODO: CRIME_DE_SCISSOR+4: 0x%016llx ]\n", idata);
778  break;
779 
780  case CRIME_DE_PRIMITIVE:
781  debug("[ sgi_de: %s CRIME_DE_PRIMITIVE: 0x%016llx ]\n",
782  writeflag == MEM_WRITE ? "write to" : "read from",
783  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
784  break;
785 
787  debug("[ sgi_de: %s CRIME_DE_WINOFFSET_SRC: 0x%016llx ]\n",
788  writeflag == MEM_WRITE ? "write to" : "read from",
789  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
790  if (writeflag == MEM_WRITE && idata != 0)
791  fatal("[ sgi_de: TODO: non-zero CRIME_DE_WINOFFSET_SRC: 0x%016llx ]\n", idata);
792  break;
793 
795  debug("[ sgi_de: %s CRIME_DE_WINOFFSET_DST: 0x%016llx ]\n",
796  writeflag == MEM_WRITE ? "write to" : "read from",
797  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
798  if (writeflag == MEM_WRITE && idata != 0)
799  fatal("[ sgi_de: TODO: non-zero CRIME_DE_WINOFFSET_DST: 0x%016llx ]\n", idata);
800  break;
801 
802  case CRIME_DE_X_VERTEX_0:
803  debug("[ sgi_de: %s CRIME_DE_X_VERTEX_0: 0x%016llx ]\n",
804  writeflag == MEM_WRITE ? "write to" : "read from",
805  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
806  break;
807 
808  case CRIME_DE_X_VERTEX_1:
809  debug("[ sgi_de: %s CRIME_DE_X_VERTEX_1: 0x%016llx ]\n",
810  writeflag == MEM_WRITE ? "write to" : "read from",
811  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
812  break;
813 
815  debug("[ sgi_de: %s CRIME_DE_XFER_ADDR_SRC: 0x%016llx ]\n",
816  writeflag == MEM_WRITE ? "write to" : "read from",
817  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
818  break;
819 
821  debug("[ sgi_de: %s CRIME_DE_XFER_STRD_SRC: 0x%016llx ]\n",
822  writeflag == MEM_WRITE ? "write to" : "read from",
823  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
824  break;
825 
827  debug("[ sgi_de: %s CRIME_DE_XFER_STEP_X: 0x%016llx ]\n",
828  writeflag == MEM_WRITE ? "write to" : "read from",
829  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
830  break;
831 
833  debug("[ sgi_de: %s CRIME_DE_XFER_STEP_Y: 0x%016llx ]\n",
834  writeflag == MEM_WRITE ? "write to" : "read from",
835  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
836  break;
837 
839  debug("[ sgi_de: %s CRIME_DE_XFER_ADDR_DST: 0x%016llx ]\n",
840  writeflag == MEM_WRITE ? "write to" : "read from",
841  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
842  break;
843 
845  debug("[ sgi_de: %s CRIME_DE_XFER_STRD_DST: 0x%016llx ]\n",
846  writeflag == MEM_WRITE ? "write to" : "read from",
847  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
848  break;
849 
851  debug("[ sgi_de: %s CRIME_DE_STIPPLE_MODE: 0x%016llx ]\n",
852  writeflag == MEM_WRITE ? "write to" : "read from",
853  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
854  break;
855 
857  debug("[ sgi_de: %s CRIME_DE_STIPPLE_PAT: 0x%016llx ]\n",
858  writeflag == MEM_WRITE ? "write to" : "read from",
859  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
860  break;
861 
862  case CRIME_DE_FG:
863  debug("[ sgi_de: %s CRIME_DE_FG: 0x%016llx ]\n",
864  writeflag == MEM_WRITE ? "write to" : "read from",
865  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
866  break;
867 
868  case CRIME_DE_BG:
869  debug("[ sgi_de: %s CRIME_DE_BG: 0x%016llx ]\n",
870  writeflag == MEM_WRITE ? "write to" : "read from",
871  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
872  break;
873 
874  case CRIME_DE_ROP:
875  debug("[ sgi_de: %s CRIME_DE_ROP: 0x%016llx ]\n",
876  writeflag == MEM_WRITE ? "write to" : "read from",
877  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
878  break;
879 
880  case CRIME_DE_PLANEMASK:
881  debug("[ sgi_de: %s CRIME_DE_PLANEMASK: 0x%016llx ]\n",
882  writeflag == MEM_WRITE ? "write to" : "read from",
883  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
884  break;
885 
886  case CRIME_DE_NULL:
887  debug("[ sgi_de: %s CRIME_DE_NULL: 0x%016llx ]\n",
888  writeflag == MEM_WRITE ? "write to" : "read from",
889  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
890  break;
891 
892  case CRIME_DE_FLUSH:
893  debug("[ sgi_de: %s CRIME_DE_FLUSH: 0x%016llx ]\n",
894  writeflag == MEM_WRITE ? "write to" : "read from",
895  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
896  break;
897 
898  default:
899  if (writeflag == MEM_WRITE)
900  fatal("[ sgi_de: unimplemented write to "
901  "address 0x%llx, data=0x%016llx ]\n",
902  (long long)relative_addr, (long long)idata);
903  else
904  fatal("[ sgi_de: unimplemented read from address"
905  " 0x%llx ]\n", (long long)relative_addr);
906  }
907 
908  if (startFlag)
909  draw_primitive(cpu, d);
910 
911  if (writeflag == MEM_READ)
912  memory_writemax64(cpu, data, len, odata);
913 
914  return 1;
915 }
916 
917 
918 /*
919  * dev_sgi_de_init():
920  */
921 void dev_sgi_de_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d)
922 {
923  memory_device_register(mem, "sgi_de", baseaddr, DEV_SGI_DE_LENGTH,
924  dev_sgi_de_access, (void *)d, DM_DEFAULT, NULL);
925 }
926 
927 
928 /****************************************************************************/
929 
930 /*
931  * SGI "mte", NetBSD sources describes it as a "memory transfer engine".
932  *
933  * If the relative address has the 0x0800 (CRIME_DE_START) flag set, it means
934  * "go ahead with the transfer". Otherwise, it is just reads and writes of the
935  * registers.
936  */
937 
938 void do_mte_transfer(struct cpu* cpu, struct sgi_re_data *d)
939 {
940  uint32_t mode = d->mte_reg[(CRIME_MTE_MODE - 0x3000) / sizeof(uint32_t)];
941  uint32_t src0 = d->mte_reg[(CRIME_MTE_SRC0 - 0x3000) / sizeof(uint32_t)];
942  uint32_t src1 = d->mte_reg[(CRIME_MTE_SRC1 - 0x3000) / sizeof(uint32_t)];
943  uint32_t dst0 = d->mte_reg[(CRIME_MTE_DST0 - 0x3000) / sizeof(uint32_t)];
944  uint32_t dst1 = d->mte_reg[(CRIME_MTE_DST1 - 0x3000) / sizeof(uint32_t)];
945  int32_t src_y_step = d->mte_reg[(CRIME_MTE_SRC_Y_STEP - 0x3000) / sizeof(uint32_t)];
946  int32_t dst_y_step = d->mte_reg[(CRIME_MTE_DST_Y_STEP - 0x3000) / sizeof(uint32_t)];
947  uint32_t dstlen = dst1 - dst0 + 1, fill_addr;
948  unsigned char zerobuf[4096];
949  int depth = 8 << ((mode & MTE_MODE_DEPTH_MASK) >> MTE_DEPTH_SHIFT);
950  int src = (mode & MTE_MODE_SRC_BUF_MASK) >> MTE_SRC_TLB_SHIFT;
951  uint32_t bytemask = d->mte_reg[(CRIME_MTE_BYTEMASK - 0x3000) / sizeof(uint32_t)];
952  uint32_t bg = d->mte_reg[(CRIME_MTE_BG - 0x3000) / sizeof(uint32_t)];
953 
954  debug("[ sgi_mte: STARTING: mode=0x%08x src0=0x%08x src1=0x%08x src_y_step=%i dst0=0x%08x,"
955  " dst1=0x%08x dst_y_step=%i bg=0x%x bytemask=0x%x ]\n",
956  mode,
957  src0, src1, src_y_step,
958  dst0, dst1, dst_y_step,
959  bg, bytemask);
960 
961  if (dst_y_step != 0 && dst_y_step != 1 && dst_y_step != -1) {
962  fatal("[ sgi_mte: TODO! unimplemented dst_y_step %i ]", dst_y_step);
963  // exit(1);
964  }
965 
966  if (mode & MTE_MODE_STIPPLE) {
967  fatal("[ sgi_mte: unimplemented MTE_MODE_STIPPLE ]");
968  exit(1);
969  }
970 
971  int src_tlb = (mode & MTE_MODE_SRC_BUF_MASK) >> MTE_SRC_TLB_SHIFT;
972  int dst_tlb = (mode & MTE_MODE_DST_BUF_MASK) >> MTE_DST_TLB_SHIFT;
973 
974  if (src > MTE_TLB_C) {
975  fatal("[ sgi_mte: unimplemented SRC ]");
976  exit(1);
977  }
978 
979  switch (dst_tlb) {
980  case MTE_TLB_A:
981  case MTE_TLB_B:
982  case MTE_TLB_C:
983  // Used by NetBSD's crmfb_fill_rect. It puts graphical
984  // coordinates in dst0 and dst1.
985  {
986  int x1 = (dst0 >> 16) & 0xfff;
987  int y1 = dst0 & 0xfff;
988  int x2 = (dst1 >> 16) & 0xfff;
989  int y2 = dst1 & 0xfff;
990  x1 /= (depth / 8);
991  x2 /= (depth / 8);
992 
993  int src_x1 = (src0 >> 16) & 0xfff;
994  int src_y1 = src0 & 0xfff;
995  // int src_x2 = (src1 >> 16) & 0xfff;
996  // int src_y2 = src1 & 0xfff;
997  src_x1 /= (depth / 8);
998  // src_x2 /= (depth / 8);
999 
1000  int dx = x1 > x2 ? -1 : 1;
1001  int dy = y1 > y2 ? -1 : 1;
1002 
1003  uint32_t src_mode = (src_tlb << 10) + (((mode & MTE_MODE_DEPTH_MASK) >> MTE_DEPTH_SHIFT) << 8);
1004  uint32_t dst_mode = (dst_tlb << 10) + (((mode & MTE_MODE_DEPTH_MASK) >> MTE_DEPTH_SHIFT) << 8);
1005 
1006  // Hack. The MTE perhaps doesn't deal with colors per se,
1007  // but this makes sure that we copy 32 bits when doing 32-bit
1008  // transfers.
1009  if (depth == 4) {
1010  src_mode |= DE_MODE_TYPE_RGBA;
1011  dst_mode |= DE_MODE_TYPE_RGBA;
1012  }
1013 
1014  int src_y = src_y1;
1015  for (int y = y1; y != y2+dy; y += dy) {
1016  int src_x = src_x1;
1017 
1018  for (int x = x1; x != x2+dx; x += dx) {
1019  if (mode & MTE_MODE_COPY) {
1020  horrible_getputpixel(false, cpu, d,
1021  src_x, src_y, &bg, src_mode);
1022  src_x += dx;
1023  }
1024 
1025  horrible_getputpixel(true, cpu, d, x, y, &bg, dst_mode);
1026  }
1027 
1028  src_y += dy;
1029  }
1030  }
1031  break;
1032  case MTE_TLB_LIN_A:
1033  case MTE_TLB_LIN_B:
1034  // Used by the PROM to zero-fill memory (?).
1035  if (mode & MTE_MODE_COPY) {
1036  fatal("[ sgi_mte: unimplemented MTE_MODE_COPY ]");
1037  exit(1);
1038  }
1039 
1040  if (depth != 8) {
1041  fatal("[ sgi_mte: unimplemented MTE_DEPTH_x ]");
1042  exit(1);
1043  }
1044 
1045  debug("[ sgi_mte: LINEAR TRANSFER: mode=0x%08x dst0=0x%016llx,"
1046  " dst1=0x%016llx (length 0x%llx), dst_y_step=%i bg=0x%x, bytemask=0x%x ]\n",
1047  mode,
1048  (long long)dst0, (long long)dst1,
1049  (long long)dstlen, dst_y_step, (int)bg, (int)bytemask);
1050 
1051  if (bytemask != 0xffffffff) {
1052  fatal("unimplemented MTE bytemask 0x%08x\n", (int)bytemask);
1053  exit(1);
1054  }
1055 
1056  /*
1057  * Horrible hack:
1058  *
1059  * During bootup, the PROM fills memory at 0x40000000 and
1060  * forward. This corresponds to the lowest possible RAM address.
1061  * However, these fills are not going via the CPU's cache,
1062  * which contains things such as the return address on the
1063  * stack. If we _really_ write this data in the emulator (which
1064  * doesn't emulate the cache), it would overwrite the stack.
1065  *
1066  * So let's not.
1067  *
1068  * (If some guest OS or firmware variant actually depends on
1069  * the ability to write to the start of memory this way,
1070  * it would not work in the emulator.)
1071  */
1072  // if (dst0 >= 0x40000000 && dst0 < 0x40004000 && dst1 > 0x40004000) {
1073  // dst0 += 0x4000;
1074  // dstlen -= 0x4000;
1075  // }
1076 
1077  /*
1078  * HUH?
1079  *
1080  * Note that due to a bug (?) in the PROM firmware when it
1081  * is setting up the TLB entries, only every _second_ page is
1082  * actually put correctly in the TLB. This means that even
1083  * though it then tries to fill 0x40000000 .. 0x40007fff with
1084  * zeroes, it only fills 0x40001000 .. 0x40001fff,
1085  * 0x40003000 .. 0x40003fff and so on!
1086  *
1087  * So the Horrible hack above is not needed.
1088  *
1089  * Ironic.
1090  */
1091 
1092  memset(zerobuf, bg, dstlen < sizeof(zerobuf) ? dstlen : sizeof(zerobuf));
1093  fill_addr = dst0;
1094  while (dstlen != 0) {
1095  uint64_t fill_len;
1096  if (dstlen > sizeof(zerobuf))
1097  fill_len = sizeof(zerobuf);
1098  else
1099  fill_len = dstlen;
1100 
1101  uint64_t starting_page = fill_addr & ~0xfff;
1102  uint64_t ending_page = (fill_addr + fill_len - 1) & ~0xfff;
1103  if (starting_page != ending_page) {
1104  fill_len = starting_page + 4096 - fill_addr;
1105  }
1106 
1107  // Find starting_page in the TLB in question.
1108  starting_page >>= 12;
1109  uint32_t *tlb = dst_tlb == MTE_TLB_LIN_A ? d->re_linear_a : d->re_linear_b;
1110  bool match = false;
1111  for (int i = 0; i < 32; ++i) {
1112  uint32_t entry = tlb[i];
1113  if (entry & 0x80000000) {
1114  entry &= ~0x80000000;
1115  if (entry == starting_page) {
1116  match = true;
1117  break;
1118  }
1119  }
1120  }
1121 
1122  if (match) {
1123  cpu->memory_rw(cpu, cpu->mem, fill_addr, zerobuf, fill_len,
1125  } else {
1126  debug("[ sgi_mte: WARNING: address 0x%x not found in TLB? Ignoring fill. ]\n",
1127  (long long)fill_addr);
1128  }
1129 
1130  fill_addr += fill_len;
1131  dstlen -= sizeof(zerobuf);
1132  }
1133  break;
1134  default:
1135  fatal("[ sgi_mte: TODO! unimplemented dst_tlb 0x%x ]", dst_tlb);
1136  }
1137 }
1138 
1140 {
1141  struct sgi_re_data *d = (struct sgi_re_data *) extra;
1142  uint64_t idata = 0, odata = 0;
1143  int regnr;
1144  bool startFlag = relative_addr & CRIME_DE_START ? true : false;
1145 
1146  relative_addr &= ~CRIME_DE_START;
1147 
1148  idata = memory_readmax64(cpu, data, len);
1149  regnr = relative_addr / sizeof(uint32_t);
1150 
1151  relative_addr += 0x3000;
1152 
1153  /*
1154  * Treat all registers as read/write, by default. Sometimes these
1155  * are accessed as 32-bit words, sometimes as 64-bit words.
1156  *
1157  * NOTE: The lowest bits are internally stored in the "low" (+0)
1158  * register, and the higher bits are stored in the "+1" word.
1159  */
1160  if (len == 4) {
1161  if (writeflag == MEM_WRITE)
1162  d->mte_reg[regnr] = idata;
1163  else
1164  odata = d->mte_reg[regnr];
1165  } else if (len != 4) {
1166  if (writeflag == MEM_WRITE) {
1167  d->mte_reg[regnr+1] = idata >> 32;
1168  d->mte_reg[regnr] = idata;
1169  } else {
1170  odata = ((uint64_t)d->mte_reg[regnr+1] << 32) +
1171  d->mte_reg[regnr];
1172  }
1173  } else {
1174  fatal("[ sgi_mte: UNIMPLEMENTED read/write len %i ]\n", len);
1175  exit(1);
1176  }
1177 
1178  switch (relative_addr) {
1179 
1180  case CRIME_MTE_MODE:
1181  debug("[ sgi_mte: %s CRIME_MTE_MODE: 0x%016llx ]\n",
1182  writeflag == MEM_WRITE ? "write to" : "read from",
1183  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1184  break;
1185 
1186  case CRIME_MTE_BYTEMASK:
1187  debug("[ sgi_mte: %s CRIME_MTE_BYTEMASK: 0x%016llx ]\n",
1188  writeflag == MEM_WRITE ? "write to" : "read from",
1189  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1190  break;
1191 
1192  case CRIME_MTE_STIPPLEMASK:
1193  fatal("[ sgi_mte: %s CRIME_MTE_STIPPLEMASK: 0x%016llx ]\n",
1194  writeflag == MEM_WRITE ? "write to" : "read from",
1195  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1196  break;
1197 
1198  case CRIME_MTE_BG:
1199  debug("[ sgi_mte: %s CRIME_MTE_BG: 0x%016llx ]\n",
1200  writeflag == MEM_WRITE ? "write to" : "read from",
1201  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1202  break;
1203 
1204  case CRIME_MTE_SRC0:
1205  debug("[ sgi_mte: %s CRIME_MTE_SRC0: 0x%016llx ]\n",
1206  writeflag == MEM_WRITE ? "write to" : "read from",
1207  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1208  break;
1209 
1210  case CRIME_MTE_SRC1:
1211  debug("[ sgi_mte: %s CRIME_MTE_SRC1: 0x%016llx ]\n",
1212  writeflag == MEM_WRITE ? "write to" : "read from",
1213  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1214  break;
1215 
1216  case CRIME_MTE_DST0:
1217  debug("[ sgi_mte: %s CRIME_MTE_DST0: 0x%016llx ]\n",
1218  writeflag == MEM_WRITE ? "write to" : "read from",
1219  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1220  break;
1221 
1222  case CRIME_MTE_DST1:
1223  debug("[ sgi_mte: %s CRIME_MTE_DST1: 0x%016llx ]\n",
1224  writeflag == MEM_WRITE ? "write to" : "read from",
1225  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1226  break;
1227 
1228  case CRIME_MTE_SRC_Y_STEP:
1229  debug("[ sgi_mte: %s CRIME_MTE_SRC_Y_STEP: 0x%016llx ]\n",
1230  writeflag == MEM_WRITE ? "write to" : "read from",
1231  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1232  break;
1233 
1234  case CRIME_MTE_DST_Y_STEP:
1235  debug("[ sgi_mte: %s CRIME_MTE_DST_Y_STEP: 0x%016llx ]\n",
1236  writeflag == MEM_WRITE ? "write to" : "read from",
1237  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1238  break;
1239 
1240  case CRIME_MTE_NULL:
1241  fatal("[ sgi_mte: %s CRIME_MTE_NULL: 0x%016llx ]\n",
1242  writeflag == MEM_WRITE ? "write to" : "read from",
1243  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1244  break;
1245 
1246  case CRIME_MTE_FLUSH:
1247  fatal("[ sgi_mte: %s CRIME_MTE_FLUSH: 0x%016llx ]\n",
1248  writeflag == MEM_WRITE ? "write to" : "read from",
1249  writeflag == MEM_WRITE ? (long long)idata : (long long)odata);
1250  break;
1251 
1252  default:
1253  if (writeflag == MEM_WRITE)
1254  fatal("[ sgi_mte: unimplemented write to "
1255  "address 0x%llx, data=0x%016llx ]\n",
1256  (long long)relative_addr, (long long)idata);
1257  else
1258  fatal("[ sgi_mte: unimplemented read from address"
1259  " 0x%llx ]\n", (long long)relative_addr);
1260  }
1261 
1262  if (startFlag)
1263  do_mte_transfer(cpu, d);
1264 
1265  if (writeflag == MEM_READ)
1266  memory_writemax64(cpu, data, len, odata);
1267 
1268  return 1;
1269 }
1270 
1271 
1272 /*
1273  * dev_sgi_mte_init():
1274  */
1275 void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d)
1276 {
1277  memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1278  dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1279 }
1280 
1281 
1282 /****************************************************************************/
1283 
1284 /*
1285  * SGI "de_status".
1286  */
1287 
1288 DEVICE_ACCESS(sgi_de_status)
1289 {
1290  // struct sgi_re_data *d = (struct sgi_re_data *) extra;
1291  uint64_t idata = 0, odata = 0;
1292 
1293  idata = memory_readmax64(cpu, data, len);
1294 
1295  relative_addr += 0x4000;
1296 
1297  switch (relative_addr) {
1298 
1299  case CRIME_DE_STATUS: // 0x4000
1300  odata = CRIME_DE_IDLE |
1304 
1305  /*
1306  * TODO: Actually simulate pipeline of a number of commands?
1307  */
1308  break;
1309 
1310  case 0x4008:
1311  /* Unknown. Ignore for now. */
1312  break;
1313 
1314  default:
1315  if (writeflag == MEM_WRITE)
1316  debug("[ sgi_de_status: unimplemented write to "
1317  "address 0x%llx, data=0x%016llx ]\n",
1318  (long long)relative_addr, (long long)idata);
1319  else
1320  debug("[ sgi_de_status: unimplemented read from address"
1321  " 0x%llx ]\n", (long long)relative_addr);
1322  }
1323 
1324  if (writeflag == MEM_READ)
1325  memory_writemax64(cpu, data, len, odata);
1326 
1327  return 1;
1328 }
1329 
1330 
1331 /*
1332  * dev_sgi_de_status_init():
1333  */
1334 void dev_sgi_de_status_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d)
1335 {
1336  memory_device_register(mem, "sgi_de_status", baseaddr, DEV_SGI_DE_STATUS_LENGTH,
1337  dev_sgi_de_status_access, (void *)d, DM_DEFAULT, NULL);
1338 }
1339 
1340 
void dev_sgi_de_status_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d)
Definition: dev_sgi_re.cc:1334
#define CRIME_DE_SCRMASK1
Definition: crmfbreg.h:281
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
#define DEV_SGI_RE_LENGTH
Definition: devices.h:399
#define DE_MODE_TYPE_MASK
Definition: crmfbreg.h:333
#define CRIME_DE_WINOFFSET_DST
Definition: crmfbreg.h:287
#define CRIME_RE_LINEAR_B
Definition: crmfbreg.h:237
#define DE_MODE_TYPE_RGB
Definition: crmfbreg.h:329
uint16_t re_tex[112]
Definition: dev_sgi_re.cc:63
void fatal(const char *fmt,...)
Definition: main.cc:152
#define MTE_TLB_LIN_B
Definition: crmfbreg.h:262
#define DM_DEFAULT
Definition: memory.h:130
#define MTE_TLB_C
Definition: crmfbreg.h:259
#define DE_PRIM_TB
Definition: crmfbreg.h:388
#define CRIME_DE_SCRMASK4
Definition: crmfbreg.h:284
#define CRIME_DE_STIPPLE_PAT
Definition: crmfbreg.h:305
#define CRIME_MTE_FLUSH
Definition: crmfbreg.h:251
#define DE_MODE_TYPE_RGBA
Definition: crmfbreg.h:330
#define CRIME_DE_MTE_IDLE
Definition: crmfbreg.h:426
uint16_t re_tlb_c[256]
Definition: dev_sgi_re.cc:62
struct memory * mem
Definition: cpu.h:362
#define MTE_DEPTH_SHIFT
Definition: crmfbreg.h:271
#define CRIME_MTE_BYTEMASK
Definition: crmfbreg.h:241
#define CRIME_DE_SCRMASK3
Definition: crmfbreg.h:283
#define CRIME_DE_XFER_STRD_SRC
Definition: crmfbreg.h:299
#define MEM_READ
Definition: memory.h:116
#define CRIME_DE_STIPPLE_MODE
Definition: crmfbreg.h:304
#define CRIME_DE_ROP
Definition: crmfbreg.h:310
uint16_t re_tlb_a[256]
Definition: dev_sgi_re.cc:60
#define CRIME_DE_MODE_SRC
Definition: crmfbreg.h:276
#define DE_PRIM_RECTANGLE
Definition: crmfbreg.h:383
#define CRIME_DE_CLIPMODE
Definition: crmfbreg.h:278
#define CRIME_DE_SCISSOR
Definition: crmfbreg.h:285
void horrible_getputpixel(bool put, struct cpu *cpu, struct sgi_re_data *d, int x, int y, uint32_t *color, int mode)
Definition: dev_sgi_re.cc:90
#define CRIME_MTE_STIPPLEMASK
Definition: crmfbreg.h:242
#define MTE_MODE_COPY
Definition: crmfbreg.h:273
#define MTE_MODE_DST_BUF_MASK
Definition: crmfbreg.h:256
#define OPENGL_LOGIC_OP_COPY
Definition: sgi_gl.h:31
#define CRIME_DE_XFER_STRD_DST
Definition: crmfbreg.h:303
#define DE_DRAWMODE_LINE_STIP
Definition: crmfbreg.h:361
void dev_sgi_re_init(struct machine *machine, struct memory *mem, uint64_t baseaddr)
Definition: dev_sgi_re.cc:380
uint32_t mte_reg[DEV_SGI_MTE_LENGTH/sizeof(uint32_t)]
Definition: dev_sgi_re.cc:72
#define CRIME_MTE_DST_Y_STEP
Definition: crmfbreg.h:249
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
#define CRIME_DE_PLANEMASK
Definition: crmfbreg.h:311
#define MTE_SRC_TLB_SHIFT
Definition: crmfbreg.h:266
#define MTE_TLB_LIN_A
Definition: crmfbreg.h:261
#define DE_STIP_STRTIDX_SHIFT
Definition: crmfbreg.h:395
#define CRIME_DE_XFER_STEP_X
Definition: crmfbreg.h:300
#define CRIME_DE_PRIMITIVE
Definition: crmfbreg.h:288
void dev_sgi_de_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d)
Definition: dev_sgi_re.cc:921
#define DE_STIP_MAXIDX_SHIFT
Definition: crmfbreg.h:394
#define PHYSICAL
Definition: memory.h:126
#define CRIME_DE_FG
Definition: crmfbreg.h:306
#define MTE_TLB_B
Definition: crmfbreg.h:258
#define MTE_MODE_DEPTH_MASK
Definition: crmfbreg.h:267
uint16_t re_tlb_b[256]
Definition: dev_sgi_re.cc:61
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 de_reg[DEV_SGI_DE_LENGTH/sizeof(uint32_t)]
Definition: dev_sgi_re.cc:69
#define CRIME_DE_SCRMASK2
Definition: crmfbreg.h:282
#define MTE_MODE_STIPPLE
Definition: crmfbreg.h:272
u_short data
Definition: siireg.h:79
#define CRIME_MTE_BG
Definition: crmfbreg.h:243
#define CRIME_DE_XFER_ADDR_DST
Definition: crmfbreg.h:302
#define DE_DRAWMODE_PLANEMASK
Definition: crmfbreg.h:373
#define DE_MODE_TYPE_ABGR
Definition: crmfbreg.h:331
#define CRIME_MTE_SRC_Y_STEP
Definition: crmfbreg.h:248
uint32_t re_linear_a[32]
Definition: dev_sgi_re.cc:65
#define CRIME_DE_FLUSH
Definition: crmfbreg.h:314
#define MEM_WRITE
Definition: memory.h:117
#define DE_PRIM_LINE_SKIP_END
Definition: crmfbreg.h:384
#define CRIME_RE_TLB_B
Definition: crmfbreg.h:231
#define CRIME_DE_STATUS
Definition: crmfbreg.h:422
#define DE_DRAWMODE_BYTEMASK
Definition: crmfbreg.h:374
#define DE_DRAWMODE_OPAQUE_STIP
Definition: crmfbreg.h:363
#define CRIME_DE_XFER_STEP_Y
Definition: crmfbreg.h:301
#define CRIME_RE_LINEAR_A
Definition: crmfbreg.h:236
#define CRIME_DE_WINOFFSET_SRC
Definition: crmfbreg.h:286
#define CRIME_DE_BG
Definition: crmfbreg.h:307
#define DEV_SGI_DE_LENGTH
Definition: devices.h:405
#define OPENGL_LOGIC_OP_COPY_INVERTED
Definition: sgi_gl.h:40
#define debug
Definition: dev_adb.cc:57
#define DE_MODE_TYPE_CI
Definition: crmfbreg.h:328
#define CRIME_RE_TEX
Definition: crmfbreg.h:233
#define OPENGL_LOGIC_OP_XOR
Definition: sgi_gl.h:34
#define DE_DRAWMODE_POLY_STIP
Definition: crmfbreg.h:362
Definition: cpu.h:326
#define NO_EXCEPTIONS
Definition: memory.h:125
#define CRIME_MTE_MODE
Definition: crmfbreg.h:240
DEVICE_ACCESS(sgi_re)
Definition: dev_sgi_re.cc:216
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
#define MTE_DST_TLB_SHIFT
Definition: crmfbreg.h:264
#define CRIME_MTE_DST1
Definition: crmfbreg.h:247
#define CRIME_DE_X_VERTEX_0
Definition: crmfbreg.h:289
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
uint32_t re_linear_b[32]
Definition: dev_sgi_re.cc:66
#define CRIME_MTE_SRC1
Definition: crmfbreg.h:245
#define DE_PRIM_LINE
Definition: crmfbreg.h:381
#define CRIME_DE_NULL
Definition: crmfbreg.h:313
#define CRIME_RE_TLB_C
Definition: crmfbreg.h:232
#define DE_DRAWMODE_XFER_EN
Definition: crmfbreg.h:359
#define CRIME_DE_XFER_ADDR_SRC
Definition: crmfbreg.h:298
Definition: memory.h:75
#define CRIME_DE_DRAWMODE
Definition: crmfbreg.h:279
#define CRIME_MTE_SRC0
Definition: crmfbreg.h:244
#define CRIME_DE_MODE_DST
Definition: crmfbreg.h:277
#define DE_PRIM_RL
Definition: crmfbreg.h:386
int dev_sgi_re_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *)
#define CRIME_MTE_DST0
Definition: crmfbreg.h:246
void do_mte_transfer(struct cpu *cpu, struct sgi_re_data *d)
Definition: dev_sgi_re.cc:938
void draw_primitive(struct cpu *cpu, struct sgi_re_data *d)
Definition: dev_sgi_re.cc:403
#define CRIME_DE_PIXPIPE_IDLE
Definition: crmfbreg.h:425
void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d)
Definition: dev_sgi_re.cc:1275
#define MTE_MODE_SRC_BUF_MASK
Definition: crmfbreg.h:265
#define MTE_TLB_A
Definition: crmfbreg.h:257
#define CRIME_MTE_NULL
Definition: crmfbreg.h:250
char * op[16]
#define CRIME_DE_SCRMASK0
Definition: crmfbreg.h:280
#define DEV_SGI_DE_STATUS_LENGTH
Definition: devices.h:417
#define DEV_SGI_MTE_LENGTH
Definition: devices.h:411
#define DE_DRAWMODE_ROP
Definition: crmfbreg.h:371
#define CRIME_DE_IDLE
Definition: crmfbreg.h:423
int dev_sgi_de_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *)
#define CRIME_DE_START
Definition: crmfbreg.h:316
#define CRIME_DE_SETUP_IDLE
Definition: crmfbreg.h:424
#define CRIME_RE_TLB_A
Definition: crmfbreg.h:230
#define CRIME_DE_X_VERTEX_1
Definition: crmfbreg.h:290

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13