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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 5 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 /*
2 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_sgi_ip32.c,v 1.53 2007/06/15 19:57:34 debug Exp $
29 *
30 * COMMENT: SGI IP32 stuff (CRIME, MACE, MACEPCI, mec, ust, mte)
31 *
32 * o) CRIME
33 * o) MACE
34 * o) MACE PCI bus
35 * o) mec (ethernet)
36 * o) ust (unknown device)
37 * o) mte (memory transfer engine? details unknown)
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "bus_pci.h"
45 #include "console.h"
46 #include "cpu.h"
47 #include "device.h"
48 #include "devices.h"
49 #include "emul.h"
50 #include "machine.h"
51 #include "memory.h"
52 #include "misc.h"
53 #include "net.h"
54
55 #include "crimereg.h"
56 #include "if_mecreg.h"
57 #include "sgi_macereg.h"
58
59
60 #define CRIME_TICKSHIFT 14
61 #define CRIME_SPEED_MUL_FACTOR 1
62 #define CRIME_SPEED_DIV_FACTOR 1
63
64 struct macepci_data {
65 struct pci_data *pci_data;
66 uint32_t reg[DEV_MACEPCI_LENGTH / 4];
67 };
68
69 #define DEV_CRIME_LENGTH 0x1000
70 struct crime_data {
71 unsigned char reg[DEV_CRIME_LENGTH];
72 struct interrupt irq;
73 int use_fb;
74 };
75
76
77 /*
78 * crime_interrupt_assert():
79 * crime_interrupt_deassert():
80 */
81 void crime_interrupt_assert(struct interrupt *interrupt)
82 {
83 struct crime_data *d = (struct crime_data *) interrupt->extra;
84 uint32_t line = interrupt->line, asserted;
85
86 d->reg[CRIME_INTSTAT + 4] |= ((line >> 24) & 255);
87 d->reg[CRIME_INTSTAT + 5] |= ((line >> 16) & 255);
88 d->reg[CRIME_INTSTAT + 6] |= ((line >> 8) & 255);
89 d->reg[CRIME_INTSTAT + 7] |= (line & 255);
90
91 asserted =
92 (d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
93 (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
94 (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
95 (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]);
96
97 if (asserted)
98 INTERRUPT_ASSERT(d->irq);
99 }
100 void crime_interrupt_deassert(struct interrupt *interrupt)
101 {
102 struct crime_data *d = (struct crime_data *) interrupt->extra;
103 uint32_t line = interrupt->line, asserted;
104
105 d->reg[CRIME_INTSTAT + 4] &= ~((line >> 24) & 255);
106 d->reg[CRIME_INTSTAT + 5] &= ~((line >> 16) & 255);
107 d->reg[CRIME_INTSTAT + 6] &= ~((line >> 8) & 255);
108 d->reg[CRIME_INTSTAT + 7] &= ~(line & 255);
109
110 asserted =
111 (d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
112 (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
113 (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
114 (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]);
115
116 if (!asserted)
117 INTERRUPT_DEASSERT(d->irq);
118 }
119
120
121 /*
122 * dev_crime_tick():
123 *
124 * This function simply updates CRIME_TIME each tick.
125 *
126 * The names DIV and MUL may be a bit confusing. Increasing the
127 * MUL factor will result in an OS running on the emulated machine
128 * detecting a faster CPU. Increasing the DIV factor will result
129 * in a slower detected CPU.
130 *
131 * A R10000 is detected as running at
132 * CRIME_SPEED_FACTOR * 66 MHz. (TODO: this is not correct anymore)
133 */
134 DEVICE_TICK(crime)
135 {
136 int j, carry, old, new, add_byte;
137 uint64_t what_to_add = (1<<CRIME_TICKSHIFT)
138 * CRIME_SPEED_DIV_FACTOR / CRIME_SPEED_MUL_FACTOR;
139 struct crime_data *d = extra;
140
141 j = 0;
142 carry = 0;
143 while (j < 8) {
144 old = d->reg[CRIME_TIME + 7 - j];
145 add_byte = what_to_add >> ((int64_t)j * 8);
146 add_byte &= 255;
147 new = old + add_byte + carry;
148 d->reg[CRIME_TIME + 7 - j] = new & 255;
149 if (new >= 256)
150 carry = 1;
151 else
152 carry = 0;
153 j++;
154 }
155 }
156
157
158 DEVICE_ACCESS(crime)
159 {
160 struct crime_data *d = extra;
161 uint64_t idata = 0;
162 size_t i;
163
164 if (writeflag == MEM_WRITE)
165 idata = memory_readmax64(cpu, data, len);
166
167 /*
168 * Set crime version/revision:
169 *
170 * This might not be the most elegant or correct solution, but it
171 * seems that the IP32 PROM likes 0x11 for machines without graphics,
172 * and 0xa1 for machines with graphics.
173 *
174 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
175 * that's something one has to live with. (TODO?)
176 */
177 d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
178 d->reg[7] = d->use_fb? 0xa1 : 0x11;
179
180 /*
181 * Amount of memory. Bit 8 of bank control set ==> 128MB instead
182 * of 32MB per bank (?)
183 *
184 * When the bank control registers contain the same value as the
185 * previous one, that bank is not valid. (?)
186 */
187 d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
188 d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
189 d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
190 d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
191
192 if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
193 if (writeflag == MEM_READ)
194 memcpy(data, &d->reg[relative_addr], len);
195 return 1;
196 }
197
198 if (writeflag == MEM_WRITE)
199 memcpy(&d->reg[relative_addr], data, len);
200 else
201 memcpy(data, &d->reg[relative_addr], len);
202
203 switch (relative_addr) {
204 case CRIME_CONTROL: /* 0x008 */
205 /* TODO: 64-bit write to CRIME_CONTROL, but some things
206 (such as NetBSD 1.6.2) write to 0x00c! */
207 if (writeflag == MEM_WRITE) {
208 /*
209 * 0x200 = watchdog timer (according to NetBSD)
210 * 0x800 = "reboot" used by the IP32 PROM
211 */
212 if (idata & 0x200) {
213 idata &= ~0x200;
214 }
215 if (idata & 0x800) {
216 int j;
217
218 /* This is used by the IP32 PROM's
219 "reboot" command: */
220 for (j=0; j<cpu->machine->ncpus; j++)
221 cpu->machine->cpus[j]->running = 0;
222 cpu->machine->
223 exit_without_entering_debugger = 1;
224 idata &= ~0x800;
225 }
226 if (idata != 0)
227 fatal("[ CRIME_CONTROL: unimplemented "
228 "control 0x%016llx ]\n", (long long)idata);
229 }
230 break;
231
232 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
233 case CRIME_INTSTAT + 4:
234 case CRIME_INTMASK: /* 0x018, Current interrupt mask */
235 case CRIME_INTMASK + 4:
236 if ((d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
237 (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
238 (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
239 (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]) )
240 INTERRUPT_ASSERT(d->irq);
241 else
242 INTERRUPT_DEASSERT(d->irq);
243 break;
244 case 0x34:
245 /* don't dump debug info for these */
246 break;
247
248 default:
249 if (writeflag==MEM_READ) {
250 debug("[ crime: read from 0x%x, len=%i:",
251 (int)relative_addr, len);
252 for (i=0; i<len; i++)
253 debug(" %02x", data[i]);
254 debug(" ]\n");
255 } else {
256 debug("[ crime: write to 0x%x:", (int)relative_addr);
257 for (i=0; i<len; i++)
258 debug(" %02x", data[i]);
259 debug(" (len=%i) ]\n", len);
260 }
261 }
262
263 return 1;
264 }
265
266
267 /*
268 * dev_crime_init():
269 */
270 void dev_crime_init(struct machine *machine, struct memory *mem,
271 uint64_t baseaddr, char *irq_path, int use_fb)
272 {
273 struct crime_data *d;
274 char tmpstr[200];
275 int i;
276
277 CHECK_ALLOCATION(d = malloc(sizeof(struct crime_data)));
278 memset(d, 0, sizeof(struct crime_data));
279
280 d->use_fb = use_fb;
281
282 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 memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
299 dev_crime_access, d, DM_DEFAULT, NULL);
300
301 snprintf(tmpstr, sizeof(tmpstr), "mace addr=0x1f310000 irq=%s.crime",
302 irq_path);
303 device_add(machine, tmpstr);
304
305 machine_add_tickfunction(machine, dev_crime_tick, d,
306 CRIME_TICKSHIFT);
307 }
308
309
310 /****************************************************************************/
311
312
313 #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 /*
322 * mace_interrupt_assert():
323 * mace_interrupt_deassert():
324 */
325 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 DEVICE_ACCESS(mace)
368 {
369 size_t i;
370 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 switch (relative_addr) {
378
379 case MACE_ISA_INT_STATUS: /* Current interrupt assertions */
380 case MACE_ISA_INT_STATUS + 4:
381 /* don't dump debug info for these */
382 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 break;
390 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 break;
404
405 default:
406 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 } 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 DEVINIT(mace)
424 {
425 struct mace_data *d;
426 char tmpstr[300];
427 int i;
428
429 CHECK_ALLOCATION(d = malloc(sizeof(struct mace_data)));
430 memset(d, 0, sizeof(struct mace_data));
431
432 snprintf(tmpstr, sizeof(tmpstr), "%s.0x%x",
433 devinit->interrupt_path, MACE_PERIPH_SERIAL);
434 INTERRUPT_CONNECT(tmpstr, d->irq_periph);
435
436 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 }
476
477
478 /****************************************************************************/
479
480
481 DEVICE_ACCESS(macepci)
482 {
483 struct macepci_data *d = extra;
484 uint64_t idata = 0, odata=0;
485 int regnr, res = 1, bus, dev, func, pcireg;
486
487 if (writeflag == MEM_WRITE)
488 idata = memory_readmax64(cpu, data, len);
489
490 regnr = relative_addr / sizeof(uint32_t);
491
492 /* Read from/write to the macepci: */
493 switch (relative_addr) {
494
495 case 0x00: /* Error address */
496 if (writeflag == MEM_WRITE) {
497 } else {
498 odata = 0;
499 }
500 break;
501
502 case 0x04: /* Error flags */
503 if (writeflag == MEM_WRITE) {
504 } else {
505 odata = 0x06;
506 }
507 break;
508
509 case 0x0c: /* Revision number */
510 if (writeflag == MEM_WRITE) {
511 } else {
512 odata = 0x01;
513 }
514 break;
515
516 case 0xcf8: /* PCI ADDR */
517 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 case 0xcfc: /* PCI DATA */
522 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
523 &odata : &idata, len, writeflag);
524 break;
525
526 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 struct pci_data *dev_macepci_init(struct machine *machine,
548 struct memory *mem, uint64_t baseaddr, char *irq_path)
549 {
550 struct macepci_data *d;
551
552 CHECK_ALLOCATION(d = malloc(sizeof(struct macepci_data)));
553 memset(d, 0, sizeof(struct macepci_data));
554
555 /* TODO: PCI vs ISA interrupt? */
556
557 d->pci_data = bus_pci_init(machine,
558 irq_path,
559 0,
560 0,
561 0,
562 0,
563 "TODO: pci irq path",
564 0x18000003, /* ISA portbase */
565 0,
566 irq_path);
567
568 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
569 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
570
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 struct interrupt irq;
596 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 #if 0
694 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 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
720 (d->cur_rx_addr_index & 0x1f) << 8;
721 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 DEVICE_TICK(sgi_mec)
895 {
896 struct sgi_mec_data *d = extra;
897 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 INTERRUPT_ASSERT(d->irq);
913 } else
914 INTERRUPT_DEASSERT(d->irq);
915 }
916
917
918 DEVICE_ACCESS(sgi_mec)
919 {
920 struct sgi_mec_data *d = extra;
921 uint64_t idata = 0, odata = 0;
922 int regnr;
923
924 if (writeflag == MEM_WRITE)
925 idata = memory_readmax64(cpu, data, len);
926
927 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 uint64_t baseaddr, char *irq_path, unsigned char *macaddr)
1079 {
1080 char *name2;
1081 size_t nlen = 55;
1082 struct sgi_mec_data *d;
1083
1084 CHECK_ALLOCATION(d = malloc(sizeof(struct sgi_mec_data)));
1085 memset(d, 0, sizeof(struct sgi_mec_data));
1086
1087 INTERRUPT_CONNECT(irq_path, d->irq);
1088 memcpy(d->macaddr, macaddr, 6);
1089 mec_reset(d);
1090
1091 CHECK_ALLOCATION(name2 = malloc(nlen));
1092 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
1093 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 DM_DEFAULT, NULL);
1099
1100 machine_add_tickfunction(machine, dev_sgi_mec_tick, d,
1101 MEC_TICK_SHIFT);
1102
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 DEVICE_ACCESS(sgi_ust)
1116 {
1117 struct sgi_ust_data *d = extra;
1118 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 debug("[ sgi_ust: unimplemented write to "
1137 "address 0x%llx, data=0x%016llx ]\n",
1138 (long long)relative_addr, (long long)idata);
1139 else
1140 debug("[ sgi_ust: unimplemented read from address"
1141 " 0x%llx ]\n", (long long)relative_addr);
1142 }
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 struct sgi_ust_data *d;
1157
1158 CHECK_ALLOCATION(d = malloc(sizeof(struct sgi_ust_data)));
1159 memset(d, 0, sizeof(struct sgi_ust_data));
1160
1161 memory_device_register(mem, "sgi_ust", baseaddr,
1162 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1163 DM_DEFAULT, NULL);
1164 }
1165
1166
1167 /****************************************************************************/
1168
1169
1170 /*
1171 * SGI "mte". This device seems to be an accelerator for copying/clearing
1172 * memory. Used by (at least) the SGI O2 PROM.
1173 *
1174 * Actually, it seems to be used for graphics output as well. (?)
1175 * The O2's PROM uses it to output graphics.
1176 */
1177 /* #define debug fatal */
1178 /* #define MTE_DEBUG */
1179 #define ZERO_CHUNK_LEN 4096
1180
1181 struct sgi_mte_data {
1182 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1183 };
1184
1185
1186 DEVICE_ACCESS(sgi_mte)
1187 {
1188 struct sgi_mte_data *d = extra;
1189 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 regnr = relative_addr / sizeof(uint32_t);
1196
1197 /*
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 if (writeflag == MEM_WRITE)
1211 d->reg[regnr] = idata;
1212 else
1213 odata = d->reg[regnr];
1214
1215 #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 /*
1223 * 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 *
1227 * 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 *
1234 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1235 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1236 * write to 0x1710, data=0x80001ea480001ea5
1237 * ...
1238 * write to 0x1770, data=0x80001e9c80001e9d
1239 * write to 0x1778, data=0x80001e9e80001e9f
1240 */
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 /* 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
1282 /* 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 uint32_t y;
1294
1295 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 size_t x, y;
1340
1341 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
1350 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 /* Operations: */
1371 case 0x3800:
1372 if (writeflag == MEM_WRITE) {
1373 switch (idata) {
1374 case 0x11: /* zerofill */
1375 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1376 last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1377 zerobuflen = last_addr - first_addr + 1;
1378 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
1383 /* TODO: is there a better way to
1384 implement this? */
1385 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 fatal("[ sgi_mte: UNKNOWN operation "
1402 "0x%x ]\n", idata);
1403 }
1404 }
1405 break;
1406 default:
1407 if (writeflag == MEM_WRITE)
1408 debug("[ sgi_mte: unimplemented write to "
1409 "address 0x%llx, data=0x%016llx ]\n",
1410 (long long)relative_addr, (long long)idata);
1411 else
1412 debug("[ sgi_mte: unimplemented read from address"
1413 " 0x%llx ]\n", (long long)relative_addr);
1414 }
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 struct sgi_mte_data *d;
1429
1430 CHECK_ALLOCATION(d = malloc(sizeof(struct sgi_mte_data)));
1431 memset(d, 0, sizeof(struct sgi_mte_data));
1432
1433 memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1434 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1435 }
1436

  ViewVC Help
Powered by ViewVC 1.1.26