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_reset(Fifo8 *fifo) 20 { 21 fifo->num = 0; 22 fifo->head = 0; 23 } 24 25 void fifo8_create(Fifo8 *fifo, uint32_t capacity) 26 { 27 fifo->data = g_new(uint8_t, capacity); 28 fifo->capacity = capacity; 29 fifo8_reset(fifo); 30 } 31 32 void fifo8_destroy(Fifo8 *fifo) 33 { 34 g_free(fifo->data); 35 } 36 37 void fifo8_push(Fifo8 *fifo, uint8_t data) 38 { 39 assert(fifo->num < fifo->capacity); 40 fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; 41 fifo->num++; 42 } 43 44 void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num) 45 { 46 uint32_t start, avail; 47 48 assert(fifo->num + num <= fifo->capacity); 49 50 start = (fifo->head + fifo->num) % fifo->capacity; 51 52 if (start + num <= fifo->capacity) { 53 memcpy(&fifo->data[start], data, num); 54 } else { 55 avail = fifo->capacity - start; 56 memcpy(&fifo->data[start], data, avail); 57 memcpy(&fifo->data[0], &data[avail], num - avail); 58 } 59 60 fifo->num += num; 61 } 62 63 uint8_t fifo8_pop(Fifo8 *fifo) 64 { 65 uint8_t ret; 66 67 assert(fifo->num > 0); 68 ret = fifo->data[fifo->head++]; 69 fifo->head %= fifo->capacity; 70 fifo->num--; 71 return ret; 72 } 73 74 uint8_t fifo8_peek(Fifo8 *fifo) 75 { 76 assert(fifo->num > 0); 77 return fifo->data[fifo->head]; 78 } 79 80 static const uint8_t *fifo8_peekpop_bufptr(Fifo8 *fifo, uint32_t max, 81 uint32_t skip, uint32_t *numptr, 82 bool do_pop) 83 { 84 uint8_t *ret; 85 uint32_t num, head; 86 87 assert(max > 0 && max <= fifo->num); 88 assert(skip <= fifo->num); 89 head = (fifo->head + skip) % fifo->capacity; 90 num = MIN(fifo->capacity - head, max); 91 ret = &fifo->data[head]; 92 93 if (do_pop) { 94 fifo->head = head + num; 95 fifo->head %= fifo->capacity; 96 fifo->num -= num; 97 } 98 if (numptr) { 99 *numptr = num; 100 } 101 return ret; 102 } 103 104 const uint8_t *fifo8_peek_bufptr(Fifo8 *fifo, uint32_t max, uint32_t *numptr) 105 { 106 return fifo8_peekpop_bufptr(fifo, max, 0, numptr, false); 107 } 108 109 const uint8_t *fifo8_pop_bufptr(Fifo8 *fifo, uint32_t max, uint32_t *numptr) 110 { 111 return fifo8_peekpop_bufptr(fifo, max, 0, numptr, true); 112 } 113 114 static uint32_t fifo8_peekpop_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen, 115 bool do_pop) 116 { 117 const uint8_t *buf; 118 uint32_t n1, n2 = 0; 119 uint32_t len; 120 121 if (destlen == 0) { 122 return 0; 123 } 124 125 len = destlen; 126 buf = fifo8_peekpop_bufptr(fifo, len, 0, &n1, do_pop); 127 if (dest) { 128 memcpy(dest, buf, n1); 129 } 130 131 /* Add FIFO wraparound if needed */ 132 len -= n1; 133 len = MIN(len, fifo8_num_used(fifo)); 134 if (len) { 135 buf = fifo8_peekpop_bufptr(fifo, len, do_pop ? 0 : n1, &n2, do_pop); 136 if (dest) { 137 memcpy(&dest[n1], buf, n2); 138 } 139 } 140 141 return n1 + n2; 142 } 143 144 uint32_t fifo8_pop_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen) 145 { 146 return fifo8_peekpop_buf(fifo, dest, destlen, true); 147 } 148 149 uint32_t fifo8_peek_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen) 150 { 151 return fifo8_peekpop_buf(fifo, dest, destlen, false); 152 } 153 154 void fifo8_drop(Fifo8 *fifo, uint32_t len) 155 { 156 len -= fifo8_pop_buf(fifo, NULL, len); 157 assert(len == 0); 158 } 159 160 bool fifo8_is_empty(Fifo8 *fifo) 161 { 162 return (fifo->num == 0); 163 } 164 165 bool fifo8_is_full(Fifo8 *fifo) 166 { 167 return (fifo->num == fifo->capacity); 168 } 169 170 uint32_t fifo8_num_free(Fifo8 *fifo) 171 { 172 return fifo->capacity - fifo->num; 173 } 174 175 uint32_t fifo8_num_used(Fifo8 *fifo) 176 { 177 return fifo->num; 178 } 179 180 const VMStateDescription vmstate_fifo8 = { 181 .name = "Fifo8", 182 .version_id = 1, 183 .minimum_version_id = 1, 184 .fields = (const VMStateField[]) { 185 VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, capacity), 186 VMSTATE_UINT32(head, Fifo8), 187 VMSTATE_UINT32(num, Fifo8), 188 VMSTATE_END_OF_LIST() 189 } 190 }; 191