1 |
/* |
/* |
2 |
* Copyright (C) 2004-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2004-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_jazz.c,v 1.24 2006/03/04 12:38:47 debug Exp $ |
* $Id: dev_jazz.c,v 1.27 2007/01/28 13:28:27 debug Exp $ |
29 |
* |
* |
30 |
* Microsoft Jazz-related stuff (Acer PICA-61, etc). |
* Microsoft Jazz-related stuff (Acer PICA-61, etc). |
31 |
* |
* |
32 |
* TODO/NOTE: This is mostly a quick hack, it doesn't really implement |
* TODO/NOTE: This is mostly a quick hack, it doesn't really implement |
33 |
* much of the Jazz architecture. Also, the a0/20 isa-like stuff is |
* much of the Jazz architecture. Also, the a0/20 isa-like stuff is |
34 |
* not supposed to be here. |
* not supposed to be here. |
35 |
|
* |
36 |
|
* TODO: Figure out how the int enable mask works; it seems to be shifted |
37 |
|
* 10 bits (?) according to NetBSD/arc sources. |
38 |
|
* |
39 |
|
* TODO: Don't hardcode the timer to 100 Hz. |
40 |
|
* |
41 |
|
* JAZZ interrupts 0..14 are connected to MIPS irq 3, |
42 |
|
* JAZZ interrupt 15 (the timer) is connected to MIPS irq 6, |
43 |
|
* and ISA interrupts 0..15 are connected to MIPS irq 4. |
44 |
*/ |
*/ |
45 |
|
|
46 |
#include <stdio.h> |
#include <stdio.h> |
50 |
#include "cpu.h" |
#include "cpu.h" |
51 |
#include "device.h" |
#include "device.h" |
52 |
#include "devices.h" |
#include "devices.h" |
53 |
|
#include "interrupt.h" |
54 |
#include "machine.h" |
#include "machine.h" |
55 |
#include "memory.h" |
#include "memory.h" |
56 |
#include "misc.h" |
#include "misc.h" |
57 |
|
#include "timer.h" |
58 |
|
|
59 |
#include "jazz_r4030_dma.h" |
#include "jazz_r4030_dma.h" |
60 |
#include "pica.h" |
#include "pica.h" |
61 |
|
|
62 |
|
|
63 |
|
#define DEV_JAZZ_LENGTH 0x280 |
64 |
#define DEV_JAZZ_TICKSHIFT 14 |
#define DEV_JAZZ_TICKSHIFT 14 |
|
|
|
65 |
#define PICA_TIMER_IRQ 15 |
#define PICA_TIMER_IRQ 15 |
66 |
|
|
67 |
|
struct jazz_data { |
68 |
|
struct interrupt mips_irq_3; |
69 |
|
struct interrupt mips_irq_4; |
70 |
|
struct interrupt mips_irq_6; |
71 |
|
|
72 |
|
struct cpu *cpu; |
73 |
|
|
74 |
|
/* Jazz stuff: */ |
75 |
|
uint32_t int_enable_mask; /* TODO! */ |
76 |
|
uint32_t int_asserted; |
77 |
|
|
78 |
|
/* ISA stuff: */ |
79 |
|
uint32_t isa_int_enable_mask; |
80 |
|
uint32_t isa_int_asserted; |
81 |
|
|
82 |
|
int interval; |
83 |
|
int interval_start; |
84 |
|
|
85 |
|
struct timer *timer; |
86 |
|
int pending_timer_interrupts; |
87 |
|
int jazz_timer_value; |
88 |
|
int jazz_timer_current; |
89 |
|
struct interrupt jazz_timer_irq; |
90 |
|
|
91 |
|
uint64_t dma_translation_table_base; |
92 |
|
uint64_t dma_translation_table_limit; |
93 |
|
|
94 |
|
uint32_t dma0_mode; |
95 |
|
uint32_t dma0_enable; |
96 |
|
uint32_t dma0_count; |
97 |
|
uint32_t dma0_addr; |
98 |
|
|
99 |
|
uint32_t dma1_mode; |
100 |
|
/* same for dma1,2,3 actually (TODO) */ |
101 |
|
|
102 |
|
int led; |
103 |
|
}; |
104 |
|
|
105 |
|
|
106 |
|
void reassert_isa_interrupts(struct jazz_data *d) |
107 |
|
{ |
108 |
|
if (d->isa_int_asserted & d->isa_int_enable_mask) |
109 |
|
INTERRUPT_ASSERT(d->mips_irq_4); |
110 |
|
else |
111 |
|
INTERRUPT_DEASSERT(d->mips_irq_4); |
112 |
|
} |
113 |
|
|
114 |
|
|
115 |
|
void jazz_interrupt_assert(struct interrupt *interrupt) |
116 |
|
{ |
117 |
|
struct jazz_data *d = interrupt->extra; |
118 |
|
d->int_asserted |= (1 << interrupt->line); |
119 |
|
|
120 |
|
if (d->int_asserted & 0x7fff) |
121 |
|
INTERRUPT_ASSERT(d->mips_irq_3); |
122 |
|
if (d->int_asserted & 0x8000) |
123 |
|
INTERRUPT_ASSERT(d->mips_irq_6); |
124 |
|
} |
125 |
|
void jazz_interrupt_deassert(struct interrupt *interrupt) |
126 |
|
{ |
127 |
|
struct jazz_data *d = interrupt->extra; |
128 |
|
d->int_asserted &= ~(1 << interrupt->line); |
129 |
|
|
130 |
|
if (!(d->int_asserted & 0x7fff)) |
131 |
|
INTERRUPT_DEASSERT(d->mips_irq_3); |
132 |
|
if (!(d->int_asserted & 0x8000)) |
133 |
|
INTERRUPT_DEASSERT(d->mips_irq_6); |
134 |
|
} |
135 |
|
void jazz_isa_interrupt_assert(struct interrupt *interrupt) |
136 |
|
{ |
137 |
|
struct jazz_data *d = interrupt->extra; |
138 |
|
d->isa_int_asserted |= (1 << interrupt->line); |
139 |
|
reassert_isa_interrupts(d); |
140 |
|
} |
141 |
|
void jazz_isa_interrupt_deassert(struct interrupt *interrupt) |
142 |
|
{ |
143 |
|
struct jazz_data *d = interrupt->extra; |
144 |
|
d->isa_int_asserted &= ~(1 << interrupt->line); |
145 |
|
reassert_isa_interrupts(d); |
146 |
|
} |
147 |
|
|
148 |
|
|
149 |
/* |
/* |
150 |
* dev_jazz_dma_controller(): |
* dev_jazz_dma_controller(): |
226 |
} |
} |
227 |
|
|
228 |
|
|
229 |
/* |
static void timer_tick(struct timer *t, void *extra) |
230 |
* dev_jazz_tick(): |
{ |
231 |
*/ |
struct jazz_data *d = extra; |
232 |
void dev_jazz_tick(struct cpu *cpu, void *extra) |
d->pending_timer_interrupts ++; |
233 |
|
} |
234 |
|
|
235 |
|
|
236 |
|
DEVICE_TICK(jazz) |
237 |
{ |
{ |
238 |
struct jazz_data *d = extra; |
struct jazz_data *d = extra; |
239 |
|
|
242 |
&& (d->int_enable_mask & 2) /* Hm? */ ) { |
&& (d->int_enable_mask & 2) /* Hm? */ ) { |
243 |
d->interval -= 2; |
d->interval -= 2; |
244 |
if (d->interval <= 0) { |
if (d->interval <= 0) { |
245 |
debug("[ jazz: interval timer interrupt ]\n"); |
/* debug("[ jazz: interval timer interrupt ]\n"); |
246 |
cpu_interrupt(cpu, 8 + PICA_TIMER_IRQ); |
INTERRUPT_ASSERT(d->jazz_timer_irq); */ |
247 |
} |
} |
248 |
|
|
249 |
|
/* New timer system: */ |
250 |
|
if (d->pending_timer_interrupts > 0) |
251 |
|
INTERRUPT_ASSERT(d->jazz_timer_irq); |
252 |
} |
} |
253 |
|
|
254 |
/* Linux? */ |
/* Linux? */ |
256 |
d->jazz_timer_current -= 5; |
d->jazz_timer_current -= 5; |
257 |
if (d->jazz_timer_current < 1) { |
if (d->jazz_timer_current < 1) { |
258 |
d->jazz_timer_current = d->jazz_timer_value; |
d->jazz_timer_current = d->jazz_timer_value; |
259 |
cpu_interrupt(cpu, 6); |
/* INTERRUPT_ASSERT(d->mips_irq_6); */ |
260 |
} |
} |
261 |
|
|
262 |
|
/* New timer system: */ |
263 |
|
if (d->pending_timer_interrupts > 0) |
264 |
|
INTERRUPT_ASSERT(d->mips_irq_6); |
265 |
} |
} |
266 |
} |
} |
267 |
|
|
268 |
|
|
|
/* |
|
|
* dev_jazz_access(): |
|
|
*/ |
|
269 |
DEVICE_ACCESS(jazz) |
DEVICE_ACCESS(jazz) |
270 |
{ |
{ |
271 |
struct jazz_data *d = (struct jazz_data *) extra; |
struct jazz_data *d = (struct jazz_data *) extra; |
365 |
break; |
break; |
366 |
case R4030_SYS_IT_STAT: |
case R4030_SYS_IT_STAT: |
367 |
/* Accessing this word seems to acknowledge interrupts? */ |
/* Accessing this word seems to acknowledge interrupts? */ |
368 |
cpu_interrupt_ack(cpu, 8 + PICA_TIMER_IRQ); |
INTERRUPT_DEASSERT(d->jazz_timer_irq); |
369 |
|
if (d->pending_timer_interrupts > 0) |
370 |
|
d->pending_timer_interrupts --; |
371 |
|
|
372 |
if (writeflag == MEM_WRITE) |
if (writeflag == MEM_WRITE) |
373 |
d->interval = idata; |
d->interval = idata; |
374 |
else |
else |
377 |
break; |
break; |
378 |
case R4030_SYS_EXT_IMASK: |
case R4030_SYS_EXT_IMASK: |
379 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
380 |
|
int old_assert_3 = (0x7fff & |
381 |
|
d->int_asserted & d->int_enable_mask); |
382 |
|
int old_assert_6 = (0x8000 & |
383 |
|
d->int_asserted & d->int_enable_mask); |
384 |
|
int new_assert_3, new_assert_6; |
385 |
|
|
386 |
d->int_enable_mask = idata; |
d->int_enable_mask = idata; |
387 |
/* Do a "nonsense" interrupt recalibration: */ |
|
388 |
cpu_interrupt_ack(cpu, 8); |
new_assert_3 = |
389 |
|
d->int_asserted & d->int_enable_mask & 0x7fff; |
390 |
|
new_assert_6 = |
391 |
|
d->int_asserted & d->int_enable_mask & 0x8000; |
392 |
|
|
393 |
|
if (old_assert_3 && !new_assert_3) |
394 |
|
INTERRUPT_DEASSERT(d->mips_irq_3); |
395 |
|
else if (!old_assert_3 && new_assert_3) |
396 |
|
INTERRUPT_ASSERT(d->mips_irq_3); |
397 |
|
|
398 |
|
if (old_assert_6 && !new_assert_6) |
399 |
|
INTERRUPT_DEASSERT(d->mips_irq_6); |
400 |
|
else if (!old_assert_6 && new_assert_6) |
401 |
|
INTERRUPT_ASSERT(d->mips_irq_6); |
402 |
} else |
} else |
403 |
odata = d->int_enable_mask; |
odata = d->int_enable_mask; |
404 |
break; |
break; |
420 |
} |
} |
421 |
|
|
422 |
|
|
|
/* |
|
|
* dev_jazz_led_access(): |
|
|
*/ |
|
423 |
DEVICE_ACCESS(jazz_led) |
DEVICE_ACCESS(jazz_led) |
424 |
{ |
{ |
425 |
struct jazz_data *d = (struct jazz_data *) extra; |
struct jazz_data *d = (struct jazz_data *) extra; |
479 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
480 |
/* TODO: only if idata == 0x20? */ |
/* TODO: only if idata == 0x20? */ |
481 |
d->isa_int_asserted &= 0xff; |
d->isa_int_asserted &= 0xff; |
482 |
cpu_interrupt_ack(cpu, 8 + 0); |
|
483 |
|
reassert_isa_interrupts(d); |
484 |
} |
} |
485 |
break; |
break; |
486 |
case 1: |
case 1: |
490 |
(d->isa_int_enable_mask & 0xff) | idata; |
(d->isa_int_enable_mask & 0xff) | idata; |
491 |
debug("[ jazz_isa_a0: setting isa_int_enable_mask " |
debug("[ jazz_isa_a0: setting isa_int_enable_mask " |
492 |
"to 0x%04x ]\n", (int)d->isa_int_enable_mask); |
"to 0x%04x ]\n", (int)d->isa_int_enable_mask); |
493 |
/* Recompute interrupt stuff: */ |
|
494 |
cpu_interrupt_ack(cpu, 8 + 0); |
reassert_isa_interrupts(d); |
495 |
} else |
} else |
496 |
odata = d->isa_int_enable_mask; |
odata = d->isa_int_enable_mask; |
497 |
break; |
break; |
531 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
532 |
/* TODO: only if idata == 0x20? */ |
/* TODO: only if idata == 0x20? */ |
533 |
d->isa_int_asserted &= 0xff00; |
d->isa_int_asserted &= 0xff00; |
534 |
cpu_interrupt_ack(cpu, 8 + 0); |
reassert_isa_interrupts(d); |
535 |
} |
} |
536 |
break; |
break; |
537 |
case 1: |
case 1: |
541 |
(d->isa_int_enable_mask & 0xff00) | idata; |
(d->isa_int_enable_mask & 0xff00) | idata; |
542 |
debug("[ jazz_isa_20: setting isa_int_enable_mask " |
debug("[ jazz_isa_20: setting isa_int_enable_mask " |
543 |
"to 0x%04x ]\n", (int)d->isa_int_enable_mask); |
"to 0x%04x ]\n", (int)d->isa_int_enable_mask); |
544 |
/* Recompute interrupt stuff: */ |
|
545 |
cpu_interrupt_ack(cpu, 8 + 0); |
reassert_isa_interrupts(d); |
546 |
} else |
} else |
547 |
odata = d->isa_int_enable_mask; |
odata = d->isa_int_enable_mask; |
548 |
break; |
break; |
610 |
} |
} |
611 |
|
|
612 |
/* This is needed by Windows NT during startup: */ |
/* This is needed by Windows NT during startup: */ |
613 |
cpu_interrupt_ack(cpu, 3); |
INTERRUPT_DEASSERT(d->mips_irq_3); |
614 |
|
|
615 |
if (writeflag == MEM_READ) |
if (writeflag == MEM_READ) |
616 |
memory_writemax64(cpu, data, len, odata); |
memory_writemax64(cpu, data, len, odata); |
621 |
|
|
622 |
DEVINIT(jazz) |
DEVINIT(jazz) |
623 |
{ |
{ |
624 |
|
char tmpstr[300]; |
625 |
|
int i; |
626 |
struct jazz_data *d = malloc(sizeof(struct jazz_data)); |
struct jazz_data *d = malloc(sizeof(struct jazz_data)); |
627 |
if (d == NULL) { |
if (d == NULL) { |
628 |
fprintf(stderr, "out of memory\n"); |
fprintf(stderr, "out of memory\n"); |
634 |
|
|
635 |
d->isa_int_enable_mask = 0xffff; |
d->isa_int_enable_mask = 0xffff; |
636 |
|
|
637 |
|
/* |
638 |
|
* Register 16 native JAZZ irqs, and 16 ISA irqs: |
639 |
|
* |
640 |
|
* emul[x].machine[y].cpu[z].jazz.%i (native) |
641 |
|
* emul[x].machine[y].cpu[z].jazz.isa.%i (ISA) |
642 |
|
*/ |
643 |
|
for (i=0; i<16; i++) { |
644 |
|
struct interrupt template; |
645 |
|
char n[300]; |
646 |
|
snprintf(n, sizeof(n), "%s.jazz.%i", |
647 |
|
devinit->interrupt_path, i); |
648 |
|
memset(&template, 0, sizeof(template)); |
649 |
|
template.line = i; |
650 |
|
template.name = n; |
651 |
|
template.extra = d; |
652 |
|
template.interrupt_assert = jazz_interrupt_assert; |
653 |
|
template.interrupt_deassert = jazz_interrupt_deassert; |
654 |
|
interrupt_handler_register(&template); |
655 |
|
} |
656 |
|
for (i=0; i<16; i++) { |
657 |
|
struct interrupt template; |
658 |
|
char n[300]; |
659 |
|
snprintf(n, sizeof(n), "%s.jazz.isa.%i", |
660 |
|
devinit->interrupt_path, i); |
661 |
|
memset(&template, 0, sizeof(template)); |
662 |
|
template.line = i; |
663 |
|
template.name = n; |
664 |
|
template.extra = d; |
665 |
|
template.interrupt_assert = jazz_isa_interrupt_assert; |
666 |
|
template.interrupt_deassert = jazz_isa_interrupt_deassert; |
667 |
|
interrupt_handler_register(&template); |
668 |
|
} |
669 |
|
|
670 |
|
/* Connect to MIPS CPU interrupt lines: */ |
671 |
|
snprintf(tmpstr, sizeof(tmpstr), "%s.3", devinit->interrupt_path); |
672 |
|
INTERRUPT_CONNECT(tmpstr, d->mips_irq_3); |
673 |
|
snprintf(tmpstr, sizeof(tmpstr), "%s.4", devinit->interrupt_path); |
674 |
|
INTERRUPT_CONNECT(tmpstr, d->mips_irq_4); |
675 |
|
snprintf(tmpstr, sizeof(tmpstr), "%s.6", devinit->interrupt_path); |
676 |
|
INTERRUPT_CONNECT(tmpstr, d->mips_irq_6); |
677 |
|
|
678 |
|
/* Connect to JAZZ timer interrupt: */ |
679 |
|
snprintf(tmpstr, sizeof(tmpstr), "%s.jazz.%i", |
680 |
|
devinit->interrupt_path, PICA_TIMER_IRQ); |
681 |
|
INTERRUPT_CONNECT(tmpstr, d->jazz_timer_irq); |
682 |
|
|
683 |
memory_device_register(devinit->machine->memory, "jazz", |
memory_device_register(devinit->machine->memory, "jazz", |
684 |
devinit->addr, DEV_JAZZ_LENGTH, |
devinit->addr, DEV_JAZZ_LENGTH, |
685 |
dev_jazz_access, (void *)d, DM_DEFAULT, NULL); |
dev_jazz_access, (void *)d, DM_DEFAULT, NULL); |
699 |
0xf0000000ULL, 4, dev_jazz_jazzio_access, (void *)d, |
0xf0000000ULL, 4, dev_jazz_jazzio_access, (void *)d, |
700 |
DM_DEFAULT, NULL); |
DM_DEFAULT, NULL); |
701 |
|
|
702 |
|
/* Add a timer, hardcoded to 100 Hz. TODO: Don't hardcode! */ |
703 |
|
d->timer = timer_add(100.0, timer_tick, d); |
704 |
machine_add_tickfunction(devinit->machine, dev_jazz_tick, |
machine_add_tickfunction(devinit->machine, dev_jazz_tick, |
705 |
d, DEV_JAZZ_TICKSHIFT, 0.0); |
d, DEV_JAZZ_TICKSHIFT, 0.0); |
706 |
|
|