armv7m_nvic.c 18.0 KB
Newer Older
P
pbrook 已提交
1 2 3 4 5 6
/*
 * ARM Nested Vectored Interrupt Controller
 *
 * Copyright (c) 2006-2007 CodeSourcery.
 * Written by Paul Brook
 *
M
Matthew Fernandez 已提交
7
 * This code is licensed under the GPL.
P
pbrook 已提交
8 9 10 11 12
 *
 * The ARMv7M System controller is fairly tightly tied in with the
 * NVIC.  Much of that is also implemented here.
 */

13
#include "hw/sysbus.h"
14
#include "qemu/timer.h"
P
Paolo Bonzini 已提交
15
#include "hw/arm.h"
16
#include "exec/address-spaces.h"
17
#include "gic_internal.h"
P
pbrook 已提交
18 19

typedef struct {
20
    GICState gic;
P
pbrook 已提交
21 22 23 24 25 26
    struct {
        uint32_t control;
        uint32_t reload;
        int64_t tick;
        QEMUTimer *timer;
    } systick;
27 28 29
    MemoryRegion sysregmem;
    MemoryRegion gic_iomem_alias;
    MemoryRegion container;
30
    uint32_t num_irq;
P
pbrook 已提交
31 32
} nvic_state;

33 34 35 36 37 38 39 40 41 42 43
#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 >*/
44
    DeviceRealize parent_realize;
45 46 47 48 49 50 51 52 53 54
    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)

55 56 57 58
static const uint8_t nvic_id[] = {
    0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
};

P
pbrook 已提交
59 60 61 62 63 64 65 66
/* 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)

67 68
int system_clock_scale;

P
pbrook 已提交
69
/* Conversion factor from qemu timer to SysTick frequencies.  */
P
pbrook 已提交
70 71 72
static inline int64_t systick_scale(nvic_state *s)
{
    if (s->systick.control & SYSTICK_CLKSOURCE)
P
pbrook 已提交
73
        return system_clock_scale;
P
pbrook 已提交
74 75 76 77 78 79 80
    else
        return 1000;
}

static void systick_reload(nvic_state *s, int reset)
{
    if (reset)
81
        s->systick.tick = qemu_get_clock_ns(vm_clock);
P
pbrook 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
    qemu_mod_timer(s->systick.timer, s->systick.tick);
}

static void systick_timer_tick(void * opaque)
{
    nvic_state *s = (nvic_state *)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);
    }
}

101 102 103 104 105 106 107 108
static void systick_reset(nvic_state *s)
{
    s->systick.control = 0;
    s->systick.reload = 0;
    s->systick.tick = 0;
    qemu_del_timer(s->systick.timer);
}

P
pbrook 已提交
109 110 111 112 113 114 115
/* The external routines use the hardware vector numbering, ie. the first
   IRQ is #16.  The internal GIC routines use #32 as the first IRQ.  */
void armv7m_nvic_set_pending(void *opaque, int irq)
{
    nvic_state *s = (nvic_state *)opaque;
    if (irq >= 16)
        irq += 16;
P
Paul Brook 已提交
116
    gic_set_pending_private(&s->gic, 0, irq);
P
pbrook 已提交
117 118 119 120 121 122 123 124
}

/* Make pending IRQ active.  */
int armv7m_nvic_acknowledge_irq(void *opaque)
{
    nvic_state *s = (nvic_state *)opaque;
    uint32_t irq;

P
Paul Brook 已提交
125
    irq = gic_acknowledge_irq(&s->gic, 0);
P
pbrook 已提交
126
    if (irq == 1023)
P
Paul Brook 已提交
127
        hw_error("Interrupt but no vector\n");
P
pbrook 已提交
128 129 130 131 132 133 134 135 136 137
    if (irq >= 32)
        irq -= 16;
    return irq;
}

void armv7m_nvic_complete_irq(void *opaque, int irq)
{
    nvic_state *s = (nvic_state *)opaque;
    if (irq >= 16)
        irq += 16;
P
Paul Brook 已提交
138
    gic_complete_irq(&s->gic, 0, irq);
P
pbrook 已提交
139 140
}

