// Copyright (c) 2026 taitep // SPDX-License-Identifier: BSD-2-Clause // // This file is part of TRVE (https://git.taitep.se/trve.git) // See LICENSE file in the project root for full license text. use std::{ io::{Read, Write}, sync::{Arc, Mutex}, time::Duration, }; mod fifo; use fifo::UartFifo; use crate::{exceptions::MemoryExceptionType, mem::MemDeviceInterface}; pub struct SifiveUart { rx: Mutex<(UartFifo<2048>, bool)>, tx: Mutex<(UartFifo<2048>, bool)>, } impl SifiveUart { pub fn new_arc() -> Arc { Arc::new(Self { rx: Mutex::new((UartFifo::default(), false)), tx: Mutex::new((UartFifo::default(), false)), }) } pub fn spawn_io_thread( self: Arc, mut rx_backend: R, mut tx_backend: T, interval: Duration, ) { std::thread::spawn(move || { loop { { // Read data let mut rx_guard = self.rx.lock().expect("could not lock uart RX half"); let (rx_buf, rx_en) = &mut *rx_guard; if *rx_en { let _ = rx_buf.read_from(&mut rx_backend); } } { // Write data let mut tx_guard = self.tx.lock().expect("could not lock uart RX half"); let (tx_buf, tx_en) = &mut *tx_guard; if *tx_en { let _ = tx_buf.write_to(&mut tx_backend); let _ = tx_backend.flush(); } } std::thread::sleep(interval); } }); } } impl MemDeviceInterface for SifiveUart { fn write_word(&self, addr: u64, value: u32) -> Result<(), MemoryExceptionType> { // dbg!(addr, value); match addr { 0x00 => { // TXDATA let (ref mut tx_buf, _) = *self.tx.lock().expect("could not lock uart TX half"); tx_buf.push_single_byte(value as u8); Ok(()) } 0x08 => { // TXCTRL let (_, ref mut tx_en) = *self.tx.lock().expect("could not lock uart TX half"); *tx_en = value & 1 != 0; Ok(()) } 0x04 => Ok(()), // RXDATA 0x0c => { // RXCTRL let (_, ref mut rx_en) = *self.rx.lock().expect("could not lock uart RX half"); *rx_en = value & 1 != 0; Ok(()) } 0x10 => Ok(()), // IE 0x14 => Ok(()), // IP 0x18 => Ok(()), // DIV _ => { if addr < 0x1c { Err(MemoryExceptionType::AddressMisaligned) } else { Err(MemoryExceptionType::AccessFault) } } } } fn read_word(&self, addr: u64) -> Result { // dbg!(addr); match addr { 0x00 => { // TXDATA let (ref tx_buf, _) = *self.tx.lock().expect("could not lock uart TX half"); Ok(if tx_buf.is_full() { 0x80000000 } else { 0 }) } 0x08 => { // TXCTRL let (_, tx_en) = *self.tx.lock().expect("could not lock uart TX half"); Ok(if tx_en { 1 } else { 0 }) } 0x04 => { // RXDATA let (ref mut rx_buf, _) = *self.rx.lock().expect("could not lock uart RX half"); Ok(match rx_buf.pop_single_byte() { None => 0x80000000, Some(b) => b as u32, }) } 0x0c => { // RXCTRL let (_, rx_en) = *self.rx.lock().expect("could not lock uart RX half"); Ok(if rx_en { 1 } else { 0 }) } 0x10 => Ok(0), // IE 0x14 => Ok(0), // IP 0x18 => Ok(1), // DIV _ => { if addr < 0x1c { Err(MemoryExceptionType::AddressMisaligned) } else { Err(MemoryExceptionType::AccessFault) } } } } }