/[gxemul]/trunk/src/devices/dev_sgi_ip32.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_sgi_ip32.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show 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 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_sgi_ip32.c,v 1.44 2006/01/01 13:17:17 debug Exp $
29 *
30 * SGI IP32 devices.
31 *
32 * o) CRIME
33 * o) MACE
34 * o) MACE PCI bus
35 * o) mec (ethernet)
36 * o) ust (unknown device)
37 * o) mte (memory transfer engine? details unknown)
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "bus_pci.h"
45 #include "console.h"
46 #include "cpu.h"
47 #include "devices.h"
48 #include "emul.h"
49 #include "machine.h"
50 #include "memory.h"
51 #include "misc.h"
52 #include "net.h"
53
54 #include "crimereg.h"
55
56 #include "if_mecreg.h"
57
58
59 #define CRIME_TICKSHIFT 14
60 #define CRIME_SPEED_MUL_FACTOR 1
61 #define CRIME_SPEED_DIV_FACTOR 1
62
63 struct macepci_data {
64 struct pci_data *pci_data;
65 uint32_t reg[DEV_MACEPCI_LENGTH / 4];
66 };
67
68
69 /*
70 * dev_crime_tick():
71 *
72 * This function simply updates CRIME_TIME each tick.
73 *
74 * The names DIV and MUL may be a bit confusing. Increasing the
75 * MUL factor will result in an OS running on the emulated machine
76 * detecting a faster CPU. Increasing the DIV factor will result
77 * in a slower detected CPU.
78 *
79 * A R10000 is detected as running at
80 * CRIME_SPEED_FACTOR * 66 MHz. (TODO: this is not correct anymore)
81 */
82 void dev_crime_tick(struct cpu *cpu, void *extra)
83 {
84 int j, carry, old, new, add_byte;
85 uint64_t what_to_add = (1<<CRIME_TICKSHIFT)
86 * CRIME_SPEED_DIV_FACTOR / CRIME_SPEED_MUL_FACTOR;
87 struct crime_data *d = extra;
88
89 j = 0;
90 carry = 0;
91 while (j < 8) {
92 old = d->reg[CRIME_TIME + 7 - j];
93 add_byte = what_to_add >> ((int64_t)j * 8);
94 add_byte &= 255;
95 new = old + add_byte + carry;
96 d->reg[CRIME_TIME + 7 - j] = new & 255;
97 if (new >= 256)
98 carry = 1;
99 else
100 carry = 0;
101 j++;
102 }
103 }
104
105
106 /*
107 * dev_crime_access():
108 */
109 DEVICE_ACCESS(crime)
110 {
111 struct crime_data *d = extra;
112 uint64_t idata = 0;
113 size_t i;
114
115 if (writeflag == MEM_WRITE)
116 idata = memory_readmax64(cpu, data, len);
117
118 /*
119 * Set crime version/revision:
120 *
121 * 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 *
125 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
126 * that's something one has to live with. (TODO?)
127 */
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 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
155 (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
156 /*
157 * Force interrupt re-assertion:
158 *
159 * NOTE: Ugly hack. Hopefully CRMERR is never used.
160 */
161 #if 0
162 /*
163 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
164 TODO.
165 */
166 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 int j;
184
185 /* This is used by the IP32 PROM's
186 "reboot" command: */
187 for (j=0; j<cpu->machine->ncpus; j++)
188 cpu->machine->cpus[j]->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 #if 0
199 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 #endif
207 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, DM_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 DEVICE_ACCESS(mace)
258 {
259 size_t i;
260 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 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 switch (relative_addr) {
272 #if 0
273 case 0x10: /* Current interrupt assertions */
274 case 0x14:
275 /* don't dump debug info for these */
276 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 break;
284 case 0x18: /* Interrupt mask */
285 case 0x1c:
286 /* don't dump debug info for these */
287 break;
288 #endif
289 default:
290 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 } 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 dev_mace_access, d, DM_DEFAULT, NULL);
325
326 return d;
327 }
328
329
330 /****************************************************************************/
331
332
333 /*
334 * dev_macepci_access():
335 */
336 DEVICE_ACCESS(macepci)
337 {
338 struct macepci_data *d = (struct macepci_data *) extra;
339 uint64_t idata = 0, odata=0;
340 int regnr, res = 1, bus, dev, func, pcireg;
341
342 if (writeflag == MEM_WRITE)
343 idata = memory_readmax64(cpu, data, len);
344
345 regnr = relative_addr / sizeof(uint32_t);
346
347 /* Read from/write to the macepci: */
348 switch (relative_addr) {
349
350 case 0x00: /* Error address */
351 if (writeflag == MEM_WRITE) {
352 } else {
353 odata = 0;
354 }
355 break;
356
357 case 0x04: /* Error flags */
358 if (writeflag == MEM_WRITE) {
359 } else {
360 odata = 0x06;
361 }
362 break;
363
364 case 0x0c: /* Revision number */
365 if (writeflag == MEM_WRITE) {
366 } else {
367 odata = 0x01;
368 }
369 break;
370
371 case 0xcf8: /* PCI ADDR */
372 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 case 0xcfc: /* PCI DATA */
377 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
378 &odata : &idata, len, writeflag);
379 break;
380
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 machine *machine,
403 struct memory *mem, uint64_t baseaddr, 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(machine, pciirq, 0,0, 0,0,0, 0,0,0);
413
414 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
415 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
416
417 return d->pci_data;
418 }
419
420
421 /****************************************************************************/
422
423
424 /*
425 * SGI "mec" ethernet. Used in SGI-IP32.
426 *
427 * Study http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c
428 * and/or NetBSD. TODO:
429 *
430 * x) tx and rx interrupts/ring/slot stuff
431 */
432
433 #define MEC_TICK_SHIFT 14
434
435 #define MAX_TX_PACKET_LEN 1700
436 #define N_RX_ADDRESSES 16
437
438 struct sgi_mec_data {
439 uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
440
441 int irq_nr;
442 unsigned char macaddr[6];
443
444 unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
445 int cur_tx_packet_len;
446
447 unsigned char *cur_rx_packet;
448 int cur_rx_packet_len;
449
450 uint64_t rx_addr[N_RX_ADDRESSES];
451 int cur_rx_addr_index_write;
452 int cur_rx_addr_index;
453 };
454
455
456 /*
457 * mec_reset():
458 */
459 static void mec_reset(struct sgi_mec_data *d)
460 {
461 if (d->cur_rx_packet != NULL)
462 free(d->cur_rx_packet);
463
464 memset(d->reg, 0, sizeof(d->reg));
465 }
466
467
468 /*
469 * mec_control_write():
470 */
471 static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d,
472 uint64_t x)
473 {
474 if (x & MEC_MAC_CORE_RESET) {
475 debug("[ sgi_mec: CORE RESET ]\n");
476 mec_reset(d);
477 }
478 }
479
480
481 /*
482 * mec_try_rx():
483 */
484 static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d)
485 {
486 uint64_t base;
487 unsigned char data[8];
488 int i, res, retval = 0;
489
490 base = d->rx_addr[d->cur_rx_addr_index];
491 if (base & 0xfff)
492 fatal("[ mec_try_rx(): WARNING! lowest bits of base are "
493 "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff));
494 base &= 0xfffff000ULL;
495 if (base == 0)
496 goto skip;
497
498 /* printf("rx base = 0x%016llx\n", (long long)base); */
499
500 /* Read an rx descriptor from memory: */
501 res = cpu->memory_rw(cpu, cpu->mem, base,
502 &data[0], sizeof(data), MEM_READ, PHYSICAL);
503 if (!res)
504 return 0;
505
506 #if 0
507 printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index);
508 for (i=0; i<sizeof(data); i++) {
509 if ((i & 3) == 0)
510 printf(" ");
511 printf("%02x", data[i]);
512 }
513 printf(" }\n");
514 #endif
515
516 /* Is this descriptor already in use? */
517 if (data[0] & 0x80) {
518 /* printf("INTERRUPT for base = 0x%x\n", (int)base); */
519 goto skip_and_advance;
520 }
521
522 if (d->cur_rx_packet == NULL &&
523 net_ethernet_rx_avail(cpu->machine->emul->net, d))
524 net_ethernet_rx(cpu->machine->emul->net, d,
525 &d->cur_rx_packet, &d->cur_rx_packet_len);
526
527 if (d->cur_rx_packet == NULL)
528 goto skip;
529
530 /* Copy the packet data: */
531 /* printf("RX: "); */
532 for (i=0; i<d->cur_rx_packet_len; i++) {
533 res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2,
534 d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL);
535 /* printf(" %02x", d->cur_rx_packet[i]); */
536 }
537 /* printf("\n"); */
538
539 #if 0
540 printf("RX: %i bytes, index %i, base = 0x%x\n",
541 d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base);
542 #endif
543
544 /* 4 bytes of CRC at the end. Hm. TODO */
545 d->cur_rx_packet_len += 4;
546
547 memset(data, 0, sizeof(data));
548 data[6] = (d->cur_rx_packet_len >> 8) & 255;
549 data[7] = d->cur_rx_packet_len & 255;
550 /* TODO: lots of bits :-) */
551 data[4] = 0x04; /* match MAC */
552 data[0] = 0x80; /* 0x80 = received. */
553 res = cpu->memory_rw(cpu, cpu->mem, base,
554 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
555
556 /* Free the packet from memory: */
557 free(d->cur_rx_packet);
558 d->cur_rx_packet = NULL;
559
560 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD;
561 skip_and_advance:
562 d->cur_rx_addr_index ++;
563 d->cur_rx_addr_index %= N_RX_ADDRESSES;
564 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS;
565 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
566 (d->cur_rx_addr_index & 0x1f) << 8;
567 retval = 1;
568
569 skip:
570 return retval;
571 }
572
573
574 /*
575 * mec_try_tx():
576 */
577 static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
578 {
579 uint64_t base, addr, dma_base;
580 int tx_ring_ptr, ringread, ringwrite, res, i, j;
581 unsigned char data[32];
582 int len, start_offset, dma_ptr_nr, dma_len;
583
584 base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
585 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
586
587 if (base == 0)
588 return 0;
589
590 /* printf("base = 0x%016llx\n", base); */
591
592 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
593 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
594 ringread >>= 16;
595 /* All done? Then abort. */
596 if (ringread == ringwrite)
597 return 0;
598
599 tx_ring_ptr &= MEC_TX_RING_READ_PTR;
600 tx_ring_ptr >>= 16;
601
602 /* Each tx descriptor (+ buffer) is 128 bytes: */
603 addr = base + tx_ring_ptr*128;
604 res = cpu->memory_rw(cpu, cpu->mem, addr,
605 &data[0], sizeof(data), MEM_READ, PHYSICAL);
606 if (!res)
607 return 0;
608
609 /* Is this packet transmitted already? */
610 if (data[0] & 0x80) {
611 fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
612 " transmitted? ]\n", tx_ring_ptr);
613 goto advance_tx;
614 }
615
616 len = data[6] * 256 + data[7];
617 start_offset = data[5] & 0x7f;
618
619 /* Is this packet empty? Then don't transmit. */
620 if (len == 0)
621 return 0;
622
623 /* Hm. Is len one too little? TODO */
624 len ++;
625
626 #if 0
627 printf("{ mec: txdesc %i: ", tx_ring_ptr);
628 for (i=0; i<sizeof(data); i++) {
629 if ((i & 3) == 0)
630 printf(" ");
631 printf("%02x", data[i]);
632 }
633 printf(" }\n");
634 #endif
635 dma_ptr_nr = 0;
636
637 j = 0;
638 d->cur_tx_packet_len = len;
639
640 for (i=start_offset; i<start_offset+len; i++) {
641 unsigned char ch;
642
643 if ((i & 0x7f) == 0x00)
644 break;
645
646 res = cpu->memory_rw(cpu, cpu->mem, addr + i,
647 &ch, sizeof(ch), MEM_READ, PHYSICAL);
648 /* printf(" %02x", ch); */
649
650 d->cur_tx_packet[j++] = ch;
651 if (j >= MAX_TX_PACKET_LEN) {
652 fatal("[ mec_try_tx: packet too large? ]\n");
653 break;
654 }
655 }
656 /* printf("\n"); */
657
658 if (j < len) {
659 /* Continue with DMA: */
660 for (;;) {
661 dma_ptr_nr ++;
662 if (dma_ptr_nr >= 4)
663 break;
664 if (!(data[4] & (0x01 << dma_ptr_nr)))
665 break;
666 dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
667 + (data[dma_ptr_nr * 8 + 5] << 16)
668 + (data[dma_ptr_nr * 8 + 6] << 8)
669 + (data[dma_ptr_nr * 8 + 7]);
670 dma_base &= 0xfffffff8ULL;
671 dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
672 + (data[dma_ptr_nr * 8 + 3]) + 1;
673
674 /* printf("dma_base = %08x, dma_len = %i\n",
675 (int)dma_base, dma_len); */
676
677 while (dma_len > 0) {
678 unsigned char ch;
679 res = cpu->memory_rw(cpu, cpu->mem, dma_base,
680 &ch, sizeof(ch), MEM_READ, PHYSICAL);
681 /* printf(" %02x", ch); */
682
683 d->cur_tx_packet[j++] = ch;
684 if (j >= MAX_TX_PACKET_LEN) {
685 fatal("[ mec_try_tx: packet too large?"
686 " ]\n");
687 break;
688 }
689 dma_base ++;
690 dma_len --;
691 }
692 }
693 }
694
695 if (j < len)
696 fatal("[ mec_try_tx: not enough data? ]\n");
697
698 net_ethernet_tx(cpu->machine->emul->net, d,
699 d->cur_tx_packet, d->cur_tx_packet_len);
700
701 /* see openbsd's if_mec.c for details */
702 if (data[4] & 0x01) {
703 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
704 MEC_INT_TX_PACKET_SENT;
705 }
706 memset(data, 0, 6); /* last 2 bytes are len */
707 data[0] = 0x80;
708 data[5] = 0x80;
709
710 res = cpu->memory_rw(cpu, cpu->mem, addr,
711 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
712
713 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
714 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
715
716 advance_tx:
717 /* Advance the ring Read ptr. */
718 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
719 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
720 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
721
722 ringread = (ringread >> 16) + 1;
723 ringread &= 63;
724 ringread <<= 16;
725
726 d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
727 (ringwrite & MEC_TX_RING_WRITE_PTR) |
728 (ringread & MEC_TX_RING_READ_PTR);
729
730 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
731 ~MEC_INT_TX_RING_BUFFER_ALIAS;
732 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
733 (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
734 MEC_INT_TX_RING_BUFFER_ALIAS);
735
736 return 1;
737 }
738
739
740 /*
741 * dev_sgi_mec_tick():
742 */
743 void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
744 {
745 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
746 int n = 0;
747
748 while (mec_try_tx(cpu, d))
749 ;
750
751 while (mec_try_rx(cpu, d) && n < 16)
752 n++;
753
754 /* Interrupts: (TODO: only when enabled) */
755 if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
756 #if 0
757 printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
758 sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
759 fflush(stdout);
760 #endif
761 cpu_interrupt(cpu, d->irq_nr);
762 } else
763 cpu_interrupt_ack(cpu, d->irq_nr);
764 }
765
766
767 /*
768 * dev_sgi_mec_access():
769 */
770 DEVICE_ACCESS(sgi_mec)
771 {
772 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
773 uint64_t idata = 0, odata = 0;
774 int regnr;
775
776 if (writeflag == MEM_WRITE)
777 idata = memory_readmax64(cpu, data, len);
778
779 regnr = relative_addr / sizeof(uint64_t);
780
781 /* Treat most registers as read/write, by default. */
782 if (writeflag == MEM_WRITE) {
783 switch (relative_addr) {
784 case MEC_INT_STATUS: /* 0x08 */
785 /* Clear bits on write: (This is just a guess) */
786 d->reg[regnr] = (d->reg[regnr] & ~0xff)
787 | ((d->reg[regnr] & ~idata) & 0xff);
788 break;
789 case MEC_TX_RING_PTR: /* 0x30 */
790 idata &= MEC_TX_RING_WRITE_PTR;
791 d->reg[regnr] = (d->reg[regnr] &
792 ~MEC_TX_RING_WRITE_PTR) | idata;
793 /* TODO */
794 break;
795 default:
796 d->reg[regnr] = idata;
797 }
798 } else
799 odata = d->reg[regnr];
800
801 switch (relative_addr) {
802 case MEC_MAC_CONTROL: /* 0x00 */
803 if (writeflag)
804 mec_control_write(cpu, d, idata);
805 else {
806 /* Fake "revision 1": */
807 odata &= ~MEC_MAC_REVISION;
808 odata |= 1 << MEC_MAC_REVISION_SHIFT;
809 }
810 break;
811 case MEC_INT_STATUS: /* 0x08 */
812 if (writeflag)
813 debug("[ sgi_mec: write to MEC_INT_STATUS: "
814 "0x%016llx ]\n", (long long)idata);
815 break;
816 case MEC_DMA_CONTROL: /* 0x10 */
817 if (writeflag) {
818 debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
819 "0x%016llx ]\n", (long long)idata);
820 if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
821 /* This should apparently stop the
822 TX Empty interrupt. */
823 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
824 ~MEC_INT_TX_EMPTY;
825 }
826 }
827 break;
828 case MEC_TX_ALIAS: /* 0x20 */
829 if (writeflag) {
830 debug("[ sgi_mec: write to MEC_TX_ALIAS: "
831 "0x%016llx ]\n", (long long)idata);
832 } else {
833 debug("[ sgi_mec: read from MEC_TX_ALIAS: "
834 "0x%016llx ]\n", (long long)idata);
835 odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
836 }
837 break;
838 case MEC_RX_ALIAS: /* 0x28 */
839 if (writeflag)
840 debug("[ sgi_mec: write to MEC_RX_ALIAS: "
841 "0x%016llx ]\n", (long long)idata);
842 break;
843 case MEC_TX_RING_PTR: /* 0x30 */
844 if (writeflag)
845 debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
846 "0x%016llx ]\n", (long long)idata);
847 break;
848 case MEC_PHY_DATA: /* 0x64 */
849 if (writeflag)
850 fatal("[ sgi_mec: write to MEC_PHY_DATA: "
851 "0x%016llx ]\n", (long long)idata);
852 else
853 odata = 0; /* ? */
854 break;
855 case MEC_PHY_ADDRESS: /* 0x6c */
856 if (writeflag)
857 debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
858 "0x%016llx ]\n", (long long)idata);
859 break;
860 case MEC_PHY_READ_INITIATE: /* 0x70 */
861 if (writeflag)
862 debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
863 "0x%016llx ]\n", (long long)idata);
864 break;
865 case 0x74:
866 if (writeflag)
867 debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
868 (long long)idata);
869 else
870 debug("[ sgi_mec: read from 0x74 ]\n");
871 break;
872 case MEC_STATION: /* 0xa0 */
873 if (writeflag)
874 debug("[ sgi_mec: setting the MAC address to "
875 "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
876 (idata >> 40) & 255, (idata >> 32) & 255,
877 (idata >> 24) & 255, (idata >> 16) & 255,
878 (idata >> 8) & 255, (idata >> 0) & 255);
879 break;
880 case MEC_STATION_ALT: /* 0xa8 */
881 if (writeflag)
882 debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
883 " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
884 (idata >> 40) & 255, (idata >> 32) & 255,
885 (idata >> 24) & 255, (idata >> 16) & 255,
886 (idata >> 8) & 255, (idata >> 0) & 255);
887 break;
888 case MEC_MULTICAST: /* 0xb0 */
889 if (writeflag)
890 debug("[ sgi_mec: write to MEC_MULTICAST: "
891 "0x%016llx ]\n", (long long)idata);
892 break;
893 case MEC_TX_RING_BASE: /* 0xb8 */
894 if (writeflag)
895 debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
896 "0x%016llx ]\n", (long long)idata);
897 break;
898 case MEC_MCL_RX_FIFO: /* 0x100 */
899 if (writeflag) {
900 debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
901 "%016llx ]\n", (long long)idata);
902 d->rx_addr[d->cur_rx_addr_index_write] = idata;
903 d->cur_rx_addr_index_write ++;
904 d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
905 }
906 break;
907 default:
908 if (writeflag == MEM_WRITE)
909 fatal("[ sgi_mec: unimplemented write to address"
910 " 0x%llx, data=0x%016llx ]\n",
911 (long long)relative_addr, (long long)idata);
912 else
913 fatal("[ sgi_mec: unimplemented read from address"
914 " 0x%llx ]\n", (long long)relative_addr);
915 }
916
917 if (writeflag == MEM_READ)
918 memory_writemax64(cpu, data, len, odata);
919
920 dev_sgi_mec_tick(cpu, extra);
921
922 return 1;
923 }
924
925
926 /*
927 * dev_sgi_mec_init():
928 */
929 void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
930 uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
931 {
932 char *name2;
933 size_t nlen = 55;
934 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
935
936 if (d == NULL) {
937 fprintf(stderr, "out of memory\n");
938 exit(1);
939 }
940 memset(d, 0, sizeof(struct sgi_mec_data));
941 d->irq_nr = irq_nr;
942 memcpy(d->macaddr, macaddr, 6);
943
944 mec_reset(d);
945
946 name2 = malloc(nlen);
947 if (name2 == NULL) {
948 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
949 exit(1);
950 }
951 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
952 d->macaddr[0], d->macaddr[1], d->macaddr[2],
953 d->macaddr[3], d->macaddr[4], d->macaddr[5]);
954
955 memory_device_register(mem, name2, baseaddr,
956 DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
957 DM_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 DEVICE_ACCESS(sgi_ust)
977 {
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 debug("[ sgi_ust: unimplemented write to "
998 "address 0x%llx, data=0x%016llx ]\n",
999 (long long)relative_addr, (long long)idata);
1000 else
1001 debug("[ sgi_ust: unimplemented read from address"
1002 " 0x%llx ]\n", (long long)relative_addr);
1003 }
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 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1026 DM_DEFAULT, NULL);
1027 }
1028
1029
1030 /****************************************************************************/
1031
1032
1033 /*
1034 * SGI "mte". This device seems to be an accelerator for copying/clearing
1035 * memory. Used by (at least) the SGI O2 PROM.
1036 *
1037 * Actually, it seems to be used for graphics output as well. (?)
1038 * The O2's PROM uses it to output graphics.
1039 */
1040 /* #define debug fatal */
1041 /* #define MTE_DEBUG */
1042 #define ZERO_CHUNK_LEN 4096
1043
1044 struct sgi_mte_data {
1045 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1046 };
1047
1048 /*
1049 * dev_sgi_mte_access():
1050 */
1051 DEVICE_ACCESS(sgi_mte)
1052 {
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 regnr = relative_addr / sizeof(uint32_t);
1061
1062 /*
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 if (writeflag == MEM_WRITE)
1076 d->reg[regnr] = idata;
1077 else
1078 odata = d->reg[regnr];
1079
1080 #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 /*
1088 * 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 *
1092 * 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 *
1099 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1100 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1101 * write to 0x1710, data=0x80001ea480001ea5
1102 * ...
1103 * write to 0x1770, data=0x80001e9c80001e9d
1104 * write to 0x1778, data=0x80001e9e80001e9f
1105 */
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 /* 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
1147 /* 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 uint32_t y;
1159
1160 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 size_t x, y;
1205
1206 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
1215 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 /* Operations: */
1236 case 0x3800:
1237 if (writeflag == MEM_WRITE) {
1238 switch (idata) {
1239 case 0x11: /* zerofill */
1240 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1241 last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1242 zerobuflen = last_addr - first_addr + 1;
1243 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
1248 /* TODO: is there a better way to
1249 implement this? */
1250 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 fatal("[ sgi_mte: UNKNOWN operation "
1267 "0x%x ]\n", idata);
1268 }
1269 }
1270 break;
1271 default:
1272 if (writeflag == MEM_WRITE)
1273 debug("[ sgi_mte: unimplemented write to "
1274 "address 0x%llx, data=0x%016llx ]\n",
1275 (long long)relative_addr, (long long)idata);
1276 else
1277 debug("[ sgi_mte: unimplemented read from address"
1278 " 0x%llx ]\n", (long long)relative_addr);
1279 }
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 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1302 }
1303

  ViewVC Help
Powered by ViewVC 1.1.26