@@ -657,8 +657,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)
@@ -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;
}
@@ -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)
@@ -5,8 +5,12 @@
typedef struct {
/* All fields are private */
+ int width; /* byte width each 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:
@@ -41,7 +46,7 @@ void fifo_destroy(Fifo *fifo);
* Clients are responsible for checking for fullness using fifo_is_full().
*/
-void fifo_push(Fifo *fifo, uint8_t data);
+void fifo_push(Fifo *fifo, uint64_t data);
/**
* fifo_pop:
@@ -53,7 +58,7 @@ void fifo_push(Fifo *fifo, uint8_t data);
* Returns: The popped data value.
*/
-uint8_t fifo_pop(Fifo *fifo);
+uint64_t fifo_pop(Fifo *fifo);
/**
* fifo_reset:
@@ -15,9 +15,11 @@
#include "qemu-common.h"
#include "qemu/fifo.h"
-void fifo_create(Fifo *fifo, uint32_t capacity)
+void fifo_create(Fifo *fifo, uint32_t capacity, int width)
{
- fifo->data = g_new(uint8_t, capacity);
+ assert(width == 8 || width == 16 || width == 32 || width == 64);
+ fifo->width = width / 8;
+ fifo->data = g_new(uint8_t, capacity * fifo->width);
fifo->capacity = capacity;
fifo->head = 0;
fifo->num = 0;
@@ -28,26 +30,55 @@ void fifo_destroy(Fifo *fifo)
g_free(fifo->data);
}
-void fifo_push(Fifo *fifo, uint8_t data)
+void fifo_push(Fifo *fifo, uint64_t data)
{
+ uint32_t next_idx = (fifo->head + fifo->num) % fifo->capacity;
+
if (fifo->num == fifo->capacity) {
abort();
}
- fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data;
+ switch (fifo->width) {
+ case(1):
+ ((uint8_t *)fifo->data)[next_idx] = data;
+ break;
+ case(2):
+ ((uint16_t *)fifo->data)[next_idx] = data;
+ break;
+ case(4):
+ ((uint32_t *)fifo->data)[next_idx] = data;
+ break;
+ case(8):
+ ((uint64_t *)fifo->data)[next_idx] = data;
+ break;
+ default:
+ abort();
+ }
fifo->num++;
}
-uint8_t fifo_pop(Fifo *fifo)
+uint64_t fifo_pop(Fifo *fifo)
{
- uint8_t ret;
+ uint32_t next_idx;
if (fifo->num == 0) {
abort();
}
- ret = fifo->data[fifo->head++];
+ next_idx = fifo->head++;
fifo->head %= fifo->capacity;
fifo->num--;
- return ret;
+ switch (fifo->width) {
+ case(1):
+ return ((uint8_t *)fifo->data)[next_idx];
+ case(2):
+ return ((uint16_t *)fifo->data)[next_idx];
+ case(4):
+ return ((uint32_t *)fifo->data)[next_idx];
+ case(8):
+ return ((uint64_t *)fifo->data)[next_idx];
+ default:
+ abort();
+ return 0; /* unreachable */
+ }
}
void fifo_reset(Fifo *fifo)
@@ -65,13 +96,55 @@ bool fifo_is_full(Fifo *fifo)
return (fifo->num == fifo->capacity);
}
+/* Always store buffer data in little (arbitrarily chosen) endian format to
+ * allow for migration to/from BE <-> LE hosts.
+ */
+
+static inline void fifo_save_load_swap(Fifo *fifo) {
+#ifdef HOST_WORDS_BIGENDIAN
+ int i;
+ uint16_t *d16 = (uint16_t *)fifo->data;
+ uint32_t *d32 = (uint32_t *)fifo->data;
+ uint64_t *d64 = (uint64_t *)fifo->data;
+
+ for (i = 0; i < fifo->capacity; ++i) {
+ switch (fifo->width) {
+ case(1):
+ return;
+ case(2):
+ d16[i] = bswap16(d16[i]);
+ break;
+ case(4):
+ d32[i] = bswap32(d32[i]);
+ break;
+ case(8):
+ d64[i] = bswap64(d64[i]);
+ break;
+ default:
+ abort();
+ }
+ }
+#endif
+}
+
+static void fifo_pre_save(void * opaque) {
+ fifo_save_load_swap((Fifo *)opaque);
+}
+
+static int fifo_post_load(void *opaque, int version_id) {
+ fifo_save_load_swap((Fifo *)opaque);
+ return 0;
+}
+
const VMStateDescription vmstate_fifo = {
.name = "Fifo8",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
+ .pre_save = fifo_pre_save,
+ .post_load = fifo_post_load,
.fields = (VMStateField[]) {
- VMSTATE_VBUFFER_UINT32(data, Fifo, 1, NULL, 0, capacity),
+ VMSTATE_VBUFFER_UINT32(data, Fifo, 1, NULL, 0, buffer_size),
VMSTATE_UINT32(head, Fifo),
VMSTATE_UINT32(num, Fifo),
VMSTATE_END_OF_LIST()
Add support for 16, 32 and 64 bit width FIFOs. The push and pop functions are patched to accept uint64_t always to support up to 64bit integer elements. The element width 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 endianess issue WRT VMSD. Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com> --- hw/char/serial.c | 4 +-- hw/ssi/xilinx_spi.c | 4 +-- hw/ssi/xilinx_spips.c | 4 +-- include/qemu/fifo.h | 15 ++++++--- util/fifo.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 98 insertions(+), 20 deletions(-)