qemu/hw/intc/puv3_intc.c
<<
>>
Prefs
   1/*
   2 * INTC device simulation in PKUnity SoC
   3 *
   4 * Copyright (C) 2010-2012 Guan Xuetao
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation, or any later version.
   9 * See the COPYING file in the top-level directory.
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "hw/sysbus.h"
  14
  15#undef DEBUG_PUV3
  16#include "hw/unicore32/puv3.h"
  17#include "qemu/module.h"
  18
  19#define TYPE_PUV3_INTC "puv3_intc"
  20#define PUV3_INTC(obj) OBJECT_CHECK(PUV3INTCState, (obj), TYPE_PUV3_INTC)
  21
  22typedef struct PUV3INTCState {
  23    SysBusDevice parent_obj;
  24
  25    MemoryRegion iomem;
  26    qemu_irq parent_irq;
  27
  28    uint32_t reg_ICMR;
  29    uint32_t reg_ICPR;
  30} PUV3INTCState;
  31
  32/* Update interrupt status after enabled or pending bits have been changed.  */
  33static void puv3_intc_update(PUV3INTCState *s)
  34{
  35    if (s->reg_ICMR & s->reg_ICPR) {
  36        qemu_irq_raise(s->parent_irq);
  37    } else {
  38        qemu_irq_lower(s->parent_irq);
  39    }
  40}
  41
  42/* Process a change in an external INTC input. */
  43static void puv3_intc_handler(void *opaque, int irq, int level)
  44{
  45    PUV3INTCState *s = opaque;
  46
  47    DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
  48    if (level) {
  49        s->reg_ICPR |= (1 << irq);
  50    } else {
  51        s->reg_ICPR &= ~(1 << irq);
  52    }
  53    puv3_intc_update(s);
  54}
  55
  56static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
  57        unsigned size)
  58{
  59    PUV3INTCState *s = opaque;
  60    uint32_t ret = 0;
  61
  62    switch (offset) {
  63    case 0x04: /* INTC_ICMR */
  64        ret = s->reg_ICMR;
  65        break;
  66    case 0x0c: /* INTC_ICIP */
  67        ret = s->reg_ICPR; /* the same value with ICPR */
  68        break;
  69    default:
  70        DPRINTF("Bad offset %x\n", (int)offset);
  71    }
  72    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
  73    return ret;
  74}
  75
  76static void puv3_intc_write(void *opaque, hwaddr offset,
  77        uint64_t value, unsigned size)
  78{
  79    PUV3INTCState *s = opaque;
  80
  81    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
  82    switch (offset) {
  83    case 0x00: /* INTC_ICLR */
  84    case 0x14: /* INTC_ICCR */
  85        break;
  86    case 0x04: /* INTC_ICMR */
  87        s->reg_ICMR = value;
  88        break;
  89    default:
  90        DPRINTF("Bad offset 0x%x\n", (int)offset);
  91        return;
  92    }
  93    puv3_intc_update(s);
  94}
  95
  96static const MemoryRegionOps puv3_intc_ops = {
  97    .read = puv3_intc_read,
  98    .write = puv3_intc_write,
  99    .impl = {
 100        .min_access_size = 4,
 101        .max_access_size = 4,
 102    },
 103    .endianness = DEVICE_NATIVE_ENDIAN,
 104};
 105
 106static void puv3_intc_realize(DeviceState *dev, Error **errp)
 107{
 108    PUV3INTCState *s = PUV3_INTC(dev);
 109    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 110
 111    qdev_init_gpio_in(dev, puv3_intc_handler, PUV3_IRQS_NR);
 112    sysbus_init_irq(sbd, &s->parent_irq);
 113
 114    s->reg_ICMR = 0;
 115    s->reg_ICPR = 0;
 116
 117    memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc",
 118                          PUV3_REGS_OFFSET);
 119    sysbus_init_mmio(sbd, &s->iomem);
 120}
 121
 122static void puv3_intc_class_init(ObjectClass *klass, void *data)
 123{
 124    DeviceClass *dc = DEVICE_CLASS(klass);
 125    dc->realize = puv3_intc_realize;
 126}
 127
 128static const TypeInfo puv3_intc_info = {
 129    .name = TYPE_PUV3_INTC,
 130    .parent = TYPE_SYS_BUS_DEVICE,
 131    .instance_size = sizeof(PUV3INTCState),
 132    .class_init = puv3_intc_class_init,
 133};
 134
 135static void puv3_intc_register_type(void)
 136{
 137    type_register_static(&puv3_intc_info);
 138}
 139
 140type_init(puv3_intc_register_type)
 141