19a52d999SPeter Maydell /* 29a52d999SPeter Maydell * ARM MPS2 AN505 FPGAIO emulation 39a52d999SPeter Maydell * 49a52d999SPeter Maydell * Copyright (c) 2018 Linaro Limited 59a52d999SPeter Maydell * Written by Peter Maydell 69a52d999SPeter Maydell * 79a52d999SPeter Maydell * This program is free software; you can redistribute it and/or modify 89a52d999SPeter Maydell * it under the terms of the GNU General Public License version 2 or 99a52d999SPeter Maydell * (at your option) any later version. 109a52d999SPeter Maydell */ 119a52d999SPeter Maydell 129a52d999SPeter Maydell /* This is a model of the "FPGA system control and I/O" block found 139a52d999SPeter Maydell * in the AN505 FPGA image for the MPS2 devboard. 149a52d999SPeter Maydell * It is documented in AN505: 159a52d999SPeter Maydell * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html 169a52d999SPeter Maydell */ 179a52d999SPeter Maydell 189a52d999SPeter Maydell #include "qemu/osdep.h" 199a52d999SPeter Maydell #include "qemu/log.h" 20*0b8fa32fSMarkus Armbruster #include "qemu/module.h" 219a52d999SPeter Maydell #include "qapi/error.h" 229a52d999SPeter Maydell #include "trace.h" 239a52d999SPeter Maydell #include "hw/sysbus.h" 249a52d999SPeter Maydell #include "hw/registerfields.h" 259a52d999SPeter Maydell #include "hw/misc/mps2-fpgaio.h" 26a1982f90SPeter Maydell #include "qemu/timer.h" 279a52d999SPeter Maydell 289a52d999SPeter Maydell REG32(LED0, 0) 299a52d999SPeter Maydell REG32(BUTTON, 8) 309a52d999SPeter Maydell REG32(CLK1HZ, 0x10) 319a52d999SPeter Maydell REG32(CLK100HZ, 0x14) 329a52d999SPeter Maydell REG32(COUNTER, 0x18) 339a52d999SPeter Maydell REG32(PRESCALE, 0x1c) 349a52d999SPeter Maydell REG32(PSCNTR, 0x20) 359a52d999SPeter Maydell REG32(MISC, 0x4c) 369a52d999SPeter Maydell 37a1982f90SPeter Maydell static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq) 38a1982f90SPeter Maydell { 39a1982f90SPeter Maydell return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND); 40a1982f90SPeter Maydell } 41a1982f90SPeter Maydell 42a1982f90SPeter Maydell static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq) 43a1982f90SPeter Maydell { 44a1982f90SPeter Maydell return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq); 45a1982f90SPeter Maydell } 46a1982f90SPeter Maydell 4793739075SPeter Maydell static void resync_counter(MPS2FPGAIO *s) 4893739075SPeter Maydell { 4993739075SPeter Maydell /* 5093739075SPeter Maydell * Update s->counter and s->pscntr to their true current values 5193739075SPeter Maydell * by calculating how many times PSCNTR has ticked since the 5293739075SPeter Maydell * last time we did a resync. 5393739075SPeter Maydell */ 5493739075SPeter Maydell int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 5593739075SPeter Maydell int64_t elapsed = now - s->pscntr_sync_ticks; 5693739075SPeter Maydell 5793739075SPeter Maydell /* 5893739075SPeter Maydell * Round elapsed down to a whole number of PSCNTR ticks, so we don't 5993739075SPeter Maydell * lose time if we do multiple resyncs in a single tick. 6093739075SPeter Maydell */ 6193739075SPeter Maydell uint64_t ticks = muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_SECOND); 6293739075SPeter Maydell 6393739075SPeter Maydell /* 6493739075SPeter Maydell * Work out what PSCNTR and COUNTER have moved to. We assume that 6593739075SPeter Maydell * PSCNTR reloads from PRESCALE one tick-period after it hits zero, 6693739075SPeter Maydell * and that COUNTER increments at the same moment. 6793739075SPeter Maydell */ 6893739075SPeter Maydell if (ticks == 0) { 6993739075SPeter Maydell /* We haven't ticked since the last time we were asked */ 7093739075SPeter Maydell return; 7193739075SPeter Maydell } else if (ticks < s->pscntr) { 7293739075SPeter Maydell /* We haven't yet reached zero, just reduce the PSCNTR */ 7393739075SPeter Maydell s->pscntr -= ticks; 7493739075SPeter Maydell } else { 7593739075SPeter Maydell if (s->prescale == 0) { 7693739075SPeter Maydell /* 7793739075SPeter Maydell * If the reload value is zero then the PSCNTR will stick 7893739075SPeter Maydell * at zero once it reaches it, and so we will increment 7993739075SPeter Maydell * COUNTER every tick after that. 8093739075SPeter Maydell */ 8193739075SPeter Maydell s->counter += ticks - s->pscntr; 8293739075SPeter Maydell s->pscntr = 0; 8393739075SPeter Maydell } else { 8493739075SPeter Maydell /* 8593739075SPeter Maydell * This is the complicated bit. This ASCII art diagram gives an 8693739075SPeter Maydell * example with PRESCALE==5 PSCNTR==7: 8793739075SPeter Maydell * 8893739075SPeter Maydell * ticks 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 8993739075SPeter Maydell * PSCNTR 7 6 5 4 3 2 1 0 5 4 3 2 1 0 5 9093739075SPeter Maydell * cinc 1 2 9193739075SPeter Maydell * y 0 1 2 3 4 5 6 7 8 9 10 11 12 9293739075SPeter Maydell * x 0 1 2 3 4 5 0 1 2 3 4 5 0 9393739075SPeter Maydell * 9493739075SPeter Maydell * where x = y % (s->prescale + 1) 9593739075SPeter Maydell * and so PSCNTR = s->prescale - x 9693739075SPeter Maydell * and COUNTER is incremented by y / (s->prescale + 1) 9793739075SPeter Maydell * 9893739075SPeter Maydell * The case where PSCNTR < PRESCALE works out the same, 9993739075SPeter Maydell * though we must be careful to calculate y as 64-bit unsigned 10093739075SPeter Maydell * for all parts of the expression. 10193739075SPeter Maydell * y < 0 is not possible because that implies ticks < s->pscntr. 10293739075SPeter Maydell */ 10393739075SPeter Maydell uint64_t y = ticks - s->pscntr + s->prescale; 10493739075SPeter Maydell s->pscntr = s->prescale - (y % (s->prescale + 1)); 10593739075SPeter Maydell s->counter += y / (s->prescale + 1); 10693739075SPeter Maydell } 10793739075SPeter Maydell } 10893739075SPeter Maydell 10993739075SPeter Maydell /* 11093739075SPeter Maydell * Only advance the sync time to the timestamp of the last PSCNTR tick, 11193739075SPeter Maydell * not all the way to 'now', so we don't lose time if we do multiple 11293739075SPeter Maydell * resyncs in a single tick. 11393739075SPeter Maydell */ 11493739075SPeter Maydell s->pscntr_sync_ticks += muldiv64(ticks, NANOSECONDS_PER_SECOND, 11593739075SPeter Maydell s->prescale_clk); 11693739075SPeter Maydell } 11793739075SPeter Maydell 1189a52d999SPeter Maydell static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size) 1199a52d999SPeter Maydell { 1209a52d999SPeter Maydell MPS2FPGAIO *s = MPS2_FPGAIO(opaque); 1219a52d999SPeter Maydell uint64_t r; 122a1982f90SPeter Maydell int64_t now; 1239a52d999SPeter Maydell 1249a52d999SPeter Maydell switch (offset) { 1259a52d999SPeter Maydell case A_LED0: 1269a52d999SPeter Maydell r = s->led0; 1279a52d999SPeter Maydell break; 1289a52d999SPeter Maydell case A_BUTTON: 1299a52d999SPeter Maydell /* User-pressable board buttons. We don't model that, so just return 1309a52d999SPeter Maydell * zeroes. 1319a52d999SPeter Maydell */ 1329a52d999SPeter Maydell r = 0; 1339a52d999SPeter Maydell break; 1349a52d999SPeter Maydell case A_PRESCALE: 1359a52d999SPeter Maydell r = s->prescale; 1369a52d999SPeter Maydell break; 1379a52d999SPeter Maydell case A_MISC: 1389a52d999SPeter Maydell r = s->misc; 1399a52d999SPeter Maydell break; 1409a52d999SPeter Maydell case A_CLK1HZ: 141a1982f90SPeter Maydell now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 142a1982f90SPeter Maydell r = counter_from_tickoff(now, s->clk1hz_tick_offset, 1); 143a1982f90SPeter Maydell break; 1449a52d999SPeter Maydell case A_CLK100HZ: 145a1982f90SPeter Maydell now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 146a1982f90SPeter Maydell r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100); 147a1982f90SPeter Maydell break; 1489a52d999SPeter Maydell case A_COUNTER: 14993739075SPeter Maydell resync_counter(s); 15093739075SPeter Maydell r = s->counter; 15193739075SPeter Maydell break; 1529a52d999SPeter Maydell case A_PSCNTR: 15393739075SPeter Maydell resync_counter(s); 15493739075SPeter Maydell r = s->pscntr; 1559a52d999SPeter Maydell break; 1569a52d999SPeter Maydell default: 1579a52d999SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 1589a52d999SPeter Maydell "MPS2 FPGAIO read: bad offset %x\n", (int) offset); 1599a52d999SPeter Maydell r = 0; 1609a52d999SPeter Maydell break; 1619a52d999SPeter Maydell } 1629a52d999SPeter Maydell 1639a52d999SPeter Maydell trace_mps2_fpgaio_read(offset, r, size); 1649a52d999SPeter Maydell return r; 1659a52d999SPeter Maydell } 1669a52d999SPeter Maydell 1679a52d999SPeter Maydell static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value, 1689a52d999SPeter Maydell unsigned size) 1699a52d999SPeter Maydell { 1709a52d999SPeter Maydell MPS2FPGAIO *s = MPS2_FPGAIO(opaque); 171a1982f90SPeter Maydell int64_t now; 1729a52d999SPeter Maydell 1739a52d999SPeter Maydell trace_mps2_fpgaio_write(offset, value, size); 1749a52d999SPeter Maydell 1759a52d999SPeter Maydell switch (offset) { 1769a52d999SPeter Maydell case A_LED0: 1779a52d999SPeter Maydell /* LED bits [1:0] control board LEDs. We don't currently have 1789a52d999SPeter Maydell * a mechanism for displaying this graphically, so use a trace event. 1799a52d999SPeter Maydell */ 1809a52d999SPeter Maydell trace_mps2_fpgaio_leds(value & 0x02 ? '*' : '.', 1819a52d999SPeter Maydell value & 0x01 ? '*' : '.'); 1829a52d999SPeter Maydell s->led0 = value & 0x3; 1839a52d999SPeter Maydell break; 1849a52d999SPeter Maydell case A_PRESCALE: 18593739075SPeter Maydell resync_counter(s); 1869a52d999SPeter Maydell s->prescale = value; 1879a52d999SPeter Maydell break; 1889a52d999SPeter Maydell case A_MISC: 1899a52d999SPeter Maydell /* These are control bits for some of the other devices on the 1909a52d999SPeter Maydell * board (SPI, CLCD, etc). We don't implement that yet, so just 1919a52d999SPeter Maydell * make the bits read as written. 1929a52d999SPeter Maydell */ 1939a52d999SPeter Maydell qemu_log_mask(LOG_UNIMP, 1949a52d999SPeter Maydell "MPS2 FPGAIO: MISC control bits unimplemented\n"); 1959a52d999SPeter Maydell s->misc = value; 1969a52d999SPeter Maydell break; 197a1982f90SPeter Maydell case A_CLK1HZ: 198a1982f90SPeter Maydell now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 199a1982f90SPeter Maydell s->clk1hz_tick_offset = tickoff_from_counter(now, value, 1); 200a1982f90SPeter Maydell break; 201a1982f90SPeter Maydell case A_CLK100HZ: 202a1982f90SPeter Maydell now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 203a1982f90SPeter Maydell s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100); 204a1982f90SPeter Maydell break; 20593739075SPeter Maydell case A_COUNTER: 20693739075SPeter Maydell resync_counter(s); 20793739075SPeter Maydell s->counter = value; 20893739075SPeter Maydell break; 20993739075SPeter Maydell case A_PSCNTR: 21093739075SPeter Maydell resync_counter(s); 21193739075SPeter Maydell s->pscntr = value; 21293739075SPeter Maydell break; 2139a52d999SPeter Maydell default: 2149a52d999SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 2159a52d999SPeter Maydell "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset); 2169a52d999SPeter Maydell break; 2179a52d999SPeter Maydell } 2189a52d999SPeter Maydell } 2199a52d999SPeter Maydell 2209a52d999SPeter Maydell static const MemoryRegionOps mps2_fpgaio_ops = { 2219a52d999SPeter Maydell .read = mps2_fpgaio_read, 2229a52d999SPeter Maydell .write = mps2_fpgaio_write, 2239a52d999SPeter Maydell .endianness = DEVICE_LITTLE_ENDIAN, 2249a52d999SPeter Maydell }; 2259a52d999SPeter Maydell 2269a52d999SPeter Maydell static void mps2_fpgaio_reset(DeviceState *dev) 2279a52d999SPeter Maydell { 2289a52d999SPeter Maydell MPS2FPGAIO *s = MPS2_FPGAIO(dev); 229a1982f90SPeter Maydell int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 2309a52d999SPeter Maydell 2319a52d999SPeter Maydell trace_mps2_fpgaio_reset(); 2329a52d999SPeter Maydell s->led0 = 0; 2339a52d999SPeter Maydell s->prescale = 0; 2349a52d999SPeter Maydell s->misc = 0; 235a1982f90SPeter Maydell s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1); 236a1982f90SPeter Maydell s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100); 23793739075SPeter Maydell s->counter = 0; 23893739075SPeter Maydell s->pscntr = 0; 23993739075SPeter Maydell s->pscntr_sync_ticks = now; 2409a52d999SPeter Maydell } 2419a52d999SPeter Maydell 2429a52d999SPeter Maydell static void mps2_fpgaio_init(Object *obj) 2439a52d999SPeter Maydell { 2449a52d999SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 2459a52d999SPeter Maydell MPS2FPGAIO *s = MPS2_FPGAIO(obj); 2469a52d999SPeter Maydell 2479a52d999SPeter Maydell memory_region_init_io(&s->iomem, obj, &mps2_fpgaio_ops, s, 2489a52d999SPeter Maydell "mps2-fpgaio", 0x1000); 2499a52d999SPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 2509a52d999SPeter Maydell } 2519a52d999SPeter Maydell 252a1982f90SPeter Maydell static bool mps2_fpgaio_counters_needed(void *opaque) 253a1982f90SPeter Maydell { 254a1982f90SPeter Maydell /* Currently vmstate.c insists all subsections have a 'needed' function */ 255a1982f90SPeter Maydell return true; 256a1982f90SPeter Maydell } 257a1982f90SPeter Maydell 258a1982f90SPeter Maydell static const VMStateDescription mps2_fpgaio_counters_vmstate = { 259a1982f90SPeter Maydell .name = "mps2-fpgaio/counters", 26093739075SPeter Maydell .version_id = 2, 26193739075SPeter Maydell .minimum_version_id = 2, 262a1982f90SPeter Maydell .needed = mps2_fpgaio_counters_needed, 263a1982f90SPeter Maydell .fields = (VMStateField[]) { 264a1982f90SPeter Maydell VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO), 265a1982f90SPeter Maydell VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO), 26693739075SPeter Maydell VMSTATE_UINT32(counter, MPS2FPGAIO), 26793739075SPeter Maydell VMSTATE_UINT32(pscntr, MPS2FPGAIO), 26893739075SPeter Maydell VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO), 269a1982f90SPeter Maydell VMSTATE_END_OF_LIST() 270a1982f90SPeter Maydell } 271a1982f90SPeter Maydell }; 272a1982f90SPeter Maydell 2739a52d999SPeter Maydell static const VMStateDescription mps2_fpgaio_vmstate = { 2749a52d999SPeter Maydell .name = "mps2-fpgaio", 2759a52d999SPeter Maydell .version_id = 1, 2769a52d999SPeter Maydell .minimum_version_id = 1, 2779a52d999SPeter Maydell .fields = (VMStateField[]) { 2789a52d999SPeter Maydell VMSTATE_UINT32(led0, MPS2FPGAIO), 2799a52d999SPeter Maydell VMSTATE_UINT32(prescale, MPS2FPGAIO), 2809a52d999SPeter Maydell VMSTATE_UINT32(misc, MPS2FPGAIO), 2819a52d999SPeter Maydell VMSTATE_END_OF_LIST() 282a1982f90SPeter Maydell }, 283a1982f90SPeter Maydell .subsections = (const VMStateDescription*[]) { 284a1982f90SPeter Maydell &mps2_fpgaio_counters_vmstate, 285a1982f90SPeter Maydell NULL 2869a52d999SPeter Maydell } 2879a52d999SPeter Maydell }; 2889a52d999SPeter Maydell 2899a52d999SPeter Maydell static Property mps2_fpgaio_properties[] = { 2909a52d999SPeter Maydell /* Frequency of the prescale counter */ 2919a52d999SPeter Maydell DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000), 2929a52d999SPeter Maydell DEFINE_PROP_END_OF_LIST(), 2939a52d999SPeter Maydell }; 2949a52d999SPeter Maydell 2959a52d999SPeter Maydell static void mps2_fpgaio_class_init(ObjectClass *klass, void *data) 2969a52d999SPeter Maydell { 2979a52d999SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 2989a52d999SPeter Maydell 2999a52d999SPeter Maydell dc->vmsd = &mps2_fpgaio_vmstate; 3009a52d999SPeter Maydell dc->reset = mps2_fpgaio_reset; 3019a52d999SPeter Maydell dc->props = mps2_fpgaio_properties; 3029a52d999SPeter Maydell } 3039a52d999SPeter Maydell 3049a52d999SPeter Maydell static const TypeInfo mps2_fpgaio_info = { 3059a52d999SPeter Maydell .name = TYPE_MPS2_FPGAIO, 3069a52d999SPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 3079a52d999SPeter Maydell .instance_size = sizeof(MPS2FPGAIO), 3089a52d999SPeter Maydell .instance_init = mps2_fpgaio_init, 3099a52d999SPeter Maydell .class_init = mps2_fpgaio_class_init, 3109a52d999SPeter Maydell }; 3119a52d999SPeter Maydell 3129a52d999SPeter Maydell static void mps2_fpgaio_register_types(void) 3139a52d999SPeter Maydell { 3149a52d999SPeter Maydell type_register_static(&mps2_fpgaio_info); 3159a52d999SPeter Maydell } 3169a52d999SPeter Maydell 3179a52d999SPeter Maydell type_init(mps2_fpgaio_register_types); 318