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 "hw/hw.h"
28
29
30
31#define D(x)
32
33#define R_RW_MASK 0
34#define R_R_VECT 1
35#define R_R_MASKED_VECT 2
36#define R_R_NMI 3
37#define R_R_GURU 4
38#define R_MAX 5
39
40#define TYPE_ETRAX_FS_PIC "etraxfs,pic"
41#define ETRAX_FS_PIC(obj) \
42 OBJECT_CHECK(struct etrax_pic, (obj), TYPE_ETRAX_FS_PIC)
43
44struct etrax_pic
45{
46 SysBusDevice parent_obj;
47
48 MemoryRegion mmio;
49 void *interrupt_vector;
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 if (fs->interrupt_vector) {
81
82 *(uint32_t*)(fs->interrupt_vector) = vector;
83 }
84 qemu_set_irq(fs->parent_irq, !!vector);
85}
86
87static uint64_t
88pic_read(void *opaque, hwaddr addr, unsigned int size)
89{
90 struct etrax_pic *fs = opaque;
91 uint32_t rval;
92
93 rval = fs->regs[addr >> 2];
94 D(printf("%s %x=%x\n", __func__, addr, rval));
95 return rval;
96}
97
98static void pic_write(void *opaque, hwaddr addr,
99 uint64_t value, unsigned int size)
100{
101 struct etrax_pic *fs = opaque;
102 D(printf("%s addr=%x val=%x\n", __func__, addr, value));
103
104 if (addr == R_RW_MASK) {
105 fs->regs[R_RW_MASK] = value;
106 pic_update(fs);
107 }
108}
109
110static const MemoryRegionOps pic_ops = {
111 .read = pic_read,
112 .write = pic_write,
113 .endianness = DEVICE_NATIVE_ENDIAN,
114 .valid = {
115 .min_access_size = 4,
116 .max_access_size = 4
117 }
118};
119
120static void nmi_handler(void *opaque, int irq, int level)
121{
122 struct etrax_pic *fs = (void *)opaque;
123 uint32_t mask;
124
125 mask = 1 << irq;
126 if (level)
127 fs->regs[R_R_NMI] |= mask;
128 else
129 fs->regs[R_R_NMI] &= ~mask;
130
131 qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
132}
133
134static void irq_handler(void *opaque, int irq, int level)
135{
136 struct etrax_pic *fs = (void *)opaque;
137
138 if (irq >= 30) {
139 nmi_handler(opaque, irq, level);
140 return;
141 }
142
143 irq -= 1;
144 fs->regs[R_R_VECT] &= ~(1 << irq);
145 fs->regs[R_R_VECT] |= (!!level << irq);
146 pic_update(fs);
147}
148
149static void etraxfs_pic_init(Object *obj)
150{
151 DeviceState *dev = DEVICE(obj);
152 struct etrax_pic *s = ETRAX_FS_PIC(obj);
153 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
154
155 qdev_init_gpio_in(dev, irq_handler, 32);
156 sysbus_init_irq(sbd, &s->parent_irq);
157 sysbus_init_irq(sbd, &s->parent_nmi);
158
159 memory_region_init_io(&s->mmio, obj, &pic_ops, s,
160 "etraxfs-pic", R_MAX * 4);
161 sysbus_init_mmio(sbd, &s->mmio);
162}
163
164static Property etraxfs_pic_properties[] = {
165 DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
166 DEFINE_PROP_END_OF_LIST(),
167};
168
169static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
170{
171 DeviceClass *dc = DEVICE_CLASS(klass);
172
173 dc->props = etraxfs_pic_properties;
174
175
176
177
178}
179
180static const TypeInfo etraxfs_pic_info = {
181 .name = TYPE_ETRAX_FS_PIC,
182 .parent = TYPE_SYS_BUS_DEVICE,
183 .instance_size = sizeof(struct etrax_pic),
184 .instance_init = etraxfs_pic_init,
185 .class_init = etraxfs_pic_class_init,
186};
187
188static void etraxfs_pic_register_types(void)
189{
190 type_register_static(&etraxfs_pic_info);
191}
192
193type_init(etraxfs_pic_register_types)
194