/[gxemul]/trunk/src/devices/dev_sgi_ip32.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_sgi_ip32.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 14 - (show annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33110 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_sgi_ip32.c,v 1.32 2005/08/19 09:43:35 debug Exp $
29 *
30 * SGI IP32 devices.
31 *
32 * o) CRIME
33 * o) MACE
34 * o) MACE PCI bus
35 * o) mec (ethernet)
36 * o) ust (unknown device)
37 * o) mte (memory transfer engine? details unknown)
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "bus_pci.h"
45 #include "console.h"
46 #include "cpu.h"
47 #include "devices.h"
48 #include "emul.h"
49 #include "machine.h"
50 #include "memory.h"
51 #include "misc.h"
52 #include "net.h"
53
54 #include "crimereg.h"
55
56 #include "if_mecreg.h"
57
58
59 #define CRIME_TICKSHIFT 14
60 #define CRIME_SPEED_MUL_FACTOR 1
61 #define CRIME_SPEED_DIV_FACTOR 1
62
63 struct macepci_data {
64 struct pci_data *pci_data;
65 uint32_t reg[DEV_MACEPCI_LENGTH / 4];
66 };
67
68
69 /*
70 * dev_crime_tick():
71 *
72 * This function simply updates CRIME_TIME each tick.
73 *
74 * The names DIV and MUL may be a bit confusing. Increasing the
75 * MUL factor will result in an OS running on the emulated machine
76 * detecting a faster CPU. Increasing the DIV factor will result
77 * in a slower detected CPU.
78 *
79 * A R10000 is detected as running at
80 * CRIME_SPEED_FACTOR * 66 MHz. (TODO: this is not correct anymore)
81 */
82 void dev_crime_tick(struct cpu *cpu, void *extra)
83 {
84 int j, carry, old, new, add_byte;
85 uint64_t what_to_add = (1<<CRIME_TICKSHIFT)
86 * CRIME_SPEED_DIV_FACTOR / CRIME_SPEED_MUL_FACTOR;
87 struct crime_data *d = extra;
88
89 j = 0;
90 carry = 0;
91 while (j < 8) {
92 old = d->reg[CRIME_TIME + 7 - j];
93 add_byte = what_to_add >> ((int64_t)j * 8);
94 add_byte &= 255;
95 new = old + add_byte + carry;
96 d->reg[CRIME_TIME + 7 - j] = new & 255;
97 if (new >= 256)
98 carry = 1;
99 else
100 carry = 0;
101 j++;
102 }
103 }
104
105
106 /*
107 * dev_crime_access():
108 */
109 int dev_crime_access(struct cpu *cpu, struct memory *mem,
110 uint64_t relative_addr, unsigned char *data, size_t len,
111 int writeflag, void *extra)
112 {
113 int i;
114 struct crime_data *d = extra;
115 uint64_t idata;
116
117 idata = memory_readmax64(cpu, data, len);
118
119 /*
120 * Set crime version/revision:
121 *
122 * This might not be the most elegant or correct solution,
123 * but it seems that the IP32 PROM likes 0x11 for machines
124 * without graphics, and 0xa1 for machines with graphics.
125 *
126 * NetBSD 2.0 complains about "unknown" crime for 0x11,
127 * but I guess that's something one has to live with.
128 *
129 * (TODO?)
130 */
131 d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
132 d->reg[7] = d->use_fb? 0xa1 : 0x11;
133
134 /*
135 * Amount of memory. Bit 8 of bank control set ==> 128MB instead
136 * of 32MB per bank (?)
137 *
138 * When the bank control registers contain the same value as the
139 * previous one, that bank is not valid. (?)
140 */
141 d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
142 d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
143 d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
144 d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
145
146 if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
147 if (writeflag == MEM_READ)
148 memcpy(data, &d->reg[relative_addr], len);
149 return 1;
150 }
151
152 if (writeflag == MEM_WRITE)
153 memcpy(&d->reg[relative_addr], data, len);
154 else
155 memcpy(data, &d->reg[relative_addr], len);
156
157 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
158 (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
159 /*
160 * Force interrupt re-assertion:
161 *
162 * NOTE: Ugly hack. Hopefully CRMERR is never used.
163 */
164 #if 0
165 /*
166 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
167 TODO.
168 */
169 cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
170 #endif
171 }
172
173 switch (relative_addr) {
174 case CRIME_CONTROL: /* 0x008 */
175 /* TODO: 64-bit write to CRIME_CONTROL, but some things
176 (such as NetBSD 1.6.2) write to 0x00c! */
177 if (writeflag == MEM_WRITE) {
178 /*
179 * 0x200 = watchdog timer (according to NetBSD)
180 * 0x800 = "reboot" used by the IP32 PROM
181 */
182 if (idata & 0x200) {
183 idata &= ~0x200;
184 }
185 if (idata & 0x800) {
186 /* This is used by the IP32 PROM's
187 "reboot" command: */
188 for (i=0; i<cpu->machine->ncpus; i++)
189 cpu->machine->cpus[i]->running = 0;
190 cpu->machine->
191 exit_without_entering_debugger = 1;
192 idata &= ~0x800;
193 }
194 if (idata != 0)
195 fatal("[ CRIME_CONTROL: unimplemented "
196 "control 0x%016llx ]\n", (long long)idata);
197 }
198 break;
199 #if 0
200 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
201 case 0x14:
202 case CRIME_INTMASK: /* 0x018, Current interrupt mask */
203 case 0x1c:
204 case 0x34:
205 /* don't dump debug info for these */
206 break;
207 #endif
208 default:
209 if (writeflag==MEM_READ) {
210 debug("[ crime: read from 0x%x, len=%i:",
211 (int)relative_addr, len);
212 for (i=0; i<len; i++)
213 debug(" %02x", data[i]);
214 debug(" ]\n");
215 } else {
216 debug("[ crime: write to 0x%x:", (int)relative_addr);
217 for (i=0; i<len; i++)
218 debug(" %02x", data[i]);
219 debug(" (len=%i) ]\n", len);
220 }
221 }
222
223 return 1;
224 }
225
226
227 /*
228 * dev_crime_init():
229 */
230 struct crime_data *dev_crime_init(struct machine *machine, struct memory *mem,
231 uint64_t baseaddr, int irq_nr, int use_fb)
232 {
233 struct crime_data *d;
234
235 d = malloc(sizeof(struct crime_data));
236 if (d == NULL) {
237 fprintf(stderr, "out of memory\n");
238 exit(1);
239 }
240 memset(d, 0, sizeof(struct crime_data));
241 d->irq_nr = irq_nr;
242 d->use_fb = use_fb;
243
244 memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
245 dev_crime_access, d, MEM_DEFAULT, NULL);
246 machine_add_tickfunction(machine, dev_crime_tick, d, CRIME_TICKSHIFT);
247
248 return d;
249 }
250
251
252 /****************************************************************************/
253
254
255 /*
256 * dev_mace_access():
257 */
258 int dev_mace_access(struct cpu *cpu, struct memory *mem,
259 uint64_t relative_addr, unsigned char *data, size_t len,
260 int writeflag, void *extra)
261 {
262 int i;
263 struct mace_data *d = extra;
264
265 if (writeflag == MEM_WRITE)
266 memcpy(&d->reg[relative_addr], data, len);
267 else
268 memcpy(data, &d->reg[relative_addr], len);
269
270 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
271 (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f))
272 cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
273
274 switch (relative_addr) {
275 #if 0
276 case 0x10: /* Current interrupt assertions */
277 case 0x14:
278 /* don't dump debug info for these */
279 if (writeflag == MEM_WRITE) {
280 fatal("[ NOTE/TODO: WRITE to mace intr: "
281 "reladdr=0x%x data=", (int)relative_addr);
282 for (i=0; i<len; i++)
283 fatal(" %02x", data[i]);
284 fatal(" (len=%i) ]\n", len);
285 }
286 break;
287 case 0x18: /* Interrupt mask */
288 case 0x1c:
289 /* don't dump debug info for these */
290 break;
291 #endif
292 default:
293 if (writeflag == MEM_READ) {
294 debug("[ mace: read from 0x%x:", (int)relative_addr);
295 for (i=0; i<len; i++)
296 debug(" %02x", data[i]);
297 debug(" (len=%i) ]\n", len);
298 } else {
299 debug("[ mace: write to 0x%x:", (int)relative_addr);
300 for (i=0; i<len; i++)
301 debug(" %02x", data[i]);
302 debug(" (len=%i) ]\n", len);
303 }
304 }
305
306 return 1;
307 }
308
309
310 /*
311 * dev_mace_init():
312 */
313 struct mace_data *dev_mace_init(struct memory *mem, uint64_t baseaddr,
314 int irqnr)
315 {
316 struct mace_data *d;
317
318 d = malloc(sizeof(struct mace_data));
319 if (d == NULL) {
320 fprintf(stderr, "out of memory\n");
321 exit(1);
322 }
323 memset(d, 0, sizeof(struct mace_data));
324 d->irqnr = irqnr;
325
326 memory_device_register(mem, "mace", baseaddr, DEV_MACE_LENGTH,
327 dev_mace_access, d, MEM_DEFAULT, NULL);
328
329 return d;
330 }
331
332
333 /****************************************************************************/
334
335
336 /*
337 * dev_macepci_access():
338 */
339 int dev_macepci_access(struct cpu *cpu, struct memory *mem,
340 uint64_t relative_addr, unsigned char *data, size_t len,
341 int writeflag, void *extra)
342 {
343 struct macepci_data *d = (struct macepci_data *) extra;
344 uint64_t idata = 0, odata=0;
345 int regnr, res = 1;
346
347 idata = memory_readmax64(cpu, data, len);
348 regnr = relative_addr / sizeof(uint32_t);
349
350 /* Read from/write to the macepci: */
351 switch (relative_addr) {
352 case 0x00: /* Error address */
353 if (writeflag == MEM_WRITE) {
354 } else {
355 odata = 0;
356 }
357 break;
358 case 0x04: /* Error flags */
359 if (writeflag == MEM_WRITE) {
360 } else {
361 odata = 0x06;
362 }
363 break;
364 case 0x0c: /* Revision number */
365 if (writeflag == MEM_WRITE) {
366 } else {
367 odata = 0x01;
368 }
369 break;
370 case 0xcf8: /* PCI ADDR */
371 case 0xcfc: /* PCI DATA */
372 if (writeflag == MEM_WRITE) {
373 res = bus_pci_access(cpu, mem, relative_addr,
374 &idata, writeflag, d->pci_data);
375 } else {
376 res = bus_pci_access(cpu, mem, relative_addr,
377 &odata, writeflag, d->pci_data);
378 /* odata = 0; */
379 }
380 break;
381 default:
382 if (writeflag == MEM_WRITE) {
383 debug("[ macepci: unimplemented write to address "
384 "0x%x, data=0x%02x ]\n",
385 (int)relative_addr, (int)idata);
386 } else {
387 debug("[ macepci: unimplemented read from address "
388 "0x%x ]\n", (int)relative_addr);
389 }
390 }
391
392 if (writeflag == MEM_READ)
393 memory_writemax64(cpu, data, len, odata);
394
395 return res;
396 }
397
398
399 /*
400 * dev_macepci_init():
401 */
402 struct pci_data *dev_macepci_init(struct memory *mem, uint64_t baseaddr,
403 int pciirq)
404 {
405 struct macepci_data *d = malloc(sizeof(struct macepci_data));
406 if (d == NULL) {
407 fprintf(stderr, "out of memory\n");
408 exit(1);
409 }
410 memset(d, 0, sizeof(struct macepci_data));
411
412 d->pci_data = bus_pci_init(pciirq);
413
414 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
415 dev_macepci_access, (void *)d, MEM_DEFAULT, NULL);
416
417 return d->pci_data;
418 }
419
420
421 /****************************************************************************/
422
423
424 /*
425 * SGI "mec" ethernet. Used in SGI-IP32.
426 *
427 * Study http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c
428 * and/or NetBSD. TODO:
429 *
430 * x) tx and rx interrupts/ring/slot stuff
431 */
432
433 #define MEC_TICK_SHIFT 14
434
435 #define MAX_TX_PACKET_LEN 1700
436 #define N_RX_ADDRESSES 16
437
438 struct sgi_mec_data {
439 uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
440
441 int irq_nr;
442 unsigned char macaddr[6];
443
444 unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
445 int cur_tx_packet_len;
446
447 unsigned char *cur_rx_packet;
448 int cur_rx_packet_len;
449
450 uint64_t rx_addr[N_RX_ADDRESSES];
451 int cur_rx_addr_index_write;
452 int cur_rx_addr_index;
453 };
454
455
456 /*
457 * mec_reset():
458 */
459 static void mec_reset(struct sgi_mec_data *d)
460 {
461 if (d->cur_rx_packet != NULL)
462 free(d->cur_rx_packet);
463
464 memset(d->reg, 0, sizeof(d->reg));
465 }
466
467
468 /*
469 * mec_control_write():
470 */
471 static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d,
472 uint64_t x)
473 {
474 if (x & MEC_MAC_CORE_RESET) {
475 debug("[ sgi_mec: CORE RESET ]\n");
476 mec_reset(d);
477 }
478 }
479
480
481 /*
482 * mec_try_rx():
483 */
484 static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d)
485 {
486 uint64_t base;
487 unsigned char data[8];
488 int i, res, retval = 0;
489
490 base = d->rx_addr[d->cur_rx_addr_index];
491 if (base & 0xfff)
492 fatal("[ mec_try_rx(): WARNING! lowest bits of base are "
493 "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff));
494 base &= 0xfffff000ULL;
495 if (base == 0)
496 goto skip;
497
498 /* printf("rx base = 0x%016llx\n", (long long)base); */
499
500 /* Read an rx descriptor from memory: */
501 res = cpu->memory_rw(cpu, cpu->mem, base,
502 &data[0], sizeof(data), MEM_READ, PHYSICAL);
503 if (!res)
504 return 0;
505
506 #if 0
507 printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index);
508 for (i=0; i<sizeof(data); i++) {
509 if ((i & 3) == 0)
510 printf(" ");
511 printf("%02x", data[i]);
512 }
513 printf(" }\n");
514 #endif
515
516 /* Is this descriptor already in use? */
517 if (data[0] & 0x80) {
518 /* printf("INTERRUPT for base = 0x%x\n", (int)base); */
519 goto skip_and_advance;
520 }
521
522 if (d->cur_rx_packet == NULL &&
523 net_ethernet_rx_avail(cpu->machine->emul->net, d))
524 net_ethernet_rx(cpu->machine->emul->net, d,
525 &d->cur_rx_packet, &d->cur_rx_packet_len);
526
527 if (d->cur_rx_packet == NULL)
528 goto skip;
529
530 /* Copy the packet data: */
531 /* printf("RX: "); */
532 for (i=0; i<d->cur_rx_packet_len; i++) {
533 res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2,
534 d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL);
535 /* printf(" %02x", d->cur_rx_packet[i]); */
536 }
537 /* printf("\n"); */
538
539 #if 0
540 printf("RX: %i bytes, index %i, base = 0x%x\n",
541 d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base);
542 #endif
543
544 /* 4 bytes of CRC at the end. Hm. TODO */
545 d->cur_rx_packet_len += 4;
546
547 memset(data, 0, sizeof(data));
548 data[6] = (d->cur_rx_packet_len >> 8) & 255;
549 data[7] = d->cur_rx_packet_len & 255;
550 /* TODO: lots of bits :-) */
551 data[4] = 0x04; /* match MAC */
552 data[0] = 0x80; /* 0x80 = received. */
553 res = cpu->memory_rw(cpu, cpu->mem, base,
554 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
555
556 /* Free the packet from memory: */
557 free(d->cur_rx_packet);
558 d->cur_rx_packet = NULL;
559
560 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD;
561 skip_and_advance:
562 d->cur_rx_addr_index ++;
563 d->cur_rx_addr_index %= N_RX_ADDRESSES;
564 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS;
565 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
566 (d->cur_rx_addr_index & 0x1f) << 8;
567 retval = 1;
568
569 skip:
570 return retval;
571 }
572
573
574 /*
575 * mec_try_tx():
576 */
577 static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
578 {
579 uint64_t base, addr, dma_base;
580 int tx_ring_ptr, ringread, ringwrite, res, i, j;
581 unsigned char data[32];
582 int len, start_offset, dma_ptr_nr, dma_len;
583
584 base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
585 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
586
587 if (base == 0)
588 return 0;
589
590 /* printf("base = 0x%016llx\n", base); */
591
592 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
593 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
594 ringread >>= 16;
595 /* All done? Then abort. */
596 if (ringread == ringwrite)
597 return 0;
598
599 tx_ring_ptr &= MEC_TX_RING_READ_PTR;
600 tx_ring_ptr >>= 16;
601
602 /* Each tx descriptor (+ buffer) is 128 bytes: */
603 addr = base + tx_ring_ptr*128;
604 res = cpu->memory_rw(cpu, cpu->mem, addr,
605 &data[0], sizeof(data), MEM_READ, PHYSICAL);
606 if (!res)
607 return 0;
608
609 /* Is this packet transmitted already? */
610 if (data[0] & 0x80) {
611 fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
612 " transmitted? ]\n", tx_ring_ptr);
613 goto advance_tx;
614 }
615
616 len = data[6] * 256 + data[7];
617 start_offset = data[5] & 0x7f;
618
619 /* Is this packet empty? Then don't transmit. */
620 if (len == 0)
621 return 0;
622
623 /* Hm. Is len one too little? TODO */
624 len ++;
625
626 #if 0
627 printf("{ mec: txdesc %i: ", tx_ring_ptr);
628 for (i=0; i<sizeof(data); i++) {
629 if ((i & 3) == 0)
630 printf(" ");
631 printf("%02x", data[i]);
632 }
633 printf(" }\n");
634 #endif
635 dma_ptr_nr = 0;
636
637 j = 0;
638 d->cur_tx_packet_len = len;
639
640 for (i=start_offset; i<start_offset+len; i++) {
641 unsigned char ch;
642
643 if ((i & 0x7f) == 0x00)
644 break;
645
646 res = cpu->memory_rw(cpu, cpu->mem, addr + i,
647 &ch, sizeof(ch), MEM_READ, PHYSICAL);
648 /* printf(" %02x", ch); */
649
650 d->cur_tx_packet[j++] = ch;
651 if (j >= MAX_TX_PACKET_LEN) {
652 fatal("[ mec_try_tx: packet too large? ]\n");
653 break;
654 }
655 }
656 /* printf("\n"); */
657
658 if (j < len) {
659 /* Continue with DMA: */
660 for (;;) {
661 dma_ptr_nr ++;
662 if (dma_ptr_nr >= 4)
663 break;
664 if (!(data[4] & (0x01 << dma_ptr_nr)))
665 break;
666 dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
667 + (data[dma_ptr_nr * 8 + 5] << 16)
668 + (data[dma_ptr_nr * 8 + 6] << 8)
669 + (data[dma_ptr_nr * 8 + 7]);
670 dma_base &= 0xfffffff8ULL;
671 dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
672 + (data[dma_ptr_nr * 8 + 3]) + 1;
673
674 /* printf("dma_base = %08x, dma_len = %i\n",
675 (int)dma_base, dma_len); */
676
677 while (dma_len > 0) {
678 unsigned char ch;
679 res = cpu->memory_rw(cpu, cpu->mem, dma_base,
680 &ch, sizeof(ch), MEM_READ, PHYSICAL);
681 /* printf(" %02x", ch); */
682
683 d->cur_tx_packet[j++] = ch;
684 if (j >= MAX_TX_PACKET_LEN) {
685 fatal("[ mec_try_tx: packet too large?"
686 " ]\n");
687 break;
688 }
689 dma_base ++;
690 dma_len --;
691 }
692 }
693 }
694
695 if (j < len)
696 fatal("[ mec_try_tx: not enough data? ]\n");
697
698 net_ethernet_tx(cpu->machine->emul->net, d,
699 d->cur_tx_packet, d->cur_tx_packet_len);
700
701 /* see openbsd's if_mec.c for details */
702 if (data[4] & 0x01) {
703 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
704 MEC_INT_TX_PACKET_SENT;
705 }
706 memset(data, 0, 6); /* last 2 bytes are len */
707 data[0] = 0x80;
708 data[5] = 0x80;
709
710 res = cpu->memory_rw(cpu, cpu->mem, addr,
711 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
712
713 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
714 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
715
716 advance_tx:
717 /* Advance the ring Read ptr. */
718 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
719 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
720 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
721
722 ringread = (ringread >> 16) + 1;
723 ringread &= 63;
724 ringread <<= 16;
725
726 d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
727 (ringwrite & MEC_TX_RING_WRITE_PTR) |
728 (ringread & MEC_TX_RING_READ_PTR);
729
730 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
731 ~MEC_INT_TX_RING_BUFFER_ALIAS;
732 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
733 (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
734 MEC_INT_TX_RING_BUFFER_ALIAS);
735
736 return 1;
737 }
738
739
740 /*
741 * dev_sgi_mec_tick():
742 */
743 void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
744 {
745 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
746 int n = 0;
747
748 while (mec_try_tx(cpu, d))
749 ;
750
751 while (mec_try_rx(cpu, d) && n < 16)
752 n++;
753
754 /* Interrupts: (TODO: only when enabled) */
755 if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
756 #if 0
757 printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
758 sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
759 fflush(stdout);
760 #endif
761 cpu_interrupt(cpu, d->irq_nr);
762 } else
763 cpu_interrupt_ack(cpu, d->irq_nr);
764 }
765
766
767 /*
768 * dev_sgi_mec_access():
769 */
770 int dev_sgi_mec_access(struct cpu *cpu, struct memory *mem,
771 uint64_t relative_addr, unsigned char *data, size_t len,
772 int writeflag, void *extra)
773 {
774 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
775 uint64_t idata = 0, odata = 0;
776 int regnr;
777
778 idata = memory_readmax64(cpu, data, len);
779 regnr = relative_addr / sizeof(uint64_t);
780
781 /* Treat most registers as read/write, by default. */
782 if (writeflag == MEM_WRITE) {
783 switch (relative_addr) {
784 case MEC_INT_STATUS: /* 0x08 */
785 /* Clear bits on write: (This is just a guess) */
786 d->reg[regnr] = (d->reg[regnr] & ~0xff)
787 | ((d->reg[regnr] & ~idata) & 0xff);
788 break;
789 case MEC_TX_RING_PTR: /* 0x30 */
790 idata &= MEC_TX_RING_WRITE_PTR;
791 d->reg[regnr] = (d->reg[regnr] &
792 ~MEC_TX_RING_WRITE_PTR) | idata;
793 /* TODO */
794 break;
795 default:
796 d->reg[regnr] = idata;
797 }
798 } else
799 odata = d->reg[regnr];
800
801 switch (relative_addr) {
802 case MEC_MAC_CONTROL: /* 0x00 */
803 if (writeflag)
804 mec_control_write(cpu, d, idata);
805 else {
806 /* Fake "revision 1": */
807 odata &= ~MEC_MAC_REVISION;
808 odata |= 1 << MEC_MAC_REVISION_SHIFT;
809 }
810 break;
811 case MEC_INT_STATUS: /* 0x08 */
812 if (writeflag)
813 debug("[ sgi_mec: write to MEC_INT_STATUS: "
814 "0x%016llx ]\n", (long long)idata);
815 break;
816 case MEC_DMA_CONTROL: /* 0x10 */
817 if (writeflag) {
818 debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
819 "0x%016llx ]\n", (long long)idata);
820 if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
821 /* This should apparently stop the
822 TX Empty interrupt. */
823 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
824 ~MEC_INT_TX_EMPTY;
825 }
826 }
827 break;
828 case MEC_TX_ALIAS: /* 0x20 */
829 if (writeflag) {
830 debug("[ sgi_mec: write to MEC_TX_ALIAS: "
831 "0x%016llx ]\n", (long long)idata);
832 } else {
833 debug("[ sgi_mec: read from MEC_TX_ALIAS: "
834 "0x%016llx ]\n", (long long)idata);
835 odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
836 }
837 break;
838 case MEC_RX_ALIAS: /* 0x28 */
839 if (writeflag)
840 debug("[ sgi_mec: write to MEC_RX_ALIAS: "
841 "0x%016llx ]\n", (long long)idata);
842 break;
843 case MEC_TX_RING_PTR: /* 0x30 */
844 if (writeflag)
845 debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
846 "0x%016llx ]\n", (long long)idata);
847 break;
848 case MEC_PHY_DATA: /* 0x64 */
849 if (writeflag)
850 fatal("[ sgi_mec: write to MEC_PHY_DATA: "
851 "0x%016llx ]\n", (long long)idata);
852 else
853 odata = 0; /* ? */
854 break;
855 case MEC_PHY_ADDRESS: /* 0x6c */
856 if (writeflag)
857 debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
858 "0x%016llx ]\n", (long long)idata);
859 break;
860 case MEC_PHY_READ_INITIATE: /* 0x70 */
861 if (writeflag)
862 debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
863 "0x%016llx ]\n", (long long)idata);
864 break;
865 case 0x74:
866 if (writeflag)
867 debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
868 (long long)idata);
869 else
870 debug("[ sgi_mec: read from 0x74 ]\n");
871 break;
872 case MEC_STATION: /* 0xa0 */
873 if (writeflag)
874 debug("[ sgi_mec: setting the MAC address to "
875 "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
876 (idata >> 40) & 255, (idata >> 32) & 255,
877 (idata >> 24) & 255, (idata >> 16) & 255,
878 (idata >> 8) & 255, (idata >> 0) & 255);
879 break;
880 case MEC_STATION_ALT: /* 0xa8 */
881 if (writeflag)
882 debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
883 " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
884 (idata >> 40) & 255, (idata >> 32) & 255,
885 (idata >> 24) & 255, (idata >> 16) & 255,
886 (idata >> 8) & 255, (idata >> 0) & 255);
887 break;
888 case MEC_MULTICAST: /* 0xb0 */
889 if (writeflag)
890 debug("[ sgi_mec: write to MEC_MULTICAST: "
891 "0x%016llx ]\n", (long long)idata);
892 break;
893 case MEC_TX_RING_BASE: /* 0xb8 */
894 if (writeflag)
895 debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
896 "0x%016llx ]\n", (long long)idata);
897 break;
898 case MEC_MCL_RX_FIFO: /* 0x100 */
899 if (writeflag) {
900 debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
901 "%016llx ]\n", (long long)idata);
902 d->rx_addr[d->cur_rx_addr_index_write] = idata;
903 d->cur_rx_addr_index_write ++;
904 d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
905 }
906 break;
907 default:
908 if (writeflag == MEM_WRITE)
909 fatal("[ sgi_mec: unimplemented write to address"
910 " 0x%llx, data=0x%016llx ]\n",
911 (long long)relative_addr, (long long)idata);
912 else
913 fatal("[ sgi_mec: unimplemented read from address"
914 " 0x%llx ]\n", (long long)relative_addr);
915 }
916
917 if (writeflag == MEM_READ)
918 memory_writemax64(cpu, data, len, odata);
919
920 dev_sgi_mec_tick(cpu, extra);
921
922 return 1;
923 }
924
925
926 /*
927 * dev_sgi_mec_init():
928 */
929 void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
930 uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
931 {
932 char *name2;
933 size_t nlen = 55;
934 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
935
936 if (d == NULL) {
937 fprintf(stderr, "out of memory\n");
938 exit(1);
939 }
940 memset(d, 0, sizeof(struct sgi_mec_data));
941 d->irq_nr = irq_nr;
942 memcpy(d->macaddr, macaddr, 6);
943
944 mec_reset(d);
945
946 name2 = malloc(nlen);
947 if (name2 == NULL) {
948 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
949 exit(1);
950 }
951 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
952 d->macaddr[0], d->macaddr[1], d->macaddr[2],
953 d->macaddr[3], d->macaddr[4], d->macaddr[5]);
954
955 memory_device_register(mem, name2, baseaddr,
956 DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
957 MEM_DEFAULT, NULL);
958
959 machine_add_tickfunction(machine, dev_sgi_mec_tick, d, MEC_TICK_SHIFT);
960
961 net_add_nic(machine->emul->net, d, macaddr);
962 }
963
964
965 /****************************************************************************/
966
967
968 struct sgi_ust_data {
969 uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
970 };
971
972
973 /*
974 * dev_sgi_ust_access():
975 */
976 int dev_sgi_ust_access(struct cpu *cpu, struct memory *mem,
977 uint64_t relative_addr, unsigned char *data, size_t len,
978 int writeflag, void *extra)
979 {
980 struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
981 uint64_t idata = 0, odata = 0;
982 int regnr;
983
984 idata = memory_readmax64(cpu, data, len);
985 regnr = relative_addr / sizeof(uint64_t);
986
987 /* Treat all registers as read/write, by default. */
988 if (writeflag == MEM_WRITE)
989 d->reg[regnr] = idata;
990 else
991 odata = d->reg[regnr];
992
993 switch (relative_addr) {
994 case 0:
995 d->reg[regnr] += 0x2710;
996 break;
997 default:
998 if (writeflag == MEM_WRITE)
999 debug("[ sgi_ust: unimplemented write to "
1000 "address 0x%llx, data=0x%016llx ]\n",
1001 (long long)relative_addr, (long long)idata);
1002 else
1003 debug("[ sgi_ust: unimplemented read from address"
1004 " 0x%llx ]\n", (long long)relative_addr);
1005 }
1006
1007 if (writeflag == MEM_READ)
1008 memory_writemax64(cpu, data, len, odata);
1009
1010 return 1;
1011 }
1012
1013
1014 /*
1015 * dev_sgi_ust_init():
1016 */
1017 void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1018 {
1019 struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1020 if (d == NULL) {
1021 fprintf(stderr, "out of memory\n");
1022 exit(1);
1023 }
1024 memset(d, 0, sizeof(struct sgi_ust_data));
1025
1026 memory_device_register(mem, "sgi_ust", baseaddr,
1027 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1028 MEM_DEFAULT, NULL);
1029 }
1030
1031
1032 /****************************************************************************/
1033
1034
1035 /*
1036 * SGI "mte". This device seems to be an accelerator for copying/clearing
1037 * memory. Used by (at least) the SGI O2 PROM.
1038 *
1039 * Actually, it seems to be used for graphics output as well. (?)
1040 * The O2's PROM uses it to output graphics.
1041 */
1042 /* #define debug fatal */
1043 /* #define MTE_DEBUG */
1044 #define ZERO_CHUNK_LEN 4096
1045
1046 struct sgi_mte_data {
1047 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1048 };
1049
1050 /*
1051 * dev_sgi_mte_access():
1052 */
1053 int dev_sgi_mte_access(struct cpu *cpu, struct memory *mem,
1054 uint64_t relative_addr, unsigned char *data, size_t len,
1055 int writeflag, void *extra)
1056 {
1057 struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1058 uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1059 unsigned char zerobuf[ZERO_CHUNK_LEN];
1060 uint64_t idata = 0, odata = 0;
1061 int regnr;
1062
1063 idata = memory_readmax64(cpu, data, len);
1064 regnr = relative_addr / sizeof(uint32_t);
1065
1066 /*
1067 * Treat all registers as read/write, by default. Sometimes these
1068 * are accessed as 32-bit words, sometimes as 64-bit words.
1069 */
1070 if (len != 4) {
1071 if (writeflag == MEM_WRITE) {
1072 d->reg[regnr] = idata >> 32;
1073 d->reg[regnr+1] = idata;
1074 } else
1075 odata = ((uint64_t)d->reg[regnr] << 32) +
1076 d->reg[regnr+1];
1077 }
1078
1079 if (writeflag == MEM_WRITE)
1080 d->reg[regnr] = idata;
1081 else
1082 odata = d->reg[regnr];
1083
1084 #ifdef MTE_DEBUG
1085 if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1086 relative_addr < 0x3000)
1087 fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1088 (long long)idata);
1089 #endif
1090
1091 /*
1092 * I've not found any docs about this 'mte' device at all, so this is
1093 * just a guess. The mte seems to be used for copying and zeroing
1094 * chunks of memory.
1095 *
1096 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1097 * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1098 * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1099 * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1100 * write to 0x3800, data=0x0000000000000011 ] <-- operation
1101 * (0x11 = zerofill)
1102 *
1103 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1104 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1105 * write to 0x1710, data=0x80001ea480001ea5
1106 * ...
1107 * write to 0x1770, data=0x80001e9c80001e9d
1108 * write to 0x1778, data=0x80001e9e80001e9f
1109 */
1110 switch (relative_addr) {
1111
1112 /* No warnings for these: */
1113 case 0x3030:
1114 case 0x3038:
1115 break;
1116
1117 /* Unknown, but no warning: */
1118 case 0x4000:
1119 case 0x3018:
1120 case 0x3008:
1121 case 0x1700:
1122 case 0x1708:
1123 case 0x1710:
1124 case 0x1718:
1125 case 0x1720:
1126 case 0x1728:
1127 case 0x1730:
1128 case 0x1738:
1129 case 0x1740:
1130 case 0x1748:
1131 case 0x1750:
1132 case 0x1758:
1133 case 0x1760:
1134 case 0x1768:
1135 case 0x1770:
1136 case 0x1778:
1137 break;
1138
1139 /* Graphics stuff? No warning: */
1140 case 0x2018:
1141 case 0x2060:
1142 case 0x2070:
1143 case 0x2074:
1144 case 0x20c0:
1145 case 0x20c4:
1146 case 0x20d0:
1147 case 0x21b0:
1148 case 0x21b8:
1149 break;
1150
1151 /* Perform graphics operation: */
1152 case 0x21f8:
1153 {
1154 uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1155 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1156 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1157 >> 16) & 0xfff;
1158 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1159 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1160 >> 16) & 0xfff;
1161 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1162 int y;
1163
1164 op >>= 24;
1165
1166 switch (op) {
1167 case 1: /* Unknown. Used after drawing bitmaps? */
1168 break;
1169 case 3: /* Fill: */
1170 if (x2 < x1) {
1171 int tmp = x1; x1 = x2; x2 = tmp;
1172 }
1173 if (y2 < y1) {
1174 int tmp = y1; y1 = y2; y2 = tmp;
1175 }
1176 for (y=y1; y<=y2; y++) {
1177 unsigned char buf[1280];
1178 int length = x2-x1+1;
1179 int addr = (x1 + y*1280);
1180 if (length < 1)
1181 length = 1;
1182 memset(buf, color, length);
1183 if (x1 < 1280 && y < 1024)
1184 cpu->memory_rw(cpu, cpu->mem,
1185 0x38000000 + addr, buf,
1186 length, MEM_WRITE,
1187 NO_EXCEPTIONS | PHYSICAL);
1188 }
1189 break;
1190
1191 default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1192 "%i,%i\n\n", op, color, x1,y1, x2,y2);
1193 }
1194 }
1195 break;
1196
1197 case 0x29f0:
1198 /* Pixel output: */
1199 {
1200 uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1201 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1202 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1203 >> 16) & 0xfff;
1204 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1205 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1206 >> 16) & 0xfff;
1207 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1208 int x,y;
1209 if (x2 < x1) {
1210 int tmp = x1; x1 = x2; x2 = tmp;
1211 }
1212 if (y2 < y1) {
1213 int tmp = y1; y1 = y2; y2 = tmp;
1214 }
1215 if (x2-x1 <= 15)
1216 data <<= 16;
1217 x=x1; y=y1;
1218 while (x <= x2 && y <= y2) {
1219 unsigned char buf = color;
1220 int addr = x + y*1280;
1221 int bit_set = data & 0x80000000UL;
1222 data <<= 1;
1223 if (x < 1280 && y < 1024 && bit_set)
1224 cpu->memory_rw(cpu, cpu->mem,
1225 0x38000000 + addr, &buf,1,MEM_WRITE,
1226 NO_EXCEPTIONS | PHYSICAL);
1227 x++;
1228 if (x > x2) {
1229 x = x1;
1230 y++;
1231 }
1232 }
1233 }
1234 break;
1235
1236
1237 /* Operations: */
1238 case 0x3800:
1239 if (writeflag == MEM_WRITE) {
1240 switch (idata) {
1241 case 0x11: /* zerofill */
1242 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1243 last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1244 zerobuflen = last_addr - first_addr + 1;
1245 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1246 " last = 0x%016llx, length = 0x%llx ]\n",
1247 (long long)first_addr, (long long)
1248 last_addr, (long long)zerobuflen);
1249
1250 /* TODO: is there a better way to
1251 implement this? */
1252 memset(zerobuf, 0, sizeof(zerobuf));
1253 fill_addr = first_addr;
1254 while (zerobuflen != 0) {
1255 if (zerobuflen > sizeof(zerobuf))
1256 fill_len = sizeof(zerobuf);
1257 else
1258 fill_len = zerobuflen;
1259 cpu->memory_rw(cpu, mem, fill_addr,
1260 zerobuf, fill_len, MEM_WRITE,
1261 NO_EXCEPTIONS | PHYSICAL);
1262 fill_addr += fill_len;
1263 zerobuflen -= sizeof(zerobuf);
1264 }
1265
1266 break;
1267 default:
1268 fatal("[ sgi_mte: UNKNOWN operation "
1269 "0x%x ]\n", idata);
1270 }
1271 }
1272 break;
1273 default:
1274 if (writeflag == MEM_WRITE)
1275 debug("[ sgi_mte: unimplemented write to "
1276 "address 0x%llx, data=0x%016llx ]\n",
1277 (long long)relative_addr, (long long)idata);
1278 else
1279 debug("[ sgi_mte: unimplemented read from address"
1280 " 0x%llx ]\n", (long long)relative_addr);
1281 }
1282
1283 if (writeflag == MEM_READ)
1284 memory_writemax64(cpu, data, len, odata);
1285
1286 return 1;
1287 }
1288
1289
1290 /*
1291 * dev_sgi_mte_init():
1292 */
1293 void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1294 {
1295 struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1296 if (d == NULL) {
1297 fprintf(stderr, "out of memory\n");
1298 exit(1);
1299 }
1300 memset(d, 0, sizeof(struct sgi_mte_data));
1301
1302 memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1303 dev_sgi_mte_access, (void *)d, MEM_DEFAULT, NULL);
1304 }
1305

  ViewVC Help
Powered by ViewVC 1.1.26