Statistics
| Branch: | Revision:

root / hw / etraxfs_pic.c @ 8109b9b6

History | View | Annotate | Download (5.5 kB)

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