Skip to contentSkip to conversation

Generalise FIFO to more integer types

PATCH New Peter Crosthwaite 1 participant 5 messages Apr 10, 2014

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v3 cover Generalise FIFO to more integer types

There is a utility helper for dealing with 8 bit fifos. This should be applicable to other integer widths as well. These two patches generalise this FIFO to work for 16, 32 and 64 bit ints.

changed since v2:
Glueified hot paths to increase performance.
Addressed various minor review comments.
Added PL022 as example client (Markus Review).
changed since v1:
Rebased to include fifo buffer functionality.

Peter Crosthwaite (4):
util/fifo: Generalise naming scheme
util/fifo: Generalise for common integer widths
ssi: pl022: Send debug info to stderr
ssi: pl022: Convert to use FIFO

 hw/char/serial.c                |  30 +++----
 hw/net/allwinner_emac.c         |  72 +++++++--------
 hw/ssi/pl022.c                  | 103 +++++++++-------------
 hw/ssi/xilinx_spi.c             |  42 ++++-----
 hw/ssi/xilinx_spips.c           |  66 +++++++-------
 include/hw/char/serial.h        |   6 +-
 include/hw/net/allwinner_emac.h |   6 +-
 include/qemu/fifo.h             | 180 +++++++++++++++++++++++++++++++++++++
 include/qemu/fifo8.h            | 160 ---------------------------------
 util/Makefile.objs              |   2 +-
 util/fifo.c                     | 190 ++++++++++++++++++++++++++++++++++++++++
 util/fifo8.c                    | 126 --------------------------
 12 files changed, 525 insertions(+), 458 deletions(-)
 create mode 100644 include/qemu/fifo.h
 delete mode 100644 include/qemu/fifo8.h
 create mode 100644 util/fifo.c
 delete mode 100644 util/fifo8.c
Signature · 1 line
1.9.1.1.gbb9f595
#1 lore raw

PATCH v3 1/4 util/fifo: Generalise naming scheme

Generalise the names of the FIFO API to not include the "8".

The exception is the push/pop functions for which we:

s/fifo8_pop/fifo_pop8
s/fifo8_push/fifo_push8

This prepares support for generalising FIFO support to more integer widths. Most APIs will just share name and implementation. The push and pop ones we change, as the "fifo8" type no longer exists, and changing to to fifo_xxxNN will be more consistent with other APIs that have different bit width variants.

---
Changed since v2:
changed subject of patch
added s/fifo8_push/fifo_push8 change. s/bytes/elements in comments as appropriate (Beniamino Review).

 hw/char/serial.c                |  30 ++++----
 hw/net/allwinner_emac.c         |  72 +++++++++---------
 hw/ssi/xilinx_spi.c             |  42 +++++------
 hw/ssi/xilinx_spips.c           |  66 ++++++++--------
 include/hw/char/serial.h        |   6 +-
 include/hw/net/allwinner_emac.h |   6 +-
 include/qemu/fifo.h             | 161 ++++++++++++++++++++++++++++++++++++++++
 include/qemu/fifo8.h            | 160 ---------------------------------------
 util/Makefile.objs              |   2 +-
 util/{fifo8.c => fifo.c}        |  32 ++++----
 10 files changed, 289 insertions(+), 288 deletions(-)
 create mode 100644 include/qemu/fifo.h
 delete mode 100644 include/qemu/fifo8.h
 rename util/{fifo8.c => fifo.c} (75%)
