aboutsummaryrefslogtreecommitdiffstats
path: root/hw/armv7m_nvic.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/armv7m_nvic.c')
-rw-r--r--hw/armv7m_nvic.c125
1 files changed, 63 insertions, 62 deletions
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index c55c958..f789c78 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. */
@@ -50,6 +50,8 @@ typedef struct {
#define SYSTICK_CLKSOURCE (1 << 2)
#define SYSTICK_COUNTFLAG (1 << 16)
+int system_clock_scale;
+
/* Conversion factor from qemu timer to SysTick frequencies. */
static inline int64_t systick_scale(nvic_state *s)
{
@@ -89,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. */
@@ -98,9 +100,9 @@ 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)
- cpu_abort(cpu_single_env, "Interrupt but no vector\n");
+ hw_error("Interrupt but no vector\n");
if (irq >= 32)
irq -= 16;
return irq;
@@ -111,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)
@@ -151,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. */
@@ -195,32 +197,31 @@ 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. */
- cpu_abort(cpu_single_env,
- "Not implemented: Configurable Fault Status.");
+ hw_error("Not implemented: Configurable Fault Status.");
return 0;
case 0xd2c: /* Hard Fault Status. */
case 0xd30: /* Debug Fault Status. */
@@ -258,7 +259,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
/* TODO: Implement debug registers. */
default:
bad_reg:
- cpu_abort(cpu_single_env, "NVIC: Bad read offset 0x%x\n", offset);
+ hw_error("NVIC: Bad read offset 0x%x\n", offset);
}
}
@@ -306,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. */
@@ -322,10 +323,10 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
case 0xd0c: /* Application Interrupt/Reset Control. */
if ((value >> 16) == 0x05fa) {
if (value & 2) {
- cpu_abort(cpu_single_env, "VECTCLRACTIVE not implemented");
+ hw_error("VECTCLRACTIVE not implemented");
}
if (value & 5) {
- cpu_abort(cpu_single_env, "System reset");
+ hw_error("System reset");
}
}
break;
@@ -337,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. */
@@ -360,7 +361,7 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
goto bad_reg;
default:
bad_reg:
- cpu_abort(cpu_single_env, "NVIC: Bad write offset 0x%x\n", offset);
+ hw_error("NVIC: Bad write offset 0x%x\n", offset);
}
}
@@ -389,19 +390,19 @@ 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);
- 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;
+ 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)
- cpu_abort(env, "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)