summaryrefslogtreecommitdiff
path: root/src/basic_uart.rs
blob: 8317950878af41f9d57de9aa8fd00711f40434a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright (c) 2025 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::collections::VecDeque;
use std::io;
use std::os::fd::AsFd;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

use nix::fcntl::fcntl;
use nix::fcntl::{FcntlArg, OFlag};
use trve::exceptions::{MemoryException, MemoryExceptionType};
use trve::mem::MemDeviceInterface;

/// byte 0: rx/tx
/// byte 1: status (------rt, r=rxready, t=txready)/none
pub struct BasicUart {
    rx_buf: Mutex<VecDeque<u8>>,
}

impl BasicUart {
    pub fn new() -> Self {
        // Make sure stdin is nonblocking
        let stdin = io::stdin();
        let fd = stdin.as_fd();
        let flags = fcntl(fd, FcntlArg::F_GETFL).unwrap();
        fcntl(
            fd,
            FcntlArg::F_SETFL(OFlag::from_bits_truncate(flags) | OFlag::O_NONBLOCK),
        )
        .unwrap();

        BasicUart {
            rx_buf: Mutex::new(VecDeque::new()),
        }
    }

    pub fn spawn_poller(self, poll_interval: Duration) -> Arc<Self> {
        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) {
        print!("{}", byte as char);
    }

    fn read(&self) -> u8 {
        self.rx_buf.lock().unwrap().pop_front().unwrap_or(0)
    }

    fn can_read(&self) -> bool {
        !self.rx_buf.lock().unwrap().is_empty()
    }

    pub fn poll(&self) {
        let mut rx_buf = self.rx_buf.lock().unwrap();

        let mut buffer = [0u8; 1];
        while let Ok(1) = nix::unistd::read(io::stdin().as_fd(), &mut buffer) {
            rx_buf.push_back(buffer[0]);
        }
    }
}

impl MemDeviceInterface for BasicUart {
    fn write_byte(&self, addr: u64, value: u8) -> Result<(), MemoryException> {
        match addr {
            0 => {
                self.write(value);
                Ok(())
            }
            _ => Err(MemoryException {
                type_: MemoryExceptionType::AccessFault,
                addr,
            }),
        }
    }
    fn read_byte(&self, addr: u64) -> Result<u8, MemoryException> {
        match addr {
            0 => Ok(self.read()),
            1 => Ok(1 | (self.can_read() as u8) << 1),
            _ => Err(MemoryException {
                type_: MemoryExceptionType::AccessFault,
                addr,
            }),
        }
    }
}