Use the FIFO API to factor out the ring buffer implementation code. Cleans up the somewhat verbose VMS description as well (version bump required).
Signed-off-by: Peter Crosthwaite <peter.crosthwa...@xilinx.com> --- hw/ssi/pl022.c | 101 ++++++++++++++++++++++++--------------------------------- 1 file changed, 42 insertions(+), 59 deletions(-) diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c index 84bf87a..f8e734b 100644 --- a/hw/ssi/pl022.c +++ b/hw/ssi/pl022.c @@ -9,6 +9,7 @@ #include "hw/sysbus.h" #include "hw/ssi.h" +#include "qemu/fifo.h" //#define DEBUG_PL022 1 @@ -42,6 +43,8 @@ do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0) #define TYPE_PL022 "pl022" #define PL022(obj) OBJECT_CHECK(PL022State, (obj), TYPE_PL022) +#define PL022_FIFO_DEPTH 8 + typedef struct PL022State { SysBusDevice parent_obj; @@ -53,13 +56,10 @@ typedef struct PL022State { uint32_t cpsr; uint32_t is; uint32_t im; - /* The FIFO head points to the next empty entry. */ - int tx_fifo_head; - int rx_fifo_head; - int tx_fifo_len; - int rx_fifo_len; - uint16_t tx_fifo[8]; - uint16_t rx_fifo[8]; + + Fifo tx_fifo; + Fifo rx_fifo; + qemu_irq irq; SSIBus *ssi; } PL022State; @@ -69,30 +69,38 @@ static const unsigned char pl022_id[8] = static void pl022_update(PL022State *s) { + uint32_t tx_fifo_len = fifo_num_used(&s->tx_fifo); + uint32_t rx_fifo_len = fifo_num_used(&s->rx_fifo); + s->sr = 0; - if (s->tx_fifo_len == 0) + if (tx_fifo_len == 0) { s->sr |= PL022_SR_TFE; - if (s->tx_fifo_len != 8) + } + if (tx_fifo_len != PL022_FIFO_DEPTH) { s->sr |= PL022_SR_TNF; - if (s->rx_fifo_len != 0) + } + if (rx_fifo_len != 0) { s->sr |= PL022_SR_RNE; - if (s->rx_fifo_len == 8) + } + if (rx_fifo_len == PL022_FIFO_DEPTH) { s->sr |= PL022_SR_RFF; - if (s->tx_fifo_len) + } + if (tx_fifo_len) { s->sr |= PL022_SR_BSY; + } s->is = 0; - if (s->rx_fifo_len >= 4) + if (rx_fifo_len >= 4) { s->is |= PL022_INT_RX; - if (s->tx_fifo_len <= 4) + } + if (tx_fifo_len <= 4) { s->is |= PL022_INT_TX; + } qemu_set_irq(s->irq, (s->is & s->im) != 0); } static void pl022_xfer(PL022State *s) { - int i; - int o; int val; if ((s->cr1 & PL022_CR1_SSE) == 0) { @@ -101,9 +109,8 @@ static void pl022_xfer(PL022State *s) return; } - DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len); - i = (s->tx_fifo_head - s->tx_fifo_len) & 7; - o = s->rx_fifo_head; + DPRINTF("Maybe xfer %" PRId32 "/%" PRId32 "\n", + fifo_num_used(&s->tx_fifo), fifo_num_used(&s->rx_fifo)); /* ??? We do not emulate the line speed. This may break some applications. The are two problematic cases: (a) A driver feeds data into the TX FIFO until it is full, @@ -116,21 +123,16 @@ static void pl022_xfer(PL022State *s) cause the RX FIFO to overflow. In practice much transmit-only code falls into (a) because it flushes the RX FIFO to determine when the transfer has completed. */ - while (s->tx_fifo_len && s->rx_fifo_len < 8) { + while (!fifo_is_empty(&s->tx_fifo) && !fifo_is_full(&s->rx_fifo)) { DPRINTF("xfer\n"); - val = s->tx_fifo[i]; + val = fifo_pop16(&s->tx_fifo); if (s->cr1 & PL022_CR1_LBM) { /* Loopback mode. */ } else { val = ssi_transfer(s->ssi, val); } - s->rx_fifo[o] = val & s->bitmask; - i = (i + 1) & 7; - o = (o + 1) & 7; - s->tx_fifo_len--; - s->rx_fifo_len++; + fifo_push16(&s->rx_fifo, val & s->bitmask); } - s->rx_fifo_head = o; pl022_update(s); } @@ -149,10 +151,9 @@ static uint64_t pl022_read(void *opaque, hwaddr offset, case 0x04: /* CR1 */ return s->cr1; case 0x08: /* DR */ - if (s->rx_fifo_len) { - val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7]; + if (!fifo_is_empty(&s->rx_fifo)) { + val = fifo_pop16(&s->rx_fifo); DPRINTF("RX %02x\n", val); - s->rx_fifo_len--; pl022_xfer(s); } else { val = 0; @@ -198,11 +199,9 @@ static void pl022_write(void *opaque, hwaddr offset, pl022_xfer(s); break; case 0x08: /* DR */ - if (s->tx_fifo_len < 8) { + if (!fifo_is_full(&s->tx_fifo)) { DPRINTF("TX %02x\n", (unsigned)value); - s->tx_fifo[s->tx_fifo_head] = value & s->bitmask; - s->tx_fifo_head = (s->tx_fifo_head + 1) & 7; - s->tx_fifo_len++; + fifo_push16(&s->tx_fifo, value & s->bitmask); pl022_xfer(s); } break; @@ -227,8 +226,8 @@ static void pl022_write(void *opaque, hwaddr offset, static void pl022_reset(PL022State *s) { - s->rx_fifo_len = 0; - s->tx_fifo_len = 0; + fifo_reset(&s->rx_fifo); + fifo_reset(&s->tx_fifo); s->im = 0; s->is = PL022_INT_TX; s->sr = PL022_SR_TFE | PL022_SR_TNF; @@ -242,9 +241,9 @@ static const MemoryRegionOps pl022_ops = { static const VMStateDescription vmstate_pl022 = { .name = "pl022_ssp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_UINT32(cr0, PL022State), VMSTATE_UINT32(cr1, PL022State), @@ -253,26 +252,8 @@ static const VMStateDescription vmstate_pl022 = { VMSTATE_UINT32(cpsr, PL022State), VMSTATE_UINT32(is, PL022State), VMSTATE_UINT32(im, PL022State), - VMSTATE_INT32(tx_fifo_head, PL022State), - VMSTATE_INT32(rx_fifo_head, PL022State), - VMSTATE_INT32(tx_fifo_len, PL022State), - VMSTATE_INT32(rx_fifo_len, PL022State), - VMSTATE_UINT16(tx_fifo[0], PL022State), - VMSTATE_UINT16(rx_fifo[0], PL022State), - VMSTATE_UINT16(tx_fifo[1], PL022State), - VMSTATE_UINT16(rx_fifo[1], PL022State), - VMSTATE_UINT16(tx_fifo[2], PL022State), - VMSTATE_UINT16(rx_fifo[2], PL022State), - VMSTATE_UINT16(tx_fifo[3], PL022State), - VMSTATE_UINT16(rx_fifo[3], PL022State), - VMSTATE_UINT16(tx_fifo[4], PL022State), - VMSTATE_UINT16(rx_fifo[4], PL022State), - VMSTATE_UINT16(tx_fifo[5], PL022State), - VMSTATE_UINT16(rx_fifo[5], PL022State), - VMSTATE_UINT16(tx_fifo[6], PL022State), - VMSTATE_UINT16(rx_fifo[6], PL022State), - VMSTATE_UINT16(tx_fifo[7], PL022State), - VMSTATE_UINT16(rx_fifo[7], PL022State), + VMSTATE_FIFO(tx_fifo, PL022State), + VMSTATE_FIFO(rx_fifo, PL022State), VMSTATE_END_OF_LIST() } }; @@ -286,6 +267,8 @@ static int pl022_init(SysBusDevice *sbd) sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); s->ssi = ssi_create_bus(dev, "ssi"); + fifo_create(&s->tx_fifo, PL022_FIFO_DEPTH, 16); + fifo_create(&s->rx_fifo, PL022_FIFO_DEPTH, 16); pl022_reset(s); vmstate_register(dev, -1, &vmstate_pl022, s); return 0; -- 1.9.2.1.g06c4abd