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
26
27
28
29
30
31
32
33
34
35#include "qemu/osdep.h"
36
37#include "hw/irq.h"
38#include "hw/qdev-properties.h"
39#include "hw/sysbus.h"
40#include "migration/vmstate.h"
41#include "qapi/error.h"
42#include "qemu/bitops.h"
43#include "qemu/log.h"
44#include "qom/object.h"
45#include "hw/intc/nios2_vic.h"
46#include "cpu.h"
47
48
49enum {
50 INT_CONFIG0 = 0,
51 INT_CONFIG31 = 31,
52 INT_ENABLE = 32,
53 INT_ENABLE_SET = 33,
54 INT_ENABLE_CLR = 34,
55 INT_PENDING = 35,
56 INT_RAW_STATUS = 36,
57 SW_INTERRUPT = 37,
58 SW_INTERRUPT_SET = 38,
59 SW_INTERRUPT_CLR = 39,
60 VIC_CONFIG = 40,
61 VIC_STATUS = 41,
62 VEC_TBL_BASE = 42,
63 VEC_TBL_ADDR = 43,
64 CSR_COUNT
65};
66
67
68static inline uint32_t vic_int_config_ril(const Nios2VIC *vic, int irq_num)
69{
70 return extract32(vic->int_config[irq_num], 0, 6);
71}
72
73
74static inline uint32_t vic_int_config_rnmi(const Nios2VIC *vic, int irq_num)
75{
76 return extract32(vic->int_config[irq_num], 6, 1);
77}
78
79
80static inline uint32_t vic_int_config_rrs(const Nios2VIC *vic, int irq_num)
81{
82 return extract32(vic->int_config[irq_num], 7, 6);
83}
84
85static inline uint32_t vic_config_vec_size(const Nios2VIC *vic)
86{
87 return 1 << (2 + extract32(vic->vic_config, 0, 3));
88}
89
90static inline uint32_t vic_int_pending(const Nios2VIC *vic)
91{
92 return (vic->int_raw_status | vic->sw_int) & vic->int_enable;
93}
94
95static void vic_update_irq(Nios2VIC *vic)
96{
97 Nios2CPU *cpu = NIOS2_CPU(vic->cpu);
98 uint32_t pending = vic_int_pending(vic);
99 int irq = -1;
100 int max_ril = 0;
101
102
103 vic->vec_tbl_addr = 0;
104 vic->vic_status = 0;
105
106 if (pending == 0) {
107 qemu_irq_lower(vic->output_int);
108 return;
109 }
110
111 for (int i = 0; i < NIOS2_VIC_MAX_IRQ; i++) {
112 if (pending & BIT(i)) {
113 int ril = vic_int_config_ril(vic, i);
114 if (ril > max_ril) {
115 irq = i;
116 max_ril = ril;
117 }
118 }
119 }
120
121 if (irq < 0) {
122 qemu_irq_lower(vic->output_int);
123 return;
124 }
125
126 vic->vec_tbl_addr = irq * vic_config_vec_size(vic) + vic->vec_tbl_base;
127 vic->vic_status = irq | BIT(31);
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 cpu->rha = vic->vec_tbl_addr;
143 cpu->ril = max_ril;
144 cpu->rrs = vic_int_config_rrs(vic, irq);
145 cpu->rnmi = vic_int_config_rnmi(vic, irq);
146
147 qemu_irq_raise(vic->output_int);
148}
149
150static void vic_set_irq(void *opaque, int irq_num, int level)
151{
152 Nios2VIC *vic = opaque;
153
154 vic->int_raw_status = deposit32(vic->int_raw_status, irq_num, 1, !!level);
155 vic_update_irq(vic);
156}
157
158static void nios2_vic_reset(DeviceState *dev)
159{
160 Nios2VIC *vic = NIOS2_VIC(dev);
161
162 memset(&vic->int_config, 0, sizeof(vic->int_config));
163 vic->vic_config = 0;
164 vic->int_raw_status = 0;
165 vic->int_enable = 0;
166 vic->sw_int = 0;
167 vic->vic_status = 0;
168 vic->vec_tbl_base = 0;
169 vic->vec_tbl_addr = 0;
170}
171
172static uint64_t nios2_vic_csr_read(void *opaque, hwaddr offset, unsigned size)
173{
174 Nios2VIC *vic = opaque;
175 int index = offset / 4;
176
177 switch (index) {
178 case INT_CONFIG0 ... INT_CONFIG31:
179 return vic->int_config[index - INT_CONFIG0];
180 case INT_ENABLE:
181 return vic->int_enable;
182 case INT_PENDING:
183 return vic_int_pending(vic);
184 case INT_RAW_STATUS:
185 return vic->int_raw_status;
186 case SW_INTERRUPT:
187 return vic->sw_int;
188 case VIC_CONFIG:
189 return vic->vic_config;
190 case VIC_STATUS:
191 return vic->vic_status;
192 case VEC_TBL_BASE:
193 return vic->vec_tbl_base;
194 case VEC_TBL_ADDR:
195 return vic->vec_tbl_addr;
196 default:
197 return 0;
198 }
199}
200
201static void nios2_vic_csr_write(void *opaque, hwaddr offset, uint64_t value,
202 unsigned size)
203{
204 Nios2VIC *vic = opaque;
205 int index = offset / 4;
206
207 switch (index) {
208 case INT_CONFIG0 ... INT_CONFIG31:
209 vic->int_config[index - INT_CONFIG0] = value;
210 break;
211 case INT_ENABLE:
212 vic->int_enable = value;
213 break;
214 case INT_ENABLE_SET:
215 vic->int_enable |= value;
216 break;
217 case INT_ENABLE_CLR:
218 vic->int_enable &= ~value;
219 break;
220 case SW_INTERRUPT:
221 vic->sw_int = value;
222 break;
223 case SW_INTERRUPT_SET:
224 vic->sw_int |= value;
225 break;
226 case SW_INTERRUPT_CLR:
227 vic->sw_int &= ~value;
228 break;
229 case VIC_CONFIG:
230 vic->vic_config = value;
231 break;
232 case VEC_TBL_BASE:
233 vic->vec_tbl_base = value;
234 break;
235 default:
236 qemu_log_mask(LOG_GUEST_ERROR,
237 "nios2-vic: write to invalid CSR address %#"
238 HWADDR_PRIx "\n", offset);
239 }
240
241 vic_update_irq(vic);
242}
243
244static const MemoryRegionOps nios2_vic_csr_ops = {
245 .read = nios2_vic_csr_read,
246 .write = nios2_vic_csr_write,
247 .endianness = DEVICE_LITTLE_ENDIAN,
248 .valid = { .min_access_size = 4, .max_access_size = 4 }
249};
250
251static void nios2_vic_realize(DeviceState *dev, Error **errp)
252{
253 Nios2VIC *vic = NIOS2_VIC(dev);
254
255 if (!vic->cpu) {
256
257 error_setg(errp, "nios2-vic 'cpu' link property was not set");
258 return;
259 }
260
261 sysbus_init_irq(SYS_BUS_DEVICE(dev), &vic->output_int);
262 qdev_init_gpio_in(dev, vic_set_irq, NIOS2_VIC_MAX_IRQ);
263
264 memory_region_init_io(&vic->csr, OBJECT(dev), &nios2_vic_csr_ops, vic,
265 "nios2.vic.csr", CSR_COUNT * sizeof(uint32_t));
266 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &vic->csr);
267}
268
269static Property nios2_vic_properties[] = {
270 DEFINE_PROP_LINK("cpu", Nios2VIC, cpu, TYPE_CPU, CPUState *),
271 DEFINE_PROP_END_OF_LIST()
272};
273
274static const VMStateDescription nios2_vic_vmstate = {
275 .name = "nios2-vic",
276 .version_id = 1,
277 .minimum_version_id = 1,
278 .fields = (VMStateField[]){
279 VMSTATE_UINT32_ARRAY(int_config, Nios2VIC, 32),
280 VMSTATE_UINT32(vic_config, Nios2VIC),
281 VMSTATE_UINT32(int_raw_status, Nios2VIC),
282 VMSTATE_UINT32(int_enable, Nios2VIC),
283 VMSTATE_UINT32(sw_int, Nios2VIC),
284 VMSTATE_UINT32(vic_status, Nios2VIC),
285 VMSTATE_UINT32(vec_tbl_base, Nios2VIC),
286 VMSTATE_UINT32(vec_tbl_addr, Nios2VIC),
287 VMSTATE_END_OF_LIST()
288 },
289};
290
291static void nios2_vic_class_init(ObjectClass *klass, void *data)
292{
293 DeviceClass *dc = DEVICE_CLASS(klass);
294
295 dc->reset = nios2_vic_reset;
296 dc->realize = nios2_vic_realize;
297 dc->vmsd = &nios2_vic_vmstate;
298 device_class_set_props(dc, nios2_vic_properties);
299}
300
301static const TypeInfo nios2_vic_info = {
302 .name = TYPE_NIOS2_VIC,
303 .parent = TYPE_SYS_BUS_DEVICE,
304 .instance_size = sizeof(Nios2VIC),
305 .class_init = nios2_vic_class_init,
306};
307
308static void nios2_vic_register_types(void)
309{
310 type_register_static(&nios2_vic_info);
311}
312
313type_init(nios2_vic_register_types);
314