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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 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 /*
2 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_sgi_ip32.c,v 1.51 2007/01/29 18:32:01 debug Exp $
29 *
30 * SGI IP32 devices.
31 *
32 * o) CRIME
33 * o) MACE
34 * o) MACE PCI bus
35 * o) mec (ethernet)
36 * o) ust (unknown device)
37 * o) mte (memory transfer engine? details unknown)
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "bus_pci.h"
45 #include "console.h"
46 #include "cpu.h"
47 #include "device.h"
48 #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 #include "sgi_macereg.h"
58
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 #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
76
77 /*
78 * 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 * 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 DEVICE_ACCESS(crime)
159 {
160 struct crime_data *d = extra;
161 uint64_t idata = 0;
162 size_t i;
163
164 if (writeflag == MEM_WRITE)
165 idata = memory_readmax64(cpu, data, len);
166
167 /*
168 * Set crime version/revision:
169 *
170 * 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 *
174 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
175 * that's something one has to live with. (TODO?)
176 */
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 int j;
217
218 /* This is used by the IP32 PROM's
219 "reboot" command: */
220 for (j=0; j<cpu->machine->ncpus; j++)
221 cpu->machine->cpus[j]->running = 0;
222 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
232 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
233 case CRIME_INTSTAT + 4:
234 case CRIME_INTMASK: /* 0x018, Current interrupt mask */
235 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 case 0x34:
245 /* don't dump debug info for these */
246 break;
247
248 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 void dev_crime_init(struct machine *machine, struct memory *mem,
271 uint64_t baseaddr, char *irq_path, int use_fb)
272 {
273 struct crime_data *d;
274 char tmpstr[200];
275 int i;
276
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 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 memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
302 dev_crime_access, d, DM_DEFAULT, NULL);
303
304 snprintf(tmpstr, sizeof(tmpstr), "mace addr=0x1f310000 irq=%s.crime",
305 irq_path);
306 device_add(machine, tmpstr);
307
308 machine_add_tickfunction(machine, dev_crime_tick, d,
309 CRIME_TICKSHIFT, 0.0);
310 }
311
312
313 /****************************************************************************/
314
315
316 #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 /*
325 * mace_interrupt_assert():
326 * mace_interrupt_deassert():
327 */
328 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 DEVICE_ACCESS(mace)
371 {
372 size_t i;
373 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 switch (relative_addr) {
381
382 case MACE_ISA_INT_STATUS: /* Current interrupt assertions */
383 case MACE_ISA_INT_STATUS + 4:
384 /* don't dump debug info for these */
385 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 break;
393 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 break;
407
408 default:
409 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 } 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 DEVINIT(mace)
427 {
428 struct mace_data *d;
429 char tmpstr[300];
430 int i;
431
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 snprintf(tmpstr, sizeof(tmpstr), "%s.0x%x",
440 devinit->interrupt_path, MACE_PERIPH_SERIAL);
441 INTERRUPT_CONNECT(tmpstr, d->irq_periph);
442
443 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 }
483
484
485 /****************************************************************************/
486
487
488 DEVICE_ACCESS(macepci)
489 {
490 struct macepci_data *d = (struct macepci_data *) extra;
491 uint64_t idata = 0, odata=0;
492 int regnr, res = 1, bus, dev, func, pcireg;
493
494 if (writeflag == MEM_WRITE)
495 idata = memory_readmax64(cpu, data, len);
496
497 regnr = relative_addr / sizeof(uint32_t);
498
499 /* Read from/write to the macepci: */
500 switch (relative_addr) {
501
502 case 0x00: /* Error address */
503 if (writeflag == MEM_WRITE) {
504 } else {
505 odata = 0;
506 }
507 break;
508
509 case 0x04: /* Error flags */
510 if (writeflag == MEM_WRITE) {
511 } else {
512 odata = 0x06;
513 }
514 break;
515
516 case 0x0c: /* Revision number */
517 if (writeflag == MEM_WRITE) {
518 } else {
519 odata = 0x01;
520 }
521 break;
522
523 case 0xcf8: /* PCI ADDR */
524 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 case 0xcfc: /* PCI DATA */
529 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
530 &odata : &idata, len, writeflag);
531 break;
532
533 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 struct pci_data *dev_macepci_init(struct machine *machine,
555 struct memory *mem, uint64_t baseaddr, char *irq_path)
556 {
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 /* TODO: PCI vs ISA interrupt? */
565
566 d->pci_data = bus_pci_init(machine,
567 irq_path,
568 0,
569 0,
570 0,
571 0,
572 "TODO: pci irq path",
573 0x18000003, /* ISA portbase */
574 0,
575 irq_path);
576
577 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
578 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
579
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 struct interrupt irq;
605 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 #if 0
703 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 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
729 (d->cur_rx_addr_index & 0x1f) << 8;
730 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 INTERRUPT_ASSERT(d->irq);
925 } else
926 INTERRUPT_DEASSERT(d->irq);
927 }
928
929
930 DEVICE_ACCESS(sgi_mec)
931 {
932 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
933 uint64_t idata = 0, odata = 0;
934 int regnr;
935
936 if (writeflag == MEM_WRITE)
937 idata = memory_readmax64(cpu, data, len);
938
939 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 uint64_t baseaddr, char *irq_path, unsigned char *macaddr)
1091 {
1092 char *name2;
1093 size_t nlen = 55;
1094 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
1102 INTERRUPT_CONNECT(irq_path, d->irq);
1103 memcpy(d->macaddr, macaddr, 6);
1104 mec_reset(d);
1105
1106 name2 = malloc(nlen);
1107 if (name2 == NULL) {
1108 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
1109 exit(1);
1110 }
1111 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
1112 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 DM_DEFAULT, NULL);
1118
1119 machine_add_tickfunction(machine, dev_sgi_mec_tick, d,
1120 MEC_TICK_SHIFT, 0.0);
1121
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 DEVICE_ACCESS(sgi_ust)
1135 {
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 debug("[ sgi_ust: unimplemented write to "
1156 "address 0x%llx, data=0x%016llx ]\n",
1157 (long long)relative_addr, (long long)idata);
1158 else
1159 debug("[ sgi_ust: unimplemented read from address"
1160 " 0x%llx ]\n", (long long)relative_addr);
1161 }
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 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1184 DM_DEFAULT, NULL);
1185 }
1186
1187
1188 /****************************************************************************/
1189
1190
1191 /*
1192 * SGI "mte". This device seems to be an accelerator for copying/clearing
1193 * memory. Used by (at least) the SGI O2 PROM.
1194 *
1195 * Actually, it seems to be used for graphics output as well. (?)
1196 * The O2's PROM uses it to output graphics.
1197 */
1198 /* #define debug fatal */
1199 /* #define MTE_DEBUG */
1200 #define ZERO_CHUNK_LEN 4096
1201
1202 struct sgi_mte_data {
1203 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1204 };
1205
1206
1207 DEVICE_ACCESS(sgi_mte)
1208 {
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 regnr = relative_addr / sizeof(uint32_t);
1217
1218 /*
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 if (writeflag == MEM_WRITE)
1232 d->reg[regnr] = idata;
1233 else
1234 odata = d->reg[regnr];
1235
1236 #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 /*
1244 * 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 *
1248 * 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 *
1255 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1256 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1257 * write to 0x1710, data=0x80001ea480001ea5
1258 * ...
1259 * write to 0x1770, data=0x80001e9c80001e9d
1260 * write to 0x1778, data=0x80001e9e80001e9f
1261 */
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 /* 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
1303 /* 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 uint32_t y;
1315
1316 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 size_t x, y;
1361
1362 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
1371 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 /* Operations: */
1392 case 0x3800:
1393 if (writeflag == MEM_WRITE) {
1394 switch (idata) {
1395 case 0x11: /* zerofill */
1396 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1397 last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1398 zerobuflen = last_addr - first_addr + 1;
1399 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
1404 /* TODO: is there a better way to
1405 implement this? */
1406 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 fatal("[ sgi_mte: UNKNOWN operation "
1423 "0x%x ]\n", idata);
1424 }
1425 }
1426 break;
1427 default:
1428 if (writeflag == MEM_WRITE)
1429 debug("[ sgi_mte: unimplemented write to "
1430 "address 0x%llx, data=0x%016llx ]\n",
1431 (long long)relative_addr, (long long)idata);
1432 else
1433 debug("[ sgi_mte: unimplemented read from address"
1434 " 0x%llx ]\n", (long long)relative_addr);
1435 }
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 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1458 }
1459

  ViewVC Help
Powered by ViewVC 1.1.26