1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26#include "hw/sysbus.h"
27#include "qemu/module.h"
28#include "hw/irq.h"
29#include "hw/qdev-properties.h"
30#include "qom/object.h"
31
32#define D(x)
33
34#define R_RW_MASK 0
35#define R_R_VECT 1
36#define R_R_MASKED_VECT 2
37#define R_R_NMI 3
38#define R_R_GURU 4
39#define R_MAX 5
40
41#define TYPE_ETRAX_FS_PIC "etraxfs-pic"
42DECLARE_INSTANCE_CHECKER(struct etrax_pic, ETRAX_FS_PIC,
43 TYPE_ETRAX_FS_PIC)
44
45struct etrax_pic
46{
47 SysBusDevice parent_obj;
48
49 MemoryRegion mmio;
50 qemu_irq parent_irq;
51 qemu_irq parent_nmi;
52 uint32_t regs[R_MAX];
53};
54
55static void pic_update(struct etrax_pic *fs)
56{
57 uint32_t vector = 0;
58 int i;
59
60 fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
61
62
63
64
65
66 if (fs->regs[R_R_MASKED_VECT]) {
67 uint32_t mv = fs->regs[R_R_MASKED_VECT];
68 for (i = 0; i < 31; i++) {
69 if (mv & 1) {
70 vector = 0x31 + i;
71
72 if (mv > 1)
73 vector = 0x30;
74 break;
75 }
76 mv >>= 1;
77 }
78 }
79
80 qemu_set_irq(fs->parent_irq, vector);
81}
82
83static uint64_t
84pic_read(void *opaque, hwaddr addr, unsigned int size)
85{
86 struct etrax_pic *fs = opaque;
87 uint32_t rval;
88
89 rval = fs->regs[addr >> 2];
90 D(printf("%s %x=%x\n", __func__, addr, rval));
91 return rval;
92}
93
94static void pic_write(void *opaque, hwaddr addr,
95 uint64_t value, unsigned int size)
96{
97 struct etrax_pic *fs = opaque;
98 D(printf("%s addr=%x val=%x\n", __func__, addr, value));
99
100 if (addr == R_RW_MASK) {
101 fs->regs[R_RW_MASK] = value;
102 pic_update(fs);
103 }
104}
105
106static const MemoryRegionOps pic_ops = {
107 .read = pic_read,
108 .write = pic_write,
109 .endianness = DEVICE_NATIVE_ENDIAN,
110 .valid = {
111 .min_access_size = 4,
112 .max_access_size = 4
113 }
114};
115
116static void nmi_handler(void *opaque, int irq, int level)
117{
118 struct etrax_pic *fs = (void *)opaque;
119 uint32_t mask;
120
121 mask = 1 << irq;
122 if (level)
123 fs->regs[R_R_NMI] |= mask;
124 else
125 fs->regs[R_R_NMI] &= ~mask;
126
127 qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
128}
129
130static void irq_handler(void *opaque, int irq, int level)
131{
132 struct etrax_pic *fs = (void *)opaque;
133
134 if (irq >= 30) {
135 nmi_handler(opaque, irq, level);
136 return;
137 }
138
139 irq -= 1;
140 fs->regs[R_R_VECT] &= ~(1 << irq);
141 fs->regs[R_R_VECT] |= (!!level << irq);
142 pic_update(fs);
143}
144
145static void etraxfs_pic_init(Object *obj)
146{
147 DeviceState *dev = DEVICE(obj);
148 struct etrax_pic *s = ETRAX_FS_PIC(obj);
149 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
150
151 qdev_init_gpio_in(dev, irq_handler, 32);
152 sysbus_init_irq(sbd, &s->parent_irq);
153 sysbus_init_irq(sbd, &s->parent_nmi);
154
155 memory_region_init_io(&s->mmio, obj, &pic_ops, s,
156 "etraxfs-pic", R_MAX * 4);
157 sysbus_init_mmio(sbd, &s->mmio);
158}
159
160static const TypeInfo etraxfs_pic_info = {
161 .name = TYPE_ETRAX_FS_PIC,
162 .parent = TYPE_SYS_BUS_DEVICE,
163 .instance_size = sizeof(struct etrax_pic),
164 .instance_init = etraxfs_pic_init,
165};
166
167static void etraxfs_pic_register_types(void)
168{
169 type_register_static(&etraxfs_pic_info);
170}
171
172type_init(etraxfs_pic_register_types)
173