141
static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
P
pbrook 已提交
142 143 144 145 146 147
{
    uint32_t val;
    int irq;

    switch (offset) {
    case 4: /* Interrupt Control Type.  */
148
        return (s->num_irq / 32) - 1;
P
pbrook 已提交
149 150 151 152 153 154 155 156 157 158 159
    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;
160
            t = qemu_get_clock_ns(vm_clock);
P
pbrook 已提交
161 162 163 164 165 166 167 168 169 170 171 172 173 174
            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_single_env->cp15.c0_cpuid;
175
    case 0xd04: /* Interrupt Control State.  */
P
pbrook 已提交
176
        /* VECTACTIVE */
P
Paul Brook 已提交
177
        val = s->gic.running_irq[0];
P
pbrook 已提交
178 179 180 181 182 183
        if (val == 1023) {
            val = 0;
        } else if (val >= 32) {
            val -= 16;
        }
        /* RETTOBASE */
P
Paul Brook 已提交
184 185
        if (s->gic.running_irq[0] == 1023
                || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
P
pbrook 已提交
186 187 188
            val |= (1 << 11);
        }
        /* VECTPENDING */
P
Paul Brook 已提交
189 190
        if (s->gic.current_pending[0] != 1023)
            val |= (s->gic.current_pending[0] << 12);
P
pbrook 已提交
191
        /* ISRPENDING */
192
        for (irq = 32; irq < s->num_irq; irq++) {
P
Paul Brook 已提交
193
            if (s->gic.irq_state[irq].pending) {
P
pbrook 已提交
194 195 196 197 198
                val |= (1 << 22);
                break;
            }
        }
        /* PENDSTSET */
P
Paul Brook 已提交
199
        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
P
pbrook 已提交
200 201
            val |= (1 << 26);
        /* PENDSVSET */
P
Paul Brook 已提交
202
        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
P
pbrook 已提交
203 204
            val |= (1 << 28);
        /* NMIPENDSET */
P
Paul Brook 已提交
205
        if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
P
pbrook 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218 219
            val |= (1 << 31);
        return val;
    case 0xd08: /* Vector Table Offset.  */
        return cpu_single_env->v7m.vecbase;
    case 0xd0c: /* Application Interrupt/Reset Control.  */
        return 0xfa05000;
    case 0xd10: /* System Control.  */
        /* TODO: Implement SLEEPONEXIT.  */
        return 0;
    case 0xd14: /* Configuration Control.  */
        /* TODO: Implement Configuration Control bits.  */
        return 0;
    case 0xd24: /* System Handler Status.  */
        val = 0;
P
Paul Brook 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233
        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);
P
pbrook 已提交
234 235 236
        return val;
    case 0xd28: /* Configurable Fault Status.  */
        /* TODO: Implement Fault Status.  */
237
        qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
P
pbrook 已提交
238 239 240 241 242 243 244
        return 0;
    case 0xd2c: /* Hard Fault Status.  */
    case 0xd30: /* Debug Fault Status.  */
    case 0xd34: /* Mem Manage Address.  */
    case 0xd38: /* Bus Fault Address.  */
    case 0xd3c: /* Aux Fault Status.  */
        /* TODO: Implement fault status registers.  */
245 246
        qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
        return 0;
P
pbrook 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    case 0xd40: /* PFR0.  */
        return 0x00000030;
    case 0xd44: /* PRF1.  */
        return 0x00000200;
    case 0xd48: /* DFR0.  */
        return 0x00100000;
    case 0xd4c: /* AFR0.  */
        return 0x00000000;
    case 0xd50: /* MMFR0.  */
        return 0x00000030;
    case 0xd54: /* MMFR1.  */
        return 0x00000000;
    case 0xd58: /* MMFR2.  */
        return 0x00000000;
    case 0xd5c: /* MMFR3.  */
        return 0x00000000;
    case 0xd60: /* ISAR0.  */
        return 0x01141110;
    case 0xd64: /* ISAR1.  */
        return 0x02111000;
    case 0xd68: /* ISAR2.  */
        return 0x21112231;
    case 0xd6c: /* ISAR3.  */
        return 0x01111110;
    case 0xd70: /* ISAR4.  */
        return 0x01310102;
    /* TODO: Implement debug registers.  */
    default:
275 276
        qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
        return 0;
P
pbrook 已提交
277 278 279
    }
}

