/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 37529 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26