Statistics
| Branch: | Revision:

root / hw / i8259.c @ 0200db65

History | View | Annotate | Download (15.4 kB)

1 80cabfad bellard
/*
2 80cabfad bellard
 * QEMU 8259 interrupt controller emulation
3 5fafdf24 ths
 *
4 80cabfad bellard
 * Copyright (c) 2003-2004 Fabrice Bellard
5 5fafdf24 ths
 *
6 80cabfad bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 80cabfad bellard
 * of this software and associated documentation files (the "Software"), to deal
8 80cabfad bellard
 * in the Software without restriction, including without limitation the rights
9 80cabfad bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 80cabfad bellard
 * copies of the Software, and to permit persons to whom the Software is
11 80cabfad bellard
 * furnished to do so, subject to the following conditions:
12 80cabfad bellard
 *
13 80cabfad bellard
 * The above copyright notice and this permission notice shall be included in
14 80cabfad bellard
 * all copies or substantial portions of the Software.
15 80cabfad bellard
 *
16 80cabfad bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 80cabfad bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 80cabfad bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 80cabfad bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 80cabfad bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 80cabfad bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 80cabfad bellard
 * THE SOFTWARE.
23 80cabfad bellard
 */
24 87ecb68b pbrook
#include "hw.h"
25 87ecb68b pbrook
#include "pc.h"
26 87ecb68b pbrook
#include "isa.h"
27 376253ec aliguori
#include "monitor.h"
28 0bf9e31a Blue Swirl
#include "qemu-timer.h"
29 80cabfad bellard
30 80cabfad bellard
/* debug PIC */
31 80cabfad bellard
//#define DEBUG_PIC
32 80cabfad bellard
33 8ac02ff8 Blue Swirl
#ifdef DEBUG_PIC
34 8ac02ff8 Blue Swirl
#define DPRINTF(fmt, ...)                                       \
35 8ac02ff8 Blue Swirl
    do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
