1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: #include "hw.h"
14: #include "qemu-timer.h"
15: #include "arm-misc.h"
16:
17:
18:
19: #define GIC_NIRQ 96
20: #define NCPU 1
21: #define NVIC 1
22:
23:
24: static inline int
25: gic_get_current_cpu(void)
26: {
27: return 0;
28: }
29:
30: static uint32_t nvic_readl(void *opaque, uint32_t offset);
31: static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
32:
33: #include "arm_gic.c"
34:
35: typedef struct {
36: struct {
37: uint32_t control;
38: uint32_t reload;
39: int64_t tick;
40: QEMUTimer *timer;
41: } systick;
42: gic_state *gic;
43: } nvic_state;
44:
45:
46: #define SYSTICK_SCALE 1000ULL
47:
48: #define SYSTICK_ENABLE (1 << 0)
49: #define SYSTICK_TICKINT (1 << 1)
50: #define SYSTICK_CLKSOURCE (1 << 2)
51: #define SYSTICK_COUNTFLAG (1 << 16)
52:
53:
54:
55: int system_clock_scale;
56:
57:
58: static inline int64_t systick_scale(nvic_state *s)
59: {
60: if (s->systick.control & SYSTICK_CLKSOURCE)
61: return system_clock_scale;
62: else
63: return 1000;
64: }
65:
66: static void systick_reload(nvic_state *s, int reset)
67: {
68: if (reset)
69: s->systick.tick = qemu_get_clock(vm_clock);
70: s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
71: qemu_mod_timer(s->systick.timer, s->systick.tick);
72: }
73:
74: static void systick_timer_tick(void * opaque)
75: {
76: nvic_state *s = (nvic_state *)opaque;
77: s->systick.control |= SYSTICK_COUNTFLAG;
78: if (s->systick.control & SYSTICK_TICKINT) {
79:
80: armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
81: }
82: if (s->systick.reload == 0) {
83: s->systick.control &= ~SYSTICK_ENABLE;
84: } else {
85: systick_reload(s, 0);
86: }
87: }
88:
89:
90:
91: void armv7m_nvic_set_pending(void *opaque, int irq)
92: {
93: nvic_state *s = (nvic_state *)opaque;
94: if (irq >= 16)
95: irq += 16;
96: gic_set_pending_private(s->gic, 0, irq);
97: }
98:
99:
100: int armv7m_nvic_acknowledge_irq(void *opaque)
101: {
102: nvic_state *s = (nvic_state *)opaque;
103: uint32_t irq;
104:
105: irq = gic_acknowledge_irq(s->gic, 0);
106: if (irq == 1023)
107: cpu_abort(cpu_single_env, "Interrupt but no vector\n");
108: if (irq >= 32)
109: irq -= 16;
110: return irq;
111: }
112:
113: void armv7m_nvic_complete_irq(void *opaque, int irq)
114: {
115: nvic_state *s = (nvic_state *)opaque;
116: if (irq >= 16)
117: irq += 16;
118: gic_complete_irq(s->gic, 0, irq);
119: }
120:
121: static uint32_t nvic_readl(void *opaque, uint32_t offset)
122: {
123: nvic_state *s = (nvic_state *)opaque;
124: uint32_t val;
125: int irq;
126:
127: switch (offset) {
128: case 4:
129: return (GIC_NIRQ / 32) - 1;
130: case 0x10:
131: val = s->systick.control;
132: s->systick.control &= ~SYSTICK_COUNTFLAG;
133: return val;
134: case 0x14:
135: return s->systick.reload;
136: case 0x18:
137: {
138: int64_t t;
139: if ((s->systick.control & SYSTICK_ENABLE) == 0)
140: return 0;
141: t = qemu_get_clock(vm_clock);
142: if (t >= s->systick.tick)
143: return 0;
144: val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
145:
146:
147:
148: if (val > s->systick.reload)
149: val = 0;
150: return val;
151: }
152: case 0x1c:
153: return 10000;
154: case 0xd00:
155: return cpu_single_env->cp15.c0_cpuid;
156: case 0xd04:
157:
158: val = s->gic->running_irq[0];
159: if (val == 1023) {
160: val = 0;
161: } else if (val >= 32) {
162: val -= 16;
163: }
164:
165: if (s->gic->running_irq[0] == 1023
166: || s->gic->last_active[s->gic->running_irq[0]][0] == 1023) {
167: val |= (1 << 11);
168: }
169:
170: if (s->gic->current_pending[0] != 1023)
171: val |= (s->gic->current_pending[0] << 12);
172:
173: for (irq = 32; irq < GIC_NIRQ; irq++) {
174: if (s->gic->irq_state[irq].pending) {
175: val |= (1 << 22);
176: break;
177: }
178: }
179:
180: if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending)
181: val |= (1 << 26);
182:
183: if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending)
184: val |= (1 << 28);
185:
186: if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending)
187: val |= (1 << 31);
188: return val;
189: case 0xd08:
190: return cpu_single_env->v7m.vecbase;
191: case 0xd0c:
192: return 0xfa05000;
193: case 0xd10:
194:
195: return 0;
196: case 0xd14:
197:
198: return 0;
199: case 0xd18: case 0xd1c: case 0xd20:
200: irq = offset - 0xd14;
201: val = 0;
202: val = s->gic->priority1[irq++][0];
203: val = s->gic->priority1[irq++][0] << 8;
204: val = s->gic->priority1[irq++][0] << 16;
205: val = s->gic->priority1[irq][0] << 24;
206: return val;
207: case 0xd24:
208: val = 0;
209: if (s->gic->irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
210: if (s->gic->irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
211: if (s->gic->irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
212: if (s->gic->irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
213: if (s->gic->irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
214: if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
215: if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
216: if (s->gic->irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
217: if (s->gic->irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
218: if (s->gic->irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
219: if (s->gic->irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
220: if (s->gic->irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
221: if (s->gic->irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
222: if (s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
223: return val;
224: case 0xd28:
225:
226: cpu_abort(cpu_single_env,
227: "Not implemented: Configurable Fault Status.");
228: return 0;
229: case 0xd2c:
230: case 0xd30:
231: case 0xd34:
232: case 0xd38:
233: case 0xd3c:
234:
235: goto bad_reg;
236: case 0xd40:
237: return 0x00000030;
238: case 0xd44:
239: return 0x00000200;
240: case 0xd48:
241: return 0x00100000;
242: case 0xd4c:
243: return 0x00000000;
244: case 0xd50:
245: return 0x00000030;
246: case 0xd54:
247: return 0x00000000;
248: case 0xd58:
249: return 0x00000000;
250: case 0xd5c:
251: return 0x00000000;
252: case 0xd60:
253: return 0x01141110;
254: case 0xd64:
255: return 0x02111000;
256: case 0xd68:
257: return 0x21112231;
258: case 0xd6c:
259: return 0x01111110;
260: case 0xd70:
261: return 0x01310102;
262:
263: default:
264: bad_reg:
265: cpu_abort(cpu_single_env, "NVIC: Bad read offset 0x%x\n", offset);
266: }
267: }
268:
269: static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
270: {
271: nvic_state *s = (nvic_state *)opaque;
272: uint32_t oldval;
273: switch (offset) {
274: case 0x10:
275: oldval = s->systick.control;
276: s->systick.control &= 0xfffffff8;
277: s->systick.control |= value & 7;
278: if ((oldval ^ value) & SYSTICK_ENABLE) {
279: int64_t now = qemu_get_clock(vm_clock);
280: if (value & SYSTICK_ENABLE) {
281: if (s->systick.tick) {
282: s->systick.tick += now;
283: qemu_mod_timer(s->systick.timer, s->systick.tick);
284: } else {
285: systick_reload(s, 1);
286: }
287: } else {
288: qemu_del_timer(s->systick.timer);
289: s->systick.tick -= now;
290: if (s->systick.tick < 0)
291: s->systick.tick = 0;
292: }
293: } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
294:
295:
296: systick_reload(s, 1);
297: }
298: break;
299: case 0x14:
300: s->systick.reload = value;
301: break;
302: case 0x18:
303: systick_reload(s, 1);
304: s->systick.control &= ~SYSTICK_COUNTFLAG;
305: break;
306: case 0xd04:
307: if (value & (1 << 31)) {
308: armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
309: }
310: if (value & (1 << 28)) {
311: armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
312: } else if (value & (1 << 27)) {
313: s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
314: gic_update(s->gic);
315: }
316: if (value & (1 << 26)) {
317: armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
318: } else if (value & (1 << 25)) {
319: s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
320: gic_update(s->gic);
321: }
322: break;
323: case 0xd08:
324: cpu_single_env->v7m.vecbase = value & 0xffffff80;
325: break;
326: case 0xd0c:
327: if ((value >> 16) == 0x05fa) {
328: if (value & 2) {
329: cpu_abort(cpu_single_env, "VECTCLRACTIVE not implemented");
330: }
331: if (value & 5) {
332: cpu_abort(cpu_single_env, "System reset");
333: }
334: }
335: break;
336: case 0xd10:
337: case 0xd14:
338:
339: goto bad_reg;
340: case 0xd18: case 0xd1c: case 0xd20:
341: {
342: int irq;
343: irq = offset - 0xd14;
344: s->gic->priority1[irq++][0] = value & 0xff;
345: s->gic->priority1[irq++][0] = (value >> 8) & 0xff;
346: s->gic->priority1[irq++][0] = (value >> 16) & 0xff;
347: s->gic->priority1[irq][0] = (value >> 24) & 0xff;
348: gic_update(s->gic);
349: }
350: break;
351: case 0xd24:
352:
353:
354: s->gic->irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
355: s->gic->irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
356: s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
357: break;
358: case 0xd28:
359: case 0xd2c:
360: case 0xd30:
361: case 0xd34:
362: case 0xd38:
363: case 0xd3c:
364: goto bad_reg;
365: default:
366: bad_reg:
367: cpu_abort(cpu_single_env, "NVIC: Bad write offset 0x%x\n", offset);
368: }
369: }
370:
371: qemu_irq *armv7m_nvic_init(CPUState *env)
372: {
373: nvic_state *s;
374: qemu_irq *parent;
375:
376: parent = arm_pic_init_cpu(env);
377: s = (nvic_state *)qemu_mallocz(sizeof(nvic_state));
378: s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]);
379: s->gic->nvic = s;
380: s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s);
381: if (env->v7m.nvic)
382: cpu_abort(env, "CPU can only have one NVIC\n");
383: env->v7m.nvic = s;
384: return s->gic->in;
385: }