use std::io;
use std::io::prelude::*;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Condvar, Mutex,
};
use std::thread;
use crate::bus::{UART_BASE, UART_SIZE};
use crate::cpu::BYTE;
use crate::exception::Exception;
pub const UART_IRQ: u64 = 10;
pub const UART_RHR: u64 = UART_BASE + 0;
pub const UART_THR: u64 = UART_BASE + 0;
pub const UART_IER: u64 = UART_BASE + 1;
pub const UART_FCR: u64 = UART_BASE + 2;
pub const UART_ISR: u64 = UART_BASE + 2;
pub const UART_LCR: u64 = UART_BASE + 3;
pub const UART_LSR: u64 = UART_BASE + 5;
pub const UART_LSR_RX: u8 = 1;
pub const UART_LSR_TX: u8 = 1 << 5;
pub struct Uart {
uart: Arc<(Mutex<[u8; UART_SIZE as usize]>, Condvar)>,
interrupting: Arc<AtomicBool>,
}
impl Uart {
pub fn new() -> Self {
let uart = Arc::new((Mutex::new([0; UART_SIZE as usize]), Condvar::new()));
let interrupting = Arc::new(AtomicBool::new(false));
{
let (uart, _cvar) = &*uart;
let mut uart = uart.lock().expect("failed to get an UART object");
uart[(UART_LSR - UART_BASE) as usize] |= UART_LSR_TX;
}
let mut byte = [0; 1];
let cloned_uart = uart.clone();
let cloned_interrupting = interrupting.clone();
let _uart_thread_for_read = thread::spawn(move || loop {
match io::stdin().read(&mut byte) {
Ok(_) => {
let (uart, cvar) = &*cloned_uart;
let mut uart = uart.lock().expect("failed to get an UART object");
while (uart[(UART_LSR - UART_BASE) as usize] & UART_LSR_RX) == 1 {
uart = cvar.wait(uart).expect("the mutex is poisoned");
}
uart[0] = byte[0];
cloned_interrupting.store(true, Ordering::Release);
uart[(UART_LSR - UART_BASE) as usize] |= UART_LSR_RX;
}
Err(e) => {
println!("input via UART is error: {}", e);
}
}
});
Self { uart, interrupting }
}
pub fn is_interrupting(&self) -> bool {
self.interrupting.swap(false, Ordering::Acquire)
}
pub fn read(&mut self, index: u64, size: u8) -> Result<u64, Exception> {
if size != BYTE {
return Err(Exception::LoadAccessFault);
}
let (uart, cvar) = &*self.uart;
let mut uart = uart.lock().expect("failed to get an UART object");
match index {
UART_RHR => {
cvar.notify_one();
uart[(UART_LSR - UART_BASE) as usize] &= !UART_LSR_RX;
Ok(uart[(UART_RHR - UART_BASE) as usize] as u64)
}
_ => Ok(uart[(index - UART_BASE) as usize] as u64),
}
}
pub fn write(&mut self, index: u64, value: u8, size: u8) -> Result<(), Exception> {
if size != BYTE {
return Err(Exception::StoreAMOAccessFault);
}
let (uart, _cvar) = &*self.uart;
let mut uart = uart.lock().expect("failed to get an UART object");
match index {
UART_THR => {
print!("{}", value as char);
io::stdout().flush().expect("failed to flush stdout");
}
_ => {
uart[(index - UART_BASE) as usize] = value;
}
}
Ok(())
}
}