36 8ac02ff8 Blue Swirl
#else
37 8ac02ff8 Blue Swirl
#define DPRINTF(fmt, ...)
38 8ac02ff8 Blue Swirl
#endif
39 8ac02ff8 Blue Swirl
40 b41a2cd1 bellard
//#define DEBUG_IRQ_LATENCY
41 4a0fb71e bellard
//#define DEBUG_IRQ_COUNT
42 b41a2cd1 bellard
43 80cabfad bellard
typedef struct PicState {
44 80cabfad bellard
    uint8_t last_irr; /* edge detection */
45 80cabfad bellard
    uint8_t irr; /* interrupt request register */
46 80cabfad bellard
    uint8_t imr; /* interrupt mask register */
47 80cabfad bellard
    uint8_t isr; /* interrupt service register */
48 80cabfad bellard
    uint8_t priority_add; /* highest irq priority */
49 80cabfad bellard
    uint8_t irq_base;
50 80cabfad bellard
    uint8_t read_reg_select;
51 80cabfad bellard
    uint8_t poll;
52 80cabfad bellard
    uint8_t special_mask;
53 80cabfad bellard
    uint8_t init_state;
54 80cabfad bellard
    uint8_t auto_eoi;
55 80cabfad bellard
    uint8_t rotate_on_auto_eoi;
56 80cabfad bellard
    uint8_t special_fully_nested_mode;
57 80cabfad bellard
    uint8_t init4; /* true if 4 byte init */
58 2053152b ths
    uint8_t single_mode; /* true if slave pic is not initialized */
59 660de336 bellard
    uint8_t elcr; /* PIIX edge/trigger selection*/
60 660de336 bellard
    uint8_t elcr_mask;
61 3de388f6 bellard
    PicState2 *pics_state;
62 098d314a Richard Henderson
    MemoryRegion base_io;
63 098d314a Richard Henderson
    MemoryRegion elcr_io;
64 80cabfad bellard
} PicState;
65 80cabfad bellard
66 3de388f6 bellard
struct PicState2 {
67 3de388f6 bellard
    /* 0 is master pic, 1 is slave pic */
68 3de388f6 bellard
    /* XXX: better separation between the two pics */
69 3de388f6 bellard
    PicState pics[2];
70 d537cf6c pbrook
    qemu_irq parent_irq;
71 3de388f6 bellard
    void *irq_request_opaque;
72 3de388f6 bellard
};
73 80cabfad bellard
74 4a0fb71e bellard
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
75 4a0fb71e bellard
static int irq_level[16];
76 4a0fb71e bellard
#endif
77 4a0fb71e bellard
#ifdef DEBUG_IRQ_COUNT
78 4a0fb71e bellard
static uint64_t irq_count[16];
79 4a0fb71e bellard
#endif
80 fbe3288d Paolo Bonzini
PicState2 *isa_pic;
81 4a0fb71e bellard
82 80cabfad bellard
/* set irq level. If an edge is detected, then the IRR is set to 1 */
83 80cabfad bellard
static inline void pic_set_irq1(PicState *s, int irq, int level)
84 80cabfad bellard
{
85 80cabfad bellard
    int mask;
86 80cabfad bellard
    mask = 1 << irq;
87 660de336 bellard
    if (s->elcr & mask) {
88 660de336 bellard
        /* level triggered */
89 660de336 bellard
        if (level) {
90 80cabfad bellard
            s->irr |= mask;
91 660de336 bellard
            s->last_irr |= mask;
92 660de336 bellard
        } else {
93 660de336 bellard
            s->irr &= ~mask;
94 660de336 bellard
            s->last_irr &= ~mask;
95 660de336 bellard
        }
96 80cabfad bellard
    } else {
97 660de336 bellard
        /* edge triggered */
98 660de336 bellard
        if (level) {
99 660de336 bellard
            if ((s->last_irr & mask) == 0)
100 660de336 bellard
                s->irr |= mask;
101 660de336 bellard
            s->last_irr |= mask;
102 660de336 bellard
        } else {
103 660de336 bellard
            s->last_irr &= ~mask;
104 660de336 bellard
        }
105 80cabfad bellard
    }
106 80cabfad bellard
}
107 80cabfad bellard
108 80cabfad bellard
/* return the highest priority found in mask (highest = smallest
109 80cabfad bellard
   number). Return 8 if no irq */
110 80cabfad bellard
static inline int get_priority(PicState *s, int mask)
111 80cabfad bellard
{
112 80cabfad bellard
    int priority;
113 80cabfad bellard
    if (mask == 0)
114 80cabfad bellard
        return 8;
115 80cabfad bellard
    priority = 0;
116 80cabfad bellard
    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
117 80cabfad bellard
        priority++;
118 80cabfad bellard
    return priority;
119 80cabfad bellard
}
120 80cabfad bellard
121 80cabfad bellard
/* return the pic wanted interrupt. return -1 if none */
122 80cabfad bellard
static int pic_get_irq(PicState *s)
123 80cabfad bellard
{
124 80cabfad bellard
    int mask, cur_priority, priority;
125 80cabfad bellard
126 80cabfad bellard
    mask = s->irr & ~s->imr;
127 80cabfad bellard
    priority = get_priority(s, mask);
128 80cabfad bellard
    if (priority == 8)
129 80cabfad bellard
        return -1;
130 80cabfad bellard
    /* compute current priority. If special fully nested mode on the
131 80cabfad bellard
       master, the IRQ coming from the slave is not taken into account
132 80cabfad bellard
       for the priority computation. */
133 80cabfad bellard
    mask = s->isr;
134 84678711 balrog
    if (s->special_mask)
135 84678711 balrog
        mask &= ~s->imr;
136 3de388f6 bellard
    if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
137 80cabfad bellard
        mask &= ~(1 << 2);
138 80cabfad bellard
    cur_priority = get_priority(s, mask);
139 80cabfad bellard
    if (priority < cur_priority) {
140 80cabfad bellard
        /* higher priority found: an irq should be generated */
141 80cabfad bellard
        return (priority + s->priority_add) & 7;
142 80cabfad bellard
    } else {
143 80cabfad bellard
        return -1;
144 80cabfad bellard
    }
145 80cabfad bellard
}
146 80cabfad bellard
147 80cabfad bellard
/* raise irq to CPU if necessary. must be called every time the active
148 80cabfad bellard
   irq may change */
