PIC reads now return IRR by default, fixes #1101.

This commit is contained in:
OBattler
2021-03-29 23:46:22 +02:00
parent 0e206a977e
commit ff5a779122
2 changed files with 79 additions and 48 deletions

View File

@@ -25,6 +25,7 @@ typedef struct pic {
ocw3, int_pending, is_master, elcr, ocw3, int_pending, is_master, elcr,
state, ack_bytes, priority, special_mask_mode, state, ack_bytes, priority, special_mask_mode,
auto_eoi_rotate, interrupt, lines, data_bus; auto_eoi_rotate, interrupt, lines, data_bus;
uint32_t at;
struct pic *slaves[8]; struct pic *slaves[8];
} pic_t; } pic_t;

116
src/pic.c
View File

@@ -55,6 +55,10 @@ static int shadow = 0, elcr_enabled = 0,
tmr_inited = 0, latched = 0; tmr_inited = 0, latched = 0;
static void (*update_pending)(void);
#ifdef ENABLE_PIC_LOG #ifdef ENABLE_PIC_LOG
int pic_do_log = ENABLE_PIC_LOG; int pic_do_log = ENABLE_PIC_LOG;
@@ -160,8 +164,18 @@ static __inline int
find_best_interrupt(pic_t *dev) find_best_interrupt(pic_t *dev)
{ {
uint8_t b, s; uint8_t b, s;
uint8_t intr;
int i, j; int i, j;
int is_at, ret = -1; int ret = -1;
#ifdef READ_LATCH
if (dev->interrupt != 0x17) {
/* We have an IRQ already latched, do not update status until it is unlatched in order to
avoid IRQ loss. */
ret = dev->interrupt;
return ret;
}
#endif
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
j = (i + dev->priority) & 7; j = (i + dev->priority) & 7;
@@ -178,22 +192,35 @@ find_best_interrupt(pic_t *dev)
break; break;
} }
dev->interrupt = (ret == -1) ? 7 : ret; intr = dev->interrupt = (ret == -1) ? 0x17 : ret;
is_at = IS_AT(machine); if (dev->at && (ret != 1)) {
if (is_at && (ret != -1) && (cpu_fast_off_flags & (1 << dev->interrupt))) if (dev == &pic2)
intr += 8;
if (cpu_fast_off_flags & (1 << intr))
cpu_fast_off_count = cpu_fast_off_val + 1; cpu_fast_off_count = cpu_fast_off_val + 1;
}
return ret; return ret;
} }
static __inline void static __inline void
pic_update_pending(void) pic_update_pending_xt(void)
{ {
int is_at = IS_AT(machine); if (find_best_interrupt(&pic) != -1) {
latched++;
if (latched == 1)
timer_on_auto(&pic_timer, 0.35);
} else if (latched == 0)
pic.int_pending = 0;
}
if (is_at) {
static __inline void
pic_update_pending_at(void)
{
pic2.int_pending = (find_best_interrupt(&pic2) != -1); pic2.int_pending = (find_best_interrupt(&pic2) != -1);
if (pic2.int_pending) if (pic2.int_pending)
@@ -202,16 +229,6 @@ pic_update_pending(void)
pic.irr &= ~(1 << pic2.icw3); pic.irr &= ~(1 << pic2.icw3);
pic.int_pending = (find_best_interrupt(&pic) != -1); pic.int_pending = (find_best_interrupt(&pic) != -1);
return;
}
if (find_best_interrupt(&pic) != -1) {
latched++;
if (latched == 1)
timer_on_auto(&pic_timer, is_at ? 0.3 : 0.35);
/* 300 ms on AT+, 350 ns on PC/PCjr/XT */
} else if (latched == 0)
pic.int_pending = 0;
} }
@@ -237,6 +254,7 @@ pic_reset()
memset(&pic2, 0, sizeof(pic_t)); memset(&pic2, 0, sizeof(pic_t));
pic.is_master = 1; pic.is_master = 1;
pic.interrupt = pic2.interrupt = 0x17;
if (is_at) if (is_at)
pic.slaves[2] = &pic2; pic.slaves[2] = &pic2;
@@ -246,6 +264,9 @@ pic_reset()
memset(&pic_timer, 0x00, sizeof(pc_timer_t)); memset(&pic_timer, 0x00, sizeof(pc_timer_t));
timer_add(&pic_timer, pic_callback, &pic, 0); timer_add(&pic_timer, pic_callback, &pic, 0);
tmr_inited = 1; tmr_inited = 1;
update_pending = is_at ? pic_update_pending_at : pic_update_pending_xt;
pic.at = pic2.at = is_at;
} }
@@ -276,7 +297,7 @@ picint_is_level(int irq)
static void static void
pic_acknowledge(pic_t *dev) pic_acknowledge(pic_t *dev)
{ {
int pic_int = dev->interrupt; int pic_int = dev->interrupt & 7;
int pic_int_num = 1 << pic_int; int pic_int_num = 1 << pic_int;
dev->isr |= pic_int_num; dev->isr |= pic_int_num;
@@ -319,7 +340,7 @@ pic_action(pic_t *dev, uint8_t irq, uint8_t eoi, uint8_t rotate)
if (rotate) if (rotate)
dev->priority = (irq + 1) & 7; dev->priority = (irq + 1) & 7;
pic_update_pending(); update_pending();
} }
} }
@@ -374,12 +395,16 @@ pic_read(uint16_t addr, void *priv)
} }
} else { } else {
/* Standard 8259 PIC read */ /* Standard 8259 PIC read */
#ifndef UNDEFINED_READ
/* Put the IRR on to the data bus by default until the real PIC is probed. */
dev->data_bus = dev->irr;
#endif
if (dev->ocw3 & 0x04) { if (dev->ocw3 & 0x04) {
if (dev->int_pending) { if (dev->int_pending) {
dev->data_bus = 0x80 | (dev->interrupt & 7); dev->data_bus = 0x80 | (dev->interrupt & 7);
pic_acknowledge(dev); pic_acknowledge(dev);
dev->int_pending = 0; dev->int_pending = 0;
pic_update_pending(); update_pending();
} else } else
dev->data_bus = 0x00; dev->data_bus = 0x00;
dev->ocw3 &= ~0x04; dev->ocw3 &= ~0x04;
@@ -388,8 +413,10 @@ pic_read(uint16_t addr, void *priv)
else if (dev->ocw3 & 0x02) { else if (dev->ocw3 & 0x02) {
if (dev->ocw3 & 0x01) if (dev->ocw3 & 0x01)
dev->data_bus = dev->isr; dev->data_bus = dev->isr;
#ifdef UNDEFINED_READ
else else
dev->data_bus = dev->irr; dev->data_bus = dev->irr;
#endif
} }
/* If A0 = 0, VIA shadow is disabled, and poll mode is disabled, /* If A0 = 0, VIA shadow is disabled, and poll mode is disabled,
simply read whatever is currently on the data bus. */ simply read whatever is currently on the data bus. */
@@ -429,7 +456,7 @@ pic_write(uint16_t addr, uint8_t val, void *priv)
break; break;
case STATE_NONE: case STATE_NONE:
dev->imr = val; dev->imr = val;
pic_update_pending(); update_pending();
break; break;
} }
} else { } else {
@@ -447,9 +474,10 @@ pic_write(uint16_t addr, uint8_t val, void *priv)
dev->imr = dev->isr = 0x00; dev->imr = dev->isr = 0x00;
dev->ack_bytes = dev->priority = 0x00; dev->ack_bytes = dev->priority = 0x00;
dev->auto_eoi_rotate = dev->special_mask_mode = 0x00; dev->auto_eoi_rotate = dev->special_mask_mode = 0x00;
dev->interrupt = dev->int_pending = 0x00; dev->interrupt = 0x17;
dev->int_pending = 0x00;
dev->state = STATE_ICW2; dev->state = STATE_ICW2;
pic_update_pending(); update_pending();
} else if (val & 0x08) { } else if (val & 0x08) {
dev->ocw3 = val; dev->ocw3 = val;
if (dev->ocw3 & 0x40) if (dev->ocw3 & 0x40)
@@ -494,11 +522,8 @@ void
picint_common(uint16_t num, int level, int set) picint_common(uint16_t num, int level, int set)
{ {
int i, raise; int i, raise;
int is_at;
uint8_t b, slaves = 0; uint8_t b, slaves = 0;
is_at = IS_AT(machine);
/* Make sure to ignore all slave IRQ's, and in case of AT+, /* Make sure to ignore all slave IRQ's, and in case of AT+,
translate IRQ 2 to IRQ 9. */ translate IRQ 2 to IRQ 9. */
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
@@ -510,7 +535,7 @@ picint_common(uint16_t num, int level, int set)
if (raise) { if (raise) {
num &= ~b; num &= ~b;
if (is_at && (i == 2)) if (pic.at && (i == 2))
num |= (1 << 9); num |= (1 << 9);
} }
} }
@@ -553,7 +578,7 @@ picint_common(uint16_t num, int level, int set)
} }
} }
pic_update_pending(); update_pending();
} }
@@ -588,33 +613,34 @@ pic_i86_mode(pic_t *dev)
static uint8_t static uint8_t
pic_irq_ack_read(pic_t *dev, int phase) pic_irq_ack_read(pic_t *dev, int phase)
{ {
uint8_t intr = dev->interrupt & 7;
pic_log(" pic_irq_ack_read(%08X, %i)\n", dev, phase); pic_log(" pic_irq_ack_read(%08X, %i)\n", dev, phase);
if (dev != NULL) { if (dev != NULL) {
if (phase == 0) { if (phase == 0) {
pic_acknowledge(dev); pic_acknowledge(dev);
if (pic_slave_on(dev, dev->interrupt)) if (pic_slave_on(dev, intr))
dev->data_bus = pic_irq_ack_read(dev->slaves[dev->interrupt], phase); dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
else else
dev->data_bus = pic_i86_mode(dev) ? 0xff : 0xcd; dev->data_bus = pic_i86_mode(dev) ? 0xff : 0xcd;
} else if (pic_i86_mode(dev)) { } else if (pic_i86_mode(dev)) {
dev->int_pending = 0; dev->int_pending = 0;
if (pic_slave_on(dev, dev->interrupt)) if (pic_slave_on(dev, intr))
dev->data_bus = pic_irq_ack_read(dev->slaves[dev->interrupt], phase); dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
else else
dev->data_bus = dev->interrupt + (dev->icw2 & 0xf8); dev->data_bus = intr + (dev->icw2 & 0xf8);
pic_auto_non_specific_eoi(dev); pic_auto_non_specific_eoi(dev);
} else if (phase == 1) { } else if (phase == 1) {
if (pic_slave_on(dev, dev->interrupt)) if (pic_slave_on(dev, intr))
dev->data_bus = pic_irq_ack_read(dev->slaves[dev->interrupt], phase); dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
else if (dev->icw1 & 0x04) else if (dev->icw1 & 0x04)
dev->data_bus = (dev->interrupt << 2) + (dev->icw1 & 0xe0); dev->data_bus = (intr << 2) + (dev->icw1 & 0xe0);
else else
dev->data_bus = (dev->interrupt << 3) + (dev->icw1 & 0xc0); dev->data_bus = (intr << 3) + (dev->icw1 & 0xc0);
} else if (phase == 2) { } else if (phase == 2) {
dev->int_pending = 0; dev->int_pending = 0;
if (pic_slave_on(dev, dev->interrupt)) if (pic_slave_on(dev, intr))
dev->data_bus = pic_irq_ack_read(dev->slaves[dev->interrupt], phase); dev->data_bus = pic_irq_ack_read(dev->slaves[intr], phase);
else else
dev->data_bus = dev->icw2; dev->data_bus = dev->icw2;
pic_auto_non_specific_eoi(dev); pic_auto_non_specific_eoi(dev);
@@ -633,8 +659,10 @@ pic_irq_ack(void)
ret = pic_irq_ack_read(&pic, pic.ack_bytes); ret = pic_irq_ack_read(&pic, pic.ack_bytes);
pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3); pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3);
if (pic.ack_bytes == 0) if (pic.ack_bytes == 0) {
pic_update_pending(); pic.interrupt = 0x17;
update_pending();
}
return ret; return ret;
} }
@@ -661,8 +689,10 @@ picinterrupt()
ret = pic_irq_ack_read(&pic, pic.ack_bytes); ret = pic_irq_ack_read(&pic, pic.ack_bytes);
pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3); pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3);
if (pic.ack_bytes == 0) if (pic.ack_bytes == 0) {
pic_update_pending(); pic.interrupt = pic2.interrupt = 0x17;
update_pending();
}
} }
} }