qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] escc: update transmit status bits when switching to async mo


From: Peter Maydell
Subject: Re: [PATCH] escc: update transmit status bits when switching to async mode
Date: Tue, 2 Nov 2021 14:46:58 +0000

On Mon, 1 Nov 2021 at 20:31, Mark Cave-Ayland
<mark.cave-ayland@ilande.co.uk> wrote:
>
> The recent ESCC reset changes cause a regression when attemping to use a real
> SS-5 Sun PROM instead of OpenBIOS. The Sun PROM doesn't send an explicit reset
> command to the ESCC but gets stuck in a loop probing the keyboard waiting for
> STATUS_TXEMPTY to be set in R_STATUS followed by SPEC_ALLSENT in R_SPEC.
>
> Reading through the ESCC datasheet again indicates that SPEC_ALLSENT is 
> updated
> when a write to W_TXCTRL1 selects async mode, or remains high if sync mode is
> selected. Whilst there is no explicit mention of STATUS_TXEMPTY, the ESCC 
> device
> emulation always updates these two register bits together when transmitting 
> data.

My reading of the spec is that this isn't the right behaviour. I think
what we ought to have is:
 * in both async and sync mode, TXEMPTY tracks the tx fifo status
   (which I think means "set if there is any space in it", contrary to
   what the name of the bit implies)
 * in sync mode, ALLSENT is always high
 * in async mode, ALLSENT reads the same as TXEMPTY (for us, since we have
   no extra delay between "data left the FIFO" and "data actually on the wire")
 * in sync mode TXEMPTY is apparently also set "when the last bit of the CRC
   has cleared the transmit shift register". I don't think I really understand
   what sync mode TXEMPTY does overall, but clearly it is not "always 0".

> Add extra logic to update both transmit status bits accordingly when writing 
> to
> W_TXCTRL1 which enables the Sun PROM to initialise and boot again under QEMU.
>
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/char/escc.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/hw/char/escc.c b/hw/char/escc.c
> index 0fce4f6324..b33cdc229f 100644
> --- a/hw/char/escc.c
> +++ b/hw/char/escc.c
> @@ -575,6 +575,18 @@ static void escc_mem_write(void *opaque, hwaddr addr,
>              s->wregs[s->reg] = val;
>              break;
>          case W_TXCTRL1:
> +            s->wregs[s->reg] = val;
> +            if (val & TXCTRL1_STPMSK) {
> +                ESCCSERIOQueue *q = &s->queue;
> +                if (s->type == escc_serial || q->count == 0) {
> +                    s->rregs[R_STATUS] |= STATUS_TXEMPTY;
> +                    s->rregs[R_SPEC] |= SPEC_ALLSENT;
> +                }

...should there be an 'else' clause here which clears these
bits if we are now in async mode and the tx queue is not empty ?

> +            } else {
> +                s->rregs[R_STATUS] &= ~STATUS_TXEMPTY;
> +                s->rregs[R_SPEC] |= SPEC_ALLSENT;
> +            }

Something is a bit odd with how we currently handle both these bits
For SPEC_ALLSENT:
 * it is zero on power-on
 * soft-reset leaves it unchanged
 * we set it on a write to SERIAL_DATA
 * this new code adds two places where we set it
 * but there is nowhere where we clear it

For STATUS_TXEMPTY:
 * it is set on power-on and soft-reset
 * it is set on write to SERIAL_DATA
 * it is never cleared

Shouldn't we be clearing these bits somewhere ?

> +            /* fallthrough */
>          case W_TXCTRL2:
>              s->wregs[s->reg] = val;
>              escc_update_parameters(s);

At this point all the "fallthrough" is doing is (1) repeat the
setting of s->wregs[s->reg] and (2) call escc_update_parameters().
So I think it would be clearer to instead make the two cases
completely separate, and have
   escc_update_parameters(s);
   break;

instead of the /* fallthrough */.

-- PMM



reply via email to

[Prev in Thread] Current Thread [Next in Thread]