Statistics
| Branch: | Revision:

root / hw / slavio_intctl.c @ 6bae7071

History | View | Annotate | Download (7.8 kB)

1
/*
2
 * QEMU Sparc SLAVIO interrupt controller emulation
3
 * 
4
 * Copyright (c) 2003-2004 Fabrice Bellard
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
#include "vl.h"
25
//#define DEBUG_IRQ_COUNT
26

    
27
/*
28
 * Registers of interrupt controller in sun4m.
29
 *
30
 * This is the interrupt controller part of chip STP2001 (Slave I/O), also
31
 * produced as NCR89C105. See
32
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
33
 *
34
 * There is a system master controller and one for each cpu.
35
 * 
36
 */
37

    
38
#define MAX_CPUS 16
39

    
40
typedef struct SLAVIO_INTCTLState {
41
    uint32_t intreg_pending[MAX_CPUS];
42
    uint32_t intregm_pending;
43
    uint32_t intregm_disabled;
44
    uint32_t target_cpu;
45
#ifdef DEBUG_IRQ_COUNT
46
    uint64_t irq_count[32];
47
#endif
48
} SLAVIO_INTCTLState;
49

    
50
#define INTCTL_MAXADDR 0xf
51
#define INTCTLM_MAXADDR 0xf
52

    
53
// per-cpu interrupt controller
54
static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
55
{
56
    SLAVIO_INTCTLState *s = opaque;
57
    uint32_t saddr;
58
    int cpu;
59

    
60
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
61
    saddr = (addr & INTCTL_MAXADDR) >> 2;
62
    switch (saddr) {
63
    case 0:
64
        return s->intreg_pending[cpu];
65
    default:
66
        break;
67
    }
68
    return 0;
69
}
70

    
71
static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
72
{
73
    SLAVIO_INTCTLState *s = opaque;
74
    uint32_t saddr;
75
    int cpu;
76

    
77
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
78
    saddr = (addr & INTCTL_MAXADDR) >> 2;
79
    switch (saddr) {
80
    case 1: // clear pending softints
81
        if (val & 0x4000)
82
            val |= 80000000;
83
        val &= 0xfffe0000;
84
        s->intreg_pending[cpu] &= ~val;
85
        break;
86
    case 2: // set softint
87
        val &= 0xfffe0000;
88
        s->intreg_pending[cpu] |= val;
89
        break;
90
    default:
91
        break;
92
    }
93
}
94

    
95
static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
96
    slavio_intctl_mem_readl,
97
    slavio_intctl_mem_readl,
98
    slavio_intctl_mem_readl,
99
};
100

    
101
static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
102
    slavio_intctl_mem_writel,
103
    slavio_intctl_mem_writel,
104
    slavio_intctl_mem_writel,
105
};
106

    
107
// master system interrupt controller
108
static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
109
{
110
    SLAVIO_INTCTLState *s = opaque;
111
    uint32_t saddr;
112

    
113
    saddr = (addr & INTCTLM_MAXADDR) >> 2;
114
    switch (saddr) {
115
    case 0:
116
        return s->intregm_pending & 0x7fffffff;
117
    case 1:
118
        return s->intregm_disabled;
119
    case 4:
120
        return s->target_cpu;
121
    default:
122
        break;
123
    }
124
    return 0;
125
}
126

    
127
static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
128
{
129
    SLAVIO_INTCTLState *s = opaque;
130
    uint32_t saddr;
131

    
132
    saddr = (addr & INTCTLM_MAXADDR) >> 2;
133
    switch (saddr) {
134
    case 2: // clear (enable)
135
        // Force clear unused bits
136
        val &= ~0x7fb2007f;
137
        s->intregm_disabled &= ~val;
138
        break;
139
    case 3: // set (disable, clear pending)
140
        // Force clear unused bits
141
        val &= ~0x7fb2007f;
142
        s->intregm_disabled |= val;
143
        s->intregm_pending &= ~val;
144
        break;
145
    case 4:
146
        s->target_cpu = val & (MAX_CPUS - 1);
147
        break;
148
    default:
149
        break;
150
    }
151
}
152

    
153
static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
154
    slavio_intctlm_mem_readl,
155
    slavio_intctlm_mem_readl,
156
    slavio_intctlm_mem_readl,
157
};
158

    
159
static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
160
    slavio_intctlm_mem_writel,
161
    slavio_intctlm_mem_writel,
162
    slavio_intctlm_mem_writel,
