/[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 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 38078 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


1 dpavlin 4 /*
2 dpavlin 34 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 dpavlin 4 *
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 34 * $Id: dev_sgi_ip32.c,v 1.51 2007/01/29 18:32:01 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 dpavlin 34 #include "device.h"
48 dpavlin 4 #include "devices.h"
49     #include "emul.h"
50     #include "machine.h"
51     #include "memory.h"
52     #include "misc.h"
53     #include "net.h"
54    
55     #include "crimereg.h"
56     #include "if_mecreg.h"
57 dpavlin 34 #include "sgi_macereg.h"
58 dpavlin 4
59    
60     #define CRIME_TICKSHIFT 14
61     #define CRIME_SPEED_MUL_FACTOR 1
62     #define CRIME_SPEED_DIV_FACTOR 1
63    
64     struct macepci_data {
65     struct pci_data *pci_data;
66     uint32_t reg[DEV_MACEPCI_LENGTH / 4];
67     };
68    
69 dpavlin 34 #define DEV_CRIME_LENGTH 0x1000
70     struct crime_data {
71     unsigned char reg[DEV_CRIME_LENGTH];
72     struct interrupt irq;
73     int use_fb;
74     };
75 dpavlin 4
76 dpavlin 34
77 dpavlin 4 /*
78 dpavlin 34 * crime_interrupt_assert():
79     * crime_interrupt_deassert():
80     */
81     void crime_interrupt_assert(struct interrupt *interrupt)
82     {
83     struct crime_data *d = (struct crime_data *) interrupt->extra;
84     uint32_t line = interrupt->line, asserted;
85    
86     d->reg[CRIME_INTSTAT + 4] |= ((line >> 24) & 255);
87     d->reg[CRIME_INTSTAT + 5] |= ((line >> 16) & 255);
88     d->reg[CRIME_INTSTAT + 6] |= ((line >> 8) & 255);
89     d->reg[CRIME_INTSTAT + 7] |= (line & 255);
90    
91     asserted =
92     (d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
93     (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
94     (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
95     (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]);
96    
97     if (asserted)
98     INTERRUPT_ASSERT(d->irq);
99     }
100     void crime_interrupt_deassert(struct interrupt *interrupt)
101     {
102     struct crime_data *d = (struct crime_data *) interrupt->extra;
103     uint32_t line = interrupt->line, asserted;
104    
105     d->reg[CRIME_INTSTAT + 4] &= ~((line >> 24) & 255);
106     d->reg[CRIME_INTSTAT + 5] &= ~((line >> 16) & 255);
107     d->reg[CRIME_INTSTAT + 6] &= ~((line >> 8) & 255);
108     d->reg[CRIME_INTSTAT + 7] &= ~(line & 255);
109    
110     asserted =
111     (d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
112     (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
113     (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
114     (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]);
115    
116     if (!asserted)
117     INTERRUPT_DEASSERT(d->irq);
118     }
119    
120    
121     /*
122 dpavlin 4 * dev_crime_tick():
123     *
124     * This function simply updates CRIME_TIME each tick.
125     *
126     * The names DIV and MUL may be a bit confusing. Increasing the
127     * MUL factor will result in an OS running on the emulated machine
128     * detecting a faster CPU. Increasing the DIV factor will result
129     * in a slower detected CPU.
130     *
131     * A R10000 is detected as running at
132     * CRIME_SPEED_FACTOR * 66 MHz. (TODO: this is not correct anymore)
133     */
134     void dev_crime_tick(struct cpu *cpu, void *extra)
135     {
136     int j, carry, old, new, add_byte;
137     uint64_t what_to_add = (1<<CRIME_TICKSHIFT)
138     * CRIME_SPEED_DIV_FACTOR / CRIME_SPEED_MUL_FACTOR;
139     struct crime_data *d = extra;
140    
141     j = 0;
142     carry = 0;
143     while (j < 8) {
144     old = d->reg[CRIME_TIME + 7 - j];
145     add_byte = what_to_add >> ((int64_t)j * 8);
146     add_byte &= 255;
147     new = old + add_byte + carry;
148     d->reg[CRIME_TIME + 7 - j] = new & 255;
149     if (new >= 256)
150     carry = 1;
151     else
152     carry = 0;
153     j++;
154     }
155     }
156    
157    
158 dpavlin 22 DEVICE_ACCESS(crime)
159 dpavlin 4 {
160 dpavlin 18 struct crime_data *d = extra;
161     uint64_t idata = 0;
162 dpavlin 22 size_t i;
163 dpavlin 4
164 dpavlin 18 if (writeflag == MEM_WRITE)
165     idata = memory_readmax64(cpu, data, len);
166 dpavlin 4
167     /*
168     * Set crime version/revision:
169     *
170 dpavlin 18 * This might not be the most elegant or correct solution, but it
171     * seems that the IP32 PROM likes 0x11 for machines without graphics,
172     * and 0xa1 for machines with graphics.
173 dpavlin 4 *
174 dpavlin 18 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
175     * that's something one has to live with. (TODO?)
176 dpavlin 4 */
177     d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
178     d->reg[7] = d->use_fb? 0xa1 : 0x11;
179    
180     /*
181     * Amount of memory. Bit 8 of bank control set ==> 128MB instead
182     * of 32MB per bank (?)
183     *
184     * When the bank control registers contain the same value as the
185     * previous one, that bank is not valid. (?)
186     */
187     d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
188     d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
189     d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
190     d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
191    
192     if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
193     if (writeflag == MEM_READ)
194     memcpy(data, &d->reg[relative_addr], len);
195     return 1;
196     }
197    
198     if (writeflag == MEM_WRITE)
199     memcpy(&d->reg[relative_addr], data, len);
200     else
201     memcpy(data, &d->reg[relative_addr], len);
202    
203     switch (relative_addr) {
204     case CRIME_CONTROL: /* 0x008 */
205     /* TODO: 64-bit write to CRIME_CONTROL, but some things
206     (such as NetBSD 1.6.2) write to 0x00c! */
207     if (writeflag == MEM_WRITE) {
208     /*
209     * 0x200 = watchdog timer (according to NetBSD)
210     * 0x800 = "reboot" used by the IP32 PROM
211     */
212     if (idata & 0x200) {
213     idata &= ~0x200;
214     }
215     if (idata & 0x800) {
216 dpavlin 22 int j;
217    
218 dpavlin 4 /* This is used by the IP32 PROM's
219     "reboot" command: */
220 dpavlin 22 for (j=0; j<cpu->machine->ncpus; j++)
221     cpu->machine->cpus[j]->running = 0;
222 dpavlin 4 cpu->machine->
223     exit_without_entering_debugger = 1;
224     idata &= ~0x800;
225     }
226     if (idata != 0)
227     fatal("[ CRIME_CONTROL: unimplemented "
228     "control 0x%016llx ]\n", (long long)idata);
229     }
230     break;
231 dpavlin 34
232 dpavlin 4 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
233 dpavlin 34 case CRIME_INTSTAT + 4:
234 dpavlin 4 case CRIME_INTMASK: /* 0x018, Current interrupt mask */
235 dpavlin 34 case CRIME_INTMASK + 4:
236     if ((d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
237     (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
238     (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
239     (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]) )
240     INTERRUPT_ASSERT(d->irq);
241     else
242     INTERRUPT_DEASSERT(d->irq);
243     break;
244 dpavlin 4 case 0x34:
245     /* don't dump debug info for these */
246     break;
247 dpavlin 34
248 dpavlin 4 default:
249     if (writeflag==MEM_READ) {
250     debug("[ crime: read from 0x%x, len=%i:",
251     (int)relative_addr, len);
252     for (i=0; i<len; i++)
253     debug(" %02x", data[i]);
254     debug(" ]\n");
255     } else {
256     debug("[ crime: write to 0x%x:", (int)relative_addr);
257     for (i=0; i<len; i++)
258     debug(" %02x", data[i]);
259     debug(" (len=%i) ]\n", len);
260     }
261     }
262    
263     return 1;
264     }
265    
266    
267     /*
268     * dev_crime_init():
269     */
270 dpavlin 34 void dev_crime_init(struct machine *machine, struct memory *mem,
271     uint64_t baseaddr, char *irq_path, int use_fb)
272 dpavlin 4 {
273     struct crime_data *d;
274 dpavlin 34 char tmpstr[200];
275     int i;
276 dpavlin 4
277     d = malloc(sizeof(struct crime_data));
278     if (d == NULL) {
279     fprintf(stderr, "out of memory\n");
280     exit(1);
281     }
282     memset(d, 0, sizeof(struct crime_data));
283     d->use_fb = use_fb;
284    
285 dpavlin 34 INTERRUPT_CONNECT(irq_path, d->irq);
286    
287     /* Register 32 crime interrupts (hexadecimal names): */
288     for (i=0; i<32; i++) {
289     struct interrupt template;
290     char name[400];
291     snprintf(name, sizeof(name), "%s.crime.0x%x", irq_path, 1 << i);
292     memset(&template, 0, sizeof(template));
293     template.line = 1 << i;
294     template.name = name;
295     template.extra = d;
296     template.interrupt_assert = crime_interrupt_assert;
297     template.interrupt_deassert = crime_interrupt_deassert;
298     interrupt_handler_register(&template);
299     }
300    
301 dpavlin 4 memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
302 dpavlin 20 dev_crime_access, d, DM_DEFAULT, NULL);
303 dpavlin 34
304     snprintf(tmpstr, sizeof(tmpstr), "mace addr=0x1f310000 irq=%s.crime",
305     irq_path);
306     device_add(machine, tmpstr);
307    
308 dpavlin 24 machine_add_tickfunction(machine, dev_crime_tick, d,
309     CRIME_TICKSHIFT, 0.0);
310 dpavlin 4 }
311    
312    
313     /****************************************************************************/
314    
315    
316 dpavlin 34 #define DEV_MACE_LENGTH 0x100
317     struct mace_data {
318     unsigned char reg[DEV_MACE_LENGTH];
319     struct interrupt irq_periph;
320     struct interrupt irq_misc;
321     };
322    
323    
324 dpavlin 4 /*
325 dpavlin 34 * mace_interrupt_assert():
326     * mace_interrupt_deassert():
327 dpavlin 4 */
328 dpavlin 34 void mace_interrupt_assert(struct interrupt *interrupt)
329     {
330     struct mace_data *d = (struct mace_data *) interrupt->extra;
331     uint32_t line = 1 << interrupt->line;
332    
333     d->reg[MACE_ISA_INT_STATUS + 4] |= ((line >> 24) & 255);
334     d->reg[MACE_ISA_INT_STATUS + 5] |= ((line >> 16) & 255);
335     d->reg[MACE_ISA_INT_STATUS + 6] |= ((line >> 8) & 255);
336     d->reg[MACE_ISA_INT_STATUS + 7] |= (line & 255);
337    
338     /* High bits = PERIPH */
339     if ((d->reg[MACE_ISA_INT_STATUS+4] & d->reg[MACE_ISA_INT_MASK+4]) |
340     (d->reg[MACE_ISA_INT_STATUS+5] & d->reg[MACE_ISA_INT_MASK+5]))
341     INTERRUPT_ASSERT(d->irq_periph);
342    
343     /* Low bits = MISC */
344     if ((d->reg[MACE_ISA_INT_STATUS+6] & d->reg[MACE_ISA_INT_MASK+6]) |
345     (d->reg[MACE_ISA_INT_STATUS+7] & d->reg[MACE_ISA_INT_MASK+7]))
346     INTERRUPT_ASSERT(d->irq_misc);
347     }
348     void mace_interrupt_deassert(struct interrupt *interrupt)
349     {
350     struct mace_data *d = (struct mace_data *) interrupt->extra;
351     uint32_t line = 1 << interrupt->line;
352    
353     d->reg[MACE_ISA_INT_STATUS + 4] |= ((line >> 24) & 255);
354     d->reg[MACE_ISA_INT_STATUS + 5] |= ((line >> 16) & 255);
355     d->reg[MACE_ISA_INT_STATUS + 6] |= ((line >> 8) & 255);
356     d->reg[MACE_ISA_INT_STATUS + 7] |= (line & 255);
357    
358     /* High bits = PERIPH */
359     if (!((d->reg[MACE_ISA_INT_STATUS+4] & d->reg[MACE_ISA_INT_MASK+4]) |
360     (d->reg[MACE_ISA_INT_STATUS+5] & d->reg[MACE_ISA_INT_MASK+5])))
361     INTERRUPT_DEASSERT(d->irq_periph);
362    
363     /* Low bits = MISC */
364     if (!((d->reg[MACE_ISA_INT_STATUS+6] & d->reg[MACE_ISA_INT_MASK+6]) |
365     (d->reg[MACE_ISA_INT_STATUS+7] & d->reg[MACE_ISA_INT_MASK+7])))
366     INTERRUPT_DEASSERT(d->irq_misc);
367     }
368    
369    
370 dpavlin 22 DEVICE_ACCESS(mace)
371 dpavlin 4 {
372 dpavlin 22 size_t i;
373 dpavlin 4 struct mace_data *d = extra;
374    
375     if (writeflag == MEM_WRITE)
376     memcpy(&d->reg[relative_addr], data, len);
377     else
378     memcpy(data, &d->reg[relative_addr], len);
379    
380 dpavlin 34 switch (relative_addr) {
381 dpavlin 10
382 dpavlin 34 case MACE_ISA_INT_STATUS: /* Current interrupt assertions */
383     case MACE_ISA_INT_STATUS + 4:
384 dpavlin 4 /* don't dump debug info for these */
385 dpavlin 10 if (writeflag == MEM_WRITE) {
386     fatal("[ NOTE/TODO: WRITE to mace intr: "
387     "reladdr=0x%x data=", (int)relative_addr);
388     for (i=0; i<len; i++)
389     fatal(" %02x", data[i]);
390     fatal(" (len=%i) ]\n", len);
391     }
392 dpavlin 4 break;
393 dpavlin 34 case MACE_ISA_INT_MASK: /* Current interrupt mask */
394     case MACE_ISA_INT_MASK + 4:
395     if ((d->reg[MACE_ISA_INT_STATUS+4]&d->reg[MACE_ISA_INT_MASK+4])|
396     (d->reg[MACE_ISA_INT_STATUS+5]&d->reg[MACE_ISA_INT_MASK+5]))
397     INTERRUPT_ASSERT(d->irq_periph);
398     else
399     INTERRUPT_DEASSERT(d->irq_periph);
400    
401     if ((d->reg[MACE_ISA_INT_STATUS+6]&d->reg[MACE_ISA_INT_MASK+6])|
402     (d->reg[MACE_ISA_INT_STATUS+7]&d->reg[MACE_ISA_INT_MASK+7]))
403     INTERRUPT_ASSERT(d->irq_misc);
404     else
405     INTERRUPT_DEASSERT(d->irq_misc);
406 dpavlin 10 break;
407 dpavlin 34
408 dpavlin 4 default:
409 dpavlin 10 if (writeflag == MEM_READ) {
410     debug("[ mace: read from 0x%x:", (int)relative_addr);
411     for (i=0; i<len; i++)
412     debug(" %02x", data[i]);
413     debug(" (len=%i) ]\n", len);
414 dpavlin 4 } else {
415     debug("[ mace: write to 0x%x:", (int)relative_addr);
416     for (i=0; i<len; i++)
417     debug(" %02x", data[i]);
418     debug(" (len=%i) ]\n", len);
419     }
420     }
421    
422     return 1;
423     }
424    
425    
426 dpavlin 34 DEVINIT(mace)
427 dpavlin 4 {
428     struct mace_data *d;
429 dpavlin 34 char tmpstr[300];
430     int i;
431 dpavlin 4
432     d = malloc(sizeof(struct mace_data));
433     if (d == NULL) {
434     fprintf(stderr, "out of memory\n");
435     exit(1);
436     }
437     memset(d, 0, sizeof(struct mace_data));
438    
439 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "%s.0x%x",
440     devinit->interrupt_path, MACE_PERIPH_SERIAL);
441     INTERRUPT_CONNECT(tmpstr, d->irq_periph);
442 dpavlin 4
443 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "%s.0x%x",
444     devinit->interrupt_path, MACE_PERIPH_SERIAL);
445     INTERRUPT_CONNECT(tmpstr, d->irq_misc);
446    
447     /*
448     * For Mace interrupts MACE_PERIPH_SERIAL and MACE_PERIPH_MISC,
449     * register 32 mace interrupts each.
450     */
451     /* Register 32 crime interrupts (hexadecimal names): */
452     for (i=0; i<32; i++) {
453     struct interrupt template;
454     char name[400];
455     snprintf(name, sizeof(name), "%s.0x%x.mace.%i",
456     devinit->interrupt_path, MACE_PERIPH_SERIAL, i);
457     memset(&template, 0, sizeof(template));
458     template.line = i;
459     template.name = name;
460     template.extra = d;
461     template.interrupt_assert = mace_interrupt_assert;
462     template.interrupt_deassert = mace_interrupt_deassert;
463     interrupt_handler_register(&template);
464    
465     snprintf(name, sizeof(name), "%s.0x%x.mace.%i",
466     devinit->interrupt_path, MACE_PERIPH_MISC, i);
467     memset(&template, 0, sizeof(template));
468     template.line = i;
469     template.name = name;
470     template.extra = d;
471     template.interrupt_assert = mace_interrupt_assert;
472     template.interrupt_deassert = mace_interrupt_deassert;
473     interrupt_handler_register(&template);
474     }
475    
476     memory_device_register(devinit->machine->memory, devinit->name,
477     devinit->addr, DEV_MACE_LENGTH, dev_mace_access, d,
478     DM_DEFAULT, NULL);
479    
480     devinit->return_ptr = d;
481     return 1;
482 dpavlin 4 }
483    
484    
485     /****************************************************************************/
486    
487    
488 dpavlin 22 DEVICE_ACCESS(macepci)
489 dpavlin 4 {
490     struct macepci_data *d = (struct macepci_data *) extra;
491     uint64_t idata = 0, odata=0;
492 dpavlin 22 int regnr, res = 1, bus, dev, func, pcireg;
493 dpavlin 4
494 dpavlin 18 if (writeflag == MEM_WRITE)
495     idata = memory_readmax64(cpu, data, len);
496    
497 dpavlin 4 regnr = relative_addr / sizeof(uint32_t);
498    
499     /* Read from/write to the macepci: */
500     switch (relative_addr) {
501 dpavlin 22
502 dpavlin 4 case 0x00: /* Error address */
503     if (writeflag == MEM_WRITE) {
504     } else {
505     odata = 0;
506     }
507     break;
508 dpavlin 22
509 dpavlin 4 case 0x04: /* Error flags */
510     if (writeflag == MEM_WRITE) {
511     } else {
512     odata = 0x06;
513     }
514     break;
515 dpavlin 22
516 dpavlin 4 case 0x0c: /* Revision number */
517     if (writeflag == MEM_WRITE) {
518     } else {
519     odata = 0x01;
520     }
521     break;
522 dpavlin 22
523 dpavlin 4 case 0xcf8: /* PCI ADDR */
524 dpavlin 22 bus_pci_decompose_1(idata, &bus, &dev, &func, &pcireg);
525     bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, pcireg);
526     break;
527    
528 dpavlin 4 case 0xcfc: /* PCI DATA */
529 dpavlin 22 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
530     &odata : &idata, len, writeflag);
531 dpavlin 4 break;
532 dpavlin 22
533 dpavlin 4 default:
534     if (writeflag == MEM_WRITE) {
535     debug("[ macepci: unimplemented write to address "
536     "0x%x, data=0x%02x ]\n",
537     (int)relative_addr, (int)idata);
538     } else {
539     debug("[ macepci: unimplemented read from address "
540     "0x%x ]\n", (int)relative_addr);
541     }
542     }
543    
544     if (writeflag == MEM_READ)
545     memory_writemax64(cpu, data, len, odata);
546    
547     return res;
548     }
549    
550    
551     /*
552     * dev_macepci_init():
553     */
554 dpavlin 22 struct pci_data *dev_macepci_init(struct machine *machine,
555 dpavlin 34 struct memory *mem, uint64_t baseaddr, char *irq_path)
556 dpavlin 4 {
557     struct macepci_data *d = malloc(sizeof(struct macepci_data));
558     if (d == NULL) {
559     fprintf(stderr, "out of memory\n");
560     exit(1);
561     }
562     memset(d, 0, sizeof(struct macepci_data));
563    
564 dpavlin 34 /* TODO: PCI vs ISA interrupt? */
565    
566 dpavlin 32 d->pci_data = bus_pci_init(machine,
567 dpavlin 34 irq_path,
568 dpavlin 32 0,
569     0,
570     0,
571     0,
572 dpavlin 34 "TODO: pci irq path",
573 dpavlin 32 0x18000003, /* ISA portbase */
574     0,
575 dpavlin 34 irq_path);
576 dpavlin 4
577     memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
578 dpavlin 20 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
579 dpavlin 4
580     return d->pci_data;
581     }
582    
583    
584     /****************************************************************************/
585    
586    
587     /*
588     * SGI "mec" ethernet. Used in SGI-IP32.
589     *
590     * Study http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c
591     * and/or NetBSD. TODO:
592     *
593     * x) tx and rx interrupts/ring/slot stuff
594     */
595    
596     #define MEC_TICK_SHIFT 14
597    
598     #define MAX_TX_PACKET_LEN 1700
599     #define N_RX_ADDRESSES 16
600    
601     struct sgi_mec_data {
602     uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
603    
604 dpavlin 34 struct interrupt irq;
605 dpavlin 4 unsigned char macaddr[6];
606    
607     unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
608     int cur_tx_packet_len;
609    
610     unsigned char *cur_rx_packet;
611     int cur_rx_packet_len;
612    
613     uint64_t rx_addr[N_RX_ADDRESSES];
614     int cur_rx_addr_index_write;
615     int cur_rx_addr_index;
616     };
617    
618    
619     /*
620     * mec_reset():
621     */
622     static void mec_reset(struct sgi_mec_data *d)
623     {
624     if (d->cur_rx_packet != NULL)
625     free(d->cur_rx_packet);
626    
627     memset(d->reg, 0, sizeof(d->reg));
628     }
629    
630    
631     /*
632     * mec_control_write():
633     */
634     static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d,
635     uint64_t x)
636     {
637     if (x & MEC_MAC_CORE_RESET) {
638     debug("[ sgi_mec: CORE RESET ]\n");
639     mec_reset(d);
640     }
641     }
642    
643    
644     /*
645     * mec_try_rx():
646     */
647     static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d)
648     {
649     uint64_t base;
650     unsigned char data[8];
651     int i, res, retval = 0;
652    
653     base = d->rx_addr[d->cur_rx_addr_index];
654     if (base & 0xfff)
655     fatal("[ mec_try_rx(): WARNING! lowest bits of base are "
656     "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff));
657     base &= 0xfffff000ULL;
658     if (base == 0)
659     goto skip;
660    
661     /* printf("rx base = 0x%016llx\n", (long long)base); */
662    
663     /* Read an rx descriptor from memory: */
664     res = cpu->memory_rw(cpu, cpu->mem, base,
665     &data[0], sizeof(data), MEM_READ, PHYSICAL);
666     if (!res)
667     return 0;
668    
669     #if 0
670     printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index);
671     for (i=0; i<sizeof(data); i++) {
672     if ((i & 3) == 0)
673     printf(" ");
674     printf("%02x", data[i]);
675     }
676     printf(" }\n");
677     #endif
678    
679     /* Is this descriptor already in use? */
680     if (data[0] & 0x80) {
681     /* printf("INTERRUPT for base = 0x%x\n", (int)base); */
682     goto skip_and_advance;
683     }
684    
685     if (d->cur_rx_packet == NULL &&
686     net_ethernet_rx_avail(cpu->machine->emul->net, d))
687     net_ethernet_rx(cpu->machine->emul->net, d,
688     &d->cur_rx_packet, &d->cur_rx_packet_len);
689    
690     if (d->cur_rx_packet == NULL)
691     goto skip;
692    
693     /* Copy the packet data: */
694     /* printf("RX: "); */
695     for (i=0; i<d->cur_rx_packet_len; i++) {
696     res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2,
697     d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL);
698     /* printf(" %02x", d->cur_rx_packet[i]); */
699     }
700     /* printf("\n"); */
701    
702 dpavlin 10 #if 0
703 dpavlin 4 printf("RX: %i bytes, index %i, base = 0x%x\n",
704     d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base);
705     #endif
706    
707     /* 4 bytes of CRC at the end. Hm. TODO */
708     d->cur_rx_packet_len += 4;
709    
710     memset(data, 0, sizeof(data));
711     data[6] = (d->cur_rx_packet_len >> 8) & 255;
712     data[7] = d->cur_rx_packet_len & 255;
713     /* TODO: lots of bits :-) */
714     data[4] = 0x04; /* match MAC */
715     data[0] = 0x80; /* 0x80 = received. */
716     res = cpu->memory_rw(cpu, cpu->mem, base,
717     &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
718    
719     /* Free the packet from memory: */
720     free(d->cur_rx_packet);
721     d->cur_rx_packet = NULL;
722    
723     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD;
724     skip_and_advance:
725     d->cur_rx_addr_index ++;
726     d->cur_rx_addr_index %= N_RX_ADDRESSES;
727     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS;
728 dpavlin 12 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
729     (d->cur_rx_addr_index & 0x1f) << 8;
730 dpavlin 4 retval = 1;
731    
732     skip:
733     return retval;
734     }
735    
736    
737     /*
738     * mec_try_tx():
739     */
740     static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
741     {
742     uint64_t base, addr, dma_base;
743     int tx_ring_ptr, ringread, ringwrite, res, i, j;
744     unsigned char data[32];
745     int len, start_offset, dma_ptr_nr, dma_len;
746    
747     base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
748     tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
749    
750     if (base == 0)
751     return 0;
752    
753     /* printf("base = 0x%016llx\n", base); */
754    
755     ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
756     ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
757     ringread >>= 16;
758     /* All done? Then abort. */
759     if (ringread == ringwrite)
760     return 0;
761    
762     tx_ring_ptr &= MEC_TX_RING_READ_PTR;
763     tx_ring_ptr >>= 16;
764    
765     /* Each tx descriptor (+ buffer) is 128 bytes: */
766     addr = base + tx_ring_ptr*128;
767     res = cpu->memory_rw(cpu, cpu->mem, addr,
768     &data[0], sizeof(data), MEM_READ, PHYSICAL);
769     if (!res)
770     return 0;
771    
772     /* Is this packet transmitted already? */
773     if (data[0] & 0x80) {
774     fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
775     " transmitted? ]\n", tx_ring_ptr);
776     goto advance_tx;
777     }
778    
779     len = data[6] * 256 + data[7];
780     start_offset = data[5] & 0x7f;
781    
782     /* Is this packet empty? Then don't transmit. */
783     if (len == 0)
784     return 0;
785    
786     /* Hm. Is len one too little? TODO */
787     len ++;
788    
789     #if 0
790     printf("{ mec: txdesc %i: ", tx_ring_ptr);
791     for (i=0; i<sizeof(data); i++) {
792     if ((i & 3) == 0)
793     printf(" ");
794     printf("%02x", data[i]);
795     }
796     printf(" }\n");
797     #endif
798     dma_ptr_nr = 0;
799    
800     j = 0;
801     d->cur_tx_packet_len = len;
802    
803     for (i=start_offset; i<start_offset+len; i++) {
804     unsigned char ch;
805    
806     if ((i & 0x7f) == 0x00)
807     break;
808    
809     res = cpu->memory_rw(cpu, cpu->mem, addr + i,
810     &ch, sizeof(ch), MEM_READ, PHYSICAL);
811     /* printf(" %02x", ch); */
812    
813     d->cur_tx_packet[j++] = ch;
814     if (j >= MAX_TX_PACKET_LEN) {
815     fatal("[ mec_try_tx: packet too large? ]\n");
816     break;
817     }
818     }
819     /* printf("\n"); */
820    
821     if (j < len) {
822     /* Continue with DMA: */
823     for (;;) {
824     dma_ptr_nr ++;
825     if (dma_ptr_nr >= 4)
826     break;
827     if (!(data[4] & (0x01 << dma_ptr_nr)))
828     break;
829     dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
830     + (data[dma_ptr_nr * 8 + 5] << 16)
831     + (data[dma_ptr_nr * 8 + 6] << 8)
832     + (data[dma_ptr_nr * 8 + 7]);
833     dma_base &= 0xfffffff8ULL;
834     dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
835     + (data[dma_ptr_nr * 8 + 3]) + 1;
836    
837     /* printf("dma_base = %08x, dma_len = %i\n",
838     (int)dma_base, dma_len); */
839    
840     while (dma_len > 0) {
841     unsigned char ch;
842     res = cpu->memory_rw(cpu, cpu->mem, dma_base,
843     &ch, sizeof(ch), MEM_READ, PHYSICAL);
844     /* printf(" %02x", ch); */
845    
846     d->cur_tx_packet[j++] = ch;
847     if (j >= MAX_TX_PACKET_LEN) {
848     fatal("[ mec_try_tx: packet too large?"
849     " ]\n");
850     break;
851     }
852     dma_base ++;
853     dma_len --;
854     }
855     }
856     }
857    
858     if (j < len)
859     fatal("[ mec_try_tx: not enough data? ]\n");
860    
861     net_ethernet_tx(cpu->machine->emul->net, d,
862     d->cur_tx_packet, d->cur_tx_packet_len);
863    
864     /* see openbsd's if_mec.c for details */
865     if (data[4] & 0x01) {
866     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
867     MEC_INT_TX_PACKET_SENT;
868     }
869     memset(data, 0, 6); /* last 2 bytes are len */
870     data[0] = 0x80;
871     data[5] = 0x80;
872    
873     res = cpu->memory_rw(cpu, cpu->mem, addr,
874     &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
875    
876     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
877     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
878    
879     advance_tx:
880     /* Advance the ring Read ptr. */
881     tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
882     ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
883     ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
884    
885     ringread = (ringread >> 16) + 1;
886     ringread &= 63;
887     ringread <<= 16;
888    
889     d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
890     (ringwrite & MEC_TX_RING_WRITE_PTR) |
891     (ringread & MEC_TX_RING_READ_PTR);
892    
893     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
894     ~MEC_INT_TX_RING_BUFFER_ALIAS;
895     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
896     (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
897     MEC_INT_TX_RING_BUFFER_ALIAS);
898    
899     return 1;
900     }
901    
902    
903     /*
904     * dev_sgi_mec_tick():
905     */
906     void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
907     {
908     struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
909     int n = 0;
910    
911     while (mec_try_tx(cpu, d))
912     ;
913    
914     while (mec_try_rx(cpu, d) && n < 16)
915     n++;
916    
917     /* Interrupts: (TODO: only when enabled) */
918     if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
919     #if 0
920     printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
921     sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
922     fflush(stdout);
923     #endif
924 dpavlin 34 INTERRUPT_ASSERT(d->irq);
925 dpavlin 4 } else
926 dpavlin 34 INTERRUPT_DEASSERT(d->irq);
927 dpavlin 4 }
928    
929    
930 dpavlin 22 DEVICE_ACCESS(sgi_mec)
931 dpavlin 4 {
932     struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
933     uint64_t idata = 0, odata = 0;
934     int regnr;
935    
936 dpavlin 18 if (writeflag == MEM_WRITE)
937     idata = memory_readmax64(cpu, data, len);
938    
939 dpavlin 4 regnr = relative_addr / sizeof(uint64_t);
940    
941     /* Treat most registers as read/write, by default. */
942     if (writeflag == MEM_WRITE) {
943     switch (relative_addr) {
944     case MEC_INT_STATUS: /* 0x08 */
945     /* Clear bits on write: (This is just a guess) */
946     d->reg[regnr] = (d->reg[regnr] & ~0xff)
947     | ((d->reg[regnr] & ~idata) & 0xff);
948     break;
949     case MEC_TX_RING_PTR: /* 0x30 */
950     idata &= MEC_TX_RING_WRITE_PTR;
951     d->reg[regnr] = (d->reg[regnr] &
952     ~MEC_TX_RING_WRITE_PTR) | idata;
953     /* TODO */
954     break;
955     default:
956     d->reg[regnr] = idata;
957     }
958     } else
959     odata = d->reg[regnr];
960    
961     switch (relative_addr) {
962     case MEC_MAC_CONTROL: /* 0x00 */
963     if (writeflag)
964     mec_control_write(cpu, d, idata);
965     else {
966     /* Fake "revision 1": */
967     odata &= ~MEC_MAC_REVISION;
968     odata |= 1 << MEC_MAC_REVISION_SHIFT;
969     }
970     break;
971     case MEC_INT_STATUS: /* 0x08 */
972     if (writeflag)
973     debug("[ sgi_mec: write to MEC_INT_STATUS: "
974     "0x%016llx ]\n", (long long)idata);
975     break;
976     case MEC_DMA_CONTROL: /* 0x10 */
977     if (writeflag) {
978     debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
979     "0x%016llx ]\n", (long long)idata);
980     if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
981     /* This should apparently stop the
982     TX Empty interrupt. */
983     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
984     ~MEC_INT_TX_EMPTY;
985     }
986     }
987     break;
988     case MEC_TX_ALIAS: /* 0x20 */
989     if (writeflag) {
990     debug("[ sgi_mec: write to MEC_TX_ALIAS: "
991     "0x%016llx ]\n", (long long)idata);
992     } else {
993     debug("[ sgi_mec: read from MEC_TX_ALIAS: "
994     "0x%016llx ]\n", (long long)idata);
995     odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
996     }
997     break;
998     case MEC_RX_ALIAS: /* 0x28 */
999     if (writeflag)
1000     debug("[ sgi_mec: write to MEC_RX_ALIAS: "
1001     "0x%016llx ]\n", (long long)idata);
1002     break;
1003     case MEC_TX_RING_PTR: /* 0x30 */
1004     if (writeflag)
1005     debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
1006     "0x%016llx ]\n", (long long)idata);
1007     break;
1008     case MEC_PHY_DATA: /* 0x64 */
1009     if (writeflag)
1010     fatal("[ sgi_mec: write to MEC_PHY_DATA: "
1011     "0x%016llx ]\n", (long long)idata);
1012     else
1013     odata = 0; /* ? */
1014     break;
1015     case MEC_PHY_ADDRESS: /* 0x6c */
1016     if (writeflag)
1017     debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
1018     "0x%016llx ]\n", (long long)idata);
1019     break;
1020     case MEC_PHY_READ_INITIATE: /* 0x70 */
1021     if (writeflag)
1022     debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
1023     "0x%016llx ]\n", (long long)idata);
1024     break;
1025     case 0x74:
1026     if (writeflag)
1027     debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
1028     (long long)idata);
1029     else
1030     debug("[ sgi_mec: read from 0x74 ]\n");
1031     break;
1032     case MEC_STATION: /* 0xa0 */
1033     if (writeflag)
1034     debug("[ sgi_mec: setting the MAC address to "
1035     "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
1036     (idata >> 40) & 255, (idata >> 32) & 255,
1037     (idata >> 24) & 255, (idata >> 16) & 255,
1038     (idata >> 8) & 255, (idata >> 0) & 255);
1039     break;
1040     case MEC_STATION_ALT: /* 0xa8 */
1041     if (writeflag)
1042     debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
1043     " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
1044     (idata >> 40) & 255, (idata >> 32) & 255,
1045     (idata >> 24) & 255, (idata >> 16) & 255,
1046     (idata >> 8) & 255, (idata >> 0) & 255);
1047     break;
1048     case MEC_MULTICAST: /* 0xb0 */
1049     if (writeflag)
1050     debug("[ sgi_mec: write to MEC_MULTICAST: "
1051     "0x%016llx ]\n", (long long)idata);
1052     break;
1053     case MEC_TX_RING_BASE: /* 0xb8 */
1054     if (writeflag)
1055     debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
1056     "0x%016llx ]\n", (long long)idata);
1057     break;
1058     case MEC_MCL_RX_FIFO: /* 0x100 */
1059     if (writeflag) {
1060     debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
1061     "%016llx ]\n", (long long)idata);
1062     d->rx_addr[d->cur_rx_addr_index_write] = idata;
1063     d->cur_rx_addr_index_write ++;
1064     d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
1065     }
1066     break;
1067     default:
1068     if (writeflag == MEM_WRITE)
1069     fatal("[ sgi_mec: unimplemented write to address"
1070     " 0x%llx, data=0x%016llx ]\n",
1071     (long long)relative_addr, (long long)idata);
1072     else
1073     fatal("[ sgi_mec: unimplemented read from address"
1074     " 0x%llx ]\n", (long long)relative_addr);
1075     }
1076    
1077     if (writeflag == MEM_READ)
1078     memory_writemax64(cpu, data, len, odata);
1079    
1080     dev_sgi_mec_tick(cpu, extra);
1081    
1082     return 1;
1083     }
1084    
1085    
1086     /*
1087     * dev_sgi_mec_init():
1088     */
1089     void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
1090 dpavlin 34 uint64_t baseaddr, char *irq_path, unsigned char *macaddr)
1091 dpavlin 4 {
1092     char *name2;
1093 dpavlin 10 size_t nlen = 55;
1094 dpavlin 4 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
1095    
1096     if (d == NULL) {
1097     fprintf(stderr, "out of memory\n");
1098     exit(1);
1099     }
1100     memset(d, 0, sizeof(struct sgi_mec_data));
1101 dpavlin 34
1102     INTERRUPT_CONNECT(irq_path, d->irq);
1103 dpavlin 4 memcpy(d->macaddr, macaddr, 6);
1104     mec_reset(d);
1105    
1106 dpavlin 10 name2 = malloc(nlen);
1107 dpavlin 4 if (name2 == NULL) {
1108     fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
1109     exit(1);
1110     }
1111 dpavlin 10 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
1112 dpavlin 4 d->macaddr[0], d->macaddr[1], d->macaddr[2],
1113     d->macaddr[3], d->macaddr[4], d->macaddr[5]);
1114    
1115     memory_device_register(mem, name2, baseaddr,
1116     DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
1117 dpavlin 20 DM_DEFAULT, NULL);
1118 dpavlin 4
1119 dpavlin 24 machine_add_tickfunction(machine, dev_sgi_mec_tick, d,
1120     MEC_TICK_SHIFT, 0.0);
1121 dpavlin 4
1122     net_add_nic(machine->emul->net, d, macaddr);
1123     }
1124    
1125    
1126     /****************************************************************************/
1127    
1128    
1129     struct sgi_ust_data {
1130     uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
1131     };
1132    
1133    
1134 dpavlin 22 DEVICE_ACCESS(sgi_ust)
1135 dpavlin 4 {
1136     struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
1137     uint64_t idata = 0, odata = 0;
1138     int regnr;
1139    
1140     idata = memory_readmax64(cpu, data, len);
1141     regnr = relative_addr / sizeof(uint64_t);
1142    
1143     /* Treat all registers as read/write, by default. */
1144     if (writeflag == MEM_WRITE)
1145     d->reg[regnr] = idata;
1146     else
1147     odata = d->reg[regnr];
1148    
1149     switch (relative_addr) {
1150     case 0:
1151     d->reg[regnr] += 0x2710;
1152     break;
1153     default:
1154     if (writeflag == MEM_WRITE)
1155 dpavlin 12 debug("[ sgi_ust: unimplemented write to "
1156     "address 0x%llx, data=0x%016llx ]\n",
1157     (long long)relative_addr, (long long)idata);
1158 dpavlin 4 else
1159 dpavlin 12 debug("[ sgi_ust: unimplemented read from address"
1160     " 0x%llx ]\n", (long long)relative_addr);
1161 dpavlin 4 }
1162    
1163     if (writeflag == MEM_READ)
1164     memory_writemax64(cpu, data, len, odata);
1165    
1166     return 1;
1167     }
1168    
1169    
1170     /*
1171     * dev_sgi_ust_init():
1172     */
1173     void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1174     {
1175     struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1176     if (d == NULL) {
1177     fprintf(stderr, "out of memory\n");
1178     exit(1);
1179     }
1180     memset(d, 0, sizeof(struct sgi_ust_data));
1181    
1182     memory_device_register(mem, "sgi_ust", baseaddr,
1183 dpavlin 12 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1184 dpavlin 20 DM_DEFAULT, NULL);
1185 dpavlin 4 }
1186    
1187    
1188     /****************************************************************************/
1189    
1190    
1191     /*
1192     * SGI "mte". This device seems to be an accelerator for copying/clearing
1193 dpavlin 12 * memory. Used by (at least) the SGI O2 PROM.
1194     *
1195     * Actually, it seems to be used for graphics output as well. (?)
1196 dpavlin 14 * The O2's PROM uses it to output graphics.
1197 dpavlin 4 */
1198 dpavlin 12 /* #define debug fatal */
1199 dpavlin 14 /* #define MTE_DEBUG */
1200 dpavlin 4 #define ZERO_CHUNK_LEN 4096
1201    
1202     struct sgi_mte_data {
1203 dpavlin 14 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1204 dpavlin 4 };
1205    
1206 dpavlin 34
1207 dpavlin 22 DEVICE_ACCESS(sgi_mte)
1208 dpavlin 4 {
1209     struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1210     uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1211     unsigned char zerobuf[ZERO_CHUNK_LEN];
1212     uint64_t idata = 0, odata = 0;
1213     int regnr;
1214    
1215     idata = memory_readmax64(cpu, data, len);
1216 dpavlin 14 regnr = relative_addr / sizeof(uint32_t);
1217 dpavlin 4
1218 dpavlin 14 /*
1219     * Treat all registers as read/write, by default. Sometimes these
1220     * are accessed as 32-bit words, sometimes as 64-bit words.
1221     */
1222     if (len != 4) {
1223     if (writeflag == MEM_WRITE) {
1224     d->reg[regnr] = idata >> 32;
1225     d->reg[regnr+1] = idata;
1226     } else
1227     odata = ((uint64_t)d->reg[regnr] << 32) +
1228     d->reg[regnr+1];
1229     }
1230    
1231 dpavlin 4 if (writeflag == MEM_WRITE)
1232     d->reg[regnr] = idata;
1233     else
1234     odata = d->reg[regnr];
1235    
1236 dpavlin 14 #ifdef MTE_DEBUG
1237     if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1238     relative_addr < 0x3000)
1239     fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1240     (long long)idata);
1241     #endif
1242    
1243 dpavlin 4 /*
1244 dpavlin 12 * I've not found any docs about this 'mte' device at all, so this is
1245     * just a guess. The mte seems to be used for copying and zeroing
1246     * chunks of memory.
1247 dpavlin 4 *
1248 dpavlin 14 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1249     * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1250     * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1251     * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1252     * write to 0x3800, data=0x0000000000000011 ] <-- operation
1253     * (0x11 = zerofill)
1254 dpavlin 4 *
1255 dpavlin 14 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1256     * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1257     * write to 0x1710, data=0x80001ea480001ea5
1258 dpavlin 4 * ...
1259 dpavlin 14 * write to 0x1770, data=0x80001e9c80001e9d
1260     * write to 0x1778, data=0x80001e9e80001e9f
1261 dpavlin 4 */
1262     switch (relative_addr) {
1263    
1264     /* No warnings for these: */
1265     case 0x3030:
1266     case 0x3038:
1267     break;
1268    
1269     /* Unknown, but no warning: */
1270     case 0x4000:
1271     case 0x3018:
1272     case 0x3008:
1273     case 0x1700:
1274     case 0x1708:
1275     case 0x1710:
1276     case 0x1718:
1277     case 0x1720:
1278     case 0x1728:
1279     case 0x1730:
1280     case 0x1738:
1281     case 0x1740:
1282     case 0x1748:
1283     case 0x1750:
1284     case 0x1758:
1285     case 0x1760:
1286     case 0x1768:
1287     case 0x1770:
1288     case 0x1778:
1289     break;
1290    
1291 dpavlin 14 /* Graphics stuff? No warning: */
1292     case 0x2018:
1293     case 0x2060:
1294     case 0x2070:
1295     case 0x2074:
1296     case 0x20c0:
1297     case 0x20c4:
1298     case 0x20d0:
1299     case 0x21b0:
1300     case 0x21b8:
1301     break;
1302 dpavlin 12
1303 dpavlin 14 /* Perform graphics operation: */
1304     case 0x21f8:
1305     {
1306     uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1307     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1308     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1309     >> 16) & 0xfff;
1310     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1311     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1312     >> 16) & 0xfff;
1313     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1314 dpavlin 22 uint32_t y;
1315 dpavlin 12
1316 dpavlin 14 op >>= 24;
1317    
1318     switch (op) {
1319     case 1: /* Unknown. Used after drawing bitmaps? */
1320     break;
1321     case 3: /* Fill: */
1322     if (x2 < x1) {
1323     int tmp = x1; x1 = x2; x2 = tmp;
1324     }
1325     if (y2 < y1) {
1326     int tmp = y1; y1 = y2; y2 = tmp;
1327     }
1328     for (y=y1; y<=y2; y++) {
1329     unsigned char buf[1280];
1330     int length = x2-x1+1;
1331     int addr = (x1 + y*1280);
1332     if (length < 1)
1333     length = 1;
1334     memset(buf, color, length);
1335     if (x1 < 1280 && y < 1024)
1336     cpu->memory_rw(cpu, cpu->mem,
1337     0x38000000 + addr, buf,
1338     length, MEM_WRITE,
1339     NO_EXCEPTIONS | PHYSICAL);
1340     }
1341     break;
1342    
1343     default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1344     "%i,%i\n\n", op, color, x1,y1, x2,y2);
1345     }
1346     }
1347     break;
1348    
1349     case 0x29f0:
1350     /* Pixel output: */
1351     {
1352     uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1353     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1354     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1355     >> 16) & 0xfff;
1356     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1357     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1358     >> 16) & 0xfff;
1359     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1360 dpavlin 22 size_t x, y;
1361    
1362 dpavlin 14 if (x2 < x1) {
1363     int tmp = x1; x1 = x2; x2 = tmp;
1364     }
1365     if (y2 < y1) {
1366     int tmp = y1; y1 = y2; y2 = tmp;
1367     }
1368     if (x2-x1 <= 15)
1369     data <<= 16;
1370 dpavlin 22
1371 dpavlin 14 x=x1; y=y1;
1372     while (x <= x2 && y <= y2) {
1373     unsigned char buf = color;
1374     int addr = x + y*1280;
1375     int bit_set = data & 0x80000000UL;
1376     data <<= 1;
1377     if (x < 1280 && y < 1024 && bit_set)
1378     cpu->memory_rw(cpu, cpu->mem,
1379     0x38000000 + addr, &buf,1,MEM_WRITE,
1380     NO_EXCEPTIONS | PHYSICAL);
1381     x++;
1382     if (x > x2) {
1383     x = x1;
1384     y++;
1385     }
1386     }
1387     }
1388     break;
1389    
1390    
1391 dpavlin 4 /* Operations: */
1392     case 0x3800:
1393     if (writeflag == MEM_WRITE) {
1394     switch (idata) {
1395     case 0x11: /* zerofill */
1396 dpavlin 14 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1397     last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1398 dpavlin 4 zerobuflen = last_addr - first_addr + 1;
1399 dpavlin 14 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1400     " last = 0x%016llx, length = 0x%llx ]\n",
1401     (long long)first_addr, (long long)
1402     last_addr, (long long)zerobuflen);
1403 dpavlin 4
1404 dpavlin 14 /* TODO: is there a better way to
1405     implement this? */
1406 dpavlin 4 memset(zerobuf, 0, sizeof(zerobuf));
1407     fill_addr = first_addr;
1408     while (zerobuflen != 0) {
1409     if (zerobuflen > sizeof(zerobuf))
1410     fill_len = sizeof(zerobuf);
1411     else
1412     fill_len = zerobuflen;
1413     cpu->memory_rw(cpu, mem, fill_addr,
1414     zerobuf, fill_len, MEM_WRITE,
1415     NO_EXCEPTIONS | PHYSICAL);
1416     fill_addr += fill_len;
1417     zerobuflen -= sizeof(zerobuf);
1418     }
1419    
1420     break;
1421     default:
1422 dpavlin 14 fatal("[ sgi_mte: UNKNOWN operation "
1423     "0x%x ]\n", idata);
1424 dpavlin 4 }
1425     }
1426     break;
1427     default:
1428     if (writeflag == MEM_WRITE)
1429 dpavlin 14 debug("[ sgi_mte: unimplemented write to "
1430     "address 0x%llx, data=0x%016llx ]\n",
1431     (long long)relative_addr, (long long)idata);
1432 dpavlin 4 else
1433 dpavlin 14 debug("[ sgi_mte: unimplemented read from address"
1434     " 0x%llx ]\n", (long long)relative_addr);
1435 dpavlin 4 }
1436    
1437     if (writeflag == MEM_READ)
1438     memory_writemax64(cpu, data, len, odata);
1439    
1440     return 1;
1441     }
1442    
1443    
1444     /*
1445     * dev_sgi_mte_init():
1446     */
1447     void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1448     {
1449     struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1450     if (d == NULL) {
1451     fprintf(stderr, "out of memory\n");
1452     exit(1);
1453     }
1454     memset(d, 0, sizeof(struct sgi_mte_data));
1455    
1456     memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1457 dpavlin 20 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1458 dpavlin 4 }
1459    

  ViewVC Help
Powered by ViewVC 1.1.26