mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 20:03:37 +08:00
sparc escc IUS improvements (SunOS 4.1.4 fix)
According to scc_escc_um.pdf: - Reset Highest IUS must update irq status to allow processing of the next priority interrupt. - rx interrupt has always higher priority than tx on same channel The documentation only explicitly says that Reset Highest IUS command (0x38) clears IUS bits, not that it clears the corresponding interrupt too, so don't clear interrupts on this command. The patch allows SunOS 4.1.4 to use the serial ports Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
68c18d1ccf
commit
9fc391f8b5
56
hw/escc.c
56
hw/escc.c
@ -65,6 +65,8 @@
|
||||
* 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented
|
||||
* serial mouse queue.
|
||||
* Implemented serial mouse protocol.
|
||||
*
|
||||
* 2010-May-23 Artyom Tarasenko: Reworked IUS logic
|
||||
*/
|
||||
|
||||
#ifdef DEBUG_SERIAL
|
||||
@ -279,7 +281,7 @@ static uint32_t get_queue(void *opaque)
|
||||
|
||||
static int escc_update_irq_chn(ChannelState *s)
|
||||
{
|
||||
if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
|
||||
if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
|
||||
// tx ints enabled, pending
|
||||
((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
|
||||
((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
|
||||
@ -342,24 +344,22 @@ static void escc_reset(DeviceState *d)
|
||||
static inline void set_rxint(ChannelState *s)
|
||||
{
|
||||
s->rxint = 1;
|
||||
if (!s->txint_under_svc) {
|
||||
s->rxint_under_svc = 1;
|
||||
if (s->chn == chn_a) {
|
||||
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
|
||||
s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
|
||||
else
|
||||
s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
|
||||
} else {
|
||||
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
|
||||
s->rregs[R_IVEC] = IVEC_HIRXINTB;
|
||||
else
|
||||
s->rregs[R_IVEC] = IVEC_LORXINTB;
|
||||
}
|
||||
}
|
||||
if (s->chn == chn_a)
|
||||
/* XXX: missing daisy chainnig: chn_b rx should have a lower priority
|
||||
than chn_a rx/tx/special_condition service*/
|
||||
s->rxint_under_svc = 1;
|
||||
if (s->chn == chn_a) {
|
||||
s->rregs[R_INTR] |= INTR_RXINTA;
|
||||
else
|
||||
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
|
||||
s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
|
||||
else
|
||||
s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
|
||||
} else {
|
||||
s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
|
||||
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
|
||||
s->rregs[R_IVEC] = IVEC_HIRXINTB;
|
||||
else
|
||||
s->rregs[R_IVEC] = IVEC_LORXINTB;
|
||||
}
|
||||
escc_update_irq(s);
|
||||
}
|
||||
|
||||
@ -369,19 +369,17 @@ static inline void set_txint(ChannelState *s)
|
||||
if (!s->rxint_under_svc) {
|
||||
s->txint_under_svc = 1;
|
||||
if (s->chn == chn_a) {
|
||||
s->rregs[R_INTR] |= INTR_TXINTA;
|
||||
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
|
||||
s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
|
||||
else
|
||||
s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
|
||||
} else {
|
||||
s->rregs[R_IVEC] = IVEC_TXINTB;
|
||||
s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
|
||||
}
|
||||
}
|
||||
if (s->chn == chn_a)
|
||||
s->rregs[R_INTR] |= INTR_TXINTA;
|
||||
else
|
||||
s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
|
||||
escc_update_irq(s);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void clr_rxint(ChannelState *s)
|
||||
@ -417,6 +415,7 @@ static inline void clr_txint(ChannelState *s)
|
||||
s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
|
||||
s->rregs[R_INTR] &= ~INTR_TXINTA;
|
||||
} else {
|
||||
s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
|
||||
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
|
||||
s->rregs[R_IVEC] = IVEC_HINOINT;
|
||||
else
|
||||
@ -515,10 +514,15 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
clr_txint(s);
|
||||
break;
|
||||
case CMD_CLR_IUS:
|
||||
if (s->rxint_under_svc)
|
||||
clr_rxint(s);
|
||||
else if (s->txint_under_svc)
|
||||
clr_txint(s);
|
||||
if (s->rxint_under_svc) {
|
||||
s->rxint_under_svc = 0;
|
||||
if (s->txint) {
|
||||
set_txint(s);
|
||||
}
|
||||
} else if (s->txint_under_svc) {
|
||||
s->txint_under_svc = 0;
|
||||
}
|
||||
escc_update_irq(s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user