/[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 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 32544 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


1 dpavlin 4 /*
2 dpavlin 22 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 4 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 22 * $Id: dev_sgi_ip32.c,v 1.44 2006/01/01 13:17:17 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 dpavlin 22 DEVICE_ACCESS(crime)
110 dpavlin 4 {
111 dpavlin 18 struct crime_data *d = extra;
112     uint64_t idata = 0;
113 dpavlin 22 size_t i;
114 dpavlin 4
115 dpavlin 18 if (writeflag == MEM_WRITE)
116     idata = memory_readmax64(cpu, data, len);
117 dpavlin 4
118     /*
119     * Set crime version/revision:
120     *
121 dpavlin 18 * This might not be the most elegant or correct solution, but it
122     * seems that the IP32 PROM likes 0x11 for machines without graphics,
123     * and 0xa1 for machines with graphics.
124 dpavlin 4 *
125 dpavlin 18 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
126     * that's something one has to live with. (TODO?)
127 dpavlin 4 */
128     d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
129     d->reg[7] = d->use_fb? 0xa1 : 0x11;
130    
131     /*
132     * Amount of memory. Bit 8 of bank control set ==> 128MB instead
133     * of 32MB per bank (?)
134     *
135     * When the bank control registers contain the same value as the
136     * previous one, that bank is not valid. (?)
137     */
138     d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
139     d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
140     d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
141     d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
142    
143     if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
144     if (writeflag == MEM_READ)
145     memcpy(data, &d->reg[relative_addr], len);
146     return 1;
147     }
148    
149     if (writeflag == MEM_WRITE)
150     memcpy(&d->reg[relative_addr], data, len);
151     else
152     memcpy(data, &d->reg[relative_addr], len);
153    
154 dpavlin 10 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
155     (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
156 dpavlin 4 /*
157     * Force interrupt re-assertion:
158     *
159     * NOTE: Ugly hack. Hopefully CRMERR is never used.
160     */
161     #if 0
162 dpavlin 10 /*
163 dpavlin 4 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
164     TODO.
165 dpavlin 10 */
166 dpavlin 4 cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
167     #endif
168     }
169    
170     switch (relative_addr) {
171     case CRIME_CONTROL: /* 0x008 */
172     /* TODO: 64-bit write to CRIME_CONTROL, but some things
173     (such as NetBSD 1.6.2) write to 0x00c! */
174     if (writeflag == MEM_WRITE) {
175     /*
176     * 0x200 = watchdog timer (according to NetBSD)
177     * 0x800 = "reboot" used by the IP32 PROM
178     */
179     if (idata & 0x200) {
180     idata &= ~0x200;
181     }
182     if (idata & 0x800) {
183 dpavlin 22 int j;
184    
185 dpavlin 4 /* This is used by the IP32 PROM's
186     "reboot" command: */
187 dpavlin 22 for (j=0; j<cpu->machine->ncpus; j++)
188     cpu->machine->cpus[j]->running = 0;
189 dpavlin 4 cpu->machine->
190     exit_without_entering_debugger = 1;
191     idata &= ~0x800;
192     }
193     if (idata != 0)
194     fatal("[ CRIME_CONTROL: unimplemented "
195     "control 0x%016llx ]\n", (long long)idata);
196     }
197     break;
198 dpavlin 10 #if 0
199 dpavlin 4 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
200     case 0x14:
201     case CRIME_INTMASK: /* 0x018, Current interrupt mask */
202     case 0x1c:
203     case 0x34:
204     /* don't dump debug info for these */
205     break;
206 dpavlin 10 #endif
207 dpavlin 4 default:
208     if (writeflag==MEM_READ) {
209     debug("[ crime: read from 0x%x, len=%i:",
210     (int)relative_addr, len);
211     for (i=0; i<len; i++)
212     debug(" %02x", data[i]);
213     debug(" ]\n");
214     } else {
215     debug("[ crime: write to 0x%x:", (int)relative_addr);
216     for (i=0; i<len; i++)
217     debug(" %02x", data[i]);
218     debug(" (len=%i) ]\n", len);
219     }
220     }
221    
222     return 1;
223     }
224    
225    
226     /*
227     * dev_crime_init():
228     */
229     struct crime_data *dev_crime_init(struct machine *machine, struct memory *mem,
230     uint64_t baseaddr, int irq_nr, int use_fb)
231     {
232     struct crime_data *d;
233    
234     d = malloc(sizeof(struct crime_data));
235     if (d == NULL) {
236     fprintf(stderr, "out of memory\n");
237     exit(1);
238     }
239     memset(d, 0, sizeof(struct crime_data));
240     d->irq_nr = irq_nr;
241     d->use_fb = use_fb;
242    
243     memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
244 dpavlin 20 dev_crime_access, d, DM_DEFAULT, NULL);
245 dpavlin 4 machine_add_tickfunction(machine, dev_crime_tick, d, CRIME_TICKSHIFT);
246    
247     return d;
248     }
249    
250    
251     /****************************************************************************/
252    
253    
254     /*
255     * dev_mace_access():
256     */
257 dpavlin 22 DEVICE_ACCESS(mace)
258 dpavlin 4 {
259 dpavlin 22 size_t i;
260 dpavlin 4 struct mace_data *d = extra;
261    
262     if (writeflag == MEM_WRITE)
263     memcpy(&d->reg[relative_addr], data, len);
264     else
265     memcpy(data, &d->reg[relative_addr], len);
266    
267 dpavlin 10 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
268     (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f))
269     cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
270    
271 dpavlin 4 switch (relative_addr) {
272     #if 0
273 dpavlin 10 case 0x10: /* Current interrupt assertions */
274     case 0x14:
275 dpavlin 4 /* don't dump debug info for these */
276 dpavlin 10 if (writeflag == MEM_WRITE) {
277     fatal("[ NOTE/TODO: WRITE to mace intr: "
278     "reladdr=0x%x data=", (int)relative_addr);
279     for (i=0; i<len; i++)
280     fatal(" %02x", data[i]);
281     fatal(" (len=%i) ]\n", len);
282     }
283 dpavlin 4 break;
284 dpavlin 10 case 0x18: /* Interrupt mask */
285     case 0x1c:
286     /* don't dump debug info for these */
287     break;
288 dpavlin 4 #endif
289     default:
290 dpavlin 10 if (writeflag == MEM_READ) {
291     debug("[ mace: read from 0x%x:", (int)relative_addr);
292     for (i=0; i<len; i++)
293     debug(" %02x", data[i]);
294     debug(" (len=%i) ]\n", len);
295 dpavlin 4 } else {
296     debug("[ mace: write to 0x%x:", (int)relative_addr);
297     for (i=0; i<len; i++)
298     debug(" %02x", data[i]);
299     debug(" (len=%i) ]\n", len);
300     }
301     }
302    
303     return 1;
304     }
305    
306    
307     /*
308     * dev_mace_init():
309     */
310     struct mace_data *dev_mace_init(struct memory *mem, uint64_t baseaddr,
311     int irqnr)
312     {
313     struct mace_data *d;
314    
315     d = malloc(sizeof(struct mace_data));
316     if (d == NULL) {
317     fprintf(stderr, "out of memory\n");
318     exit(1);
319     }
320     memset(d, 0, sizeof(struct mace_data));
321     d->irqnr = irqnr;
322    
323     memory_device_register(mem, "mace", baseaddr, DEV_MACE_LENGTH,
324 dpavlin 20 dev_mace_access, d, DM_DEFAULT, NULL);
325 dpavlin 4
326     return d;
327     }
328    
329    
330     /****************************************************************************/
331    
332    
333     /*
334     * dev_macepci_access():
335     */
336 dpavlin 22 DEVICE_ACCESS(macepci)
337 dpavlin 4 {
338     struct macepci_data *d = (struct macepci_data *) extra;
339     uint64_t idata = 0, odata=0;
340 dpavlin 22 int regnr, res = 1, bus, dev, func, pcireg;
341 dpavlin 4
342 dpavlin 18 if (writeflag == MEM_WRITE)
343     idata = memory_readmax64(cpu, data, len);
344    
345 dpavlin 4 regnr = relative_addr / sizeof(uint32_t);
346    
347     /* Read from/write to the macepci: */
348     switch (relative_addr) {
349 dpavlin 22
350 dpavlin 4 case 0x00: /* Error address */
351     if (writeflag == MEM_WRITE) {
352     } else {
353     odata = 0;
354     }
355     break;
356 dpavlin 22
357 dpavlin 4 case 0x04: /* Error flags */
358     if (writeflag == MEM_WRITE) {
359     } else {
360     odata = 0x06;
361     }
362     break;
363 dpavlin 22
364 dpavlin 4 case 0x0c: /* Revision number */
365     if (writeflag == MEM_WRITE) {
366     } else {
367     odata = 0x01;
368     }
369     break;
370 dpavlin 22
371 dpavlin 4 case 0xcf8: /* PCI ADDR */
372 dpavlin 22 bus_pci_decompose_1(idata, &bus, &dev, &func, &pcireg);
373     bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, pcireg);
374     break;
375    
376 dpavlin 4 case 0xcfc: /* PCI DATA */
377 dpavlin 22 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
378     &odata : &idata, len, writeflag);
379 dpavlin 4 break;
380 dpavlin 22
381 dpavlin 4 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 dpavlin 22 struct pci_data *dev_macepci_init(struct machine *machine,
403     struct memory *mem, uint64_t baseaddr, int pciirq)
404 dpavlin 4 {
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 dpavlin 22 d->pci_data = bus_pci_init(machine, pciirq, 0,0, 0,0,0, 0,0,0);
413 dpavlin 4
414     memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
415 dpavlin 20 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
416 dpavlin 4
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 dpavlin 22 DEVICE_ACCESS(sgi_mec)
771 dpavlin 4 {
772     struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
773     uint64_t idata = 0, odata = 0;
774     int regnr;
775    
776 dpavlin 18 if (writeflag == MEM_WRITE)
777     idata = memory_readmax64(cpu, data, len);
778    
779 dpavlin 4 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 dpavlin 20 DM_DEFAULT, NULL);
958 dpavlin 4
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 dpavlin 22 DEVICE_ACCESS(sgi_ust)
977 dpavlin 4 {
978     struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
979     uint64_t idata = 0, odata = 0;
980     int regnr;
981    
982     idata = memory_readmax64(cpu, data, len);
983     regnr = relative_addr / sizeof(uint64_t);
984    
985     /* Treat all registers as read/write, by default. */
986     if (writeflag == MEM_WRITE)
987     d->reg[regnr] = idata;
988     else
989     odata = d->reg[regnr];
990    
991     switch (relative_addr) {
992     case 0:
993     d->reg[regnr] += 0x2710;
994     break;
995     default:
996     if (writeflag == MEM_WRITE)
997 dpavlin 12 debug("[ sgi_ust: unimplemented write to "
998     "address 0x%llx, data=0x%016llx ]\n",
999     (long long)relative_addr, (long long)idata);
1000 dpavlin 4 else
1001 dpavlin 12 debug("[ sgi_ust: unimplemented read from address"
1002     " 0x%llx ]\n", (long long)relative_addr);
1003 dpavlin 4 }
1004    
1005     if (writeflag == MEM_READ)
1006     memory_writemax64(cpu, data, len, odata);
1007    
1008     return 1;
1009     }
1010    
1011    
1012     /*
1013     * dev_sgi_ust_init():
1014     */
1015     void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1016     {
1017     struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1018     if (d == NULL) {
1019     fprintf(stderr, "out of memory\n");
1020     exit(1);
1021     }
1022     memset(d, 0, sizeof(struct sgi_ust_data));
1023    
1024     memory_device_register(mem, "sgi_ust", baseaddr,
1025 dpavlin 12 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1026 dpavlin 20 DM_DEFAULT, NULL);
1027 dpavlin 4 }
1028    
1029    
1030     /****************************************************************************/
1031    
1032    
1033     /*
1034     * SGI "mte". This device seems to be an accelerator for copying/clearing
1035 dpavlin 12 * memory. Used by (at least) the SGI O2 PROM.
1036     *
1037     * Actually, it seems to be used for graphics output as well. (?)
1038 dpavlin 14 * The O2's PROM uses it to output graphics.
1039 dpavlin 4 */
1040 dpavlin 12 /* #define debug fatal */
1041 dpavlin 14 /* #define MTE_DEBUG */
1042 dpavlin 4 #define ZERO_CHUNK_LEN 4096
1043    
1044     struct sgi_mte_data {
1045 dpavlin 14 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1046 dpavlin 4 };
1047    
1048     /*
1049     * dev_sgi_mte_access():
1050     */
1051 dpavlin 22 DEVICE_ACCESS(sgi_mte)
1052 dpavlin 4 {
1053     struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1054     uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1055     unsigned char zerobuf[ZERO_CHUNK_LEN];
1056     uint64_t idata = 0, odata = 0;
1057     int regnr;
1058    
1059     idata = memory_readmax64(cpu, data, len);
1060 dpavlin 14 regnr = relative_addr / sizeof(uint32_t);
1061 dpavlin 4
1062 dpavlin 14 /*
1063     * Treat all registers as read/write, by default. Sometimes these
1064     * are accessed as 32-bit words, sometimes as 64-bit words.
1065     */
1066     if (len != 4) {
1067     if (writeflag == MEM_WRITE) {
1068     d->reg[regnr] = idata >> 32;
1069     d->reg[regnr+1] = idata;
1070     } else
1071     odata = ((uint64_t)d->reg[regnr] << 32) +
1072     d->reg[regnr+1];
1073     }
1074    
1075 dpavlin 4 if (writeflag == MEM_WRITE)
1076     d->reg[regnr] = idata;
1077     else
1078     odata = d->reg[regnr];
1079    
1080 dpavlin 14 #ifdef MTE_DEBUG
1081     if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1082     relative_addr < 0x3000)
1083     fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1084     (long long)idata);
1085     #endif
1086    
1087 dpavlin 4 /*
1088 dpavlin 12 * I've not found any docs about this 'mte' device at all, so this is
1089     * just a guess. The mte seems to be used for copying and zeroing
1090     * chunks of memory.
1091 dpavlin 4 *
1092 dpavlin 14 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1093     * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1094     * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1095     * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1096     * write to 0x3800, data=0x0000000000000011 ] <-- operation
1097     * (0x11 = zerofill)
1098 dpavlin 4 *
1099 dpavlin 14 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1100     * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1101     * write to 0x1710, data=0x80001ea480001ea5
1102 dpavlin 4 * ...
1103 dpavlin 14 * write to 0x1770, data=0x80001e9c80001e9d
1104     * write to 0x1778, data=0x80001e9e80001e9f
1105 dpavlin 4 */
1106     switch (relative_addr) {
1107    
1108     /* No warnings for these: */
1109     case 0x3030:
1110     case 0x3038:
1111     break;
1112    
1113     /* Unknown, but no warning: */
1114     case 0x4000:
1115     case 0x3018:
1116     case 0x3008:
1117     case 0x1700:
1118     case 0x1708:
1119     case 0x1710:
1120     case 0x1718:
1121     case 0x1720:
1122     case 0x1728:
1123     case 0x1730:
1124     case 0x1738:
1125     case 0x1740:
1126     case 0x1748:
1127     case 0x1750:
1128     case 0x1758:
1129     case 0x1760:
1130     case 0x1768:
1131     case 0x1770:
1132     case 0x1778:
1133     break;
1134    
1135 dpavlin 14 /* Graphics stuff? No warning: */
1136     case 0x2018:
1137     case 0x2060:
1138     case 0x2070:
1139     case 0x2074:
1140     case 0x20c0:
1141     case 0x20c4:
1142     case 0x20d0:
1143     case 0x21b0:
1144     case 0x21b8:
1145     break;
1146 dpavlin 12
1147 dpavlin 14 /* Perform graphics operation: */
1148     case 0x21f8:
1149     {
1150     uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1151     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1152     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1153     >> 16) & 0xfff;
1154     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1155     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1156     >> 16) & 0xfff;
1157     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1158 dpavlin 22 uint32_t y;
1159 dpavlin 12
1160 dpavlin 14 op >>= 24;
1161    
1162     switch (op) {
1163     case 1: /* Unknown. Used after drawing bitmaps? */
1164     break;
1165     case 3: /* Fill: */
1166     if (x2 < x1) {
1167     int tmp = x1; x1 = x2; x2 = tmp;
1168     }
1169     if (y2 < y1) {
1170     int tmp = y1; y1 = y2; y2 = tmp;
1171     }
1172     for (y=y1; y<=y2; y++) {
1173     unsigned char buf[1280];
1174     int length = x2-x1+1;
1175     int addr = (x1 + y*1280);
1176     if (length < 1)
1177     length = 1;
1178     memset(buf, color, length);
1179     if (x1 < 1280 && y < 1024)
1180     cpu->memory_rw(cpu, cpu->mem,
1181     0x38000000 + addr, buf,
1182     length, MEM_WRITE,
1183     NO_EXCEPTIONS | PHYSICAL);
1184     }
1185     break;
1186    
1187     default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1188     "%i,%i\n\n", op, color, x1,y1, x2,y2);
1189     }
1190     }
1191     break;
1192    
1193     case 0x29f0:
1194     /* Pixel output: */
1195     {
1196     uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1197     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1198     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1199     >> 16) & 0xfff;
1200     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1201     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1202     >> 16) & 0xfff;
1203     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1204 dpavlin 22 size_t x, y;
1205    
1206 dpavlin 14 if (x2 < x1) {
1207     int tmp = x1; x1 = x2; x2 = tmp;
1208     }
1209     if (y2 < y1) {
1210     int tmp = y1; y1 = y2; y2 = tmp;
1211     }
1212     if (x2-x1 <= 15)
1213     data <<= 16;
1214 dpavlin 22
1215 dpavlin 14 x=x1; y=y1;
1216     while (x <= x2 && y <= y2) {
1217     unsigned char buf = color;
1218     int addr = x + y*1280;
1219     int bit_set = data & 0x80000000UL;
1220     data <<= 1;
1221     if (x < 1280 && y < 1024 && bit_set)
1222     cpu->memory_rw(cpu, cpu->mem,
1223     0x38000000 + addr, &buf,1,MEM_WRITE,
1224     NO_EXCEPTIONS | PHYSICAL);
1225     x++;
1226     if (x > x2) {
1227     x = x1;
1228     y++;
1229     }
1230     }
1231     }
1232     break;
1233    
1234    
1235 dpavlin 4 /* Operations: */
1236     case 0x3800:
1237     if (writeflag == MEM_WRITE) {
1238     switch (idata) {
1239     case 0x11: /* zerofill */
1240 dpavlin 14 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1241     last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1242 dpavlin 4 zerobuflen = last_addr - first_addr + 1;
1243 dpavlin 14 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1244     " last = 0x%016llx, length = 0x%llx ]\n",
1245     (long long)first_addr, (long long)
1246     last_addr, (long long)zerobuflen);
1247 dpavlin 4
1248 dpavlin 14 /* TODO: is there a better way to
1249     implement this? */
1250 dpavlin 4 memset(zerobuf, 0, sizeof(zerobuf));
1251     fill_addr = first_addr;
1252     while (zerobuflen != 0) {
1253     if (zerobuflen > sizeof(zerobuf))
1254     fill_len = sizeof(zerobuf);
1255     else
1256     fill_len = zerobuflen;
1257     cpu->memory_rw(cpu, mem, fill_addr,
1258     zerobuf, fill_len, MEM_WRITE,
1259     NO_EXCEPTIONS | PHYSICAL);
1260     fill_addr += fill_len;
1261     zerobuflen -= sizeof(zerobuf);
1262     }
1263    
1264     break;
1265     default:
1266 dpavlin 14 fatal("[ sgi_mte: UNKNOWN operation "
1267     "0x%x ]\n", idata);
1268 dpavlin 4 }
1269     }
1270     break;
1271     default:
1272     if (writeflag == MEM_WRITE)
1273 dpavlin 14 debug("[ sgi_mte: unimplemented write to "
1274     "address 0x%llx, data=0x%016llx ]\n",
1275     (long long)relative_addr, (long long)idata);
1276 dpavlin 4 else
1277 dpavlin 14 debug("[ sgi_mte: unimplemented read from address"
1278     " 0x%llx ]\n", (long long)relative_addr);
1279 dpavlin 4 }
1280    
1281     if (writeflag == MEM_READ)
1282     memory_writemax64(cpu, data, len, odata);
1283    
1284     return 1;
1285     }
1286    
1287    
1288     /*
1289     * dev_sgi_mte_init():
1290     */
1291     void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1292     {
1293     struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1294     if (d == NULL) {
1295     fprintf(stderr, "out of memory\n");
1296     exit(1);
1297     }
1298     memset(d, 0, sizeof(struct sgi_mte_data));
1299    
1300     memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1301 dpavlin 20 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1302 dpavlin 4 }
1303    

  ViewVC Help
Powered by ViewVC 1.1.26