280
static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
P
pbrook 已提交
281 282 283 284 285 286 287 288
{
    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) {
289
            int64_t now = qemu_get_clock_ns(vm_clock);
P
pbrook 已提交
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
            if (value & SYSTICK_ENABLE) {
                if (s->systick.tick) {
                    s->systick.tick += now;
                    qemu_mod_timer(s->systick.timer, s->systick.tick);
                } else {
                    systick_reload(s, 1);
                }
            } else {
                qemu_del_timer(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);
        }
        if (value & (1 << 28)) {
            armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
        } else if (value & (1 << 27)) {
P
Paul Brook 已提交
323 324
            s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
            gic_update(&s->gic);
P
pbrook 已提交
325 326 327 328
        }
        if (value & (1 << 26)) {
            armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
        } else if (value & (1 << 25)) {
P
Paul Brook 已提交
329 330
            s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
            gic_update(&s->gic);
P
pbrook 已提交
331 332 333 334 335 336 337 338
        }
        break;
    case 0xd08: /* Vector Table Offset.  */
        cpu_single_env->v7m.vecbase = value & 0xffffff80;
        break;
    case 0xd0c: /* Application Interrupt/Reset Control.  */
        if ((value >> 16) == 0x05fa) {
            if (value & 2) {
339
                qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
P
pbrook 已提交
340 341
            }
            if (value & 5) {
342
                qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
P
pbrook 已提交
343 344 345 346 347 348
            }
        }
        break;
    case 0xd10: /* System Control.  */
    case 0xd14: /* Configuration Control.  */
        /* TODO: Implement control registers.  */
349 350
        qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
        break;
P
pbrook 已提交
351 352 353
    case 0xd24: /* System Handler Control.  */
        /* TODO: Real hardware allows you to set/clear the active bits
           under some circumstances.  We don't implement this.  */
P
Paul Brook 已提交
354 355 356
        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;
P
pbrook 已提交
357 358 359 360 361 362 363
        break;
    case 0xd28: /* Configurable Fault Status.  */
    case 0xd2c: /* Hard Fault Status.  */
    case 0xd30: /* Debug Fault Status.  */
    case 0xd34: /* Mem Manage Address.  */
    case 0xd38: /* Bus Fault Address.  */
    case 0xd3c: /* Aux Fault Status.  */
364 365 366
        qemu_log_mask(LOG_UNIMP,
                      "NVIC: fault status registers unimplemented\n");
        break;
367 368 369 370 371
    case 0xf00: /* Software Triggered Interrupt Register */
        if ((value & 0x1ff) < s->num_irq) {
            gic_set_pending_private(&s->gic, 0, value & 0x1ff);
        }
        break;
P
pbrook 已提交
372
    default:
373 374
        qemu_log_mask(LOG_GUEST_ERROR,
                      "NVIC: Bad write offset 0x%x\n", offset);
P
pbrook 已提交
375 376 377
    }
}