hw/char/serial.c +15 -15
index f4d167f..c7a1841 100644
@@ -108,8 +108,8 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size);
 static inline void recv_fifo_put(SerialState *s, uint8_t chr)
 {
     /* Receive overruns do not overwrite FIFO contents. */
-    if (!fifo8_is_full(&s->recv_fifo)) {
-        fifo8_push(&s->recv_fifo, chr);
+    if (!fifo_is_full(&s->recv_fifo)) {
+        fifo_push8(&s->recv_fifo, chr);
     } else {
         s->lsr |= UART_LSR_OE;
     }
@@ -225,10 +225,10 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
 
     if (s->tsr_retry <= 0) {
         if (s->fcr & UART_FCR_FE) {
-            if (fifo8_is_empty(&s->xmit_fifo)) {
+            if (fifo_is_empty(&s->xmit_fifo)) {
                 return FALSE;
             }
-            s->tsr = fifo8_pop(&s->xmit_fifo);
+            s->tsr = fifo_pop8(&s->xmit_fifo);
             if (!s->xmit_fifo.num) {
                 s->lsr |= UART_LSR_THRE;
             }
@@ -284,10 +284,10 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
             s->thr = (uint8_t) val;
             if(s->fcr & UART_FCR_FE) {
                 /* xmit overruns overwrite data, so make space if needed */
-                if (fifo8_is_full(&s->xmit_fifo)) {
-                    fifo8_pop(&s->xmit_fifo);
+                if (fifo_is_full(&s->xmit_fifo)) {
+                    fifo_pop8(&s->xmit_fifo);
                 }
-                fifo8_push(&s->xmit_fifo, s->thr);
+                fifo_push8(&s->xmit_fifo, s->thr);
                 s->lsr &= ~UART_LSR_TEMT;
             }
             s->thr_ipending = 0;
@@ -334,11 +334,11 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
         if (val & UART_FCR_RFR) {
             timer_del(s->fifo_timeout_timer);
             s->timeout_ipending=0;
-            fifo8_reset(&s->recv_fifo);
+            fifo_reset(&s->recv_fifo);
         }
 
         if (val & UART_FCR_XFR) {
-            fifo8_reset(&s->xmit_fifo);
+            fifo_reset(&s->xmit_fifo);
         }
 
         if (val & UART_FCR_FE) {
@@ -427,8 +427,8 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
             ret = s->divider & 0xff;
         } else {
             if(s->fcr & UART_FCR_FE) {
-                ret = fifo8_is_empty(&s->recv_fifo) ?
-                            0 : fifo8_pop(&s->recv_fifo);
+                ret = fifo_is_empty(&s->recv_fifo) ?
+                            0 : fifo_pop8(&s->recv_fifo);
                 if (s->recv_fifo.num == 0) {
                     s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
                 } else {
@@ -635,8 +635,8 @@ static void serial_reset(void *opaque)
     s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10;
     s->poll_msl = 0;
 
-    fifo8_reset(&s->recv_fifo);
-    fifo8_reset(&s->xmit_fifo);
+    fifo_reset(&s->recv_fifo);
+    fifo_reset(&s->xmit_fifo);
 
     s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 
@@ -659,8 +659,8 @@ void serial_realize_core(SerialState *s, Error **errp)
 
     qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
                           serial_event, s);
-    fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
-    fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
+    fifo_create(&s->recv_fifo, UART_FIFO_LENGTH);
+    fifo_create(&s->xmit_fifo, UART_FIFO_LENGTH);
 }
 
 void serial_exit_core(SerialState *s)
hw/net/allwinner_emac.c +36 -36

181 lines not on this page · raw message

hw/ssi/xilinx_spi.c +21 -21

112 lines not on this page · raw message

hw/ssi/xilinx_spips.c +33 -33

182 lines not on this page · raw message

include/hw/char/serial.h +3 -3
index f431764..021499b 100644
@@ -28,7 +28,7 @@
 #include "hw/hw.h"
 #include "sysemu/sysemu.h"
 #include "exec/memory.h"
-#include "qemu/fifo8.h"
+#include "qemu/fifo.h"
 
 #define UART_FIFO_LENGTH    16      /* 16550A Fifo Length */
 
@@ -60,8 +60,8 @@ struct SerialState {
 
     /* Time when the last byte was successfully sent out of the tsr */
     uint64_t last_xmit_ts;
-    Fifo8 recv_fifo;
-    Fifo8 xmit_fifo;
+    Fifo recv_fifo;
+    Fifo xmit_fifo;
     /* Interrupt trigger level for recv_fifo */
     uint8_t recv_fifo_itl;
 
include/hw/net/allwinner_emac.h +3 -3
index a5e944a..295b524 100644
@@ -23,7 +23,7 @@
 #define AW_EMAC_H
 
 #include "net/net.h"
-#include "qemu/fifo8.h"
+#include "qemu/fifo.h"
 
 #define TYPE_AW_EMAC "allwinner-emac"
 #define AW_EMAC(obj) OBJECT_CHECK(AwEmacState, (obj), TYPE_AW_EMAC)
@@ -197,12 +197,12 @@ typedef struct AwEmacState {
     uint32_t       int_sta;
     uint32_t       phy_target;
 
-    Fifo8          rx_fifo;
+    Fifo           rx_fifo;
     uint32_t       rx_num_packets;
     uint32_t       rx_packet_size;
     uint32_t       rx_packet_pos;
 
-    Fifo8          tx_fifo[NUM_TX_FIFOS];
+    Fifo           tx_fifo[NUM_TX_FIFOS];
     uint32_t       tx_length[NUM_TX_FIFOS];
     uint32_t       tx_channel;
 } AwEmacState;
include/qemu/fifo.h new file +161 -0

161 lines not on this page · raw message

include/qemu/fifo8.h deleted +0 -160

160 lines not on this page · raw message

util/Makefile.objs +1 -1
index df83b62..7f1489c 100644
@@ -3,7 +3,7 @@ util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win
 util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o qemu-openpty.o
 util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o
 util-obj-y += bitmap.o bitops.o hbitmap.o
-util-obj-y += fifo8.o
+util-obj-y += fifo.o
 util-obj-y += acl.o
 util-obj-y += error.o qemu-error.o
 util-obj-$(CONFIG_POSIX) += compatfd.o
util/fifo.c renamed from util/fifo8.c +16 -16
similarity index 75%
rename from util/fifo8.c
rename to util/fifo.c
index 6a43482..4ee6c85 100644
@@ -13,9 +13,9 @@
  */
 
 #include "qemu-common.h"
-#include "qemu/fifo8.h"
+#include "qemu/fifo.h"
 
-void fifo8_create(Fifo8 *fifo, uint32_t capacity)
+void fifo_create(Fifo *fifo, uint32_t capacity)
 {
     fifo->data = g_new(uint8_t, capacity);
     fifo->capacity = capacity;
@@ -23,12 +23,12 @@ void fifo8_create(Fifo8 *fifo, uint32_t capacity)
     fifo->num = 0;
 }
 
-void fifo8_destroy(Fifo8 *fifo)
+void fifo_destroy(Fifo *fifo)
 {
     g_free(fifo->data);
 }
 
-void fifo8_push(Fifo8 *fifo, uint8_t data)
+void fifo_push8(Fifo *fifo, uint8_t data)
 {
     if (fifo->num == fifo->capacity) {
         abort();
@@ -37,7 +37,7 @@ void fifo8_push(Fifo8 *fifo, uint8_t data)
     fifo->num++;
 }
 
-void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num)
+void fifo_push_all(Fifo *fifo, const uint8_t *data, uint32_t num)
 {
     uint32_t start, avail;
 
@@ -58,7 +58,7 @@ void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num)
     fifo->num += num;
 }
 
-uint8_t fifo8_pop(Fifo8 *fifo)
+uint8_t fifo_pop8(Fifo *fifo)
 {
     uint8_t ret;
 
@@ -71,7 +71,7 @@ uint8_t fifo8_pop(Fifo8 *fifo)
     return ret;
 }
 
-const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num)
+const uint8_t *fifo_pop_buf(Fifo *fifo, uint32_t max, uint32_t *num)
 {
     uint8_t *ret;
 
@@ -86,41 +86,41 @@ const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num)
     return ret;
 }
 
-void fifo8_reset(Fifo8 *fifo)
+void fifo_reset(Fifo *fifo)
 {
     fifo->num = 0;
     fifo->head = 0;
 }
 
-bool fifo8_is_empty(Fifo8 *fifo)
+bool fifo_is_empty(Fifo *fifo)
 {
     return (fifo->num == 0);
 }
 
-bool fifo8_is_full(Fifo8 *fifo)
+bool fifo_is_full(Fifo *fifo)
 {
     return (fifo->num == fifo->capacity);
 }
 
-uint32_t fifo8_num_free(Fifo8 *fifo)
+uint32_t fifo_num_free(Fifo *fifo)
 {
     return fifo->capacity - fifo->num;
 }
 
-uint32_t fifo8_num_used(Fifo8 *fifo)
+uint32_t fifo_num_used(Fifo *fifo)
 {
     return fifo->num;
 }
 
-const VMStateDescription vmstate_fifo8 = {
+const VMStateDescription vmstate_fifo = {
     .name = "Fifo8",
     .version_id = 1,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
-        VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, 0, capacity),
-        VMSTATE_UINT32(head, Fifo8),
-        VMSTATE_UINT32(num, Fifo8),
+        VMSTATE_VBUFFER_UINT32(data, Fifo, 1, NULL, 0, capacity),
+        VMSTATE_UINT32(head, Fifo),
+        VMSTATE_UINT32(num, Fifo),
         VMSTATE_END_OF_LIST()
     }
 };
Signature · 1 line
1.9.1.1.gbb9f595
#2 lore raw

PATCH v3 2/4 util/fifo: Generalise for common integer widths

In reply to Peter Crosthwaite

Add support for 16, 32 and 64 bit width FIFOs. The push and pop functions are replicated to accept all four different integer types. The element width of the FIFO is set at creation time.

The backing storage for all element types is still uint8_t regardless of element width so some save-load logic is needed to handle endianness issue WRT VMSD.

---
changed since v2:
replicated (and glueified) the push/pop functions (Don Slutz review). Fix "each each" typo (Beniamino review).
Done use "Case(n):" (Beniamino review).

 hw/char/serial.c        |   4 +-
 hw/net/allwinner_emac.c |   6 +--
 hw/ssi/xilinx_spi.c     |   4 +-
 hw/ssi/xilinx_spips.c   |   4 +-
 include/qemu/fifo.h     |  33 ++++++++++---
 util/fifo.c             | 120 +++++++++++++++++++++++++++++++++++++-----------
 6 files changed, 127 insertions(+), 44 deletions(-)
hw/char/serial.c +2 -2
index c7a1841..c53db13 100644
@@ -659,8 +659,8 @@ void serial_realize_core(SerialState *s, Error **errp)
 
     qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
                           serial_event, s);
-    fifo_create(&s->recv_fifo, UART_FIFO_LENGTH);
-    fifo_create(&s->xmit_fifo, UART_FIFO_LENGTH);
+    fifo_create(&s->recv_fifo, UART_FIFO_LENGTH, 8);
+    fifo_create(&s->xmit_fifo, UART_FIFO_LENGTH, 8);
 }
 
 void serial_exit_core(SerialState *s)
hw/net/allwinner_emac.c +3 -3
index 860cb5e..669b54a 100644
@@ -455,9 +455,9 @@ static void aw_emac_realize(DeviceState *dev, Error **errp)
                           object_get_typename(OBJECT(dev)), dev->id, s);
     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
 
-    fifo_create(&s->rx_fifo, RX_FIFO_SIZE);
-    fifo_create(&s->tx_fifo[0], TX_FIFO_SIZE);
-    fifo_create(&s->tx_fifo[1], TX_FIFO_SIZE);
+    fifo_create(&s->rx_fifo, RX_FIFO_SIZE, 8);
+    fifo_create(&s->tx_fifo[0], TX_FIFO_SIZE, 8);
+    fifo_create(&s->tx_fifo[1], TX_FIFO_SIZE, 8);
 }
 
 static Property aw_emac_properties[] = {
hw/ssi/xilinx_spi.c +2 -2
index ca19e47..017331d 100644
@@ -341,8 +341,8 @@ static int xilinx_spi_init(SysBusDevice *sbd)
 
     s->irqline = -1;
 
-    fifo_create(&s->tx_fifo, FIFO_CAPACITY);
-    fifo_create(&s->rx_fifo, FIFO_CAPACITY);
+    fifo_create(&s->tx_fifo, FIFO_CAPACITY, 8);
+    fifo_create(&s->rx_fifo, FIFO_CAPACITY, 8);
 
     return 0;
 }
