/[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 24 - (hide annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 32564 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26