186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/*
286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * QEMU 8259 interrupt controller emulation
386797937017f52bff088d02edf64fb931177a7eaJun Nakajima *
486797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Copyright (c) 2003-2004 Fabrice Bellard
586797937017f52bff088d02edf64fb931177a7eaJun Nakajima *
686797937017f52bff088d02edf64fb931177a7eaJun Nakajima * Permission is hereby granted, free of charge, to any person obtaining a copy
786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * of this software and associated documentation files (the "Software"), to deal
886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * in the Software without restriction, including without limitation the rights
986797937017f52bff088d02edf64fb931177a7eaJun Nakajima * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1086797937017f52bff088d02edf64fb931177a7eaJun Nakajima * copies of the Software, and to permit persons to whom the Software is
1186797937017f52bff088d02edf64fb931177a7eaJun Nakajima * furnished to do so, subject to the following conditions:
1286797937017f52bff088d02edf64fb931177a7eaJun Nakajima *
1386797937017f52bff088d02edf64fb931177a7eaJun Nakajima * The above copyright notice and this permission notice shall be included in
1486797937017f52bff088d02edf64fb931177a7eaJun Nakajima * all copies or substantial portions of the Software.
1586797937017f52bff088d02edf64fb931177a7eaJun Nakajima *
1686797937017f52bff088d02edf64fb931177a7eaJun Nakajima * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1786797937017f52bff088d02edf64fb931177a7eaJun Nakajima * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1886797937017f52bff088d02edf64fb931177a7eaJun Nakajima * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1986797937017f52bff088d02edf64fb931177a7eaJun Nakajima * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2086797937017f52bff088d02edf64fb931177a7eaJun Nakajima * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2186797937017f52bff088d02edf64fb931177a7eaJun Nakajima * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2286797937017f52bff088d02edf64fb931177a7eaJun Nakajima * THE SOFTWARE.
2386797937017f52bff088d02edf64fb931177a7eaJun Nakajima */
2486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "hw.h"
2586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "pc.h"
2686797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "isa.h"
2786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#include "monitor.h"
28d0b482eb3e8cb699a2090bc773364d3a7d369a25Vladimir Chtchetkine#include "goldfish_device.h"
2986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
3086797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* debug PIC */
3186797937017f52bff088d02edf64fb931177a7eaJun Nakajima//#define DEBUG_PIC
3286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
3386797937017f52bff088d02edf64fb931177a7eaJun Nakajima//#define DEBUG_IRQ_LATENCY
3486797937017f52bff088d02edf64fb931177a7eaJun Nakajima//#define DEBUG_IRQ_COUNT
3586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
3686797937017f52bff088d02edf64fb931177a7eaJun Nakajimatypedef struct PicState {
3786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t last_irr; /* edge detection */
3886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t irr; /* interrupt request register */
3986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t imr; /* interrupt mask register */
4086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t isr; /* interrupt service register */
4186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t priority_add; /* highest irq priority */
4286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t irq_base;
4386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t read_reg_select;
4486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t poll;
4586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t special_mask;
4686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t init_state;
4786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t auto_eoi;
4886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t rotate_on_auto_eoi;
4986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t special_fully_nested_mode;
5086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t init4; /* true if 4 byte init */
5186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t single_mode; /* true if slave pic is not initialized */
5286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t elcr; /* PIIX edge/trigger selection*/
5386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    uint8_t elcr_mask;
5486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState2 *pics_state;
5586797937017f52bff088d02edf64fb931177a7eaJun Nakajima} PicState;
5686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
5786797937017f52bff088d02edf64fb931177a7eaJun Nakajimastruct PicState2 {
5886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* 0 is master pic, 1 is slave pic */
5986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* XXX: better separation between the two pics */
6086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState pics[2];
6186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_irq parent_irq;
6286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    void *irq_request_opaque;
6386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* IOAPIC callback support */
6486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    SetIRQFunc *alt_irq_func;
6586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    void *alt_irq_opaque;
6686797937017f52bff088d02edf64fb931177a7eaJun Nakajima};
6786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
6886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
6986797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int irq_level[16];
7086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
7186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_IRQ_COUNT
7286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint64_t irq_count[16];
7386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
7486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
7586797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* set irq level. If an edge is detected, then the IRR is set to 1 */
7686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void pic_set_irq1(PicState *s, int irq, int level)
7786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
7886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int mask;
7986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    mask = 1 << irq;
8086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->elcr & mask) {
8186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* level triggered */
8286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (level) {
8386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->irr |= mask;
8486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->last_irr |= mask;
8586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        } else {
8686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->irr &= ~mask;
8786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->last_irr &= ~mask;
8886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
8986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
9086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* edge triggered */
9186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (level) {
9286797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if ((s->last_irr & mask) == 0)
9386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->irr |= mask;
9486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->last_irr |= mask;
9586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        } else {
9686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->last_irr &= ~mask;
9786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
9886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
9986797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
10086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
10186797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* return the highest priority found in mask (highest = smallest
10286797937017f52bff088d02edf64fb931177a7eaJun Nakajima   number). Return 8 if no irq */
10386797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline int get_priority(PicState *s, int mask)
10486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
10586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int priority;
10686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (mask == 0)
10786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return 8;
10886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    priority = 0;
10986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
11086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        priority++;
11186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return priority;
11286797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
11386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
11486797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* return the pic wanted interrupt. return -1 if none */
11586797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int pic_get_irq(PicState *s)
11686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
11786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int mask, cur_priority, priority;
11886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
11986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    mask = s->irr & ~s->imr;
12086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    priority = get_priority(s, mask);
12186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (priority == 8)
12286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return -1;
12386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* compute current priority. If special fully nested mode on the
12486797937017f52bff088d02edf64fb931177a7eaJun Nakajima       master, the IRQ coming from the slave is not taken into account
12586797937017f52bff088d02edf64fb931177a7eaJun Nakajima       for the priority computation. */
12686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    mask = s->isr;
12786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->special_mask)
12886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        mask &= ~s->imr;
12986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
13086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        mask &= ~(1 << 2);
13186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    cur_priority = get_priority(s, mask);
13286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (priority < cur_priority) {
13386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* higher priority found: an irq should be generated */
13486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return (priority + s->priority_add) & 7;
13586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
13686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return -1;
13786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
13886797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
13986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
14086797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* raise irq to CPU if necessary. must be called every time the active
14186797937017f52bff088d02edf64fb931177a7eaJun Nakajima   irq may change */
14286797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: should not export it, but it is needed for an APIC kludge */
14386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid pic_update_irq(PicState2 *s)
14486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
14586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int irq2, irq;
14686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
14786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* first look at slave pic */
14886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    irq2 = pic_get_irq(&s->pics[1]);
14986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (irq2 >= 0) {
15086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* if irq request by slave pic, signal master PIC */
15186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        pic_set_irq1(&s->pics[0], 2, 1);
15286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        pic_set_irq1(&s->pics[0], 2, 0);
15386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
15486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* look at requested irq */
15586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    irq = pic_get_irq(&s->pics[0]);
15686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (irq >= 0) {
15786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(DEBUG_PIC)
15886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        {
15986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            int i;
16086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            for(i = 0; i < 2; i++) {
16186797937017f52bff088d02edf64fb931177a7eaJun Nakajima                printf("pic%d: imr=%x irr=%x padd=%d\n",
16286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                       i, s->pics[i].imr, s->pics[i].irr,
16386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                       s->pics[i].priority_add);
16486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
16586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            }
16686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
16786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        printf("pic: cpu_interrupt\n");
16886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
16986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_irq_raise(s->parent_irq);
17086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
17186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
17286797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* all targets should do this rather than acking the IRQ in the cpu */
17386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(TARGET_MIPS) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
17486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    else {
17586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        qemu_irq_lower(s->parent_irq);
17686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
17786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
17886797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
17986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
18086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_IRQ_LATENCY
18186797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint64_t irq_time[16];
18286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
18386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
18486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void i8259_set_irq(void *opaque, int irq, int level)
18586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
18686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState2 *s = opaque;
18786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
18886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
18986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (level != irq_level[irq]) {
19086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(DEBUG_PIC)
19186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
19286797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
19386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        irq_level[irq] = level;
19486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_IRQ_COUNT
19586797937017f52bff088d02edf64fb931177a7eaJun Nakajima	if (level == 1)
19686797937017f52bff088d02edf64fb931177a7eaJun Nakajima	    irq_count[irq]++;
19786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
19886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
19986797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
20086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_IRQ_LATENCY
20186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (level) {
20286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        irq_time[irq] = qemu_get_clock(vm_clock);
20386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
20486797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
20586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
20686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* used for IOAPIC irqs */
20786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->alt_irq_func)
20886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->alt_irq_func(s->alt_irq_opaque, irq, level);
20986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    pic_update_irq(s);
21086797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
21186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
21286797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* acknowledge interrupt 'irq' */
21386797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic inline void pic_intack(PicState *s, int irq)
21486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
21586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->auto_eoi) {
21686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (s->rotate_on_auto_eoi)
21786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->priority_add = (irq + 1) & 7;
21886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
21986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->isr |= (1 << irq);
22086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
22186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* We don't clear a level sensitive interrupt here */
22286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (!(s->elcr & (1 << irq)))
22386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->irr &= ~(1 << irq);
22486797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
22586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
22686797937017f52bff088d02edf64fb931177a7eaJun Nakajimaint pic_read_irq(PicState2 *s)
22786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
22886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int irq, irq2, intno;
22986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
23086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    irq = pic_get_irq(&s->pics[0]);
23186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (irq >= 0) {
23286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        pic_intack(&s->pics[0], irq);
23386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (irq == 2) {
23486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            irq2 = pic_get_irq(&s->pics[1]);
23586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (irq2 >= 0) {
23686797937017f52bff088d02edf64fb931177a7eaJun Nakajima                pic_intack(&s->pics[1], irq2);
23786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            } else {
23886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                /* spurious IRQ on slave controller */
23986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                irq2 = 7;
24086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            }
24186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            intno = s->pics[1].irq_base + irq2;
24286797937017f52bff088d02edf64fb931177a7eaJun Nakajima            irq = irq2 + 8;
24386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        } else {
24486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            intno = s->pics[0].irq_base + irq;
24586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
24686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
24786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        /* spurious IRQ on host controller */
24886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        irq = 7;
24986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        intno = s->pics[0].irq_base + irq;
25086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
25186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    pic_update_irq(s);
25286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
25386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_IRQ_LATENCY
25486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    printf("IRQ%d latency=%0.3fus\n",
25586797937017f52bff088d02edf64fb931177a7eaJun Nakajima           irq,
25686797937017f52bff088d02edf64fb931177a7eaJun Nakajima           (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / get_ticks_per_sec);
25786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
25886797937017f52bff088d02edf64fb931177a7eaJun Nakajima#if defined(DEBUG_PIC)
25986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    printf("pic_interrupt: irq=%d\n", irq);
26086797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
26186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return intno;
26286797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
26386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
26486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void pic_reset(void *opaque)
26586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
26686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState *s = opaque;
26786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
26886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->last_irr = 0;
26986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->irr = 0;
27086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->imr = 0;
27186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->isr = 0;
27286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->priority_add = 0;
27386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->irq_base = 0;
27486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->read_reg_select = 0;
27586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->poll = 0;
27686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->special_mask = 0;
27786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->init_state = 0;
27886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->auto_eoi = 0;
27986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->rotate_on_auto_eoi = 0;
28086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->special_fully_nested_mode = 0;
28186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->init4 = 0;
28286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->single_mode = 0;
28386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* Note: ELCR is not reset */
28486797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
28586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
28686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
28786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
28886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState *s = opaque;
28986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int priority, cmd, irq;
29086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
29186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_PIC
29286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
29386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
29486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    addr &= 1;
29586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (addr == 0) {
29686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (val & 0x10) {
29786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            /* init */
29886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            pic_reset(s);
29986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            /* deassert a pending interrupt */
30086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            qemu_irq_lower(s->pics_state->parent_irq);
30186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->init_state = 1;
30286797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->init4 = val & 1;
30386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->single_mode = val & 2;
30486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (val & 0x08)
30586797937017f52bff088d02edf64fb931177a7eaJun Nakajima                hw_error("level sensitive irq not supported");
30686797937017f52bff088d02edf64fb931177a7eaJun Nakajima        } else if (val & 0x08) {
30786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (val & 0x04)
30886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->poll = 1;
30986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (val & 0x02)
31086797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->read_reg_select = val & 1;
31186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (val & 0x40)
31286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->special_mask = (val >> 5) & 1;
31386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        } else {
31486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            cmd = val >> 5;
31586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            switch(cmd) {
31686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            case 0:
31786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            case 4:
31886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->rotate_on_auto_eoi = cmd >> 2;
31986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                break;
32086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            case 1: /* end of interrupt */
32186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            case 5:
32286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                priority = get_priority(s, s->isr);
32386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                if (priority != 8) {
32486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    irq = (priority + s->priority_add) & 7;
32586797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    s->isr &= ~(1 << irq);
32686797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    if (cmd == 5)
32786797937017f52bff088d02edf64fb931177a7eaJun Nakajima                        s->priority_add = (irq + 1) & 7;
32886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                    pic_update_irq(s->pics_state);
32986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                }
33086797937017f52bff088d02edf64fb931177a7eaJun Nakajima                break;
33186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            case 3:
33286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                irq = val & 7;
33386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->isr &= ~(1 << irq);
33486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                pic_update_irq(s->pics_state);
33586797937017f52bff088d02edf64fb931177a7eaJun Nakajima                break;
33686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            case 6:
33786797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->priority_add = (val + 1) & 7;
33886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                pic_update_irq(s->pics_state);
33986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                break;
34086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            case 7:
34186797937017f52bff088d02edf64fb931177a7eaJun Nakajima                irq = val & 7;
34286797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->isr &= ~(1 << irq);
34386797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->priority_add = (irq + 1) & 7;
34486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                pic_update_irq(s->pics_state);
34586797937017f52bff088d02edf64fb931177a7eaJun Nakajima                break;
34686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            default:
34786797937017f52bff088d02edf64fb931177a7eaJun Nakajima                /* no operation */
34886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                break;
34986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            }
35086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
35186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
35286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        switch(s->init_state) {
35386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case 0:
35486797937017f52bff088d02edf64fb931177a7eaJun Nakajima            /* normal mode */
35586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->imr = val;
35686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            pic_update_irq(s->pics_state);
35786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
35886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case 1:
35986797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->irq_base = val & 0xf8;
36086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
36186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
36286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case 2:
36386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (s->init4) {
36486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->init_state = 3;
36586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            } else {
36686797937017f52bff088d02edf64fb931177a7eaJun Nakajima                s->init_state = 0;
36786797937017f52bff088d02edf64fb931177a7eaJun Nakajima            }
36886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
36986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        case 3:
37086797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->special_fully_nested_mode = (val >> 4) & 1;
37186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->auto_eoi = (val >> 1) & 1;
37286797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->init_state = 0;
37386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            break;
37486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
37586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
37686797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
37786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
37886797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint32_t pic_poll_read (PicState *s, uint32_t addr1)
37986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
38086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int ret;
38186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
38286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    ret = pic_get_irq(s);
38386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (ret >= 0) {
38486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (addr1 >> 7) {
38586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->pics_state->pics[0].isr &= ~(1 << 2);
38686797937017f52bff088d02edf64fb931177a7eaJun Nakajima            s->pics_state->pics[0].irr &= ~(1 << 2);
38786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
38886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->irr &= ~(1 << ret);
38986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->isr &= ~(1 << ret);
39086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (addr1 >> 7 || ret != 2)
39186797937017f52bff088d02edf64fb931177a7eaJun Nakajima            pic_update_irq(s->pics_state);
39286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
39386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        ret = 0x07;
39486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        pic_update_irq(s->pics_state);
39586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
39686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
39786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return ret;
39886797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
39986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
40086797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
40186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
40286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState *s = opaque;
40386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    unsigned int addr;
40486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int ret;
40586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
40686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    addr = addr1;
40786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    addr &= 1;
40886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (s->poll) {
40986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        ret = pic_poll_read(s, addr1);
41086797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s->poll = 0;
41186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    } else {
41286797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (addr == 0) {
41386797937017f52bff088d02edf64fb931177a7eaJun Nakajima            if (s->read_reg_select)
41486797937017f52bff088d02edf64fb931177a7eaJun Nakajima                ret = s->isr;
41586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            else
41686797937017f52bff088d02edf64fb931177a7eaJun Nakajima                ret = s->irr;
41786797937017f52bff088d02edf64fb931177a7eaJun Nakajima        } else {
41886797937017f52bff088d02edf64fb931177a7eaJun Nakajima            ret = s->imr;
41986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        }
42086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
42186797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifdef DEBUG_PIC
42286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
42386797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
42486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return ret;
42586797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
42686797937017f52bff088d02edf64fb931177a7eaJun Nakajima
42786797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* memory mapped interrupt status */
42886797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: may be the same than pic_read_irq() */
42986797937017f52bff088d02edf64fb931177a7eaJun Nakajimauint32_t pic_intack_read(PicState2 *s)
43086797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
43186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int ret;
43286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
43386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    ret = pic_poll_read(&s->pics[0], 0x00);
43486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (ret == 2)
43586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        ret = pic_poll_read(&s->pics[1], 0x80) + 8;
43686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    /* Prepare for ISR read */
43786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->pics[0].read_reg_select = 1;
43886797937017f52bff088d02edf64fb931177a7eaJun Nakajima
43986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return ret;
44086797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
44186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
44286797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
44386797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
44486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState *s = opaque;
44586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->elcr = val & s->elcr_mask;
44686797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
44786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
44886797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
44986797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
45086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState *s = opaque;
45186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return s->elcr;
45286797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
45386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
45486797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void pic_save(QEMUFile *f, void *opaque)
45586797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
45686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState *s = opaque;
45786797937017f52bff088d02edf64fb931177a7eaJun Nakajima
45886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->last_irr);
45986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->irr);
46086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->imr);
46186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->isr);
46286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->priority_add);
46386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->irq_base);
46486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->read_reg_select);
46586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->poll);
46686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->special_mask);
46786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->init_state);
46886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->auto_eoi);
46986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->rotate_on_auto_eoi);
47086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->special_fully_nested_mode);
47186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->init4);
47286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->single_mode);
47386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_put_8s(f, &s->elcr);
47486797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
47586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
47686797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic int pic_load(QEMUFile *f, void *opaque, int version_id)
47786797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
47886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState *s = opaque;
47986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
48086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (version_id != 1)
48186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return -EINVAL;
48286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
48386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->last_irr);
48486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->irr);
48586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->imr);
48686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->isr);
48786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->priority_add);
48886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->irq_base);
48986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->read_reg_select);
49086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->poll);
49186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->special_mask);
49286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->init_state);
49386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->auto_eoi);
49486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->rotate_on_auto_eoi);
49586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->special_fully_nested_mode);
49686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->init4);
49786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->single_mode);
49886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_get_8s(f, &s->elcr);
49986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    return 0;
50086797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
50186797937017f52bff088d02edf64fb931177a7eaJun Nakajima
50286797937017f52bff088d02edf64fb931177a7eaJun Nakajima/* XXX: add generic master/slave system */
50386797937017f52bff088d02edf64fb931177a7eaJun Nakajimastatic void pic_init1(int io_addr, int elcr_addr, PicState *s)
50486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
50586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
50686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
50786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (elcr_addr >= 0) {
50886797937017f52bff088d02edf64fb931177a7eaJun Nakajima        register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
50986797937017f52bff088d02edf64fb931177a7eaJun Nakajima        register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
51086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
51186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
51286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    qemu_register_reset(pic_reset, 0, s);
51386797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
51486797937017f52bff088d02edf64fb931177a7eaJun Nakajima
51586797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid pic_info(Monitor *mon)
51686797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
51786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int i;
51886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState *s;
51986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
52086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    if (!isa_pic)
52186797937017f52bff088d02edf64fb931177a7eaJun Nakajima        return;
52286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
52386797937017f52bff088d02edf64fb931177a7eaJun Nakajima    for(i=0;i<2;i++) {
52486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        s = &isa_pic->pics[i];
52586797937017f52bff088d02edf64fb931177a7eaJun Nakajima        monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
52686797937017f52bff088d02edf64fb931177a7eaJun Nakajima                       "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
52786797937017f52bff088d02edf64fb931177a7eaJun Nakajima                       i, s->irr, s->imr, s->isr, s->priority_add,
52886797937017f52bff088d02edf64fb931177a7eaJun Nakajima                       s->irq_base, s->read_reg_select, s->elcr,
52986797937017f52bff088d02edf64fb931177a7eaJun Nakajima                       s->special_fully_nested_mode);
53086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
53186797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
53286797937017f52bff088d02edf64fb931177a7eaJun Nakajima
53386797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid irq_info(Monitor *mon)
53486797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
53586797937017f52bff088d02edf64fb931177a7eaJun Nakajima#ifndef DEBUG_IRQ_COUNT
53686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    monitor_printf(mon, "irq statistic code not compiled.\n");
53786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#else
53886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int i;
53986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    int64_t count;
54086797937017f52bff088d02edf64fb931177a7eaJun Nakajima
54186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    monitor_printf(mon, "IRQ statistics:\n");
54286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    for (i = 0; i < 16; i++) {
54386797937017f52bff088d02edf64fb931177a7eaJun Nakajima        count = irq_count[i];
54486797937017f52bff088d02edf64fb931177a7eaJun Nakajima        if (count > 0)
54586797937017f52bff088d02edf64fb931177a7eaJun Nakajima            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
54686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    }
54786797937017f52bff088d02edf64fb931177a7eaJun Nakajima#endif
54886797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
54986797937017f52bff088d02edf64fb931177a7eaJun Nakajima
55086797937017f52bff088d02edf64fb931177a7eaJun Nakajimaqemu_irq *i8259_init(qemu_irq parent_irq)
55186797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
55286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    PicState2 *s;
55386797937017f52bff088d02edf64fb931177a7eaJun Nakajima
55486797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s = qemu_mallocz(sizeof(PicState2));
55586797937017f52bff088d02edf64fb931177a7eaJun Nakajima    pic_init1(0x20, 0x4d0, &s->pics[0]);
55686797937017f52bff088d02edf64fb931177a7eaJun Nakajima    pic_init1(0xa0, 0x4d1, &s->pics[1]);
55786797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->pics[0].elcr_mask = 0xf8;
55886797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->pics[1].elcr_mask = 0xde;
55986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->parent_irq = parent_irq;
56086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->pics[0].pics_state = s;
56186797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->pics[1].pics_state = s;
56286797937017f52bff088d02edf64fb931177a7eaJun Nakajima    isa_pic = s;
563d0b482eb3e8cb699a2090bc773364d3a7d369a25Vladimir Chtchetkine    return qemu_allocate_irqs(i8259_set_irq, s, GFD_MAX_IRQ);
56486797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
56586797937017f52bff088d02edf64fb931177a7eaJun Nakajima
56686797937017f52bff088d02edf64fb931177a7eaJun Nakajimavoid pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
56786797937017f52bff088d02edf64fb931177a7eaJun Nakajima                          void *alt_irq_opaque)
56886797937017f52bff088d02edf64fb931177a7eaJun Nakajima{
56986797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->alt_irq_func = alt_irq_func;
57086797937017f52bff088d02edf64fb931177a7eaJun Nakajima    s->alt_irq_opaque = alt_irq_opaque;
57186797937017f52bff088d02edf64fb931177a7eaJun Nakajima}
572