mirror of https://gitee.com/openkylin/qemu.git
hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters
The MPS2 FPGAIO block includes some simple free-running counters. Implement these. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20180820141116.9118-2-peter.maydell@linaro.org
This commit is contained in:
parent
299953b989
commit
a1982f90a4
|
@ -22,6 +22,7 @@
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "hw/registerfields.h"
|
#include "hw/registerfields.h"
|
||||||
#include "hw/misc/mps2-fpgaio.h"
|
#include "hw/misc/mps2-fpgaio.h"
|
||||||
|
#include "qemu/timer.h"
|
||||||
|
|
||||||
REG32(LED0, 0)
|
REG32(LED0, 0)
|
||||||
REG32(BUTTON, 8)
|
REG32(BUTTON, 8)
|
||||||
|
@ -32,10 +33,21 @@ REG32(PRESCALE, 0x1c)
|
||||||
REG32(PSCNTR, 0x20)
|
REG32(PSCNTR, 0x20)
|
||||||
REG32(MISC, 0x4c)
|
REG32(MISC, 0x4c)
|
||||||
|
|
||||||
|
static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq)
|
||||||
|
{
|
||||||
|
return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
|
||||||
|
{
|
||||||
|
return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
|
static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
|
||||||
{
|
{
|
||||||
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
|
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
|
||||||
uint64_t r;
|
uint64_t r;
|
||||||
|
int64_t now;
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case A_LED0:
|
case A_LED0:
|
||||||
|
@ -54,10 +66,15 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
|
||||||
r = s->misc;
|
r = s->misc;
|
||||||
break;
|
break;
|
||||||
case A_CLK1HZ:
|
case A_CLK1HZ:
|
||||||
|
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
r = counter_from_tickoff(now, s->clk1hz_tick_offset, 1);
|
||||||
|
break;
|
||||||
case A_CLK100HZ:
|
case A_CLK100HZ:
|
||||||
|
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
|
||||||
|
break;
|
||||||
case A_COUNTER:
|
case A_COUNTER:
|
||||||
case A_PSCNTR:
|
case A_PSCNTR:
|
||||||
/* These are all upcounters of various frequencies. */
|
|
||||||
qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
|
qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
|
||||||
r = 0;
|
r = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -76,6 +93,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
|
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
|
||||||
|
int64_t now;
|
||||||
|
|
||||||
trace_mps2_fpgaio_write(offset, value, size);
|
trace_mps2_fpgaio_write(offset, value, size);
|
||||||
|
|
||||||
|
@ -100,6 +118,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
|
||||||
"MPS2 FPGAIO: MISC control bits unimplemented\n");
|
"MPS2 FPGAIO: MISC control bits unimplemented\n");
|
||||||
s->misc = value;
|
s->misc = value;
|
||||||
break;
|
break;
|
||||||
|
case A_CLK1HZ:
|
||||||
|
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
s->clk1hz_tick_offset = tickoff_from_counter(now, value, 1);
|
||||||
|
break;
|
||||||
|
case A_CLK100HZ:
|
||||||
|
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
"MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
|
"MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
|
||||||
|
@ -116,11 +142,14 @@ static const MemoryRegionOps mps2_fpgaio_ops = {
|
||||||
static void mps2_fpgaio_reset(DeviceState *dev)
|
static void mps2_fpgaio_reset(DeviceState *dev)
|
||||||
{
|
{
|
||||||
MPS2FPGAIO *s = MPS2_FPGAIO(dev);
|
MPS2FPGAIO *s = MPS2_FPGAIO(dev);
|
||||||
|
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
|
|
||||||
trace_mps2_fpgaio_reset();
|
trace_mps2_fpgaio_reset();
|
||||||
s->led0 = 0;
|
s->led0 = 0;
|
||||||
s->prescale = 0;
|
s->prescale = 0;
|
||||||
s->misc = 0;
|
s->misc = 0;
|
||||||
|
s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
|
||||||
|
s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mps2_fpgaio_init(Object *obj)
|
static void mps2_fpgaio_init(Object *obj)
|
||||||
|
@ -133,6 +162,24 @@ static void mps2_fpgaio_init(Object *obj)
|
||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mps2_fpgaio_counters_needed(void *opaque)
|
||||||
|
{
|
||||||
|
/* Currently vmstate.c insists all subsections have a 'needed' function */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription mps2_fpgaio_counters_vmstate = {
|
||||||
|
.name = "mps2-fpgaio/counters",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.needed = mps2_fpgaio_counters_needed,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
|
||||||
|
VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static const VMStateDescription mps2_fpgaio_vmstate = {
|
static const VMStateDescription mps2_fpgaio_vmstate = {
|
||||||
.name = "mps2-fpgaio",
|
.name = "mps2-fpgaio",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
|
@ -142,6 +189,10 @@ static const VMStateDescription mps2_fpgaio_vmstate = {
|
||||||
VMSTATE_UINT32(prescale, MPS2FPGAIO),
|
VMSTATE_UINT32(prescale, MPS2FPGAIO),
|
||||||
VMSTATE_UINT32(misc, MPS2FPGAIO),
|
VMSTATE_UINT32(misc, MPS2FPGAIO),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
.subsections = (const VMStateDescription*[]) {
|
||||||
|
&mps2_fpgaio_counters_vmstate,
|
||||||
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,10 @@ typedef struct {
|
||||||
uint32_t misc;
|
uint32_t misc;
|
||||||
|
|
||||||
uint32_t prescale_clk;
|
uint32_t prescale_clk;
|
||||||
|
|
||||||
|
/* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was zero */
|
||||||
|
int64_t clk1hz_tick_offset;
|
||||||
|
int64_t clk100hz_tick_offset;
|
||||||
} MPS2FPGAIO;
|
} MPS2FPGAIO;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue