xref: /openbmc/qemu/util/fifo8.c (revision 5e37bc4997c32a1c9a6621a060462c84df9f1b8f)
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 "migration/vmstate.h"
17  #include "qemu/fifo8.h"
18  
19  void fifo8_create(Fifo8 *fifo, uint32_t capacity)
20  {
21      fifo->data = g_new(uint8_t, capacity);
22      fifo->capacity = capacity;
23      fifo->head = 0;
24      fifo->num = 0;
25  }
26  
27  void fifo8_destroy(Fifo8 *fifo)
28  {
29      g_free(fifo->data);
30  }
31  
32  void fifo8_push(Fifo8 *fifo, uint8_t data)
33  {
34      assert(fifo->num < fifo->capacity);
35      fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data;
36      fifo->num++;
37  }
38  
39  void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num)
40  {
41      uint32_t start, avail;
42  
43      assert(fifo->num + num <= fifo->capacity);
44  
45      start = (fifo->head + fifo->num) % fifo->capacity;
46  
47      if (start + num <= fifo->capacity) {
48          memcpy(&fifo->data[start], data, num);
49      } else {
50          avail = fifo->capacity - start;
51          memcpy(&fifo->data[start], data, avail);
52          memcpy(&fifo->data[0], &data[avail], num - avail);
53      }
54  
55      fifo->num += num;
56  }
57  
58  uint8_t fifo8_pop(Fifo8 *fifo)
59  {
60      uint8_t ret;
61  
62      assert(fifo->num > 0);
63      ret = fifo->data[fifo->head++];
64      fifo->head %= fifo->capacity;
65      fifo->num--;
66      return ret;
67  }
68  
69  static const uint8_t *fifo8_peekpop_buf(Fifo8 *fifo, uint32_t max,
70                                          uint32_t *numptr, bool do_pop)
71  {
72      uint8_t *ret;
73      uint32_t num;
74  
75      assert(max > 0 && max <= fifo->num);
76      num = MIN(fifo->capacity - fifo->head, max);
77      ret = &fifo->data[fifo->head];
78  
79      if (do_pop) {
80          fifo->head += num;
81          fifo->head %= fifo->capacity;
82          fifo->num -= num;
83      }
84      if (numptr) {
85          *numptr = num;
86      }
87      return ret;
88  }
89  
90  const uint8_t *fifo8_peek_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr)
91  {
92      return fifo8_peekpop_buf(fifo, max, numptr, false);
93  }
94  
95  const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr)
96  {
97      return fifo8_peekpop_buf(fifo, max, numptr, true);
98  }
99  
100  void fifo8_reset(Fifo8 *fifo)
101  {
102      fifo->num = 0;
103      fifo->head = 0;
104  }
105  
106  bool fifo8_is_empty(Fifo8 *fifo)
107  {
108      return (fifo->num == 0);
109  }
110  
111  bool fifo8_is_full(Fifo8 *fifo)
112  {
113      return (fifo->num == fifo->capacity);
114  }
115  
116  uint32_t fifo8_num_free(Fifo8 *fifo)
117  {
118      return fifo->capacity - fifo->num;
119  }
120  
121  uint32_t fifo8_num_used(Fifo8 *fifo)
122  {
123      return fifo->num;
124  }
125  
126  const VMStateDescription vmstate_fifo8 = {
127      .name = "Fifo8",
128      .version_id = 1,
129      .minimum_version_id = 1,
130      .fields = (const VMStateField[]) {
131          VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, capacity),
132          VMSTATE_UINT32(head, Fifo8),
133          VMSTATE_UINT32(num, Fifo8),
134          VMSTATE_END_OF_LIST()
135      }
136  };
137