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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26