/[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 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33198 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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.34 2005/10/27 14:01:14 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, MEM_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, MEM_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, writeflag, d->pci_data);
376 } else {
377 res = bus_pci_access(cpu, mem, relative_addr,
378 &odata, writeflag, d->pci_data);
379 /* odata = 0; */
380 }
381 break;
382 default:
383 if (writeflag == MEM_WRITE) {
384 debug("[ macepci: unimplemented write to address "
385 "0x%x, data=0x%02x ]\n",
386 (int)relative_addr, (int)idata);
387 } else {
388 debug("[ macepci: unimplemented read from address "
389 "0x%x ]\n", (int)relative_addr);
390 }
391 }
392
393 if (writeflag == MEM_READ)
394 memory_writemax64(cpu, data, len, odata);
395
396 return res;
397 }
398
399
400 /*
401 * dev_macepci_init():
402 */
403 struct pci_data *dev_macepci_init(struct memory *mem, uint64_t baseaddr,
404 int pciirq)
405 {
406 struct macepci_data *d = malloc(sizeof(struct macepci_data));
407 if (d == NULL) {
408 fprintf(stderr, "out of memory\n");
409 exit(1);
410 }
411 memset(d, 0, sizeof(struct macepci_data));
412
413 d->pci_data = bus_pci_init(pciirq);
414
415 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
416 dev_macepci_access, (void *)d, MEM_DEFAULT, NULL);
417
418 return d->pci_data;
419 }
420
421
422 /****************************************************************************/
423
424
425 /*
426 * SGI "mec" ethernet. Used in SGI-IP32.
427 *
428 * Study http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c
429 * and/or NetBSD. TODO:
430 *
431 * x) tx and rx interrupts/ring/slot stuff
432 */
433
434 #define MEC_TICK_SHIFT 14
435
436 #define MAX_TX_PACKET_LEN 1700
437 #define N_RX_ADDRESSES 16
438
439 struct sgi_mec_data {
440 uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
441
442 int irq_nr;
443 unsigned char macaddr[6];
444
445 unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
446 int cur_tx_packet_len;
447
448 unsigned char *cur_rx_packet;
449 int cur_rx_packet_len;
450
451 uint64_t rx_addr[N_RX_ADDRESSES];
452 int cur_rx_addr_index_write;
453 int cur_rx_addr_index;
454 };
455
456
457 /*
458 * mec_reset():
459 */
460 static void mec_reset(struct sgi_mec_data *d)
461 {
462 if (d->cur_rx_packet != NULL)
463 free(d->cur_rx_packet);
464
465 memset(d->reg, 0, sizeof(d->reg));
466 }
467
468
469 /*
470 * mec_control_write():
471 */
472 static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d,
473 uint64_t x)
474 {
475 if (x & MEC_MAC_CORE_RESET) {
476 debug("[ sgi_mec: CORE RESET ]\n");
477 mec_reset(d);
478 }
479 }
480
481
482 /*
483 * mec_try_rx():
484 */
485 static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d)
486 {
487 uint64_t base;
488 unsigned char data[8];
489 int i, res, retval = 0;
490
491 base = d->rx_addr[d->cur_rx_addr_index];
492 if (base & 0xfff)
493 fatal("[ mec_try_rx(): WARNING! lowest bits of base are "
494 "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff));
495 base &= 0xfffff000ULL;
496 if (base == 0)
497 goto skip;
498
499 /* printf("rx base = 0x%016llx\n", (long long)base); */
500
501 /* Read an rx descriptor from memory: */
502 res = cpu->memory_rw(cpu, cpu->mem, base,
503 &data[0], sizeof(data), MEM_READ, PHYSICAL);
504 if (!res)
505 return 0;
506
507 #if 0
508 printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index);
509 for (i=0; i<sizeof(data); i++) {
510 if ((i & 3) == 0)
511 printf(" ");
512 printf("%02x", data[i]);
513 }
514 printf(" }\n");
515 #endif
516
517 /* Is this descriptor already in use? */
518 if (data[0] & 0x80) {
519 /* printf("INTERRUPT for base = 0x%x\n", (int)base); */
520 goto skip_and_advance;
521 }
522
523 if (d->cur_rx_packet == NULL &&
524 net_ethernet_rx_avail(cpu->machine->emul->net, d))
525 net_ethernet_rx(cpu->machine->emul->net, d,
526 &d->cur_rx_packet, &d->cur_rx_packet_len);
527
528 if (d->cur_rx_packet == NULL)
529 goto skip;
530
531 /* Copy the packet data: */
532 /* printf("RX: "); */
533 for (i=0; i<d->cur_rx_packet_len; i++) {
534 res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2,
535 d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL);
536 /* printf(" %02x", d->cur_rx_packet[i]); */
537 }
538 /* printf("\n"); */
539
540 #if 0
541 printf("RX: %i bytes, index %i, base = 0x%x\n",
542 d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base);
543 #endif
544
545 /* 4 bytes of CRC at the end. Hm. TODO */
546 d->cur_rx_packet_len += 4;
547
548 memset(data, 0, sizeof(data));
549 data[6] = (d->cur_rx_packet_len >> 8) & 255;
550 data[7] = d->cur_rx_packet_len & 255;
551 /* TODO: lots of bits :-) */
552 data[4] = 0x04; /* match MAC */
553 data[0] = 0x80; /* 0x80 = received. */
554 res = cpu->memory_rw(cpu, cpu->mem, base,
555 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
556
557 /* Free the packet from memory: */
558 free(d->cur_rx_packet);
559 d->cur_rx_packet = NULL;
560
561 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD;
562 skip_and_advance:
563 d->cur_rx_addr_index ++;
564 d->cur_rx_addr_index %= N_RX_ADDRESSES;
565 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS;
566 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
567 (d->cur_rx_addr_index & 0x1f) << 8;
568 retval = 1;
569
570 skip:
571 return retval;
572 }
573
574
575 /*
576 * mec_try_tx():
577 */
578 static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
579 {
580 uint64_t base, addr, dma_base;
581 int tx_ring_ptr, ringread, ringwrite, res, i, j;
582 unsigned char data[32];
583 int len, start_offset, dma_ptr_nr, dma_len;
584
585 base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
586 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
587
588 if (base == 0)
589 return 0;
590
591 /* printf("base = 0x%016llx\n", base); */
592
593 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
594 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
595 ringread >>= 16;
596 /* All done? Then abort. */
597 if (ringread == ringwrite)
598 return 0;
599
600 tx_ring_ptr &= MEC_TX_RING_READ_PTR;
601 tx_ring_ptr >>= 16;
602
603 /* Each tx descriptor (+ buffer) is 128 bytes: */
604 addr = base + tx_ring_ptr*128;
605 res = cpu->memory_rw(cpu, cpu->mem, addr,
606 &data[0], sizeof(data), MEM_READ, PHYSICAL);
607 if (!res)
608 return 0;
609
610 /* Is this packet transmitted already? */
611 if (data[0] & 0x80) {
612 fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
613 " transmitted? ]\n", tx_ring_ptr);
614 goto advance_tx;
615 }
616
617 len = data[6] * 256 + data[7];
618 start_offset = data[5] & 0x7f;
619
620 /* Is this packet empty? Then don't transmit. */
621 if (len == 0)
622 return 0;
623
624 /* Hm. Is len one too little? TODO */
625 len ++;
626
627 #if 0
628 printf("{ mec: txdesc %i: ", tx_ring_ptr);
629 for (i=0; i<sizeof(data); i++) {
630 if ((i & 3) == 0)
631 printf(" ");
632 printf("%02x", data[i]);
633 }
634 printf(" }\n");
635 #endif
636 dma_ptr_nr = 0;
637
638 j = 0;
639 d->cur_tx_packet_len = len;
640
641 for (i=start_offset; i<start_offset+len; i++) {
642 unsigned char ch;
643
644 if ((i & 0x7f) == 0x00)
645 break;
646
647 res = cpu->memory_rw(cpu, cpu->mem, addr + i,
648 &ch, sizeof(ch), MEM_READ, PHYSICAL);
649 /* printf(" %02x", ch); */
650
651 d->cur_tx_packet[j++] = ch;
652 if (j >= MAX_TX_PACKET_LEN) {
653 fatal("[ mec_try_tx: packet too large? ]\n");
654 break;
655 }
656 }
657 /* printf("\n"); */
658
659 if (j < len) {
660 /* Continue with DMA: */
661 for (;;) {
662 dma_ptr_nr ++;
663 if (dma_ptr_nr >= 4)
664 break;
665 if (!(data[4] & (0x01 << dma_ptr_nr)))
666 break;
667 dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
668 + (data[dma_ptr_nr * 8 + 5] << 16)
669 + (data[dma_ptr_nr * 8 + 6] << 8)
670 + (data[dma_ptr_nr * 8 + 7]);
671 dma_base &= 0xfffffff8ULL;
672 dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
673 + (data[dma_ptr_nr * 8 + 3]) + 1;
674
675 /* printf("dma_base = %08x, dma_len = %i\n",
676 (int)dma_base, dma_len); */
677
678 while (dma_len > 0) {
679 unsigned char ch;
680 res = cpu->memory_rw(cpu, cpu->mem, dma_base,
681 &ch, sizeof(ch), MEM_READ, PHYSICAL);
682 /* printf(" %02x", ch); */
683
684 d->cur_tx_packet[j++] = ch;
685 if (j >= MAX_TX_PACKET_LEN) {
686 fatal("[ mec_try_tx: packet too large?"
687 " ]\n");
688 break;
689 }
690 dma_base ++;
691 dma_len --;
692 }
693 }
694 }
695
696 if (j < len)
697 fatal("[ mec_try_tx: not enough data? ]\n");
698
699 net_ethernet_tx(cpu->machine->emul->net, d,
700 d->cur_tx_packet, d->cur_tx_packet_len);
701
702 /* see openbsd's if_mec.c for details */
703 if (data[4] & 0x01) {
704 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
705 MEC_INT_TX_PACKET_SENT;
706 }
707 memset(data, 0, 6); /* last 2 bytes are len */
708 data[0] = 0x80;
709 data[5] = 0x80;
710
711 res = cpu->memory_rw(cpu, cpu->mem, addr,
712 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
713
714 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
715 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
716
717 advance_tx:
718 /* Advance the ring Read ptr. */
719 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
720 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
721 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
722
723 ringread = (ringread >> 16) + 1;
724 ringread &= 63;
725 ringread <<= 16;
726
727 d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
728 (ringwrite & MEC_TX_RING_WRITE_PTR) |
729 (ringread & MEC_TX_RING_READ_PTR);
730
731 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
732 ~MEC_INT_TX_RING_BUFFER_ALIAS;
733 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
734 (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
735 MEC_INT_TX_RING_BUFFER_ALIAS);
736
737 return 1;
738 }
739
740
741 /*
742 * dev_sgi_mec_tick():
743 */
744 void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
745 {
746 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
747 int n = 0;
748
749 while (mec_try_tx(cpu, d))
750 ;
751
752 while (mec_try_rx(cpu, d) && n < 16)
753 n++;
754
755 /* Interrupts: (TODO: only when enabled) */
756 if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
757 #if 0
758 printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
759 sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
760 fflush(stdout);
761 #endif
762 cpu_interrupt(cpu, d->irq_nr);
763 } else
764 cpu_interrupt_ack(cpu, d->irq_nr);
765 }
766
767
768 /*
769 * dev_sgi_mec_access():
770 */
771 int dev_sgi_mec_access(struct cpu *cpu, struct memory *mem,
772 uint64_t relative_addr, unsigned char *data, size_t len,
773 int writeflag, void *extra)
774 {
775 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
776 uint64_t idata = 0, odata = 0;
777 int regnr;
778
779 if (writeflag == MEM_WRITE)
780 idata = memory_readmax64(cpu, data, len);
781
782 regnr = relative_addr / sizeof(uint64_t);
783
784 /* Treat most registers as read/write, by default. */
785 if (writeflag == MEM_WRITE) {
786 switch (relative_addr) {
787 case MEC_INT_STATUS: /* 0x08 */
788 /* Clear bits on write: (This is just a guess) */
789 d->reg[regnr] = (d->reg[regnr] & ~0xff)
790 | ((d->reg[regnr] & ~idata) & 0xff);
791 break;
792 case MEC_TX_RING_PTR: /* 0x30 */
793 idata &= MEC_TX_RING_WRITE_PTR;
794 d->reg[regnr] = (d->reg[regnr] &
795 ~MEC_TX_RING_WRITE_PTR) | idata;
796 /* TODO */
797 break;
798 default:
799 d->reg[regnr] = idata;
800 }
801 } else
802 odata = d->reg[regnr];
803
804 switch (relative_addr) {
805 case MEC_MAC_CONTROL: /* 0x00 */
806 if (writeflag)
807 mec_control_write(cpu, d, idata);
808 else {
809 /* Fake "revision 1": */
810 odata &= ~MEC_MAC_REVISION;
811 odata |= 1 << MEC_MAC_REVISION_SHIFT;
812 }
813 break;
814 case MEC_INT_STATUS: /* 0x08 */
815 if (writeflag)
816 debug("[ sgi_mec: write to MEC_INT_STATUS: "
817 "0x%016llx ]\n", (long long)idata);
818 break;
819 case MEC_DMA_CONTROL: /* 0x10 */
820 if (writeflag) {
821 debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
822 "0x%016llx ]\n", (long long)idata);
823 if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
824 /* This should apparently stop the
825 TX Empty interrupt. */
826 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
827 ~MEC_INT_TX_EMPTY;
828 }
829 }
830 break;
831 case MEC_TX_ALIAS: /* 0x20 */
832 if (writeflag) {
833 debug("[ sgi_mec: write to MEC_TX_ALIAS: "
834 "0x%016llx ]\n", (long long)idata);
835 } else {
836 debug("[ sgi_mec: read from MEC_TX_ALIAS: "
837 "0x%016llx ]\n", (long long)idata);
838 odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
839 }
840 break;
841 case MEC_RX_ALIAS: /* 0x28 */
842 if (writeflag)
843 debug("[ sgi_mec: write to MEC_RX_ALIAS: "
844 "0x%016llx ]\n", (long long)idata);
845 break;
846 case MEC_TX_RING_PTR: /* 0x30 */
847 if (writeflag)
848 debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
849 "0x%016llx ]\n", (long long)idata);
850 break;
851 case MEC_PHY_DATA: /* 0x64 */
852 if (writeflag)
853 fatal("[ sgi_mec: write to MEC_PHY_DATA: "
854 "0x%016llx ]\n", (long long)idata);
855 else
856 odata = 0; /* ? */
857 break;
858 case MEC_PHY_ADDRESS: /* 0x6c */
859 if (writeflag)
860 debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
861 "0x%016llx ]\n", (long long)idata);
862 break;
863 case MEC_PHY_READ_INITIATE: /* 0x70 */
864 if (writeflag)
865 debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
866 "0x%016llx ]\n", (long long)idata);
867 break;
868 case 0x74:
869 if (writeflag)
870 debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
871 (long long)idata);
872 else
873 debug("[ sgi_mec: read from 0x74 ]\n");
874 break;
875 case MEC_STATION: /* 0xa0 */
876 if (writeflag)
877 debug("[ sgi_mec: setting the MAC address to "
878 "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
879 (idata >> 40) & 255, (idata >> 32) & 255,
880 (idata >> 24) & 255, (idata >> 16) & 255,
881 (idata >> 8) & 255, (idata >> 0) & 255);
882 break;
883 case MEC_STATION_ALT: /* 0xa8 */
884 if (writeflag)
885 debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
886 " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
887 (idata >> 40) & 255, (idata >> 32) & 255,
888 (idata >> 24) & 255, (idata >> 16) & 255,
889 (idata >> 8) & 255, (idata >> 0) & 255);
890 break;
891 case MEC_MULTICAST: /* 0xb0 */
892 if (writeflag)
893 debug("[ sgi_mec: write to MEC_MULTICAST: "
894 "0x%016llx ]\n", (long long)idata);
895 break;
896 case MEC_TX_RING_BASE: /* 0xb8 */
897 if (writeflag)
898 debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
899 "0x%016llx ]\n", (long long)idata);
900 break;
901 case MEC_MCL_RX_FIFO: /* 0x100 */
902 if (writeflag) {
903 debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
904 "%016llx ]\n", (long long)idata);
905 d->rx_addr[d->cur_rx_addr_index_write] = idata;
906 d->cur_rx_addr_index_write ++;
907 d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
908 }
909 break;
910 default:
911 if (writeflag == MEM_WRITE)
912 fatal("[ sgi_mec: unimplemented write to address"
913 " 0x%llx, data=0x%016llx ]\n",
914 (long long)relative_addr, (long long)idata);
915 else
916 fatal("[ sgi_mec: unimplemented read from address"
917 " 0x%llx ]\n", (long long)relative_addr);
918 }
919
920 if (writeflag == MEM_READ)
921 memory_writemax64(cpu, data, len, odata);
922
923 dev_sgi_mec_tick(cpu, extra);
924
925 return 1;
926 }
927
928
929 /*
930 * dev_sgi_mec_init():
931 */
932 void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
933 uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
934 {
935 char *name2;
936 size_t nlen = 55;
937 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
938
939 if (d == NULL) {
940 fprintf(stderr, "out of memory\n");
941 exit(1);
942 }
943 memset(d, 0, sizeof(struct sgi_mec_data));
944 d->irq_nr = irq_nr;
945 memcpy(d->macaddr, macaddr, 6);
946
947 mec_reset(d);
948
949 name2 = malloc(nlen);
950 if (name2 == NULL) {
951 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
952 exit(1);
953 }
954 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
955 d->macaddr[0], d->macaddr[1], d->macaddr[2],
956 d->macaddr[3], d->macaddr[4], d->macaddr[5]);
957
958 memory_device_register(mem, name2, baseaddr,
959 DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
960 MEM_DEFAULT, NULL);
961
962 machine_add_tickfunction(machine, dev_sgi_mec_tick, d, MEC_TICK_SHIFT);
963
964 net_add_nic(machine->emul->net, d, macaddr);
965 }
966
967
968 /****************************************************************************/
969
970
971 struct sgi_ust_data {
972 uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
973 };
974
975
976 /*
977 * dev_sgi_ust_access():
978 */
979 int dev_sgi_ust_access(struct cpu *cpu, struct memory *mem,
980 uint64_t relative_addr, unsigned char *data, size_t len,
981 int writeflag, void *extra)
982 {
983 struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
984 uint64_t idata = 0, odata = 0;
985 int regnr;
986
987 idata = memory_readmax64(cpu, data, len);
988 regnr = relative_addr / sizeof(uint64_t);
989
990 /* Treat all registers as read/write, by default. */
991 if (writeflag == MEM_WRITE)
992 d->reg[regnr] = idata;
993 else
994 odata = d->reg[regnr];
995
996 switch (relative_addr) {
997 case 0:
998 d->reg[regnr] += 0x2710;
999 break;
1000 default:
1001 if (writeflag == MEM_WRITE)
1002 debug("[ sgi_ust: unimplemented write to "
1003 "address 0x%llx, data=0x%016llx ]\n",
1004 (long long)relative_addr, (long long)idata);
1005 else
1006 debug("[ sgi_ust: unimplemented read from address"
1007 " 0x%llx ]\n", (long long)relative_addr);
1008 }
1009
1010 if (writeflag == MEM_READ)
1011 memory_writemax64(cpu, data, len, odata);
1012
1013 return 1;
1014 }
1015
1016
1017 /*
1018 * dev_sgi_ust_init():
1019 */
1020 void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1021 {
1022 struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1023 if (d == NULL) {
1024 fprintf(stderr, "out of memory\n");
1025 exit(1);
1026 }
1027 memset(d, 0, sizeof(struct sgi_ust_data));
1028
1029 memory_device_register(mem, "sgi_ust", baseaddr,
1030 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1031 MEM_DEFAULT, NULL);
1032 }
1033
1034
1035 /****************************************************************************/
1036
1037
1038 /*
1039 * SGI "mte". This device seems to be an accelerator for copying/clearing
1040 * memory. Used by (at least) the SGI O2 PROM.
1041 *
1042 * Actually, it seems to be used for graphics output as well. (?)
1043 * The O2's PROM uses it to output graphics.
1044 */
1045 /* #define debug fatal */
1046 /* #define MTE_DEBUG */
1047 #define ZERO_CHUNK_LEN 4096
1048
1049 struct sgi_mte_data {
1050 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1051 };
1052
1053 /*
1054 * dev_sgi_mte_access():
1055 */
1056 int dev_sgi_mte_access(struct cpu *cpu, struct memory *mem,
1057 uint64_t relative_addr, unsigned char *data, size_t len,
1058 int writeflag, void *extra)
1059 {
1060 struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1061 uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1062 unsigned char zerobuf[ZERO_CHUNK_LEN];
1063 uint64_t idata = 0, odata = 0;
1064 int regnr;
1065
1066 idata = memory_readmax64(cpu, data, len);
1067 regnr = relative_addr / sizeof(uint32_t);
1068
1069 /*
1070 * Treat all registers as read/write, by default. Sometimes these
1071 * are accessed as 32-bit words, sometimes as 64-bit words.
1072 */
1073 if (len != 4) {
1074 if (writeflag == MEM_WRITE) {
1075 d->reg[regnr] = idata >> 32;
1076 d->reg[regnr+1] = idata;
1077 } else
1078 odata = ((uint64_t)d->reg[regnr] << 32) +
1079 d->reg[regnr+1];
1080 }
1081
1082 if (writeflag == MEM_WRITE)
1083 d->reg[regnr] = idata;
1084 else
1085 odata = d->reg[regnr];
1086
1087 #ifdef MTE_DEBUG
1088 if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1089 relative_addr < 0x3000)
1090 fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1091 (long long)idata);
1092 #endif
1093
1094 /*
1095 * I've not found any docs about this 'mte' device at all, so this is
1096 * just a guess. The mte seems to be used for copying and zeroing
1097 * chunks of memory.
1098 *
1099 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1100 * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1101 * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1102 * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1103 * write to 0x3800, data=0x0000000000000011 ] <-- operation
1104 * (0x11 = zerofill)
1105 *
1106 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1107 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1108 * write to 0x1710, data=0x80001ea480001ea5
1109 * ...
1110 * write to 0x1770, data=0x80001e9c80001e9d
1111 * write to 0x1778, data=0x80001e9e80001e9f
1112 */
1113 switch (relative_addr) {
1114
1115 /* No warnings for these: */
1116 case 0x3030:
1117 case 0x3038:
1118 break;
1119
1120 /* Unknown, but no warning: */
1121 case 0x4000:
1122 case 0x3018:
1123 case 0x3008:
1124 case 0x1700:
1125 case 0x1708:
1126 case 0x1710:
1127 case 0x1718:
1128 case 0x1720:
1129 case 0x1728:
1130 case 0x1730:
1131 case 0x1738:
1132 case 0x1740:
1133 case 0x1748:
1134 case 0x1750:
1135 case 0x1758:
1136 case 0x1760:
1137 case 0x1768:
1138 case 0x1770:
1139 case 0x1778:
1140 break;
1141
1142 /* Graphics stuff? No warning: */
1143 case 0x2018:
1144 case 0x2060:
1145 case 0x2070:
1146 case 0x2074:
1147 case 0x20c0:
1148 case 0x20c4:
1149 case 0x20d0:
1150 case 0x21b0:
1151 case 0x21b8:
1152 break;
1153
1154 /* Perform graphics operation: */
1155 case 0x21f8:
1156 {
1157 uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1158 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1159 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1160 >> 16) & 0xfff;
1161 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1162 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1163 >> 16) & 0xfff;
1164 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1165 int y;
1166
1167 op >>= 24;
1168
1169 switch (op) {
1170 case 1: /* Unknown. Used after drawing bitmaps? */
1171 break;
1172 case 3: /* Fill: */
1173 if (x2 < x1) {
1174 int tmp = x1; x1 = x2; x2 = tmp;
1175 }
1176 if (y2 < y1) {
1177 int tmp = y1; y1 = y2; y2 = tmp;
1178 }
1179 for (y=y1; y<=y2; y++) {
1180 unsigned char buf[1280];
1181 int length = x2-x1+1;
1182 int addr = (x1 + y*1280);
1183 if (length < 1)
1184 length = 1;
1185 memset(buf, color, length);
1186 if (x1 < 1280 && y < 1024)
1187 cpu->memory_rw(cpu, cpu->mem,
1188 0x38000000 + addr, buf,
1189 length, MEM_WRITE,
1190 NO_EXCEPTIONS | PHYSICAL);
1191 }
1192 break;
1193
1194 default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1195 "%i,%i\n\n", op, color, x1,y1, x2,y2);
1196 }
1197 }
1198 break;
1199
1200 case 0x29f0:
1201 /* Pixel output: */
1202 {
1203 uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1204 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1205 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1206 >> 16) & 0xfff;
1207 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1208 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1209 >> 16) & 0xfff;
1210 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1211 int x,y;
1212 if (x2 < x1) {
1213 int tmp = x1; x1 = x2; x2 = tmp;
1214 }
1215 if (y2 < y1) {
1216 int tmp = y1; y1 = y2; y2 = tmp;
1217 }
1218 if (x2-x1 <= 15)
1219 data <<= 16;
1220 x=x1; y=y1;
1221 while (x <= x2 && y <= y2) {
1222 unsigned char buf = color;
1223 int addr = x + y*1280;
1224 int bit_set = data & 0x80000000UL;
1225 data <<= 1;
1226 if (x < 1280 && y < 1024 && bit_set)
1227 cpu->memory_rw(cpu, cpu->mem,
1228 0x38000000 + addr, &buf,1,MEM_WRITE,
1229 NO_EXCEPTIONS | PHYSICAL);
1230 x++;
1231 if (x > x2) {
1232 x = x1;
1233 y++;
1234 }
1235 }
1236 }
1237 break;
1238
1239
1240 /* Operations: */
1241 case 0x3800:
1242 if (writeflag == MEM_WRITE) {
1243 switch (idata) {
1244 case 0x11: /* zerofill */
1245 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1246 last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1247 zerobuflen = last_addr - first_addr + 1;
1248 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1249 " last = 0x%016llx, length = 0x%llx ]\n",
1250 (long long)first_addr, (long long)
1251 last_addr, (long long)zerobuflen);
1252
1253 /* TODO: is there a better way to
1254 implement this? */
1255 memset(zerobuf, 0, sizeof(zerobuf));
1256 fill_addr = first_addr;
1257 while (zerobuflen != 0) {
1258 if (zerobuflen > sizeof(zerobuf))
1259 fill_len = sizeof(zerobuf);
1260 else
1261 fill_len = zerobuflen;
1262 cpu->memory_rw(cpu, mem, fill_addr,
1263 zerobuf, fill_len, MEM_WRITE,
1264 NO_EXCEPTIONS | PHYSICAL);
1265 fill_addr += fill_len;
1266 zerobuflen -= sizeof(zerobuf);
1267 }
1268
1269 break;
1270 default:
1271 fatal("[ sgi_mte: UNKNOWN operation "
1272 "0x%x ]\n", idata);
1273 }
1274 }
1275 break;
1276 default:
1277 if (writeflag == MEM_WRITE)
1278 debug("[ sgi_mte: unimplemented write to "
1279 "address 0x%llx, data=0x%016llx ]\n",
1280 (long long)relative_addr, (long long)idata);
1281 else
1282 debug("[ sgi_mte: unimplemented read from address"
1283 " 0x%llx ]\n", (long long)relative_addr);
1284 }
1285
1286 if (writeflag == MEM_READ)
1287 memory_writemax64(cpu, data, len, odata);
1288
1289 return 1;
1290 }
1291
1292
1293 /*
1294 * dev_sgi_mte_init():
1295 */
1296 void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1297 {
1298 struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1299 if (d == NULL) {
1300 fprintf(stderr, "out of memory\n");
1301 exit(1);
1302 }
1303 memset(d, 0, sizeof(struct sgi_mte_data));
1304
1305 memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1306 dev_sgi_mte_access, (void *)d, MEM_DEFAULT, NULL);
1307 }
1308

  ViewVC Help
Powered by ViewVC 1.1.26