/** @note if an interrupt line state changes from unmasked to masked, then it must be deactivated when currently pending! */ static void pic_update_imr(PDEVPIC pThis, PPICSTATE pPic, uint8_t val) { int irq, intno; PPICSTATE pActivePIC; /* Query the current pending irq, if any. */ pActivePIC = &pThis->aPics[0]; intno = irq = pic_get_irq(pActivePIC); if (irq == 2) { pActivePIC = &pThis->aPics[1]; irq = pic_get_irq(pActivePIC); intno = irq + 8; } /* Update IMR */ Log(("pic_update_imr: pic%u %#x -> %#x\n", pPic->idxPic, pPic->imr, val)); pPic->imr = val; /* If an interrupt is pending and now masked, then clear the FF flag. */ if ( irq >= 0 && ((1 << irq) & ~pActivePIC->imr) == 0) { Log(("pic_update_imr: pic0: elcr=%x last_irr=%x irr=%x imr=%x isr=%x irq_base=%x\n", pThis->aPics[0].elcr, pThis->aPics[0].last_irr, pThis->aPics[0].irr, pThis->aPics[0].imr, pThis->aPics[0].isr, pThis->aPics[0].irq_base)); Log(("pic_update_imr: pic1: elcr=%x last_irr=%x irr=%x imr=%x isr=%x irq_base=%x\n", pThis->aPics[1].elcr, pThis->aPics[1].last_irr, pThis->aPics[1].irr, pThis->aPics[1].imr, pThis->aPics[1].isr, pThis->aPics[1].irq_base)); /* Clear pending IRQ 2 on master controller in case of slave interrupt. */ /** @todo Is this correct? */ if (intno > 7) { pThis->aPics[0].irr &= ~(1 << 2); STAM_COUNTER_INC(&pThis->StatClearedActiveSlaveIRQ); } else STAM_COUNTER_INC(&pThis->StatClearedActiveMasterIRQ); Log(("pic_update_imr: clear pending interrupt %d\n", intno)); pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns)); } }
/** * Set the an IRQ. * * @param pDevIns Device instance of the PICs. * @param iIrq IRQ number to set. * @param iLevel IRQ level. * @param uTagSrc The IRQ tag and source ID (for tracing). */ PDMBOTHCBDECL(void) picSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc) { PDEVPIC pThis = PDMINS_2_DATA(pDevIns, PDEVPIC); Assert(pThis->CTX_SUFF(pDevIns) == pDevIns); Assert(pThis->aPics[0].CTX_SUFF(pDevIns) == pDevIns); Assert(pThis->aPics[1].CTX_SUFF(pDevIns) == pDevIns); AssertMsg(iIrq < 16, ("iIrq=%d\n", iIrq)); Log(("picSetIrq %d %d\n", iIrq, iLevel)); DumpPICState(&pThis->aPics[0], "picSetIrq"); DumpPICState(&pThis->aPics[1], "picSetIrq"); STAM_COUNTER_INC(&pThis->CTXSUFF(StatSetIrq)); if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) { /* A flip-flop lowers the IRQ line and immediately raises it, so * that a rising edge is guaranteed to occur. Note that the IRQ * line must be held high for a while to avoid spurious interrupts. */ pic_set_irq1(&pThis->aPics[iIrq >> 3], iIrq & 7, 0, uTagSrc); pic_update_irq(pThis); }
/* raise irq to CPU if necessary. must be called every time the active irq may change */ static int pic_update_irq(PDEVPIC pThis) { PicState *pics = &pThis->aPics[0]; int irq2, irq; /* first look at slave pic */ irq2 = pic_get_irq(&pics[1]); Log(("pic_update_irq irq2=%d\n", irq2)); if (irq2 >= 0) { /* if irq request by slave pic, signal master PIC */ pic_set_irq1(&pics[0], 2, 1); } else { /* If not, clear the IR on the master PIC. */ pic_set_irq1(&pics[0], 2, 0); } /* look at requested irq */ irq = pic_get_irq(&pics[0]); if (irq >= 0) { /* If irq 2 is pending on the master pic, then there must be one pending on the slave pic too! Otherwise we'll get * spurious slave interrupts in picGetInterrupt. */ if (irq != 2 || irq2 != -1) { #if defined(DEBUG_PIC) int i; for(i = 0; i < 2; i++) { Log(("pic%d: imr=%x irr=%x padd=%d\n", i, pics[i].imr, pics[i].irr, pics[i].priority_add)); } Log(("pic: cpu_interrupt\n")); #endif pThis->CTX_SUFF(pPicHlp)->pfnSetInterruptFF(pThis->CTX_SUFF(pDevIns)); } else { STAM_COUNTER_INC(&pThis->StatClearedActiveIRQ2); Log(("pic_update_irq: irq 2 is active, but no interrupt is pending on the slave pic!!\n")); /* Clear it here, so lower priority interrupts can still be dispatched. */ /* if this was the only pending irq, then we must clear the interrupt ff flag */ pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns)); /** @note Is this correct? */ pics[0].irr &= ~(1 << 2); /* Call ourselves again just in case other interrupts are pending */ return pic_update_irq(pThis); } } else { Log(("pic_update_irq: no interrupt is pending!!\n")); /* we must clear the interrupt ff flag */ pThis->CTX_SUFF(pPicHlp)->pfnClearInterruptFF(pThis->CTX_SUFF(pDevIns)); } return VINF_SUCCESS; }