149 3de388f6 bellard
/* XXX: should not export it, but it is needed for an APIC kludge */
150 3de388f6 bellard
void pic_update_irq(PicState2 *s)
151 80cabfad bellard
{
152 80cabfad bellard
    int irq2, irq;
153 80cabfad bellard
154 80cabfad bellard
    /* first look at slave pic */
155 3de388f6 bellard
    irq2 = pic_get_irq(&s->pics[1]);
156 80cabfad bellard
    if (irq2 >= 0) {
157 80cabfad bellard
        /* if irq request by slave pic, signal master PIC */
158 3de388f6 bellard
        pic_set_irq1(&s->pics[0], 2, 1);
159 3de388f6 bellard
        pic_set_irq1(&s->pics[0], 2, 0);
160 80cabfad bellard
    }
161 80cabfad bellard
    /* look at requested irq */
162 3de388f6 bellard
    irq = pic_get_irq(&s->pics[0]);
163 80cabfad bellard
    if (irq >= 0) {
164 80cabfad bellard
#if defined(DEBUG_PIC)
165 80cabfad bellard
        {
166 80cabfad bellard
            int i;
167 80cabfad bellard
            for(i = 0; i < 2; i++) {
168 5fafdf24 ths
                printf("pic%d: imr=%x irr=%x padd=%d\n",
169 5fafdf24 ths
                       i, s->pics[i].imr, s->pics[i].irr,
170 3de388f6 bellard
                       s->pics[i].priority_add);
171 3b46e624 ths
172 80cabfad bellard
            }
173 80cabfad bellard
        }
174 2444ca41 bellard
        printf("pic: cpu_interrupt\n");
175 80cabfad bellard
#endif
176 d537cf6c pbrook
        qemu_irq_raise(s->parent_irq);
177 80cabfad bellard
    }
178 4de9b249 ths
179 4de9b249 ths
/* all targets should do this rather than acking the IRQ in the cpu */
180 29463b24 aurel32
#if defined(TARGET_MIPS) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
181 4de9b249 ths
    else {
182 d537cf6c pbrook
        qemu_irq_lower(s->parent_irq);
183 4de9b249 ths
    }
184 4de9b249 ths
#endif
185 80cabfad bellard
}
186 80cabfad bellard
187 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
188 80cabfad bellard
int64_t irq_time[16];
189 80cabfad bellard
#endif
190 80cabfad bellard
191 9596ebb7 pbrook
static void i8259_set_irq(void *opaque, int irq, int level)
192 80cabfad bellard
{
193 3de388f6 bellard
    PicState2 *s = opaque;
194 3de388f6 bellard
195 4a0fb71e bellard
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
196 80cabfad bellard
    if (level != irq_level[irq]) {
197 8ac02ff8 Blue Swirl
        DPRINTF("i8259_set_irq: irq=%d level=%d\n", irq, level);
198 80cabfad bellard
        irq_level[irq] = level;
199 4a0fb71e bellard
#ifdef DEBUG_IRQ_COUNT
200 4a0fb71e bellard
        if (level == 1)
201 4a0fb71e bellard
            irq_count[irq]++;
202 4a0fb71e bellard
#endif
203 80cabfad bellard
    }
204 80cabfad bellard
#endif
205 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
206 80cabfad bellard
    if (level) {
207 74475455 Paolo Bonzini
        irq_time[irq] = qemu_get_clock_ns(vm_clock);
208 80cabfad bellard
    }
209 80cabfad bellard
#endif
210 3de388f6 bellard
    pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
211 3de388f6 bellard
    pic_update_irq(s);
212 80cabfad bellard
}
213 80cabfad bellard
214 80cabfad bellard
/* acknowledge interrupt 'irq' */
215 80cabfad bellard
static inline void pic_intack(PicState *s, int irq)
216 80cabfad bellard
{
217 80cabfad bellard
    if (s->auto_eoi) {
218 80cabfad bellard
        if (s->rotate_on_auto_eoi)
219 80cabfad bellard
            s->priority_add = (irq + 1) & 7;
220 80cabfad bellard
    } else {
221 80cabfad bellard
        s->isr |= (1 << irq);
222 80cabfad bellard
    }
223 0ecf89aa bellard
    /* We don't clear a level sensitive interrupt here */
224 0ecf89aa bellard
    if (!(s->elcr & (1 << irq)))
225 0ecf89aa bellard
        s->irr &= ~(1 << irq);
226 80cabfad bellard
}
227 80cabfad bellard
228 3de388f6 bellard
int pic_read_irq(PicState2 *s)
229 80cabfad bellard
{
230 80cabfad bellard
    int irq, irq2, intno;
231 80cabfad bellard
232 3de388f6 bellard
    irq = pic_get_irq(&s->pics[0]);
233 15aeac38 bellard
    if (irq >= 0) {
234 3de388f6 bellard
        pic_intack(&s->pics[0], irq);
235 15aeac38 bellard
        if (irq == 2) {
236 3de388f6 bellard
            irq2 = pic_get_irq(&s->pics[1]);
237 15aeac38 bellard
            if (irq2 >= 0) {
238 3de388f6 bellard
                pic_intack(&s->pics[1], irq2);
239 15aeac38 bellard
            } else {
240 15aeac38 bellard
                /* spurious IRQ on slave controller */
241 15aeac38 bellard
                irq2 = 7;
242 15aeac38 bellard
            }
243 3de388f6 bellard
            intno = s->pics[1].irq_base + irq2;
244 7f5b7d3e Blue Swirl
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
245 15aeac38 bellard
            irq = irq2 + 8;
246 7f5b7d3e Blue Swirl
#endif
247 15aeac38 bellard
        } else {
248 3de388f6 bellard
            intno = s->pics[0].irq_base + irq;
249 15aeac38 bellard
        }
250 15aeac38 bellard
    } else {
251 15aeac38 bellard
        /* spurious IRQ on host controller */
252 15aeac38 bellard
        irq = 7;
253 3de388f6 bellard
        intno = s->pics[0].irq_base + irq;
254 15aeac38 bellard
    }
255 3de388f6 bellard
    pic_update_irq(s);
256 3b46e624 ths
257 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
258 5fafdf24 ths
    printf("IRQ%d latency=%0.3fus\n",
259 5fafdf24 ths
           irq,
260 74475455 Paolo Bonzini
           (double)(qemu_get_clock_ns(vm_clock) -
261 6ee093c9 Juan Quintela
                    irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
262 80cabfad bellard
#endif
263 8ac02ff8 Blue Swirl
    DPRINTF("pic_interrupt: irq=%d\n", irq);
264 80cabfad bellard
    return intno;
265 80cabfad bellard
}
266 80cabfad bellard
267 d7d02e3c bellard
static void pic_reset(void *opaque)
268 d7d02e3c bellard
{
269 d7d02e3c bellard
    PicState *s = opaque;
270 d7d02e3c bellard
271 3de388f6 bellard
    s->last_irr = 0;
272 3de388f6 bellard
    s->irr = 0;
273 3de388f6 bellard
    s->imr = 0;
274 3de388f6 bellard
    s->isr = 0;
275 3de388f6 bellard
    s->priority_add = 0;
276 3de388f6 bellard
    s->irq_base = 0;
277 3de388f6 bellard
    s->read_reg_select = 0;
278 3de388f6 bellard
    s->poll = 0;
279 3de388f6 bellard
    s->special_mask = 0;
280 3de388f6 bellard
    s->init_state = 0;
281 3de388f6 bellard
    s->auto_eoi = 0;
282 3de388f6 bellard
    s->rotate_on_auto_eoi = 0;
283 3de388f6 bellard
    s->special_fully_nested_mode = 0;
284 3de388f6 bellard
    s->init4 = 0;
285 2053152b ths
    s->single_mode = 0;
286 4dbe19e1 bellard
    /* Note: ELCR is not reset */
287 d7d02e3c bellard
}
288 d7d02e3c bellard
289 098d314a Richard Henderson
static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
290 098d314a Richard Henderson
                             uint64_t val64, unsigned size)
291 80cabfad bellard
{
292 b41a2cd1 bellard
    PicState *s = opaque;
293 098d314a Richard Henderson
    uint32_t addr = addr64;
294 098d314a Richard Henderson
    uint32_t val = val64;
295 d7d02e3c bellard
    int priority, cmd, irq;
296 80cabfad bellard
297 8ac02ff8 Blue Swirl
    DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
298 80cabfad bellard
    if (addr == 0) {
299 80cabfad bellard
        if (val & 0x10) {
300 80cabfad bellard
            /* init */
301 d7d02e3c bellard
            pic_reset(s);
302 b54ad049 bellard
            /* deassert a pending interrupt */
303 d537cf6c pbrook
            qemu_irq_lower(s->pics_state->parent_irq);
304 80cabfad bellard
            s->init_state = 1;
305 80cabfad bellard
            s->init4 = val & 1;
306 2053152b ths
            s->single_mode = val & 2;
307 80cabfad bellard
            if (val & 0x08)
308 80cabfad bellard
                hw_error("level sensitive irq not supported");
309 80cabfad bellard
        } else if (val & 0x08) {
310 80cabfad bellard
            if (val & 0x04)
311 80cabfad bellard
                s->poll = 1;
312 80cabfad bellard
            if (val & 0x02)
313 80cabfad bellard
                s->read_reg_select = val & 1;
314 80cabfad bellard
            if (val & 0x40)
315 80cabfad bellard
                s->special_mask = (val >> 5) & 1;
316 80cabfad bellard
        } else {
317 80cabfad bellard
            cmd = val >> 5;
318 80cabfad bellard
            switch(cmd) {
319 80cabfad bellard
            case 0:
320 80cabfad bellard
            case 4:
321 80cabfad bellard
                s->rotate_on_auto_eoi = cmd >> 2;
322 80cabfad bellard
                break;
323 80cabfad bellard
            case 1: /* end of interrupt */
324 80cabfad bellard
            case 5:
325 80cabfad bellard
                priority = get_priority(s, s->isr);
326 80cabfad bellard
                if (priority != 8) {
327 80cabfad bellard
                    irq = (priority + s->priority_add) & 7;
328 80cabfad bellard
                    s->isr &= ~(1 << irq);
329 80cabfad bellard
                    if (cmd == 5)
330 80cabfad bellard
                        s->priority_add = (irq + 1) & 7;
331 3de388f6 bellard
                    pic_update_irq(s->pics_state);
332 80cabfad bellard
                }
333 80cabfad bellard
                break;
334 80cabfad bellard
            case 3:
335 80cabfad bellard
                irq = val & 7;
336 80cabfad bellard
                s->isr &= ~(1 << irq);
337 3de388f6 bellard
                pic_update_irq(s->pics_state);
338 80cabfad bellard
                break;
339 80cabfad bellard
            case 6:
340 80cabfad bellard
                s->priority_add = (val + 1) & 7;
341 3de388f6 bellard
                pic_update_irq(s->pics_state);
342 80cabfad bellard
                break;
343 80cabfad bellard
            case 7:
344 80cabfad bellard
                irq = val & 7;
345 80cabfad bellard
                s->isr &= ~(1 << irq);
346 80cabfad bellard
                s->priority_add = (irq + 1) & 7;
347 3de388f6 bellard
                pic_update_irq(s->pics_state);
348 80cabfad bellard
                break;
349 80cabfad bellard
            default:
350 80cabfad bellard
                /* no operation */
351 80cabfad bellard
                break;
352 80cabfad bellard
            }
353 80cabfad bellard
        }
354 80cabfad bellard
    } else {
355 80cabfad bellard
        switch(s->init_state) {
356 80cabfad bellard
        case 0:
357 80cabfad bellard
            /* normal mode */
358 80cabfad bellard
            s->imr = val;
359 3de388f6 bellard
            pic_update_irq(s->pics_state);
360 80cabfad bellard
            break;
361 80cabfad bellard
        case 1:
362 80cabfad bellard
            s->irq_base = val & 0xf8;
363 2bb081f7 ths
            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
364 80cabfad bellard
            break;
365 80cabfad bellard
        case 2:
366 80cabfad bellard
            if (s->init4) {
367 80cabfad bellard
                s->init_state = 3;
368 80cabfad bellard
            } else {
369 80cabfad bellard
                s->init_state = 0;
370 80cabfad bellard
            }
371 80cabfad bellard
            break;
372 80cabfad bellard
        case 3:
373 80cabfad bellard
            s->special_fully_nested_mode = (val >> 4) & 1;
374 80cabfad bellard
            s->auto_eoi = (val >> 1) & 1;
375 80cabfad bellard
            s->init_state = 0;
376 80cabfad bellard
            break;
377 80cabfad bellard
        }
378 80cabfad bellard
    }
379 80cabfad bellard
}
380 80cabfad bellard
381 098d314a Richard Henderson
static uint32_t pic_poll_read(PicState *s)
382 80cabfad bellard
{
383 80cabfad bellard
    int ret;
384 80cabfad bellard
385 80cabfad bellard
    ret = pic_get_irq(s);
386 80cabfad bellard
    if (ret >= 0) {
387 098d314a Richard Henderson
        bool slave = (s == &isa_pic->pics[1]);
388 098d314a Richard Henderson
389 098d314a Richard Henderson
        if (slave) {
390 3de388f6 bellard
            s->pics_state->pics[0].isr &= ~(1 << 2);
391 3de388f6 bellard
            s->pics_state->pics[0].irr &= ~(1 << 2);
392 80cabfad bellard
        }
393 80cabfad bellard
        s->irr &= ~(1 << ret);
394 80cabfad bellard
        s->isr &= ~(1 << ret);
395 098d314a Richard Henderson
        if (slave || ret != 2)
396 3de388f6 bellard
            pic_update_irq(s->pics_state);
397 80cabfad bellard
    } else {
398 80cabfad bellard
        ret = 0x07;
399 3de388f6 bellard
        pic_update_irq(s->pics_state);
400 80cabfad bellard
    }
401 80cabfad bellard
402 80cabfad bellard
    return ret;
403 80cabfad bellard
}
404 80cabfad bellard
405 098d314a Richard Henderson
static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr1,
406 098d314a Richard Henderson
                                unsigned size)
