--- trunk/src/devices/dev_jazz.c 2007/10/08 16:19:37 22 +++ trunk/src/devices/dev_jazz.c 2007/10/08 16:22:32 42 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. + * Copyright (C) 2004-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,13 +25,22 @@ * SUCH DAMAGE. * * - * $Id: dev_jazz.c,v 1.23 2006/02/09 20:02:59 debug Exp $ + * $Id: dev_jazz.c,v 1.29 2007/06/15 19:11:15 debug Exp $ * - * Microsoft Jazz-related stuff (Acer PICA-61, etc). + * COMMENT: Microsoft Jazz-related stuff (Acer PICA-61, etc) * * TODO/NOTE: This is mostly a quick hack, it doesn't really implement * much of the Jazz architecture. Also, the a0/20 isa-like stuff is * not supposed to be here. + * + * TODO: Figure out how the int enable mask works; it seems to be shifted + * 10 bits (?) according to NetBSD/arc sources. + * + * TODO: Don't hardcode the timer to 100 Hz. + * + * JAZZ interrupts 0..14 are connected to MIPS irq 3, + * JAZZ interrupt 15 (the timer) is connected to MIPS irq 6, + * and ISA interrupts 0..15 are connected to MIPS irq 4. */ #include @@ -41,18 +50,101 @@ #include "cpu.h" #include "device.h" #include "devices.h" +#include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" +#include "timer.h" #include "jazz_r4030_dma.h" #include "pica.h" +#define DEV_JAZZ_LENGTH 0x280 #define DEV_JAZZ_TICKSHIFT 14 - #define PICA_TIMER_IRQ 15 +struct jazz_data { + struct interrupt mips_irq_3; + struct interrupt mips_irq_4; + struct interrupt mips_irq_6; + + struct cpu *cpu; + + /* Jazz stuff: */ + uint32_t int_enable_mask; /* TODO! */ + uint32_t int_asserted; + + /* ISA stuff: */ + uint32_t isa_int_enable_mask; + uint32_t isa_int_asserted; + + int interval; + int interval_start; + + struct timer *timer; + int pending_timer_interrupts; + int jazz_timer_value; + int jazz_timer_current; + struct interrupt jazz_timer_irq; + + uint64_t dma_translation_table_base; + uint64_t dma_translation_table_limit; + + uint32_t dma0_mode; + uint32_t dma0_enable; + uint32_t dma0_count; + uint32_t dma0_addr; + + uint32_t dma1_mode; + /* same for dma1,2,3 actually (TODO) */ + + int led; +}; + + +void reassert_isa_interrupts(struct jazz_data *d) +{ + if (d->isa_int_asserted & d->isa_int_enable_mask) + INTERRUPT_ASSERT(d->mips_irq_4); + else + INTERRUPT_DEASSERT(d->mips_irq_4); +} + + +void jazz_interrupt_assert(struct interrupt *interrupt) +{ + struct jazz_data *d = interrupt->extra; + d->int_asserted |= (1 << interrupt->line); + + if (d->int_asserted & 0x7fff) + INTERRUPT_ASSERT(d->mips_irq_3); + if (d->int_asserted & 0x8000) + INTERRUPT_ASSERT(d->mips_irq_6); +} +void jazz_interrupt_deassert(struct interrupt *interrupt) +{ + struct jazz_data *d = interrupt->extra; + d->int_asserted &= ~(1 << interrupt->line); + + if (!(d->int_asserted & 0x7fff)) + INTERRUPT_DEASSERT(d->mips_irq_3); + if (!(d->int_asserted & 0x8000)) + INTERRUPT_DEASSERT(d->mips_irq_6); +} +void jazz_isa_interrupt_assert(struct interrupt *interrupt) +{ + struct jazz_data *d = interrupt->extra; + d->isa_int_asserted |= (1 << interrupt->line); + reassert_isa_interrupts(d); +} +void jazz_isa_interrupt_deassert(struct interrupt *interrupt) +{ + struct jazz_data *d = interrupt->extra; + d->isa_int_asserted &= ~(1 << interrupt->line); + reassert_isa_interrupts(d); +} + /* * dev_jazz_dma_controller(): @@ -134,10 +226,14 @@ } -/* - * dev_jazz_tick(): - */ -void dev_jazz_tick(struct cpu *cpu, void *extra) +static void timer_tick(struct timer *t, void *extra) +{ + struct jazz_data *d = extra; + d->pending_timer_interrupts ++; +} + + +DEVICE_TICK(jazz) { struct jazz_data *d = extra; @@ -146,9 +242,13 @@ && (d->int_enable_mask & 2) /* Hm? */ ) { d->interval -= 2; if (d->interval <= 0) { - debug("[ jazz: interval timer interrupt ]\n"); - cpu_interrupt(cpu, 8 + PICA_TIMER_IRQ); + /* debug("[ jazz: interval timer interrupt ]\n"); + INTERRUPT_ASSERT(d->jazz_timer_irq); */ } + + /* New timer system: */ + if (d->pending_timer_interrupts > 0) + INTERRUPT_ASSERT(d->jazz_timer_irq); } /* Linux? */ @@ -156,18 +256,19 @@ d->jazz_timer_current -= 5; if (d->jazz_timer_current < 1) { d->jazz_timer_current = d->jazz_timer_value; - cpu_interrupt(cpu, 6); + /* INTERRUPT_ASSERT(d->mips_irq_6); */ } + + /* New timer system: */ + if (d->pending_timer_interrupts > 0) + INTERRUPT_ASSERT(d->mips_irq_6); } } -/* - * dev_jazz_access(): - */ DEVICE_ACCESS(jazz) { - struct jazz_data *d = (struct jazz_data *) extra; + struct jazz_data *d = extra; uint64_t idata = 0, odata = 0; int regnr; @@ -264,7 +365,10 @@ break; case R4030_SYS_IT_STAT: /* Accessing this word seems to acknowledge interrupts? */ - cpu_interrupt_ack(cpu, 8 + PICA_TIMER_IRQ); + INTERRUPT_DEASSERT(d->jazz_timer_irq); + if (d->pending_timer_interrupts > 0) + d->pending_timer_interrupts --; + if (writeflag == MEM_WRITE) d->interval = idata; else @@ -273,9 +377,28 @@ break; case R4030_SYS_EXT_IMASK: if (writeflag == MEM_WRITE) { + int old_assert_3 = (0x7fff & + d->int_asserted & d->int_enable_mask); + int old_assert_6 = (0x8000 & + d->int_asserted & d->int_enable_mask); + int new_assert_3, new_assert_6; + d->int_enable_mask = idata; - /* Do a "nonsense" interrupt recalibration: */ - cpu_interrupt_ack(cpu, 8); + + new_assert_3 = + d->int_asserted & d->int_enable_mask & 0x7fff; + new_assert_6 = + d->int_asserted & d->int_enable_mask & 0x8000; + + if (old_assert_3 && !new_assert_3) + INTERRUPT_DEASSERT(d->mips_irq_3); + else if (!old_assert_3 && new_assert_3) + INTERRUPT_ASSERT(d->mips_irq_3); + + if (old_assert_6 && !new_assert_6) + INTERRUPT_DEASSERT(d->mips_irq_6); + else if (!old_assert_6 && new_assert_6) + INTERRUPT_ASSERT(d->mips_irq_6); } else odata = d->int_enable_mask; break; @@ -297,12 +420,9 @@ } -/* - * dev_jazz_led_access(): - */ DEVICE_ACCESS(jazz_led) { - struct jazz_data *d = (struct jazz_data *) extra; + struct jazz_data *d = extra; uint64_t idata = 0, odata = 0; int regnr; @@ -348,7 +468,7 @@ */ DEVICE_ACCESS(jazz_a0) { - struct jazz_data *d = (struct jazz_data *) extra; + struct jazz_data *d = extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) @@ -359,7 +479,8 @@ if (writeflag == MEM_WRITE) { /* TODO: only if idata == 0x20? */ d->isa_int_asserted &= 0xff; - cpu_interrupt_ack(cpu, 8 + 0); + + reassert_isa_interrupts(d); } break; case 1: @@ -369,8 +490,8 @@ (d->isa_int_enable_mask & 0xff) | idata; debug("[ jazz_isa_a0: setting isa_int_enable_mask " "to 0x%04x ]\n", (int)d->isa_int_enable_mask); - /* Recompute interrupt stuff: */ - cpu_interrupt_ack(cpu, 8 + 0); + + reassert_isa_interrupts(d); } else odata = d->isa_int_enable_mask; break; @@ -399,7 +520,7 @@ */ DEVICE_ACCESS(jazz_20) { - struct jazz_data *d = (struct jazz_data *) extra; + struct jazz_data *d = extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) @@ -410,7 +531,7 @@ if (writeflag == MEM_WRITE) { /* TODO: only if idata == 0x20? */ d->isa_int_asserted &= 0xff00; - cpu_interrupt_ack(cpu, 8 + 0); + reassert_isa_interrupts(d); } break; case 1: @@ -420,8 +541,8 @@ (d->isa_int_enable_mask & 0xff00) | idata; debug("[ jazz_isa_20: setting isa_int_enable_mask " "to 0x%04x ]\n", (int)d->isa_int_enable_mask); - /* Recompute interrupt stuff: */ - cpu_interrupt_ack(cpu, 8 + 0); + + reassert_isa_interrupts(d); } else odata = d->isa_int_enable_mask; break; @@ -451,7 +572,7 @@ */ DEVICE_ACCESS(jazz_jazzio) { - struct jazz_data *d = (struct jazz_data *) extra; + struct jazz_data *d = extra; uint64_t idata = 0, odata = 0; int i, v; @@ -489,7 +610,7 @@ } /* This is needed by Windows NT during startup: */ - cpu_interrupt_ack(cpu, 3); + INTERRUPT_DEASSERT(d->mips_irq_3); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); @@ -500,17 +621,63 @@ DEVINIT(jazz) { - struct jazz_data *d = malloc(sizeof(struct jazz_data)); - if (d == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } + struct jazz_data *d; + char tmpstr[300]; + int i; + + CHECK_ALLOCATION(d = malloc(sizeof(struct jazz_data))); memset(d, 0, sizeof(struct jazz_data)); d->cpu = devinit->machine->cpus[0]; /* TODO */ d->isa_int_enable_mask = 0xffff; + /* + * Register 16 native JAZZ irqs, and 16 ISA irqs: + * + * emul[x].machine[y].cpu[z].jazz.%i (native) + * emul[x].machine[y].cpu[z].jazz.isa.%i (ISA) + */ + for (i=0; i<16; i++) { + struct interrupt template; + char n[300]; + snprintf(n, sizeof(n), "%s.jazz.%i", + devinit->interrupt_path, i); + memset(&template, 0, sizeof(template)); + template.line = i; + template.name = n; + template.extra = d; + template.interrupt_assert = jazz_interrupt_assert; + template.interrupt_deassert = jazz_interrupt_deassert; + interrupt_handler_register(&template); + } + for (i=0; i<16; i++) { + struct interrupt template; + char n[300]; + snprintf(n, sizeof(n), "%s.jazz.isa.%i", + devinit->interrupt_path, i); + memset(&template, 0, sizeof(template)); + template.line = i; + template.name = n; + template.extra = d; + template.interrupt_assert = jazz_isa_interrupt_assert; + template.interrupt_deassert = jazz_isa_interrupt_deassert; + interrupt_handler_register(&template); + } + + /* Connect to MIPS CPU interrupt lines: */ + snprintf(tmpstr, sizeof(tmpstr), "%s.3", devinit->interrupt_path); + INTERRUPT_CONNECT(tmpstr, d->mips_irq_3); + snprintf(tmpstr, sizeof(tmpstr), "%s.4", devinit->interrupt_path); + INTERRUPT_CONNECT(tmpstr, d->mips_irq_4); + snprintf(tmpstr, sizeof(tmpstr), "%s.6", devinit->interrupt_path); + INTERRUPT_CONNECT(tmpstr, d->mips_irq_6); + + /* Connect to JAZZ timer interrupt: */ + snprintf(tmpstr, sizeof(tmpstr), "%s.jazz.%i", + devinit->interrupt_path, PICA_TIMER_IRQ); + INTERRUPT_CONNECT(tmpstr, d->jazz_timer_irq); + memory_device_register(devinit->machine->memory, "jazz", devinit->addr, DEV_JAZZ_LENGTH, dev_jazz_access, (void *)d, DM_DEFAULT, NULL); @@ -530,6 +697,8 @@ 0xf0000000ULL, 4, dev_jazz_jazzio_access, (void *)d, DM_DEFAULT, NULL); + /* Add a timer, hardcoded to 100 Hz. TODO: Don't hardcode! */ + d->timer = timer_add(100.0, timer_tick, d); machine_add_tickfunction(devinit->machine, dev_jazz_tick, d, DEV_JAZZ_TICKSHIFT);