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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations)
Mon Oct 8 16:20:48 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 32564 byte(s)
0.4.2
1 /*
2 * Copyright (C) 2003-2006 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.45 2006/03/04 12:38:48 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 DEVICE_ACCESS(crime)
110 {
111 struct crime_data *d = extra;
112 uint64_t idata = 0;
113 size_t i;
114
115 if (writeflag == MEM_WRITE)
116 idata = memory_readmax64(cpu, data, len);
117
118 /*
119 * Set crime version/revision:
120 *
121 * This might not be the most elegant or correct solution, but it
122 * seems that the IP32 PROM likes 0x11 for machines without graphics,
123 * and 0xa1 for machines with graphics.
124 *
125 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
126 * that's something one has to live with. (TODO?)
127 */
128 d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
129 d->reg[7] = d->use_fb? 0xa1 : 0x11;
130
131 /*
132 * Amount of memory. Bit 8 of bank control set ==> 128MB instead
133 * of 32MB per bank (?)
134 *
135 * When the bank control registers contain the same value as the
136 * previous one, that bank is not valid. (?)
137 */
138 d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
139 d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
140 d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
141 d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
142
143 if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
144 if (writeflag == MEM_READ)
145 memcpy(data, &d->reg[relative_addr], len);
146 return 1;
147 }
148
149 if (writeflag == MEM_WRITE)
150 memcpy(&d->reg[relative_addr], data, len);
151 else
152 memcpy(data, &d->reg[relative_addr], len);
153
154 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
155 (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
156 /*
157 * Force interrupt re-assertion:
158 *
159 * NOTE: Ugly hack. Hopefully CRMERR is never used.
160 */
161 #if 0
162 /*
163 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
164 TODO.
165 */
166 cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
167 #endif
168 }
169
170 switch (relative_addr) {
171 case CRIME_CONTROL: /* 0x008 */
172 /* TODO: 64-bit write to CRIME_CONTROL, but some things
173 (such as NetBSD 1.6.2) write to 0x00c! */
174 if (writeflag == MEM_WRITE) {
175 /*
176 * 0x200 = watchdog timer (according to NetBSD)
177 * 0x800 = "reboot" used by the IP32 PROM
178 */
179 if (idata & 0x200) {
180 idata &= ~0x200;
181 }
182 if (idata & 0x800) {
183 int j;
184
185 /* This is used by the IP32 PROM's
186 "reboot" command: */
187 for (j=0; j<cpu->machine->ncpus; j++)
188 cpu->machine->cpus[j]->running = 0;
189 cpu->machine->
190 exit_without_entering_debugger = 1;
191 idata &= ~0x800;
192 }
193 if (idata != 0)
194 fatal("[ CRIME_CONTROL: unimplemented "
195 "control 0x%016llx ]\n", (long long)idata);
196 }
197 break;
198 #if 0
199 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
200 case 0x14:
201 case CRIME_INTMASK: /* 0x018, Current interrupt mask */
202 case 0x1c:
203 case 0x34:
204 /* don't dump debug info for these */
205 break;
206 #endif
207 default:
208 if (writeflag==MEM_READ) {
209 debug("[ crime: read from 0x%x, len=%i:",
210 (int)relative_addr, len);
211 for (i=0; i<len; i++)
212 debug(" %02x", data[i]);
213 debug(" ]\n");
214 } else {
215 debug("[ crime: write to 0x%x:", (int)relative_addr);
216 for (i=0; i<len; i++)
217 debug(" %02x", data[i]);
218 debug(" (len=%i) ]\n", len);
219 }
220 }
221
222 return 1;
223 }
224
225
226 /*
227 * dev_crime_init():
228 */
229 struct crime_data *dev_crime_init(struct machine *machine, struct memory *mem,
230 uint64_t baseaddr, int irq_nr, int use_fb)
231 {
232 struct crime_data *d;
233
234 d = malloc(sizeof(struct crime_data));
235 if (d == NULL) {
236 fprintf(stderr, "out of memory\n");
237 exit(1);
238 }
239 memset(d, 0, sizeof(struct crime_data));
240 d->irq_nr = irq_nr;
241 d->use_fb = use_fb;
242
243 memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
244 dev_crime_access, d, DM_DEFAULT, NULL);
245 machine_add_tickfunction(machine, dev_crime_tick, d,
246 CRIME_TICKSHIFT, 0.0);
247
248 return d;
249 }
250
251
252 /****************************************************************************/
253
254
255 /*
256 * dev_mace_access():
257 */
258 DEVICE_ACCESS(mace)
259 {
260 size_t i;
261 struct mace_data *d = extra;
262
263 if (writeflag == MEM_WRITE)
264 memcpy(&d->reg[relative_addr], data, len);
265 else
266 memcpy(data, &d->reg[relative_addr], len);
267
268 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
269 (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f))
270 cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
271
272 switch (relative_addr) {
273 #if 0
274 case 0x10: /* Current interrupt assertions */
275 case 0x14:
276 /* don't dump debug info for these */
277 if (writeflag == MEM_WRITE) {
278 fatal("[ NOTE/TODO: WRITE to mace intr: "
279 "reladdr=0x%x data=", (int)relative_addr);
280 for (i=0; i<len; i++)
281 fatal(" %02x", data[i]);
282 fatal(" (len=%i) ]\n", len);
283 }
284 break;
285 case 0x18: /* Interrupt mask */
286 case 0x1c:
287 /* don't dump debug info for these */
288 break;
289 #endif
290 default:
291 if (writeflag == MEM_READ) {
292 debug("[ mace: read from 0x%x:", (int)relative_addr);
293 for (i=0; i<len; i++)
294 debug(" %02x", data[i]);
295 debug(" (len=%i) ]\n", len);
296 } else {
297 debug("[ mace: write to 0x%x:", (int)relative_addr);
298 for (i=0; i<len; i++)
299 debug(" %02x", data[i]);
300 debug(" (len=%i) ]\n", len);
301 }
302 }
303
304 return 1;
305 }
306
307
308 /*
309 * dev_mace_init():
310 */
311 struct mace_data *dev_mace_init(struct memory *mem, uint64_t baseaddr,
312 int irqnr)
313 {
314 struct mace_data *d;
315
316 d = malloc(sizeof(struct mace_data));
317 if (d == NULL) {
318 fprintf(stderr, "out of memory\n");
319 exit(1);
320 }
321 memset(d, 0, sizeof(struct mace_data));
322 d->irqnr = irqnr;
323
324 memory_device_register(mem, "mace", baseaddr, DEV_MACE_LENGTH,
325 dev_mace_access, d, DM_DEFAULT, NULL);
326
327 return d;
328 }
329
330
331 /****************************************************************************/
332
333
334 /*
335 * dev_macepci_access():
336 */
337 DEVICE_ACCESS(macepci)
338 {
339 struct macepci_data *d = (struct macepci_data *) extra;
340 uint64_t idata = 0, odata=0;
341 int regnr, res = 1, bus, dev, func, pcireg;
342
343 if (writeflag == MEM_WRITE)
344 idata = memory_readmax64(cpu, data, len);
345
346 regnr = relative_addr / sizeof(uint32_t);
347
348 /* Read from/write to the macepci: */
349 switch (relative_addr) {
350
351 case 0x00: /* Error address */
352 if (writeflag == MEM_WRITE) {
353 } else {
354 odata = 0;
355 }
356 break;
357
358 case 0x04: /* Error flags */
359 if (writeflag == MEM_WRITE) {
360 } else {
361 odata = 0x06;
362 }
363 break;
364
365 case 0x0c: /* Revision number */
366 if (writeflag == MEM_WRITE) {
367 } else {
368 odata = 0x01;
369 }
370 break;
371
372 case 0xcf8: /* PCI ADDR */
373 bus_pci_decompose_1(idata, &bus, &dev, &func, &pcireg);
374 bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, pcireg);
375 break;
376
377 case 0xcfc: /* PCI DATA */
378 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
379 &odata : &idata, len, writeflag);
380 break;
381
382 default:
383 if (writeflag == MEM_WRITE) {
384 debug("[ macepci: unimplemented write to address "
385 "0x%x, data=0x%02x ]\n",
386 (int)relative_addr, (int)idata);
387 } else {
388 debug("[ macepci: unimplemented read from address "
389 "0x%x ]\n", (int)relative_addr);
390 }
391 }
392
393 if (writeflag == MEM_READ)
394 memory_writemax64(cpu, data, len, odata);
395
396 return res;
397 }
398
399
400 /*
401 * dev_macepci_init():
402 */
403 struct pci_data *dev_macepci_init(struct machine *machine,
404 struct memory *mem, uint64_t baseaddr, int pciirq)
405 {
406 struct macepci_data *d = malloc(sizeof(struct macepci_data));
407 if (d == NULL) {
408 fprintf(stderr, "out of memory\n");
409 exit(1);
410 }
411 memset(d, 0, sizeof(struct macepci_data));
412
413 d->pci_data = bus_pci_init(machine, pciirq, 0,0, 0,0,0, 0,0,0);
414
415 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
416 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
417
418 return d->pci_data;
419 }
420
421
422 /****************************************************************************/
423
424
425 /*
426 * SGI "mec" ethernet. Used in SGI-IP32.
427 *
428 * Study http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c
429 * and/or NetBSD. TODO:
430 *
431 * x) tx and rx interrupts/ring/slot stuff
432 */
433
434 #define MEC_TICK_SHIFT 14
435
436 #define MAX_TX_PACKET_LEN 1700
437 #define N_RX_ADDRESSES 16
438
439 struct sgi_mec_data {
440 uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
441
442 int irq_nr;
443 unsigned char macaddr[6];
444
445 unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
446 int cur_tx_packet_len;
447
448 unsigned char *cur_rx_packet;
449 int cur_rx_packet_len;
450
451 uint64_t rx_addr[N_RX_ADDRESSES];
452 int cur_rx_addr_index_write;
453 int cur_rx_addr_index;
454 };
455
456
457 /*
458 * mec_reset():
459 */
460 static void mec_reset(struct sgi_mec_data *d)
461 {
462 if (d->cur_rx_packet != NULL)
463 free(d->cur_rx_packet);
464
465 memset(d->reg, 0, sizeof(d->reg));
466 }
467
468
469 /*
470 * mec_control_write():
471 */
472 static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d,
473 uint64_t x)
474 {
475 if (x & MEC_MAC_CORE_RESET) {
476 debug("[ sgi_mec: CORE RESET ]\n");
477 mec_reset(d);
478 }
479 }
480
481
482 /*
483 * mec_try_rx():
484 */
485 static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d)
486 {
487 uint64_t base;
488 unsigned char data[8];
489 int i, res, retval = 0;
490
491 base = d->rx_addr[d->cur_rx_addr_index];
492 if (base & 0xfff)
493 fatal("[ mec_try_rx(): WARNING! lowest bits of base are "
494 "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff));
495 base &= 0xfffff000ULL;
496 if (base == 0)
497 goto skip;
498
499 /* printf("rx base = 0x%016llx\n", (long long)base); */
500
501 /* Read an rx descriptor from memory: */
502 res = cpu->memory_rw(cpu, cpu->mem, base,
503 &data[0], sizeof(data), MEM_READ, PHYSICAL);
504 if (!res)
505 return 0;
506
507 #if 0
508 printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index);
509 for (i=0; i<sizeof(data); i++) {
510 if ((i & 3) == 0)
511 printf(" ");
512 printf("%02x", data[i]);
513 }
514 printf(" }\n");
515 #endif
516
517 /* Is this descriptor already in use? */
518 if (data[0] & 0x80) {
519 /* printf("INTERRUPT for base = 0x%x\n", (int)base); */
520 goto skip_and_advance;
521 }
522
523 if (d->cur_rx_packet == NULL &&
524 net_ethernet_rx_avail(cpu->machine->emul->net, d))
525 net_ethernet_rx(cpu->machine->emul->net, d,
526 &d->cur_rx_packet, &d->cur_rx_packet_len);
527
528 if (d->cur_rx_packet == NULL)
529 goto skip;
530
531 /* Copy the packet data: */
532 /* printf("RX: "); */
533 for (i=0; i<d->cur_rx_packet_len; i++) {
534 res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2,
535 d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL);
536 /* printf(" %02x", d->cur_rx_packet[i]); */
537 }
538 /* printf("\n"); */
539
540 #if 0
541 printf("RX: %i bytes, index %i, base = 0x%x\n",
542 d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base);
543 #endif
544
545 /* 4 bytes of CRC at the end. Hm. TODO */
546 d->cur_rx_packet_len += 4;
547
548 memset(data, 0, sizeof(data));
549 data[6] = (d->cur_rx_packet_len >> 8) & 255;
550 data[7] = d->cur_rx_packet_len & 255;
551 /* TODO: lots of bits :-) */
552 data[4] = 0x04; /* match MAC */
553 data[0] = 0x80; /* 0x80 = received. */
554 res = cpu->memory_rw(cpu, cpu->mem, base,
555 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
556
557 /* Free the packet from memory: */
558 free(d->cur_rx_packet);
559 d->cur_rx_packet = NULL;
560
561 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD;
562 skip_and_advance:
563 d->cur_rx_addr_index ++;
564 d->cur_rx_addr_index %= N_RX_ADDRESSES;
565 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS;
566 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
567 (d->cur_rx_addr_index & 0x1f) << 8;
568 retval = 1;
569
570 skip:
571 return retval;
572 }
573
574
575 /*
576 * mec_try_tx():
577 */
578 static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
579 {
580 uint64_t base, addr, dma_base;
581 int tx_ring_ptr, ringread, ringwrite, res, i, j;
582 unsigned char data[32];
583 int len, start_offset, dma_ptr_nr, dma_len;
584
585 base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
586 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
587
588 if (base == 0)
589 return 0;
590
591 /* printf("base = 0x%016llx\n", base); */
592
593 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
594 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
595 ringread >>= 16;
596 /* All done? Then abort. */
597 if (ringread == ringwrite)
598 return 0;
599
600 tx_ring_ptr &= MEC_TX_RING_READ_PTR;
601 tx_ring_ptr >>= 16;
602
603 /* Each tx descriptor (+ buffer) is 128 bytes: */
604 addr = base + tx_ring_ptr*128;
605 res = cpu->memory_rw(cpu, cpu->mem, addr,
606 &data[0], sizeof(data), MEM_READ, PHYSICAL);
607 if (!res)
608 return 0;
609
610 /* Is this packet transmitted already? */
611 if (data[0] & 0x80) {
612 fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
613 " transmitted? ]\n", tx_ring_ptr);
614 goto advance_tx;
615 }
616
617 len = data[6] * 256 + data[7];
618 start_offset = data[5] & 0x7f;
619
620 /* Is this packet empty? Then don't transmit. */
621 if (len == 0)
622 return 0;
623
624 /* Hm. Is len one too little? TODO */
625 len ++;
626
627 #if 0
628 printf("{ mec: txdesc %i: ", tx_ring_ptr);
629 for (i=0; i<sizeof(data); i++) {
630 if ((i & 3) == 0)
631 printf(" ");
632 printf("%02x", data[i]);
633 }
634 printf(" }\n");
635 #endif
636 dma_ptr_nr = 0;
637
638 j = 0;
639 d->cur_tx_packet_len = len;
640
641 for (i=start_offset; i<start_offset+len; i++) {
642 unsigned char ch;
643
644 if ((i & 0x7f) == 0x00)
645 break;
646
647 res = cpu->memory_rw(cpu, cpu->mem, addr + i,
648 &ch, sizeof(ch), MEM_READ, PHYSICAL);
649 /* printf(" %02x", ch); */
650
651 d->cur_tx_packet[j++] = ch;
652 if (j >= MAX_TX_PACKET_LEN) {
653 fatal("[ mec_try_tx: packet too large? ]\n");
654 break;
655 }
656 }
657 /* printf("\n"); */
658
659 if (j < len) {
660 /* Continue with DMA: */
661 for (;;) {
662 dma_ptr_nr ++;
663 if (dma_ptr_nr >= 4)
664 break;
665 if (!(data[4] & (0x01 << dma_ptr_nr)))
666 break;
667 dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
668 + (data[dma_ptr_nr * 8 + 5] << 16)
669 + (data[dma_ptr_nr * 8 + 6] << 8)
670 + (data[dma_ptr_nr * 8 + 7]);
671 dma_base &= 0xfffffff8ULL;
672 dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
673 + (data[dma_ptr_nr * 8 + 3]) + 1;
674
675 /* printf("dma_base = %08x, dma_len = %i\n",
676 (int)dma_base, dma_len); */
677
678 while (dma_len > 0) {
679 unsigned char ch;
680 res = cpu->memory_rw(cpu, cpu->mem, dma_base,
681 &ch, sizeof(ch), MEM_READ, PHYSICAL);
682 /* printf(" %02x", ch); */
683
684 d->cur_tx_packet[j++] = ch;
685 if (j >= MAX_TX_PACKET_LEN) {
686 fatal("[ mec_try_tx: packet too large?"
687 " ]\n");
688 break;
689 }
690 dma_base ++;
691 dma_len --;
692 }
693 }
694 }
695
696 if (j < len)
697 fatal("[ mec_try_tx: not enough data? ]\n");
698
699 net_ethernet_tx(cpu->machine->emul->net, d,
700 d->cur_tx_packet, d->cur_tx_packet_len);
701
702 /* see openbsd's if_mec.c for details */
703 if (data[4] & 0x01) {
704 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
705 MEC_INT_TX_PACKET_SENT;
706 }
707 memset(data, 0, 6); /* last 2 bytes are len */
708 data[0] = 0x80;
709 data[5] = 0x80;
710
711 res = cpu->memory_rw(cpu, cpu->mem, addr,
712 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
713
714 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
715 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
716
717 advance_tx:
718 /* Advance the ring Read ptr. */
719 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
720 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
721 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
722
723 ringread = (ringread >> 16) + 1;
724 ringread &= 63;
725 ringread <<= 16;
726
727 d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
728 (ringwrite & MEC_TX_RING_WRITE_PTR) |
729 (ringread & MEC_TX_RING_READ_PTR);
730
731 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
732 ~MEC_INT_TX_RING_BUFFER_ALIAS;
733 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
734 (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
735 MEC_INT_TX_RING_BUFFER_ALIAS);
736
737 return 1;
738 }
739
740
741 /*
742 * dev_sgi_mec_tick():
743 */
744 void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
745 {
746 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
747 int n = 0;
748
749 while (mec_try_tx(cpu, d))
750 ;
751
752 while (mec_try_rx(cpu, d) && n < 16)
753 n++;
754
755 /* Interrupts: (TODO: only when enabled) */
756 if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
757 #if 0
758 printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
759 sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
760 fflush(stdout);
761 #endif
762 cpu_interrupt(cpu, d->irq_nr);
763 } else
764 cpu_interrupt_ack(cpu, d->irq_nr);
765 }
766
767
768 /*
769 * dev_sgi_mec_access():
770 */
771 DEVICE_ACCESS(sgi_mec)
772 {
773 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
774 uint64_t idata = 0, odata = 0;
775 int regnr;
776
777 if (writeflag == MEM_WRITE)
778 idata = memory_readmax64(cpu, data, len);
779
780 regnr = relative_addr / sizeof(uint64_t);
781
782 /* Treat most registers as read/write, by default. */
783 if (writeflag == MEM_WRITE) {
784 switch (relative_addr) {
785 case MEC_INT_STATUS: /* 0x08 */
786 /* Clear bits on write: (This is just a guess) */
787 d->reg[regnr] = (d->reg[regnr] & ~0xff)
788 | ((d->reg[regnr] & ~idata) & 0xff);
789 break;
790 case MEC_TX_RING_PTR: /* 0x30 */
791 idata &= MEC_TX_RING_WRITE_PTR;
792 d->reg[regnr] = (d->reg[regnr] &
793 ~MEC_TX_RING_WRITE_PTR) | idata;
794 /* TODO */
795 break;
796 default:
797 d->reg[regnr] = idata;
798 }
799 } else
800 odata = d->reg[regnr];
801
802 switch (relative_addr) {
803 case MEC_MAC_CONTROL: /* 0x00 */
804 if (writeflag)
805 mec_control_write(cpu, d, idata);
806 else {
807 /* Fake "revision 1": */
808 odata &= ~MEC_MAC_REVISION;
809 odata |= 1 << MEC_MAC_REVISION_SHIFT;
810 }
811 break;
812 case MEC_INT_STATUS: /* 0x08 */
813 if (writeflag)
814 debug("[ sgi_mec: write to MEC_INT_STATUS: "
815 "0x%016llx ]\n", (long long)idata);
816 break;
817 case MEC_DMA_CONTROL: /* 0x10 */
818 if (writeflag) {
819 debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
820 "0x%016llx ]\n", (long long)idata);
821 if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
822 /* This should apparently stop the
823 TX Empty interrupt. */
824 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
825 ~MEC_INT_TX_EMPTY;
826 }
827 }
828 break;
829 case MEC_TX_ALIAS: /* 0x20 */
830 if (writeflag) {
831 debug("[ sgi_mec: write to MEC_TX_ALIAS: "
832 "0x%016llx ]\n", (long long)idata);
833 } else {
834 debug("[ sgi_mec: read from MEC_TX_ALIAS: "
835 "0x%016llx ]\n", (long long)idata);
836 odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
837 }
838 break;
839 case MEC_RX_ALIAS: /* 0x28 */
840 if (writeflag)
841 debug("[ sgi_mec: write to MEC_RX_ALIAS: "
842 "0x%016llx ]\n", (long long)idata);
843 break;
844 case MEC_TX_RING_PTR: /* 0x30 */
845 if (writeflag)
846 debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
847 "0x%016llx ]\n", (long long)idata);
848 break;
849 case MEC_PHY_DATA: /* 0x64 */
850 if (writeflag)
851 fatal("[ sgi_mec: write to MEC_PHY_DATA: "
852 "0x%016llx ]\n", (long long)idata);
853 else
854 odata = 0; /* ? */
855 break;
856 case MEC_PHY_ADDRESS: /* 0x6c */
857 if (writeflag)
858 debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
859 "0x%016llx ]\n", (long long)idata);
860 break;
861 case MEC_PHY_READ_INITIATE: /* 0x70 */
862 if (writeflag)
863 debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
864 "0x%016llx ]\n", (long long)idata);
865 break;
866 case 0x74:
867 if (writeflag)
868 debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
869 (long long)idata);
870 else
871 debug("[ sgi_mec: read from 0x74 ]\n");
872 break;
873 case MEC_STATION: /* 0xa0 */
874 if (writeflag)
875 debug("[ sgi_mec: setting the MAC address to "
876 "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
877 (idata >> 40) & 255, (idata >> 32) & 255,
878 (idata >> 24) & 255, (idata >> 16) & 255,
879 (idata >> 8) & 255, (idata >> 0) & 255);
880 break;
881 case MEC_STATION_ALT: /* 0xa8 */
882 if (writeflag)
883 debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
884 " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
885 (idata >> 40) & 255, (idata >> 32) & 255,
886 (idata >> 24) & 255, (idata >> 16) & 255,
887 (idata >> 8) & 255, (idata >> 0) & 255);
888 break;
889 case MEC_MULTICAST: /* 0xb0 */
890 if (writeflag)
891 debug("[ sgi_mec: write to MEC_MULTICAST: "
892 "0x%016llx ]\n", (long long)idata);
893 break;
894 case MEC_TX_RING_BASE: /* 0xb8 */
895 if (writeflag)
896 debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
897 "0x%016llx ]\n", (long long)idata);
898 break;
899 case MEC_MCL_RX_FIFO: /* 0x100 */
900 if (writeflag) {
901 debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
902 "%016llx ]\n", (long long)idata);
903 d->rx_addr[d->cur_rx_addr_index_write] = idata;
904 d->cur_rx_addr_index_write ++;
905 d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
906 }
907 break;
908 default:
909 if (writeflag == MEM_WRITE)
910 fatal("[ sgi_mec: unimplemented write to address"
911 " 0x%llx, data=0x%016llx ]\n",
912 (long long)relative_addr, (long long)idata);
913 else
914 fatal("[ sgi_mec: unimplemented read from address"
915 " 0x%llx ]\n", (long long)relative_addr);
916 }
917
918 if (writeflag == MEM_READ)
919 memory_writemax64(cpu, data, len, odata);
920
921 dev_sgi_mec_tick(cpu, extra);
922
923 return 1;
924 }
925
926
927 /*
928 * dev_sgi_mec_init():
929 */
930 void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
931 uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
932 {
933 char *name2;
934 size_t nlen = 55;
935 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
936
937 if (d == NULL) {
938 fprintf(stderr, "out of memory\n");
939 exit(1);
940 }
941 memset(d, 0, sizeof(struct sgi_mec_data));
942 d->irq_nr = irq_nr;
943 memcpy(d->macaddr, macaddr, 6);
944
945 mec_reset(d);
946
947 name2 = malloc(nlen);
948 if (name2 == NULL) {
949 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
950 exit(1);
951 }
952 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
953 d->macaddr[0], d->macaddr[1], d->macaddr[2],
954 d->macaddr[3], d->macaddr[4], d->macaddr[5]);
955
956 memory_device_register(mem, name2, baseaddr,
957 DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
958 DM_DEFAULT, NULL);
959
960 machine_add_tickfunction(machine, dev_sgi_mec_tick, d,
961 MEC_TICK_SHIFT, 0.0);
962
963 net_add_nic(machine->emul->net, d, macaddr);
964 }
965
966
967 /****************************************************************************/
968
969
970 struct sgi_ust_data {
971 uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
972 };
973
974
975 /*
976 * dev_sgi_ust_access():
977 */
978 DEVICE_ACCESS(sgi_ust)
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 DM_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 DEVICE_ACCESS(sgi_mte)
1054 {
1055 struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1056 uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1057 unsigned char zerobuf[ZERO_CHUNK_LEN];
1058 uint64_t idata = 0, odata = 0;
1059 int regnr;
1060
1061 idata = memory_readmax64(cpu, data, len);
1062 regnr = relative_addr / sizeof(uint32_t);
1063
1064 /*
1065 * Treat all registers as read/write, by default. Sometimes these
1066 * are accessed as 32-bit words, sometimes as 64-bit words.
1067 */
1068 if (len != 4) {
1069 if (writeflag == MEM_WRITE) {
1070 d->reg[regnr] = idata >> 32;
1071 d->reg[regnr+1] = idata;
1072 } else
1073 odata = ((uint64_t)d->reg[regnr] << 32) +
1074 d->reg[regnr+1];
1075 }
1076
1077 if (writeflag == MEM_WRITE)
1078 d->reg[regnr] = idata;
1079 else
1080 odata = d->reg[regnr];
1081
1082 #ifdef MTE_DEBUG
1083 if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1084 relative_addr < 0x3000)
1085 fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1086 (long long)idata);
1087 #endif
1088
1089 /*
1090 * I've not found any docs about this 'mte' device at all, so this is
1091 * just a guess. The mte seems to be used for copying and zeroing
1092 * chunks of memory.
1093 *
1094 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1095 * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1096 * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1097 * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1098 * write to 0x3800, data=0x0000000000000011 ] <-- operation
1099 * (0x11 = zerofill)
1100 *
1101 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1102 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1103 * write to 0x1710, data=0x80001ea480001ea5
1104 * ...
1105 * write to 0x1770, data=0x80001e9c80001e9d
1106 * write to 0x1778, data=0x80001e9e80001e9f
1107 */
1108 switch (relative_addr) {
1109
1110 /* No warnings for these: */
1111 case 0x3030:
1112 case 0x3038:
1113 break;
1114
1115 /* Unknown, but no warning: */
1116 case 0x4000:
1117 case 0x3018:
1118 case 0x3008:
1119 case 0x1700:
1120 case 0x1708:
1121 case 0x1710:
1122 case 0x1718:
1123 case 0x1720:
1124 case 0x1728:
1125 case 0x1730:
1126 case 0x1738:
1127 case 0x1740:
1128 case 0x1748:
1129 case 0x1750:
1130 case 0x1758:
1131 case 0x1760:
1132 case 0x1768:
1133 case 0x1770:
1134 case 0x1778:
1135 break;
1136
1137 /* Graphics stuff? No warning: */
1138 case 0x2018:
1139 case 0x2060:
1140 case 0x2070:
1141 case 0x2074:
1142 case 0x20c0:
1143 case 0x20c4:
1144 case 0x20d0:
1145 case 0x21b0:
1146 case 0x21b8:
1147 break;
1148
1149 /* Perform graphics operation: */
1150 case 0x21f8:
1151 {
1152 uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1153 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1154 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1155 >> 16) & 0xfff;
1156 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1157 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1158 >> 16) & 0xfff;
1159 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1160 uint32_t y;
1161
1162 op >>= 24;
1163
1164 switch (op) {
1165 case 1: /* Unknown. Used after drawing bitmaps? */
1166 break;
1167 case 3: /* Fill: */
1168 if (x2 < x1) {
1169 int tmp = x1; x1 = x2; x2 = tmp;
1170 }
1171 if (y2 < y1) {
1172 int tmp = y1; y1 = y2; y2 = tmp;
1173 }
1174 for (y=y1; y<=y2; y++) {
1175 unsigned char buf[1280];
1176 int length = x2-x1+1;
1177 int addr = (x1 + y*1280);
1178 if (length < 1)
1179 length = 1;
1180 memset(buf, color, length);
1181 if (x1 < 1280 && y < 1024)
1182 cpu->memory_rw(cpu, cpu->mem,
1183 0x38000000 + addr, buf,
1184 length, MEM_WRITE,
1185 NO_EXCEPTIONS | PHYSICAL);
1186 }
1187 break;
1188
1189 default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1190 "%i,%i\n\n", op, color, x1,y1, x2,y2);
1191 }
1192 }
1193 break;
1194
1195 case 0x29f0:
1196 /* Pixel output: */
1197 {
1198 uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1199 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1200 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1201 >> 16) & 0xfff;
1202 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1203 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1204 >> 16) & 0xfff;
1205 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1206 size_t x, y;
1207
1208 if (x2 < x1) {
1209 int tmp = x1; x1 = x2; x2 = tmp;
1210 }
1211 if (y2 < y1) {
1212 int tmp = y1; y1 = y2; y2 = tmp;
1213 }
1214 if (x2-x1 <= 15)
1215 data <<= 16;
1216
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, DM_DEFAULT, NULL);
1304 }
1305

  ViewVC Help
Powered by ViewVC 1.1.26