407 80cabfad bellard
{
408 b41a2cd1 bellard
    PicState *s = opaque;
409 098d314a Richard Henderson
    unsigned int addr = addr1;
410 80cabfad bellard
    int ret;
411 80cabfad bellard
412 80cabfad bellard
    if (s->poll) {
413 098d314a Richard Henderson
        ret = pic_poll_read(s);
414 80cabfad bellard
        s->poll = 0;
415 80cabfad bellard
    } else {
416 80cabfad bellard
        if (addr == 0) {
417 80cabfad bellard
            if (s->read_reg_select)
418 80cabfad bellard
                ret = s->isr;
419 80cabfad bellard
            else
420 80cabfad bellard
                ret = s->irr;
421 80cabfad bellard
        } else {
422 80cabfad bellard
            ret = s->imr;
423 80cabfad bellard
        }
424 80cabfad bellard
    }
425 098d314a Richard Henderson
    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
426 80cabfad bellard
    return ret;
427 80cabfad bellard
}
428 80cabfad bellard
429 80cabfad bellard
/* memory mapped interrupt status */
430 3de388f6 bellard
/* XXX: may be the same than pic_read_irq() */
431 3de388f6 bellard
uint32_t pic_intack_read(PicState2 *s)
432 80cabfad bellard
{
433 80cabfad bellard
    int ret;
434 80cabfad bellard
435 098d314a Richard Henderson
    ret = pic_poll_read(&s->pics[0]);
436 80cabfad bellard
    if (ret == 2)
437 098d314a Richard Henderson
        ret = pic_poll_read(&s->pics[1]) + 8;
438 80cabfad bellard
    /* Prepare for ISR read */
439 3de388f6 bellard
    s->pics[0].read_reg_select = 1;
440 3b46e624 ths
441 80cabfad bellard
    return ret;
442 80cabfad bellard
}
443 80cabfad bellard
444 098d314a Richard Henderson
static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
445 098d314a Richard Henderson
                              uint64_t val, unsigned size)
