18
#include "qemu/osdep.h"
20
#include "qemu/module.h"
21
#include "qapi/error.h"
24
#include "migration/vmstate.h"
25
#include "hw/registerfields.h"
26
#include "hw/misc/mps2-fpgaio.h"
27
#include "hw/misc/led.h"
28
#include "hw/qdev-properties.h"
29
#include "qemu/timer.h"
42
static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq)
44
return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND);
47
static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
49
return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
52
static void resync_counter(MPS2FPGAIO *s)
59
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
60
int64_t elapsed = now - s->pscntr_sync_ticks;
66
uint64_t ticks = muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_SECOND);
76
} else if (ticks < s->pscntr) {
80
if (s->prescale == 0) {
86
s->counter += ticks - s->pscntr;
108
uint64_t y = ticks - s->pscntr + s->prescale;
109
s->pscntr = s->prescale - (y % (s->prescale + 1));
110
s->counter += y / (s->prescale + 1);
119
s->pscntr_sync_ticks += muldiv64(ticks, NANOSECONDS_PER_SECOND,
123
static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
125
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
134
if (!s->has_dbgctrl) {
152
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
153
r = counter_from_tickoff(now, s->clk1hz_tick_offset, 1);
156
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
157
r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
168
if (!s->has_switches) {
176
qemu_log_mask(LOG_GUEST_ERROR,
177
"MPS2 FPGAIO read: bad offset %x\n", (int) offset);
182
trace_mps2_fpgaio_read(offset, r, size);
186
static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
189
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
192
trace_mps2_fpgaio_write(offset, value, size);
196
if (s->num_leds != 0) {
199
s->led0 = value & MAKE_64BIT_MASK(0, s->num_leds);
200
for (i = 0; i < s->num_leds; i++) {
201
led_set_state(s->led[i], value & (1 << i));
206
if (!s->has_dbgctrl) {
209
qemu_log_mask(LOG_UNIMP,
210
"MPS2 FPGAIO: DBGCTRL unimplemented\n");
222
qemu_log_mask(LOG_UNIMP,
223
"MPS2 FPGAIO: MISC control bits unimplemented\n");
227
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
228
s->clk1hz_tick_offset = tickoff_from_counter(now, value, 1);
231
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
232
s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
244
qemu_log_mask(LOG_GUEST_ERROR,
245
"MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
250
static const MemoryRegionOps mps2_fpgaio_ops = {
251
.read = mps2_fpgaio_read,
252
.write = mps2_fpgaio_write,
253
.endianness = DEVICE_LITTLE_ENDIAN,
256
static void mps2_fpgaio_reset(DeviceState *dev)
258
MPS2FPGAIO *s = MPS2_FPGAIO(dev);
259
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
261
trace_mps2_fpgaio_reset();
265
s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
266
s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
269
s->pscntr_sync_ticks = now;
271
for (size_t i = 0; i < s->num_leds; i++) {
272
device_cold_reset(DEVICE(s->led[i]));
276
static void mps2_fpgaio_init(Object *obj)
278
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
279
MPS2FPGAIO *s = MPS2_FPGAIO(obj);
281
memory_region_init_io(&s->iomem, obj, &mps2_fpgaio_ops, s,
282
"mps2-fpgaio", 0x1000);
283
sysbus_init_mmio(sbd, &s->iomem);
286
static void mps2_fpgaio_realize(DeviceState *dev, Error **errp)
288
MPS2FPGAIO *s = MPS2_FPGAIO(dev);
291
if (s->num_leds > MPS2FPGAIO_MAX_LEDS) {
292
error_setg(errp, "num-leds cannot be greater than %d",
293
MPS2FPGAIO_MAX_LEDS);
297
for (i = 0; i < s->num_leds; i++) {
298
g_autofree char *ledname = g_strdup_printf("USERLED%d", i);
299
s->led[i] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
300
LED_COLOR_GREEN, ledname);
304
static const VMStateDescription mps2_fpgaio_vmstate = {
305
.name = "mps2-fpgaio",
307
.minimum_version_id = 3,
308
.fields = (const VMStateField[]) {
309
VMSTATE_UINT32(led0, MPS2FPGAIO),
310
VMSTATE_UINT32(prescale, MPS2FPGAIO),
311
VMSTATE_UINT32(misc, MPS2FPGAIO),
312
VMSTATE_UINT32(dbgctrl, MPS2FPGAIO),
313
VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
314
VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
315
VMSTATE_UINT32(counter, MPS2FPGAIO),
316
VMSTATE_UINT32(pscntr, MPS2FPGAIO),
317
VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO),
318
VMSTATE_END_OF_LIST()
322
static Property mps2_fpgaio_properties[] = {
324
DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000),
326
DEFINE_PROP_UINT32("num-leds", MPS2FPGAIO, num_leds, 2),
327
DEFINE_PROP_BOOL("has-switches", MPS2FPGAIO, has_switches, false),
328
DEFINE_PROP_BOOL("has-dbgctrl", MPS2FPGAIO, has_dbgctrl, false),
329
DEFINE_PROP_END_OF_LIST(),
332
static void mps2_fpgaio_class_init(ObjectClass *klass, void *data)
334
DeviceClass *dc = DEVICE_CLASS(klass);
336
dc->vmsd = &mps2_fpgaio_vmstate;
337
dc->realize = mps2_fpgaio_realize;
338
dc->reset = mps2_fpgaio_reset;
339
device_class_set_props(dc, mps2_fpgaio_properties);
342
static const TypeInfo mps2_fpgaio_info = {
343
.name = TYPE_MPS2_FPGAIO,
344
.parent = TYPE_SYS_BUS_DEVICE,
345
.instance_size = sizeof(MPS2FPGAIO),
346
.instance_init = mps2_fpgaio_init,
347
.class_init = mps2_fpgaio_class_init,
350
static void mps2_fpgaio_register_types(void)
352
type_register_static(&mps2_fpgaio_info);
355
type_init(mps2_fpgaio_register_types);