/[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 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33199 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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.38 2005/11/21 09:17:27 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 struct crime_data *d = extra;
114 uint64_t idata = 0;
115 int i;
116
117 if (writeflag == MEM_WRITE)
118 idata = memory_readmax64(cpu, data, len);
119
120 /*
121 * Set crime version/revision:
122 *
123 * This might not be the most elegant or correct solution, but it
124 * seems that the IP32 PROM likes 0x11 for machines without graphics,
125 * and 0xa1 for machines with graphics.
126 *
127 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
128 * that's something one has to live with. (TODO?)
129 */
130 d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
131 d->reg[7] = d->use_fb? 0xa1 : 0x11;
132
133 /*
134 * Amount of memory. Bit 8 of bank control set ==> 128MB instead
135 * of 32MB per bank (?)
136 *
137 * When the bank control registers contain the same value as the
138 * previous one, that bank is not valid. (?)
139 */
140 d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
141 d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
142 d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
143 d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
144
145 if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
146 if (writeflag == MEM_READ)
147 memcpy(data, &d->reg[relative_addr], len);
148 return 1;
149 }
150
151 if (writeflag == MEM_WRITE)
152 memcpy(&d->reg[relative_addr], data, len);
153 else
154 memcpy(data, &d->reg[relative_addr], len);
155
156 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
157 (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
158 /*
159 * Force interrupt re-assertion:
160 *
161 * NOTE: Ugly hack. Hopefully CRMERR is never used.
162 */
163 #if 0
164 /*
165 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
166 TODO.
167 */
168 cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
169 #endif
170 }
171
172 switch (relative_addr) {
173 case CRIME_CONTROL: /* 0x008 */
174 /* TODO: 64-bit write to CRIME_CONTROL, but some things
175 (such as NetBSD 1.6.2) write to 0x00c! */
176 if (writeflag == MEM_WRITE) {
177 /*
178 * 0x200 = watchdog timer (according to NetBSD)
179 * 0x800 = "reboot" used by the IP32 PROM
180 */
181 if (idata & 0x200) {
182 idata &= ~0x200;
183 }
184 if (idata & 0x800) {
185 /* This is used by the IP32 PROM's
186 "reboot" command: */
187 for (i=0; i<cpu->machine->ncpus; i++)
188 cpu->machine->cpus[i]->running = 0;
189 cpu->machine->
190 exit_without_entering_debugger = 1;
191 idata &= ~0x800;
192 }
193 if (idata != 0)
194 fatal("[ CRIME_CONTROL: unimplemented "
195 "control 0x%016llx ]\n", (long long)idata);
196 }
197 break;
198 #if 0
199 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
200 case 0x14:
201 case CRIME_INTMASK: /* 0x018, Current interrupt mask */
202 case 0x1c:
203 case 0x34:
204 /* don't dump debug info for these */
205 break;
206 #endif
207 default:
208 if (writeflag==MEM_READ) {
209 debug("[ crime: read from 0x%x, len=%i:",
210 (int)relative_addr, len);
211 for (i=0; i<len; i++)
212 debug(" %02x", data[i]);
213 debug(" ]\n");
214 } else {
215 debug("[ crime: write to 0x%x:", (int)relative_addr);
216 for (i=0; i<len; i++)
217 debug(" %02x", data[i]);
218 debug(" (len=%i) ]\n", len);
219 }
220 }
221
222 return 1;
223 }
224
225
226 /*
227 * dev_crime_init():
228 */
229 struct crime_data *dev_crime_init(struct machine *machine, struct memory *mem,
230 uint64_t baseaddr, int irq_nr, int use_fb)
231 {
232 struct crime_data *d;
233
234 d = malloc(sizeof(struct crime_data));
235 if (d == NULL) {
236 fprintf(stderr, "out of memory\n");
237 exit(1);
238 }
239 memset(d, 0, sizeof(struct crime_data));
240 d->irq_nr = irq_nr;
241 d->use_fb = use_fb;
242
243 memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
244 dev_crime_access, d, DM_DEFAULT, NULL);
245 machine_add_tickfunction(machine, dev_crime_tick, d, CRIME_TICKSHIFT);
246
247 return d;
248 }
249
250
251 /****************************************************************************/
252
253
254 /*
255 * dev_mace_access():
256 */
257 int dev_mace_access(struct cpu *cpu, struct memory *mem,
258 uint64_t relative_addr, unsigned char *data, size_t len,
259 int writeflag, void *extra)
260 {
261 int i;
262 struct mace_data *d = extra;
263
264 if (writeflag == MEM_WRITE)
265 memcpy(&d->reg[relative_addr], data, len);
266 else
267 memcpy(data, &d->reg[relative_addr], len);
268
269 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
270 (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f))
271 cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
272
273 switch (relative_addr) {
274 #if 0
275 case 0x10: /* Current interrupt assertions */
276 case 0x14:
277 /* don't dump debug info for these */
278 if (writeflag == MEM_WRITE) {
279 fatal("[ NOTE/TODO: WRITE to mace intr: "
280 "reladdr=0x%x data=", (int)relative_addr);
281 for (i=0; i<len; i++)
282 fatal(" %02x", data[i]);
283 fatal(" (len=%i) ]\n", len);
284 }
285 break;
286 case 0x18: /* Interrupt mask */
287 case 0x1c:
288 /* don't dump debug info for these */
289 break;
290 #endif
291 default:
292 if (writeflag == MEM_READ) {
293 debug("[ mace: read from 0x%x:", (int)relative_addr);
294 for (i=0; i<len; i++)
295 debug(" %02x", data[i]);
296 debug(" (len=%i) ]\n", len);
297 } else {
298 debug("[ mace: write to 0x%x:", (int)relative_addr);
299 for (i=0; i<len; i++)
300 debug(" %02x", data[i]);
301 debug(" (len=%i) ]\n", len);
302 }
303 }
304
305 return 1;
306 }
307
308
309 /*
310 * dev_mace_init():
311 */
312 struct mace_data *dev_mace_init(struct memory *mem, uint64_t baseaddr,
313 int irqnr)
314 {
315 struct mace_data *d;
316
317 d = malloc(sizeof(struct mace_data));
318 if (d == NULL) {
319 fprintf(stderr, "out of memory\n");
320 exit(1);
321 }
322 memset(d, 0, sizeof(struct mace_data));
323 d->irqnr = irqnr;
324
325 memory_device_register(mem, "mace", baseaddr, DEV_MACE_LENGTH,
326 dev_mace_access, d, DM_DEFAULT, NULL);
327
328 return d;
329 }
330
331
332 /****************************************************************************/
333
334
335 /*
336 * dev_macepci_access():
337 */
338 int dev_macepci_access(struct cpu *cpu, struct memory *mem,
339 uint64_t relative_addr, unsigned char *data, size_t len,
340 int writeflag, void *extra)
341 {
342 struct macepci_data *d = (struct macepci_data *) extra;
343 uint64_t idata = 0, odata=0;
344 int regnr, res = 1;
345
346 if (writeflag == MEM_WRITE)
347 idata = memory_readmax64(cpu, data, len);
348
349 regnr = relative_addr / sizeof(uint32_t);
350
351 /* Read from/write to the macepci: */
352 switch (relative_addr) {
353 case 0x00: /* Error address */
354 if (writeflag == MEM_WRITE) {
355 } else {
356 odata = 0;
357 }
358 break;
359 case 0x04: /* Error flags */
360 if (writeflag == MEM_WRITE) {
361 } else {
362 odata = 0x06;
363 }
364 break;
365 case 0x0c: /* Revision number */
366 if (writeflag == MEM_WRITE) {
367 } else {
368 odata = 0x01;
369 }
370 break;
371 case 0xcf8: /* PCI ADDR */
372 case 0xcfc: /* PCI DATA */
373 if (writeflag == MEM_WRITE) {
374 res = bus_pci_access(cpu, mem, relative_addr,
375 &idata, len, writeflag, d->pci_data);
376 } else {
377 res = bus_pci_access(cpu, mem, relative_addr,
378 &odata, len, writeflag, d->pci_data);
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, 0,0, 0,0,0, 0,0,0);
413
414 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
415 dev_macepci_access, (void *)d, DM_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 if (writeflag == MEM_WRITE)
779 idata = memory_readmax64(cpu, data, len);
780
781 regnr = relative_addr / sizeof(uint64_t);
782
783 /* Treat most registers as read/write, by default. */
784 if (writeflag == MEM_WRITE) {
785 switch (relative_addr) {
786 case MEC_INT_STATUS: /* 0x08 */
787 /* Clear bits on write: (This is just a guess) */
788 d->reg[regnr] = (d->reg[regnr] & ~0xff)
789 | ((d->reg[regnr] & ~idata) & 0xff);
790 break;
791 case MEC_TX_RING_PTR: /* 0x30 */
792 idata &= MEC_TX_RING_WRITE_PTR;
793 d->reg[regnr] = (d->reg[regnr] &
794 ~MEC_TX_RING_WRITE_PTR) | idata;
795 /* TODO */
796 break;
797 default:
798 d->reg[regnr] = idata;
799 }
800 } else
801 odata = d->reg[regnr];
802
803 switch (relative_addr) {
804 case MEC_MAC_CONTROL: /* 0x00 */
805 if (writeflag)
806 mec_control_write(cpu, d, idata);
807 else {
808 /* Fake "revision 1": */
809 odata &= ~MEC_MAC_REVISION;
810 odata |= 1 << MEC_MAC_REVISION_SHIFT;
811 }
812 break;
813 case MEC_INT_STATUS: /* 0x08 */
814 if (writeflag)
815 debug("[ sgi_mec: write to MEC_INT_STATUS: "
816 "0x%016llx ]\n", (long long)idata);
817 break;
818 case MEC_DMA_CONTROL: /* 0x10 */
819 if (writeflag) {
820 debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
821 "0x%016llx ]\n", (long long)idata);
822 if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
823 /* This should apparently stop the
824 TX Empty interrupt. */
825 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
826 ~MEC_INT_TX_EMPTY;
827 }
828 }
829 break;
830 case MEC_TX_ALIAS: /* 0x20 */
831 if (writeflag) {
832 debug("[ sgi_mec: write to MEC_TX_ALIAS: "
833 "0x%016llx ]\n", (long long)idata);
834 } else {
835 debug("[ sgi_mec: read from MEC_TX_ALIAS: "
836 "0x%016llx ]\n", (long long)idata);
837 odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
838 }
839 break;
840 case MEC_RX_ALIAS: /* 0x28 */
841 if (writeflag)
842 debug("[ sgi_mec: write to MEC_RX_ALIAS: "
843 "0x%016llx ]\n", (long long)idata);
844 break;
845 case MEC_TX_RING_PTR: /* 0x30 */
846 if (writeflag)
847 debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
848 "0x%016llx ]\n", (long long)idata);
849 break;
850 case MEC_PHY_DATA: /* 0x64 */
851 if (writeflag)
852 fatal("[ sgi_mec: write to MEC_PHY_DATA: "
853 "0x%016llx ]\n", (long long)idata);
854 else
855 odata = 0; /* ? */
856 break;
857 case MEC_PHY_ADDRESS: /* 0x6c */
858 if (writeflag)
859 debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
860 "0x%016llx ]\n", (long long)idata);
861 break;
862 case MEC_PHY_READ_INITIATE: /* 0x70 */
863 if (writeflag)
864 debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
865 "0x%016llx ]\n", (long long)idata);
866 break;
867 case 0x74:
868 if (writeflag)
869 debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
870 (long long)idata);
871 else
872 debug("[ sgi_mec: read from 0x74 ]\n");
873 break;
874 case MEC_STATION: /* 0xa0 */
875 if (writeflag)
876 debug("[ sgi_mec: setting the MAC address to "
877 "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
878 (idata >> 40) & 255, (idata >> 32) & 255,
879 (idata >> 24) & 255, (idata >> 16) & 255,
880 (idata >> 8) & 255, (idata >> 0) & 255);
881 break;
882 case MEC_STATION_ALT: /* 0xa8 */
883 if (writeflag)
884 debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
885 " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
886 (idata >> 40) & 255, (idata >> 32) & 255,
887 (idata >> 24) & 255, (idata >> 16) & 255,
888 (idata >> 8) & 255, (idata >> 0) & 255);
889 break;
890 case MEC_MULTICAST: /* 0xb0 */
891 if (writeflag)
892 debug("[ sgi_mec: write to MEC_MULTICAST: "
893 "0x%016llx ]\n", (long long)idata);
894 break;
895 case MEC_TX_RING_BASE: /* 0xb8 */
896 if (writeflag)
897 debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
898 "0x%016llx ]\n", (long long)idata);
899 break;
900 case MEC_MCL_RX_FIFO: /* 0x100 */
901 if (writeflag) {
902 debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
903 "%016llx ]\n", (long long)idata);
904 d->rx_addr[d->cur_rx_addr_index_write] = idata;
905 d->cur_rx_addr_index_write ++;
906 d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
907 }
908 break;
909 default:
910 if (writeflag == MEM_WRITE)
911 fatal("[ sgi_mec: unimplemented write to address"
912 " 0x%llx, data=0x%016llx ]\n",
913 (long long)relative_addr, (long long)idata);
914 else
915 fatal("[ sgi_mec: unimplemented read from address"
916 " 0x%llx ]\n", (long long)relative_addr);
917 }
918
919 if (writeflag == MEM_READ)
920 memory_writemax64(cpu, data, len, odata);
921
922 dev_sgi_mec_tick(cpu, extra);
923
924 return 1;
925 }
926
927
928 /*
929 * dev_sgi_mec_init():
930 */
931 void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
932 uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
933 {
934 char *name2;
935 size_t nlen = 55;
936 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
937
938 if (d == NULL) {
939 fprintf(stderr, "out of memory\n");
940 exit(1);
941 }
942 memset(d, 0, sizeof(struct sgi_mec_data));
943 d->irq_nr = irq_nr;
944 memcpy(d->macaddr, macaddr, 6);
945
946 mec_reset(d);
947
948 name2 = malloc(nlen);
949 if (name2 == NULL) {
950 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
951 exit(1);
952 }
953 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
954 d->macaddr[0], d->macaddr[1], d->macaddr[2],
955 d->macaddr[3], d->macaddr[4], d->macaddr[5]);
956
957 memory_device_register(mem, name2, baseaddr,
958 DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
959 DM_DEFAULT, NULL);
960
961 machine_add_tickfunction(machine, dev_sgi_mec_tick, d, MEC_TICK_SHIFT);
962
963 net_add_nic(machine->emul->net, d, macaddr);
964 }
965
966
967 /****************************************************************************/
968
969
970 struct sgi_ust_data {
971 uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
972 };
973
974
975 /*
976 * dev_sgi_ust_access():
977 */
978 int dev_sgi_ust_access(struct cpu *cpu, struct memory *mem,
979 uint64_t relative_addr, unsigned char *data, size_t len,
980 int writeflag, void *extra)
981 {
982 struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
983 uint64_t idata = 0, odata = 0;
984 int regnr;
985
986 idata = memory_readmax64(cpu, data, len);
987 regnr = relative_addr / sizeof(uint64_t);
988
989 /* Treat all registers as read/write, by default. */
990 if (writeflag == MEM_WRITE)
991 d->reg[regnr] = idata;
992 else
993 odata = d->reg[regnr];
994
995 switch (relative_addr) {
996 case 0:
997 d->reg[regnr] += 0x2710;
998 break;
999 default:
1000 if (writeflag == MEM_WRITE)
1001 debug("[ sgi_ust: unimplemented write to "
1002 "address 0x%llx, data=0x%016llx ]\n",
1003 (long long)relative_addr, (long long)idata);
1004 else
1005 debug("[ sgi_ust: unimplemented read from address"
1006 " 0x%llx ]\n", (long long)relative_addr);
1007 }
1008
1009 if (writeflag == MEM_READ)
1010 memory_writemax64(cpu, data, len, odata);
1011
1012 return 1;
1013 }
1014
1015
1016 /*
1017 * dev_sgi_ust_init():
1018 */
1019 void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1020 {
1021 struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1022 if (d == NULL) {
1023 fprintf(stderr, "out of memory\n");
1024 exit(1);
1025 }
1026 memset(d, 0, sizeof(struct sgi_ust_data));
1027
1028 memory_device_register(mem, "sgi_ust", baseaddr,
1029 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1030 DM_DEFAULT, NULL);
1031 }
1032
1033
1034 /****************************************************************************/
1035
1036
1037 /*
1038 * SGI "mte". This device seems to be an accelerator for copying/clearing
1039 * memory. Used by (at least) the SGI O2 PROM.
1040 *
1041 * Actually, it seems to be used for graphics output as well. (?)
1042 * The O2's PROM uses it to output graphics.
1043 */
1044 /* #define debug fatal */
1045 /* #define MTE_DEBUG */
1046 #define ZERO_CHUNK_LEN 4096
1047
1048 struct sgi_mte_data {
1049 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1050 };
1051
1052 /*
1053 * dev_sgi_mte_access():
1054 */
1055 int dev_sgi_mte_access(struct cpu *cpu, struct memory *mem,
1056 uint64_t relative_addr, unsigned char *data, size_t len,
1057 int writeflag, void *extra)
1058 {
1059 struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1060 uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1061 unsigned char zerobuf[ZERO_CHUNK_LEN];
1062 uint64_t idata = 0, odata = 0;
1063 int regnr;
1064
1065 idata = memory_readmax64(cpu, data, len);
1066 regnr = relative_addr / sizeof(uint32_t);
1067
1068 /*
1069 * Treat all registers as read/write, by default. Sometimes these
1070 * are accessed as 32-bit words, sometimes as 64-bit words.
1071 */
1072 if (len != 4) {
1073 if (writeflag == MEM_WRITE) {
1074 d->reg[regnr] = idata >> 32;
1075 d->reg[regnr+1] = idata;
1076 } else
1077 odata = ((uint64_t)d->reg[regnr] << 32) +
1078 d->reg[regnr+1];
1079 }
1080
1081 if (writeflag == MEM_WRITE)
1082 d->reg[regnr] = idata;
1083 else
1084 odata = d->reg[regnr];
1085
1086 #ifdef MTE_DEBUG
1087 if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1088 relative_addr < 0x3000)
1089 fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1090 (long long)idata);
1091 #endif
1092
1093 /*
1094 * I've not found any docs about this 'mte' device at all, so this is
1095 * just a guess. The mte seems to be used for copying and zeroing
1096 * chunks of memory.
1097 *
1098 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1099 * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1100 * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1101 * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1102 * write to 0x3800, data=0x0000000000000011 ] <-- operation
1103 * (0x11 = zerofill)
1104 *
1105 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1106 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1107 * write to 0x1710, data=0x80001ea480001ea5
1108 * ...
1109 * write to 0x1770, data=0x80001e9c80001e9d
1110 * write to 0x1778, data=0x80001e9e80001e9f
1111 */
1112 switch (relative_addr) {
1113
1114 /* No warnings for these: */
1115 case 0x3030:
1116 case 0x3038:
1117 break;
1118
1119 /* Unknown, but no warning: */
1120 case 0x4000:
1121 case 0x3018:
1122 case 0x3008:
1123 case 0x1700:
1124 case 0x1708:
1125 case 0x1710:
1126 case 0x1718:
1127 case 0x1720:
1128 case 0x1728:
1129 case 0x1730:
1130 case 0x1738:
1131 case 0x1740:
1132 case 0x1748:
1133 case 0x1750:
1134 case 0x1758:
1135 case 0x1760:
1136 case 0x1768:
1137 case 0x1770:
1138 case 0x1778:
1139 break;
1140
1141 /* Graphics stuff? No warning: */
1142 case 0x2018:
1143 case 0x2060:
1144 case 0x2070:
1145 case 0x2074:
1146 case 0x20c0:
1147 case 0x20c4:
1148 case 0x20d0:
1149 case 0x21b0:
1150 case 0x21b8:
1151 break;
1152
1153 /* Perform graphics operation: */
1154 case 0x21f8:
1155 {
1156 uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1157 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1158 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1159 >> 16) & 0xfff;
1160 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1161 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1162 >> 16) & 0xfff;
1163 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1164 int y;
1165
1166 op >>= 24;
1167
1168 switch (op) {
1169 case 1: /* Unknown. Used after drawing bitmaps? */
1170 break;
1171 case 3: /* Fill: */
1172 if (x2 < x1) {
1173 int tmp = x1; x1 = x2; x2 = tmp;
1174 }
1175 if (y2 < y1) {
1176 int tmp = y1; y1 = y2; y2 = tmp;
1177 }
1178 for (y=y1; y<=y2; y++) {
1179 unsigned char buf[1280];
1180 int length = x2-x1+1;
1181 int addr = (x1 + y*1280);
1182 if (length < 1)
1183 length = 1;
1184 memset(buf, color, length);
1185 if (x1 < 1280 && y < 1024)
1186 cpu->memory_rw(cpu, cpu->mem,
1187 0x38000000 + addr, buf,
1188 length, MEM_WRITE,
1189 NO_EXCEPTIONS | PHYSICAL);
1190 }
1191 break;
1192
1193 default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1194 "%i,%i\n\n", op, color, x1,y1, x2,y2);
1195 }
1196 }
1197 break;
1198
1199 case 0x29f0:
1200 /* Pixel output: */
1201 {
1202 uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1203 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1204 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1205 >> 16) & 0xfff;
1206 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1207 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1208 >> 16) & 0xfff;
1209 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1210 int x,y;
1211 if (x2 < x1) {
1212 int tmp = x1; x1 = x2; x2 = tmp;
1213 }
1214 if (y2 < y1) {
1215 int tmp = y1; y1 = y2; y2 = tmp;
1216 }
1217 if (x2-x1 <= 15)
1218 data <<= 16;
1219 x=x1; y=y1;
1220 while (x <= x2 && y <= y2) {
1221 unsigned char buf = color;
1222 int addr = x + y*1280;
1223 int bit_set = data & 0x80000000UL;
1224 data <<= 1;
1225 if (x < 1280 && y < 1024 && bit_set)
1226 cpu->memory_rw(cpu, cpu->mem,
1227 0x38000000 + addr, &buf,1,MEM_WRITE,
1228 NO_EXCEPTIONS | PHYSICAL);
1229 x++;
1230 if (x > x2) {
1231 x = x1;
1232 y++;
1233 }
1234 }
1235 }
1236 break;
1237
1238
1239 /* Operations: */
1240 case 0x3800:
1241 if (writeflag == MEM_WRITE) {
1242 switch (idata) {
1243 case 0x11: /* zerofill */
1244 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1245 last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1246 zerobuflen = last_addr - first_addr + 1;
1247 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1248 " last = 0x%016llx, length = 0x%llx ]\n",
1249 (long long)first_addr, (long long)
1250 last_addr, (long long)zerobuflen);
1251
1252 /* TODO: is there a better way to
1253 implement this? */
1254 memset(zerobuf, 0, sizeof(zerobuf));
1255 fill_addr = first_addr;
1256 while (zerobuflen != 0) {
1257 if (zerobuflen > sizeof(zerobuf))
1258 fill_len = sizeof(zerobuf);
1259 else
1260 fill_len = zerobuflen;
1261 cpu->memory_rw(cpu, mem, fill_addr,
1262 zerobuf, fill_len, MEM_WRITE,
1263 NO_EXCEPTIONS | PHYSICAL);
1264 fill_addr += fill_len;
1265 zerobuflen -= sizeof(zerobuf);
1266 }
1267
1268 break;
1269 default:
1270 fatal("[ sgi_mte: UNKNOWN operation "
1271 "0x%x ]\n", idata);
1272 }
1273 }
1274 break;
1275 default:
1276 if (writeflag == MEM_WRITE)
1277 debug("[ sgi_mte: unimplemented write to "
1278 "address 0x%llx, data=0x%016llx ]\n",
1279 (long long)relative_addr, (long long)idata);
1280 else
1281 debug("[ sgi_mte: unimplemented read from address"
1282 " 0x%llx ]\n", (long long)relative_addr);
1283 }
1284
1285 if (writeflag == MEM_READ)
1286 memory_writemax64(cpu, data, len, odata);
1287
1288 return 1;
1289 }
1290
1291
1292 /*
1293 * dev_sgi_mte_init():
1294 */
1295 void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1296 {
1297 struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1298 if (d == NULL) {
1299 fprintf(stderr, "out of memory\n");
1300 exit(1);
1301 }
1302 memset(d, 0, sizeof(struct sgi_mte_data));
1303
1304 memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1305 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1306 }
1307

  ViewVC Help
Powered by ViewVC 1.1.26