/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

==============  RELEASE 0.3.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26