/[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 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 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 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 dpavlin 10 * $Id: dev_sgi_ip32.c,v 1.27 2005/06/26 11:43:48 debug Exp $
29 dpavlin 4 *
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 dpavlin 10 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
158     (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
159 dpavlin 4 /*
160     * Force interrupt re-assertion:
161     *
162     * NOTE: Ugly hack. Hopefully CRMERR is never used.
163     */
164     #if 0
165 dpavlin 10 /*
166 dpavlin 4 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
167     TODO.
168 dpavlin 10 */
169 dpavlin 4 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 dpavlin 10 #if 0
200 dpavlin 4 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 dpavlin 10 #endif
208 dpavlin 4 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 dpavlin 10 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 dpavlin 4 switch (relative_addr) {
275     #if 0
276 dpavlin 10 case 0x10: /* Current interrupt assertions */
277     case 0x14:
278 dpavlin 4 /* don't dump debug info for these */
279 dpavlin 10 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 dpavlin 4 break;
287 dpavlin 10 case 0x18: /* Interrupt mask */
288     case 0x1c:
289     /* don't dump debug info for these */
290     break;
291 dpavlin 4 #endif
292     default:
293 dpavlin 10 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 dpavlin 4 } 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 dpavlin 10 #if 0
540 dpavlin 4 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 dpavlin 10 size_t nlen = 55;
933 dpavlin 4 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 dpavlin 10 name2 = malloc(nlen);
946 dpavlin 4 if (name2 == NULL) {
947     fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
948     exit(1);
949     }
950 dpavlin 10 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
951 dpavlin 4 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