163
};
164

    
165
void slavio_pic_info(void *opaque)
166
{
167
    SLAVIO_INTCTLState *s = opaque;
168
    int i;
169

    
170
    for (i = 0; i < MAX_CPUS; i++) {
171
        term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
172
    }
173
    term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
174
}
175

    
176
void slavio_irq_info(void *opaque)
177
{
178
#ifndef DEBUG_IRQ_COUNT
179
    term_printf("irq statistic code not compiled.\n");
180
#else
181
    SLAVIO_INTCTLState *s = opaque;
182
    int i;
183
    int64_t count;
184

    
185
    term_printf("IRQ statistics:\n");
186
    for (i = 0; i < 32; i++) {
187
        count = s->irq_count[i];
188
        if (count > 0)
189
            term_printf("%2d: %lld\n", i, count);
190
    }
191
#endif
192
}
193

    
194
static const uint32_t intbit_to_level[32] = {
195
    2, 3, 5, 7, 9, 11, 0, 14,        3, 5, 7, 9, 11, 13, 12, 12,
196
    6, 0, 4, 10, 8, 0, 11, 0,        0, 0, 0, 0, 15, 0, 0, 0,
197
};
198

    
199
/*
200
 * "irq" here is the bit number in the system interrupt register to
201
 * separate serial and keyboard interrupts sharing a level.
202
 */
203
void slavio_pic_set_irq(void *opaque, int irq, int level)
204
{
205
    SLAVIO_INTCTLState *s = opaque;
206

    
207
    if (irq < 32) {
208
        uint32_t mask = 1 << irq;
209
        uint32_t pil = intbit_to_level[irq];
210
        if (pil > 0) {
211
            if (level) {
212
                s->intregm_pending |= mask;
213
                s->intreg_pending[s->target_cpu] |= 1 << pil;
214
            }
215
            else {
216
                s->intregm_pending &= ~mask;
217
                s->intreg_pending[s->target_cpu] &= ~(1 << pil);
218
            }
219
            if (level &&
220
                !(s->intregm_disabled & mask) &&
221
                !(s->intregm_disabled & 0x80000000) &&
222
                (pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) {
223
#ifdef DEBUG_IRQ_COUNT
224
                if (level == 1)
225
                    s->irq_count[pil]++;
226
#endif
227
                cpu_single_env->interrupt_index = TT_EXTINT | pil;
228
                cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
229
            }
230
        }
231
    }
232
}
233

    
234
static void slavio_intctl_save(QEMUFile *f, void *opaque)
235
{
236
    SLAVIO_INTCTLState *s = opaque;
237
    int i;
238
    
239
    for (i = 0; i < MAX_CPUS; i++) {
240
        qemu_put_be32s(f, &s->intreg_pending[i]);
241
    }
242
    qemu_put_be32s(f, &s->intregm_pending);
243
    qemu_put_be32s(f, &s->intregm_disabled);
244
    qemu_put_be32s(f, &s->target_cpu);
245
}
246

    
247
static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
248
{
249
    SLAVIO_INTCTLState *s = opaque;
250
    int i;
251

    
252
    if (version_id != 1)
253
        return -EINVAL;
254

    
255
    for (i = 0; i < MAX_CPUS; i++) {
256
        qemu_get_be32s(f, &s->intreg_pending[i]);
257
    }
258
    qemu_get_be32s(f, &s->intregm_pending);
259
    qemu_get_be32s(f, &s->intregm_disabled);
260
    qemu_get_be32s(f, &s->target_cpu);
261
    return 0;
262
}
263

    
264
static void slavio_intctl_reset(void *opaque)
265
{
266
    SLAVIO_INTCTLState *s = opaque;
267
    int i;
268

    
269
    for (i = 0; i < MAX_CPUS; i++) {
270
        s->intreg_pending[i] = 0;
271
    }
272
    s->intregm_disabled = ~0xffb2007f;
273
    s->intregm_pending = 0;
274
    s->target_cpu = 0;
275
}
276

    
277
void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
278
{
279
    int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
280
    SLAVIO_INTCTLState *s;
281

    
282
    s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
283
    if (!s)
284
        return NULL;
285

    
286
    for (i = 0; i < MAX_CPUS; i++) {
287
        slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
288
        cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
289
    }
290

    
291
    slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
292
    cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
293

    
294
    register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
295
    qemu_register_reset(slavio_intctl_reset, s);
296
    slavio_intctl_reset(s);
297
    return s;
298
}
299