Statistics
| Branch: | Revision:

root / hw / i8259.c @ 273a2142

History | View | Annotate | Download (15 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 b41a2cd1 bellard
//#define DEBUG_IRQ_LATENCY
34 4a0fb71e bellard
//#define DEBUG_IRQ_COUNT
35 b41a2cd1 bellard
36 80cabfad bellard
typedef struct PicState {
37 80cabfad bellard
    uint8_t last_irr; /* edge detection */
38 80cabfad bellard
    uint8_t irr; /* interrupt request register */
39 80cabfad bellard
    uint8_t imr; /* interrupt mask register */
40 80cabfad bellard
    uint8_t isr; /* interrupt service register */
41 80cabfad bellard
    uint8_t priority_add; /* highest irq priority */
42 80cabfad bellard
    uint8_t irq_base;
43 80cabfad bellard
    uint8_t read_reg_select;
44 80cabfad bellard
    uint8_t poll;
45 80cabfad bellard
    uint8_t special_mask;
46 80cabfad bellard
    uint8_t init_state;
47 80cabfad bellard
    uint8_t auto_eoi;
48 80cabfad bellard
    uint8_t rotate_on_auto_eoi;
49 80cabfad bellard
    uint8_t special_fully_nested_mode;
50 80cabfad bellard
    uint8_t init4; /* true if 4 byte init */
51 2053152b ths
    uint8_t single_mode; /* true if slave pic is not initialized */
52 660de336 bellard
    uint8_t elcr; /* PIIX edge/trigger selection*/
53 660de336 bellard
    uint8_t elcr_mask;
54 3de388f6 bellard
    PicState2 *pics_state;
55 80cabfad bellard
} PicState;
56 80cabfad bellard
57 3de388f6 bellard
struct PicState2 {
58 3de388f6 bellard
    /* 0 is master pic, 1 is slave pic */
59 3de388f6 bellard
    /* XXX: better separation between the two pics */
60 3de388f6 bellard
    PicState pics[2];
61 d537cf6c pbrook
    qemu_irq parent_irq;
62 3de388f6 bellard
    void *irq_request_opaque;
63 3de388f6 bellard
};
64 80cabfad bellard
65 4a0fb71e bellard
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
66 4a0fb71e bellard
static int irq_level[16];
67 4a0fb71e bellard
#endif
68 4a0fb71e bellard
#ifdef DEBUG_IRQ_COUNT
69 4a0fb71e bellard
static uint64_t irq_count[16];
70 4a0fb71e bellard
#endif
71 4a0fb71e bellard
72 80cabfad bellard
/* set irq level. If an edge is detected, then the IRR is set to 1 */
73 80cabfad bellard
static inline void pic_set_irq1(PicState *s, int irq, int level)
74 80cabfad bellard
{
75 80cabfad bellard
    int mask;
76 80cabfad bellard
    mask = 1 << irq;
77 660de336 bellard
    if (s->elcr & mask) {
78 660de336 bellard
        /* level triggered */
79 660de336 bellard
        if (level) {
80 80cabfad bellard
            s->irr |= mask;
81 660de336 bellard
            s->last_irr |= mask;
82 660de336 bellard
        } else {
83 660de336 bellard
            s->irr &= ~mask;
84 660de336 bellard
            s->last_irr &= ~mask;
85 660de336 bellard
        }
86 80cabfad bellard
    } else {
87 660de336 bellard
        /* edge triggered */
88 660de336 bellard
        if (level) {
89 660de336 bellard
            if ((s->last_irr & mask) == 0)
90 660de336 bellard
                s->irr |= mask;
91 660de336 bellard
            s->last_irr |= mask;
92 660de336 bellard
        } else {
93 660de336 bellard
            s->last_irr &= ~mask;
94 660de336 bellard
        }
95 80cabfad bellard
    }
96 80cabfad bellard
}
97 80cabfad bellard
98 80cabfad bellard
/* return the highest priority found in mask (highest = smallest
99 80cabfad bellard
   number). Return 8 if no irq */
100 80cabfad bellard
static inline int get_priority(PicState *s, int mask)
101 80cabfad bellard
{
102 80cabfad bellard
    int priority;
103 80cabfad bellard
    if (mask == 0)
104 80cabfad bellard
        return 8;
105 80cabfad bellard
    priority = 0;
106 80cabfad bellard
    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
107 80cabfad bellard
        priority++;
108 80cabfad bellard
    return priority;
109 80cabfad bellard
}
110 80cabfad bellard
111 80cabfad bellard
/* return the pic wanted interrupt. return -1 if none */
112 80cabfad bellard
static int pic_get_irq(PicState *s)
113 80cabfad bellard
{
114 80cabfad bellard
    int mask, cur_priority, priority;
115 80cabfad bellard
116 80cabfad bellard
    mask = s->irr & ~s->imr;
117 80cabfad bellard
    priority = get_priority(s, mask);
118 80cabfad bellard
    if (priority == 8)
119 80cabfad bellard
        return -1;
120 80cabfad bellard
    /* compute current priority. If special fully nested mode on the
121 80cabfad bellard
       master, the IRQ coming from the slave is not taken into account
122 80cabfad bellard
       for the priority computation. */
123 80cabfad bellard
    mask = s->isr;
124 84678711 balrog
    if (s->special_mask)
125 84678711 balrog
        mask &= ~s->imr;
126 3de388f6 bellard
    if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
127 80cabfad bellard
        mask &= ~(1 << 2);
128 80cabfad bellard
    cur_priority = get_priority(s, mask);
129 80cabfad bellard
    if (priority < cur_priority) {
130 80cabfad bellard
        /* higher priority found: an irq should be generated */
131 80cabfad bellard
        return (priority + s->priority_add) & 7;
132 80cabfad bellard
    } else {
133 80cabfad bellard
        return -1;
134 80cabfad bellard
    }
135 80cabfad bellard
}
136 80cabfad bellard
137 80cabfad bellard
/* raise irq to CPU if necessary. must be called every time the active
138 80cabfad bellard
   irq may change */
139 3de388f6 bellard
/* XXX: should not export it, but it is needed for an APIC kludge */
140 3de388f6 bellard
void pic_update_irq(PicState2 *s)
141 80cabfad bellard
{
142 80cabfad bellard
    int irq2, irq;
143 80cabfad bellard
144 80cabfad bellard
    /* first look at slave pic */
145 3de388f6 bellard
    irq2 = pic_get_irq(&s->pics[1]);
146 80cabfad bellard
    if (irq2 >= 0) {
147 80cabfad bellard
        /* if irq request by slave pic, signal master PIC */
148 3de388f6 bellard
        pic_set_irq1(&s->pics[0], 2, 1);
149 3de388f6 bellard
        pic_set_irq1(&s->pics[0], 2, 0);
150 80cabfad bellard
    }
151 80cabfad bellard
    /* look at requested irq */
152 3de388f6 bellard
    irq = pic_get_irq(&s->pics[0]);
153 80cabfad bellard
    if (irq >= 0) {
154 80cabfad bellard
#if defined(DEBUG_PIC)
155 80cabfad bellard
        {
156 80cabfad bellard
            int i;
157 80cabfad bellard
            for(i = 0; i < 2; i++) {
158 5fafdf24 ths
                printf("pic%d: imr=%x irr=%x padd=%d\n",
159 5fafdf24 ths
                       i, s->pics[i].imr, s->pics[i].irr,
160 3de388f6 bellard
                       s->pics[i].priority_add);
161 3b46e624 ths
162 80cabfad bellard
            }
163 80cabfad bellard
        }
164 2444ca41 bellard
        printf("pic: cpu_interrupt\n");
165 80cabfad bellard
#endif
166 d537cf6c pbrook
        qemu_irq_raise(s->parent_irq);
167 80cabfad bellard
    }
168 4de9b249 ths
169 4de9b249 ths
/* all targets should do this rather than acking the IRQ in the cpu */
170 29463b24 aurel32
#if defined(TARGET_MIPS) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
171 4de9b249 ths
    else {
172 d537cf6c pbrook
        qemu_irq_lower(s->parent_irq);
173 4de9b249 ths
    }
174 4de9b249 ths
#endif
175 80cabfad bellard
}
176 80cabfad bellard
177 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
178 80cabfad bellard
int64_t irq_time[16];
179 80cabfad bellard
#endif
180 80cabfad bellard
181 9596ebb7 pbrook
static void i8259_set_irq(void *opaque, int irq, int level)
182 80cabfad bellard
{
183 3de388f6 bellard
    PicState2 *s = opaque;
184 3de388f6 bellard
185 4a0fb71e bellard
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
186 80cabfad bellard
    if (level != irq_level[irq]) {
187 4a0fb71e bellard
#if defined(DEBUG_PIC)
188 d537cf6c pbrook
        printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
189 4a0fb71e bellard
#endif
190 80cabfad bellard
        irq_level[irq] = level;
191 4a0fb71e bellard
#ifdef DEBUG_IRQ_COUNT
192 4a0fb71e bellard
        if (level == 1)
193 4a0fb71e bellard
            irq_count[irq]++;
194 4a0fb71e bellard
#endif
195 80cabfad bellard
    }
196 80cabfad bellard
#endif
197 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
198 80cabfad bellard
    if (level) {
199 2444ca41 bellard
        irq_time[irq] = qemu_get_clock(vm_clock);
200 80cabfad bellard
    }
201 80cabfad bellard
#endif
202 3de388f6 bellard
    pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
203 3de388f6 bellard
    pic_update_irq(s);
204 80cabfad bellard
}
205 80cabfad bellard
206 80cabfad bellard
/* acknowledge interrupt 'irq' */
207 80cabfad bellard
static inline void pic_intack(PicState *s, int irq)
208 80cabfad bellard
{
209 80cabfad bellard
    if (s->auto_eoi) {
210 80cabfad bellard
        if (s->rotate_on_auto_eoi)
211 80cabfad bellard
            s->priority_add = (irq + 1) & 7;
212 80cabfad bellard
    } else {
213 80cabfad bellard
        s->isr |= (1 << irq);
214 80cabfad bellard
    }
215 0ecf89aa bellard
    /* We don't clear a level sensitive interrupt here */
216 0ecf89aa bellard
    if (!(s->elcr & (1 << irq)))
217 0ecf89aa bellard
        s->irr &= ~(1 << irq);
218 80cabfad bellard
}
219 80cabfad bellard
220 3de388f6 bellard
int pic_read_irq(PicState2 *s)
221 80cabfad bellard
{
222 80cabfad bellard
    int irq, irq2, intno;
223 80cabfad bellard
224 3de388f6 bellard
    irq = pic_get_irq(&s->pics[0]);
225 15aeac38 bellard
    if (irq >= 0) {
226 3de388f6 bellard
        pic_intack(&s->pics[0], irq);
227 15aeac38 bellard
        if (irq == 2) {
228 3de388f6 bellard
            irq2 = pic_get_irq(&s->pics[1]);
229 15aeac38 bellard
            if (irq2 >= 0) {
230 3de388f6 bellard
                pic_intack(&s->pics[1], irq2);
231 15aeac38 bellard
            } else {
232 15aeac38 bellard
                /* spurious IRQ on slave controller */
233 15aeac38 bellard
                irq2 = 7;
234 15aeac38 bellard
            }
235 3de388f6 bellard
            intno = s->pics[1].irq_base + irq2;
236 15aeac38 bellard
            irq = irq2 + 8;
237 15aeac38 bellard
        } else {
238 3de388f6 bellard
            intno = s->pics[0].irq_base + irq;
239 15aeac38 bellard
        }
240 15aeac38 bellard
    } else {
241 15aeac38 bellard
        /* spurious IRQ on host controller */
242 15aeac38 bellard
        irq = 7;
243 3de388f6 bellard
        intno = s->pics[0].irq_base + irq;
244 15aeac38 bellard
    }
245 3de388f6 bellard
    pic_update_irq(s);
246 3b46e624 ths
247 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
248 5fafdf24 ths
    printf("IRQ%d latency=%0.3fus\n",
249 5fafdf24 ths
           irq,
250 2444ca41 bellard
           (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
251 80cabfad bellard
#endif
252 80cabfad bellard
#if defined(DEBUG_PIC)
253 80cabfad bellard
    printf("pic_interrupt: irq=%d\n", irq);
254 80cabfad bellard
#endif
255 80cabfad bellard
    return intno;
256 80cabfad bellard
}
257 80cabfad bellard
258 d7d02e3c bellard
static void pic_reset(void *opaque)
259 d7d02e3c bellard
{
260 d7d02e3c bellard
    PicState *s = opaque;
261 d7d02e3c bellard
262 3de388f6 bellard
    s->last_irr = 0;
263 3de388f6 bellard
    s->irr = 0;
264 3de388f6 bellard
    s->imr = 0;
265 3de388f6 bellard
    s->isr = 0;
266 3de388f6 bellard
    s->priority_add = 0;
267 3de388f6 bellard
    s->irq_base = 0;
268 3de388f6 bellard
    s->read_reg_select = 0;
269 3de388f6 bellard
    s->poll = 0;
270 3de388f6 bellard
    s->special_mask = 0;
271 3de388f6 bellard
    s->init_state = 0;
272 3de388f6 bellard
    s->auto_eoi = 0;
273 3de388f6 bellard
    s->rotate_on_auto_eoi = 0;
274 3de388f6 bellard
    s->special_fully_nested_mode = 0;
275 3de388f6 bellard
    s->init4 = 0;
276 2053152b ths
    s->single_mode = 0;
277 4dbe19e1 bellard
    /* Note: ELCR is not reset */
278 d7d02e3c bellard
}
279 d7d02e3c bellard
280 b41a2cd1 bellard
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
281 80cabfad bellard
{
282 b41a2cd1 bellard
    PicState *s = opaque;
283 d7d02e3c bellard
    int priority, cmd, irq;
284 80cabfad bellard
285 80cabfad bellard
#ifdef DEBUG_PIC
286 80cabfad bellard
    printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
287 80cabfad bellard
#endif
288 80cabfad bellard
    addr &= 1;
289 80cabfad bellard
    if (addr == 0) {
290 80cabfad bellard
        if (val & 0x10) {
291 80cabfad bellard
            /* init */
292 d7d02e3c bellard
            pic_reset(s);
293 b54ad049 bellard
            /* deassert a pending interrupt */
294 d537cf6c pbrook
            qemu_irq_lower(s->pics_state->parent_irq);
295 80cabfad bellard
            s->init_state = 1;
296 80cabfad bellard
            s->init4 = val & 1;
297 2053152b ths
            s->single_mode = val & 2;
298 80cabfad bellard
            if (val & 0x08)
299 80cabfad bellard
                hw_error("level sensitive irq not supported");
300 80cabfad bellard
        } else if (val & 0x08) {
301 80cabfad bellard
            if (val & 0x04)
302 80cabfad bellard
                s->poll = 1;
303 80cabfad bellard
            if (val & 0x02)
304 80cabfad bellard
                s->read_reg_select = val & 1;
305 80cabfad bellard
            if (val & 0x40)
306 80cabfad bellard
                s->special_mask = (val >> 5) & 1;
307 80cabfad bellard
        } else {
308 80cabfad bellard
            cmd = val >> 5;
309 80cabfad bellard
            switch(cmd) {
310 80cabfad bellard
            case 0:
311 80cabfad bellard
            case 4:
312 80cabfad bellard
                s->rotate_on_auto_eoi = cmd >> 2;
313 80cabfad bellard
                break;
314 80cabfad bellard
            case 1: /* end of interrupt */
315 80cabfad bellard
            case 5:
316 80cabfad bellard
                priority = get_priority(s, s->isr);
317 80cabfad bellard
                if (priority != 8) {
318 80cabfad bellard
                    irq = (priority + s->priority_add) & 7;
319 80cabfad bellard
                    s->isr &= ~(1 << irq);
320 80cabfad bellard
                    if (cmd == 5)
321 80cabfad bellard
                        s->priority_add = (irq + 1) & 7;
322 3de388f6 bellard
                    pic_update_irq(s->pics_state);
323 80cabfad bellard
                }
324 80cabfad bellard
                break;
325 80cabfad bellard
            case 3:
326 80cabfad bellard
                irq = val & 7;
327 80cabfad bellard
                s->isr &= ~(1 << irq);
328 3de388f6 bellard
                pic_update_irq(s->pics_state);
329 80cabfad bellard
                break;
330 80cabfad bellard
            case 6:
331 80cabfad bellard
                s->priority_add = (val + 1) & 7;
332 3de388f6 bellard
                pic_update_irq(s->pics_state);
333 80cabfad bellard
                break;
334 80cabfad bellard
            case 7:
335 80cabfad bellard
                irq = val & 7;
336 80cabfad bellard
                s->isr &= ~(1 << irq);
337 80cabfad bellard
                s->priority_add = (irq + 1) & 7;
338 3de388f6 bellard
                pic_update_irq(s->pics_state);
339 80cabfad bellard
                break;
340 80cabfad bellard
            default:
341 80cabfad bellard
                /* no operation */
342 80cabfad bellard
                break;
343 80cabfad bellard
            }
344 80cabfad bellard
        }
345 80cabfad bellard
    } else {
346 80cabfad bellard
        switch(s->init_state) {
347 80cabfad bellard
        case 0:
348 80cabfad bellard
            /* normal mode */
349 80cabfad bellard
            s->imr = val;
350 3de388f6 bellard
            pic_update_irq(s->pics_state);
351 80cabfad bellard
            break;
352 80cabfad bellard
        case 1:
353 80cabfad bellard
            s->irq_base = val & 0xf8;
354 2bb081f7 ths
            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
355 80cabfad bellard
            break;
356 80cabfad bellard
        case 2:
357 80cabfad bellard
            if (s->init4) {
358 80cabfad bellard
                s->init_state = 3;
359 80cabfad bellard
            } else {
360 80cabfad bellard
                s->init_state = 0;
361 80cabfad bellard
            }
362 80cabfad bellard
            break;
363 80cabfad bellard
        case 3:
364 80cabfad bellard
            s->special_fully_nested_mode = (val >> 4) & 1;
365 80cabfad bellard
            s->auto_eoi = (val >> 1) & 1;
366 80cabfad bellard
            s->init_state = 0;
367 80cabfad bellard
            break;
368 80cabfad bellard
        }
369 80cabfad bellard
    }
370 80cabfad bellard
}
371 80cabfad bellard
372 80cabfad bellard
static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
373 80cabfad bellard
{
374 80cabfad bellard
    int ret;
375 80cabfad bellard
376 80cabfad bellard
    ret = pic_get_irq(s);
377 80cabfad bellard
    if (ret >= 0) {
378 80cabfad bellard
        if (addr1 >> 7) {
379 3de388f6 bellard
            s->pics_state->pics[0].isr &= ~(1 << 2);
380 3de388f6 bellard
            s->pics_state->pics[0].irr &= ~(1 << 2);
381 80cabfad bellard
        }
382 80cabfad bellard
        s->irr &= ~(1 << ret);
383 80cabfad bellard
        s->isr &= ~(1 << ret);
384 80cabfad bellard
        if (addr1 >> 7 || ret != 2)
385 3de388f6 bellard
            pic_update_irq(s->pics_state);
386 80cabfad bellard
    } else {
387 80cabfad bellard
        ret = 0x07;
388 3de388f6 bellard
        pic_update_irq(s->pics_state);
389 80cabfad bellard
    }
390 80cabfad bellard
391 80cabfad bellard
    return ret;
392 80cabfad bellard
}
393 80cabfad bellard
394 b41a2cd1 bellard
static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
395 80cabfad bellard
{
396 b41a2cd1 bellard
    PicState *s = opaque;
397 80cabfad bellard
    unsigned int addr;
398 80cabfad bellard
    int ret;
399 80cabfad bellard
400 80cabfad bellard
    addr = addr1;
401 80cabfad bellard
    addr &= 1;
402 80cabfad bellard
    if (s->poll) {
403 80cabfad bellard
        ret = pic_poll_read(s, addr1);
404 80cabfad bellard
        s->poll = 0;
405 80cabfad bellard
    } else {
406 80cabfad bellard
        if (addr == 0) {
407 80cabfad bellard
            if (s->read_reg_select)
408 80cabfad bellard
                ret = s->isr;
409 80cabfad bellard
            else
410 80cabfad bellard
                ret = s->irr;
411 80cabfad bellard
        } else {
412 80cabfad bellard
            ret = s->imr;
413 80cabfad bellard
        }
414 80cabfad bellard
    }
415 80cabfad bellard
#ifdef DEBUG_PIC
416 80cabfad bellard
    printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
417 80cabfad bellard
#endif
418 80cabfad bellard
    return ret;
419 80cabfad bellard
}
420 80cabfad bellard
421 80cabfad bellard
/* memory mapped interrupt status */
422 3de388f6 bellard
/* XXX: may be the same than pic_read_irq() */
423 3de388f6 bellard
uint32_t pic_intack_read(PicState2 *s)
424 80cabfad bellard
{
425 80cabfad bellard
    int ret;
426 80cabfad bellard
427 3de388f6 bellard
    ret = pic_poll_read(&s->pics[0], 0x00);
428 80cabfad bellard
    if (ret == 2)
429 3de388f6 bellard
        ret = pic_poll_read(&s->pics[1], 0x80) + 8;
430 80cabfad bellard
    /* Prepare for ISR read */
431 3de388f6 bellard
    s->pics[0].read_reg_select = 1;
432 3b46e624 ths
433 80cabfad bellard
    return ret;
434 80cabfad bellard
}
435 80cabfad bellard
436 660de336 bellard
static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
437 660de336 bellard
{
438 660de336 bellard
    PicState *s = opaque;
439 660de336 bellard
    s->elcr = val & s->elcr_mask;
440 660de336 bellard
}
441 660de336 bellard
442 660de336 bellard
static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
443 660de336 bellard
{
444 660de336 bellard
    PicState *s = opaque;
445 660de336 bellard
    return s->elcr;
446 660de336 bellard
}
447 660de336 bellard
448 b0a21b53 bellard
static void pic_save(QEMUFile *f, void *opaque)
449 b0a21b53 bellard
{
450 b0a21b53 bellard
    PicState *s = opaque;
451 3b46e624 ths
452 b0a21b53 bellard
    qemu_put_8s(f, &s->last_irr);
453 b0a21b53 bellard
    qemu_put_8s(f, &s->irr);
454 b0a21b53 bellard
    qemu_put_8s(f, &s->imr);
455 b0a21b53 bellard
    qemu_put_8s(f, &s->isr);
456 b0a21b53 bellard
    qemu_put_8s(f, &s->priority_add);
457 b0a21b53 bellard
    qemu_put_8s(f, &s->irq_base);
458 b0a21b53 bellard
    qemu_put_8s(f, &s->read_reg_select);
459 b0a21b53 bellard
    qemu_put_8s(f, &s->poll);
460 b0a21b53 bellard
    qemu_put_8s(f, &s->special_mask);
461 b0a21b53 bellard
    qemu_put_8s(f, &s->init_state);
462 b0a21b53 bellard
    qemu_put_8s(f, &s->auto_eoi);
463 b0a21b53 bellard
    qemu_put_8s(f, &s->rotate_on_auto_eoi);
464 b0a21b53 bellard
    qemu_put_8s(f, &s->special_fully_nested_mode);
465 b0a21b53 bellard
    qemu_put_8s(f, &s->init4);
466 2053152b ths
    qemu_put_8s(f, &s->single_mode);
467 660de336 bellard
    qemu_put_8s(f, &s->elcr);
468 b0a21b53 bellard
}
469 b0a21b53 bellard
470 b0a21b53 bellard
static int pic_load(QEMUFile *f, void *opaque, int version_id)
471 b0a21b53 bellard
{
472 b0a21b53 bellard
    PicState *s = opaque;
473 3b46e624 ths
474 b0a21b53 bellard
    if (version_id != 1)
475 b0a21b53 bellard
        return -EINVAL;
476 b0a21b53 bellard
477 b0a21b53 bellard
    qemu_get_8s(f, &s->last_irr);
478 b0a21b53 bellard
    qemu_get_8s(f, &s->irr);
479 b0a21b53 bellard
    qemu_get_8s(f, &s->imr);
480 b0a21b53 bellard
    qemu_get_8s(f, &s->isr);
481 b0a21b53 bellard
    qemu_get_8s(f, &s->priority_add);
482 b0a21b53 bellard
    qemu_get_8s(f, &s->irq_base);
483 b0a21b53 bellard
    qemu_get_8s(f, &s->read_reg_select);
484 b0a21b53 bellard
    qemu_get_8s(f, &s->poll);
485 b0a21b53 bellard
    qemu_get_8s(f, &s->special_mask);
486 b0a21b53 bellard
    qemu_get_8s(f, &s->init_state);
487 b0a21b53 bellard
    qemu_get_8s(f, &s->auto_eoi);
488 b0a21b53 bellard
    qemu_get_8s(f, &s->rotate_on_auto_eoi);
489 b0a21b53 bellard
    qemu_get_8s(f, &s->special_fully_nested_mode);
490 b0a21b53 bellard
    qemu_get_8s(f, &s->init4);
491 2053152b ths
    qemu_get_8s(f, &s->single_mode);
492 660de336 bellard
    qemu_get_8s(f, &s->elcr);
493 b0a21b53 bellard
    return 0;
494 b0a21b53 bellard
}
495 b0a21b53 bellard
496 b0a21b53 bellard
/* XXX: add generic master/slave system */
497 660de336 bellard
static void pic_init1(int io_addr, int elcr_addr, PicState *s)
498 b0a21b53 bellard
{
499 b0a21b53 bellard
    register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
500 b0a21b53 bellard
    register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
501 660de336 bellard
    if (elcr_addr >= 0) {
502 660de336 bellard
        register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
503 660de336 bellard
        register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
504 660de336 bellard
    }
505 b0a21b53 bellard
    register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
506 a08d4367 Jan Kiszka
    qemu_register_reset(pic_reset, s);
507 b0a21b53 bellard
}
508 b0a21b53 bellard
509 376253ec aliguori
void pic_info(Monitor *mon)
510 ba91cd80 bellard
{
511 ba91cd80 bellard
    int i;
512 ba91cd80 bellard
    PicState *s;
513 3b46e624 ths
514 3de388f6 bellard
    if (!isa_pic)
515 3de388f6 bellard
        return;
516 ba91cd80 bellard
517 ba91cd80 bellard
    for(i=0;i<2;i++) {
518 3de388f6 bellard
        s = &isa_pic->pics[i];
519 376253ec aliguori
        monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
520 376253ec aliguori
                       "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
521 376253ec aliguori
                       i, s->irr, s->imr, s->isr, s->priority_add,
522 376253ec aliguori
                       s->irq_base, s->read_reg_select, s->elcr,
523 376253ec aliguori
                       s->special_fully_nested_mode);
524 ba91cd80 bellard
    }
525 ba91cd80 bellard
}
526 ba91cd80 bellard
527 376253ec aliguori
void irq_info(Monitor *mon)
528 4a0fb71e bellard
{
529 4a0fb71e bellard
#ifndef DEBUG_IRQ_COUNT
530 376253ec aliguori
    monitor_printf(mon, "irq statistic code not compiled.\n");
531 4a0fb71e bellard
#else
532 4a0fb71e bellard
    int i;
533 4a0fb71e bellard
    int64_t count;
534 4a0fb71e bellard
535 376253ec aliguori
    monitor_printf(mon, "IRQ statistics:\n");
536 4a0fb71e bellard
    for (i = 0; i < 16; i++) {
537 4a0fb71e bellard
        count = irq_count[i];
538 4a0fb71e bellard
        if (count > 0)
539 376253ec aliguori
            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
540 4a0fb71e bellard
    }
541 4a0fb71e bellard
#endif
542 4a0fb71e bellard
}
543 ba91cd80 bellard
544 d537cf6c pbrook
qemu_irq *i8259_init(qemu_irq parent_irq)
545 80cabfad bellard
{
546 3de388f6 bellard
    PicState2 *s;
547 d537cf6c pbrook
548 3de388f6 bellard
    s = qemu_mallocz(sizeof(PicState2));
549 3de388f6 bellard
    pic_init1(0x20, 0x4d0, &s->pics[0]);
550 3de388f6 bellard
    pic_init1(0xa0, 0x4d1, &s->pics[1]);
551 3de388f6 bellard
    s->pics[0].elcr_mask = 0xf8;
552 3de388f6 bellard
    s->pics[1].elcr_mask = 0xde;
553 d537cf6c pbrook
    s->parent_irq = parent_irq;
554 3de388f6 bellard
    s->pics[0].pics_state = s;
555 3de388f6 bellard
    s->pics[1].pics_state = s;
556 d537cf6c pbrook
    isa_pic = s;
557 d537cf6c pbrook
    return qemu_allocate_irqs(i8259_set_irq, s, 16);
558 80cabfad bellard
}