From f771e9e612425e9e7dcc7a2cf68275e1a4945d0a Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 10 Aug 2023 05:03:11 +0200 Subject: [PATCH] PIC fixes: poll mode is no longer broken. --- src/pic.c | 66 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/pic.c b/src/pic.c index 526be90ff..588082c74 100644 --- a/src/pic.c +++ b/src/pic.c @@ -65,6 +65,8 @@ static int pic_pci = 0; static void (*update_pending)(void); static void pic_update_request(pic_t *dev, int irq); +static void pic_update_irr(pic_t *dev, uint16_t num); + static void pic_cascade(int set); #ifdef ENABLE_PIC_LOG @@ -224,17 +226,23 @@ find_best_interrupt(pic_t *dev) static __inline void pic_update_pending_xt(void) { - pic.int_pending = (find_best_interrupt(&pic) != -1); + if (!(pic.flags & PIC_FREEZE)) + pic.int_pending = (find_best_interrupt(&pic) != -1); } static __inline void pic_update_pending_at(void) { - pic2.int_pending = (find_best_interrupt(&pic2) != -1); + if (!(pic2.flags & PIC_FREEZE)) { + pic2.int_pending = (find_best_interrupt(&pic2) != -1); - pic_cascade(pic2.int_pending); + pic_cascade(pic2.int_pending); + } - pic.int_pending = (find_best_interrupt(&pic) != -1); + if (!(pic.flags & PIC_FREEZE)) + pic.int_pending = (find_best_interrupt(&pic) != -1); + + pic_log("pic_update_pending_at(): dev->int_pending = %i (%i)\n", pic.int_pending, !!(pic.flags & PIC_FREEZE)); } static void @@ -312,7 +320,7 @@ picint_is_level(int irq) } static void -pic_acknowledge(pic_t *dev) +pic_acknowledge(pic_t *dev, int poll) { int pic_int = dev->interrupt & 7; int pic_int_num = 1 << pic_int; @@ -324,10 +332,13 @@ pic_acknowledge(pic_t *dev) /* Clear the edge sense latch. */ dev->irq_latch &= ~pic_int_num; - dev->flags |= PIC_FREEZE; /* Freeze it so it still takes interrupts but they do not - override the one currently being processed. */ - /* Clear the reset latch. */ - pic_update_request(dev, pic_int); + if (!poll) { + dev->flags |= PIC_FREEZE; /* Freeze it so it still takes interrupts but they do not + override the one currently being processed. */ + + /* Clear the reset latch. */ + pic_update_request(dev, pic_int); + } } /* Find IRQ for non-specific EOI (either by command or automatic) by finding the highest IRQ @@ -434,15 +445,16 @@ pic_read(uint16_t addr, void *priv) } else { /* Standard 8259 PIC read */ if (dev->ocw3 & 0x04) { - dev->flags &= ~PIC_FREEZE; /* Freeze the interrupt until the poll is over. */ if (dev->int_pending) { dev->data_bus = 0x80 | (dev->interrupt & 7); - pic_acknowledge(dev); + pic_acknowledge(dev, 1); dev->int_pending = 0; - update_pending(); } else dev->data_bus = 0x00; dev->ocw3 &= ~0x04; + dev->flags &= ~PIC_FREEZE; /* Freeze the interrupt until the poll is over. */ + pic_update_irr(dev, 0x00ff); /* Update IRR, just in case anything came while frozen. */ + update_pending(); } else if (addr & 0x0001) dev->data_bus = dev->imr; else if (dev->ocw3 & 0x02) { @@ -509,10 +521,10 @@ pic_write(uint16_t addr, uint8_t val, void *priv) if (!(dev->icw1 & 1)) dev->icw4 = 0x00; dev->ocw2 = dev->ocw3 = 0x00; + dev->flags = PIC_MASTER_CLEAR; dev->irr = 0x00; dev->edge_lines = 0x00; dev->irq_latch = 0x00; - dev->flags |= PIC_MASTER_CLEAR; for (i = 0; i <= 7; i++) pic_update_request(dev, i); dev->flags &= ~PIC_MASTER_CLEAR; @@ -668,7 +680,6 @@ pic_irq_get_request(pic_t *dev, int irq) ret = ((dev->edge_lines & (1 << irq)) || (dev->lines[irq] > 0)); - pic_log("pic_irq_get_request(%08X, %i) = %02X\n", (uint32_t) (uintptr_t) dev, irq, ret); return ret; } @@ -679,7 +690,6 @@ pic_es_latch_clear(pic_t *dev, int irq) ret = (dev->isr & (1 << irq)) || (dev->flags & PIC_MASTER_CLEAR); - pic_log("pic_es_latch_clear(%08X, %i) = %02X\n", (uint32_t) (uintptr_t) dev, irq, ret); return ret; } @@ -690,7 +700,6 @@ pic_es_latch_out(pic_t *dev, int irq) ret = !((pic_es_latch_clear(dev, irq) && (dev->irq_latch & (1 << irq))) || !pic_irq_get_request(dev, irq)); - pic_log("pic_es_latch_out(%08X, %i) = %02X\n", (uint32_t) (uintptr_t) dev, irq, ret); return ret; } @@ -701,7 +710,6 @@ pic_es_latch_nor(pic_t *dev, int irq) ret = !(pic_es_latch_out(dev, irq) || picint_is_level(irq)); - pic_log("pic_es_latch_nor(%08X, %i) = %02X\n", (uint32_t) (uintptr_t) dev, irq, ret); return ret; } @@ -712,7 +720,6 @@ pic_irq_request_nor(pic_t *dev, int irq) ret = !(pic_es_latch_nor(dev, irq) || !pic_irq_get_request(dev, irq)); - pic_log("pic_irq_request_nor(%08X, %i) = %02X\n", (uint32_t) (uintptr_t) dev, irq, ret); return ret; } @@ -721,12 +728,8 @@ pic_update_request(pic_t *dev, int irq) { dev->irr &= ~(1 << irq); - if (dev->flags & PIC_FREEZE) { - pic_log("pic_update_request(%08X, %i): FREEZE#\n", (uint32_t) (uintptr_t) dev, irq); - } else { + if (!(dev->flags & PIC_FREEZE)) dev->irr |= (pic_irq_request_nor(dev, irq) << irq); - pic_log("pic_update_request(%08X, %i): IRR = %02X\n", (uint32_t) (uintptr_t) dev, irq, dev->irr); - } } static void @@ -736,8 +739,6 @@ pic_update_irr(pic_t *dev, uint16_t num) if (num & (1 << i)) pic_update_request(dev, i); } - - pic_log("IRQ %04x: IRR now: %02X\n", num, dev->irr); } void @@ -792,8 +793,7 @@ picint_common(uint16_t num, int level, int set, uint8_t *irq_state) pic_update_irr(&pic, num & 0x00ff); } - if (!(pic.flags & PIC_FREEZE) && !(pic2.flags & PIC_FREEZE)) - update_pending(); + update_pending(); } static void @@ -818,7 +818,7 @@ pic_irq_ack_read(pic_t *dev, int phase) if (dev != NULL) { if (phase == 0) { - pic_acknowledge(dev); + pic_acknowledge(dev, 0); if (slave) dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase); else @@ -850,6 +850,9 @@ pic_irq_ack_read(pic_t *dev, int phase) return dev->data_bus; } +/* 808x: Update the requests for all interrupts since any of them + could have arrived during the freeze. */ + uint8_t pic_irq_ack(void) { @@ -873,11 +876,11 @@ pic_irq_ack(void) /* Needed for Xi8088. */ if (pic.flags & PIC_SLAVE_PENDING) { pic2.flags &= ~PIC_FREEZE; - pic_update_request(&pic2, pic2.interrupt & 0x07); + pic_update_irr(&pic2, num & 0x00ff); pic2.interrupt = 0x17; } pic.flags &= ~(PIC_SLAVE_PENDING | PIC_FREEZE); - pic_update_request(&pic, pic.interrupt & 0x07); + pic_update_irr(&pic, num & 0x00ff); pic.interrupt = 0x17; update_pending(); } @@ -885,6 +888,9 @@ pic_irq_ack(void) return ret; } +/* 286+: Only update the request for the pending interrupt as it is + impossible that any other interrupt has arrived during the + freeze. */ int picinterrupt(void) {