/[gxemul]/upstream/0.3.1/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 /upstream/0.3.1/devices/dev_sgi_ip32.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 29687 byte(s)
0.3.1
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