446 660de336 bellard
{
447 660de336 bellard
    PicState *s = opaque;
448 660de336 bellard
    s->elcr = val & s->elcr_mask;
449 660de336 bellard
}
450 660de336 bellard
451 098d314a Richard Henderson
static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
452 098d314a Richard Henderson
                                 unsigned size)
453 660de336 bellard
{
454 660de336 bellard
    PicState *s = opaque;
455 660de336 bellard
    return s->elcr;
456 660de336 bellard
}
457 660de336 bellard
458 77eea838 Juan Quintela
static const VMStateDescription vmstate_pic = {
459 77eea838 Juan Quintela
    .name = "i8259",
460 77eea838 Juan Quintela
    .version_id = 1,
461 77eea838 Juan Quintela
    .minimum_version_id = 1,
462 77eea838 Juan Quintela
    .minimum_version_id_old = 1,
463 77eea838 Juan Quintela
    .fields      = (VMStateField []) {
464 77eea838 Juan Quintela
        VMSTATE_UINT8(last_irr, PicState),
465 77eea838 Juan Quintela
        VMSTATE_UINT8(irr, PicState),
466 77eea838 Juan Quintela
        VMSTATE_UINT8(imr, PicState),
467 77eea838 Juan Quintela
        VMSTATE_UINT8(isr, PicState),
468 77eea838 Juan Quintela
        VMSTATE_UINT8(priority_add, PicState),
469 77eea838 Juan Quintela
        VMSTATE_UINT8(irq_base, PicState),
470 77eea838 Juan Quintela
        VMSTATE_UINT8(read_reg_select, PicState),
471 77eea838 Juan Quintela
        VMSTATE_UINT8(poll, PicState),
472 77eea838 Juan Quintela
        VMSTATE_UINT8(special_mask, PicState),
473 77eea838 Juan Quintela
        VMSTATE_UINT8(init_state, PicState),
474 77eea838 Juan Quintela
        VMSTATE_UINT8(auto_eoi, PicState),
475 77eea838 Juan Quintela
        VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
476 77eea838 Juan Quintela
        VMSTATE_UINT8(special_fully_nested_mode, PicState),
477 77eea838 Juan Quintela
        VMSTATE_UINT8(init4, PicState),
478 77eea838 Juan Quintela
        VMSTATE_UINT8(single_mode, PicState),
479 77eea838 Juan Quintela
        VMSTATE_UINT8(elcr, PicState),
480 77eea838 Juan Quintela
        VMSTATE_END_OF_LIST()
481 77eea838 Juan Quintela
    }
482 77eea838 Juan Quintela
};
483 b0a21b53 bellard
484 098d314a Richard Henderson
static const MemoryRegionOps pic_base_ioport_ops = {
485 098d314a Richard Henderson
    .read = pic_ioport_read,
486 098d314a Richard Henderson
    .write = pic_ioport_write,
487 098d314a Richard Henderson
    .impl = {
488 098d314a Richard Henderson
        .min_access_size = 1,
489 098d314a Richard Henderson
        .max_access_size = 1,
490 098d314a Richard Henderson
    },
491 098d314a Richard Henderson
};
492 098d314a Richard Henderson
493 098d314a Richard Henderson
static const MemoryRegionOps pic_elcr_ioport_ops = {
494 098d314a Richard Henderson
    .read = elcr_ioport_read,
495 098d314a Richard Henderson
    .write = elcr_ioport_write,
496 098d314a Richard Henderson
    .impl = {
497 098d314a Richard Henderson
        .min_access_size = 1,
498 098d314a Richard Henderson
        .max_access_size = 1,
499 098d314a Richard Henderson
    },
500 098d314a Richard Henderson
};
501 098d314a Richard Henderson
502 b0a21b53 bellard
/* XXX: add generic master/slave system */
503 660de336 bellard
static void pic_init1(int io_addr, int elcr_addr, PicState *s)
504 b0a21b53 bellard
{
505 098d314a Richard Henderson
    memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
506 098d314a Richard Henderson
    memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
507 098d314a Richard Henderson
508 098d314a Richard Henderson
    isa_register_ioport(NULL, &s->base_io, io_addr);
509 660de336 bellard
    if (elcr_addr >= 0) {
510 098d314a Richard Henderson
        isa_register_ioport(NULL, &s->elcr_io, elcr_addr);
511 660de336 bellard
    }
512 098d314a Richard Henderson
513 0be71e32 Alex Williamson
    vmstate_register(NULL, io_addr, &vmstate_pic, s);
514 a08d4367 Jan Kiszka
    qemu_register_reset(pic_reset, s);
515 b0a21b53 bellard
}
516 b0a21b53 bellard
517 376253ec aliguori
void pic_info(Monitor *mon)
518 ba91cd80 bellard
{
519 ba91cd80 bellard
    int i;
520 ba91cd80 bellard
    PicState *s;
521 3b46e624 ths
522 3de388f6 bellard
    if (!isa_pic)
523 3de388f6 bellard
        return;
524 ba91cd80 bellard
525 ba91cd80 bellard
    for(i=0;i<2;i++) {
526 3de388f6 bellard
        s = &isa_pic->pics[i];
527 376253ec aliguori
        monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
528 376253ec aliguori
                       "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
529 376253ec aliguori
                       i, s->irr, s->imr, s->isr, s->priority_add,
530 376253ec aliguori
                       s->irq_base, s->read_reg_select, s->elcr,
531 376253ec aliguori
                       s->special_fully_nested_mode);
532 ba91cd80 bellard
    }
