/[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 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 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 dpavlin 4 /*
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 dpavlin 12 * $Id: dev_sgi_ip32.c,v 1.29 2005/08/13 08:25:48 debug Exp $
29 dpavlin 4 *
30     * SGI IP32 devices.
31     *
32     * o) CRIME
33     * o) MACE
34     * o) MACE PCI bus
35     * o) mec (ethernet)
36     * o) ust (unknown device)
37     * o) mte (memory transfer engine? details unknown)
38     */
39    
40     #include <stdio.h>
41     #include <stdlib.h>
42     #include <string.h>
43    
44     #include "bus_pci.h"
45     #include "console.h"
46     #include "cpu.h"
47     #include "devices.h"
48     #include "emul.h"
49     #include "machine.h"
50     #include "memory.h"
51     #include "misc.h"
52     #include "net.h"
53    
54     #include "crimereg.h"
55    
56     #include "if_mecreg.h"
57    
58    
59     #define CRIME_TICKSHIFT 14
60     #define CRIME_SPEED_MUL_FACTOR 1
61     #define CRIME_SPEED_DIV_FACTOR 1
62    
63     struct macepci_data {
64     struct pci_data *pci_data;
65     uint32_t reg[DEV_MACEPCI_LENGTH / 4];
66     };
67    
68    
69     /*
70     * dev_crime_tick():
71     *
72     * This function simply updates CRIME_TIME each tick.
73     *
74     * The names DIV and MUL may be a bit confusing. Increasing the
75     * MUL factor will result in an OS running on the emulated machine
76     * detecting a faster CPU. Increasing the DIV factor will result
77     * in a slower detected CPU.
78     *
79     * A R10000 is detected as running at
80     * CRIME_SPEED_FACTOR * 66 MHz. (TODO: this is not correct anymore)
81     */
82     void dev_crime_tick(struct cpu *cpu, void *extra)
83     {
84     int j, carry, old, new, add_byte;
85     uint64_t what_to_add = (1<<CRIME_TICKSHIFT)
86     * CRIME_SPEED_DIV_FACTOR / CRIME_SPEED_MUL_FACTOR;
87     struct crime_data *d = extra;
88    
89     j = 0;
90     carry = 0;
91     while (j < 8) {
92     old = d->reg[CRIME_TIME + 7 - j];
93     add_byte = what_to_add >> ((int64_t)j * 8);
94     add_byte &= 255;
95     new = old + add_byte + carry;
96     d->reg[CRIME_TIME + 7 - j] = new & 255;
97     if (new >= 256)
98     carry = 1;
99     else
100     carry = 0;
101     j++;
102     }
103     }
104    
105    
106     /*
107     * dev_crime_access():
108     */
109     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 dpavlin 10 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
158     (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
159 dpavlin 4 /*
160     * Force interrupt re-assertion:
161     *
162     * NOTE: Ugly hack. Hopefully CRMERR is never used.
163     */
164     #if 0
165 dpavlin 10 /*
166 dpavlin 4 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
167     TODO.
168 dpavlin 10 */
169 dpavlin 4 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 dpavlin 10 #if 0
200 dpavlin 4 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 dpavlin 10 #endif
208 dpavlin 4 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 dpavlin 10 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 dpavlin 4 switch (relative_addr) {
275     #if 0
276 dpavlin 10 case 0x10: /* Current interrupt assertions */
277     case 0x14:
278 dpavlin 4 /* don't dump debug info for these */
279 dpavlin 10 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 dpavlin 4 break;
287 dpavlin 10 case 0x18: /* Interrupt mask */
288     case 0x1c:
289     /* don't dump debug info for these */
290     break;
291 dpavlin 4 #endif
292     default:
293 dpavlin 10 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 dpavlin 4 } 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 dpavlin 10 #if 0
540 dpavlin 4 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 dpavlin 12 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
566     (d->cur_rx_addr_index & 0x1f) << 8;
567 dpavlin 4 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 dpavlin 10 size_t nlen = 55;
934 dpavlin 4 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 dpavlin 10 name2 = malloc(nlen);
947 dpavlin 4 if (name2 == NULL) {
948     fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
949     exit(1);
950     }
951 dpavlin 10 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
952 dpavlin 4 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 dpavlin 12 debug("[ sgi_ust: unimplemented write to "
1000     "address 0x%llx, data=0x%016llx ]\n",
1001     (long long)relative_addr, (long long)idata);
1002 dpavlin 4 else
1003 dpavlin 12 debug("[ sgi_ust: unimplemented read from address"
1004     " 0x%llx ]\n", (long long)relative_addr);
1005 dpavlin 4 }
1006    
1007     if (writeflag == MEM_READ)
1008     memory_writemax64(cpu, data, len, odata);
1009    
1010     return 1;
1011     }
1012    
1013    
1014     /*
1015     * dev_sgi_ust_init():
1016     */
1017     void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1018     {
1019     struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1020     if (d == NULL) {
1021     fprintf(stderr, "out of memory\n");
1022     exit(1);
1023     }
1024     memset(d, 0, sizeof(struct sgi_ust_data));
1025    
1026     memory_device_register(mem, "sgi_ust", baseaddr,
1027 dpavlin 12 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1028     MEM_DEFAULT, NULL);
1029 dpavlin 4 }
1030    
1031    
1032     /****************************************************************************/
1033    
1034    
1035     /*
1036     * SGI "mte". This device seems to be an accelerator for copying/clearing
1037 dpavlin 12 * memory. Used by (at least) the SGI O2 PROM.
1038     *
1039     * Actually, it seems to be used for graphics output as well. (?)
1040     * TODO: Run the O2's prom and try to figure out what it really does.
1041 dpavlin 4 */
1042 dpavlin 12 /* #define debug fatal */
1043 dpavlin 4 #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 dpavlin 12 * 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 dpavlin 4 *
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 dpavlin 12 #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 dpavlin 4 /* 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