]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * LatticeMico32 CPU interrupt controller logic. | |
3 | * | |
4 | * Copyright (c) 2010 Michael Walle <michael@walle.cc> | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include <assert.h> | |
21 | ||
22 | #include "hw.h" | |
23 | #include "pc.h" | |
24 | #include "monitor.h" | |
25 | #include "sysbus.h" | |
26 | #include "trace.h" | |
27 | #include "lm32_pic.h" | |
28 | ||
29 | struct LM32PicState { | |
30 | SysBusDevice busdev; | |
31 | qemu_irq parent_irq; | |
32 | uint32_t im; /* interrupt mask */ | |
33 | uint32_t ip; /* interrupt pending */ | |
34 | uint32_t irq_state; | |
35 | ||
36 | /* statistics */ | |
37 | uint32_t stats_irq_count[32]; | |
38 | }; | |
39 | typedef struct LM32PicState LM32PicState; | |
40 | ||
41 | static LM32PicState *pic; | |
42 | void pic_info(Monitor *mon) | |
43 | { | |
44 | if (pic == NULL) { | |
45 | return; | |
46 | } | |
47 | ||
48 | monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n", | |
49 | pic->im, pic->ip, pic->irq_state); | |
50 | } | |
51 | ||
52 | void irq_info(Monitor *mon) | |
53 | { | |
54 | int i; | |
55 | uint32_t count; | |
56 | ||
57 | if (pic == NULL) { | |
58 | return; | |
59 | } | |
60 | ||
61 | monitor_printf(mon, "IRQ statistics:\n"); | |
62 | for (i = 0; i < 32; i++) { | |
63 | count = pic->stats_irq_count[i]; | |
64 | if (count > 0) { | |
65 | monitor_printf(mon, "%2d: %u\n", i, count); | |
66 | } | |
67 | } | |
68 | } | |
69 | ||
70 | static void update_irq(LM32PicState *s) | |
71 | { | |
72 | s->ip |= s->irq_state; | |
73 | ||
74 | if (s->ip & s->im) { | |
75 | trace_lm32_pic_raise_irq(); | |
76 | qemu_irq_raise(s->parent_irq); | |
77 | } else { | |
78 | trace_lm32_pic_lower_irq(); | |
79 | qemu_irq_lower(s->parent_irq); | |
80 | } | |
81 | } | |
82 | ||
83 | static void irq_handler(void *opaque, int irq, int level) | |
84 | { | |
85 | LM32PicState *s = opaque; | |
86 | ||
87 | assert(irq < 32); | |
88 | trace_lm32_pic_interrupt(irq, level); | |
89 | ||
90 | if (level) { | |
91 | s->irq_state |= (1 << irq); | |
92 | s->stats_irq_count[irq]++; | |
93 | } else { | |
94 | s->irq_state &= ~(1 << irq); | |
95 | } | |
96 | ||
97 | update_irq(s); | |
98 | } | |
99 | ||
100 | void lm32_pic_set_im(DeviceState *d, uint32_t im) | |
101 | { | |
102 | LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); | |
103 | ||
104 | trace_lm32_pic_set_im(im); | |
105 | s->im = im; | |
106 | ||
107 | update_irq(s); | |
108 | } | |
109 | ||
110 | void lm32_pic_set_ip(DeviceState *d, uint32_t ip) | |
111 | { | |
112 | LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); | |
113 | ||
114 | trace_lm32_pic_set_ip(ip); | |
115 | ||
116 | /* ack interrupt */ | |
117 | s->ip &= ~ip; | |
118 | ||
119 | update_irq(s); | |
120 | } | |
121 | ||
122 | uint32_t lm32_pic_get_im(DeviceState *d) | |
123 | { | |
124 | LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); | |
125 | ||
126 | trace_lm32_pic_get_im(s->im); | |
127 | return s->im; | |
128 | } | |
129 | ||
130 | uint32_t lm32_pic_get_ip(DeviceState *d) | |
131 | { | |
132 | LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); | |
133 | ||
134 | trace_lm32_pic_get_ip(s->ip); | |
135 | return s->ip; | |
136 | } | |
137 | ||
138 | static void pic_reset(DeviceState *d) | |
139 | { | |
140 | LM32PicState *s = container_of(d, LM32PicState, busdev.qdev); | |
141 | int i; | |
142 | ||
143 | s->im = 0; | |
144 | s->ip = 0; | |
145 | s->irq_state = 0; | |
146 | for (i = 0; i < 32; i++) { | |
147 | s->stats_irq_count[i] = 0; | |
148 | } | |
149 | } | |
150 | ||
151 | static int lm32_pic_init(SysBusDevice *dev) | |
152 | { | |
153 | LM32PicState *s = FROM_SYSBUS(typeof(*s), dev); | |
154 | ||
155 | qdev_init_gpio_in(&dev->qdev, irq_handler, 32); | |
156 | sysbus_init_irq(dev, &s->parent_irq); | |
157 | ||
158 | pic = s; | |
159 | ||
160 | return 0; | |
161 | } | |
162 | ||
163 | static const VMStateDescription vmstate_lm32_pic = { | |
164 | .name = "lm32-pic", | |
165 | .version_id = 1, | |
166 | .minimum_version_id = 1, | |
167 | .minimum_version_id_old = 1, | |
168 | .fields = (VMStateField[]) { | |
169 | VMSTATE_UINT32(im, LM32PicState), | |
170 | VMSTATE_UINT32(ip, LM32PicState), | |
171 | VMSTATE_UINT32(irq_state, LM32PicState), | |
172 | VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32), | |
173 | VMSTATE_END_OF_LIST() | |
174 | } | |
175 | }; | |
176 | ||
177 | static SysBusDeviceInfo lm32_pic_info = { | |
178 | .init = lm32_pic_init, | |
179 | .qdev.name = "lm32-pic", | |
180 | .qdev.size = sizeof(LM32PicState), | |
181 | .qdev.vmsd = &vmstate_lm32_pic, | |
182 | .qdev.reset = pic_reset, | |
183 | }; | |
184 | ||
185 | static void lm32_pic_register(void) | |
186 | { | |
187 | sysbus_register_withprop(&lm32_pic_info); | |
188 | } | |
189 | ||
190 | device_init(lm32_pic_register) |