A
Avi Kivity 已提交
378
static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
379 380
                                 unsigned size)
{
381
    nvic_state *s = (nvic_state *)opaque;
382
    uint32_t offset = addr;
383 384 385 386 387 388 389 390 391 392 393
    int i;
    uint32_t val;

    switch (offset) {
    case 0xd18 ... 0xd23: /* System Handler Priority.  */
        val = 0;
        for (i = 0; i < size; i++) {
            val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
        }
        return val;
    case 0xfe0 ... 0xfff: /* ID.  */
394 395 396 397 398 399
        if (offset & 3) {
            return 0;
        }
        return nvic_id[(offset - 0xfe0) >> 2];
    }
    if (size == 4) {
400
        return nvic_readl(s, offset);
401
    }
402 403 404
    qemu_log_mask(LOG_GUEST_ERROR,
                  "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
    return 0;
405 406
}

A
Avi Kivity 已提交
407
static void nvic_sysreg_write(void *opaque, hwaddr addr,
408 409
                              uint64_t value, unsigned size)
{
410
    nvic_state *s = (nvic_state *)opaque;
411
    uint32_t offset = addr;
412 413 414 415 416 417 418 419 420 421 422
    int i;

    switch (offset) {
    case 0xd18 ... 0xd23: /* System Handler Priority.  */
        for (i = 0; i < size; i++) {
            s->gic.priority1[(offset - 0xd14) + i][0] =
                (value >> (i * 8)) & 0xff;
        }
        gic_update(&s->gic);
        return;
    }
423
    if (size == 4) {
424
        nvic_writel(s, offset, value);
425 426
        return;
    }
427 428
    qemu_log_mask(LOG_GUEST_ERROR,
                  "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
429 430 431 432 433 434 435 436
}

static const MemoryRegionOps nvic_sysreg_ops = {
    .read = nvic_sysreg_read,
    .write = nvic_sysreg_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};

J
Juan Quintela 已提交
437 438 439 440 441 442 443 444 445 446 447 448 449
static const VMStateDescription vmstate_nvic = {
    .name = "armv7m_nvic",
    .version_id = 1,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
    .fields      = (VMStateField[]) {
        VMSTATE_UINT32(systick.control, nvic_state),
        VMSTATE_UINT32(systick.reload, nvic_state),
        VMSTATE_INT64(systick.tick, nvic_state),
        VMSTATE_TIMER(systick.timer, nvic_state),
        VMSTATE_END_OF_LIST()
    }
};
P
pbrook 已提交
450

451 452
static void armv7m_nvic_reset(DeviceState *dev)
{
453 454 455
    nvic_state *s = NVIC(dev);
    NVICClass *nc = NVIC_GET_CLASS(s);
    nc->parent_reset(dev);
456 457
    /* Common GIC reset resets to disabled; the NVIC doesn't have
     * per-CPU interfaces so mark our non-existent CPU interface
458 459
     * as enabled by default, and with a priority mask which allows
     * all interrupts through.
460
     */
461
    s->gic.cpu_enabled[0] = true;
462
    s->gic.priority_mask[0] = 0x100;
463
    /* The NVIC as a whole is always enabled. */
464
    s->gic.enabled = true;
465 466 467
    systick_reset(s);
}

468
static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
P
pbrook 已提交
469
{
470 471
    nvic_state *s = NVIC(dev);
    NVICClass *nc = NVIC_GET_CLASS(s);
P
pbrook 已提交
472

473 474
    /* The NVIC always has only one CPU */
    s->gic.num_cpu = 1;
475 476
    /* Tell the common code we're an NVIC */
    s->gic.revision = 0xffffffff;
477
    s->num_irq = s->gic.num_irq;
478 479 480 481
    nc->parent_realize(dev, errp);
    if (error_is_set(errp)) {
        return;
    }
482
    gic_init_irqs_and_distributor(&s->gic, s->num_irq);
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
    /* The NVIC and system controller register area looks like this:
     *  0..0xff : system control registers, including systick
     *  0x100..0xcff : GIC-like registers
     *  0xd00..0xfff : system control registers
     * We use overlaying to put the GIC like registers
     * over the top of the system control register region.
     */
    memory_region_init(&s->container, "nvic", 0x1000);
    /* The system register region goes at the bottom of the priority
     * stack as it covers the whole page.
     */
    memory_region_init_io(&s->sysregmem, &nvic_sysreg_ops, s,
                          "nvic_sysregs", 0x1000);
    memory_region_add_subregion(&s->container, 0, &s->sysregmem);
    /* Alias the GIC region so we can get only the section of it
     * we need, and layer it on top of the system register region.
     */
    memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
                             0x100, 0xc00);
502 503
    memory_region_add_subregion_overlap(&s->container, 0x100,
                                        &s->gic_iomem_alias, 1);
504 505 506 507
    /* Map the whole thing into system memory at the location required
     * by the v7M architecture.
     */
    memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
508
    s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
P
pbrook 已提交
509
}
P
Paul Brook 已提交
510

511 512 513 514 515 516
static void armv7m_nvic_instance_init(Object *obj)
{
    /* We have a different default value for the num-irq property
     * than our superclass. This function runs after qdev init
     * has set the defaults from the Property array and before
     * any user-specified property setting, so just modify the
517
     * value in the GICState struct.
518
     */
519
    GICState *s = ARM_GIC_COMMON(obj);
520 521
    /* The ARM v7m may have anything from 0 to 496 external interrupt
     * IRQ lines. We default to 64. Other boards may differ and should
522
     * set the num-irq property appropriately.
523
     */
524 525
    s->num_irq = 64;
}
526

527 528
static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
{
529
    NVICClass *nc = NVIC_CLASS(klass);
530
    DeviceClass *dc = DEVICE_CLASS(klass);
531

532
    nc->parent_reset = dc->reset;
533
    nc->parent_realize = dc->realize;
534
    dc->vmsd  = &vmstate_nvic;
535
    dc->reset = armv7m_nvic_reset;
536
    dc->realize = armv7m_nvic_realize;
537 538
}

539
static const TypeInfo armv7m_nvic_info = {
540 541
    .name          = TYPE_NVIC,
    .parent        = TYPE_ARM_GIC_COMMON,
542
    .instance_init = armv7m_nvic_instance_init,
543 544
    .instance_size = sizeof(nvic_state),
    .class_init    = armv7m_nvic_class_init,
545
    .class_size    = sizeof(NVICClass),
546 547
};

A
Andreas Färber 已提交
548
static void armv7m_nvic_register_types(void)
P
Paul Brook 已提交
549
{
550
    type_register_static(&armv7m_nvic_info);
P
Paul Brook 已提交
551 552
}

A
Andreas Färber 已提交
553
type_init(armv7m_nvic_register_types)