/[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 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 33198 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26