mirror of
https://github.com/xemu-project/xemu.git
synced 2024-12-18 01:08:51 +00:00
armv7m: Split systick out from NVIC
The SysTick timer isn't really part of the NVIC proper; we just modelled it that way back when we couldn't easily have devices that only occupied a small chunk of a memory region. Split it out into its own device. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1487604965-23220-10-git-send-email-peter.maydell@linaro.org Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
This commit is contained in:
parent
743eb70560
commit
ff68dacbc7
@ -58,65 +58,6 @@ static const uint8_t nvic_id[] = {
|
||||
0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
|
||||
};
|
||||
|
||||
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
|
||||
#define SYSTICK_SCALE 1000ULL
|
||||
|
||||
#define SYSTICK_ENABLE (1 << 0)
|
||||
#define SYSTICK_TICKINT (1 << 1)
|
||||
#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(NVICState *s)
|
||||
{
|
||||
if (s->systick.control & SYSTICK_CLKSOURCE)
|
||||
return system_clock_scale;
|
||||
else
|
||||
return 1000;
|
||||
}
|
||||
|
||||
static void systick_reload(NVICState *s, int reset)
|
||||
{
|
||||
/* The Cortex-M3 Devices Generic User Guide says that "When the
|
||||
* ENABLE bit is set to 1, the counter loads the RELOAD value from the
|
||||
* SYST RVR register and then counts down". So, we need to check the
|
||||
* ENABLE bit before reloading the value.
|
||||
*/
|
||||
if ((s->systick.control & SYSTICK_ENABLE) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reset)
|
||||
s->systick.tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
|
||||
timer_mod(s->systick.timer, s->systick.tick);
|
||||
}
|
||||
|
||||
static void systick_timer_tick(void * opaque)
|
||||
{
|
||||
NVICState *s = (NVICState *)opaque;
|
||||
s->systick.control |= SYSTICK_COUNTFLAG;
|
||||
if (s->systick.control & SYSTICK_TICKINT) {
|
||||
/* Trigger the interrupt. */
|
||||
armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
|
||||
}
|
||||
if (s->systick.reload == 0) {
|
||||
s->systick.control &= ~SYSTICK_ENABLE;
|
||||
} else {
|
||||
systick_reload(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void systick_reset(NVICState *s)
|
||||
{
|
||||
s->systick.control = 0;
|
||||
s->systick.reload = 0;
|
||||
s->systick.tick = 0;
|
||||
timer_del(s->systick.timer);
|
||||
}
|
||||
|
||||
static int nvic_pending_prio(NVICState *s)
|
||||
{
|
||||
/* return the priority of the current pending interrupt,
|
||||
@ -462,30 +403,6 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
|
||||
switch (offset) {
|
||||
case 4: /* Interrupt Control Type. */
|
||||
return ((s->num_irq - NVIC_FIRST_IRQ) / 32) - 1;
|
||||
case 0x10: /* SysTick Control and Status. */
|
||||
val = s->systick.control;
|
||||
s->systick.control &= ~SYSTICK_COUNTFLAG;
|
||||
return val;
|
||||
case 0x14: /* SysTick Reload Value. */
|
||||
return s->systick.reload;
|
||||
case 0x18: /* SysTick Current Value. */
|
||||
{
|
||||
int64_t t;
|
||||
if ((s->systick.control & SYSTICK_ENABLE) == 0)
|
||||
return 0;
|
||||
t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
if (t >= s->systick.tick)
|
||||
return 0;
|
||||
val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
|
||||
/* The interrupt in triggered when the timer reaches zero.
|
||||
However the counter is not reloaded until the next clock
|
||||
tick. This is a hack to return zero during the first tick. */
|
||||
if (val > s->systick.reload)
|
||||
val = 0;
|
||||
return val;
|
||||
}
|
||||
case 0x1c: /* SysTick Calibration Value. */
|
||||
return 10000;
|
||||
case 0xd00: /* CPUID Base. */
|
||||
return cpu->midr;
|
||||
case 0xd04: /* Interrupt Control State. */
|
||||
@ -620,40 +537,8 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
|
||||
static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
|
||||
{
|
||||
ARMCPU *cpu = s->cpu;
|
||||
uint32_t oldval;
|
||||
|
||||
switch (offset) {
|
||||
case 0x10: /* SysTick Control and Status. */
|
||||
oldval = s->systick.control;
|
||||
s->systick.control &= 0xfffffff8;
|
||||
s->systick.control |= value & 7;
|
||||
if ((oldval ^ value) & SYSTICK_ENABLE) {
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
if (value & SYSTICK_ENABLE) {
|
||||
if (s->systick.tick) {
|
||||
s->systick.tick += now;
|
||||
timer_mod(s->systick.timer, s->systick.tick);
|
||||
} else {
|
||||
systick_reload(s, 1);
|
||||
}
|
||||
} else {
|
||||
timer_del(s->systick.timer);
|
||||
s->systick.tick -= now;
|
||||
if (s->systick.tick < 0)
|
||||
s->systick.tick = 0;
|
||||
}
|
||||
} else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
|
||||
/* This is a hack. Force the timer to be reloaded
|
||||
when the reference clock is changed. */
|
||||
systick_reload(s, 1);
|
||||
}
|
||||
break;
|
||||
case 0x14: /* SysTick Reload Value. */
|
||||
s->systick.reload = value;
|
||||
break;
|
||||
case 0x18: /* SysTick Current Value. Writes reload the timer. */
|
||||
systick_reload(s, 1);
|
||||
s->systick.control &= ~SYSTICK_COUNTFLAG;
|
||||
break;
|
||||
case 0xd04: /* Interrupt Control State. */
|
||||
if (value & (1 << 31)) {
|
||||
armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
|
||||
@ -952,16 +837,12 @@ static const VMStateDescription vmstate_VecInfo = {
|
||||
|
||||
static const VMStateDescription vmstate_nvic = {
|
||||
.name = "armv7m_nvic",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.version_id = 4,
|
||||
.minimum_version_id = 4,
|
||||
.post_load = &nvic_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_ARRAY(vectors, NVICState, NVIC_MAX_VECTORS, 1,
|
||||
vmstate_VecInfo, VecInfo),
|
||||
VMSTATE_UINT32(systick.control, NVICState),
|
||||
VMSTATE_UINT32(systick.reload, NVICState),
|
||||
VMSTATE_INT64(systick.tick, NVICState),
|
||||
VMSTATE_TIMER_PTR(systick.timer, NVICState),
|
||||
VMSTATE_UINT32(prigroup, NVICState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@ -999,13 +880,26 @@ static void armv7m_nvic_reset(DeviceState *dev)
|
||||
|
||||
s->exception_prio = NVIC_NOEXC_PRIO;
|
||||
s->vectpending = 0;
|
||||
}
|
||||
|
||||
systick_reset(s);
|
||||
static void nvic_systick_trigger(void *opaque, int n, int level)
|
||||
{
|
||||
NVICState *s = opaque;
|
||||
|
||||
if (level) {
|
||||
/* SysTick just asked us to pend its exception.
|
||||
* (This is different from an external interrupt line's
|
||||
* behaviour.)
|
||||
*/
|
||||
armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
|
||||
}
|
||||
}
|
||||
|
||||
static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
NVICState *s = NVIC(dev);
|
||||
SysBusDevice *systick_sbd;
|
||||
Error *err = NULL;
|
||||
|
||||
s->cpu = ARM_CPU(qemu_get_cpu(0));
|
||||
assert(s->cpu);
|
||||
@ -1020,10 +914,19 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
|
||||
/* include space for internal exception vectors */
|
||||
s->num_irq += NVIC_FIRST_IRQ;
|
||||
|
||||
object_property_set_bool(OBJECT(&s->systick), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
systick_sbd = SYS_BUS_DEVICE(&s->systick);
|
||||
sysbus_connect_irq(systick_sbd, 0,
|
||||
qdev_get_gpio_in_named(dev, "systick-trigger", 0));
|
||||
|
||||
/* The NVIC and System Control Space (SCS) starts at 0xe000e000
|
||||
* and looks like this:
|
||||
* 0x004 - ICTR
|
||||
* 0x010 - 0x1c - systick
|
||||
* 0x010 - 0xff - systick
|
||||
* 0x100..0x7ec - NVIC
|
||||
* 0x7f0..0xcff - Reserved
|
||||
* 0xd00..0xd3c - SCS registers
|
||||
@ -1041,10 +944,11 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_init_io(&s->sysregmem, OBJECT(s), &nvic_sysreg_ops, s,
|
||||
"nvic_sysregs", 0x1000);
|
||||
memory_region_add_subregion(&s->container, 0, &s->sysregmem);
|
||||
memory_region_add_subregion_overlap(&s->container, 0x10,
|
||||
sysbus_mmio_get_region(systick_sbd, 0),
|
||||
1);
|
||||
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container);
|
||||
|
||||
s->systick.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
|
||||
}
|
||||
|
||||
static void armv7m_nvic_instance_init(Object *obj)
|
||||
@ -1059,8 +963,12 @@ static void armv7m_nvic_instance_init(Object *obj)
|
||||
NVICState *nvic = NVIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
object_initialize(&nvic->systick, sizeof(nvic->systick), TYPE_SYSTICK);
|
||||
qdev_set_parent_bus(DEVICE(&nvic->systick), sysbus_get_default());
|
||||
|
||||
sysbus_init_irq(sbd, &nvic->excpout);
|
||||
qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1);
|
||||
qdev_init_gpio_in_named(dev, nvic_systick_trigger, "systick-trigger", 1);
|
||||
}
|
||||
|
||||
static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
|
||||
|
@ -1,5 +1,6 @@
|
||||
common-obj-$(CONFIG_ARM_TIMER) += arm_timer.o
|
||||
common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
|
||||
common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
|
||||
common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
|
||||
common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
|
||||
common-obj-$(CONFIG_DS1338) += ds1338.o
|
||||
|
240
hw/timer/armv7m_systick.c
Normal file
240
hw/timer/armv7m_systick.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* ARMv7M SysTick timer
|
||||
*
|
||||
* Copyright (c) 2006-2007 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
* Copyright (c) 2017 Linaro Ltd
|
||||
* Written by Peter Maydell
|
||||
*
|
||||
* This code is licensed under the GPL (version 2 or later).
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/timer/armv7m_systick.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
|
||||
#define SYSTICK_SCALE 1000ULL
|
||||
|
||||
#define SYSTICK_ENABLE (1 << 0)
|
||||
#define SYSTICK_TICKINT (1 << 1)
|
||||
#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(SysTickState *s)
|
||||
{
|
||||
if (s->control & SYSTICK_CLKSOURCE) {
|
||||
return system_clock_scale;
|
||||
} else {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
static void systick_reload(SysTickState *s, int reset)
|
||||
{
|
||||
/* The Cortex-M3 Devices Generic User Guide says that "When the
|
||||
* ENABLE bit is set to 1, the counter loads the RELOAD value from the
|
||||
* SYST RVR register and then counts down". So, we need to check the
|
||||
* ENABLE bit before reloading the value.
|
||||
*/
|
||||
trace_systick_reload();
|
||||
|
||||
if ((s->control & SYSTICK_ENABLE) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
}
|
||||
s->tick += (s->reload + 1) * systick_scale(s);
|
||||
timer_mod(s->timer, s->tick);
|
||||
}
|
||||
|
||||
static void systick_timer_tick(void *opaque)
|
||||
{
|
||||
SysTickState *s = (SysTickState *)opaque;
|
||||
|
||||
trace_systick_timer_tick();
|
||||
|
||||
s->control |= SYSTICK_COUNTFLAG;
|
||||
if (s->control & SYSTICK_TICKINT) {
|
||||
/* Tell the NVIC to pend the SysTick exception */
|
||||
qemu_irq_pulse(s->irq);
|
||||
}
|
||||
if (s->reload == 0) {
|
||||
s->control &= ~SYSTICK_ENABLE;
|
||||
} else {
|
||||
systick_reload(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t systick_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
SysTickState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
switch (addr) {
|
||||
case 0x0: /* SysTick Control and Status. */
|
||||
val = s->control;
|
||||
s->control &= ~SYSTICK_COUNTFLAG;
|
||||
break;
|
||||
case 0x4: /* SysTick Reload Value. */
|
||||
val = s->reload;
|
||||
break;
|
||||
case 0x8: /* SysTick Current Value. */
|
||||
{
|
||||
int64_t t;
|
||||
|
||||
if ((s->control & SYSTICK_ENABLE) == 0) {
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
if (t >= s->tick) {
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
val = ((s->tick - (t + 1)) / systick_scale(s)) + 1;
|
||||
/* The interrupt in triggered when the timer reaches zero.
|
||||
However the counter is not reloaded until the next clock
|
||||
tick. This is a hack to return zero during the first tick. */
|
||||
if (val > s->reload) {
|
||||
val = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xc: /* SysTick Calibration Value. */
|
||||
val = 10000;
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_systick_read(addr, val, size);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void systick_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
SysTickState *s = opaque;
|
||||
|
||||
trace_systick_write(addr, value, size);
|
||||
|
||||
switch (addr) {
|
||||
case 0x0: /* SysTick Control and Status. */
|
||||
{
|
||||
uint32_t oldval = s->control;
|
||||
|
||||
s->control &= 0xfffffff8;
|
||||
s->control |= value & 7;
|
||||
if ((oldval ^ value) & SYSTICK_ENABLE) {
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
if (value & SYSTICK_ENABLE) {
|
||||
if (s->tick) {
|
||||
s->tick += now;
|
||||
timer_mod(s->timer, s->tick);
|
||||
} else {
|
||||
systick_reload(s, 1);
|
||||
}
|
||||
} else {
|
||||
timer_del(s->timer);
|
||||
s->tick -= now;
|
||||
if (s->tick < 0) {
|
||||
s->tick = 0;
|
||||
}
|
||||
}
|
||||
} else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
|
||||
/* This is a hack. Force the timer to be reloaded
|
||||
when the reference clock is changed. */
|
||||
systick_reload(s, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x4: /* SysTick Reload Value. */
|
||||
s->reload = value;
|
||||
break;
|
||||
case 0x8: /* SysTick Current Value. Writes reload the timer. */
|
||||
systick_reload(s, 1);
|
||||
s->control &= ~SYSTICK_COUNTFLAG;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps systick_ops = {
|
||||
.read = systick_read,
|
||||
.write = systick_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static void systick_reset(DeviceState *dev)
|
||||
{
|
||||
SysTickState *s = SYSTICK(dev);
|
||||
|
||||
s->control = 0;
|
||||
s->reload = 0;
|
||||
s->tick = 0;
|
||||
timer_del(s->timer);
|
||||
}
|
||||
|
||||
static void systick_instance_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
SysTickState *s = SYSTICK(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_systick = {
|
||||
.name = "armv7m_systick",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(control, SysTickState),
|
||||
VMSTATE_UINT32(reload, SysTickState),
|
||||
VMSTATE_INT64(tick, SysTickState),
|
||||
VMSTATE_TIMER_PTR(timer, SysTickState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void systick_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_systick;
|
||||
dc->reset = systick_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo armv7m_systick_info = {
|
||||
.name = TYPE_SYSTICK,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_init = systick_instance_init,
|
||||
.instance_size = sizeof(SysTickState),
|
||||
.class_init = systick_class_init,
|
||||
};
|
||||
|
||||
static void armv7m_systick_register_types(void)
|
||||
{
|
||||
type_register_static(&armv7m_systick_info);
|
||||
}
|
||||
|
||||
type_init(armv7m_systick_register_types)
|
@ -49,3 +49,9 @@ aspeed_timer_ctrl_pulse_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d"
|
||||
aspeed_timer_set_ctrl2(uint32_t value) "Value: 0x%" PRIx32
|
||||
aspeed_timer_set_value(int timer, int reg, uint32_t value) "Timer %d register %d: 0x%" PRIx32
|
||||
aspeed_timer_read(uint64_t offset, unsigned size, uint64_t value) "From 0x%" PRIx64 ": of size %u: 0x%" PRIx64
|
||||
|
||||
# hw/timer/armv7m_systick.c
|
||||
systick_reload(void) "systick reload"
|
||||
systick_timer_tick(void) "systick reload"
|
||||
systick_read(uint64_t addr, uint32_t value, unsigned size) "systick read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
|
||||
systick_write(uint64_t addr, uint32_t value, unsigned size) "systick write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "target/arm/cpu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/timer/armv7m_systick.h"
|
||||
|
||||
#define TYPE_NVIC "armv7m_nvic"
|
||||
|
||||
@ -48,19 +49,14 @@ typedef struct NVICState {
|
||||
unsigned int vectpending; /* highest prio pending enabled exception */
|
||||
int exception_prio; /* group prio of the highest prio active exception */
|
||||
|
||||
struct {
|
||||
uint32_t control;
|
||||
uint32_t reload;
|
||||
int64_t tick;
|
||||
QEMUTimer *timer;
|
||||
} systick;
|
||||
|
||||
MemoryRegion sysregmem;
|
||||
MemoryRegion container;
|
||||
|
||||
uint32_t num_irq;
|
||||
qemu_irq excpout;
|
||||
qemu_irq sysresetreq;
|
||||
|
||||
SysTickState systick;
|
||||
} NVICState;
|
||||
|
||||
#endif
|
||||
|
34
include/hw/timer/armv7m_systick.h
Normal file
34
include/hw/timer/armv7m_systick.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* ARMv7M SysTick timer
|
||||
*
|
||||
* Copyright (c) 2006-2007 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
* Copyright (c) 2017 Linaro Ltd
|
||||
* Written by Peter Maydell
|
||||
*
|
||||
* This code is licensed under the GPL (version 2 or later).
|
||||
*/
|
||||
|
||||
#ifndef HW_TIMER_ARMV7M_SYSTICK_H
|
||||
#define HW_TIMER_ARMV7M_SYSTICK_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_SYSTICK "armv7m_systick"
|
||||
|
||||
#define SYSTICK(obj) OBJECT_CHECK(SysTickState, (obj), TYPE_SYSTICK)
|
||||
|
||||
typedef struct SysTickState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
uint32_t control;
|
||||
uint32_t reload;
|
||||
int64_t tick;
|
||||
QEMUTimer *timer;
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
} SysTickState;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user