diff options
Diffstat (limited to 'hw/armv7m_nvic.c')
-rw-r--r-- | hw/armv7m_nvic.c | 109 |
1 files changed, 57 insertions, 52 deletions
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 306ac38337..2a948ac346 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -10,7 +10,7 @@ * NVIC. Much of that is also implemented here. */ -#include "hw.h" +#include "sysbus.h" #include "qemu-timer.h" #include "arm-misc.h" @@ -33,13 +33,13 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value); #include "arm_gic.c" typedef struct { + gic_state gic; struct { uint32_t control; uint32_t reload; int64_t tick; QEMUTimer *timer; } systick; - gic_state *gic; } nvic_state; /* qemu timers run at 1GHz. We want something closer to 1MHz. */ @@ -91,7 +91,7 @@ void armv7m_nvic_set_pending(void *opaque, int irq) nvic_state *s = (nvic_state *)opaque; if (irq >= 16) irq += 16; - gic_set_pending_private(s->gic, 0, irq); + gic_set_pending_private(&s->gic, 0, irq); } /* Make pending IRQ active. */ @@ -100,7 +100,7 @@ int armv7m_nvic_acknowledge_irq(void *opaque) nvic_state *s = (nvic_state *)opaque; uint32_t irq; - irq = gic_acknowledge_irq(s->gic, 0); + irq = gic_acknowledge_irq(&s->gic, 0); if (irq == 1023) hw_error("Interrupt but no vector\n"); if (irq >= 32) @@ -113,7 +113,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq) nvic_state *s = (nvic_state *)opaque; if (irq >= 16) irq += 16; - gic_complete_irq(s->gic, 0, irq); + gic_complete_irq(&s->gic, 0, irq); } static uint32_t nvic_readl(void *opaque, uint32_t offset) @@ -153,35 +153,35 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) return cpu_single_env->cp15.c0_cpuid; case 0xd04: /* Interrypt Control State. */ /* VECTACTIVE */ - val = s->gic->running_irq[0]; + val = s->gic.running_irq[0]; if (val == 1023) { val = 0; } else if (val >= 32) { val -= 16; } /* RETTOBASE */ - if (s->gic->running_irq[0] == 1023 - || s->gic->last_active[s->gic->running_irq[0]][0] == 1023) { + if (s->gic.running_irq[0] == 1023 + || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) { val |= (1 << 11); } /* VECTPENDING */ - if (s->gic->current_pending[0] != 1023) - val |= (s->gic->current_pending[0] << 12); + if (s->gic.current_pending[0] != 1023) + val |= (s->gic.current_pending[0] << 12); /* ISRPENDING */ for (irq = 32; irq < GIC_NIRQ; irq++) { - if (s->gic->irq_state[irq].pending) { + if (s->gic.irq_state[irq].pending) { val |= (1 << 22); break; } } /* PENDSTSET */ - if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending) + if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending) val |= (1 << 26); /* PENDSVSET */ - if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending) + if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending) val |= (1 << 28); /* NMIPENDSET */ - if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending) + if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending) val |= (1 << 31); return val; case 0xd08: /* Vector Table Offset. */ @@ -197,27 +197,27 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ irq = offset - 0xd14; val = 0; - val = s->gic->priority1[irq++][0]; - val = s->gic->priority1[irq++][0] << 8; - val = s->gic->priority1[irq++][0] << 16; - val = s->gic->priority1[irq][0] << 24; + val = s->gic.priority1[irq++][0]; + val = s->gic.priority1[irq++][0] << 8; + val = s->gic.priority1[irq++][0] << 16; + val = s->gic.priority1[irq][0] << 24; return val; case 0xd24: /* System Handler Status. */ val = 0; - if (s->gic->irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0); - if (s->gic->irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1); - if (s->gic->irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3); - if (s->gic->irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7); - if (s->gic->irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8); - if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10); - if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11); - if (s->gic->irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12); - if (s->gic->irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13); - if (s->gic->irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14); - if (s->gic->irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15); - if (s->gic->irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16); - if (s->gic->irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17); - if (s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18); + if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0); + if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1); + if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3); + if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7); + if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8); + if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10); + if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11); + if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12); + if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13); + if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14); + if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15); + if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16); + if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17); + if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18); return val; case 0xd28: /* Configurable Fault Status. */ /* TODO: Implement Fault Status. */ @@ -307,14 +307,14 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) if (value & (1 << 28)) { armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV); } else if (value & (1 << 27)) { - s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending = 0; - gic_update(s->gic); + s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0; + gic_update(&s->gic); } if (value & (1 << 26)) { armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); } else if (value & (1 << 25)) { - s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending = 0; - gic_update(s->gic); + s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0; + gic_update(&s->gic); } break; case 0xd08: /* Vector Table Offset. */ @@ -338,19 +338,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) { int irq; irq = offset - 0xd14; - s->gic->priority1[irq++][0] = value & 0xff; - s->gic->priority1[irq++][0] = (value >> 8) & 0xff; - s->gic->priority1[irq++][0] = (value >> 16) & 0xff; - s->gic->priority1[irq][0] = (value >> 24) & 0xff; - gic_update(s->gic); + s->gic.priority1[irq++][0] = value & 0xff; + s->gic.priority1[irq++][0] = (value >> 8) & 0xff; + s->gic.priority1[irq++][0] = (value >> 16) & 0xff; + s->gic.priority1[irq][0] = (value >> 24) & 0xff; + gic_update(&s->gic); } break; case 0xd24: /* System Handler Control. */ /* TODO: Real hardware allows you to set/clear the active bits under some circumstances. We don't implement this. */ - s->gic->irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0; - s->gic->irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0; - s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0; + s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0; + s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0; + s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0; break; case 0xd28: /* Configurable Fault Status. */ case 0xd2c: /* Hard Fault Status. */ @@ -390,19 +390,24 @@ static int nvic_load(QEMUFile *f, void *opaque, int version_id) return 0; } -qemu_irq *armv7m_nvic_init(CPUState *env) +static void armv7m_nvic_init(SysBusDevice *dev) { - nvic_state *s; - qemu_irq *parent; + nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev); + CPUState *env; - parent = arm_pic_init_cpu(env); - s = (nvic_state *)qemu_mallocz(sizeof(nvic_state)); - s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]); - s->gic->nvic = s; + env = qdev_get_prop_ptr(&dev->qdev, "cpu"); + gic_init(&s->gic); + cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype); s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s); if (env->v7m.nvic) hw_error("CPU can only have one NVIC\n"); env->v7m.nvic = s; register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s); - return s->gic->in; } + +static void armv7m_nvic_register_devices(void) +{ + sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init); +} + +device_init(armv7m_nvic_register_devices) |