]>
Commit | Line | Data |
---|---|---|
4ef66fa7 MW |
1 | /* |
2 | * LatticeMico32 CPU interrupt controller logic. | |
3 | * | |
4 | * Copyright (c) 2010 Michael Walle <[email protected]> | |
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; | |
661f1929 | 42 | void lm32_do_pic_info(Monitor *mon) |
4ef66fa7 MW |
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 | ||
661f1929 | 52 | void lm32_irq_info(Monitor *mon) |
4ef66fa7 MW |
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 | ||
999e12bb AL |
177 | static void lm32_pic_class_init(ObjectClass *klass, void *data) |
178 | { | |
39bffca2 | 179 | DeviceClass *dc = DEVICE_CLASS(klass); |
999e12bb AL |
180 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
181 | ||
182 | k->init = lm32_pic_init; | |
39bffca2 AL |
183 | dc->reset = pic_reset; |
184 | dc->vmsd = &vmstate_lm32_pic; | |
999e12bb AL |
185 | } |
186 | ||
39bffca2 AL |
187 | static TypeInfo lm32_pic_info = { |
188 | .name = "lm32-pic", | |
189 | .parent = TYPE_SYS_BUS_DEVICE, | |
190 | .instance_size = sizeof(LM32PicState), | |
191 | .class_init = lm32_pic_class_init, | |
4ef66fa7 MW |
192 | }; |
193 | ||
83f7d43a | 194 | static void lm32_pic_register_types(void) |
4ef66fa7 | 195 | { |
39bffca2 | 196 | type_register_static(&lm32_pic_info); |
4ef66fa7 MW |
197 | } |
198 | ||
83f7d43a | 199 | type_init(lm32_pic_register_types) |