Statistics
| Branch: | Revision:

root / hw / puv3_intc.c @ 0d09e41a

History | View | Annotate | Download (3.2 kB)

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
#include "hw/sysbus.h"
12

    
13
#undef DEBUG_PUV3
14
#include "hw/unicore32/puv3.h"
15

    
16
typedef struct {
17
    SysBusDevice busdev;
18
    MemoryRegion iomem;
19
    qemu_irq parent_irq;
20

    
21
    uint32_t reg_ICMR;
22
    uint32_t reg_ICPR;
23
} PUV3INTCState;
24

    
25
/* Update interrupt status after enabled or pending bits have been changed.  */
26
static void puv3_intc_update(PUV3INTCState *s)
27
{
28
    if (s->reg_ICMR & s->reg_ICPR) {
29
        qemu_irq_raise(s->parent_irq);
30
    } else {
31
        qemu_irq_lower(s->parent_irq);
32
    }
33
}
34

    
35
/* Process a change in an external INTC input. */
36
static void puv3_intc_handler(void *opaque, int irq, int level)
37
{
38
    PUV3INTCState *s = opaque;
39

    
40
    DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
41
    if (level) {
42
        s->reg_ICPR |= (1 << irq);
43
    } else {
44
        s->reg_ICPR &= ~(1 << irq);
45
    }
46
    puv3_intc_update(s);
47
}
48

    
49
static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
50
        unsigned size)
51
{
52
    PUV3INTCState *s = opaque;
53
    uint32_t ret = 0;
54

    
55
    switch (offset) {
56
    case 0x04: /* INTC_ICMR */
57
        ret = s->reg_ICMR;
58
        break;
59
    case 0x0c: /* INTC_ICIP */
60
        ret = s->reg_ICPR; /* the same value with ICPR */
61
        break;
62
    default:
63
        DPRINTF("Bad offset %x\n", (int)offset);
64
    }
65
    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
66
    return ret;
67
}
68

    
69
static void puv3_intc_write(void *opaque, hwaddr offset,
70
        uint64_t value, unsigned size)
71
{
72
    PUV3INTCState *s = opaque;
73

    
74
    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
75
    switch (offset) {
76
    case 0x00: /* INTC_ICLR */
77
    case 0x14: /* INTC_ICCR */
78
        break;
79
    case 0x04: /* INTC_ICMR */
80
        s->reg_ICMR = value;
81
        break;
82
    default:
83
        DPRINTF("Bad offset 0x%x\n", (int)offset);
84
        return;
85
    }
86
    puv3_intc_update(s);
87
}
88

    
89
static const MemoryRegionOps puv3_intc_ops = {
90
    .read = puv3_intc_read,
91
    .write = puv3_intc_write,
92
    .impl = {
93
        .min_access_size = 4,
94
        .max_access_size = 4,
95
    },
96
    .endianness = DEVICE_NATIVE_ENDIAN,
97
};
98

    
99
static int puv3_intc_init(SysBusDevice *dev)
100
{
101
    PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev);
102

    
103
    qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR);
104
    sysbus_init_irq(&s->busdev, &s->parent_irq);
105

    
106
    s->reg_ICMR = 0;
107
    s->reg_ICPR = 0;
108

    
109
    memory_region_init_io(&s->iomem, &puv3_intc_ops, s, "puv3_intc",
110
            PUV3_REGS_OFFSET);
111
    sysbus_init_mmio(dev, &s->iomem);
112

    
113
    return 0;
114
}
115

    
116
static void puv3_intc_class_init(ObjectClass *klass, void *data)
117
{
118
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
119

    
120
    sdc->init = puv3_intc_init;
121
}
122

    
123
static const TypeInfo puv3_intc_info = {
124
    .name = "puv3_intc",
125
    .parent = TYPE_SYS_BUS_DEVICE,
126
    .instance_size = sizeof(PUV3INTCState),
127
    .class_init = puv3_intc_class_init,
128
};
129

    
130
static void puv3_intc_register_type(void)
131
{
132
    type_register_static(&puv3_intc_info);
133
}
134

    
135
type_init(puv3_intc_register_type)