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 | if (fifo->num == fifo->capacity) { |
35 | abort(); |
36 | } |
37 | fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; |
38 | fifo->num++; |
39 | } |
40 | |
41 | void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num) |
42 | { |
43 | uint32_t start, avail; |
44 | |
45 | if (fifo->num + num > fifo->capacity) { |
46 | abort(); |
47 | } |
48 | |
49 | start = (fifo->head + fifo->num) % fifo->capacity; |
50 | |
51 | if (start + num <= fifo->capacity) { |
52 | memcpy(&fifo->data[start], data, num); |
53 | } else { |
54 | avail = fifo->capacity - start; |
55 | memcpy(&fifo->data[start], data, avail); |
56 | memcpy(&fifo->data[0], &data[avail], num - avail); |
57 | } |
58 | |
59 | fifo->num += num; |
60 | } |
61 | |
62 | uint8_t fifo8_pop(Fifo8 *fifo) |
63 | { |
64 | uint8_t ret; |
65 | |
66 | if (fifo->num == 0) { |
67 | abort(); |
68 | } |
69 | ret = fifo->data[fifo->head++]; |
70 | fifo->head %= fifo->capacity; |
71 | fifo->num--; |
72 | return ret; |
73 | } |
74 | |
75 | const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num) |
76 | { |
77 | uint8_t *ret; |
78 | |
79 | if (max == 0 || max > fifo->num) { |
80 | abort(); |
81 | } |
82 | *num = MIN(fifo->capacity - fifo->head, max); |
83 | ret = &fifo->data[fifo->head]; |
84 | fifo->head += *num; |
85 | fifo->head %= fifo->capacity; |
86 | fifo->num -= *num; |
87 | return ret; |
88 | } |
89 | |
90 | void fifo8_reset(Fifo8 *fifo) |
91 | { |
92 | fifo->num = 0; |
93 | fifo->head = 0; |
94 | } |
95 | |
96 | bool fifo8_is_empty(Fifo8 *fifo) |
97 | { |
98 | return (fifo->num == 0); |
99 | } |
100 | |
101 | bool fifo8_is_full(Fifo8 *fifo) |
102 | { |
103 | return (fifo->num == fifo->capacity); |
104 | } |
105 | |
106 | uint32_t fifo8_num_free(Fifo8 *fifo) |
107 | { |
108 | return fifo->capacity - fifo->num; |
109 | } |
110 | |
111 | uint32_t fifo8_num_used(Fifo8 *fifo) |
112 | { |
113 | return fifo->num; |
114 | } |
115 | |
116 | const VMStateDescription vmstate_fifo8 = { |
117 | .name = "Fifo8" , |
118 | .version_id = 1, |
119 | .minimum_version_id = 1, |
120 | .fields = (VMStateField[]) { |
121 | VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, capacity), |
122 | VMSTATE_UINT32(head, Fifo8), |
123 | VMSTATE_UINT32(num, Fifo8), |
124 | VMSTATE_END_OF_LIST() |
125 | } |
126 | }; |
127 | |