From 9743b581a819a05668e6a1f60e3ee6486d25f141 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: m68k: move files referencing CPU to hw/m68k/ Signed-off-by: Paolo Bonzini --- hw/m68k/Makefile.objs | 3 +- hw/m68k/mcf5206.c | 548 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/m68k/mcf_intc.c | 154 ++++++++++++++ hw/mcf5206.c | 548 -------------------------------------------------- hw/mcf_intc.c | 154 -------------- 5 files changed, 704 insertions(+), 703 deletions(-) create mode 100644 hw/m68k/mcf5206.c create mode 100644 hw/m68k/mcf_intc.c delete mode 100644 hw/mcf5206.c delete mode 100644 hw/mcf_intc.c (limited to 'hw') diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs index 7c033a886c..ede32a7c4e 100644 --- a/hw/m68k/Makefile.objs +++ b/hw/m68k/Makefile.objs @@ -1,7 +1,8 @@ -obj-y = mcf5206.o mcf_uart.o mcf_intc.o mcf_fec.o +obj-y = mcf_uart.o mcf_fec.o obj-y := $(addprefix ../,$(obj-y)) obj-y += an5206.o mcf5208.o obj-y += dummy_m68k.o +obj-y += mcf5206.o mcf_intc.o diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c new file mode 100644 index 0000000000..58cd8d46c9 --- /dev/null +++ b/hw/m68k/mcf5206.c @@ -0,0 +1,548 @@ +/* + * Motorola ColdFire MCF5206 SoC embedded peripheral emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ +#include "hw/hw.h" +#include "hw/mcf.h" +#include "qemu/timer.h" +#include "hw/ptimer.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" + +/* General purpose timer module. */ +typedef struct { + uint16_t tmr; + uint16_t trr; + uint16_t tcr; + uint16_t ter; + ptimer_state *timer; + qemu_irq irq; + int irq_state; +} m5206_timer_state; + +#define TMR_RST 0x01 +#define TMR_CLK 0x06 +#define TMR_FRR 0x08 +#define TMR_ORI 0x10 +#define TMR_OM 0x20 +#define TMR_CE 0xc0 + +#define TER_CAP 0x01 +#define TER_REF 0x02 + +static void m5206_timer_update(m5206_timer_state *s) +{ + if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF)) + qemu_irq_raise(s->irq); + else + qemu_irq_lower(s->irq); +} + +static void m5206_timer_reset(m5206_timer_state *s) +{ + s->tmr = 0; + s->trr = 0; +} + +static void m5206_timer_recalibrate(m5206_timer_state *s) +{ + int prescale; + int mode; + + ptimer_stop(s->timer); + + if ((s->tmr & TMR_RST) == 0) + return; + + prescale = (s->tmr >> 8) + 1; + mode = (s->tmr >> 1) & 3; + if (mode == 2) + prescale *= 16; + + if (mode == 3 || mode == 0) + hw_error("m5206_timer: mode %d not implemented\n", mode); + if ((s->tmr & TMR_FRR) == 0) + hw_error("m5206_timer: free running mode not implemented\n"); + + /* Assume 66MHz system clock. */ + ptimer_set_freq(s->timer, 66000000 / prescale); + + ptimer_set_limit(s->timer, s->trr, 0); + + ptimer_run(s->timer, 0); +} + +static void m5206_timer_trigger(void *opaque) +{ + m5206_timer_state *s = (m5206_timer_state *)opaque; + s->ter |= TER_REF; + m5206_timer_update(s); +} + +static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr) +{ + switch (addr) { + case 0: + return s->tmr; + case 4: + return s->trr; + case 8: + return s->tcr; + case 0xc: + return s->trr - ptimer_get_count(s->timer); + case 0x11: + return s->ter; + default: + return 0; + } +} + +static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) +{ + switch (addr) { + case 0: + if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) { + m5206_timer_reset(s); + } + s->tmr = val; + m5206_timer_recalibrate(s); + break; + case 4: + s->trr = val; + m5206_timer_recalibrate(s); + break; + case 8: + s->tcr = val; + break; + case 0xc: + ptimer_set_count(s->timer, val); + break; + case 0x11: + s->ter &= ~val; + break; + default: + break; + } + m5206_timer_update(s); +} + +static m5206_timer_state *m5206_timer_init(qemu_irq irq) +{ + m5206_timer_state *s; + QEMUBH *bh; + + s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state)); + bh = qemu_bh_new(m5206_timer_trigger, s); + s->timer = ptimer_init(bh); + s->irq = irq; + m5206_timer_reset(s); + return s; +} + +/* System Integration Module. */ + +typedef struct { + M68kCPU *cpu; + MemoryRegion iomem; + m5206_timer_state *timer[2]; + void *uart[2]; + uint8_t scr; + uint8_t icr[14]; + uint16_t imr; /* 1 == interrupt is masked. */ + uint16_t ipr; + uint8_t rsr; + uint8_t swivr; + uint8_t par; + /* Include the UART vector registers here. */ + uint8_t uivr[2]; +} m5206_mbar_state; + +/* Interrupt controller. */ + +static int m5206_find_pending_irq(m5206_mbar_state *s) +{ + int level; + int vector; + uint16_t active; + int i; + + level = 0; + vector = 0; + active = s->ipr & ~s->imr; + if (!active) + return 0; + + for (i = 1; i < 14; i++) { + if (active & (1 << i)) { + if ((s->icr[i] & 0x1f) > level) { + level = s->icr[i] & 0x1f; + vector = i; + } + } + } + + if (level < 4) + vector = 0; + + return vector; +} + +static void m5206_mbar_update(m5206_mbar_state *s) +{ + int irq; + int vector; + int level; + + irq = m5206_find_pending_irq(s); + if (irq) { + int tmp; + tmp = s->icr[irq]; + level = (tmp >> 2) & 7; + if (tmp & 0x80) { + /* Autovector. */ + vector = 24 + level; + } else { + switch (irq) { + case 8: /* SWT */ + vector = s->swivr; + break; + case 12: /* UART1 */ + vector = s->uivr[0]; + break; + case 13: /* UART2 */ + vector = s->uivr[1]; + break; + default: + /* Unknown vector. */ + fprintf(stderr, "Unhandled vector for IRQ %d\n", irq); + vector = 0xf; + break; + } + } + } else { + level = 0; + vector = 0; + } + m68k_set_irq_level(s->cpu, level, vector); +} + +static void m5206_mbar_set_irq(void *opaque, int irq, int level) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + if (level) { + s->ipr |= 1 << irq; + } else { + s->ipr &= ~(1 << irq); + } + m5206_mbar_update(s); +} + +/* System Integration Module. */ + +static void m5206_mbar_reset(m5206_mbar_state *s) +{ + s->scr = 0xc0; + s->icr[1] = 0x04; + s->icr[2] = 0x08; + s->icr[3] = 0x0c; + s->icr[4] = 0x10; + s->icr[5] = 0x14; + s->icr[6] = 0x18; + s->icr[7] = 0x1c; + s->icr[8] = 0x1c; + s->icr[9] = 0x80; + s->icr[10] = 0x80; + s->icr[11] = 0x80; + s->icr[12] = 0x00; + s->icr[13] = 0x00; + s->imr = 0x3ffe; + s->rsr = 0x80; + s->swivr = 0x0f; + s->par = 0; +} + +static uint64_t m5206_mbar_read(m5206_mbar_state *s, + uint64_t offset, unsigned size) +{ + if (offset >= 0x100 && offset < 0x120) { + return m5206_timer_read(s->timer[0], offset - 0x100); + } else if (offset >= 0x120 && offset < 0x140) { + return m5206_timer_read(s->timer[1], offset - 0x120); + } else if (offset >= 0x140 && offset < 0x160) { + return mcf_uart_read(s->uart[0], offset - 0x140, size); + } else if (offset >= 0x180 && offset < 0x1a0) { + return mcf_uart_read(s->uart[1], offset - 0x180, size); + } + switch (offset) { + case 0x03: return s->scr; + case 0x14 ... 0x20: return s->icr[offset - 0x13]; + case 0x36: return s->imr; + case 0x3a: return s->ipr; + case 0x40: return s->rsr; + case 0x41: return 0; + case 0x42: return s->swivr; + case 0x50: + /* DRAM mask register. */ + /* FIXME: currently hardcoded to 128Mb. */ + { + uint32_t mask = ~0; + while (mask > ram_size) + mask >>= 1; + return mask & 0x0ffe0000; + } + case 0x5c: return 1; /* DRAM bank 1 empty. */ + case 0xcb: return s->par; + case 0x170: return s->uivr[0]; + case 0x1b0: return s->uivr[1]; + } + hw_error("Bad MBAR read offset 0x%x", (int)offset); + return 0; +} + +static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, + uint64_t value, unsigned size) +{ + if (offset >= 0x100 && offset < 0x120) { + m5206_timer_write(s->timer[0], offset - 0x100, value); + return; + } else if (offset >= 0x120 && offset < 0x140) { + m5206_timer_write(s->timer[1], offset - 0x120, value); + return; + } else if (offset >= 0x140 && offset < 0x160) { + mcf_uart_write(s->uart[0], offset - 0x140, value, size); + return; + } else if (offset >= 0x180 && offset < 0x1a0) { + mcf_uart_write(s->uart[1], offset - 0x180, value, size); + return; + } + switch (offset) { + case 0x03: + s->scr = value; + break; + case 0x14 ... 0x20: + s->icr[offset - 0x13] = value; + m5206_mbar_update(s); + break; + case 0x36: + s->imr = value; + m5206_mbar_update(s); + break; + case 0x40: + s->rsr &= ~value; + break; + case 0x41: + /* TODO: implement watchdog. */ + break; + case 0x42: + s->swivr = value; + break; + case 0xcb: + s->par = value; + break; + case 0x170: + s->uivr[0] = value; + break; + case 0x178: case 0x17c: case 0x1c8: case 0x1bc: + /* Not implemented: UART Output port bits. */ + break; + case 0x1b0: + s->uivr[1] = value; + break; + default: + hw_error("Bad MBAR write offset 0x%x", (int)offset); + break; + } +} + +/* Internal peripherals use a variety of register widths. + This lookup table allows a single routine to handle all of them. */ +static const uint8_t m5206_mbar_width[] = +{ + /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, + /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, + /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0, + /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset); +static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset); + +static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + if (m5206_mbar_width[offset >> 2] > 1) { + uint16_t val; + val = m5206_mbar_readw(opaque, offset & ~1); + if ((offset & 1) == 0) { + val >>= 8; + } + return val & 0xff; + } + return m5206_mbar_read(s, offset, 1); +} + +static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 2) { + uint32_t val; + val = m5206_mbar_readl(opaque, offset & ~3); + if ((offset & 3) == 0) + val >>= 16; + return val & 0xffff; + } else if (width < 2) { + uint16_t val; + val = m5206_mbar_readb(opaque, offset) << 8; + val |= m5206_mbar_readb(opaque, offset + 1); + return val; + } + return m5206_mbar_read(s, offset, 2); +} + +static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width < 4) { + uint32_t val; + val = m5206_mbar_readw(opaque, offset) << 16; + val |= m5206_mbar_readw(opaque, offset + 2); + return val; + } + return m5206_mbar_read(s, offset, 4); +} + +static void m5206_mbar_writew(void *opaque, hwaddr offset, + uint32_t value); +static void m5206_mbar_writel(void *opaque, hwaddr offset, + uint32_t value); + +static void m5206_mbar_writeb(void *opaque, hwaddr offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 1) { + uint32_t tmp; + tmp = m5206_mbar_readw(opaque, offset & ~1); + if (offset & 1) { + tmp = (tmp & 0xff00) | value; + } else { + tmp = (tmp & 0x00ff) | (value << 8); + } + m5206_mbar_writew(opaque, offset & ~1, tmp); + return; + } + m5206_mbar_write(s, offset, value, 1); +} + +static void m5206_mbar_writew(void *opaque, hwaddr offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 2) { + uint32_t tmp; + tmp = m5206_mbar_readl(opaque, offset & ~3); + if (offset & 3) { + tmp = (tmp & 0xffff0000) | value; + } else { + tmp = (tmp & 0x0000ffff) | (value << 16); + } + m5206_mbar_writel(opaque, offset & ~3, tmp); + return; + } else if (width < 2) { + m5206_mbar_writeb(opaque, offset, value >> 8); + m5206_mbar_writeb(opaque, offset + 1, value & 0xff); + return; + } + m5206_mbar_write(s, offset, value, 2); +} + +static void m5206_mbar_writel(void *opaque, hwaddr offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width < 4) { + m5206_mbar_writew(opaque, offset, value >> 16); + m5206_mbar_writew(opaque, offset + 2, value & 0xffff); + return; + } + m5206_mbar_write(s, offset, value, 4); +} + +static const MemoryRegionOps m5206_mbar_ops = { + .old_mmio = { + .read = { + m5206_mbar_readb, + m5206_mbar_readw, + m5206_mbar_readl, + }, + .write = { + m5206_mbar_writeb, + m5206_mbar_writew, + m5206_mbar_writel, + }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, M68kCPU *cpu) +{ + m5206_mbar_state *s; + qemu_irq *pic; + + s = (m5206_mbar_state *)g_malloc0(sizeof(m5206_mbar_state)); + + memory_region_init_io(&s->iomem, &m5206_mbar_ops, s, + "mbar", 0x00001000); + memory_region_add_subregion(sysmem, base, &s->iomem); + + pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); + s->timer[0] = m5206_timer_init(pic[9]); + s->timer[1] = m5206_timer_init(pic[10]); + s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]); + s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]); + s->cpu = cpu; + + m5206_mbar_reset(s); + return pic; +} diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c new file mode 100644 index 0000000000..fff27b34aa --- /dev/null +++ b/hw/m68k/mcf_intc.c @@ -0,0 +1,154 @@ +/* + * ColdFire Interrupt Controller emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licensed under the GPL + */ +#include "hw/hw.h" +#include "hw/mcf.h" +#include "exec/address-spaces.h" + +typedef struct { + MemoryRegion iomem; + uint64_t ipr; + uint64_t imr; + uint64_t ifr; + uint64_t enabled; + uint8_t icr[64]; + M68kCPU *cpu; + int active_vector; +} mcf_intc_state; + +static void mcf_intc_update(mcf_intc_state *s) +{ + uint64_t active; + int i; + int best; + int best_level; + + active = (s->ipr | s->ifr) & s->enabled & ~s->imr; + best_level = 0; + best = 64; + if (active) { + for (i = 0; i < 64; i++) { + if ((active & 1) != 0 && s->icr[i] >= best_level) { + best_level = s->icr[i]; + best = i; + } + active >>= 1; + } + } + s->active_vector = ((best == 64) ? 24 : (best + 64)); + m68k_set_irq_level(s->cpu, best_level, s->active_vector); +} + +static uint64_t mcf_intc_read(void *opaque, hwaddr addr, + unsigned size) +{ + int offset; + mcf_intc_state *s = (mcf_intc_state *)opaque; + offset = addr & 0xff; + if (offset >= 0x40 && offset < 0x80) { + return s->icr[offset - 0x40]; + } + switch (offset) { + case 0x00: + return (uint32_t)(s->ipr >> 32); + case 0x04: + return (uint32_t)s->ipr; + case 0x08: + return (uint32_t)(s->imr >> 32); + case 0x0c: + return (uint32_t)s->imr; + case 0x10: + return (uint32_t)(s->ifr >> 32); + case 0x14: + return (uint32_t)s->ifr; + case 0xe0: /* SWIACK. */ + return s->active_vector; + case 0xe1: case 0xe2: case 0xe3: case 0xe4: + case 0xe5: case 0xe6: case 0xe7: + /* LnIACK */ + hw_error("mcf_intc_read: LnIACK not implemented\n"); + default: + return 0; + } +} + +static void mcf_intc_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + int offset; + mcf_intc_state *s = (mcf_intc_state *)opaque; + offset = addr & 0xff; + if (offset >= 0x40 && offset < 0x80) { + int n = offset - 0x40; + s->icr[n] = val; + if (val == 0) + s->enabled &= ~(1ull << n); + else + s->enabled |= (1ull << n); + mcf_intc_update(s); + return; + } + switch (offset) { + case 0x00: case 0x04: + /* Ignore IPR writes. */ + return; + case 0x08: + s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32); + break; + case 0x0c: + s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val; + break; + default: + hw_error("mcf_intc_write: Bad write offset %d\n", offset); + break; + } + mcf_intc_update(s); +} + +static void mcf_intc_set_irq(void *opaque, int irq, int level) +{ + mcf_intc_state *s = (mcf_intc_state *)opaque; + if (irq >= 64) + return; + if (level) + s->ipr |= 1ull << irq; + else + s->ipr &= ~(1ull << irq); + mcf_intc_update(s); +} + +static void mcf_intc_reset(mcf_intc_state *s) +{ + s->imr = ~0ull; + s->ipr = 0; + s->ifr = 0; + s->enabled = 0; + memset(s->icr, 0, 64); + s->active_vector = 24; +} + +static const MemoryRegionOps mcf_intc_ops = { + .read = mcf_intc_read, + .write = mcf_intc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +qemu_irq *mcf_intc_init(MemoryRegion *sysmem, + hwaddr base, + M68kCPU *cpu) +{ + mcf_intc_state *s; + + s = g_malloc0(sizeof(mcf_intc_state)); + s->cpu = cpu; + mcf_intc_reset(s); + + memory_region_init_io(&s->iomem, &mcf_intc_ops, s, "mcf", 0x100); + memory_region_add_subregion(sysmem, base, &s->iomem); + + return qemu_allocate_irqs(mcf_intc_set_irq, s, 64); +} diff --git a/hw/mcf5206.c b/hw/mcf5206.c deleted file mode 100644 index 58cd8d46c9..0000000000 --- a/hw/mcf5206.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * Motorola ColdFire MCF5206 SoC embedded peripheral emulation. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ -#include "hw/hw.h" -#include "hw/mcf.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "sysemu/sysemu.h" -#include "exec/address-spaces.h" - -/* General purpose timer module. */ -typedef struct { - uint16_t tmr; - uint16_t trr; - uint16_t tcr; - uint16_t ter; - ptimer_state *timer; - qemu_irq irq; - int irq_state; -} m5206_timer_state; - -#define TMR_RST 0x01 -#define TMR_CLK 0x06 -#define TMR_FRR 0x08 -#define TMR_ORI 0x10 -#define TMR_OM 0x20 -#define TMR_CE 0xc0 - -#define TER_CAP 0x01 -#define TER_REF 0x02 - -static void m5206_timer_update(m5206_timer_state *s) -{ - if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF)) - qemu_irq_raise(s->irq); - else - qemu_irq_lower(s->irq); -} - -static void m5206_timer_reset(m5206_timer_state *s) -{ - s->tmr = 0; - s->trr = 0; -} - -static void m5206_timer_recalibrate(m5206_timer_state *s) -{ - int prescale; - int mode; - - ptimer_stop(s->timer); - - if ((s->tmr & TMR_RST) == 0) - return; - - prescale = (s->tmr >> 8) + 1; - mode = (s->tmr >> 1) & 3; - if (mode == 2) - prescale *= 16; - - if (mode == 3 || mode == 0) - hw_error("m5206_timer: mode %d not implemented\n", mode); - if ((s->tmr & TMR_FRR) == 0) - hw_error("m5206_timer: free running mode not implemented\n"); - - /* Assume 66MHz system clock. */ - ptimer_set_freq(s->timer, 66000000 / prescale); - - ptimer_set_limit(s->timer, s->trr, 0); - - ptimer_run(s->timer, 0); -} - -static void m5206_timer_trigger(void *opaque) -{ - m5206_timer_state *s = (m5206_timer_state *)opaque; - s->ter |= TER_REF; - m5206_timer_update(s); -} - -static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr) -{ - switch (addr) { - case 0: - return s->tmr; - case 4: - return s->trr; - case 8: - return s->tcr; - case 0xc: - return s->trr - ptimer_get_count(s->timer); - case 0x11: - return s->ter; - default: - return 0; - } -} - -static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0: - if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) { - m5206_timer_reset(s); - } - s->tmr = val; - m5206_timer_recalibrate(s); - break; - case 4: - s->trr = val; - m5206_timer_recalibrate(s); - break; - case 8: - s->tcr = val; - break; - case 0xc: - ptimer_set_count(s->timer, val); - break; - case 0x11: - s->ter &= ~val; - break; - default: - break; - } - m5206_timer_update(s); -} - -static m5206_timer_state *m5206_timer_init(qemu_irq irq) -{ - m5206_timer_state *s; - QEMUBH *bh; - - s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state)); - bh = qemu_bh_new(m5206_timer_trigger, s); - s->timer = ptimer_init(bh); - s->irq = irq; - m5206_timer_reset(s); - return s; -} - -/* System Integration Module. */ - -typedef struct { - M68kCPU *cpu; - MemoryRegion iomem; - m5206_timer_state *timer[2]; - void *uart[2]; - uint8_t scr; - uint8_t icr[14]; - uint16_t imr; /* 1 == interrupt is masked. */ - uint16_t ipr; - uint8_t rsr; - uint8_t swivr; - uint8_t par; - /* Include the UART vector registers here. */ - uint8_t uivr[2]; -} m5206_mbar_state; - -/* Interrupt controller. */ - -static int m5206_find_pending_irq(m5206_mbar_state *s) -{ - int level; - int vector; - uint16_t active; - int i; - - level = 0; - vector = 0; - active = s->ipr & ~s->imr; - if (!active) - return 0; - - for (i = 1; i < 14; i++) { - if (active & (1 << i)) { - if ((s->icr[i] & 0x1f) > level) { - level = s->icr[i] & 0x1f; - vector = i; - } - } - } - - if (level < 4) - vector = 0; - - return vector; -} - -static void m5206_mbar_update(m5206_mbar_state *s) -{ - int irq; - int vector; - int level; - - irq = m5206_find_pending_irq(s); - if (irq) { - int tmp; - tmp = s->icr[irq]; - level = (tmp >> 2) & 7; - if (tmp & 0x80) { - /* Autovector. */ - vector = 24 + level; - } else { - switch (irq) { - case 8: /* SWT */ - vector = s->swivr; - break; - case 12: /* UART1 */ - vector = s->uivr[0]; - break; - case 13: /* UART2 */ - vector = s->uivr[1]; - break; - default: - /* Unknown vector. */ - fprintf(stderr, "Unhandled vector for IRQ %d\n", irq); - vector = 0xf; - break; - } - } - } else { - level = 0; - vector = 0; - } - m68k_set_irq_level(s->cpu, level, vector); -} - -static void m5206_mbar_set_irq(void *opaque, int irq, int level) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - if (level) { - s->ipr |= 1 << irq; - } else { - s->ipr &= ~(1 << irq); - } - m5206_mbar_update(s); -} - -/* System Integration Module. */ - -static void m5206_mbar_reset(m5206_mbar_state *s) -{ - s->scr = 0xc0; - s->icr[1] = 0x04; - s->icr[2] = 0x08; - s->icr[3] = 0x0c; - s->icr[4] = 0x10; - s->icr[5] = 0x14; - s->icr[6] = 0x18; - s->icr[7] = 0x1c; - s->icr[8] = 0x1c; - s->icr[9] = 0x80; - s->icr[10] = 0x80; - s->icr[11] = 0x80; - s->icr[12] = 0x00; - s->icr[13] = 0x00; - s->imr = 0x3ffe; - s->rsr = 0x80; - s->swivr = 0x0f; - s->par = 0; -} - -static uint64_t m5206_mbar_read(m5206_mbar_state *s, - uint64_t offset, unsigned size) -{ - if (offset >= 0x100 && offset < 0x120) { - return m5206_timer_read(s->timer[0], offset - 0x100); - } else if (offset >= 0x120 && offset < 0x140) { - return m5206_timer_read(s->timer[1], offset - 0x120); - } else if (offset >= 0x140 && offset < 0x160) { - return mcf_uart_read(s->uart[0], offset - 0x140, size); - } else if (offset >= 0x180 && offset < 0x1a0) { - return mcf_uart_read(s->uart[1], offset - 0x180, size); - } - switch (offset) { - case 0x03: return s->scr; - case 0x14 ... 0x20: return s->icr[offset - 0x13]; - case 0x36: return s->imr; - case 0x3a: return s->ipr; - case 0x40: return s->rsr; - case 0x41: return 0; - case 0x42: return s->swivr; - case 0x50: - /* DRAM mask register. */ - /* FIXME: currently hardcoded to 128Mb. */ - { - uint32_t mask = ~0; - while (mask > ram_size) - mask >>= 1; - return mask & 0x0ffe0000; - } - case 0x5c: return 1; /* DRAM bank 1 empty. */ - case 0xcb: return s->par; - case 0x170: return s->uivr[0]; - case 0x1b0: return s->uivr[1]; - } - hw_error("Bad MBAR read offset 0x%x", (int)offset); - return 0; -} - -static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, - uint64_t value, unsigned size) -{ - if (offset >= 0x100 && offset < 0x120) { - m5206_timer_write(s->timer[0], offset - 0x100, value); - return; - } else if (offset >= 0x120 && offset < 0x140) { - m5206_timer_write(s->timer[1], offset - 0x120, value); - return; - } else if (offset >= 0x140 && offset < 0x160) { - mcf_uart_write(s->uart[0], offset - 0x140, value, size); - return; - } else if (offset >= 0x180 && offset < 0x1a0) { - mcf_uart_write(s->uart[1], offset - 0x180, value, size); - return; - } - switch (offset) { - case 0x03: - s->scr = value; - break; - case 0x14 ... 0x20: - s->icr[offset - 0x13] = value; - m5206_mbar_update(s); - break; - case 0x36: - s->imr = value; - m5206_mbar_update(s); - break; - case 0x40: - s->rsr &= ~value; - break; - case 0x41: - /* TODO: implement watchdog. */ - break; - case 0x42: - s->swivr = value; - break; - case 0xcb: - s->par = value; - break; - case 0x170: - s->uivr[0] = value; - break; - case 0x178: case 0x17c: case 0x1c8: case 0x1bc: - /* Not implemented: UART Output port bits. */ - break; - case 0x1b0: - s->uivr[1] = value; - break; - default: - hw_error("Bad MBAR write offset 0x%x", (int)offset); - break; - } -} - -/* Internal peripherals use a variety of register widths. - This lookup table allows a single routine to handle all of them. */ -static const uint8_t m5206_mbar_width[] = -{ - /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, - /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, - /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0, - /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -}; - -static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset); -static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset); - -static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); - } - if (m5206_mbar_width[offset >> 2] > 1) { - uint16_t val; - val = m5206_mbar_readw(opaque, offset & ~1); - if ((offset & 1) == 0) { - val >>= 8; - } - return val & 0xff; - } - return m5206_mbar_read(s, offset, 1); -} - -static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width > 2) { - uint32_t val; - val = m5206_mbar_readl(opaque, offset & ~3); - if ((offset & 3) == 0) - val >>= 16; - return val & 0xffff; - } else if (width < 2) { - uint16_t val; - val = m5206_mbar_readb(opaque, offset) << 8; - val |= m5206_mbar_readb(opaque, offset + 1); - return val; - } - return m5206_mbar_read(s, offset, 2); -} - -static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR read offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width < 4) { - uint32_t val; - val = m5206_mbar_readw(opaque, offset) << 16; - val |= m5206_mbar_readw(opaque, offset + 2); - return val; - } - return m5206_mbar_read(s, offset, 4); -} - -static void m5206_mbar_writew(void *opaque, hwaddr offset, - uint32_t value); -static void m5206_mbar_writel(void *opaque, hwaddr offset, - uint32_t value); - -static void m5206_mbar_writeb(void *opaque, hwaddr offset, - uint32_t value) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width > 1) { - uint32_t tmp; - tmp = m5206_mbar_readw(opaque, offset & ~1); - if (offset & 1) { - tmp = (tmp & 0xff00) | value; - } else { - tmp = (tmp & 0x00ff) | (value << 8); - } - m5206_mbar_writew(opaque, offset & ~1, tmp); - return; - } - m5206_mbar_write(s, offset, value, 1); -} - -static void m5206_mbar_writew(void *opaque, hwaddr offset, - uint32_t value) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width > 2) { - uint32_t tmp; - tmp = m5206_mbar_readl(opaque, offset & ~3); - if (offset & 3) { - tmp = (tmp & 0xffff0000) | value; - } else { - tmp = (tmp & 0x0000ffff) | (value << 16); - } - m5206_mbar_writel(opaque, offset & ~3, tmp); - return; - } else if (width < 2) { - m5206_mbar_writeb(opaque, offset, value >> 8); - m5206_mbar_writeb(opaque, offset + 1, value & 0xff); - return; - } - m5206_mbar_write(s, offset, value, 2); -} - -static void m5206_mbar_writel(void *opaque, hwaddr offset, - uint32_t value) -{ - m5206_mbar_state *s = (m5206_mbar_state *)opaque; - int width; - offset &= 0x3ff; - if (offset >= 0x200) { - hw_error("Bad MBAR write offset 0x%x", (int)offset); - } - width = m5206_mbar_width[offset >> 2]; - if (width < 4) { - m5206_mbar_writew(opaque, offset, value >> 16); - m5206_mbar_writew(opaque, offset + 2, value & 0xffff); - return; - } - m5206_mbar_write(s, offset, value, 4); -} - -static const MemoryRegionOps m5206_mbar_ops = { - .old_mmio = { - .read = { - m5206_mbar_readb, - m5206_mbar_readw, - m5206_mbar_readl, - }, - .write = { - m5206_mbar_writeb, - m5206_mbar_writew, - m5206_mbar_writel, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, M68kCPU *cpu) -{ - m5206_mbar_state *s; - qemu_irq *pic; - - s = (m5206_mbar_state *)g_malloc0(sizeof(m5206_mbar_state)); - - memory_region_init_io(&s->iomem, &m5206_mbar_ops, s, - "mbar", 0x00001000); - memory_region_add_subregion(sysmem, base, &s->iomem); - - pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); - s->timer[0] = m5206_timer_init(pic[9]); - s->timer[1] = m5206_timer_init(pic[10]); - s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]); - s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]); - s->cpu = cpu; - - m5206_mbar_reset(s); - return pic; -} diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c deleted file mode 100644 index fff27b34aa..0000000000 --- a/hw/mcf_intc.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * ColdFire Interrupt Controller emulation. - * - * Copyright (c) 2007 CodeSourcery. - * - * This code is licensed under the GPL - */ -#include "hw/hw.h" -#include "hw/mcf.h" -#include "exec/address-spaces.h" - -typedef struct { - MemoryRegion iomem; - uint64_t ipr; - uint64_t imr; - uint64_t ifr; - uint64_t enabled; - uint8_t icr[64]; - M68kCPU *cpu; - int active_vector; -} mcf_intc_state; - -static void mcf_intc_update(mcf_intc_state *s) -{ - uint64_t active; - int i; - int best; - int best_level; - - active = (s->ipr | s->ifr) & s->enabled & ~s->imr; - best_level = 0; - best = 64; - if (active) { - for (i = 0; i < 64; i++) { - if ((active & 1) != 0 && s->icr[i] >= best_level) { - best_level = s->icr[i]; - best = i; - } - active >>= 1; - } - } - s->active_vector = ((best == 64) ? 24 : (best + 64)); - m68k_set_irq_level(s->cpu, best_level, s->active_vector); -} - -static uint64_t mcf_intc_read(void *opaque, hwaddr addr, - unsigned size) -{ - int offset; - mcf_intc_state *s = (mcf_intc_state *)opaque; - offset = addr & 0xff; - if (offset >= 0x40 && offset < 0x80) { - return s->icr[offset - 0x40]; - } - switch (offset) { - case 0x00: - return (uint32_t)(s->ipr >> 32); - case 0x04: - return (uint32_t)s->ipr; - case 0x08: - return (uint32_t)(s->imr >> 32); - case 0x0c: - return (uint32_t)s->imr; - case 0x10: - return (uint32_t)(s->ifr >> 32); - case 0x14: - return (uint32_t)s->ifr; - case 0xe0: /* SWIACK. */ - return s->active_vector; - case 0xe1: case 0xe2: case 0xe3: case 0xe4: - case 0xe5: case 0xe6: case 0xe7: - /* LnIACK */ - hw_error("mcf_intc_read: LnIACK not implemented\n"); - default: - return 0; - } -} - -static void mcf_intc_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - int offset; - mcf_intc_state *s = (mcf_intc_state *)opaque; - offset = addr & 0xff; - if (offset >= 0x40 && offset < 0x80) { - int n = offset - 0x40; - s->icr[n] = val; - if (val == 0) - s->enabled &= ~(1ull << n); - else - s->enabled |= (1ull << n); - mcf_intc_update(s); - return; - } - switch (offset) { - case 0x00: case 0x04: - /* Ignore IPR writes. */ - return; - case 0x08: - s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32); - break; - case 0x0c: - s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val; - break; - default: - hw_error("mcf_intc_write: Bad write offset %d\n", offset); - break; - } - mcf_intc_update(s); -} - -static void mcf_intc_set_irq(void *opaque, int irq, int level) -{ - mcf_intc_state *s = (mcf_intc_state *)opaque; - if (irq >= 64) - return; - if (level) - s->ipr |= 1ull << irq; - else - s->ipr &= ~(1ull << irq); - mcf_intc_update(s); -} - -static void mcf_intc_reset(mcf_intc_state *s) -{ - s->imr = ~0ull; - s->ipr = 0; - s->ifr = 0; - s->enabled = 0; - memset(s->icr, 0, 64); - s->active_vector = 24; -} - -static const MemoryRegionOps mcf_intc_ops = { - .read = mcf_intc_read, - .write = mcf_intc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -qemu_irq *mcf_intc_init(MemoryRegion *sysmem, - hwaddr base, - M68kCPU *cpu) -{ - mcf_intc_state *s; - - s = g_malloc0(sizeof(mcf_intc_state)); - s->cpu = cpu; - mcf_intc_reset(s); - - memory_region_init_io(&s->iomem, &mcf_intc_ops, s, "mcf", 0x100); - memory_region_add_subregion(sysmem, base, &s->iomem); - - return qemu_allocate_irqs(mcf_intc_set_irq, s, 64); -} -- cgit v1.2.1