/[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 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33110 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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 14 * $Id: dev_sgi_ip32.c,v 1.32 2005/08/19 09:43:35 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 dpavlin 14 * The O2's PROM uses it to output graphics.
1041 dpavlin 4 */
1042 dpavlin 12 /* #define debug fatal */
1043 dpavlin 14 /* #define MTE_DEBUG */
1044 dpavlin 4 #define ZERO_CHUNK_LEN 4096
1045    
1046     struct sgi_mte_data {
1047 dpavlin 14 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1048 dpavlin 4 };
1049    
1050     /*
1051     * dev_sgi_mte_access():
1052     */
1053     int dev_sgi_mte_access(struct cpu *cpu, struct memory *mem,
1054     uint64_t relative_addr, unsigned char *data, size_t len,
1055     int writeflag, void *extra)
1056     {
1057     struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1058     uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1059     unsigned char zerobuf[ZERO_CHUNK_LEN];
1060     uint64_t idata = 0, odata = 0;
1061     int regnr;
1062    
1063     idata = memory_readmax64(cpu, data, len);
1064 dpavlin 14 regnr = relative_addr / sizeof(uint32_t);
1065 dpavlin 4
1066 dpavlin 14 /*
1067     * Treat all registers as read/write, by default. Sometimes these
1068     * are accessed as 32-bit words, sometimes as 64-bit words.
1069     */
1070     if (len != 4) {
1071     if (writeflag == MEM_WRITE) {
1072     d->reg[regnr] = idata >> 32;
1073     d->reg[regnr+1] = idata;
1074     } else
1075     odata = ((uint64_t)d->reg[regnr] << 32) +
1076     d->reg[regnr+1];
1077     }
1078    
1079 dpavlin 4 if (writeflag == MEM_WRITE)
1080     d->reg[regnr] = idata;
1081     else
1082     odata = d->reg[regnr];
1083    
1084 dpavlin 14 #ifdef MTE_DEBUG
1085     if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1086     relative_addr < 0x3000)
1087     fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1088     (long long)idata);
1089     #endif
1090    
1091 dpavlin 4 /*
1092 dpavlin 12 * I've not found any docs about this 'mte' device at all, so this is
1093     * just a guess. The mte seems to be used for copying and zeroing
1094     * chunks of memory.
1095 dpavlin 4 *
1096 dpavlin 14 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1097     * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1098     * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1099     * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1100     * write to 0x3800, data=0x0000000000000011 ] <-- operation
1101     * (0x11 = zerofill)
1102 dpavlin 4 *
1103 dpavlin 14 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1104     * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1105     * write to 0x1710, data=0x80001ea480001ea5
1106 dpavlin 4 * ...
1107 dpavlin 14 * write to 0x1770, data=0x80001e9c80001e9d
1108     * write to 0x1778, data=0x80001e9e80001e9f
1109 dpavlin 4 */
1110     switch (relative_addr) {
1111    
1112     /* No warnings for these: */
1113     case 0x3030:
1114     case 0x3038:
1115     break;
1116    
1117     /* Unknown, but no warning: */
1118     case 0x4000:
1119     case 0x3018:
1120     case 0x3008:
1121     case 0x1700:
1122     case 0x1708:
1123     case 0x1710:
1124     case 0x1718:
1125     case 0x1720:
1126     case 0x1728:
1127     case 0x1730:
1128     case 0x1738:
1129     case 0x1740:
1130     case 0x1748:
1131     case 0x1750:
1132     case 0x1758:
1133     case 0x1760:
1134     case 0x1768:
1135     case 0x1770:
1136     case 0x1778:
1137     break;
1138    
1139 dpavlin 14 /* Graphics stuff? No warning: */
1140     case 0x2018:
1141     case 0x2060:
1142     case 0x2070:
1143     case 0x2074:
1144     case 0x20c0:
1145     case 0x20c4:
1146     case 0x20d0:
1147     case 0x21b0:
1148     case 0x21b8:
1149     break;
1150 dpavlin 12
1151 dpavlin 14 /* Perform graphics operation: */
1152     case 0x21f8:
1153     {
1154     uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1155     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1156     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1157     >> 16) & 0xfff;
1158     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1159     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1160     >> 16) & 0xfff;
1161     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1162     int y;
1163 dpavlin 12
1164 dpavlin 14 op >>= 24;
1165    
1166     switch (op) {
1167     case 1: /* Unknown. Used after drawing bitmaps? */
1168     break;
1169     case 3: /* Fill: */
1170     if (x2 < x1) {
1171     int tmp = x1; x1 = x2; x2 = tmp;
1172     }
1173     if (y2 < y1) {
1174     int tmp = y1; y1 = y2; y2 = tmp;
1175     }
1176     for (y=y1; y<=y2; y++) {
1177     unsigned char buf[1280];
1178     int length = x2-x1+1;
1179     int addr = (x1 + y*1280);
1180     if (length < 1)
1181     length = 1;
1182     memset(buf, color, length);
1183     if (x1 < 1280 && y < 1024)
1184     cpu->memory_rw(cpu, cpu->mem,
1185     0x38000000 + addr, buf,
1186     length, MEM_WRITE,
1187     NO_EXCEPTIONS | PHYSICAL);
1188     }
1189     break;
1190    
1191     default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1192     "%i,%i\n\n", op, color, x1,y1, x2,y2);
1193     }
1194     }
1195     break;
1196    
1197     case 0x29f0:
1198     /* Pixel output: */
1199     {
1200     uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1201     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1202     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1203     >> 16) & 0xfff;
1204     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1205     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1206     >> 16) & 0xfff;
1207     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1208     int x,y;
1209     if (x2 < x1) {
1210     int tmp = x1; x1 = x2; x2 = tmp;
1211     }
1212     if (y2 < y1) {
1213     int tmp = y1; y1 = y2; y2 = tmp;
1214     }
1215     if (x2-x1 <= 15)
1216     data <<= 16;
1217     x=x1; y=y1;
1218     while (x <= x2 && y <= y2) {
1219     unsigned char buf = color;
1220     int addr = x + y*1280;
1221     int bit_set = data & 0x80000000UL;
1222     data <<= 1;
1223     if (x < 1280 && y < 1024 && bit_set)
1224     cpu->memory_rw(cpu, cpu->mem,
1225     0x38000000 + addr, &buf,1,MEM_WRITE,
1226     NO_EXCEPTIONS | PHYSICAL);
1227     x++;
1228     if (x > x2) {
1229     x = x1;
1230     y++;
1231     }
1232     }
1233     }
1234     break;
1235    
1236    
1237 dpavlin 4 /* Operations: */
1238     case 0x3800:
1239     if (writeflag == MEM_WRITE) {
1240     switch (idata) {
1241     case 0x11: /* zerofill */
1242 dpavlin 14 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1243     last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1244 dpavlin 4 zerobuflen = last_addr - first_addr + 1;
1245 dpavlin 14 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1246     " last = 0x%016llx, length = 0x%llx ]\n",
1247     (long long)first_addr, (long long)
1248     last_addr, (long long)zerobuflen);
1249 dpavlin 4
1250 dpavlin 14 /* TODO: is there a better way to
1251     implement this? */
1252 dpavlin 4 memset(zerobuf, 0, sizeof(zerobuf));
1253     fill_addr = first_addr;
1254     while (zerobuflen != 0) {
1255     if (zerobuflen > sizeof(zerobuf))
1256     fill_len = sizeof(zerobuf);
1257     else
1258     fill_len = zerobuflen;
1259     cpu->memory_rw(cpu, mem, fill_addr,
1260     zerobuf, fill_len, MEM_WRITE,
1261     NO_EXCEPTIONS | PHYSICAL);
1262     fill_addr += fill_len;
1263     zerobuflen -= sizeof(zerobuf);
1264     }
1265    
1266     break;
1267     default:
1268 dpavlin 14 fatal("[ sgi_mte: UNKNOWN operation "
1269     "0x%x ]\n", idata);
1270 dpavlin 4 }
1271     }
1272     break;
1273     default:
1274     if (writeflag == MEM_WRITE)
1275 dpavlin 14 debug("[ sgi_mte: unimplemented write to "
1276     "address 0x%llx, data=0x%016llx ]\n",
1277     (long long)relative_addr, (long long)idata);
1278 dpavlin 4 else
1279 dpavlin 14 debug("[ sgi_mte: unimplemented read from address"
1280     " 0x%llx ]\n", (long long)relative_addr);
1281 dpavlin 4 }
1282    
1283     if (writeflag == MEM_READ)
1284     memory_writemax64(cpu, data, len, odata);
1285    
1286     return 1;
1287     }
1288    
1289    
1290     /*
1291     * dev_sgi_mte_init():
1292     */
1293     void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1294     {
1295     struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1296     if (d == NULL) {
1297     fprintf(stderr, "out of memory\n");
1298     exit(1);
1299     }
1300     memset(d, 0, sizeof(struct sgi_mte_data));
1301    
1302     memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1303     dev_sgi_mte_access, (void *)d, MEM_DEFAULT, NULL);
1304     }
1305    

  ViewVC Help
Powered by ViewVC 1.1.26