Statistics
| Branch: | Revision:

root / hw / etraxfs_pic.c @ e0dd114c

History | View | Annotate | Download (4.9 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 e62b5b13 edgar_igl
35 e62b5b13 edgar_igl
        uint32_t rw_mask;
36 e62b5b13 edgar_igl
        /* Active interrupt lines.  */
37 e62b5b13 edgar_igl
        uint32_t r_vect;
38 e62b5b13 edgar_igl
        /* Active lines, gated through the mask.  */
39 e62b5b13 edgar_igl
        uint32_t r_masked_vect;
40 e62b5b13 edgar_igl
        uint32_t r_nmi;
41 e62b5b13 edgar_igl
        uint32_t r_guru;
42 e62b5b13 edgar_igl
};
43 e62b5b13 edgar_igl
44 70ea255d edgar_igl
static void pic_update(struct fs_pic_state_t *fs)
45 70ea255d edgar_igl
{        
46 70ea255d edgar_igl
        CPUState *env = fs->env;
47 70ea255d edgar_igl
        int i;
48 70ea255d edgar_igl
        uint32_t vector = 0;
49 70ea255d edgar_igl
50 70ea255d edgar_igl
        fs->r_masked_vect = fs->r_vect & fs->rw_mask;
51 70ea255d edgar_igl
52 70ea255d edgar_igl
        /* The ETRAX interrupt controller signals interrupts to teh core
53 70ea255d edgar_igl
           through an interrupt request wire and an irq vector bus. If 
54 70ea255d edgar_igl
           multiple interrupts are simultaneously active it chooses vector 
55 70ea255d edgar_igl
           0x30 and lets the sw choose the priorities.  */
56 70ea255d edgar_igl
        if (fs->r_masked_vect) {
57 70ea255d edgar_igl
                uint32_t mv = fs->r_masked_vect;
58 70ea255d edgar_igl
                for (i = 0; i < 31; i++) {
59 70ea255d edgar_igl
                        if (mv & 1) {
60 70ea255d edgar_igl
                                vector = 0x31 + i;
61 70ea255d edgar_igl
                                /* Check for multiple interrupts.  */
62 70ea255d edgar_igl
                                if (mv > 1)
63 70ea255d edgar_igl
                                        vector = 0x30;
64 70ea255d edgar_igl
                                break;
65 70ea255d edgar_igl
                        }
66 70ea255d edgar_igl
                        mv >>= 1;
67 70ea255d edgar_igl
                }
68 70ea255d edgar_igl
                if (vector) {
69 70ea255d edgar_igl
                        env->interrupt_vector = vector;
70 70ea255d edgar_igl
                        D(printf("%s vector=%x\n", __func__, vector));
71 70ea255d edgar_igl
                        cpu_interrupt(env, CPU_INTERRUPT_HARD);
72 70ea255d edgar_igl
                }
73 70ea255d edgar_igl
        } else {
74 70ea255d edgar_igl
                env->interrupt_vector = 0;
75 70ea255d edgar_igl
                cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
76 70ea255d edgar_igl
                D(printf("%s reset irqs\n", __func__));
77 70ea255d edgar_igl
        }
78 e62b5b13 edgar_igl
}
79 e62b5b13 edgar_igl
80 e62b5b13 edgar_igl
static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
81 e62b5b13 edgar_igl
{
82 e62b5b13 edgar_igl
        struct fs_pic_state_t *fs = opaque;
83 e62b5b13 edgar_igl
        uint32_t rval;
84 e62b5b13 edgar_igl
85 e62b5b13 edgar_igl
        switch (addr)
86 e62b5b13 edgar_igl
        {
87 e62b5b13 edgar_igl
                case 0x0: 
88 e62b5b13 edgar_igl
                        rval = fs->rw_mask;
89 e62b5b13 edgar_igl
                        break;
90 e62b5b13 edgar_igl
                case 0x4: 
91 e62b5b13 edgar_igl
                        rval = fs->r_vect;
92 e62b5b13 edgar_igl
                        break;
93 e62b5b13 edgar_igl
                case 0x8: 
94 e62b5b13 edgar_igl
                        rval = fs->r_masked_vect;
95 e62b5b13 edgar_igl
                        break;
96 e62b5b13 edgar_igl
                case 0xc: 
97 e62b5b13 edgar_igl
                        rval = fs->r_nmi;
98 e62b5b13 edgar_igl
                        break;
99 e62b5b13 edgar_igl
                case 0x10: 
100 e62b5b13 edgar_igl
                        rval = fs->r_guru;
101 e62b5b13 edgar_igl
                        break;
102 e62b5b13 edgar_igl
                default:
103 e62b5b13 edgar_igl
                        cpu_abort(fs->env, "invalid PIC register.\n");
104 e62b5b13 edgar_igl
                        break;
105 e62b5b13 edgar_igl
106 e62b5b13 edgar_igl
        }
107 e62b5b13 edgar_igl
        D(printf("%s %x=%x\n", __func__, addr, rval));
108 e62b5b13 edgar_igl
        return rval;
109 e62b5b13 edgar_igl
}
110 e62b5b13 edgar_igl
111 e62b5b13 edgar_igl
static void
112 e62b5b13 edgar_igl
pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
113 e62b5b13 edgar_igl
{
114 e62b5b13 edgar_igl
        struct fs_pic_state_t *fs = opaque;
115 e62b5b13 edgar_igl
        D(printf("%s addr=%x val=%x\n", __func__, addr, value));
116 e62b5b13 edgar_igl
        switch (addr) 
117 e62b5b13 edgar_igl
        {
118 e62b5b13 edgar_igl
                case 0x0: 
119 e62b5b13 edgar_igl
                        fs->rw_mask = value;
120 70ea255d edgar_igl
                        pic_update(fs);
121 e62b5b13 edgar_igl
                        break;
122 e62b5b13 edgar_igl
                default:
123 e62b5b13 edgar_igl
                        cpu_abort(fs->env, "invalid PIC register.\n");
124 e62b5b13 edgar_igl
                        break;
125 e62b5b13 edgar_igl
        }
126 e62b5b13 edgar_igl
}
127 e62b5b13 edgar_igl
128 e62b5b13 edgar_igl
static CPUReadMemoryFunc *pic_read[] = {
129 70ea255d edgar_igl
        NULL, NULL,
130 e62b5b13 edgar_igl
        &pic_readl,
131 e62b5b13 edgar_igl
};
132 e62b5b13 edgar_igl
133 e62b5b13 edgar_igl
static CPUWriteMemoryFunc *pic_write[] = {
134 70ea255d edgar_igl
        NULL, NULL,
135 e62b5b13 edgar_igl
        &pic_writel,
136 e62b5b13 edgar_igl
};
137 e62b5b13 edgar_igl
138 e62b5b13 edgar_igl
void pic_info(void)
139 e62b5b13 edgar_igl
{
140 e62b5b13 edgar_igl
}
141 e62b5b13 edgar_igl
142 e62b5b13 edgar_igl
void irq_info(void)
143 e62b5b13 edgar_igl
{
144 e62b5b13 edgar_igl
}
145 e62b5b13 edgar_igl
146 5ef98b47 edgar_igl
static void irq_handler(void *opaque, int irq, int level)
147 e62b5b13 edgar_igl
{        
148 e62b5b13 edgar_igl
        struct fs_pic_state_t *fs = (void *)opaque;
149 e62b5b13 edgar_igl
150 e62b5b13 edgar_igl
        D(printf("%s irq=%d level=%d mask=%x v=%x mv=%x\n", 
151 e62b5b13 edgar_igl
                 __func__, irq, level,
152 e62b5b13 edgar_igl
                 fs->rw_mask, fs->r_vect, fs->r_masked_vect));
153 e62b5b13 edgar_igl
154 48318011 edgar_igl
        irq -= 1;
155 e62b5b13 edgar_igl
        fs->r_vect &= ~(1 << irq);
156 e62b5b13 edgar_igl
        fs->r_vect |= (!!level << irq);
157 e62b5b13 edgar_igl
158 70ea255d edgar_igl
        pic_update(fs);
159 e62b5b13 edgar_igl
}
160 e62b5b13 edgar_igl
161 5ef98b47 edgar_igl
static void nmi_handler(void *opaque, int irq, int level)
162 5ef98b47 edgar_igl
{        
163 5ef98b47 edgar_igl
        struct fs_pic_state_t *fs = (void *)opaque;
164 5ef98b47 edgar_igl
        CPUState *env = fs->env;
165 5ef98b47 edgar_igl
        uint32_t mask;
166 5ef98b47 edgar_igl
167 5ef98b47 edgar_igl
        mask = 1 << irq;
168 5ef98b47 edgar_igl
        if (level)
169 5ef98b47 edgar_igl
                fs->r_nmi |= mask;
170 5ef98b47 edgar_igl
        else
171 5ef98b47 edgar_igl
                fs->r_nmi &= ~mask;
172 5ef98b47 edgar_igl
173 5ef98b47 edgar_igl
        if (fs->r_nmi)
174 5ef98b47 edgar_igl
                cpu_interrupt(env, CPU_INTERRUPT_NMI);
175 5ef98b47 edgar_igl
        else
176 5ef98b47 edgar_igl
                cpu_reset_interrupt(env, CPU_INTERRUPT_NMI);
177 5ef98b47 edgar_igl
}
178 5ef98b47 edgar_igl
179 5ef98b47 edgar_igl
static void guru_handler(void *opaque, int irq, int level)
180 5ef98b47 edgar_igl
{        
181 5ef98b47 edgar_igl
        struct fs_pic_state_t *fs = (void *)opaque;
182 5ef98b47 edgar_igl
        CPUState *env = fs->env;
183 5ef98b47 edgar_igl
        cpu_abort(env, "%s unsupported exception\n", __func__);
184 5ef98b47 edgar_igl
185 5ef98b47 edgar_igl
}
186 5ef98b47 edgar_igl
187 5ef98b47 edgar_igl
struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base)
188 e62b5b13 edgar_igl
{
189 5ef98b47 edgar_igl
        struct fs_pic_state_t *fs = NULL;
190 5ef98b47 edgar_igl
        struct etraxfs_pic *pic = NULL;
191 e62b5b13 edgar_igl
        int intr_vect_regs;
192 e62b5b13 edgar_igl
193 5ef98b47 edgar_igl
        pic = qemu_mallocz(sizeof *pic);
194 5ef98b47 edgar_igl
        pic->internal = fs = qemu_mallocz(sizeof *fs);
195 5ef98b47 edgar_igl
        if (!fs || !pic)
196 5ef98b47 edgar_igl
                goto err;
197 e62b5b13 edgar_igl
198 5ef98b47 edgar_igl
        fs->env = env;
199 5ef98b47 edgar_igl
        pic->irq = qemu_allocate_irqs(irq_handler, fs, 30);
200 5ef98b47 edgar_igl
        pic->nmi = qemu_allocate_irqs(nmi_handler, fs, 2);
201 5ef98b47 edgar_igl
        pic->guru = qemu_allocate_irqs(guru_handler, fs, 1);
202 e62b5b13 edgar_igl
203 e62b5b13 edgar_igl
        intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs);
204 e62b5b13 edgar_igl
        cpu_register_physical_memory(base, 0x14, intr_vect_regs);
205 e62b5b13 edgar_igl
206 e62b5b13 edgar_igl
        return pic;
207 5ef98b47 edgar_igl
  err:
208 5ef98b47 edgar_igl
        free(pic);
209 5ef98b47 edgar_igl
        free(fs);
210 5ef98b47 edgar_igl
        return NULL;
211 e62b5b13 edgar_igl
}