/[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 12 - (show annotations)
Mon Oct 8 16:18:38 2007 UTC (12 years, 2 months ago) by dpavlin
File MIME type: text/plain
File size: 31021 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26