f32b3021c4ac3e50a2cce8b657b07f3123cb873a
[qemu] / hw / etraxfs_pic.c
1 /*
2  * QEMU ETRAX Interrupt Controller.
3  *
4  * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include <stdio.h>
26 #include "hw.h"
27 #include "pc.h"
28 #include "etraxfs.h"
29
30 #define D(x)
31
32 struct fs_pic_state_t
33 {
34         CPUState *env;
35
36         uint32_t rw_mask;
37         /* Active interrupt lines.  */
38         uint32_t r_vect;
39         /* Active lines, gated through the mask.  */
40         uint32_t r_masked_vect;
41         uint32_t r_nmi;
42         uint32_t r_guru;
43 };
44
45 static void pic_update(struct fs_pic_state_t *fs)
46 {       
47         CPUState *env = fs->env;
48         int i;
49         uint32_t vector = 0;
50
51         fs->r_masked_vect = fs->r_vect & fs->rw_mask;
52
53         /* The ETRAX interrupt controller signals interrupts to teh core
54            through an interrupt request wire and an irq vector bus. If 
55            multiple interrupts are simultaneously active it chooses vector 
56            0x30 and lets the sw choose the priorities.  */
57         if (fs->r_masked_vect) {
58                 uint32_t mv = fs->r_masked_vect;
59                 for (i = 0; i < 31; i++) {
60                         if (mv & 1) {
61                                 vector = 0x31 + i;
62                                 /* Check for multiple interrupts.  */
63                                 if (mv > 1)
64                                         vector = 0x30;
65                                 break;
66                         }
67                         mv >>= 1;
68                 }
69                 if (vector) {
70                         env->interrupt_vector = vector;
71                         D(printf("%s vector=%x\n", __func__, vector));
72                         cpu_interrupt(env, CPU_INTERRUPT_HARD);
73                 }
74         } else {
75                 env->interrupt_vector = 0;
76                 cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
77                 D(printf("%s reset irqs\n", __func__));
78         }
79 }
80
81 static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
82 {
83         struct fs_pic_state_t *fs = opaque;
84         uint32_t rval;
85
86         switch (addr)
87         {
88                 case 0x0: 
89                         rval = fs->rw_mask;
90                         break;
91                 case 0x4: 
92                         rval = fs->r_vect;
93                         break;
94                 case 0x8: 
95                         rval = fs->r_masked_vect;
96                         break;
97                 case 0xc: 
98                         rval = fs->r_nmi;
99                         break;
100                 case 0x10: 
101                         rval = fs->r_guru;
102                         break;
103                 default:
104                         cpu_abort(fs->env, "invalid PIC register.\n");
105                         break;
106
107         }
108         D(printf("%s %x=%x\n", __func__, addr, rval));
109         return rval;
110 }
111
112 static void
113 pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
114 {
115         struct fs_pic_state_t *fs = opaque;
116         D(printf("%s addr=%x val=%x\n", __func__, addr, value));
117         switch (addr) 
118         {
119                 case 0x0: 
120                         fs->rw_mask = value;
121                         pic_update(fs);
122                         break;
123                 default:
124                         cpu_abort(fs->env, "invalid PIC register.\n");
125                         break;
126         }
127 }
128
129 static CPUReadMemoryFunc *pic_read[] = {
130         NULL, NULL,
131         &pic_readl,
132 };
133
134 static CPUWriteMemoryFunc *pic_write[] = {
135         NULL, NULL,
136         &pic_writel,
137 };
138
139 void pic_info(Monitor *mon)
140 {
141 }
142
143 void irq_info(Monitor *mon)
144 {
145 }
146
147 static void irq_handler(void *opaque, int irq, int level)
148 {       
149         struct fs_pic_state_t *fs = (void *)opaque;
150
151         D(printf("%s irq=%d level=%d mask=%x v=%x mv=%x\n", 
152                  __func__, irq, level,
153                  fs->rw_mask, fs->r_vect, fs->r_masked_vect));
154
155         irq -= 1;
156         fs->r_vect &= ~(1 << irq);
157         fs->r_vect |= (!!level << irq);
158
159         pic_update(fs);
160 }
161
162 static void nmi_handler(void *opaque, int irq, int level)
163 {       
164         struct fs_pic_state_t *fs = (void *)opaque;
165         CPUState *env = fs->env;
166         uint32_t mask;
167
168         mask = 1 << irq;
169         if (level)
170                 fs->r_nmi |= mask;
171         else
172                 fs->r_nmi &= ~mask;
173
174         if (fs->r_nmi)
175                 cpu_interrupt(env, CPU_INTERRUPT_NMI);
176         else
177                 cpu_reset_interrupt(env, CPU_INTERRUPT_NMI);
178 }
179
180 static void guru_handler(void *opaque, int irq, int level)
181 {       
182         struct fs_pic_state_t *fs = (void *)opaque;
183         CPUState *env = fs->env;
184         cpu_abort(env, "%s unsupported exception\n", __func__);
185
186 }
187
188 struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base)
189 {
190         struct fs_pic_state_t *fs = NULL;
191         struct etraxfs_pic *pic = NULL;
192         int intr_vect_regs;
193
194         pic = qemu_mallocz(sizeof *pic);
195         pic->internal = fs = qemu_mallocz(sizeof *fs);
196
197         fs->env = env;
198         pic->irq = qemu_allocate_irqs(irq_handler, fs, 30);
199         pic->nmi = qemu_allocate_irqs(nmi_handler, fs, 2);
200         pic->guru = qemu_allocate_irqs(guru_handler, fs, 1);
201
202         intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs);
203         cpu_register_physical_memory(base, 0x14, intr_vect_regs);
204
205         return pic;
206 }