--- trunk/src/devices/dev_gc.c 2007/10/08 16:19:56 24 +++ trunk/src/devices/dev_openpic.c 2007/10/14 14:56:57 68 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. + * Copyright (C) 2005-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: @@ -24,9 +24,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dev_gc.c,v 1.8 2006/02/27 05:32:26 debug Exp $ + * $Id: dev_openpic.c,v 1.14 2007/09/11 21:42:52 debug Exp $ * - * Grand Central Interrupt controller (used by MacPPC). + * COMMENT: OpenPIC Interrupt controller (used by sandpoint ppc) + * based on dev_gc.c */ #include @@ -35,22 +36,123 @@ #include "cpu.h" #include "device.h" -#include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" -DEVICE_ACCESS(gc) +#define DEV_OPENPIC_LENGTH 0x40000 + +struct openpic_data { + struct interrupt cpu_irq; + + uint32_t status_hi; + uint32_t status_lo; + uint32_t enable_hi; + uint32_t enable_lo; +}; + + +void openpic_hi_interrupt_assert(struct interrupt *interrupt) +{ + struct openpic_data *d = interrupt->extra; + d->status_hi |= interrupt->line; + if (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi) + INTERRUPT_ASSERT(d->cpu_irq); +} +void openpic_hi_interrupt_deassert(struct interrupt *interrupt) +{ + struct openpic_data *d = interrupt->extra; + d->status_hi &= ~interrupt->line; + if (!(d->status_lo & d->enable_lo || d->status_hi & d->enable_hi)) + INTERRUPT_DEASSERT(d->cpu_irq); +} +void openpic_lo_interrupt_assert(struct interrupt *interrupt) +{ + struct openpic_data *d = interrupt->extra; + d->status_lo |= interrupt->line; + if (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi) + INTERRUPT_ASSERT(d->cpu_irq); +} +void openpic_lo_interrupt_deassert(struct interrupt *interrupt) +{ + struct openpic_data *d = interrupt->extra; + d->status_lo &= ~interrupt->line; + if (!(d->status_lo & d->enable_lo || d->status_hi & d->enable_hi)) + INTERRUPT_DEASSERT(d->cpu_irq); +} + +/* + * FIXME acitvity is never sat + */ + +#define OPENPIC_MASK 0x80000000 +#define OPENPIC_ACTIVITY 0x40000000 /* Read Only */ +#define OPENPIC_PRIORITY_MASK 0x000f0000 +#define OPENPIC_PRIORITY_SHIFT 16 +#define OPENPIC_VECTOR_MASK 0x000000ff + +#define OPENPIC_VEC_TIMER 64 /* and up */ +#define OPENPIC_VEC_IPI 72 /* and up */ +#define OPENPIC_VEC_SPURIOUS 127 + +#define OPENPIC_NUM_TIMERS 4 +#define OPENPIC_NUM_IPI 4 +#define OPENPIC_NUM_PRI 16 +#define OPENPIC_NUM_VECTORS 256 + +DEVICE_ACCESS(openpic) { - struct gc_data *d = extra; +// struct openpic_data *d = extra; uint64_t idata = 0, odata = 0; - if (writeflag == MEM_WRITE) + if (writeflag == MEM_WRITE) { idata = memory_readmax64(cpu, data, len); + // shuffle byte order + idata = + ( idata & 0x000000ff ) << 24 | + ( idata & 0x0000ff00 ) << 8 | + ( idata & 0x00ff0000 ) >> 8 | + ( idata & 0xff000000 ) >> 24 ; + + uint64_t priority,vector, active; + priority = ( idata & OPENPIC_PRIORITY_MASK ) >> OPENPIC_PRIORITY_SHIFT; + vector = ( idata & OPENPIC_VECTOR_MASK ); + active = ( idata & OPENPIC_ACTIVITY ); + + debug("[ openpic: WRITE %05x | %08x | priority: %x vector: 0x%02x %d active: %x ]\n", + (int)relative_addr, (int)idata, (int)priority, (int)vector, (int)vector, (int)active ); + } switch (relative_addr) { + // version + case 0x00: + if (writeflag == MEM_READ) { + // version 1.2 + odata = 0x02000000; + fatal("[ openpic: read version " + "offset 0x%x = %x]\n", (int) + relative_addr, (int)odata); + } + fatal("[ openpic: unimplemented write to " + "offset 0x%x: data=0x%x (OpenPIC version) ]\n", (int) + relative_addr, (int)idata); + break; + + // global timer frequency + case 0xf0: + if (writeflag == MEM_READ) { + odata = 170 * 1000000; // MHz + fatal("[ openpic: read global timer frequency " + "offset 0x%x = %x]\n", (int) + relative_addr, (int)odata); + } + fatal("[ openpic: unimplemented write to " + "offset 0x%x: data=0x%x ]\n", (int) + relative_addr, (int)idata); + break; + #if 0 #define INT_STATE_REG_H (interrupt_reg + 0x00) #define INT_ENABLE_REG_H (interrupt_reg + 0x04) @@ -60,7 +162,6 @@ #define INT_ENABLE_REG_L (interrupt_reg + 0x14) #define INT_CLEAR_REG_L (interrupt_reg + 0x18) #define INT_LEVEL_REG_L (interrupt_reg + 0x1c) -#endif case 0x10: if (writeflag == MEM_READ) @@ -71,19 +172,35 @@ if (writeflag == MEM_READ) odata = d->enable_hi; else { - uint32_t old_enable_hi = d->enable_hi; + int old_assert = (d->status_lo & d->enable_lo + || d->status_hi & d->enable_hi); + int new_assert; d->enable_hi = idata; - if (d->enable_hi != old_enable_hi) - cpu_interrupt(cpu, d->reassert_irq); + + new_assert = (d->status_lo & d->enable_lo || + d->status_hi & d->enable_hi); + + if (old_assert && !new_assert) + INTERRUPT_DEASSERT(d->cpu_irq); + else if (!old_assert && new_assert) + INTERRUPT_ASSERT(d->cpu_irq); } break; case 0x18: if (writeflag == MEM_WRITE) { - uint32_t old_status_hi = d->status_hi; + int old_assert = (d->status_lo & d->enable_lo + || d->status_hi & d->enable_hi); + int new_assert; d->status_hi &= ~idata; - if (d->status_hi != old_status_hi) - cpu_interrupt(cpu, d->reassert_irq); + + new_assert = (d->status_lo & d->enable_lo || + d->status_hi & d->enable_hi); + + if (old_assert && !new_assert) + INTERRUPT_DEASSERT(d->cpu_irq); + else if (!old_assert && new_assert) + INTERRUPT_ASSERT(d->cpu_irq); } break; @@ -96,62 +213,106 @@ if (writeflag == MEM_READ) odata = d->enable_lo; else { - uint32_t old_enable_lo = d->enable_lo; + int old_assert = (d->status_lo & d->enable_lo + || d->status_hi & d->enable_hi); + int new_assert; d->enable_lo = idata; - if (d->enable_lo != old_enable_lo) - cpu_interrupt(cpu, d->reassert_irq); + + new_assert = (d->status_lo & d->enable_lo || + d->status_hi & d->enable_hi); + + if (old_assert && !new_assert) + INTERRUPT_DEASSERT(d->cpu_irq); + else if (!old_assert && new_assert) + INTERRUPT_ASSERT(d->cpu_irq); } break; case 0x28: if (writeflag == MEM_WRITE) { - uint32_t old_status_lo = d->status_lo; + int old_assert = (d->status_lo & d->enable_lo + || d->status_hi & d->enable_hi); + int new_assert; d->status_lo &= ~idata; - if (d->status_lo != old_status_lo) - cpu_interrupt(cpu, d->reassert_irq); + + new_assert = (d->status_lo & d->enable_lo || + d->status_hi & d->enable_hi); + + if (old_assert && !new_assert) + INTERRUPT_DEASSERT(d->cpu_irq); + else if (!old_assert && new_assert) + INTERRUPT_ASSERT(d->cpu_irq); } break; + case 0x1c: case 0x2c: - /* Avoir a debug message. */ + /* Avoid a debug message. */ break; - - default:if (writeflag == MEM_WRITE) { - fatal("[ gc: unimplemented write to " - "offset 0x%x: data=0x%x ]\n", (int) - relative_addr, (int)idata); +#endif + default: + if (writeflag == MEM_WRITE) { + fatal("[ openpic: unimplemented write to " + "offset 0x%x idata = %x ]\n", + (int)relative_addr, (int)idata + ); } else { - fatal("[ gc: unimplemented read from " - "offset 0x%x ]\n", (int)relative_addr); + fatal("[ openpic: unimplemented read from " + "offset 0x%x odata = %x ]\n", + (int)relative_addr, (int)odata + ); } } - if (writeflag == MEM_READ) + if (writeflag == MEM_READ) { + // shuffle byte order + odata = + ( odata & 0x000000ff ) << 24 | + ( odata & 0x0000ff00 ) << 8 | + ( odata & 0x00ff0000 ) >> 8 | + ( odata & 0xff000000 ) >> 24 ; memory_writemax64(cpu, data, len, odata); + debug("[ openpic: READ %05x | %08x ]\n", + (int)relative_addr, (int)odata + ); + } return 1; } -/* - * dev_gc_init(): - */ -struct gc_data *dev_gc_init(struct machine *machine, struct memory *mem, - uint64_t addr, int reassert_irq) +DEVINIT(openpic) { - struct gc_data *d; + struct openpic_data *d; + int i; + + CHECK_ALLOCATION(d = malloc(sizeof(struct openpic_data))); + memset(d, 0, sizeof(struct openpic_data)); - d = malloc(sizeof(struct gc_data)); - if (d == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); + /* Connect to the CPU interrupt pin: */ + INTERRUPT_CONNECT(devinit->interrupt_path, d->cpu_irq); + + /* + * Register the 126 OpenPIC interrupts + */ + for (i=0; i<126; i++) { + struct interrupt template; + char n[300]; + snprintf(n, sizeof(n), "%s.openpic.%i", + devinit->interrupt_path, i); + memset(&template, 0, sizeof(template)); + template.line = 1 << i; + template.name = n; + template.extra = d; + template.interrupt_assert = openpic_lo_interrupt_assert; + template.interrupt_deassert = openpic_lo_interrupt_deassert; + interrupt_handler_register(&template); + debug("[ openpic: added interrupt %s ]\n", n); } - memset(d, 0, sizeof(struct gc_data)); - d->reassert_irq = reassert_irq; - memory_device_register(mem, "gc", addr, 0x100, - dev_gc_access, d, DM_DEFAULT, NULL); + memory_device_register(devinit->machine->memory, "openpic", + devinit->addr, DEV_OPENPIC_LENGTH, dev_openpic_access, d, DM_DEFAULT, NULL); - return d; + return 1; }