From 0457530e0c91ad64065e3a63fad41a25ff312b36 Mon Sep 17 00:00:00 2001 From: taitep Date: Sun, 21 Dec 2025 15:27:39 +0100 Subject: [PATCH] Add a basic UART (very much temporary, its performance is most likely horrible --- src/basic_uart.rs | 154 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 25 ++++++-- 2 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 src/basic_uart.rs diff --git a/src/basic_uart.rs b/src/basic_uart.rs new file mode 100644 index 0000000..04230a2 --- /dev/null +++ b/src/basic_uart.rs @@ -0,0 +1,154 @@ +use std::collections::VecDeque; +use std::io::{Read, Write, stdin, stdout}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; + +use trve::consts::{Byte, DWord, HWord, Word}; +use trve::mem::{MemAccessFault, MemDeviceInterface, PageNum}; + +/// byte 0: rx/tx +/// byte 1: status (------rt, r=rxready, t=txready)/none +pub struct BasicUart { + buffers: Mutex, +} + +struct UartBuffers { + rx: VecDeque, + tx: VecDeque, +} + +impl BasicUart { + pub fn new() -> Self { + BasicUart { + buffers: Mutex::new(UartBuffers { + rx: VecDeque::new(), + tx: VecDeque::new(), + }), + } + } + + pub fn spawn_poller(self, poll_interval: Duration) -> Arc { + let shared = Arc::new(self); + + let uart_clone = shared.clone(); + + thread::spawn(move || { + loop { + uart_clone.poll(); + thread::sleep(poll_interval); + } + }); + + shared + } + + fn write(&self, byte: u8) { + let mut bufs = self.buffers.lock().unwrap(); + bufs.tx.push_back(byte); + } + + fn read(&self) -> u8 { + let mut bufs = self.buffers.lock().unwrap(); + bufs.rx.pop_front().unwrap_or(0) + } + + fn can_read(&self) -> bool { + let bufs = self.buffers.lock().unwrap(); + !bufs.rx.is_empty() + } + + pub fn poll(&self) { + let mut bufs = self.buffers.lock().unwrap(); + + while let Some(byte) = bufs.tx.pop_front() { + print!("{}", byte as char); + } + stdout().flush().unwrap(); + + let mut buffer = [0u8; 1]; + if let Ok(n) = stdin().read(&mut buffer) { + if n > 0 { + bufs.rx.push_back(buffer[0]); + } + } + } +} + +impl MemDeviceInterface for BasicUart { + fn write_dword( + &self, + _page: PageNum, + _offset: u16, + _value: DWord, + ) -> Result<(), MemAccessFault> { + Err(MemAccessFault) + } + + fn write_word(&self, _page: PageNum, _offset: u16, _value: Word) -> Result<(), MemAccessFault> { + Err(MemAccessFault) + } + + fn write_hword( + &self, + _page: PageNum, + _offset: u16, + _value: HWord, + ) -> Result<(), MemAccessFault> { + Err(MemAccessFault) + } + + fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), MemAccessFault> { + if page > 0 { + return Err(MemAccessFault); + } + + match offset { + 0 => { + self.write(value); + Ok(()) + } + _ => Err(MemAccessFault), + } + } + + fn read_dword(&self, _page: PageNum, _offset: u16) -> Result { + Err(MemAccessFault) + } + + fn read_word(&self, _page: PageNum, _offset: u16) -> Result { + Err(MemAccessFault) + } + + fn read_hword(&self, _page: PageNum, _offset: u16) -> Result { + Err(MemAccessFault) + } + + fn read_byte(&self, page: PageNum, offset: u16) -> Result { + if page > 0 { + return Err(MemAccessFault); + } + + match offset { + 0 => Ok(self.read()), + 1 => Ok(1 | (self.can_read() as u8) << 1), + _ => Err(MemAccessFault), + } + } + + fn get_atomic_word( + &self, + _page: PageNum, + _offset: u16, + ) -> Result<&std::sync::atomic::AtomicU32, MemAccessFault> { + Err(MemAccessFault) + } + + fn get_atomic_dword( + &self, + _page: PageNum, + _offset: u16, + ) -> Result<&std::sync::atomic::AtomicU64, MemAccessFault> { + Err(MemAccessFault) + } +} diff --git a/src/main.rs b/src/main.rs index ef3e772..cdaa6eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use std::{ fs::File, io::{self, Read}, sync::Arc, + time::Duration, }; use trve::{ @@ -17,6 +18,8 @@ use trve::{ mem::{DeviceEntry, MemAccessFault, MemConfig, MemDeviceInterface, PageNum, Ram}, }; +use crate::basic_uart::BasicUart; + fn read_file_to_buffer(path: &str, buffer: &mut [u8]) -> io::Result { let mut file = File::open(path)?; let mut total_read = 0; @@ -42,14 +45,24 @@ fn main() -> Result<(), Box> { let buf = ram.buf_mut(); read_file_to_buffer("./img", buf)?; + let uart = BasicUart::new(); + let uart = uart.spawn_poller(Duration::from_millis(10)); + let mem_cfg = MemConfig { ram: Arc::new(ram), ram_start: 0x8000_0000 / 4096, - devices: Box::new([DeviceEntry { - base: 0, - size: 1, - interface: Arc::new(DbgOut), - }]), + devices: Box::new([ + DeviceEntry { + base: 0, + size: 1, + interface: Arc::new(DbgOut), + }, + DeviceEntry { + base: 1, + size: 1, + interface: uart, + }, + ]), }; let mut core = Core::new(mem_cfg); @@ -59,6 +72,8 @@ fn main() -> Result<(), Box> { Ok(()) } +mod basic_uart; + struct DbgOut; impl MemDeviceInterface for DbgOut {