PIC reads now return IRR by default, fixes #1101.
This commit is contained in:
@@ -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
116
src/pic.c
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user