util/fifo8: implement push/pop of multiple bytes

The patch adds functions fifo8_push_all() and fifo8_pop_buf() which
can be used respectively to push the content of a memory buffer to the
fifo and to pop multiple bytes obtaining a pointer to the fifo backing
buffer.

In addition, it implements fifo8_num_free() and fifo8_num_used() which
allow to check if a multi-byte operation can be performed.

Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Beniamino Galvani 2014-01-30 23:02:04 +01:00 committed by Peter Maydell
parent 999b53ec87
commit c4e57af852
2 changed files with 107 additions and 0 deletions

View File

@ -43,6 +43,19 @@ void fifo8_destroy(Fifo8 *fifo);
void fifo8_push(Fifo8 *fifo, uint8_t data); void fifo8_push(Fifo8 *fifo, uint8_t data);
/**
* fifo8_push_all:
* @fifo: FIFO to push to
* @data: data to push
* @size: number of bytes to push
*
* Push a byte array to the FIFO. Behaviour is undefined if the FIFO is full.
* Clients are responsible for checking the space left in the FIFO using
* fifo8_num_free().
*/
void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num);
/** /**
* fifo8_pop: * fifo8_pop:
* @fifo: fifo to pop from * @fifo: fifo to pop from
@ -55,6 +68,32 @@ void fifo8_push(Fifo8 *fifo, uint8_t data);
uint8_t fifo8_pop(Fifo8 *fifo); uint8_t fifo8_pop(Fifo8 *fifo);
/**
* fifo8_pop_buf:
* @fifo: FIFO to pop from
* @max: maximum number of bytes to pop
* @num: actual number of returned bytes
*
* Pop a number of elements from the FIFO up to a maximum of max. The buffer
* containing the popped data is returned. This buffer points directly into
* the FIFO backing store and data is invalidated once any of the fifo8_* APIs
* are called on the FIFO.
*
* The function may return fewer bytes than requested when the data wraps
* around in the ring buffer; in this case only a contiguous part of the data
* is returned.
*
* The number of valid bytes returned is populated in *num; will always return
* at least 1 byte. max must not be 0 or greater than the number of bytes in
* the FIFO.
*
* Clients are responsible for checking the availability of requested data
* using fifo8_num_used().
*
* Returns: A pointer to popped data.
*/
const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num);
/** /**
* fifo8_reset: * fifo8_reset:
* @fifo: FIFO to reset * @fifo: FIFO to reset
@ -86,6 +125,28 @@ bool fifo8_is_empty(Fifo8 *fifo);
bool fifo8_is_full(Fifo8 *fifo); bool fifo8_is_full(Fifo8 *fifo);
/**
* fifo8_num_free:
* @fifo: FIFO to check
*
* Return the number of free bytes in the FIFO.
*
* Returns: Number of free bytes.
*/
uint32_t fifo8_num_free(Fifo8 *fifo);
/**
* fifo8_num_used:
* @fifo: FIFO to check
*
* Return the number of used bytes in the FIFO.
*
* Returns: Number of used bytes.
*/
uint32_t fifo8_num_used(Fifo8 *fifo);
extern const VMStateDescription vmstate_fifo8; extern const VMStateDescription vmstate_fifo8;
#define VMSTATE_FIFO8(_field, _state) { \ #define VMSTATE_FIFO8(_field, _state) { \

View File

@ -37,6 +37,27 @@ void fifo8_push(Fifo8 *fifo, uint8_t data)
fifo->num++; fifo->num++;
} }
void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num)
{
uint32_t start, avail;
if (fifo->num + num > fifo->capacity) {
abort();
}
start = (fifo->head + fifo->num) % fifo->capacity;
if (start + num <= fifo->capacity) {
memcpy(&fifo->data[start], data, num);
} else {
avail = fifo->capacity - start;
memcpy(&fifo->data[start], data, avail);
memcpy(&fifo->data[0], &data[avail], num - avail);
}
fifo->num += num;
}
uint8_t fifo8_pop(Fifo8 *fifo) uint8_t fifo8_pop(Fifo8 *fifo)
{ {
uint8_t ret; uint8_t ret;
@ -50,6 +71,21 @@ uint8_t fifo8_pop(Fifo8 *fifo)
return ret; return ret;
} }
const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num)
{
uint8_t *ret;
if (max == 0 || max > fifo->num) {
abort();
}
*num = MIN(fifo->capacity - fifo->head, max);
ret = &fifo->data[fifo->head];
fifo->head += *num;
fifo->head %= fifo->capacity;
fifo->num -= *num;
return ret;
}
void fifo8_reset(Fifo8 *fifo) void fifo8_reset(Fifo8 *fifo)
{ {
fifo->num = 0; fifo->num = 0;
@ -65,6 +101,16 @@ bool fifo8_is_full(Fifo8 *fifo)
return (fifo->num == fifo->capacity); return (fifo->num == fifo->capacity);
} }
uint32_t fifo8_num_free(Fifo8 *fifo)
{
return fifo->capacity - fifo->num;
}
uint32_t fifo8_num_used(Fifo8 *fifo)
{
return fifo->num;
}
const VMStateDescription vmstate_fifo8 = { const VMStateDescription vmstate_fifo8 = {
.name = "Fifo8", .name = "Fifo8",
.version_id = 1, .version_id = 1,