/[gxemul]/upstream/0.4.5.1/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 /upstream/0.4.5.1/src/devices/dev_sgi_ip32.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 41 - (show annotations)
Mon Oct 8 16:22:20 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 38078 byte(s)
0.4.5.1
1 /*
2 * Copyright (C) 2003-2007 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.51 2007/01/29 18:32:01 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 "device.h"
48 #include "devices.h"
49 #include "emul.h"
50 #include "machine.h"
51 #include "memory.h"
52 #include "misc.h"
53 #include "net.h"
54
55 #include "crimereg.h"
56 #include "if_mecreg.h"
57 #include "sgi_macereg.h"
58
59
60 #define CRIME_TICKSHIFT 14
61 #define CRIME_SPEED_MUL_FACTOR 1
62 #define CRIME_SPEED_DIV_FACTOR 1
63
64 struct macepci_data {
65 struct pci_data *pci_data;
66 uint32_t reg[DEV_MACEPCI_LENGTH / 4];
67 };
68
69 #define DEV_CRIME_LENGTH 0x1000
70 struct crime_data {
71 unsigned char reg[DEV_CRIME_LENGTH];
72 struct interrupt irq;
73 int use_fb;
74 };
75
76
77 /*
78 * crime_interrupt_assert():
79 * crime_interrupt_deassert():
80 */
81 void crime_interrupt_assert(struct interrupt *interrupt)
82 {
83 struct crime_data *d = (struct crime_data *) interrupt->extra;
84 uint32_t line = interrupt->line, asserted;
85
86 d->reg[CRIME_INTSTAT + 4] |= ((line >> 24) & 255);
87 d->reg[CRIME_INTSTAT + 5] |= ((line >> 16) & 255);
88 d->reg[CRIME_INTSTAT + 6] |= ((line >> 8) & 255);
89 d->reg[CRIME_INTSTAT + 7] |= (line & 255);
90
91 asserted =
92 (d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
93 (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
94 (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
95 (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]);
96
97 if (asserted)
98 INTERRUPT_ASSERT(d->irq);
99 }
100 void crime_interrupt_deassert(struct interrupt *interrupt)
101 {
102 struct crime_data *d = (struct crime_data *) interrupt->extra;
103 uint32_t line = interrupt->line, asserted;
104
105 d->reg[CRIME_INTSTAT + 4] &= ~((line >> 24) & 255);
106 d->reg[CRIME_INTSTAT + 5] &= ~((line >> 16) & 255);
107 d->reg[CRIME_INTSTAT + 6] &= ~((line >> 8) & 255);
108 d->reg[CRIME_INTSTAT + 7] &= ~(line & 255);
109
110 asserted =
111 (d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
112 (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
113 (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
114 (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]);
115
116 if (!asserted)
117 INTERRUPT_DEASSERT(d->irq);
118 }
119
120
121 /*
122 * dev_crime_tick():
123 *
124 * This function simply updates CRIME_TIME each tick.
125 *
126 * The names DIV and MUL may be a bit confusing. Increasing the
127 * MUL factor will result in an OS running on the emulated machine
128 * detecting a faster CPU. Increasing the DIV factor will result
129 * in a slower detected CPU.
130 *
131 * A R10000 is detected as running at
132 * CRIME_SPEED_FACTOR * 66 MHz. (TODO: this is not correct anymore)
133 */
134 void dev_crime_tick(struct cpu *cpu, void *extra)
135 {
136 int j, carry, old, new, add_byte;
137 uint64_t what_to_add = (1<<CRIME_TICKSHIFT)
138 * CRIME_SPEED_DIV_FACTOR / CRIME_SPEED_MUL_FACTOR;
139 struct crime_data *d = extra;
140
141 j = 0;
142 carry = 0;
143 while (j < 8) {
144 old = d->reg[CRIME_TIME + 7 - j];
145 add_byte = what_to_add >> ((int64_t)j * 8);
146 add_byte &= 255;
147 new = old + add_byte + carry;
148 d->reg[CRIME_TIME + 7 - j] = new & 255;
149 if (new >= 256)
150 carry = 1;
151 else
152 carry = 0;
153 j++;
154 }
155 }
156
157
158 DEVICE_ACCESS(crime)
159 {
160 struct crime_data *d = extra;
161 uint64_t idata = 0;
162 size_t i;
163
164 if (writeflag == MEM_WRITE)
165 idata = memory_readmax64(cpu, data, len);
166
167 /*
168 * Set crime version/revision:
169 *
170 * This might not be the most elegant or correct solution, but it
171 * seems that the IP32 PROM likes 0x11 for machines without graphics,
172 * and 0xa1 for machines with graphics.
173 *
174 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
175 * that's something one has to live with. (TODO?)
176 */
177 d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
178 d->reg[7] = d->use_fb? 0xa1 : 0x11;
179
180 /*
181 * Amount of memory. Bit 8 of bank control set ==> 128MB instead
182 * of 32MB per bank (?)
183 *
184 * When the bank control registers contain the same value as the
185 * previous one, that bank is not valid. (?)
186 */
187 d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
188 d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
189 d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
190 d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
191
192 if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
193 if (writeflag == MEM_READ)
194 memcpy(data, &d->reg[relative_addr], len);
195 return 1;
196 }
197
198 if (writeflag == MEM_WRITE)
199 memcpy(&d->reg[relative_addr], data, len);
200 else
201 memcpy(data, &d->reg[relative_addr], len);
202
203 switch (relative_addr) {
204 case CRIME_CONTROL: /* 0x008 */
205 /* TODO: 64-bit write to CRIME_CONTROL, but some things
206 (such as NetBSD 1.6.2) write to 0x00c! */
207 if (writeflag == MEM_WRITE) {
208 /*
209 * 0x200 = watchdog timer (according to NetBSD)
210 * 0x800 = "reboot" used by the IP32 PROM
211 */
212 if (idata & 0x200) {
213 idata &= ~0x200;
214 }
215 if (idata & 0x800) {
216 int j;
217
218 /* This is used by the IP32 PROM's
219 "reboot" command: */
220 for (j=0; j<cpu->machine->ncpus; j++)
221 cpu->machine->cpus[j]->running = 0;
222 cpu->machine->
223 exit_without_entering_debugger = 1;
224 idata &= ~0x800;
225 }
226 if (idata != 0)
227 fatal("[ CRIME_CONTROL: unimplemented "
228 "control 0x%016llx ]\n", (long long)idata);
229 }
230 break;
231
232 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
233 case CRIME_INTSTAT + 4:
234 case CRIME_INTMASK: /* 0x018, Current interrupt mask */
235 case CRIME_INTMASK + 4:
236 if ((d->reg[CRIME_INTSTAT + 4] & d->reg[CRIME_INTMASK + 4]) |
237 (d->reg[CRIME_INTSTAT + 5] & d->reg[CRIME_INTMASK + 5]) |
238 (d->reg[CRIME_INTSTAT + 6] & d->reg[CRIME_INTMASK + 6]) |
239 (d->reg[CRIME_INTSTAT + 7] & d->reg[CRIME_INTMASK + 7]) )
240 INTERRUPT_ASSERT(d->irq);
241 else
242 INTERRUPT_DEASSERT(d->irq);
243 break;
244 case 0x34:
245 /* don't dump debug info for these */
246 break;
247
248 default:
249 if (writeflag==MEM_READ) {
250 debug("[ crime: read from 0x%x, len=%i:",
251 (int)relative_addr, len);
252 for (i=0; i<len; i++)
253 debug(" %02x", data[i]);
254 debug(" ]\n");
255 } else {
256 debug("[ crime: write to 0x%x:", (int)relative_addr);
257 for (i=0; i<len; i++)
258 debug(" %02x", data[i]);
259 debug(" (len=%i) ]\n", len);
260 }
261 }
262
263 return 1;
264 }
265
266
267 /*
268 * dev_crime_init():
269 */
270 void dev_crime_init(struct machine *machine, struct memory *mem,
271 uint64_t baseaddr, char *irq_path, int use_fb)
272 {
273 struct crime_data *d;
274 char tmpstr[200];
275 int i;
276
277 d = malloc(sizeof(struct crime_data));
278 if (d == NULL) {
279 fprintf(stderr, "out of memory\n");
280 exit(1);
281 }
282 memset(d, 0, sizeof(struct crime_data));
283 d->use_fb = use_fb;
284
285 INTERRUPT_CONNECT(irq_path, d->irq);
286
287 /* Register 32 crime interrupts (hexadecimal names): */
288 for (i=0; i<32; i++) {
289 struct interrupt template;
290 char name[400];
291 snprintf(name, sizeof(name), "%s.crime.0x%x", irq_path, 1 << i);
292 memset(&template, 0, sizeof(template));
293 template.line = 1 << i;
294 template.name = name;
295 template.extra = d;
296 template.interrupt_assert = crime_interrupt_assert;
297 template.interrupt_deassert = crime_interrupt_deassert;
298 interrupt_handler_register(&template);
299 }
300
301 memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
302 dev_crime_access, d, DM_DEFAULT, NULL);
303
304 snprintf(tmpstr, sizeof(tmpstr), "mace addr=0x1f310000 irq=%s.crime",
305 irq_path);
306 device_add(machine, tmpstr);
307
308 machine_add_tickfunction(machine, dev_crime_tick, d,
309 CRIME_TICKSHIFT, 0.0);
310 }
311
312
313 /****************************************************************************/
314
315
316 #define DEV_MACE_LENGTH 0x100
317 struct mace_data {
318 unsigned char reg[DEV_MACE_LENGTH];
319 struct interrupt irq_periph;
320 struct interrupt irq_misc;
321 };
322
323
324 /*
325 * mace_interrupt_assert():
326 * mace_interrupt_deassert():
327 */
328 void mace_interrupt_assert(struct interrupt *interrupt)
329 {
330 struct mace_data *d = (struct mace_data *) interrupt->extra;
331 uint32_t line = 1 << interrupt->line;
332
333 d->reg[MACE_ISA_INT_STATUS + 4] |= ((line >> 24) & 255);
334 d->reg[MACE_ISA_INT_STATUS + 5] |= ((line >> 16) & 255);
335 d->reg[MACE_ISA_INT_STATUS + 6] |= ((line >> 8) & 255);
336 d->reg[MACE_ISA_INT_STATUS + 7] |= (line & 255);
337
338 /* High bits = PERIPH */
339 if ((d->reg[MACE_ISA_INT_STATUS+4] & d->reg[MACE_ISA_INT_MASK+4]) |
340 (d->reg[MACE_ISA_INT_STATUS+5] & d->reg[MACE_ISA_INT_MASK+5]))
341 INTERRUPT_ASSERT(d->irq_periph);
342
343 /* Low bits = MISC */
344 if ((d->reg[MACE_ISA_INT_STATUS+6] & d->reg[MACE_ISA_INT_MASK+6]) |
345 (d->reg[MACE_ISA_INT_STATUS+7] & d->reg[MACE_ISA_INT_MASK+7]))
346 INTERRUPT_ASSERT(d->irq_misc);
347 }
348 void mace_interrupt_deassert(struct interrupt *interrupt)
349 {
350 struct mace_data *d = (struct mace_data *) interrupt->extra;
351 uint32_t line = 1 << interrupt->line;
352
353 d->reg[MACE_ISA_INT_STATUS + 4] |= ((line >> 24) & 255);
354 d->reg[MACE_ISA_INT_STATUS + 5] |= ((line >> 16) & 255);
355 d->reg[MACE_ISA_INT_STATUS + 6] |= ((line >> 8) & 255);
356 d->reg[MACE_ISA_INT_STATUS + 7] |= (line & 255);
357
358 /* High bits = PERIPH */
359 if (!((d->reg[MACE_ISA_INT_STATUS+4] & d->reg[MACE_ISA_INT_MASK+4]) |
360 (d->reg[MACE_ISA_INT_STATUS+5] & d->reg[MACE_ISA_INT_MASK+5])))
361 INTERRUPT_DEASSERT(d->irq_periph);
362
363 /* Low bits = MISC */
364 if (!((d->reg[MACE_ISA_INT_STATUS+6] & d->reg[MACE_ISA_INT_MASK+6]) |
365 (d->reg[MACE_ISA_INT_STATUS+7] & d->reg[MACE_ISA_INT_MASK+7])))
366 INTERRUPT_DEASSERT(d->irq_misc);
367 }
368
369
370 DEVICE_ACCESS(mace)
371 {
372 size_t i;
373 struct mace_data *d = extra;
374
375 if (writeflag == MEM_WRITE)
376 memcpy(&d->reg[relative_addr], data, len);
377 else
378 memcpy(data, &d->reg[relative_addr], len);
379
380 switch (relative_addr) {
381
382 case MACE_ISA_INT_STATUS: /* Current interrupt assertions */
383 case MACE_ISA_INT_STATUS + 4:
384 /* don't dump debug info for these */
385 if (writeflag == MEM_WRITE) {
386 fatal("[ NOTE/TODO: WRITE to mace intr: "
387 "reladdr=0x%x data=", (int)relative_addr);
388 for (i=0; i<len; i++)
389 fatal(" %02x", data[i]);
390 fatal(" (len=%i) ]\n", len);
391 }
392 break;
393 case MACE_ISA_INT_MASK: /* Current interrupt mask */
394 case MACE_ISA_INT_MASK + 4:
395 if ((d->reg[MACE_ISA_INT_STATUS+4]&d->reg[MACE_ISA_INT_MASK+4])|
396 (d->reg[MACE_ISA_INT_STATUS+5]&d->reg[MACE_ISA_INT_MASK+5]))
397 INTERRUPT_ASSERT(d->irq_periph);
398 else
399 INTERRUPT_DEASSERT(d->irq_periph);
400
401 if ((d->reg[MACE_ISA_INT_STATUS+6]&d->reg[MACE_ISA_INT_MASK+6])|
402 (d->reg[MACE_ISA_INT_STATUS+7]&d->reg[MACE_ISA_INT_MASK+7]))
403 INTERRUPT_ASSERT(d->irq_misc);
404 else
405 INTERRUPT_DEASSERT(d->irq_misc);
406 break;
407
408 default:
409 if (writeflag == MEM_READ) {
410 debug("[ mace: read from 0x%x:", (int)relative_addr);
411 for (i=0; i<len; i++)
412 debug(" %02x", data[i]);
413 debug(" (len=%i) ]\n", len);
414 } else {
415 debug("[ mace: write to 0x%x:", (int)relative_addr);
416 for (i=0; i<len; i++)
417 debug(" %02x", data[i]);
418 debug(" (len=%i) ]\n", len);
419 }
420 }
421
422 return 1;
423 }
424
425
426 DEVINIT(mace)
427 {
428 struct mace_data *d;
429 char tmpstr[300];
430 int i;
431
432 d = malloc(sizeof(struct mace_data));
433 if (d == NULL) {
434 fprintf(stderr, "out of memory\n");
435 exit(1);
436 }
437 memset(d, 0, sizeof(struct mace_data));
438
439 snprintf(tmpstr, sizeof(tmpstr), "%s.0x%x",
440 devinit->interrupt_path, MACE_PERIPH_SERIAL);
441 INTERRUPT_CONNECT(tmpstr, d->irq_periph);
442
443 snprintf(tmpstr, sizeof(tmpstr), "%s.0x%x",
444 devinit->interrupt_path, MACE_PERIPH_SERIAL);
445 INTERRUPT_CONNECT(tmpstr, d->irq_misc);
446
447 /*
448 * For Mace interrupts MACE_PERIPH_SERIAL and MACE_PERIPH_MISC,
449 * register 32 mace interrupts each.
450 */
451 /* Register 32 crime interrupts (hexadecimal names): */
452 for (i=0; i<32; i++) {
453 struct interrupt template;
454 char name[400];
455 snprintf(name, sizeof(name), "%s.0x%x.mace.%i",
456 devinit->interrupt_path, MACE_PERIPH_SERIAL, i);
457 memset(&template, 0, sizeof(template));
458 template.line = i;
459 template.name = name;
460 template.extra = d;
461 template.interrupt_assert = mace_interrupt_assert;
462 template.interrupt_deassert = mace_interrupt_deassert;
463 interrupt_handler_register(&template);
464
465 snprintf(name, sizeof(name), "%s.0x%x.mace.%i",
466 devinit->interrupt_path, MACE_PERIPH_MISC, i);
467 memset(&template, 0, sizeof(template));
468 template.line = i;
469 template.name = name;
470 template.extra = d;
471 template.interrupt_assert = mace_interrupt_assert;
472 template.interrupt_deassert = mace_interrupt_deassert;
473 interrupt_handler_register(&template);
474 }
475
476 memory_device_register(devinit->machine->memory, devinit->name,
477 devinit->addr, DEV_MACE_LENGTH, dev_mace_access, d,
478 DM_DEFAULT, NULL);
479
480 devinit->return_ptr = d;
481 return 1;
482 }
483
484
485 /****************************************************************************/
486
487
488 DEVICE_ACCESS(macepci)
489 {
490 struct macepci_data *d = (struct macepci_data *) extra;
491 uint64_t idata = 0, odata=0;
492 int regnr, res = 1, bus, dev, func, pcireg;
493
494 if (writeflag == MEM_WRITE)
495 idata = memory_readmax64(cpu, data, len);
496
497 regnr = relative_addr / sizeof(uint32_t);
498
499 /* Read from/write to the macepci: */
500 switch (relative_addr) {
501
502 case 0x00: /* Error address */
503 if (writeflag == MEM_WRITE) {
504 } else {
505 odata = 0;
506 }
507 break;
508
509 case 0x04: /* Error flags */
510 if (writeflag == MEM_WRITE) {
511 } else {
512 odata = 0x06;
513 }
514 break;
515
516 case 0x0c: /* Revision number */
517 if (writeflag == MEM_WRITE) {
518 } else {
519 odata = 0x01;
520 }
521 break;
522
523 case 0xcf8: /* PCI ADDR */
524 bus_pci_decompose_1(idata, &bus, &dev, &func, &pcireg);
525 bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, pcireg);
526 break;
527
528 case 0xcfc: /* PCI DATA */
529 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
530 &odata : &idata, len, writeflag);
531 break;
532
533 default:
534 if (writeflag == MEM_WRITE) {
535 debug("[ macepci: unimplemented write to address "
536 "0x%x, data=0x%02x ]\n",
537 (int)relative_addr, (int)idata);
538 } else {
539 debug("[ macepci: unimplemented read from address "
540 "0x%x ]\n", (int)relative_addr);
541 }
542 }
543
544 if (writeflag == MEM_READ)
545 memory_writemax64(cpu, data, len, odata);
546
547 return res;
548 }
549
550
551 /*
552 * dev_macepci_init():
553 */
554 struct pci_data *dev_macepci_init(struct machine *machine,
555 struct memory *mem, uint64_t baseaddr, char *irq_path)
556 {
557 struct macepci_data *d = malloc(sizeof(struct macepci_data));
558 if (d == NULL) {
559 fprintf(stderr, "out of memory\n");
560 exit(1);
561 }
562 memset(d, 0, sizeof(struct macepci_data));
563
564 /* TODO: PCI vs ISA interrupt? */
565
566 d->pci_data = bus_pci_init(machine,
567 irq_path,
568 0,
569 0,
570 0,
571 0,
572 "TODO: pci irq path",
573 0x18000003, /* ISA portbase */
574 0,
575 irq_path);
576
577 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
578 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
579
580 return d->pci_data;
581 }
582
583
584 /****************************************************************************/
585
586
587 /*
588 * SGI "mec" ethernet. Used in SGI-IP32.
589 *
590 * Study http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c
591 * and/or NetBSD. TODO:
592 *
593 * x) tx and rx interrupts/ring/slot stuff
594 */
595
596 #define MEC_TICK_SHIFT 14
597
598 #define MAX_TX_PACKET_LEN 1700
599 #define N_RX_ADDRESSES 16
600
601 struct sgi_mec_data {
602 uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
603
604 struct interrupt irq;
605 unsigned char macaddr[6];
606
607 unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
608 int cur_tx_packet_len;
609
610 unsigned char *cur_rx_packet;
611 int cur_rx_packet_len;
612
613 uint64_t rx_addr[N_RX_ADDRESSES];
614 int cur_rx_addr_index_write;
615 int cur_rx_addr_index;
616 };
617
618
619 /*
620 * mec_reset():
621 */
622 static void mec_reset(struct sgi_mec_data *d)
623 {
624 if (d->cur_rx_packet != NULL)
625 free(d->cur_rx_packet);
626
627 memset(d->reg, 0, sizeof(d->reg));
628 }
629
630
631 /*
632 * mec_control_write():
633 */
634 static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d,
635 uint64_t x)
636 {
637 if (x & MEC_MAC_CORE_RESET) {
638 debug("[ sgi_mec: CORE RESET ]\n");
639 mec_reset(d);
640 }
641 }
642
643
644 /*
645 * mec_try_rx():
646 */
647 static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d)
648 {
649 uint64_t base;
650 unsigned char data[8];
651 int i, res, retval = 0;
652
653 base = d->rx_addr[d->cur_rx_addr_index];
654 if (base & 0xfff)
655 fatal("[ mec_try_rx(): WARNING! lowest bits of base are "
656 "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff));
657 base &= 0xfffff000ULL;
658 if (base == 0)
659 goto skip;
660
661 /* printf("rx base = 0x%016llx\n", (long long)base); */
662
663 /* Read an rx descriptor from memory: */
664 res = cpu->memory_rw(cpu, cpu->mem, base,
665 &data[0], sizeof(data), MEM_READ, PHYSICAL);
666 if (!res)
667 return 0;
668
669 #if 0
670 printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index);
671 for (i=0; i<sizeof(data); i++) {
672 if ((i & 3) == 0)
673 printf(" ");
674 printf("%02x", data[i]);
675 }
676 printf(" }\n");
677 #endif
678
679 /* Is this descriptor already in use? */
680 if (data[0] & 0x80) {
681 /* printf("INTERRUPT for base = 0x%x\n", (int)base); */
682 goto skip_and_advance;
683 }
684
685 if (d->cur_rx_packet == NULL &&
686 net_ethernet_rx_avail(cpu->machine->emul->net, d))
687 net_ethernet_rx(cpu->machine->emul->net, d,
688 &d->cur_rx_packet, &d->cur_rx_packet_len);
689
690 if (d->cur_rx_packet == NULL)
691 goto skip;
692
693 /* Copy the packet data: */
694 /* printf("RX: "); */
695 for (i=0; i<d->cur_rx_packet_len; i++) {
696 res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2,
697 d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL);
698 /* printf(" %02x", d->cur_rx_packet[i]); */
699 }
700 /* printf("\n"); */
701
702 #if 0
703 printf("RX: %i bytes, index %i, base = 0x%x\n",
704 d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base);
705 #endif
706
707 /* 4 bytes of CRC at the end. Hm. TODO */
708 d->cur_rx_packet_len += 4;
709
710 memset(data, 0, sizeof(data));
711 data[6] = (d->cur_rx_packet_len >> 8) & 255;
712 data[7] = d->cur_rx_packet_len & 255;
713 /* TODO: lots of bits :-) */
714 data[4] = 0x04; /* match MAC */
715 data[0] = 0x80; /* 0x80 = received. */
716 res = cpu->memory_rw(cpu, cpu->mem, base,
717 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
718
719 /* Free the packet from memory: */
720 free(d->cur_rx_packet);
721 d->cur_rx_packet = NULL;
722
723 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD;
724 skip_and_advance:
725 d->cur_rx_addr_index ++;
726 d->cur_rx_addr_index %= N_RX_ADDRESSES;
727 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS;
728 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
729 (d->cur_rx_addr_index & 0x1f) << 8;
730 retval = 1;
731
732 skip:
733 return retval;
734 }
735
736
737 /*
738 * mec_try_tx():
739 */
740 static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
741 {
742 uint64_t base, addr, dma_base;
743 int tx_ring_ptr, ringread, ringwrite, res, i, j;
744 unsigned char data[32];
745 int len, start_offset, dma_ptr_nr, dma_len;
746
747 base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
748 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
749
750 if (base == 0)
751 return 0;
752
753 /* printf("base = 0x%016llx\n", base); */
754
755 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
756 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
757 ringread >>= 16;
758 /* All done? Then abort. */
759 if (ringread == ringwrite)
760 return 0;
761
762 tx_ring_ptr &= MEC_TX_RING_READ_PTR;
763 tx_ring_ptr >>= 16;
764
765 /* Each tx descriptor (+ buffer) is 128 bytes: */
766 addr = base + tx_ring_ptr*128;
767 res = cpu->memory_rw(cpu, cpu->mem, addr,
768 &data[0], sizeof(data), MEM_READ, PHYSICAL);
769 if (!res)
770 return 0;
771
772 /* Is this packet transmitted already? */
773 if (data[0] & 0x80) {
774 fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
775 " transmitted? ]\n", tx_ring_ptr);
776 goto advance_tx;
777 }
778
779 len = data[6] * 256 + data[7];
780 start_offset = data[5] & 0x7f;
781
782 /* Is this packet empty? Then don't transmit. */
783 if (len == 0)
784 return 0;
785
786 /* Hm. Is len one too little? TODO */
787 len ++;
788
789 #if 0
790 printf("{ mec: txdesc %i: ", tx_ring_ptr);
791 for (i=0; i<sizeof(data); i++) {
792 if ((i & 3) == 0)
793 printf(" ");
794 printf("%02x", data[i]);
795 }
796 printf(" }\n");
797 #endif
798 dma_ptr_nr = 0;
799
800 j = 0;
801 d->cur_tx_packet_len = len;
802
803 for (i=start_offset; i<start_offset+len; i++) {
804 unsigned char ch;
805
806 if ((i & 0x7f) == 0x00)
807 break;
808
809 res = cpu->memory_rw(cpu, cpu->mem, addr + i,
810 &ch, sizeof(ch), MEM_READ, PHYSICAL);
811 /* printf(" %02x", ch); */
812
813 d->cur_tx_packet[j++] = ch;
814 if (j >= MAX_TX_PACKET_LEN) {
815 fatal("[ mec_try_tx: packet too large? ]\n");
816 break;
817 }
818 }
819 /* printf("\n"); */
820
821 if (j < len) {
822 /* Continue with DMA: */
823 for (;;) {
824 dma_ptr_nr ++;
825 if (dma_ptr_nr >= 4)
826 break;
827 if (!(data[4] & (0x01 << dma_ptr_nr)))
828 break;
829 dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
830 + (data[dma_ptr_nr * 8 + 5] << 16)
831 + (data[dma_ptr_nr * 8 + 6] << 8)
832 + (data[dma_ptr_nr * 8 + 7]);
833 dma_base &= 0xfffffff8ULL;
834 dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
835 + (data[dma_ptr_nr * 8 + 3]) + 1;
836
837 /* printf("dma_base = %08x, dma_len = %i\n",
838 (int)dma_base, dma_len); */
839
840 while (dma_len > 0) {
841 unsigned char ch;
842 res = cpu->memory_rw(cpu, cpu->mem, dma_base,
843 &ch, sizeof(ch), MEM_READ, PHYSICAL);
844 /* printf(" %02x", ch); */
845
846 d->cur_tx_packet[j++] = ch;
847 if (j >= MAX_TX_PACKET_LEN) {
848 fatal("[ mec_try_tx: packet too large?"
849 " ]\n");
850 break;
851 }
852 dma_base ++;
853 dma_len --;
854 }
855 }
856 }
857
858 if (j < len)
859 fatal("[ mec_try_tx: not enough data? ]\n");
860
861 net_ethernet_tx(cpu->machine->emul->net, d,
862 d->cur_tx_packet, d->cur_tx_packet_len);
863
864 /* see openbsd's if_mec.c for details */
865 if (data[4] & 0x01) {
866 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
867 MEC_INT_TX_PACKET_SENT;
868 }
869 memset(data, 0, 6); /* last 2 bytes are len */
870 data[0] = 0x80;
871 data[5] = 0x80;
872
873 res = cpu->memory_rw(cpu, cpu->mem, addr,
874 &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
875
876 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
877 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
878
879 advance_tx:
880 /* Advance the ring Read ptr. */
881 tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
882 ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
883 ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
884
885 ringread = (ringread >> 16) + 1;
886 ringread &= 63;
887 ringread <<= 16;
888
889 d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
890 (ringwrite & MEC_TX_RING_WRITE_PTR) |
891 (ringread & MEC_TX_RING_READ_PTR);
892
893 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
894 ~MEC_INT_TX_RING_BUFFER_ALIAS;
895 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
896 (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
897 MEC_INT_TX_RING_BUFFER_ALIAS);
898
899 return 1;
900 }
901
902
903 /*
904 * dev_sgi_mec_tick():
905 */
906 void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
907 {
908 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
909 int n = 0;
910
911 while (mec_try_tx(cpu, d))
912 ;
913
914 while (mec_try_rx(cpu, d) && n < 16)
915 n++;
916
917 /* Interrupts: (TODO: only when enabled) */
918 if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
919 #if 0
920 printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
921 sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
922 fflush(stdout);
923 #endif
924 INTERRUPT_ASSERT(d->irq);
925 } else
926 INTERRUPT_DEASSERT(d->irq);
927 }
928
929
930 DEVICE_ACCESS(sgi_mec)
931 {
932 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
933 uint64_t idata = 0, odata = 0;
934 int regnr;
935
936 if (writeflag == MEM_WRITE)
937 idata = memory_readmax64(cpu, data, len);
938
939 regnr = relative_addr / sizeof(uint64_t);
940
941 /* Treat most registers as read/write, by default. */
942 if (writeflag == MEM_WRITE) {
943 switch (relative_addr) {
944 case MEC_INT_STATUS: /* 0x08 */
945 /* Clear bits on write: (This is just a guess) */
946 d->reg[regnr] = (d->reg[regnr] & ~0xff)
947 | ((d->reg[regnr] & ~idata) & 0xff);
948 break;
949 case MEC_TX_RING_PTR: /* 0x30 */
950 idata &= MEC_TX_RING_WRITE_PTR;
951 d->reg[regnr] = (d->reg[regnr] &
952 ~MEC_TX_RING_WRITE_PTR) | idata;
953 /* TODO */
954 break;
955 default:
956 d->reg[regnr] = idata;
957 }
958 } else
959 odata = d->reg[regnr];
960
961 switch (relative_addr) {
962 case MEC_MAC_CONTROL: /* 0x00 */
963 if (writeflag)
964 mec_control_write(cpu, d, idata);
965 else {
966 /* Fake "revision 1": */
967 odata &= ~MEC_MAC_REVISION;
968 odata |= 1 << MEC_MAC_REVISION_SHIFT;
969 }
970 break;
971 case MEC_INT_STATUS: /* 0x08 */
972 if (writeflag)
973 debug("[ sgi_mec: write to MEC_INT_STATUS: "
974 "0x%016llx ]\n", (long long)idata);
975 break;
976 case MEC_DMA_CONTROL: /* 0x10 */
977 if (writeflag) {
978 debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
979 "0x%016llx ]\n", (long long)idata);
980 if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
981 /* This should apparently stop the
982 TX Empty interrupt. */
983 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
984 ~MEC_INT_TX_EMPTY;
985 }
986 }
987 break;
988 case MEC_TX_ALIAS: /* 0x20 */
989 if (writeflag) {
990 debug("[ sgi_mec: write to MEC_TX_ALIAS: "
991 "0x%016llx ]\n", (long long)idata);
992 } else {
993 debug("[ sgi_mec: read from MEC_TX_ALIAS: "
994 "0x%016llx ]\n", (long long)idata);
995 odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
996 }
997 break;
998 case MEC_RX_ALIAS: /* 0x28 */
999 if (writeflag)
1000 debug("[ sgi_mec: write to MEC_RX_ALIAS: "
1001 "0x%016llx ]\n", (long long)idata);
1002 break;
1003 case MEC_TX_RING_PTR: /* 0x30 */
1004 if (writeflag)
1005 debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
1006 "0x%016llx ]\n", (long long)idata);
1007 break;
1008 case MEC_PHY_DATA: /* 0x64 */
1009 if (writeflag)
1010 fatal("[ sgi_mec: write to MEC_PHY_DATA: "
1011 "0x%016llx ]\n", (long long)idata);
1012 else
1013 odata = 0; /* ? */
1014 break;
1015 case MEC_PHY_ADDRESS: /* 0x6c */
1016 if (writeflag)
1017 debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
1018 "0x%016llx ]\n", (long long)idata);
1019 break;
1020 case MEC_PHY_READ_INITIATE: /* 0x70 */
1021 if (writeflag)
1022 debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
1023 "0x%016llx ]\n", (long long)idata);
1024 break;
1025 case 0x74:
1026 if (writeflag)
1027 debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
1028 (long long)idata);
1029 else
1030 debug("[ sgi_mec: read from 0x74 ]\n");
1031 break;
1032 case MEC_STATION: /* 0xa0 */
1033 if (writeflag)
1034 debug("[ sgi_mec: setting the MAC address to "
1035 "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
1036 (idata >> 40) & 255, (idata >> 32) & 255,
1037 (idata >> 24) & 255, (idata >> 16) & 255,
1038 (idata >> 8) & 255, (idata >> 0) & 255);
1039 break;
1040 case MEC_STATION_ALT: /* 0xa8 */
1041 if (writeflag)
1042 debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
1043 " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
1044 (idata >> 40) & 255, (idata >> 32) & 255,
1045 (idata >> 24) & 255, (idata >> 16) & 255,
1046 (idata >> 8) & 255, (idata >> 0) & 255);
1047 break;
1048 case MEC_MULTICAST: /* 0xb0 */
1049 if (writeflag)
1050 debug("[ sgi_mec: write to MEC_MULTICAST: "
1051 "0x%016llx ]\n", (long long)idata);
1052 break;
1053 case MEC_TX_RING_BASE: /* 0xb8 */
1054 if (writeflag)
1055 debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
1056 "0x%016llx ]\n", (long long)idata);
1057 break;
1058 case MEC_MCL_RX_FIFO: /* 0x100 */
1059 if (writeflag) {
1060 debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
1061 "%016llx ]\n", (long long)idata);
1062 d->rx_addr[d->cur_rx_addr_index_write] = idata;
1063 d->cur_rx_addr_index_write ++;
1064 d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
1065 }
1066 break;
1067 default:
1068 if (writeflag == MEM_WRITE)
1069 fatal("[ sgi_mec: unimplemented write to address"
1070 " 0x%llx, data=0x%016llx ]\n",
1071 (long long)relative_addr, (long long)idata);
1072 else
1073 fatal("[ sgi_mec: unimplemented read from address"
1074 " 0x%llx ]\n", (long long)relative_addr);
1075 }
1076
1077 if (writeflag == MEM_READ)
1078 memory_writemax64(cpu, data, len, odata);
1079
1080 dev_sgi_mec_tick(cpu, extra);
1081
1082 return 1;
1083 }
1084
1085
1086 /*
1087 * dev_sgi_mec_init():
1088 */
1089 void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
1090 uint64_t baseaddr, char *irq_path, unsigned char *macaddr)
1091 {
1092 char *name2;
1093 size_t nlen = 55;
1094 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
1095
1096 if (d == NULL) {
1097 fprintf(stderr, "out of memory\n");
1098 exit(1);
1099 }
1100 memset(d, 0, sizeof(struct sgi_mec_data));
1101
1102 INTERRUPT_CONNECT(irq_path, d->irq);
1103 memcpy(d->macaddr, macaddr, 6);
1104 mec_reset(d);
1105
1106 name2 = malloc(nlen);
1107 if (name2 == NULL) {
1108 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
1109 exit(1);
1110 }
1111 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
1112 d->macaddr[0], d->macaddr[1], d->macaddr[2],
1113 d->macaddr[3], d->macaddr[4], d->macaddr[5]);
1114
1115 memory_device_register(mem, name2, baseaddr,
1116 DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
1117 DM_DEFAULT, NULL);
1118
1119 machine_add_tickfunction(machine, dev_sgi_mec_tick, d,
1120 MEC_TICK_SHIFT, 0.0);
1121
1122 net_add_nic(machine->emul->net, d, macaddr);
1123 }
1124
1125
1126 /****************************************************************************/
1127
1128
1129 struct sgi_ust_data {
1130 uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
1131 };
1132
1133
1134 DEVICE_ACCESS(sgi_ust)
1135 {
1136 struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
1137 uint64_t idata = 0, odata = 0;
1138 int regnr;
1139
1140 idata = memory_readmax64(cpu, data, len);
1141 regnr = relative_addr / sizeof(uint64_t);
1142
1143 /* Treat all registers as read/write, by default. */
1144 if (writeflag == MEM_WRITE)
1145 d->reg[regnr] = idata;
1146 else
1147 odata = d->reg[regnr];
1148
1149 switch (relative_addr) {
1150 case 0:
1151 d->reg[regnr] += 0x2710;
1152 break;
1153 default:
1154 if (writeflag == MEM_WRITE)
1155 debug("[ sgi_ust: unimplemented write to "
1156 "address 0x%llx, data=0x%016llx ]\n",
1157 (long long)relative_addr, (long long)idata);
1158 else
1159 debug("[ sgi_ust: unimplemented read from address"
1160 " 0x%llx ]\n", (long long)relative_addr);
1161 }
1162
1163 if (writeflag == MEM_READ)
1164 memory_writemax64(cpu, data, len, odata);
1165
1166 return 1;
1167 }
1168
1169
1170 /*
1171 * dev_sgi_ust_init():
1172 */
1173 void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1174 {
1175 struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1176 if (d == NULL) {
1177 fprintf(stderr, "out of memory\n");
1178 exit(1);
1179 }
1180 memset(d, 0, sizeof(struct sgi_ust_data));
1181
1182 memory_device_register(mem, "sgi_ust", baseaddr,
1183 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1184 DM_DEFAULT, NULL);
1185 }
1186
1187
1188 /****************************************************************************/
1189
1190
1191 /*
1192 * SGI "mte". This device seems to be an accelerator for copying/clearing
1193 * memory. Used by (at least) the SGI O2 PROM.
1194 *
1195 * Actually, it seems to be used for graphics output as well. (?)
1196 * The O2's PROM uses it to output graphics.
1197 */
1198 /* #define debug fatal */
1199 /* #define MTE_DEBUG */
1200 #define ZERO_CHUNK_LEN 4096
1201
1202 struct sgi_mte_data {
1203 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1204 };
1205
1206
1207 DEVICE_ACCESS(sgi_mte)
1208 {
1209 struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1210 uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1211 unsigned char zerobuf[ZERO_CHUNK_LEN];
1212 uint64_t idata = 0, odata = 0;
1213 int regnr;
1214
1215 idata = memory_readmax64(cpu, data, len);
1216 regnr = relative_addr / sizeof(uint32_t);
1217
1218 /*
1219 * Treat all registers as read/write, by default. Sometimes these
1220 * are accessed as 32-bit words, sometimes as 64-bit words.
1221 */
1222 if (len != 4) {
1223 if (writeflag == MEM_WRITE) {
1224 d->reg[regnr] = idata >> 32;
1225 d->reg[regnr+1] = idata;
1226 } else
1227 odata = ((uint64_t)d->reg[regnr] << 32) +
1228 d->reg[regnr+1];
1229 }
1230
1231 if (writeflag == MEM_WRITE)
1232 d->reg[regnr] = idata;
1233 else
1234 odata = d->reg[regnr];
1235
1236 #ifdef MTE_DEBUG
1237 if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1238 relative_addr < 0x3000)
1239 fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1240 (long long)idata);
1241 #endif
1242
1243 /*
1244 * I've not found any docs about this 'mte' device at all, so this is
1245 * just a guess. The mte seems to be used for copying and zeroing
1246 * chunks of memory.
1247 *
1248 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1249 * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1250 * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1251 * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1252 * write to 0x3800, data=0x0000000000000011 ] <-- operation
1253 * (0x11 = zerofill)
1254 *
1255 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1256 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1257 * write to 0x1710, data=0x80001ea480001ea5
1258 * ...
1259 * write to 0x1770, data=0x80001e9c80001e9d
1260 * write to 0x1778, data=0x80001e9e80001e9f
1261 */
1262 switch (relative_addr) {
1263
1264 /* No warnings for these: */
1265 case 0x3030:
1266 case 0x3038:
1267 break;
1268
1269 /* Unknown, but no warning: */
1270 case 0x4000:
1271 case 0x3018:
1272 case 0x3008:
1273 case 0x1700:
1274 case 0x1708:
1275 case 0x1710:
1276 case 0x1718:
1277 case 0x1720:
1278 case 0x1728:
1279 case 0x1730:
1280 case 0x1738:
1281 case 0x1740:
1282 case 0x1748:
1283 case 0x1750:
1284 case 0x1758:
1285 case 0x1760:
1286 case 0x1768:
1287 case 0x1770:
1288 case 0x1778:
1289 break;
1290
1291 /* Graphics stuff? No warning: */
1292 case 0x2018:
1293 case 0x2060:
1294 case 0x2070:
1295 case 0x2074:
1296 case 0x20c0:
1297 case 0x20c4:
1298 case 0x20d0:
1299 case 0x21b0:
1300 case 0x21b8:
1301 break;
1302
1303 /* Perform graphics operation: */
1304 case 0x21f8:
1305 {
1306 uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1307 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1308 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1309 >> 16) & 0xfff;
1310 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1311 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1312 >> 16) & 0xfff;
1313 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1314 uint32_t y;
1315
1316 op >>= 24;
1317
1318 switch (op) {
1319 case 1: /* Unknown. Used after drawing bitmaps? */
1320 break;
1321 case 3: /* Fill: */
1322 if (x2 < x1) {
1323 int tmp = x1; x1 = x2; x2 = tmp;
1324 }
1325 if (y2 < y1) {
1326 int tmp = y1; y1 = y2; y2 = tmp;
1327 }
1328 for (y=y1; y<=y2; y++) {
1329 unsigned char buf[1280];
1330 int length = x2-x1+1;
1331 int addr = (x1 + y*1280);
1332 if (length < 1)
1333 length = 1;
1334 memset(buf, color, length);
1335 if (x1 < 1280 && y < 1024)
1336 cpu->memory_rw(cpu, cpu->mem,
1337 0x38000000 + addr, buf,
1338 length, MEM_WRITE,
1339 NO_EXCEPTIONS | PHYSICAL);
1340 }
1341 break;
1342
1343 default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1344 "%i,%i\n\n", op, color, x1,y1, x2,y2);
1345 }
1346 }
1347 break;
1348
1349 case 0x29f0:
1350 /* Pixel output: */
1351 {
1352 uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1353 uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1354 uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1355 >> 16) & 0xfff;
1356 uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1357 uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1358 >> 16) & 0xfff;
1359 uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1360 size_t x, y;
1361
1362 if (x2 < x1) {
1363 int tmp = x1; x1 = x2; x2 = tmp;
1364 }
1365 if (y2 < y1) {
1366 int tmp = y1; y1 = y2; y2 = tmp;
1367 }
1368 if (x2-x1 <= 15)
1369 data <<= 16;
1370
1371 x=x1; y=y1;
1372 while (x <= x2 && y <= y2) {
1373 unsigned char buf = color;
1374 int addr = x + y*1280;
1375 int bit_set = data & 0x80000000UL;
1376 data <<= 1;
1377 if (x < 1280 && y < 1024 && bit_set)
1378 cpu->memory_rw(cpu, cpu->mem,
1379 0x38000000 + addr, &buf,1,MEM_WRITE,
1380 NO_EXCEPTIONS | PHYSICAL);
1381 x++;
1382 if (x > x2) {
1383 x = x1;
1384 y++;
1385 }
1386 }
1387 }
1388 break;
1389
1390
1391 /* Operations: */
1392 case 0x3800:
1393 if (writeflag == MEM_WRITE) {
1394 switch (idata) {
1395 case 0x11: /* zerofill */
1396 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1397 last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1398 zerobuflen = last_addr - first_addr + 1;
1399 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1400 " last = 0x%016llx, length = 0x%llx ]\n",
1401 (long long)first_addr, (long long)
1402 last_addr, (long long)zerobuflen);
1403
1404 /* TODO: is there a better way to
1405 implement this? */
1406 memset(zerobuf, 0, sizeof(zerobuf));
1407 fill_addr = first_addr;
1408 while (zerobuflen != 0) {
1409 if (zerobuflen > sizeof(zerobuf))
1410 fill_len = sizeof(zerobuf);
1411 else
1412 fill_len = zerobuflen;
1413 cpu->memory_rw(cpu, mem, fill_addr,
1414 zerobuf, fill_len, MEM_WRITE,
1415 NO_EXCEPTIONS | PHYSICAL);
1416 fill_addr += fill_len;
1417 zerobuflen -= sizeof(zerobuf);
1418 }
1419
1420 break;
1421 default:
1422 fatal("[ sgi_mte: UNKNOWN operation "
1423 "0x%x ]\n", idata);
1424 }
1425 }
1426 break;
1427 default:
1428 if (writeflag == MEM_WRITE)
1429 debug("[ sgi_mte: unimplemented write to "
1430 "address 0x%llx, data=0x%016llx ]\n",
1431 (long long)relative_addr, (long long)idata);
1432 else
1433 debug("[ sgi_mte: unimplemented read from address"
1434 " 0x%llx ]\n", (long long)relative_addr);
1435 }
1436
1437 if (writeflag == MEM_READ)
1438 memory_writemax64(cpu, data, len, odata);
1439
1440 return 1;
1441 }
1442
1443
1444 /*
1445 * dev_sgi_mte_init():
1446 */
1447 void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1448 {
1449 struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1450 if (d == NULL) {
1451 fprintf(stderr, "out of memory\n");
1452 exit(1);
1453 }
1454 memset(d, 0, sizeof(struct sgi_mte_data));
1455
1456 memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1457 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1458 }
1459

  ViewVC Help
Powered by ViewVC 1.1.26