qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Alistair Francis <alistair23@gmail.com>
To: Peter Maydell <peter.maydell@linaro.org>
Cc: qemu-arm <qemu-arm@nongnu.org>,
	"qemu-devel@nongnu.org Developers" <qemu-devel@nongnu.org>,
	Patch Tracking <patches@linaro.org>
Subject: Re: [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER
Date: Mon, 30 Jul 2018 15:09:48 -0700	[thread overview]
Message-ID: <CAKmqyKO2oUfSoiqWAA_rOWRzjgHE8om_X9sMuDdcZjgkE3q2Gg@mail.gmail.com> (raw)
In-Reply-To: <20180730162458.23186-3-peter.maydell@linaro.org>

On Mon, Jul 30, 2018 at 9:24 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> In the MPS2 FPGAIO, PSCNTR is a free-running downcounter with
> a reload value configured via the PRESCALE register, and
> COUNTER counts up by 1 every time PSCNTR reaches zero.
> Implement these counters.
>
> We can just increment the counters migration subsection's
> version ID because we only added it in the previous commit,
> so no released QEMU versions will be using it.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  include/hw/misc/mps2-fpgaio.h |  6 +++
>  hw/misc/mps2-fpgaio.c         | 97 +++++++++++++++++++++++++++++++++--
>  2 files changed, 99 insertions(+), 4 deletions(-)
>
> diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h
> index ec057d38c76..69e265cd4b2 100644
> --- a/include/hw/misc/mps2-fpgaio.h
> +++ b/include/hw/misc/mps2-fpgaio.h
> @@ -37,6 +37,12 @@ typedef struct {
>      uint32_t prescale;
>      uint32_t misc;
>
> +    /* QEMU_CLOCK_VIRTUAL time at which counter and pscntr were last synced */
> +    int64_t pscntr_sync_ticks;
> +    /* Values of COUNTER and PSCNTR at time pscntr_sync_ticks */
> +    uint32_t counter;
> +    uint32_t pscntr;
> +
>      uint32_t prescale_clk;
>
>      /* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was zero */
> diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
> index bbc28f641f0..5cf10ebd66a 100644
> --- a/hw/misc/mps2-fpgaio.c
> +++ b/hw/misc/mps2-fpgaio.c
> @@ -43,6 +43,77 @@ static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
>      return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
>  }
>
> +static void resync_counter(MPS2FPGAIO *s)
> +{
> +    /*
> +     * Update s->counter and s->pscntr to their true current values
> +     * by calculating how many times PSCNTR has ticked since the
> +     * last time we did a resync.
> +     */
> +    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    int64_t elapsed = now - s->pscntr_sync_ticks;
> +
> +    /*
> +     * Round elapsed down to a whole number of PSCNTR ticks, so we don't
> +     * lose time if we do multiple resyncs in a single tick.
> +     */
> +    uint64_t ticks = muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_SECOND);
> +
> +    /*
> +     * Work out what PSCNTR and COUNTER have moved to. We assume that
> +     * PSCNTR reloads from PRESCALE one tick-period after it hits zero,
> +     * and that COUNTER increments at the same moment.
> +     */
> +    if (ticks == 0) {
> +        /* We haven't ticked since the last time we were asked */
> +        return;
> +    } else if (ticks < s->pscntr) {
> +        /* We haven't yet reached zero, just reduce the PSCNTR */
> +        s->pscntr -= ticks;
> +    } else {
> +        if (s->prescale == 0) {
> +            /*
> +             * If the reload value is zero then the PSCNTR will stick
> +             * at zero once it reaches it, and so we will increment
> +             * COUNTER every tick after that.
> +             */
> +            s->counter += ticks - s->pscntr;
> +            s->pscntr = 0;
> +        } else {
> +            /*
> +             * This is the complicated bit. This ASCII art diagram gives an
> +             * example with PRESCALE==5 PSCNTR==7:
> +             *
> +             * ticks  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
> +             * PSCNTR 7  6  5  4  3  2  1  0  5  4  3  2  1  0  5
> +             * cinc                           1                 2
> +             * y            0  1  2  3  4  5  6  7  8  9 10 11 12
> +             * x            0  1  2  3  4  5  0  1  2  3  4  5  0
> +             *
> +             * where x = y % (s->prescale + 1)
> +             * and so PSCNTR = s->prescale - x
> +             * and COUNTER is incremented by y / (s->prescale + 1)
> +             *
> +             * The case where PSCNTR < PRESCALE works out the same,
> +             * though we must be careful to calculate y as 64-bit unsigned
> +             * for all parts of the expression.
> +             * y < 0 is not possible because that implies ticks < s->pscntr.
> +             */
> +            uint64_t y = ticks - s->pscntr + s->prescale;
> +            s->pscntr = s->prescale - (y % (s->prescale + 1));
> +            s->counter += y / (s->prescale + 1);
> +        }
> +    }
> +
> +    /*
> +     * Only advance the sync time to the timestamp of the last PSCNTR tick,
> +     * not all the way to 'now', so we don't lose time if we do multiple
> +     * resyncs in a single tick.
> +     */
> +    s->pscntr_sync_ticks += muldiv64(ticks, NANOSECONDS_PER_SECOND,
> +                                     s->prescale_clk);
> +}
> +
>  static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
>  {
>      MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
> @@ -74,9 +145,12 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
>          r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
>          break;
>      case A_COUNTER:
> +        resync_counter(s);
> +        r = s->counter;
> +        break;
>      case A_PSCNTR:
> -        qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
> -        r = 0;
> +        resync_counter(s);
> +        r = s->pscntr;
>          break;
>      default:
>          qemu_log_mask(LOG_GUEST_ERROR,
> @@ -107,6 +181,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
>          s->led0 = value & 0x3;
>          break;
>      case A_PRESCALE:
> +        resync_counter(s);
>          s->prescale = value;
>          break;
>      case A_MISC:
> @@ -126,6 +201,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
>          now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>          s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
>          break;
> +    case A_COUNTER:
> +        resync_counter(s);
> +        s->counter = value;
> +        break;
> +    case A_PSCNTR:
> +        resync_counter(s);
> +        s->pscntr = value;
> +        break;
>      default:
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
> @@ -150,6 +233,9 @@ static void mps2_fpgaio_reset(DeviceState *dev)
>      s->misc = 0;
>      s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
>      s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
> +    s->counter = 0;
> +    s->pscntr = 0;
> +    s->pscntr_sync_ticks = now;
>  }
>
>  static void mps2_fpgaio_init(Object *obj)
> @@ -170,12 +256,15 @@ static bool mps2_fpgaio_counters_needed(void *opaque)
>
>  static const VMStateDescription mps2_fpgaio_counters_vmstate = {
>      .name = "mps2-fpgaio/counters",
> -    .version_id = 1,
> -    .minimum_version_id = 1,
> +    .version_id = 2,
> +    .minimum_version_id = 2,
>      .needed = mps2_fpgaio_counters_needed,
>      .fields = (VMStateField[]) {
>          VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
>          VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
> +        VMSTATE_UINT32(counter, MPS2FPGAIO),
> +        VMSTATE_UINT32(pscntr, MPS2FPGAIO),
> +        VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO),
>          VMSTATE_END_OF_LIST()
>      }
>  };
> --
> 2.17.1
>
>

  reply	other threads:[~2018-07-30 22:10 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-30 16:24 [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer Peter Maydell
2018-07-30 16:24 ` [Qemu-devel] [PATCH 1/5] hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters Peter Maydell
2018-07-30 16:24 ` [Qemu-devel] [PATCH 2/5] hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER Peter Maydell
2018-07-30 22:09   ` Alistair Francis [this message]
2018-07-30 16:24 ` [Qemu-devel] [PATCH 3/5] hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module Peter Maydell
2018-07-30 16:24 ` [Qemu-devel] [PATCH 4/5] hw/arm/iotkit: Wire up the dualtimer Peter Maydell
2018-07-30 16:24 ` [Qemu-devel] [PATCH 5/5] hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511 Peter Maydell
2018-07-30 21:00 ` [Qemu-devel] [PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer no-reply
2018-07-31  5:26 ` no-reply
2018-08-16 12:20 ` Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAKmqyKO2oUfSoiqWAA_rOWRzjgHE8om_X9sMuDdcZjgkE3q2Gg@mail.gmail.com \
    --to=alistair23@gmail.com \
    --cc=patches@linaro.org \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).