/[gxemul]/trunk/src/devices/dev_sgi_ip32.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_sgi_ip32.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 30300 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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.27 2005/06/26 11:43: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 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)] |= (d->cur_rx_addr_index & 0x1f) << 8;
566 retval = 1;
567
568 skip:
569 return retval;
570 }
571
572
573 /*
574 * mec_try_tx():
575 */
576 static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
577 {
578 uint64_t base, addr, dma_base;
579 int tx_ring_ptr, ringread, ringwrite, res, i, j;
580 unsigned char data[32];
581 int len, start_offset, dma_ptr_nr, dma_len;
582
583 base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
584 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
585
586 if (base == 0)
587 return 0;
588
589 /* printf("base = 0x%016llx\n", base); */
590
591 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
592 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
593 ringread >>= 16;
594 /* All done? Then abort. */
595 if (ringread == ringwrite)
596 return 0;
597
598 tx_ring_ptr &= MEC_TX_RING_READ_PTR;
599 tx_ring_ptr >>= 16;
600
601 /* Each tx descriptor (+ buffer) is 128 bytes: */
602 addr = base + tx_ring_ptr*128;
603 res = cpu->memory_rw(cpu, cpu->mem, addr,
604 &data[0], sizeof(data), MEM_READ, PHYSICAL);
605 if (!res)
606 return 0;
607
608 /* Is this packet transmitted already? */
609 if (data[0] & 0x80) {
610 fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
611 " transmitted? ]\n", tx_ring_ptr);
612 goto advance_tx;
613 }
614
615 len = data[6] * 256 + data[7];
616 start_offset = data[5] & 0x7f;
617
618 /* Is this packet empty? Then don't transmit. */
619 if (len == 0)
620 return 0;
621
622 /* Hm. Is len one too little? TODO */
623 len ++;
624
625 #if 0
626 printf("{ mec: txdesc %i: ", tx_ring_ptr);
627 for (i=0; i<sizeof(data); i++) {
628 if ((i & 3) == 0)
629 printf(" ");
630 printf("%02x", data[i]);
631 }
632 printf(" }\n");
633 #endif
634 dma_ptr_nr = 0;
635
636 j = 0;
637 d->cur_tx_packet_len = len;
638
639 for (i=start_offset; i<start_offset+len; i++) {
640 unsigned char ch;
641
642 if ((i & 0x7f) == 0x00)
643 break;
644
645 res = cpu->memory_rw(cpu, cpu->mem, addr + i,
646 &ch, sizeof(ch), MEM_READ, PHYSICAL);
647 /* printf(" %02x", ch); */
648
649 d->cur_tx_packet[j++] = ch;
650 if (j >= MAX_TX_PACKET_LEN) {
651 fatal("[ mec_try_tx: packet too large? ]\n");
652 break;
653 }
654 }
655 /* printf("\n"); */
656
657 if (j < len) {
658 /* Continue with DMA: */
659 for (;;) {
660 dma_ptr_nr ++;
661 if (dma_ptr_nr >= 4)
662 break;
663 if (!(data[4] & (0x01 << dma_ptr_nr)))
664 break;
665 dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
666 + (data[dma_ptr_nr * 8 + 5] << 16)
667 + (data[dma_ptr_nr * 8 + 6] << 8)
668 + (data[dma_ptr_nr * 8 + 7]);
669 dma_base &= 0xfffffff8ULL;
670 dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
671 + (data[dma_ptr_nr * 8 + 3]) + 1;
672
673 /* printf("dma_base = %08x, dma_len = %i\n",
674 (int)dma_base, dma_len); */
675
676 while (dma_len > 0) {
677 unsigned char ch;
678 res = cpu->memory_rw(cpu, cpu->mem, dma_base,
679 &ch, sizeof(ch), MEM_READ, PHYSICAL);
680 /* printf(" %02x", ch); */
681
682 d->cur_tx_packet[j++] = ch;
683 if (j >= MAX_TX_PACKET_LEN) {
684 fatal("[ mec_try_tx: packet too large?"
685 " ]\n");
686 break;
687 }
688 dma_base ++;
689 dma_len --;
690 }
691 }
692 }
693
694 if (j < len)
695 fatal("[ mec_try_tx: not enough data? ]\n");
696
697 net_ethernet_tx(cpu->machine->emul->net, d,
698 d->cur_tx_packet, d->cur_tx_packet_len);
699
700 /* see openbsd's if_mec.c for details */
701 if (data[4] & 0x01) {
702 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
703 MEC_INT_TX_PACKET_SENT;
704 }
705 memset(data, 0, 6); /* last 2 bytes are len */
706 data[0] = 0x80;
707 data[5] = 0x80;
708
709 res = cpu->memory_rw(cpu, cpu->mem, addr,
710 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
711
712 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
713 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
714
715 advance_tx:
716 /* Advance the ring Read ptr. */
717 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
718 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
719 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
720
721 ringread = (ringread >> 16) + 1;
722 ringread &= 63;
723 ringread <<= 16;
724
725 d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
726 (ringwrite & MEC_TX_RING_WRITE_PTR) |
727 (ringread & MEC_TX_RING_READ_PTR);
728
729 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
730 ~MEC_INT_TX_RING_BUFFER_ALIAS;
731 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
732 (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
733 MEC_INT_TX_RING_BUFFER_ALIAS);
734
735 return 1;
736 }
737
738
739 /*
740 * dev_sgi_mec_tick():
741 */
742 void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
743 {
744 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
745 int n = 0;
746
747 while (mec_try_tx(cpu, d))
748 ;
749
750 while (mec_try_rx(cpu, d) && n < 16)
751 n++;
752
753 /* Interrupts: (TODO: only when enabled) */
754 if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
755 #if 0
756 printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
757 sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
758 fflush(stdout);
759 #endif
760 cpu_interrupt(cpu, d->irq_nr);
761 } else
762 cpu_interrupt_ack(cpu, d->irq_nr);
763 }
764
765
766 /*
767 * dev_sgi_mec_access():
768 */
769 int dev_sgi_mec_access(struct cpu *cpu, struct memory *mem,
770 uint64_t relative_addr, unsigned char *data, size_t len,
771 int writeflag, void *extra)
772 {
773 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
774 uint64_t idata = 0, odata = 0;
775 int regnr;
776
777 idata = memory_readmax64(cpu, data, len);
778 regnr = relative_addr / sizeof(uint64_t);
779
780 /* Treat most registers as read/write, by default. */
781 if (writeflag == MEM_WRITE) {
782 switch (relative_addr) {
783 case MEC_INT_STATUS: /* 0x08 */
784 /* Clear bits on write: (This is just a guess) */
785 d->reg[regnr] = (d->reg[regnr] & ~0xff)
786 | ((d->reg[regnr] & ~idata) & 0xff);
787 break;
788 case MEC_TX_RING_PTR: /* 0x30 */
789 idata &= MEC_TX_RING_WRITE_PTR;
790 d->reg[regnr] = (d->reg[regnr] &
791 ~MEC_TX_RING_WRITE_PTR) | idata;
792 /* TODO */
793 break;
794 default:
795 d->reg[regnr] = idata;
796 }
797 } else
798 odata = d->reg[regnr];
799
800 switch (relative_addr) {
801 case MEC_MAC_CONTROL: /* 0x00 */
802 if (writeflag)
803 mec_control_write(cpu, d, idata);
804 else {
805 /* Fake "revision 1": */
806 odata &= ~MEC_MAC_REVISION;
807 odata |= 1 << MEC_MAC_REVISION_SHIFT;
808 }
809 break;
810 case MEC_INT_STATUS: /* 0x08 */
811 if (writeflag)
812 debug("[ sgi_mec: write to MEC_INT_STATUS: "
813 "0x%016llx ]\n", (long long)idata);
814 break;
815 case MEC_DMA_CONTROL: /* 0x10 */
816 if (writeflag) {
817 debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
818 "0x%016llx ]\n", (long long)idata);
819 if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
820 /* This should apparently stop the
821 TX Empty interrupt. */
822 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
823 ~MEC_INT_TX_EMPTY;
824 }
825 }
826 break;
827 case MEC_TX_ALIAS: /* 0x20 */
828 if (writeflag) {
829 debug("[ sgi_mec: write to MEC_TX_ALIAS: "
830 "0x%016llx ]\n", (long long)idata);
831 } else {
832 debug("[ sgi_mec: read from MEC_TX_ALIAS: "
833 "0x%016llx ]\n", (long long)idata);
834 odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
835 }
836 break;
837 case MEC_RX_ALIAS: /* 0x28 */
838 if (writeflag)
839 debug("[ sgi_mec: write to MEC_RX_ALIAS: "
840 "0x%016llx ]\n", (long long)idata);
841 break;
842 case MEC_TX_RING_PTR: /* 0x30 */
843 if (writeflag)
844 debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
845 "0x%016llx ]\n", (long long)idata);
846 break;
847 case MEC_PHY_DATA: /* 0x64 */
848 if (writeflag)
849 fatal("[ sgi_mec: write to MEC_PHY_DATA: "
850 "0x%016llx ]\n", (long long)idata);
851 else
852 odata = 0; /* ? */
853 break;
854 case MEC_PHY_ADDRESS: /* 0x6c */
855 if (writeflag)
856 debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
857 "0x%016llx ]\n", (long long)idata);
858 break;
859 case MEC_PHY_READ_INITIATE: /* 0x70 */
860 if (writeflag)
861 debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
862 "0x%016llx ]\n", (long long)idata);
863 break;
864 case 0x74:
865 if (writeflag)
866 debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
867 (long long)idata);
868 else
869 debug("[ sgi_mec: read from 0x74 ]\n");
870 break;
871 case MEC_STATION: /* 0xa0 */
872 if (writeflag)
873 debug("[ sgi_mec: setting the MAC address to "
874 "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
875 (idata >> 40) & 255, (idata >> 32) & 255,
876 (idata >> 24) & 255, (idata >> 16) & 255,
877 (idata >> 8) & 255, (idata >> 0) & 255);
878 break;
879 case MEC_STATION_ALT: /* 0xa8 */
880 if (writeflag)
881 debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
882 " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
883 (idata >> 40) & 255, (idata >> 32) & 255,
884 (idata >> 24) & 255, (idata >> 16) & 255,
885 (idata >> 8) & 255, (idata >> 0) & 255);
886 break;
887 case MEC_MULTICAST: /* 0xb0 */
888 if (writeflag)
889 debug("[ sgi_mec: write to MEC_MULTICAST: "
890 "0x%016llx ]\n", (long long)idata);
891 break;
892 case MEC_TX_RING_BASE: /* 0xb8 */
893 if (writeflag)
894 debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
895 "0x%016llx ]\n", (long long)idata);
896 break;
897 case MEC_MCL_RX_FIFO: /* 0x100 */
898 if (writeflag) {
899 debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
900 "%016llx ]\n", (long long)idata);
901 d->rx_addr[d->cur_rx_addr_index_write] = idata;
902 d->cur_rx_addr_index_write ++;
903 d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
904 }
905 break;
906 default:
907 if (writeflag == MEM_WRITE)
908 fatal("[ sgi_mec: unimplemented write to address"
909 " 0x%llx, data=0x%016llx ]\n",
910 (long long)relative_addr, (long long)idata);
911 else
912 fatal("[ sgi_mec: unimplemented read from address"
913 " 0x%llx ]\n", (long long)relative_addr);
914 }
915
916 if (writeflag == MEM_READ)
917 memory_writemax64(cpu, data, len, odata);
918
919 dev_sgi_mec_tick(cpu, extra);
920
921 return 1;
922 }
923
924
925 /*
926 * dev_sgi_mec_init():
927 */
928 void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
929 uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
930 {
931 char *name2;
932 size_t nlen = 55;
933 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
934
935 if (d == NULL) {
936 fprintf(stderr, "out of memory\n");
937 exit(1);
938 }
939 memset(d, 0, sizeof(struct sgi_mec_data));
940 d->irq_nr = irq_nr;
941 memcpy(d->macaddr, macaddr, 6);
942
943 mec_reset(d);
944
945 name2 = malloc(nlen);
946 if (name2 == NULL) {
947 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
948 exit(1);
949 }
950 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
951 d->macaddr[0], d->macaddr[1], d->macaddr[2],
952 d->macaddr[3], d->macaddr[4], d->macaddr[5]);
953
954 memory_device_register(mem, name2, baseaddr,
955 DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
956 MEM_DEFAULT, NULL);
957
958 machine_add_tickfunction(machine, dev_sgi_mec_tick, d, MEC_TICK_SHIFT);
959
960 net_add_nic(machine->emul->net, d, macaddr);
961 }
962
963
964 /****************************************************************************/
965
966
967 struct sgi_ust_data {
968 uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
969 };
970
971
972 /*
973 * dev_sgi_ust_access():
974 */
975 int dev_sgi_ust_access(struct cpu *cpu, struct memory *mem,
976 uint64_t relative_addr, unsigned char *data, size_t len,
977 int writeflag, void *extra)
978 {
979 struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
980 uint64_t idata = 0, odata = 0;
981 int regnr;
982
983 idata = memory_readmax64(cpu, data, len);
984 regnr = relative_addr / sizeof(uint64_t);
985
986 /* Treat all registers as read/write, by default. */
987 if (writeflag == MEM_WRITE)
988 d->reg[regnr] = idata;
989 else
990 odata = d->reg[regnr];
991
992 switch (relative_addr) {
993 case 0:
994 d->reg[regnr] += 0x2710;
995 break;
996 default:
997 if (writeflag == MEM_WRITE)
998 debug("[ sgi_ust: unimplemented write to address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata);
999 else
1000 debug("[ sgi_ust: unimplemented read from address 0x%llx ]\n", (long long)relative_addr);
1001 }
1002
1003 if (writeflag == MEM_READ)
1004 memory_writemax64(cpu, data, len, odata);
1005
1006 return 1;
1007 }
1008
1009
1010 /*
1011 * dev_sgi_ust_init():
1012 */
1013 void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1014 {
1015 struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1016 if (d == NULL) {
1017 fprintf(stderr, "out of memory\n");
1018 exit(1);
1019 }
1020 memset(d, 0, sizeof(struct sgi_ust_data));
1021
1022 memory_device_register(mem, "sgi_ust", baseaddr,
1023 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d, MEM_DEFAULT, NULL);
1024 }
1025
1026
1027 /****************************************************************************/
1028
1029
1030 /*
1031 * SGI "mte". This device seems to be an accelerator for copying/clearing
1032 * memory. Used in SGI-IP32.
1033 */
1034
1035 #define ZERO_CHUNK_LEN 4096
1036
1037 struct sgi_mte_data {
1038 uint64_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint64_t)];
1039 };
1040
1041 /*
1042 * dev_sgi_mte_access():
1043 */
1044 int dev_sgi_mte_access(struct cpu *cpu, struct memory *mem,
1045 uint64_t relative_addr, unsigned char *data, size_t len,
1046 int writeflag, void *extra)
1047 {
1048 struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1049 uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1050 unsigned char zerobuf[ZERO_CHUNK_LEN];
1051 uint64_t idata = 0, odata = 0;
1052 int regnr;
1053
1054 idata = memory_readmax64(cpu, data, len);
1055 regnr = relative_addr / sizeof(uint64_t);
1056
1057 /* Treat all registers as read/write, by default. */
1058 if (writeflag == MEM_WRITE)
1059 d->reg[regnr] = idata;
1060 else
1061 odata = d->reg[regnr];
1062
1063 /*
1064 * I've not found any docs about this 'mte' device at all, so this is just
1065 * a guess. The mte seems to be used for copying and zeroing chunks of
1066 * memory.
1067 *
1068 * [ sgi_mte: unimplemented write to address 0x3030, data=0x00000000003da000 ] <-- first address
1069 * [ sgi_mte: unimplemented write to address 0x3038, data=0x00000000003f9fff ] <-- last address
1070 * [ sgi_mte: unimplemented write to address 0x3018, data=0x0000000000000000 ] <-- what to fill?
1071 * [ sgi_mte: unimplemented write to address 0x3008, data=0x00000000ffffffff ] <-- ?
1072 * [ sgi_mte: unimplemented write to address 0x3800, data=0x0000000000000011 ] <-- operation (0x11 = zerofill)
1073 *
1074 * [ sgi_mte: unimplemented write to address 0x1700, data=0x80001ea080001ea1 ] <-- also containing the address to fill (?)
1075 * [ sgi_mte: unimplemented write to address 0x1708, data=0x80001ea280001ea3 ]
1076 * [ sgi_mte: unimplemented write to address 0x1710, data=0x80001ea480001ea5 ]
1077 * ...
1078 * [ sgi_mte: unimplemented write to address 0x1770, data=0x80001e9c80001e9d ]
1079 * [ sgi_mte: unimplemented write to address 0x1778, data=0x80001e9e80001e9f ]
1080 */
1081 switch (relative_addr) {
1082
1083 /* No warnings for these: */
1084 case 0x3030:
1085 case 0x3038:
1086 break;
1087
1088 /* Unknown, but no warning: */
1089 case 0x4000:
1090 case 0x3018:
1091 case 0x3008:
1092 case 0x1700:
1093 case 0x1708:
1094 case 0x1710:
1095 case 0x1718:
1096 case 0x1720:
1097 case 0x1728:
1098 case 0x1730:
1099 case 0x1738:
1100 case 0x1740:
1101 case 0x1748:
1102 case 0x1750:
1103 case 0x1758:
1104 case 0x1760:
1105 case 0x1768:
1106 case 0x1770:
1107 case 0x1778:
1108 break;
1109
1110 /* Operations: */
1111 case 0x3800:
1112 if (writeflag == MEM_WRITE) {
1113 switch (idata) {
1114 case 0x11: /* zerofill */
1115 first_addr = d->reg[0x3030 / sizeof(uint64_t)];
1116 last_addr = d->reg[0x3038 / sizeof(uint64_t)];
1117 zerobuflen = last_addr - first_addr + 1;
1118 debug("[ sgi_mte: zerofill: first = 0x%016llx, last = 0x%016llx, length = 0x%llx ]\n",
1119 (long long)first_addr, (long long)last_addr, (long long)zerobuflen);
1120
1121 /* TODO: is there a better way to implement this? */
1122 memset(zerobuf, 0, sizeof(zerobuf));
1123 fill_addr = first_addr;
1124 while (zerobuflen != 0) {
1125 if (zerobuflen > sizeof(zerobuf))
1126 fill_len = sizeof(zerobuf);
1127 else
1128 fill_len = zerobuflen;
1129 cpu->memory_rw(cpu, mem, fill_addr,
1130 zerobuf, fill_len, MEM_WRITE,
1131 NO_EXCEPTIONS | PHYSICAL);
1132 fill_addr += fill_len;
1133 zerobuflen -= sizeof(zerobuf);
1134 }
1135
1136 break;
1137 default:
1138 fatal("[ sgi_mte: UNKNOWN operation 0x%x ]\n", idata);
1139 }
1140 }
1141 break;
1142 default:
1143 if (writeflag == MEM_WRITE)
1144 debug("[ sgi_mte: unimplemented write to address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata);
1145 else
1146 debug("[ sgi_mte: unimplemented read from address 0x%llx ]\n", (long long)relative_addr);
1147 }
1148
1149 if (writeflag == MEM_READ)
1150 memory_writemax64(cpu, data, len, odata);
1151
1152 return 1;
1153 }
1154
1155
1156 /*
1157 * dev_sgi_mte_init():
1158 */
1159 void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1160 {
1161 struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1162 if (d == NULL) {
1163 fprintf(stderr, "out of memory\n");
1164 exit(1);
1165 }
1166 memset(d, 0, sizeof(struct sgi_mte_data));
1167
1168 memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1169 dev_sgi_mte_access, (void *)d, MEM_DEFAULT, NULL);
1170 }
1171

  ViewVC Help
Powered by ViewVC 1.1.26