qemu/util/fifo.c
<<
>>
Prefs
   1/*
   2 * Generic FIFO component, implemented as a circular buffer.
   3 *
   4 * Copyright (c) 2012 Peter A. G. Crosthwaite
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 *
  11 * You should have received a copy of the GNU General Public License along
  12 * with this program; if not, see <http://www.gnu.org/licenses/>.
  13 */
  14
  15#include "qemu/osdep.h"
  16#include "qemu-common.h"
  17#include "qemu/fifo.h"
  18
  19static inline void fifo_createxx(Fifo *fifo, uint32_t capacity, int bytes)
  20{
  21    fifo->width = bytes;
  22    fifo->capacity = capacity;
  23    fifo->buffer_size = capacity * fifo->width;
  24    fifo->data = g_new(uint8_t, fifo->buffer_size);
  25    fifo->head = 0;
  26    fifo->num = 0;
  27}
  28
  29void fifo_create8(Fifo *fifo, uint32_t capacity)
  30{
  31    fifo_createxx(fifo, capacity, 1);
  32}
  33
  34void fifo_create16(Fifo *fifo, uint32_t capacity)
  35{
  36    fifo_createxx(fifo, capacity, 2);
  37}
  38
  39void fifo_create32(Fifo *fifo, uint32_t capacity)
  40{
  41    fifo_createxx(fifo, capacity, 4);
  42}
  43
  44void fifo_create64(Fifo *fifo, uint32_t capacity)
  45{
  46    fifo_createxx(fifo, capacity, 8);
  47}
  48
  49void fifo_destroy(Fifo *fifo)
  50{
  51    g_free(fifo->data);
  52}
  53
  54#define FIFO_PUSH_FN(n)                                                     \
  55void fifo_push ## n(Fifo *fifo, uint ## n ## _t data)                       \
  56{                                                                           \
  57    uint32_t next_idx = (fifo->head + fifo->num) % fifo->capacity;          \
  58                                                                            \
  59    assert(n == fifo->width * 8);                                           \
  60    if (fifo->num == fifo->capacity) {                                      \
  61        abort();                                                            \
  62    }                                                                       \
  63    ((uint ## n ## _t *)fifo->data)[next_idx] = data;                       \
  64    fifo->num++;                                                            \
  65}
  66
  67FIFO_PUSH_FN(8)
  68FIFO_PUSH_FN(16)
  69FIFO_PUSH_FN(32)
  70FIFO_PUSH_FN(64)
  71
  72void fifo_push_all(Fifo *fifo, const void *data, uint32_t num)
  73{
  74    uint32_t start, avail;
  75
  76    if (fifo->num + num > fifo->capacity) {
  77        abort();
  78    }
  79
  80    start = (fifo->head + fifo->num) % fifo->capacity;
  81
  82    if (start + num <= fifo->capacity) {
  83        memcpy(&fifo->data[start * fifo->width], data, num * fifo->width);
  84    } else {
  85        avail = fifo->capacity - start;
  86        memcpy(&fifo->data[start * fifo->width], data, avail * fifo->width);
  87        memcpy(&fifo->data[0], data + avail * fifo->width,
  88               (num - avail) * fifo->width);
  89    }
  90
  91    fifo->num += num;
  92}
  93
  94#define FIFO_POP_FN(n)                                                      \
  95uint ## n ## _t fifo_pop ## n(Fifo *fifo)                                   \
  96{                                                                           \
  97    uint32_t next_idx;                                                      \
  98                                                                            \
  99    assert(n == fifo->width * 8);                                           \
 100    if (fifo->num == 0) {                                                   \
 101        abort();                                                            \
 102    }                                                                       \
 103    next_idx = fifo->head++;                                                \
 104    fifo->head %= fifo->capacity;                                           \
 105    fifo->num--;                                                            \
 106    return ((uint ## n ## _t *)fifo->data)[next_idx];                       \
 107}
 108
 109FIFO_POP_FN(8)
 110FIFO_POP_FN(16)
 111FIFO_POP_FN(32)
 112FIFO_POP_FN(64)
 113
 114const void *fifo_pop_buf(Fifo *fifo, uint32_t max, uint32_t *num)
 115{
 116    void *ret;
 117
 118    if (max == 0 || max > fifo->num) {
 119        abort();
 120    }
 121    *num = MIN(fifo->capacity - fifo->head, max);
 122    ret = &fifo->data[fifo->head * fifo->width];
 123    fifo->head += *num;
 124    fifo->head %= fifo->capacity;
 125    fifo->num -= *num;
 126    return ret;
 127}
 128
 129void fifo_reset(Fifo *fifo)
 130{
 131    fifo->num = 0;
 132    fifo->head = 0;
 133}
 134
 135bool fifo_is_empty(Fifo *fifo)
 136{
 137    return (fifo->num == 0);
 138}
 139
 140bool fifo_is_full(Fifo *fifo)
 141{
 142    return (fifo->num == fifo->capacity);
 143}
 144
 145uint32_t fifo_num_free(Fifo *fifo)
 146{
 147    return fifo->capacity - fifo->num;
 148}
 149
 150uint32_t fifo_num_used(Fifo *fifo)
 151{
 152    return fifo->num;
 153}
 154
 155const VMStateDescription vmstate_fifo = {
 156    .name = "Fifo8",
 157    .version_id = 1,
 158    .minimum_version_id = 1,
 159    .fields      = (VMStateField[]) {
 160        VMSTATE_VBUFFER_UINT32(data, Fifo, 1, NULL, 0, capacity),
 161        VMSTATE_UINT32(head, Fifo),
 162        VMSTATE_UINT32(num, Fifo),
 163        VMSTATE_END_OF_LIST()
 164    }
 165};
 166