mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-13 03:34:35 +00:00
033c4e9a5b
* Updated style * Updated files * fixed new line * Updated spacing * File fix WIP * Updated to clang 13 * updated comment style * Removed old comment code
239 lines
4.9 KiB
C++
239 lines
4.9 KiB
C++
/*
|
|
* Copyright (C) 2013 Jared Boone, ShareBrained Technology, Inc.
|
|
*
|
|
* This file is part of PortaPack.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifndef __FIFO_H__
|
|
#define __FIFO_H__
|
|
|
|
#include <cstddef>
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <memory>
|
|
|
|
#include <hal.h>
|
|
|
|
/* FIFO implementation inspired by Linux kfifo. */
|
|
|
|
template <typename T>
|
|
class FIFO {
|
|
public:
|
|
constexpr FIFO(
|
|
T* data,
|
|
size_t k)
|
|
: _data{data},
|
|
_size{1U << k},
|
|
_in{0},
|
|
_out{0} {
|
|
}
|
|
|
|
void reset() {
|
|
_in = _out = 0;
|
|
}
|
|
|
|
void reset_in() {
|
|
_in = _out;
|
|
}
|
|
|
|
void reset_out() {
|
|
_out = _in;
|
|
}
|
|
|
|
size_t len() const {
|
|
return _in - _out;
|
|
}
|
|
|
|
size_t unused() const {
|
|
return size() - (_in - _out);
|
|
}
|
|
|
|
bool is_empty() const {
|
|
return _in == _out;
|
|
}
|
|
|
|
bool is_full() const {
|
|
return unused() == 0;
|
|
}
|
|
|
|
bool in(const T& val) {
|
|
if (is_full()) {
|
|
return false;
|
|
}
|
|
|
|
_data[_in & mask()] = val;
|
|
smp_wmb();
|
|
_in += 1;
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t in(const T* const buf, size_t len) {
|
|
const size_t l = unused();
|
|
if (len > l) {
|
|
len = l;
|
|
}
|
|
|
|
copy_in(buf, len, _in);
|
|
_in += len;
|
|
return len;
|
|
}
|
|
|
|
size_t in_r(const void* const buf, const size_t len) {
|
|
if ((len + recsize()) > unused()) {
|
|
return 0;
|
|
}
|
|
|
|
poke_n(len);
|
|
copy_in((const T*)buf, len, _in + recsize());
|
|
_in += len + recsize();
|
|
return len;
|
|
}
|
|
|
|
bool out(T& val) {
|
|
if (is_empty()) {
|
|
return false;
|
|
}
|
|
|
|
val = _data[_out & mask()]; // Crashes
|
|
smp_wmb(); // Ok
|
|
_out += 1; // Crashes
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t out(T* const buf, size_t len) {
|
|
len = out_peek(buf, len);
|
|
_out += len;
|
|
return len;
|
|
}
|
|
|
|
bool skip() {
|
|
if (is_empty()) {
|
|
return false;
|
|
}
|
|
|
|
size_t len = peek_n();
|
|
_out += len + recsize();
|
|
return true;
|
|
}
|
|
|
|
size_t peek_r(void* const buf, size_t len) {
|
|
if (is_empty()) {
|
|
return 0;
|
|
}
|
|
|
|
size_t n;
|
|
len = out_copy_r((T*)buf, len, &n);
|
|
return len;
|
|
}
|
|
|
|
size_t out_r(void* const buf, size_t len) {
|
|
if (is_empty()) {
|
|
return 0;
|
|
}
|
|
|
|
size_t n;
|
|
len = out_copy_r((T*)buf, len, &n);
|
|
_out += n + recsize();
|
|
return len;
|
|
}
|
|
|
|
private:
|
|
size_t size() const {
|
|
return _size;
|
|
}
|
|
|
|
static constexpr size_t esize() {
|
|
return sizeof(T);
|
|
}
|
|
|
|
size_t mask() const {
|
|
return size() - 1;
|
|
}
|
|
|
|
static constexpr size_t recsize() {
|
|
return 2;
|
|
}
|
|
|
|
void smp_wmb() {
|
|
__DMB();
|
|
}
|
|
|
|
size_t peek_n() {
|
|
size_t l = _data[_out & mask()];
|
|
if (recsize() > 1) {
|
|
l |= _data[(_out + 1) & mask()] << 8;
|
|
}
|
|
return l;
|
|
}
|
|
|
|
void poke_n(const size_t n) {
|
|
_data[_in & mask()] = n & 0xff;
|
|
if (recsize() > 1) {
|
|
_data[(_in + 1) & mask()] = (n >> 8) & 0xff;
|
|
}
|
|
}
|
|
|
|
void copy_in(const T* const src, const size_t len, size_t off) {
|
|
off &= mask();
|
|
const size_t l = std::min(len, size() - off);
|
|
|
|
memcpy(&_data[off], &src[0], l * esize());
|
|
memcpy(&_data[0], &src[l], (len - l) * esize());
|
|
smp_wmb();
|
|
}
|
|
|
|
void copy_out(T* const dst, const size_t len, size_t off) {
|
|
off &= mask();
|
|
const size_t l = std::min(len, size() - off);
|
|
|
|
memcpy(&dst[0], &_data[off], l * esize());
|
|
memcpy(&dst[l], &_data[0], (len - l) * esize());
|
|
smp_wmb();
|
|
}
|
|
|
|
size_t out_copy_r(void* buf, size_t len, size_t* const n) {
|
|
*n = peek_n();
|
|
|
|
if (len > *n) {
|
|
len = *n;
|
|
}
|
|
|
|
copy_out((T*)buf, len, _out + recsize());
|
|
return len;
|
|
}
|
|
|
|
size_t out_peek(T* const buf, size_t buf_len) {
|
|
const size_t l = len();
|
|
if (buf_len > l) {
|
|
buf_len = l;
|
|
}
|
|
|
|
copy_out(buf, buf_len, _out);
|
|
return buf_len;
|
|
}
|
|
|
|
T* const _data;
|
|
const size_t _size;
|
|
volatile size_t _in;
|
|
volatile size_t _out;
|
|
};
|
|
|
|
#endif /*__FIFO_H__*/
|