Statistics
| Branch: | Revision:

root / hw / etraxfs_pic.c @ d9f75a4e

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