/[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 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 33199 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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 20 * $Id: dev_sgi_ip32.c,v 1.38 2005/11/21 09:17:27 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 dpavlin 18 struct crime_data *d = extra;
114     uint64_t idata = 0;
115 dpavlin 4 int i;
116    
117 dpavlin 18 if (writeflag == MEM_WRITE)
118     idata = memory_readmax64(cpu, data, len);
119 dpavlin 4
120     /*
121     * Set crime version/revision:
122     *
123 dpavlin 18 * This might not be the most elegant or correct solution, but it
124     * seems that the IP32 PROM likes 0x11 for machines without graphics,
125     * and 0xa1 for machines with graphics.
126 dpavlin 4 *
127 dpavlin 18 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
128     * that's something one has to live with. (TODO?)
129 dpavlin 4 */
130     d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
131     d->reg[7] = d->use_fb? 0xa1 : 0x11;
132    
133     /*
134     * Amount of memory. Bit 8 of bank control set ==> 128MB instead
135     * of 32MB per bank (?)
136     *
137     * When the bank control registers contain the same value as the
138     * previous one, that bank is not valid. (?)
139     */
140     d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
141     d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
142     d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
143     d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
144    
145     if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
146     if (writeflag == MEM_READ)
147     memcpy(data, &d->reg[relative_addr], len);
148     return 1;
149     }
150    
151     if (writeflag == MEM_WRITE)
152     memcpy(&d->reg[relative_addr], data, len);
153     else
154     memcpy(data, &d->reg[relative_addr], len);
155    
156 dpavlin 10 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
157     (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
158 dpavlin 4 /*
159     * Force interrupt re-assertion:
160     *
161     * NOTE: Ugly hack. Hopefully CRMERR is never used.
162     */
163     #if 0
164 dpavlin 10 /*
165 dpavlin 4 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
166     TODO.
167 dpavlin 10 */
168 dpavlin 4 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 dpavlin 10 #if 0
199 dpavlin 4 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
200     case 0x14:
201     case CRIME_INTMASK: /* 0x018, Current interrupt mask */
202     case 0x1c:
203     case 0x34:
204     /* don't dump debug info for these */
205     break;
206 dpavlin 10 #endif
207 dpavlin 4 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 dpavlin 20 dev_crime_access, d, DM_DEFAULT, NULL);
245 dpavlin 4 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 dpavlin 10 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
270     (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f))
271     cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
272    
273 dpavlin 4 switch (relative_addr) {
274     #if 0
275 dpavlin 10 case 0x10: /* Current interrupt assertions */
276     case 0x14:
277 dpavlin 4 /* don't dump debug info for these */
278 dpavlin 10 if (writeflag == MEM_WRITE) {
279     fatal("[ NOTE/TODO: WRITE to mace intr: "
280     "reladdr=0x%x data=", (int)relative_addr);
281     for (i=0; i<len; i++)
282     fatal(" %02x", data[i]);
283     fatal(" (len=%i) ]\n", len);
284     }
285 dpavlin 4 break;
286 dpavlin 10 case 0x18: /* Interrupt mask */
287     case 0x1c:
288     /* don't dump debug info for these */
289     break;
290 dpavlin 4 #endif
291     default:
292 dpavlin 10 if (writeflag == MEM_READ) {
293     debug("[ mace: read from 0x%x:", (int)relative_addr);
294     for (i=0; i<len; i++)
295     debug(" %02x", data[i]);
296     debug(" (len=%i) ]\n", len);
297 dpavlin 4 } else {
298     debug("[ mace: write to 0x%x:", (int)relative_addr);
299     for (i=0; i<len; i++)
300     debug(" %02x", data[i]);
301     debug(" (len=%i) ]\n", len);
302     }
303     }
304    
305     return 1;
306     }
307    
308    
309     /*
310     * dev_mace_init():
311     */
312     struct mace_data *dev_mace_init(struct memory *mem, uint64_t baseaddr,
313     int irqnr)
314     {
315     struct mace_data *d;
316    
317     d = malloc(sizeof(struct mace_data));
318     if (d == NULL) {
319     fprintf(stderr, "out of memory\n");
320     exit(1);
321     }
322     memset(d, 0, sizeof(struct mace_data));
323     d->irqnr = irqnr;
324    
325     memory_device_register(mem, "mace", baseaddr, DEV_MACE_LENGTH,
326 dpavlin 20 dev_mace_access, d, DM_DEFAULT, NULL);
327 dpavlin 4
328     return d;
329     }
330    
331    
332     /****************************************************************************/
333    
334    
335     /*
336     * dev_macepci_access():
337     */
338     int dev_macepci_access(struct cpu *cpu, struct memory *mem,
339     uint64_t relative_addr, unsigned char *data, size_t len,
340     int writeflag, void *extra)
341     {
342     struct macepci_data *d = (struct macepci_data *) extra;
343     uint64_t idata = 0, odata=0;
344     int regnr, res = 1;
345    
346 dpavlin 18 if (writeflag == MEM_WRITE)
347     idata = memory_readmax64(cpu, data, len);
348    
349 dpavlin 4 regnr = relative_addr / sizeof(uint32_t);
350    
351     /* Read from/write to the macepci: */
352     switch (relative_addr) {
353     case 0x00: /* Error address */
354     if (writeflag == MEM_WRITE) {
355     } else {
356     odata = 0;
357     }
358     break;
359     case 0x04: /* Error flags */
360     if (writeflag == MEM_WRITE) {
361     } else {
362     odata = 0x06;
363     }
364     break;
365     case 0x0c: /* Revision number */
366     if (writeflag == MEM_WRITE) {
367     } else {
368     odata = 0x01;
369     }
370     break;
371     case 0xcf8: /* PCI ADDR */
372     case 0xcfc: /* PCI DATA */
373     if (writeflag == MEM_WRITE) {
374     res = bus_pci_access(cpu, mem, relative_addr,
375 dpavlin 20 &idata, len, writeflag, d->pci_data);
376 dpavlin 4 } else {
377     res = bus_pci_access(cpu, mem, relative_addr,
378 dpavlin 20 &odata, len, writeflag, d->pci_data);
379 dpavlin 4 }
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 dpavlin 20 d->pci_data = bus_pci_init(pciirq, 0,0, 0,0,0, 0,0,0);
413 dpavlin 4
414     memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
415 dpavlin 20 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
416 dpavlin 4
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 dpavlin 12 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
566     (d->cur_rx_addr_index & 0x1f) << 8;
567 dpavlin 4 retval = 1;
568    
569     skip:
570     return retval;
571     }
572    
573    
574     /*
575     * mec_try_tx():
576     */
577     static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
578     {
579     uint64_t base, addr, dma_base;
580     int tx_ring_ptr, ringread, ringwrite, res, i, j;
581     unsigned char data[32];
582     int len, start_offset, dma_ptr_nr, dma_len;
583    
584     base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
585     tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
586    
587     if (base == 0)
588     return 0;
589    
590     /* printf("base = 0x%016llx\n", base); */
591    
592     ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
593     ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
594     ringread >>= 16;
595     /* All done? Then abort. */
596     if (ringread == ringwrite)
597     return 0;
598    
599     tx_ring_ptr &= MEC_TX_RING_READ_PTR;
600     tx_ring_ptr >>= 16;
601    
602     /* Each tx descriptor (+ buffer) is 128 bytes: */
603     addr = base + tx_ring_ptr*128;
604     res = cpu->memory_rw(cpu, cpu->mem, addr,
605     &data[0], sizeof(data), MEM_READ, PHYSICAL);
606     if (!res)
607     return 0;
608    
609     /* Is this packet transmitted already? */
610     if (data[0] & 0x80) {
611     fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
612     " transmitted? ]\n", tx_ring_ptr);
613     goto advance_tx;
614     }
615    
616     len = data[6] * 256 + data[7];
617     start_offset = data[5] & 0x7f;
618    
619     /* Is this packet empty? Then don't transmit. */
620     if (len == 0)
621     return 0;
622    
623     /* Hm. Is len one too little? TODO */
624     len ++;
625    
626     #if 0
627     printf("{ mec: txdesc %i: ", tx_ring_ptr);
628     for (i=0; i<sizeof(data); i++) {
629     if ((i & 3) == 0)
630     printf(" ");
631     printf("%02x", data[i]);
632     }
633     printf(" }\n");
634     #endif
635     dma_ptr_nr = 0;
636    
637     j = 0;
638     d->cur_tx_packet_len = len;
639    
640     for (i=start_offset; i<start_offset+len; i++) {
641     unsigned char ch;
642    
643     if ((i & 0x7f) == 0x00)
644     break;
645    
646     res = cpu->memory_rw(cpu, cpu->mem, addr + i,
647     &ch, sizeof(ch), MEM_READ, PHYSICAL);
648     /* printf(" %02x", ch); */
649    
650     d->cur_tx_packet[j++] = ch;
651     if (j >= MAX_TX_PACKET_LEN) {
652     fatal("[ mec_try_tx: packet too large? ]\n");
653     break;
654     }
655     }
656     /* printf("\n"); */
657    
658     if (j < len) {
659     /* Continue with DMA: */
660     for (;;) {
661     dma_ptr_nr ++;
662     if (dma_ptr_nr >= 4)
663     break;
664     if (!(data[4] & (0x01 << dma_ptr_nr)))
665     break;
666     dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
667     + (data[dma_ptr_nr * 8 + 5] << 16)
668     + (data[dma_ptr_nr * 8 + 6] << 8)
669     + (data[dma_ptr_nr * 8 + 7]);
670     dma_base &= 0xfffffff8ULL;
671     dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
672     + (data[dma_ptr_nr * 8 + 3]) + 1;
673    
674     /* printf("dma_base = %08x, dma_len = %i\n",
675     (int)dma_base, dma_len); */
676    
677     while (dma_len > 0) {
678     unsigned char ch;
679     res = cpu->memory_rw(cpu, cpu->mem, dma_base,
680     &ch, sizeof(ch), MEM_READ, PHYSICAL);
681     /* printf(" %02x", ch); */
682    
683     d->cur_tx_packet[j++] = ch;
684     if (j >= MAX_TX_PACKET_LEN) {
685     fatal("[ mec_try_tx: packet too large?"
686     " ]\n");
687     break;
688     }
689     dma_base ++;
690     dma_len --;
691     }
692     }
693     }
694    
695     if (j < len)
696     fatal("[ mec_try_tx: not enough data? ]\n");
697    
698     net_ethernet_tx(cpu->machine->emul->net, d,
699     d->cur_tx_packet, d->cur_tx_packet_len);
700    
701     /* see openbsd's if_mec.c for details */
702     if (data[4] & 0x01) {
703     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
704     MEC_INT_TX_PACKET_SENT;
705     }
706     memset(data, 0, 6); /* last 2 bytes are len */
707     data[0] = 0x80;
708     data[5] = 0x80;
709    
710     res = cpu->memory_rw(cpu, cpu->mem, addr,
711     &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
712    
713     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
714     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
715    
716     advance_tx:
717     /* Advance the ring Read ptr. */
718     tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
719     ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
720     ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
721    
722     ringread = (ringread >> 16) + 1;
723     ringread &= 63;
724     ringread <<= 16;
725    
726     d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
727     (ringwrite & MEC_TX_RING_WRITE_PTR) |
728     (ringread & MEC_TX_RING_READ_PTR);
729    
730     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
731     ~MEC_INT_TX_RING_BUFFER_ALIAS;
732     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
733     (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
734     MEC_INT_TX_RING_BUFFER_ALIAS);
735    
736     return 1;
737     }
738    
739    
740     /*
741     * dev_sgi_mec_tick():
742     */
743     void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
744     {
745     struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
746     int n = 0;
747    
748     while (mec_try_tx(cpu, d))
749     ;
750    
751     while (mec_try_rx(cpu, d) && n < 16)
752     n++;
753    
754     /* Interrupts: (TODO: only when enabled) */
755     if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
756     #if 0
757     printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
758     sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
759     fflush(stdout);
760     #endif
761     cpu_interrupt(cpu, d->irq_nr);
762     } else
763     cpu_interrupt_ack(cpu, d->irq_nr);
764     }
765    
766    
767     /*
768     * dev_sgi_mec_access():
769     */
770     int dev_sgi_mec_access(struct cpu *cpu, struct memory *mem,
771     uint64_t relative_addr, unsigned char *data, size_t len,
772     int writeflag, void *extra)
773     {
774     struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
775     uint64_t idata = 0, odata = 0;
776     int regnr;
777    
778 dpavlin 18 if (writeflag == MEM_WRITE)
779     idata = memory_readmax64(cpu, data, len);
780    
781 dpavlin 4 regnr = relative_addr / sizeof(uint64_t);
782    
783     /* Treat most registers as read/write, by default. */
784     if (writeflag == MEM_WRITE) {
785     switch (relative_addr) {
786     case MEC_INT_STATUS: /* 0x08 */
787     /* Clear bits on write: (This is just a guess) */
788     d->reg[regnr] = (d->reg[regnr] & ~0xff)
789     | ((d->reg[regnr] & ~idata) & 0xff);
790     break;
791     case MEC_TX_RING_PTR: /* 0x30 */
792     idata &= MEC_TX_RING_WRITE_PTR;
793     d->reg[regnr] = (d->reg[regnr] &
794     ~MEC_TX_RING_WRITE_PTR) | idata;
795     /* TODO */
796     break;
797     default:
798     d->reg[regnr] = idata;
799     }
800     } else
801     odata = d->reg[regnr];
802    
803     switch (relative_addr) {
804     case MEC_MAC_CONTROL: /* 0x00 */
805     if (writeflag)
806     mec_control_write(cpu, d, idata);
807     else {
808     /* Fake "revision 1": */
809     odata &= ~MEC_MAC_REVISION;
810     odata |= 1 << MEC_MAC_REVISION_SHIFT;
811     }
812     break;
813     case MEC_INT_STATUS: /* 0x08 */
814     if (writeflag)
815     debug("[ sgi_mec: write to MEC_INT_STATUS: "
816     "0x%016llx ]\n", (long long)idata);
817     break;
818     case MEC_DMA_CONTROL: /* 0x10 */
819     if (writeflag) {
820     debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
821     "0x%016llx ]\n", (long long)idata);
822     if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
823     /* This should apparently stop the
824     TX Empty interrupt. */
825     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
826     ~MEC_INT_TX_EMPTY;
827     }
828     }
829     break;
830     case MEC_TX_ALIAS: /* 0x20 */
831     if (writeflag) {
832     debug("[ sgi_mec: write to MEC_TX_ALIAS: "
833     "0x%016llx ]\n", (long long)idata);
834     } else {
835     debug("[ sgi_mec: read from MEC_TX_ALIAS: "
836     "0x%016llx ]\n", (long long)idata);
837     odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
838     }
839     break;
840     case MEC_RX_ALIAS: /* 0x28 */
841     if (writeflag)
842     debug("[ sgi_mec: write to MEC_RX_ALIAS: "
843     "0x%016llx ]\n", (long long)idata);
844     break;
845     case MEC_TX_RING_PTR: /* 0x30 */
846     if (writeflag)
847     debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
848     "0x%016llx ]\n", (long long)idata);
849     break;
850     case MEC_PHY_DATA: /* 0x64 */
851     if (writeflag)
852     fatal("[ sgi_mec: write to MEC_PHY_DATA: "
853     "0x%016llx ]\n", (long long)idata);
854     else
855     odata = 0; /* ? */
856     break;
857     case MEC_PHY_ADDRESS: /* 0x6c */
858     if (writeflag)
859     debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
860     "0x%016llx ]\n", (long long)idata);
861     break;
862     case MEC_PHY_READ_INITIATE: /* 0x70 */
863     if (writeflag)
864     debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
865     "0x%016llx ]\n", (long long)idata);
866     break;
867     case 0x74:
868     if (writeflag)
869     debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
870     (long long)idata);
871     else
872     debug("[ sgi_mec: read from 0x74 ]\n");
873     break;
874     case MEC_STATION: /* 0xa0 */
875     if (writeflag)
876     debug("[ sgi_mec: setting the MAC address to "
877     "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
878     (idata >> 40) & 255, (idata >> 32) & 255,
879     (idata >> 24) & 255, (idata >> 16) & 255,
880     (idata >> 8) & 255, (idata >> 0) & 255);
881     break;
882     case MEC_STATION_ALT: /* 0xa8 */
883     if (writeflag)
884     debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
885     " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
886     (idata >> 40) & 255, (idata >> 32) & 255,
887     (idata >> 24) & 255, (idata >> 16) & 255,
888     (idata >> 8) & 255, (idata >> 0) & 255);
889     break;
890     case MEC_MULTICAST: /* 0xb0 */
891     if (writeflag)
892     debug("[ sgi_mec: write to MEC_MULTICAST: "
893     "0x%016llx ]\n", (long long)idata);
894     break;
895     case MEC_TX_RING_BASE: /* 0xb8 */
896     if (writeflag)
897     debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
898     "0x%016llx ]\n", (long long)idata);
899     break;
900     case MEC_MCL_RX_FIFO: /* 0x100 */
901     if (writeflag) {
902     debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
903     "%016llx ]\n", (long long)idata);
904     d->rx_addr[d->cur_rx_addr_index_write] = idata;
905     d->cur_rx_addr_index_write ++;
906     d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
907     }
908     break;
909     default:
910     if (writeflag == MEM_WRITE)
911     fatal("[ sgi_mec: unimplemented write to address"
912     " 0x%llx, data=0x%016llx ]\n",
913     (long long)relative_addr, (long long)idata);
914     else
915     fatal("[ sgi_mec: unimplemented read from address"
916     " 0x%llx ]\n", (long long)relative_addr);
917     }
918    
919     if (writeflag == MEM_READ)
920     memory_writemax64(cpu, data, len, odata);
921    
922     dev_sgi_mec_tick(cpu, extra);
923    
924     return 1;
925     }
926    
927    
928     /*
929     * dev_sgi_mec_init():
930     */
931     void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
932     uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
933     {
934     char *name2;
935 dpavlin 10 size_t nlen = 55;
936 dpavlin 4 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
937    
938     if (d == NULL) {
939     fprintf(stderr, "out of memory\n");
940     exit(1);
941     }
942     memset(d, 0, sizeof(struct sgi_mec_data));
943     d->irq_nr = irq_nr;
944     memcpy(d->macaddr, macaddr, 6);
945    
946     mec_reset(d);
947    
948 dpavlin 10 name2 = malloc(nlen);
949 dpavlin 4 if (name2 == NULL) {
950     fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
951     exit(1);
952     }
953 dpavlin 10 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
954 dpavlin 4 d->macaddr[0], d->macaddr[1], d->macaddr[2],
955     d->macaddr[3], d->macaddr[4], d->macaddr[5]);
956    
957     memory_device_register(mem, name2, baseaddr,
958     DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
959 dpavlin 20 DM_DEFAULT, NULL);
960 dpavlin 4
961     machine_add_tickfunction(machine, dev_sgi_mec_tick, d, MEC_TICK_SHIFT);
962    
963     net_add_nic(machine->emul->net, d, macaddr);
964     }
965    
966    
967     /****************************************************************************/
968    
969    
970     struct sgi_ust_data {
971     uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
972     };
973    
974    
975     /*
976     * dev_sgi_ust_access():
977     */
978     int dev_sgi_ust_access(struct cpu *cpu, struct memory *mem,
979     uint64_t relative_addr, unsigned char *data, size_t len,
980     int writeflag, void *extra)
981     {
982     struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
983     uint64_t idata = 0, odata = 0;
984     int regnr;
985    
986     idata = memory_readmax64(cpu, data, len);
987     regnr = relative_addr / sizeof(uint64_t);
988    
989     /* Treat all registers as read/write, by default. */
990     if (writeflag == MEM_WRITE)
991     d->reg[regnr] = idata;
992     else
993     odata = d->reg[regnr];
994    
995     switch (relative_addr) {
996     case 0:
997     d->reg[regnr] += 0x2710;
998     break;
999     default:
1000     if (writeflag == MEM_WRITE)
1001 dpavlin 12 debug("[ sgi_ust: unimplemented write to "
1002     "address 0x%llx, data=0x%016llx ]\n",
1003     (long long)relative_addr, (long long)idata);
1004 dpavlin 4 else
1005 dpavlin 12 debug("[ sgi_ust: unimplemented read from address"
1006     " 0x%llx ]\n", (long long)relative_addr);
1007 dpavlin 4 }
1008    
1009     if (writeflag == MEM_READ)
1010     memory_writemax64(cpu, data, len, odata);
1011    
1012     return 1;
1013     }
1014    
1015    
1016     /*
1017     * dev_sgi_ust_init():
1018     */
1019     void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1020     {
1021     struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1022     if (d == NULL) {
1023     fprintf(stderr, "out of memory\n");
1024     exit(1);
1025     }
1026     memset(d, 0, sizeof(struct sgi_ust_data));
1027    
1028     memory_device_register(mem, "sgi_ust", baseaddr,
1029 dpavlin 12 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1030 dpavlin 20 DM_DEFAULT, NULL);
1031 dpavlin 4 }
1032    
1033    
1034     /****************************************************************************/
1035    
1036    
1037     /*
1038     * SGI "mte". This device seems to be an accelerator for copying/clearing
1039 dpavlin 12 * memory. Used by (at least) the SGI O2 PROM.
1040     *
1041     * Actually, it seems to be used for graphics output as well. (?)
1042 dpavlin 14 * The O2's PROM uses it to output graphics.
1043 dpavlin 4 */
1044 dpavlin 12 /* #define debug fatal */
1045 dpavlin 14 /* #define MTE_DEBUG */
1046 dpavlin 4 #define ZERO_CHUNK_LEN 4096
1047    
1048     struct sgi_mte_data {
1049 dpavlin 14 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1050 dpavlin 4 };
1051    
1052     /*
1053     * dev_sgi_mte_access():
1054     */
1055     int dev_sgi_mte_access(struct cpu *cpu, struct memory *mem,
1056     uint64_t relative_addr, unsigned char *data, size_t len,
1057     int writeflag, void *extra)
1058     {
1059     struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1060     uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1061     unsigned char zerobuf[ZERO_CHUNK_LEN];
1062     uint64_t idata = 0, odata = 0;
1063     int regnr;
1064    
1065     idata = memory_readmax64(cpu, data, len);
1066 dpavlin 14 regnr = relative_addr / sizeof(uint32_t);
1067 dpavlin 4
1068 dpavlin 14 /*
1069     * Treat all registers as read/write, by default. Sometimes these
1070     * are accessed as 32-bit words, sometimes as 64-bit words.
1071     */
1072     if (len != 4) {
1073     if (writeflag == MEM_WRITE) {
1074     d->reg[regnr] = idata >> 32;
1075     d->reg[regnr+1] = idata;
1076     } else
1077     odata = ((uint64_t)d->reg[regnr] << 32) +
1078     d->reg[regnr+1];
1079     }
1080    
1081 dpavlin 4 if (writeflag == MEM_WRITE)
1082     d->reg[regnr] = idata;
1083     else
1084     odata = d->reg[regnr];
1085    
1086 dpavlin 14 #ifdef MTE_DEBUG
1087     if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1088     relative_addr < 0x3000)
1089     fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1090     (long long)idata);
1091     #endif
1092    
1093 dpavlin 4 /*
1094 dpavlin 12 * I've not found any docs about this 'mte' device at all, so this is
1095     * just a guess. The mte seems to be used for copying and zeroing
1096     * chunks of memory.
1097 dpavlin 4 *
1098 dpavlin 14 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1099     * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1100     * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1101     * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1102     * write to 0x3800, data=0x0000000000000011 ] <-- operation
1103     * (0x11 = zerofill)
1104 dpavlin 4 *
1105 dpavlin 14 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1106     * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1107     * write to 0x1710, data=0x80001ea480001ea5
1108 dpavlin 4 * ...
1109 dpavlin 14 * write to 0x1770, data=0x80001e9c80001e9d
1110     * write to 0x1778, data=0x80001e9e80001e9f
1111 dpavlin 4 */
1112     switch (relative_addr) {
1113    
1114     /* No warnings for these: */
1115     case 0x3030:
1116     case 0x3038:
1117     break;
1118    
1119     /* Unknown, but no warning: */
1120     case 0x4000:
1121     case 0x3018:
1122     case 0x3008:
1123     case 0x1700:
1124     case 0x1708:
1125     case 0x1710:
1126     case 0x1718:
1127     case 0x1720:
1128     case 0x1728:
1129     case 0x1730:
1130     case 0x1738:
1131     case 0x1740:
1132     case 0x1748:
1133     case 0x1750:
1134     case 0x1758:
1135     case 0x1760:
1136     case 0x1768:
1137     case 0x1770:
1138     case 0x1778:
1139     break;
1140    
1141 dpavlin 14 /* Graphics stuff? No warning: */
1142     case 0x2018:
1143     case 0x2060:
1144     case 0x2070:
1145     case 0x2074:
1146     case 0x20c0:
1147     case 0x20c4:
1148     case 0x20d0:
1149     case 0x21b0:
1150     case 0x21b8:
1151     break;
1152 dpavlin 12
1153 dpavlin 14 /* Perform graphics operation: */
1154     case 0x21f8:
1155     {
1156     uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1157     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1158     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1159     >> 16) & 0xfff;
1160     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1161     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1162     >> 16) & 0xfff;
1163     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1164     int y;
1165 dpavlin 12
1166 dpavlin 14 op >>= 24;
1167    
1168     switch (op) {
1169     case 1: /* Unknown. Used after drawing bitmaps? */
1170     break;
1171     case 3: /* Fill: */
1172     if (x2 < x1) {
1173     int tmp = x1; x1 = x2; x2 = tmp;
1174     }
1175     if (y2 < y1) {
1176     int tmp = y1; y1 = y2; y2 = tmp;
1177     }
1178     for (y=y1; y<=y2; y++) {
1179     unsigned char buf[1280];
1180     int length = x2-x1+1;
1181     int addr = (x1 + y*1280);
1182     if (length < 1)
1183     length = 1;
1184     memset(buf, color, length);
1185     if (x1 < 1280 && y < 1024)
1186     cpu->memory_rw(cpu, cpu->mem,
1187     0x38000000 + addr, buf,
1188     length, MEM_WRITE,
1189     NO_EXCEPTIONS | PHYSICAL);
1190     }
1191     break;
1192    
1193     default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1194     "%i,%i\n\n", op, color, x1,y1, x2,y2);
1195     }
1196     }
1197     break;
1198    
1199     case 0x29f0:
1200     /* Pixel output: */
1201     {
1202     uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1203     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1204     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1205     >> 16) & 0xfff;
1206     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1207     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1208     >> 16) & 0xfff;
1209     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1210     int x,y;
1211     if (x2 < x1) {
1212     int tmp = x1; x1 = x2; x2 = tmp;
1213     }
1214     if (y2 < y1) {
1215     int tmp = y1; y1 = y2; y2 = tmp;
1216     }
1217     if (x2-x1 <= 15)
1218     data <<= 16;
1219     x=x1; y=y1;
1220     while (x <= x2 && y <= y2) {
1221     unsigned char buf = color;
1222     int addr = x + y*1280;
1223     int bit_set = data & 0x80000000UL;
1224     data <<= 1;
1225     if (x < 1280 && y < 1024 && bit_set)
1226     cpu->memory_rw(cpu, cpu->mem,
1227     0x38000000 + addr, &buf,1,MEM_WRITE,
1228     NO_EXCEPTIONS | PHYSICAL);
1229     x++;
1230     if (x > x2) {
1231     x = x1;
1232     y++;
1233     }
1234     }
1235     }
1236     break;
1237    
1238    
1239 dpavlin 4 /* Operations: */
1240     case 0x3800:
1241     if (writeflag == MEM_WRITE) {
1242     switch (idata) {
1243     case 0x11: /* zerofill */
1244 dpavlin 14 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1245     last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1246 dpavlin 4 zerobuflen = last_addr - first_addr + 1;
1247 dpavlin 14 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1248     " last = 0x%016llx, length = 0x%llx ]\n",
1249     (long long)first_addr, (long long)
1250     last_addr, (long long)zerobuflen);
1251 dpavlin 4
1252 dpavlin 14 /* TODO: is there a better way to
1253     implement this? */
1254 dpavlin 4 memset(zerobuf, 0, sizeof(zerobuf));
1255     fill_addr = first_addr;
1256     while (zerobuflen != 0) {
1257     if (zerobuflen > sizeof(zerobuf))
1258     fill_len = sizeof(zerobuf);
1259     else
1260     fill_len = zerobuflen;
1261     cpu->memory_rw(cpu, mem, fill_addr,
1262     zerobuf, fill_len, MEM_WRITE,
1263     NO_EXCEPTIONS | PHYSICAL);
1264     fill_addr += fill_len;
1265     zerobuflen -= sizeof(zerobuf);
1266     }
1267    
1268     break;
1269     default:
1270 dpavlin 14 fatal("[ sgi_mte: UNKNOWN operation "
1271     "0x%x ]\n", idata);
1272 dpavlin 4 }
1273     }
1274     break;
1275     default:
1276     if (writeflag == MEM_WRITE)
1277 dpavlin 14 debug("[ sgi_mte: unimplemented write to "
1278     "address 0x%llx, data=0x%016llx ]\n",
1279     (long long)relative_addr, (long long)idata);
1280 dpavlin 4 else
1281 dpavlin 14 debug("[ sgi_mte: unimplemented read from address"
1282     " 0x%llx ]\n", (long long)relative_addr);
1283 dpavlin 4 }
1284    
1285     if (writeflag == MEM_READ)
1286     memory_writemax64(cpu, data, len, odata);
1287    
1288     return 1;
1289     }
1290    
1291    
1292     /*
1293     * dev_sgi_mte_init():
1294     */
1295     void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1296     {
1297     struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1298     if (d == NULL) {
1299     fprintf(stderr, "out of memory\n");
1300     exit(1);
1301     }
1302     memset(d, 0, sizeof(struct sgi_mte_data));
1303    
1304     memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1305 dpavlin 20 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1306 dpavlin 4 }
1307    

  ViewVC Help
Powered by ViewVC 1.1.26