hw/ssi/xilinx_spips.c +2 -2
index 5633209..0777f5c 100644
@@ -669,8 +669,8 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
 
     s->irqline = -1;
 
-    fifo_create(&s->rx_fifo, xsc->rx_fifo_size);
-    fifo_create(&s->tx_fifo, xsc->tx_fifo_size);
+    fifo_create(&s->rx_fifo, xsc->rx_fifo_size, 8);
+    fifo_create(&s->tx_fifo, xsc->tx_fifo_size, 8);
 }
 
 static void xilinx_qspips_realize(DeviceState *dev, Error **errp)
include/qemu/fifo.h +26 -7
index a704bd4..d15964d 100644
@@ -5,8 +5,12 @@
 
 typedef struct {
     /* All fields are private */
+    int width; /* byte width of each element */
+    uint32_t capacity; /* number of elements */
+
     uint8_t *data;
-    uint32_t capacity;
+    uint32_t buffer_size;
+
     uint32_t head;
     uint32_t num;
 } Fifo;
@@ -14,13 +18,14 @@ typedef struct {
 /**
  * fifo_create:
  * @fifo: struct Fifo to initialise with new FIFO
- * @capacity: capacity of the newly created FIFO
+ * @capacity: capacity (number of elements) of the newly created FIFO
+ * @width: integer width of each element. Must be 8, 16, 32 or 64.
  *
  * Create a FIFO of the specified size. Clients should call fifo_destroy()
  * when finished using the fifo. The FIFO is initially empty.
  */
 
-void fifo_create(Fifo *fifo, uint32_t capacity);
+void fifo_create(Fifo *fifo, uint32_t capacity, int width);
 
 /**
  * fifo_destroy:
@@ -33,15 +38,22 @@ void fifo_create(Fifo *fifo, uint32_t capacity);
 void fifo_destroy(Fifo *fifo);
 
 /**
- * fifo_push:
+ * fifo_pushX:
  * @fifo: FIFO to push to
  * @data: data value to push
  *
  * Push a data value to the FIFO. Behaviour is undefined if the FIFO is full.
  * Clients are responsible for checking for fullness using fifo_is_full().
+ *
+ * 8, 16, 32 and 64 bit variants are available. Behaviour is undefined if a
+ * variant mismatched to the FIFO width used (e.g. you cannot use fifo_push8
+ * with a FIFO created with width == 16).
  */
 
 void fifo_push8(Fifo *fifo, uint8_t data);
+void fifo_push16(Fifo *fifo, uint16_t data);
+void fifo_push32(Fifo *fifo, uint32_t data);
+void fifo_push64(Fifo *fifo, uint64_t data);
 
 /**
  * fifo_push_all:
@@ -54,19 +66,26 @@ void fifo_push8(Fifo *fifo, uint8_t data);
  * fifo_num_free().
  */
 
-void fifo_push_all(Fifo *fifo, const uint8_t *data, uint32_t num);
+void fifo_push_all(Fifo *fifo, const void *data, uint32_t num);
 
 /**
- * fifo_pop:
+ * fifo_popX:
  * @fifo: fifo to pop from
  *
  * Pop a data value from the FIFO. Behaviour is undefined if the FIFO is empty.
  * Clients are responsible for checking for emptyness using fifo_is_empty().
  *
+ * 8, 16, 32 and 64 bit variants are available. Behaviour is undefined if a
+ * variant mismatched to the FIFO width is used (e.g. you cannot use fifo_pop8
+ * with a FIFO created with width == 16).
+ *
  * Returns: The popped data value.
  */
 
 uint8_t fifo_pop8(Fifo *fifo);
+uint16_t fifo_pop16(Fifo *fifo);
+uint32_t fifo_pop32(Fifo *fifo);
+uint64_t fifo_pop64(Fifo *fifo);
 
 /**
  * fifo_pop_buf:
@@ -93,7 +112,7 @@ uint8_t fifo_pop8(Fifo *fifo);
  * Returns: A pointer to popped data.
  */
 
-const uint8_t *fifo_pop_buf(Fifo *fifo, uint32_t max, uint32_t *num);
+const void *fifo_pop_buf(Fifo *fifo, uint32_t max, uint32_t *num);
 
 /**
  * fifo_reset:
util/fifo.c +92 -28

168 lines not on this page · raw message

Signature · 1 line
1.9.1.1.gbb9f595
#3 lore raw

PATCH v3 3/4 ssi: pl022: Send debug info to stderr

In reply to Peter Crosthwaite

To disentangle it from the monitor.

---

 hw/ssi/pl022.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
hw/ssi/pl022.c +1 -1
index fd479ef..84bf87a 100644
@@ -14,7 +14,7 @@
 
 #ifdef DEBUG_PL022
 #define DPRINTF(fmt, ...) \
-do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
+do { fprintf(stderr, "pl022: " fmt , ## __VA_ARGS__); } while (0)
 #define BADF(fmt, ...) \
 do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
 #else
Signature · 1 line
1.9.1.1.gbb9f595
#4 lore raw

PATCH v3 4/4 ssi: pl022: Convert to use FIFO

In reply to Peter Crosthwaite

Use the FIFO API to factor out the ring buffer implementation code. Cleans up the somewhat verbose VMS description as well (version bump required).

---

 hw/ssi/pl022.c | 101 ++++++++++++++++++++++++---------------------------------
 1 file changed, 42 insertions(+), 59 deletions(-)
hw/ssi/pl022.c +42 -59
index 84bf87a..f8e734b 100644
@@ -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;
Signature · 1 line
1.9.1.1.gbb9f595