/[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 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 29687 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.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.24 2005/03/18 23:20:52 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 == 0x1c) {
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 1
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 #endif
205 /* don't dump debug info for these */
206 break;
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 switch (relative_addr) {
270 #if 0
271 case 0x14: /* Current interrupt assertions */
272 case 0x18: /* ??? */
273 case 0x1c: /* Interrupt mask */
274 /* don't dump debug info for these */
275 break;
276 #endif
277 default:
278 if (writeflag==MEM_READ) {
279 debug("[ mace: read from 0x%x, len=%i ]\n",
280 (int)relative_addr, len);
281 } else {
282 debug("[ mace: write to 0x%x:", (int)relative_addr);
283 for (i=0; i<len; i++)
284 debug(" %02x", data[i]);
285 debug(" (len=%i) ]\n", len);
286 }
287 }
288
289 return 1;
290 }
291
292
293 /*
294 * dev_mace_init():
295 */
296 struct mace_data *dev_mace_init(struct memory *mem, uint64_t baseaddr,
297 int irqnr)
298 {
299 struct mace_data *d;
300
301 d = malloc(sizeof(struct mace_data));
302 if (d == NULL) {
303 fprintf(stderr, "out of memory\n");
304 exit(1);
305 }
306 memset(d, 0, sizeof(struct mace_data));
307 d->irqnr = irqnr;
308
309 memory_device_register(mem, "mace", baseaddr, DEV_MACE_LENGTH,
310 dev_mace_access, d, MEM_DEFAULT, NULL);
311
312 return d;
313 }
314
315
316 /****************************************************************************/
317
318
319 /*
320 * dev_macepci_access():
321 */
322 int dev_macepci_access(struct cpu *cpu, struct memory *mem,
323 uint64_t relative_addr, unsigned char *data, size_t len,
324 int writeflag, void *extra)
325 {
326 struct macepci_data *d = (struct macepci_data *) extra;
327 uint64_t idata = 0, odata=0;
328 int regnr, res = 1;
329
330 idata = memory_readmax64(cpu, data, len);
331 regnr = relative_addr / sizeof(uint32_t);
332
333 /* Read from/write to the macepci: */
334 switch (relative_addr) {
335 case 0x00: /* Error address */
336 if (writeflag == MEM_WRITE) {
337 } else {
338 odata = 0;
339 }
340 break;
341 case 0x04: /* Error flags */
342 if (writeflag == MEM_WRITE) {
343 } else {
344 odata = 0x06;
345 }
346 break;
347 case 0x0c: /* Revision number */
348 if (writeflag == MEM_WRITE) {
349 } else {
350 odata = 0x01;
351 }
352 break;
353 case 0xcf8: /* PCI ADDR */
354 case 0xcfc: /* PCI DATA */
355 if (writeflag == MEM_WRITE) {
356 res = bus_pci_access(cpu, mem, relative_addr,
357 &idata, writeflag, d->pci_data);
358 } else {
359 res = bus_pci_access(cpu, mem, relative_addr,
360 &odata, writeflag, d->pci_data);
361 /* odata = 0; */
362 }
363 break;
364 default:
365 if (writeflag == MEM_WRITE) {
366 debug("[ macepci: unimplemented write to address "
367 "0x%x, data=0x%02x ]\n",
368 (int)relative_addr, (int)idata);
369 } else {
370 debug("[ macepci: unimplemented read from address "
371 "0x%x ]\n", (int)relative_addr);
372 }
373 }
374
375 if (writeflag == MEM_READ)
376 memory_writemax64(cpu, data, len, odata);
377
378 return res;
379 }
380
381
382 /*
383 * dev_macepci_init():
384 */
385 struct pci_data *dev_macepci_init(struct memory *mem, uint64_t baseaddr,
386 int pciirq)
387 {
388 struct macepci_data *d = malloc(sizeof(struct macepci_data));
389 if (d == NULL) {
390 fprintf(stderr, "out of memory\n");
391 exit(1);
392 }
393 memset(d, 0, sizeof(struct macepci_data));
394
395 d->pci_data = bus_pci_init(pciirq);
396
397 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
398 dev_macepci_access, (void *)d, MEM_DEFAULT, NULL);
399
400 return d->pci_data;
401 }
402
403
404 /****************************************************************************/
405
406
407 /*
408 * SGI "mec" ethernet. Used in SGI-IP32.
409 *
410 * Study http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c
411 * and/or NetBSD. TODO:
412 *
413 * x) tx and rx interrupts/ring/slot stuff
414 */
415
416 #define MEC_TICK_SHIFT 14
417
418 #define MAX_TX_PACKET_LEN 1700
419 #define N_RX_ADDRESSES 16
420
421 struct sgi_mec_data {
422 uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
423
424 int irq_nr;
425 unsigned char macaddr[6];
426
427 unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
428 int cur_tx_packet_len;
429
430 unsigned char *cur_rx_packet;
431 int cur_rx_packet_len;
432
433 uint64_t rx_addr[N_RX_ADDRESSES];
434 int cur_rx_addr_index_write;
435 int cur_rx_addr_index;
436 };
437
438
439 /*
440 * mec_reset():
441 */
442 static void mec_reset(struct sgi_mec_data *d)
443 {
444 if (d->cur_rx_packet != NULL)
445 free(d->cur_rx_packet);
446
447 memset(d->reg, 0, sizeof(d->reg));
448 }
449
450
451 /*
452 * mec_control_write():
453 */
454 static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d,
455 uint64_t x)
456 {
457 if (x & MEC_MAC_CORE_RESET) {
458 debug("[ sgi_mec: CORE RESET ]\n");
459 mec_reset(d);
460 }
461 }
462
463
464 /*
465 * mec_try_rx():
466 */
467 static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d)
468 {
469 uint64_t base;
470 unsigned char data[8];
471 int i, res, retval = 0;
472
473 base = d->rx_addr[d->cur_rx_addr_index];
474 if (base & 0xfff)
475 fatal("[ mec_try_rx(): WARNING! lowest bits of base are "
476 "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff));
477 base &= 0xfffff000ULL;
478 if (base == 0)
479 goto skip;
480
481 /* printf("rx base = 0x%016llx\n", (long long)base); */
482
483 /* Read an rx descriptor from memory: */
484 res = cpu->memory_rw(cpu, cpu->mem, base,
485 &data[0], sizeof(data), MEM_READ, PHYSICAL);
486 if (!res)
487 return 0;
488
489 #if 0
490 printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index);
491 for (i=0; i<sizeof(data); i++) {
492 if ((i & 3) == 0)
493 printf(" ");
494 printf("%02x", data[i]);
495 }
496 printf(" }\n");
497 #endif
498
499 /* Is this descriptor already in use? */
500 if (data[0] & 0x80) {
501 /* printf("INTERRUPT for base = 0x%x\n", (int)base); */
502 goto skip_and_advance;
503 }
504
505 if (d->cur_rx_packet == NULL &&
506 net_ethernet_rx_avail(cpu->machine->emul->net, d))
507 net_ethernet_rx(cpu->machine->emul->net, d,
508 &d->cur_rx_packet, &d->cur_rx_packet_len);
509
510 if (d->cur_rx_packet == NULL)
511 goto skip;
512
513 /* Copy the packet data: */
514 /* printf("RX: "); */
515 for (i=0; i<d->cur_rx_packet_len; i++) {
516 res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2,
517 d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL);
518 /* printf(" %02x", d->cur_rx_packet[i]); */
519 }
520 /* printf("\n"); */
521
522 #if 1
523 printf("RX: %i bytes, index %i, base = 0x%x\n",
524 d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base);
525 #endif
526
527 /* 4 bytes of CRC at the end. Hm. TODO */
528 d->cur_rx_packet_len += 4;
529
530 memset(data, 0, sizeof(data));
531 data[6] = (d->cur_rx_packet_len >> 8) & 255;
532 data[7] = d->cur_rx_packet_len & 255;
533 /* TODO: lots of bits :-) */
534 data[4] = 0x04; /* match MAC */
535 data[0] = 0x80; /* 0x80 = received. */
536 res = cpu->memory_rw(cpu, cpu->mem, base,
537 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
538
539 /* Free the packet from memory: */
540 free(d->cur_rx_packet);
541 d->cur_rx_packet = NULL;
542
543 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD;
544 skip_and_advance:
545 d->cur_rx_addr_index ++;
546 d->cur_rx_addr_index %= N_RX_ADDRESSES;
547 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS;
548 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= (d->cur_rx_addr_index & 0x1f) << 8;
549 retval = 1;
550
551 skip:
552 return retval;
553 }
554
555
556 /*
557 * mec_try_tx():
558 */
559 static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
560 {
561 uint64_t base, addr, dma_base;
562 int tx_ring_ptr, ringread, ringwrite, res, i, j;
563 unsigned char data[32];
564 int len, start_offset, dma_ptr_nr, dma_len;
565
566 base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
567 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
568
569 if (base == 0)
570 return 0;
571
572 /* printf("base = 0x%016llx\n", base); */
573
574 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
575 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
576 ringread >>= 16;
577 /* All done? Then abort. */
578 if (ringread == ringwrite)
579 return 0;
580
581 tx_ring_ptr &= MEC_TX_RING_READ_PTR;
582 tx_ring_ptr >>= 16;
583
584 /* Each tx descriptor (+ buffer) is 128 bytes: */
585 addr = base + tx_ring_ptr*128;
586 res = cpu->memory_rw(cpu, cpu->mem, addr,
587 &data[0], sizeof(data), MEM_READ, PHYSICAL);
588 if (!res)
589 return 0;
590
591 /* Is this packet transmitted already? */
592 if (data[0] & 0x80) {
593 fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
594 " transmitted? ]\n", tx_ring_ptr);
595 goto advance_tx;
596 }
597
598 len = data[6] * 256 + data[7];
599 start_offset = data[5] & 0x7f;
600
601 /* Is this packet empty? Then don't transmit. */
602 if (len == 0)
603 return 0;
604
605 /* Hm. Is len one too little? TODO */
606 len ++;
607
608 #if 0
609 printf("{ mec: txdesc %i: ", tx_ring_ptr);
610 for (i=0; i<sizeof(data); i++) {
611 if ((i & 3) == 0)
612 printf(" ");
613 printf("%02x", data[i]);
614 }
615 printf(" }\n");
616 #endif
617 dma_ptr_nr = 0;
618
619 j = 0;
620 d->cur_tx_packet_len = len;
621
622 for (i=start_offset; i<start_offset+len; i++) {
623 unsigned char ch;
624
625 if ((i & 0x7f) == 0x00)
626 break;
627
628 res = cpu->memory_rw(cpu, cpu->mem, addr + i,
629 &ch, sizeof(ch), MEM_READ, PHYSICAL);
630 /* printf(" %02x", ch); */
631
632 d->cur_tx_packet[j++] = ch;
633 if (j >= MAX_TX_PACKET_LEN) {
634 fatal("[ mec_try_tx: packet too large? ]\n");
635 break;
636 }
637 }
638 /* printf("\n"); */
639
640 if (j < len) {
641 /* Continue with DMA: */
642 for (;;) {
643 dma_ptr_nr ++;
644 if (dma_ptr_nr >= 4)
645 break;
646 if (!(data[4] & (0x01 << dma_ptr_nr)))
647 break;
648 dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
649 + (data[dma_ptr_nr * 8 + 5] << 16)
650 + (data[dma_ptr_nr * 8 + 6] << 8)
651 + (data[dma_ptr_nr * 8 + 7]);
652 dma_base &= 0xfffffff8ULL;
653 dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
654 + (data[dma_ptr_nr * 8 + 3]) + 1;
655
656 /* printf("dma_base = %08x, dma_len = %i\n",
657 (int)dma_base, dma_len); */
658
659 while (dma_len > 0) {
660 unsigned char ch;
661 res = cpu->memory_rw(cpu, cpu->mem, dma_base,
662 &ch, sizeof(ch), MEM_READ, PHYSICAL);
663 /* printf(" %02x", ch); */
664
665 d->cur_tx_packet[j++] = ch;
666 if (j >= MAX_TX_PACKET_LEN) {
667 fatal("[ mec_try_tx: packet too large?"
668 " ]\n");
669 break;
670 }
671 dma_base ++;
672 dma_len --;
673 }
674 }
675 }
676
677 if (j < len)
678 fatal("[ mec_try_tx: not enough data? ]\n");
679
680 net_ethernet_tx(cpu->machine->emul->net, d,
681 d->cur_tx_packet, d->cur_tx_packet_len);
682
683 /* see openbsd's if_mec.c for details */
684 if (data[4] & 0x01) {
685 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
686 MEC_INT_TX_PACKET_SENT;
687 }
688 memset(data, 0, 6); /* last 2 bytes are len */
689 data[0] = 0x80;
690 data[5] = 0x80;
691
692 res = cpu->memory_rw(cpu, cpu->mem, addr,
693 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
694
695 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
696 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
697
698 advance_tx:
699 /* Advance the ring Read ptr. */
700 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
701 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
702 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
703
704 ringread = (ringread >> 16) + 1;
705 ringread &= 63;
706 ringread <<= 16;
707
708 d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
709 (ringwrite & MEC_TX_RING_WRITE_PTR) |
710 (ringread & MEC_TX_RING_READ_PTR);
711
712 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
713 ~MEC_INT_TX_RING_BUFFER_ALIAS;
714 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
715 (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
716 MEC_INT_TX_RING_BUFFER_ALIAS);
717
718 return 1;
719 }
720
721
722 /*
723 * dev_sgi_mec_tick():
724 */
725 void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
726 {
727 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
728 int n = 0;
729
730 while (mec_try_tx(cpu, d))
731 ;
732
733 while (mec_try_rx(cpu, d) && n < 16)
734 n++;
735
736 /* Interrupts: (TODO: only when enabled) */
737 if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
738 #if 0
739 printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
740 sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
741 fflush(stdout);
742 #endif
743 cpu_interrupt(cpu, d->irq_nr);
744 } else
745 cpu_interrupt_ack(cpu, d->irq_nr);
746 }
747
748
749 /*
750 * dev_sgi_mec_access():
751 */
752 int dev_sgi_mec_access(struct cpu *cpu, struct memory *mem,
753 uint64_t relative_addr, unsigned char *data, size_t len,
754 int writeflag, void *extra)
755 {
756 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
757 uint64_t idata = 0, odata = 0;
758 int regnr;
759
760 idata = memory_readmax64(cpu, data, len);
761 regnr = relative_addr / sizeof(uint64_t);
762
763 /* Treat most registers as read/write, by default. */
764 if (writeflag == MEM_WRITE) {
765 switch (relative_addr) {
766 case MEC_INT_STATUS: /* 0x08 */
767 /* Clear bits on write: (This is just a guess) */
768 d->reg[regnr] = (d->reg[regnr] & ~0xff)
769 | ((d->reg[regnr] & ~idata) & 0xff);
770 break;
771 case MEC_TX_RING_PTR: /* 0x30 */
772 idata &= MEC_TX_RING_WRITE_PTR;
773 d->reg[regnr] = (d->reg[regnr] &
774 ~MEC_TX_RING_WRITE_PTR) | idata;
775 /* TODO */
776 break;
777 default:
778 d->reg[regnr] = idata;
779 }
780 } else
781 odata = d->reg[regnr];
782
783 switch (relative_addr) {
784 case MEC_MAC_CONTROL: /* 0x00 */
785 if (writeflag)
786 mec_control_write(cpu, d, idata);
787 else {
788 /* Fake "revision 1": */
789 odata &= ~MEC_MAC_REVISION;
790 odata |= 1 << MEC_MAC_REVISION_SHIFT;
791 }
792 break;
793 case MEC_INT_STATUS: /* 0x08 */
794 if (writeflag)
795 debug("[ sgi_mec: write to MEC_INT_STATUS: "
796 "0x%016llx ]\n", (long long)idata);
797 break;
798 case MEC_DMA_CONTROL: /* 0x10 */
799 if (writeflag) {
800 debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
801 "0x%016llx ]\n", (long long)idata);
802 if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
803 /* This should apparently stop the
804 TX Empty interrupt. */
805 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
806 ~MEC_INT_TX_EMPTY;
807 }
808 }
809 break;
810 case MEC_TX_ALIAS: /* 0x20 */
811 if (writeflag) {
812 debug("[ sgi_mec: write to MEC_TX_ALIAS: "
813 "0x%016llx ]\n", (long long)idata);
814 } else {
815 debug("[ sgi_mec: read from MEC_TX_ALIAS: "
816 "0x%016llx ]\n", (long long)idata);
817 odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
818 }
819 break;
820 case MEC_RX_ALIAS: /* 0x28 */
821 if (writeflag)
822 debug("[ sgi_mec: write to MEC_RX_ALIAS: "
823 "0x%016llx ]\n", (long long)idata);
824 break;
825 case MEC_TX_RING_PTR: /* 0x30 */
826 if (writeflag)
827 debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
828 "0x%016llx ]\n", (long long)idata);
829 break;
830 case MEC_PHY_DATA: /* 0x64 */
831 if (writeflag)
832 fatal("[ sgi_mec: write to MEC_PHY_DATA: "
833 "0x%016llx ]\n", (long long)idata);
834 else
835 odata = 0; /* ? */
836 break;
837 case MEC_PHY_ADDRESS: /* 0x6c */
838 if (writeflag)
839 debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
840 "0x%016llx ]\n", (long long)idata);
841 break;
842 case MEC_PHY_READ_INITIATE: /* 0x70 */
843 if (writeflag)
844 debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
845 "0x%016llx ]\n", (long long)idata);
846 break;
847 case 0x74:
848 if (writeflag)
849 debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
850 (long long)idata);
851 else
852 debug("[ sgi_mec: read from 0x74 ]\n");
853 break;
854 case MEC_STATION: /* 0xa0 */
855 if (writeflag)
856 debug("[ sgi_mec: setting the MAC address to "
857 "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
858 (idata >> 40) & 255, (idata >> 32) & 255,
859 (idata >> 24) & 255, (idata >> 16) & 255,
860 (idata >> 8) & 255, (idata >> 0) & 255);
861 break;
862 case MEC_STATION_ALT: /* 0xa8 */
863 if (writeflag)
864 debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
865 " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
866 (idata >> 40) & 255, (idata >> 32) & 255,
867 (idata >> 24) & 255, (idata >> 16) & 255,
868 (idata >> 8) & 255, (idata >> 0) & 255);
869 break;
870 case MEC_MULTICAST: /* 0xb0 */
871 if (writeflag)
872 debug("[ sgi_mec: write to MEC_MULTICAST: "
873 "0x%016llx ]\n", (long long)idata);
874 break;
875 case MEC_TX_RING_BASE: /* 0xb8 */
876 if (writeflag)
877 debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
878 "0x%016llx ]\n", (long long)idata);
879 break;
880 case MEC_MCL_RX_FIFO: /* 0x100 */
881 if (writeflag) {
882 debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
883 "%016llx ]\n", (long long)idata);
884 d->rx_addr[d->cur_rx_addr_index_write] = idata;
885 d->cur_rx_addr_index_write ++;
886 d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
887 }
888 break;
889 default:
890 if (writeflag == MEM_WRITE)
891 fatal("[ sgi_mec: unimplemented write to address"
892 " 0x%llx, data=0x%016llx ]\n",
893 (long long)relative_addr, (long long)idata);
894 else
895 fatal("[ sgi_mec: unimplemented read from address"
896 " 0x%llx ]\n", (long long)relative_addr);
897 }
898
899 if (writeflag == MEM_READ)
900 memory_writemax64(cpu, data, len, odata);
901
902 dev_sgi_mec_tick(cpu, extra);
903
904 return 1;
905 }
906
907
908 /*
909 * dev_sgi_mec_init():
910 */
911 void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
912 uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
913 {
914 char *name2;
915 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
916
917 if (d == NULL) {
918 fprintf(stderr, "out of memory\n");
919 exit(1);
920 }
921 memset(d, 0, sizeof(struct sgi_mec_data));
922 d->irq_nr = irq_nr;
923 memcpy(d->macaddr, macaddr, 6);
924
925 mec_reset(d);
926
927 name2 = malloc(50);
928 if (name2 == NULL) {
929 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
930 exit(1);
931 }
932 sprintf(name2, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
933 d->macaddr[0], d->macaddr[1], d->macaddr[2],
934 d->macaddr[3], d->macaddr[4], d->macaddr[5]);
935
936 memory_device_register(mem, name2, baseaddr,
937 DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
938 MEM_DEFAULT, NULL);
939
940 machine_add_tickfunction(machine, dev_sgi_mec_tick, d, MEC_TICK_SHIFT);
941
942 net_add_nic(machine->emul->net, d, macaddr);
943 }
944
945
946 /****************************************************************************/
947
948
949 struct sgi_ust_data {
950 uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
951 };
952
953
954 /*
955 * dev_sgi_ust_access():
956 */
957 int dev_sgi_ust_access(struct cpu *cpu, struct memory *mem,
958 uint64_t relative_addr, unsigned char *data, size_t len,
959 int writeflag, void *extra)
960 {
961 struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
962 uint64_t idata = 0, odata = 0;
963 int regnr;
964
965 idata = memory_readmax64(cpu, data, len);
966 regnr = relative_addr / sizeof(uint64_t);
967
968 /* Treat all registers as read/write, by default. */
969 if (writeflag == MEM_WRITE)
970 d->reg[regnr] = idata;
971 else
972 odata = d->reg[regnr];
973
974 switch (relative_addr) {
975 case 0:
976 d->reg[regnr] += 0x2710;
977 break;
978 default:
979 if (writeflag == MEM_WRITE)
980 debug("[ sgi_ust: unimplemented write to address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata);
981 else
982 debug("[ sgi_ust: unimplemented read from address 0x%llx ]\n", (long long)relative_addr);
983 }
984
985 if (writeflag == MEM_READ)
986 memory_writemax64(cpu, data, len, odata);
987
988 return 1;
989 }
990
991
992 /*
993 * dev_sgi_ust_init():
994 */
995 void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
996 {
997 struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
998 if (d == NULL) {
999 fprintf(stderr, "out of memory\n");
1000 exit(1);
1001 }
1002 memset(d, 0, sizeof(struct sgi_ust_data));
1003
1004 memory_device_register(mem, "sgi_ust", baseaddr,
1005 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d, MEM_DEFAULT, NULL);
1006 }
1007
1008
1009 /****************************************************************************/
1010
1011
1012 /*
1013 * SGI "mte". This device seems to be an accelerator for copying/clearing
1014 * memory. Used in SGI-IP32.
1015 */
1016
1017 #define ZERO_CHUNK_LEN 4096
1018
1019 struct sgi_mte_data {
1020 uint64_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint64_t)];
1021 };
1022
1023 /*
1024 * dev_sgi_mte_access():
1025 */
1026 int dev_sgi_mte_access(struct cpu *cpu, struct memory *mem,
1027 uint64_t relative_addr, unsigned char *data, size_t len,
1028 int writeflag, void *extra)
1029 {
1030 struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1031 uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1032 unsigned char zerobuf[ZERO_CHUNK_LEN];
1033 uint64_t idata = 0, odata = 0;
1034 int regnr;
1035
1036 idata = memory_readmax64(cpu, data, len);
1037 regnr = relative_addr / sizeof(uint64_t);
1038
1039 /* Treat all registers as read/write, by default. */
1040 if (writeflag == MEM_WRITE)
1041 d->reg[regnr] = idata;
1042 else
1043 odata = d->reg[regnr];
1044
1045 /*
1046 * I've not found any docs about this 'mte' device at all, so this is just
1047 * a guess. The mte seems to be used for copying and zeroing chunks of
1048 * memory.
1049 *
1050 * [ sgi_mte: unimplemented write to address 0x3030, data=0x00000000003da000 ] <-- first address
1051 * [ sgi_mte: unimplemented write to address 0x3038, data=0x00000000003f9fff ] <-- last address
1052 * [ sgi_mte: unimplemented write to address 0x3018, data=0x0000000000000000 ] <-- what to fill?
1053 * [ sgi_mte: unimplemented write to address 0x3008, data=0x00000000ffffffff ] <-- ?
1054 * [ sgi_mte: unimplemented write to address 0x3800, data=0x0000000000000011 ] <-- operation (0x11 = zerofill)
1055 *
1056 * [ sgi_mte: unimplemented write to address 0x1700, data=0x80001ea080001ea1 ] <-- also containing the address to fill (?)
1057 * [ sgi_mte: unimplemented write to address 0x1708, data=0x80001ea280001ea3 ]
1058 * [ sgi_mte: unimplemented write to address 0x1710, data=0x80001ea480001ea5 ]
1059 * ...
1060 * [ sgi_mte: unimplemented write to address 0x1770, data=0x80001e9c80001e9d ]
1061 * [ sgi_mte: unimplemented write to address 0x1778, data=0x80001e9e80001e9f ]
1062 */
1063 switch (relative_addr) {
1064
1065 /* No warnings for these: */
1066 case 0x3030:
1067 case 0x3038:
1068 break;
1069
1070 /* Unknown, but no warning: */
1071 case 0x4000:
1072 case 0x3018:
1073 case 0x3008:
1074 case 0x1700:
1075 case 0x1708:
1076 case 0x1710:
1077 case 0x1718:
1078 case 0x1720:
1079 case 0x1728:
1080 case 0x1730:
1081 case 0x1738:
1082 case 0x1740:
1083 case 0x1748:
1084 case 0x1750:
1085 case 0x1758:
1086 case 0x1760:
1087 case 0x1768:
1088 case 0x1770:
1089 case 0x1778:
1090 break;
1091
1092 /* Operations: */
1093 case 0x3800:
1094 if (writeflag == MEM_WRITE) {
1095 switch (idata) {
1096 case 0x11: /* zerofill */
1097 first_addr = d->reg[0x3030 / sizeof(uint64_t)];
1098 last_addr = d->reg[0x3038 / sizeof(uint64_t)];
1099 zerobuflen = last_addr - first_addr + 1;
1100 debug("[ sgi_mte: zerofill: first = 0x%016llx, last = 0x%016llx, length = 0x%llx ]\n",
1101 (long long)first_addr, (long long)last_addr, (long long)zerobuflen);
1102
1103 /* TODO: is there a better way to implement this? */
1104 memset(zerobuf, 0, sizeof(zerobuf));
1105 fill_addr = first_addr;
1106 while (zerobuflen != 0) {
1107 if (zerobuflen > sizeof(zerobuf))
1108 fill_len = sizeof(zerobuf);
1109 else
1110 fill_len = zerobuflen;
1111 cpu->memory_rw(cpu, mem, fill_addr,
1112 zerobuf, fill_len, MEM_WRITE,
1113 NO_EXCEPTIONS | PHYSICAL);
1114 fill_addr += fill_len;
1115 zerobuflen -= sizeof(zerobuf);
1116 }
1117
1118 break;
1119 default:
1120 fatal("[ sgi_mte: UNKNOWN operation 0x%x ]\n", idata);
1121 }
1122 }
1123 break;
1124 default:
1125 if (writeflag == MEM_WRITE)
1126 debug("[ sgi_mte: unimplemented write to address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata);
1127 else
1128 debug("[ sgi_mte: unimplemented read from address 0x%llx ]\n", (long long)relative_addr);
1129 }
1130
1131 if (writeflag == MEM_READ)
1132 memory_writemax64(cpu, data, len, odata);
1133
1134 return 1;
1135 }
1136
1137
1138 /*
1139 * dev_sgi_mte_init():
1140 */
1141 void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1142 {
1143 struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1144 if (d == NULL) {
1145 fprintf(stderr, "out of memory\n");
1146 exit(1);
1147 }
1148 memset(d, 0, sizeof(struct sgi_mte_data));
1149
1150 memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1151 dev_sgi_mte_access, (void *)d, MEM_DEFAULT, NULL);
1152 }
1153

  ViewVC Help
Powered by ViewVC 1.1.26