Expand the NVIC to fully support -M priorities and masking. Doesn't use GIC code.
Move some state to ARMCPU to allow calculation of exception masking. Add storage for PRIGROUP to configure group/sub-group split. Track group and sub-group in separate fields for quick comparison. Mix in vector # with sub-group as per tie breaking rules. NVIC now derives directly from SysBusDevice, and struct NVICClass is eliminated. Also add DPRINTF() macro. Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com> --- hw/intc/armv7m_nvic.c | 74 ++++++++++++++++++++++++++++++++++----------------- target-arm/cpu.h | 3 +++ 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 6fc167e..487a09a 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -13,43 +13,67 @@ #include "hw/sysbus.h" #include "qemu/timer.h" #include "hw/arm/arm.h" +#include "target-arm/cpu.h" #include "exec/address-spaces.h" -#include "gic_internal.h" -typedef struct { - GICState gic; +/*#define DEBUG_NVIC 0 + */ +#ifdef DEBUG_NVIC +#define DPRINTF(LVL, fmt, ...) \ +do { if ((LVL) <= DEBUG_NVIC) { \ + fprintf(stderr, "armv7m_nvic: " fmt , ## __VA_ARGS__); \ +} } while (0) +#else +#define DPRINTF(LVL, fmt, ...) do {} while (0) +#endif + +/* the number of IRQ lines in addition to the 16 internal + * exception vectors. + */ +#define NVIC_MAX_IRQ 496 + +#define NVIC_MAX_VECTORS 512 + +struct vec_info { + uint16_t prio_sub; /* sub-group priority*512 + exception# */ + int8_t prio_group; /* group priority [-2, 0x7f] */ + uint8_t raw_prio; /* value writen by guest */ + uint8_t enabled; + uint8_t pending; + uint8_t active; + uint8_t level; + /* exceptions <=15 never set level */ +}; +typedef struct vec_info vec_info; + +struct nvic_state { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + ARMCPU *cpu; /* NVIC is so closely tied to the CPU, just keep a ref */ + + vec_info vectors[NVIC_MAX_VECTORS]; + + uint8_t prigroup; + struct { uint32_t control; uint32_t reload; int64_t tick; QEMUTimer *timer; } systick; - MemoryRegion sysregmem; - MemoryRegion gic_iomem_alias; - MemoryRegion container; + + MemoryRegion iomem; /* system control space and NVIC */ + uint32_t num_irq; + qemu_irq excpout; qemu_irq sysresetreq; -} nvic_state; +}; +typedef struct nvic_state nvic_state; #define TYPE_NVIC "armv7m_nvic" -/** - * NVICClass: - * @parent_reset: the parent class' reset handler. - * - * A model of the v7M NVIC and System Controller - */ -typedef struct NVICClass { - /*< private >*/ - ARMGICClass parent_class; - /*< public >*/ - DeviceRealize parent_realize; - void (*parent_reset)(DeviceState *dev); -} NVICClass; - -#define NVIC_CLASS(klass) \ - OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC) -#define NVIC_GET_CLASS(obj) \ - OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC) + #define NVIC(obj) \ OBJECT_CHECK(nvic_state, (obj), TYPE_NVIC) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 815fef8..c193fbb 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -398,6 +398,9 @@ typedef struct CPUARMState { uint32_t control; int current_sp; int exception; + int exception_prio; + unsigned pending; + int pending_prio; } v7m; /* Information associated with an exception about to be taken: -- 2.1.4