Statistics
| Branch: | Revision:

root / hw / etraxfs_pic.c @ 5ef98b47

History | View | Annotate | Download (5.5 kB)

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 "etraxfs.h"
28

    
29
#define D(x)
30

    
31
struct fs_pic_state_t
32
{
33
        CPUState *env;
34
        target_phys_addr_t base;
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 uint32_t pic_readb (void *opaque, target_phys_addr_t addr)
46
{
47
        return 0;
48
}
49
static uint32_t pic_readw (void *opaque, target_phys_addr_t addr)
50
{
51
        return 0;
52
}
53

    
54
static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
55
{
56
        struct fs_pic_state_t *fs = opaque;
57
        uint32_t rval;
58

    
59
        /* Transform this to a relative addr.  */
60
        addr -= fs->base;
61
        switch (addr)
62
        {
63
                case 0x0: 
64
                        rval = fs->rw_mask;
65
                        break;
66
                case 0x4: 
67
                        rval = fs->r_vect;
68
                        break;
69
                case 0x8: 
70
                        rval = fs->r_masked_vect;
71
                        break;
72
                case 0xc: 
73
                        rval = fs->r_nmi;
74
                        break;
75
                case 0x10: 
76
                        rval = fs->r_guru;
77
                        break;
78
                default:
79
                        cpu_abort(fs->env, "invalid PIC register.\n");
80
                        break;
81

    
82
        }
83
        D(printf("%s %x=%x\n", __func__, addr, rval));
84
        return rval;
85
}
86

    
87
static void
88
pic_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
89
{
90
}
91

    
92
static void
93
pic_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
94
{
95
}
96

    
97
static void
98
pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
99
{
100
        struct fs_pic_state_t *fs = opaque;
101
        D(printf("%s addr=%x val=%x\n", __func__, addr, value));
102
        /* Transform this to a relative addr.  */
103
        addr -= fs->base;
104
        switch (addr) 
105
        {
106
                case 0x0: 
107
                        fs->rw_mask = value;
108
                        break;
109
                case 0x4: 
110
                        fs->r_vect = value;
111
                        break;
112
                case 0x8: 
113
                        fs->r_masked_vect = value;
114
                        break;
115
                case 0xc: 
116
                        fs->r_nmi = value;
117
                        break;
118
                case 0x10: 
119
                        fs->r_guru = value;
120
                        break;
121
                default:
122
                        cpu_abort(fs->env, "invalid PIC register.\n");
123
                        break;
124
        }
125
}
126

    
127
static CPUReadMemoryFunc *pic_read[] = {
128
        &pic_readb,
129
        &pic_readw,
130
        &pic_readl,
131
};
132

    
133
static CPUWriteMemoryFunc *pic_write[] = {
134
        &pic_writeb,
135
        &pic_writew,
136
        &pic_writel,
137
};
138

    
139
void pic_info(void)
140
{
141
}
142

    
143
void irq_info(void)
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
        CPUState *env = fs->env;
151
        int i;
152
        uint32_t vector = 0;
153

    
154
        D(printf("%s irq=%d level=%d mask=%x v=%x mv=%x\n", 
155
                 __func__, irq, level,
156
                 fs->rw_mask, fs->r_vect, fs->r_masked_vect));
157

    
158
        irq -= 1;
159
        fs->r_vect &= ~(1 << irq);
160
        fs->r_vect |= (!!level << irq);
161
        fs->r_masked_vect = fs->r_vect & fs->rw_mask;
162

    
163
        /* The ETRAX interrupt controller signals interrupts to teh core
164
           through an interrupt request wire and an irq vector bus. If 
165
           multiple interrupts are simultaneously active it chooses vector 
166
           0x30 and lets the sw choose the priorities.  */
167
        if (fs->r_masked_vect) {
168
                uint32_t mv = fs->r_masked_vect;
169
                for (i = 0; i < 31; i++) {
170
                        if (mv & 1) {
171
                                vector = 0x31 + i;
172
                                /* Check for multiple interrupts.  */
173
                                if (mv > 1)
174
                                        vector = 0x30;
175
                                break;
176
                        }
177
                        mv >>= 1;
178
                }
179
                if (vector) {
180
                        env->interrupt_vector = vector;
181
                        D(printf("%s vector=%x\n", __func__, vector));
182
                        cpu_interrupt(env, CPU_INTERRUPT_HARD);
183
                }
184
        } else {
185
                env->interrupt_vector = 0;
186
                cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
187
                D(printf("%s reset irqs\n", __func__));
188
        }
189
}
190

    
191
static void nmi_handler(void *opaque, int irq, int level)
192
{        
193
        struct fs_pic_state_t *fs = (void *)opaque;
194
        CPUState *env = fs->env;
195
        uint32_t mask;
196

    
197
        mask = 1 << irq;
198
        if (level)
199
                fs->r_nmi |= mask;
200
        else
201
                fs->r_nmi &= ~mask;
202

    
203
        if (fs->r_nmi)
204
                cpu_interrupt(env, CPU_INTERRUPT_NMI);
205
        else
206
                cpu_reset_interrupt(env, CPU_INTERRUPT_NMI);
207
}
208

    
209
static void guru_handler(void *opaque, int irq, int level)
210
{        
211
        struct fs_pic_state_t *fs = (void *)opaque;
212
        CPUState *env = fs->env;
213
        cpu_abort(env, "%s unsupported exception\n", __func__);
214

    
215
}
216

    
217

    
218
struct etraxfs_pic *etraxfs_pic_init(CPUState *env, target_phys_addr_t base)
219
{
220
        struct fs_pic_state_t *fs = NULL;
221
        struct etraxfs_pic *pic = NULL;
222
        int intr_vect_regs;
223

    
224
        pic = qemu_mallocz(sizeof *pic);
225
        pic->internal = fs = qemu_mallocz(sizeof *fs);
226
        if (!fs || !pic)
227
                goto err;
228

    
229
        fs->env = env;
230
        pic->irq = qemu_allocate_irqs(irq_handler, fs, 30);
231
        pic->nmi = qemu_allocate_irqs(nmi_handler, fs, 2);
232
        pic->guru = qemu_allocate_irqs(guru_handler, fs, 1);
233

    
234
        intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, fs);
235
        cpu_register_physical_memory(base, 0x14, intr_vect_regs);
236
        fs->base = base;
237

    
238
        return pic;
239
  err:
240
        free(pic);
241
        free(fs);
242
        return NULL;
243
}