summaryrefslogtreecommitdiff
path: root/src/devices/serial
diff options
context:
space:
mode:
authortaitep <taitep@taitep.se>2026-01-29 19:07:43 +0100
committertaitep <taitep@taitep.se>2026-01-29 19:07:43 +0100
commitbbfa20befe163c04d0a99278107f2608639318d3 (patch)
treeada64685dcefcf587fb2016a77a78a47465cd290 /src/devices/serial
parent36e6ec10069fe84aa677ab9ea4446e7fa3332886 (diff)
Replace custom UART with a sifive uart subset
Diffstat (limited to 'src/devices/serial')
-rw-r--r--src/devices/serial/fifo.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/devices/serial/fifo.rs b/src/devices/serial/fifo.rs
new file mode 100644
index 0000000..dbf4659
--- /dev/null
+++ b/src/devices/serial/fifo.rs
@@ -0,0 +1,113 @@
+// Copyright (c) 2026 taitep
+// SPDX-License-Identifier: BSD-2-Clause
+//
+// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
+// See LICENSE file in the project root for full license text.
+
+use std::io::{self, Read, Write};
+
+pub struct UartFifo<const CAP: usize> {
+ buf: [u8; CAP],
+ head: usize,
+ tail: usize,
+ len: usize,
+}
+
+impl<const CAP: usize> UartFifo<CAP> {
+ pub fn pop_single_byte(&mut self) -> Option<u8> {
+ if self.is_empty() {
+ return None;
+ }
+
+ let value = self.buf[self.tail];
+ self.advance_read(1);
+ Some(value)
+ }
+
+ pub fn push_single_byte(&mut self, value: u8) -> bool {
+ if self.is_full() {
+ return false;
+ }
+
+ self.buf[self.head] = value;
+ self.advance_write(1);
+ true
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.len == 0
+ }
+
+ pub fn is_full(&self) -> bool {
+ self.len == CAP
+ }
+
+ fn write_slice(&mut self) -> &mut [u8] {
+ if self.is_full() {
+ return &mut [];
+ }
+
+ if self.head >= self.tail {
+ &mut self.buf[self.head..]
+ } else {
+ &mut self.buf[self.head..self.tail]
+ }
+ }
+
+ fn advance_write(&mut self, n: usize) {
+ debug_assert!(n <= CAP - self.len);
+ self.head = (self.head + n) % CAP;
+ self.len += n;
+ }
+
+ fn read_slice(&self) -> &[u8] {
+ if self.is_empty() {
+ return &[];
+ }
+
+ if self.tail < self.head {
+ &self.buf[self.tail..self.head]
+ } else {
+ &self.buf[self.tail..]
+ }
+ }
+
+ fn advance_read(&mut self, n: usize) {
+ debug_assert!(n <= self.len);
+ self.tail = (self.tail + n) % CAP;
+ self.len -= n;
+ }
+
+ pub fn read_from<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
+ let slice = self.write_slice();
+ if slice.is_empty() {
+ return Ok(0);
+ }
+
+ let n = reader.read(slice)?;
+ self.advance_write(n);
+ Ok(n)
+ }
+
+ pub fn write_to<W: Write>(&mut self, writer: &mut W) -> io::Result<usize> {
+ let slice = self.read_slice();
+ if slice.is_empty() {
+ return Ok(0);
+ }
+
+ let n = writer.write(slice)?;
+ self.advance_read(n);
+ Ok(n)
+ }
+}
+
+impl<const SIZE: usize> Default for UartFifo<SIZE> {
+ fn default() -> Self {
+ UartFifo {
+ buf: [0; SIZE],
+ head: 0,
+ tail: 0,
+ len: 0,
+ }
+ }
+}