1fd7f0d66SPaolo Bonzini /*
2fd7f0d66SPaolo Bonzini * Generic FIFO component, implemented as a circular buffer.
3fd7f0d66SPaolo Bonzini *
4fd7f0d66SPaolo Bonzini * Copyright (c) 2012 Peter A. G. Crosthwaite
5fd7f0d66SPaolo Bonzini *
6fd7f0d66SPaolo Bonzini * This program is free software; you can redistribute it and/or
7fd7f0d66SPaolo Bonzini * modify it under the terms of the GNU General Public License
8fd7f0d66SPaolo Bonzini * as published by the Free Software Foundation; either version
9fd7f0d66SPaolo Bonzini * 2 of the License, or (at your option) any later version.
10fd7f0d66SPaolo Bonzini *
11fd7f0d66SPaolo Bonzini * You should have received a copy of the GNU General Public License along
12fd7f0d66SPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>.
13fd7f0d66SPaolo Bonzini */
14fd7f0d66SPaolo Bonzini
15aafd7584SPeter Maydell #include "qemu/osdep.h"
16d6454270SMarkus Armbruster #include "migration/vmstate.h"
17fd7f0d66SPaolo Bonzini #include "qemu/fifo8.h"
18fd7f0d66SPaolo Bonzini
fifo8_reset(Fifo8 * fifo)19b81bc8dcSPhilippe Mathieu-Daudé void fifo8_reset(Fifo8 *fifo)
20b81bc8dcSPhilippe Mathieu-Daudé {
21b81bc8dcSPhilippe Mathieu-Daudé fifo->num = 0;
22b81bc8dcSPhilippe Mathieu-Daudé fifo->head = 0;
23b81bc8dcSPhilippe Mathieu-Daudé }
24b81bc8dcSPhilippe Mathieu-Daudé
fifo8_create(Fifo8 * fifo,uint32_t capacity)25fd7f0d66SPaolo Bonzini void fifo8_create(Fifo8 *fifo, uint32_t capacity)
26fd7f0d66SPaolo Bonzini {
27fd7f0d66SPaolo Bonzini fifo->data = g_new(uint8_t, capacity);
28fd7f0d66SPaolo Bonzini fifo->capacity = capacity;
29b81bc8dcSPhilippe Mathieu-Daudé fifo8_reset(fifo);
30fd7f0d66SPaolo Bonzini }
31fd7f0d66SPaolo Bonzini
fifo8_destroy(Fifo8 * fifo)32fd7f0d66SPaolo Bonzini void fifo8_destroy(Fifo8 *fifo)
33fd7f0d66SPaolo Bonzini {
34fd7f0d66SPaolo Bonzini g_free(fifo->data);
35fd7f0d66SPaolo Bonzini }
36fd7f0d66SPaolo Bonzini
fifo8_push(Fifo8 * fifo,uint8_t data)37fd7f0d66SPaolo Bonzini void fifo8_push(Fifo8 *fifo, uint8_t data)
38fd7f0d66SPaolo Bonzini {
39f71407edSMark Cave-Ayland assert(fifo->num < fifo->capacity);
40fd7f0d66SPaolo Bonzini fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data;
41fd7f0d66SPaolo Bonzini fifo->num++;
42fd7f0d66SPaolo Bonzini }
43fd7f0d66SPaolo Bonzini
fifo8_push_all(Fifo8 * fifo,const uint8_t * data,uint32_t num)44c4e57af8SBeniamino Galvani void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num)
45c4e57af8SBeniamino Galvani {
46c4e57af8SBeniamino Galvani uint32_t start, avail;
47c4e57af8SBeniamino Galvani
48f71407edSMark Cave-Ayland assert(fifo->num + num <= fifo->capacity);
49c4e57af8SBeniamino Galvani
50c4e57af8SBeniamino Galvani start = (fifo->head + fifo->num) % fifo->capacity;
51c4e57af8SBeniamino Galvani
52c4e57af8SBeniamino Galvani if (start + num <= fifo->capacity) {
53c4e57af8SBeniamino Galvani memcpy(&fifo->data[start], data, num);
54c4e57af8SBeniamino Galvani } else {
55c4e57af8SBeniamino Galvani avail = fifo->capacity - start;
56c4e57af8SBeniamino Galvani memcpy(&fifo->data[start], data, avail);
57c4e57af8SBeniamino Galvani memcpy(&fifo->data[0], &data[avail], num - avail);
58c4e57af8SBeniamino Galvani }
59c4e57af8SBeniamino Galvani
60c4e57af8SBeniamino Galvani fifo->num += num;
61c4e57af8SBeniamino Galvani }
62c4e57af8SBeniamino Galvani
fifo8_pop(Fifo8 * fifo)63fd7f0d66SPaolo Bonzini uint8_t fifo8_pop(Fifo8 *fifo)
64fd7f0d66SPaolo Bonzini {
65fd7f0d66SPaolo Bonzini uint8_t ret;
66fd7f0d66SPaolo Bonzini
67f71407edSMark Cave-Ayland assert(fifo->num > 0);
68fd7f0d66SPaolo Bonzini ret = fifo->data[fifo->head++];
69fd7f0d66SPaolo Bonzini fifo->head %= fifo->capacity;
70fd7f0d66SPaolo Bonzini fifo->num--;
71fd7f0d66SPaolo Bonzini return ret;
72fd7f0d66SPaolo Bonzini }
73fd7f0d66SPaolo Bonzini
fifo8_peek(Fifo8 * fifo)74*570bf143SMark Cave-Ayland uint8_t fifo8_peek(Fifo8 *fifo)
75*570bf143SMark Cave-Ayland {
76*570bf143SMark Cave-Ayland assert(fifo->num > 0);
77*570bf143SMark Cave-Ayland return fifo->data[fifo->head];
78*570bf143SMark Cave-Ayland }
79*570bf143SMark Cave-Ayland
fifo8_peekpop_bufptr(Fifo8 * fifo,uint32_t max,uint32_t skip,uint32_t * numptr,bool do_pop)80f9309d96SMark Cave-Ayland static const uint8_t *fifo8_peekpop_bufptr(Fifo8 *fifo, uint32_t max,
81e8b33243SMark Cave-Ayland uint32_t skip, uint32_t *numptr,
82e8b33243SMark Cave-Ayland bool do_pop)
83c4e57af8SBeniamino Galvani {
84c4e57af8SBeniamino Galvani uint8_t *ret;
850b73afecSMark Cave-Ayland uint32_t num, head;
86c4e57af8SBeniamino Galvani
87f71407edSMark Cave-Ayland assert(max > 0 && max <= fifo->num);
88e8b33243SMark Cave-Ayland assert(skip <= fifo->num);
89e8b33243SMark Cave-Ayland head = (fifo->head + skip) % fifo->capacity;
900b73afecSMark Cave-Ayland num = MIN(fifo->capacity - head, max);
910b73afecSMark Cave-Ayland ret = &fifo->data[head];
92995d8348SPhilippe Mathieu-Daudé
93995d8348SPhilippe Mathieu-Daudé if (do_pop) {
94e8b33243SMark Cave-Ayland fifo->head = head + num;
95c4e57af8SBeniamino Galvani fifo->head %= fifo->capacity;
96cd04033dSPhilippe Mathieu-Daudé fifo->num -= num;
97995d8348SPhilippe Mathieu-Daudé }
98cd04033dSPhilippe Mathieu-Daudé if (numptr) {
99cd04033dSPhilippe Mathieu-Daudé *numptr = num;
100cd04033dSPhilippe Mathieu-Daudé }
101c4e57af8SBeniamino Galvani return ret;
102c4e57af8SBeniamino Galvani }
103c4e57af8SBeniamino Galvani
fifo8_peek_bufptr(Fifo8 * fifo,uint32_t max,uint32_t * numptr)10406a16e7bSPhilippe Mathieu-Daudé const uint8_t *fifo8_peek_bufptr(Fifo8 *fifo, uint32_t max, uint32_t *numptr)
105995d8348SPhilippe Mathieu-Daudé {
106e8b33243SMark Cave-Ayland return fifo8_peekpop_bufptr(fifo, max, 0, numptr, false);
107995d8348SPhilippe Mathieu-Daudé }
108995d8348SPhilippe Mathieu-Daudé
fifo8_pop_bufptr(Fifo8 * fifo,uint32_t max,uint32_t * numptr)10906252bf5SPhilippe Mathieu-Daudé const uint8_t *fifo8_pop_bufptr(Fifo8 *fifo, uint32_t max, uint32_t *numptr)
110995d8348SPhilippe Mathieu-Daudé {
111e8b33243SMark Cave-Ayland return fifo8_peekpop_bufptr(fifo, max, 0, numptr, true);
112995d8348SPhilippe Mathieu-Daudé }
113995d8348SPhilippe Mathieu-Daudé
fifo8_peekpop_buf(Fifo8 * fifo,uint8_t * dest,uint32_t destlen,bool do_pop)1147fd6866cSMark Cave-Ayland static uint32_t fifo8_peekpop_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen,
1157fd6866cSMark Cave-Ayland bool do_pop)
11623ad5711SPhilippe Mathieu-Daudé {
11723ad5711SPhilippe Mathieu-Daudé const uint8_t *buf;
11823ad5711SPhilippe Mathieu-Daudé uint32_t n1, n2 = 0;
11923ad5711SPhilippe Mathieu-Daudé uint32_t len;
12023ad5711SPhilippe Mathieu-Daudé
12123ad5711SPhilippe Mathieu-Daudé if (destlen == 0) {
12223ad5711SPhilippe Mathieu-Daudé return 0;
12323ad5711SPhilippe Mathieu-Daudé }
12423ad5711SPhilippe Mathieu-Daudé
12523ad5711SPhilippe Mathieu-Daudé len = destlen;
126cfc65db1SMark Cave-Ayland buf = fifo8_peekpop_bufptr(fifo, len, 0, &n1, do_pop);
12723ad5711SPhilippe Mathieu-Daudé if (dest) {
12823ad5711SPhilippe Mathieu-Daudé memcpy(dest, buf, n1);
12923ad5711SPhilippe Mathieu-Daudé }
13023ad5711SPhilippe Mathieu-Daudé
13123ad5711SPhilippe Mathieu-Daudé /* Add FIFO wraparound if needed */
13223ad5711SPhilippe Mathieu-Daudé len -= n1;
13323ad5711SPhilippe Mathieu-Daudé len = MIN(len, fifo8_num_used(fifo));
13423ad5711SPhilippe Mathieu-Daudé if (len) {
135cfc65db1SMark Cave-Ayland buf = fifo8_peekpop_bufptr(fifo, len, do_pop ? 0 : n1, &n2, do_pop);
13623ad5711SPhilippe Mathieu-Daudé if (dest) {
13723ad5711SPhilippe Mathieu-Daudé memcpy(&dest[n1], buf, n2);
13823ad5711SPhilippe Mathieu-Daudé }
13923ad5711SPhilippe Mathieu-Daudé }
14023ad5711SPhilippe Mathieu-Daudé
14123ad5711SPhilippe Mathieu-Daudé return n1 + n2;
14223ad5711SPhilippe Mathieu-Daudé }
14323ad5711SPhilippe Mathieu-Daudé
fifo8_pop_buf(Fifo8 * fifo,uint8_t * dest,uint32_t destlen)1447fd6866cSMark Cave-Ayland uint32_t fifo8_pop_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen)
1457fd6866cSMark Cave-Ayland {
1467fd6866cSMark Cave-Ayland return fifo8_peekpop_buf(fifo, dest, destlen, true);
1477fd6866cSMark Cave-Ayland }
1487fd6866cSMark Cave-Ayland
fifo8_peek_buf(Fifo8 * fifo,uint8_t * dest,uint32_t destlen)14928fbf33bSMark Cave-Ayland uint32_t fifo8_peek_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen)
15028fbf33bSMark Cave-Ayland {
15128fbf33bSMark Cave-Ayland return fifo8_peekpop_buf(fifo, dest, destlen, false);
15228fbf33bSMark Cave-Ayland }
15328fbf33bSMark Cave-Ayland
fifo8_drop(Fifo8 * fifo,uint32_t len)154e4e9db25SPhilippe Mathieu-Daudé void fifo8_drop(Fifo8 *fifo, uint32_t len)
155e4e9db25SPhilippe Mathieu-Daudé {
156e4e9db25SPhilippe Mathieu-Daudé len -= fifo8_pop_buf(fifo, NULL, len);
157e4e9db25SPhilippe Mathieu-Daudé assert(len == 0);
158e4e9db25SPhilippe Mathieu-Daudé }
159e4e9db25SPhilippe Mathieu-Daudé
fifo8_is_empty(Fifo8 * fifo)160fd7f0d66SPaolo Bonzini bool fifo8_is_empty(Fifo8 *fifo)
161fd7f0d66SPaolo Bonzini {
162fd7f0d66SPaolo Bonzini return (fifo->num == 0);
163fd7f0d66SPaolo Bonzini }
164fd7f0d66SPaolo Bonzini
fifo8_is_full(Fifo8 * fifo)165fd7f0d66SPaolo Bonzini bool fifo8_is_full(Fifo8 *fifo)
166fd7f0d66SPaolo Bonzini {
167fd7f0d66SPaolo Bonzini return (fifo->num == fifo->capacity);
168fd7f0d66SPaolo Bonzini }
169fd7f0d66SPaolo Bonzini
fifo8_num_free(Fifo8 * fifo)170c4e57af8SBeniamino Galvani uint32_t fifo8_num_free(Fifo8 *fifo)
171c4e57af8SBeniamino Galvani {
172c4e57af8SBeniamino Galvani return fifo->capacity - fifo->num;
173c4e57af8SBeniamino Galvani }
174c4e57af8SBeniamino Galvani
fifo8_num_used(Fifo8 * fifo)175c4e57af8SBeniamino Galvani uint32_t fifo8_num_used(Fifo8 *fifo)
176c4e57af8SBeniamino Galvani {
177c4e57af8SBeniamino Galvani return fifo->num;
178c4e57af8SBeniamino Galvani }
179c4e57af8SBeniamino Galvani
180fd7f0d66SPaolo Bonzini const VMStateDescription vmstate_fifo8 = {
181fd7f0d66SPaolo Bonzini .name = "Fifo8",
182fd7f0d66SPaolo Bonzini .version_id = 1,
183fd7f0d66SPaolo Bonzini .minimum_version_id = 1,
18459c2ddedSRichard Henderson .fields = (const VMStateField[]) {
18559046ec2SHalil Pasic VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, capacity),
186fd7f0d66SPaolo Bonzini VMSTATE_UINT32(head, Fifo8),
187fd7f0d66SPaolo Bonzini VMSTATE_UINT32(num, Fifo8),
188fd7f0d66SPaolo Bonzini VMSTATE_END_OF_LIST()
189fd7f0d66SPaolo Bonzini }
190fd7f0d66SPaolo Bonzini };
191