533 ba91cd80 bellard
}
534 ba91cd80 bellard
535 376253ec aliguori
void irq_info(Monitor *mon)
536 4a0fb71e bellard
{
537 4a0fb71e bellard
#ifndef DEBUG_IRQ_COUNT
538 376253ec aliguori
    monitor_printf(mon, "irq statistic code not compiled.\n");
539 4a0fb71e bellard
#else
540 4a0fb71e bellard
    int i;
541 4a0fb71e bellard
    int64_t count;
542 4a0fb71e bellard
543 376253ec aliguori
    monitor_printf(mon, "IRQ statistics:\n");
544 4a0fb71e bellard
    for (i = 0; i < 16; i++) {
545 4a0fb71e bellard
        count = irq_count[i];
546 4a0fb71e bellard
        if (count > 0)
547 376253ec aliguori
            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
548 4a0fb71e bellard
    }
549 4a0fb71e bellard
#endif
550 4a0fb71e bellard
}
551 ba91cd80 bellard
552 d537cf6c pbrook
qemu_irq *i8259_init(qemu_irq parent_irq)
553 80cabfad bellard
{
554 3de388f6 bellard
    PicState2 *s;
555 d537cf6c pbrook
556 7267c094 Anthony Liguori
    s = g_malloc0(sizeof(PicState2));
557 3de388f6 bellard
    pic_init1(0x20, 0x4d0, &s->pics[0]);
558 3de388f6 bellard
    pic_init1(0xa0, 0x4d1, &s->pics[1]);
559 3de388f6 bellard
    s->pics[0].elcr_mask = 0xf8;
560 3de388f6 bellard
    s->pics[1].elcr_mask = 0xde;
561 d537cf6c pbrook
    s->parent_irq = parent_irq;
562 3de388f6 bellard
    s->pics[0].pics_state = s;
563 3de388f6 bellard
    s->pics[1].pics_state = s;
564 d537cf6c pbrook
    isa_pic = s;
565 d537cf6c pbrook
    return qemu_allocate_irqs(i8259_set_irq, s, 16);
566 80cabfad bellard
}