--- trunk/src/devices/dev_sgi_ip32.c 2007/10/08 16:18:38 12 +++ trunk/src/devices/dev_sgi_ip32.c 2007/10/08 16:19:11 18 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: dev_sgi_ip32.c,v 1.29 2005/08/13 08:25:48 debug Exp $ + * $Id: dev_sgi_ip32.c,v 1.34 2005/10/27 14:01:14 debug Exp $ * * SGI IP32 devices. * @@ -110,23 +110,22 @@ uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *extra) { - int i; struct crime_data *d = extra; - uint64_t idata; + uint64_t idata = 0; + int i; - idata = memory_readmax64(cpu, data, len); + if (writeflag == MEM_WRITE) + idata = memory_readmax64(cpu, data, len); /* * Set crime version/revision: * - * This might not be the most elegant or correct solution, - * but it seems that the IP32 PROM likes 0x11 for machines - * without graphics, and 0xa1 for machines with graphics. - * - * NetBSD 2.0 complains about "unknown" crime for 0x11, - * but I guess that's something one has to live with. + * This might not be the most elegant or correct solution, but it + * seems that the IP32 PROM likes 0x11 for machines without graphics, + * and 0xa1 for machines with graphics. * - * (TODO?) + * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess + * that's something one has to live with. (TODO?) */ d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00; d->reg[7] = d->use_fb? 0xa1 : 0x11; @@ -344,7 +343,9 @@ uint64_t idata = 0, odata=0; int regnr, res = 1; - idata = memory_readmax64(cpu, data, len); + if (writeflag == MEM_WRITE) + idata = memory_readmax64(cpu, data, len); + regnr = relative_addr / sizeof(uint32_t); /* Read from/write to the macepci: */ @@ -775,7 +776,9 @@ uint64_t idata = 0, odata = 0; int regnr; - idata = memory_readmax64(cpu, data, len); + if (writeflag == MEM_WRITE) + idata = memory_readmax64(cpu, data, len); + regnr = relative_addr / sizeof(uint64_t); /* Treat most registers as read/write, by default. */ @@ -1037,13 +1040,14 @@ * memory. Used by (at least) the SGI O2 PROM. * * Actually, it seems to be used for graphics output as well. (?) - * TODO: Run the O2's prom and try to figure out what it really does. + * The O2's PROM uses it to output graphics. */ /* #define debug fatal */ +/* #define MTE_DEBUG */ #define ZERO_CHUNK_LEN 4096 struct sgi_mte_data { - uint64_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint64_t)]; + uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)]; }; /* @@ -1060,31 +1064,51 @@ int regnr; idata = memory_readmax64(cpu, data, len); - regnr = relative_addr / sizeof(uint64_t); + regnr = relative_addr / sizeof(uint32_t); + + /* + * Treat all registers as read/write, by default. Sometimes these + * are accessed as 32-bit words, sometimes as 64-bit words. + */ + if (len != 4) { + if (writeflag == MEM_WRITE) { + d->reg[regnr] = idata >> 32; + d->reg[regnr+1] = idata; + } else + odata = ((uint64_t)d->reg[regnr] << 32) + + d->reg[regnr+1]; + } - /* Treat all registers as read/write, by default. */ if (writeflag == MEM_WRITE) d->reg[regnr] = idata; else odata = d->reg[regnr]; +#ifdef MTE_DEBUG + if (writeflag == MEM_WRITE && relative_addr >= 0x2000 && + relative_addr < 0x3000) + fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr, + (long long)idata); +#endif + /* * I've not found any docs about this 'mte' device at all, so this is * just a guess. The mte seems to be used for copying and zeroing * chunks of memory. * - * [ sgi_mte: unimplemented write to address 0x3030, data=0x00000000003da000 ] <-- first address - * [ sgi_mte: unimplemented write to address 0x3038, data=0x00000000003f9fff ] <-- last address - * [ sgi_mte: unimplemented write to address 0x3018, data=0x0000000000000000 ] <-- what to fill? - * [ sgi_mte: unimplemented write to address 0x3008, data=0x00000000ffffffff ] <-- ? - * [ sgi_mte: unimplemented write to address 0x3800, data=0x0000000000000011 ] <-- operation (0x11 = zerofill) + * write to 0x3030, data=0x00000000003da000 ] <-- first address + * write to 0x3038, data=0x00000000003f9fff ] <-- last address + * write to 0x3018, data=0x0000000000000000 ] <-- what to fill? + * write to 0x3008, data=0x00000000ffffffff ] <-- ? + * write to 0x3800, data=0x0000000000000011 ] <-- operation + * (0x11 = zerofill) * - * [ sgi_mte: unimplemented write to address 0x1700, data=0x80001ea080001ea1 ] <-- also containing the address to fill (?) - * [ sgi_mte: unimplemented write to address 0x1708, data=0x80001ea280001ea3 ] - * [ sgi_mte: unimplemented write to address 0x1710, data=0x80001ea480001ea5 ] + * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the + * write to 0x1708, data=0x80001ea280001ea3 address to fill (?) + * write to 0x1710, data=0x80001ea480001ea5 * ... - * [ sgi_mte: unimplemented write to address 0x1770, data=0x80001e9c80001e9d ] - * [ sgi_mte: unimplemented write to address 0x1778, data=0x80001e9e80001e9f ] + * write to 0x1770, data=0x80001e9c80001e9d + * write to 0x1778, data=0x80001e9e80001e9f */ switch (relative_addr) { @@ -1115,39 +1139,119 @@ case 0x1778: break; -#if 1 -case 0x2074: -{ -/* This seems to have to do with graphical output: - 0x000000000xxx0yyy where x is usually 0..1279 and y is 0..1023? */ -/* Gaaah... */ - int x = (idata >> 16) & 0xfff; - int y = idata & 0xfff; - int addr; -unsigned char buf[3]; - printf("x = %i, y = %i\n", x, y); -buf[0] = buf[1] = buf[2] = random() | 0x80; -addr = (x/2 + (y/2)*640) * 3; -if (x < 640 && y < 480) -cpu->memory_rw(cpu, cpu->mem, 0x38000000 + addr, - buf, 3, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); + /* Graphics stuff? No warning: */ + case 0x2018: + case 0x2060: + case 0x2070: + case 0x2074: + case 0x20c0: + case 0x20c4: + case 0x20d0: + case 0x21b0: + case 0x21b8: + break; + + /* Perform graphics operation: */ + case 0x21f8: + { + uint32_t op = d->reg[0x2060 / sizeof(uint32_t)]; + uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255; + uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)] + >> 16) & 0xfff; + uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff; + uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)] + >> 16) & 0xfff; + uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff; + int y; + + op >>= 24; + + switch (op) { + case 1: /* Unknown. Used after drawing bitmaps? */ + break; + case 3: /* Fill: */ + if (x2 < x1) { + int tmp = x1; x1 = x2; x2 = tmp; + } + if (y2 < y1) { + int tmp = y1; y1 = y2; y2 = tmp; + } + for (y=y1; y<=y2; y++) { + unsigned char buf[1280]; + int length = x2-x1+1; + int addr = (x1 + y*1280); + if (length < 1) + length = 1; + memset(buf, color, length); + if (x1 < 1280 && y < 1024) + cpu->memory_rw(cpu, cpu->mem, + 0x38000000 + addr, buf, + length, MEM_WRITE, + NO_EXCEPTIONS | PHYSICAL); + } + break; + + default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - " + "%i,%i\n\n", op, color, x1,y1, x2,y2); + } + } + break; + + case 0x29f0: + /* Pixel output: */ + { + uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)]; + uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255; + uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)] + >> 16) & 0xfff; + uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff; + uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)] + >> 16) & 0xfff; + uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff; + int x,y; + if (x2 < x1) { + int tmp = x1; x1 = x2; x2 = tmp; + } + if (y2 < y1) { + int tmp = y1; y1 = y2; y2 = tmp; + } + if (x2-x1 <= 15) + data <<= 16; + x=x1; y=y1; + while (x <= x2 && y <= y2) { + unsigned char buf = color; + int addr = x + y*1280; + int bit_set = data & 0x80000000UL; + data <<= 1; + if (x < 1280 && y < 1024 && bit_set) + cpu->memory_rw(cpu, cpu->mem, + 0x38000000 + addr, &buf,1,MEM_WRITE, + NO_EXCEPTIONS | PHYSICAL); + x++; + if (x > x2) { + x = x1; + y++; + } + } + } + break; -} -break; -#endif /* Operations: */ case 0x3800: if (writeflag == MEM_WRITE) { switch (idata) { case 0x11: /* zerofill */ - first_addr = d->reg[0x3030 / sizeof(uint64_t)]; - last_addr = d->reg[0x3038 / sizeof(uint64_t)]; + first_addr = d->reg[0x3030 / sizeof(uint32_t)]; + last_addr = d->reg[0x3038 / sizeof(uint32_t)]; zerobuflen = last_addr - first_addr + 1; - debug("[ sgi_mte: zerofill: first = 0x%016llx, last = 0x%016llx, length = 0x%llx ]\n", - (long long)first_addr, (long long)last_addr, (long long)zerobuflen); + debug("[ sgi_mte: zerofill: first = 0x%016llx," + " last = 0x%016llx, length = 0x%llx ]\n", + (long long)first_addr, (long long) + last_addr, (long long)zerobuflen); - /* TODO: is there a better way to implement this? */ + /* TODO: is there a better way to + implement this? */ memset(zerobuf, 0, sizeof(zerobuf)); fill_addr = first_addr; while (zerobuflen != 0) { @@ -1164,15 +1268,19 @@ break; default: - fatal("[ sgi_mte: UNKNOWN operation 0x%x ]\n", idata); + fatal("[ sgi_mte: UNKNOWN operation " + "0x%x ]\n", idata); } } break; default: if (writeflag == MEM_WRITE) - debug("[ sgi_mte: unimplemented write to address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); + debug("[ sgi_mte: unimplemented write to " + "address 0x%llx, data=0x%016llx ]\n", + (long long)relative_addr, (long long)idata); else - debug("[ sgi_mte: unimplemented read from address 0x%llx ]\n", (long long)relative_addr); + debug("[ sgi_mte: unimplemented read from address" + " 0x%llx ]\n", (long long)relative_addr); } if (writeflag == MEM_READ)