Skip to main content

tg_rcore_tutorial_uart1/
uart.rs

1//! NS16550A 串口驱动实现
2//!
3//! 提供寄存器定义、硬件初始化和字符输入输出操作。
4//! 详细说明请参考 doc/note&sum/uart-driver-summary.md
5
6/// 串口驱动错误类型
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum UartError {
9    /// 初始化失败
10    InitFailed,
11    /// 发送超时
12    TxTimeout,
13    /// 接收超时
14    RxTimeout,
15}
16
17/// 串口驱动结果别名
18pub type Result<T> = core::result::Result<T, UartError>;
19
20/// QEMU virt 机器 UART0 基地址
21const UART0: usize = 0x1000_0000;
22
23/// 寄存器偏移量(某些寄存器读写时有不同含义)
24const RHR: usize = 0; // 接收保持寄存器(只读)
25const THR: usize = 0; // 发送保持寄存器(只写)
26const IER: usize = 1; // 中断使能寄存器
27const FCR: usize = 2; // FIFO 控制寄存器(只写)
28#[allow(dead_code)]
29const ISR: usize = 2; // 中断状态寄存器(只读)
30const LCR: usize = 3; // 线路控制寄存器
31const LSR: usize = 5; // 线路状态寄存器
32
33/// 中断使能寄存器(IER)标志位
34mod ier {
35    #[allow(dead_code)]
36    pub const RX_ENABLE: u8 = 1 << 0;
37    #[allow(dead_code)]
38    pub const TX_ENABLE: u8 = 1 << 1;
39}
40
41/// FIFO 控制寄存器(FCR)标志位
42mod fcr {
43    pub const FIFO_ENABLE: u8 = 1 << 0;
44    pub const RX_FIFO_CLEAR: u8 = 1 << 1;
45    pub const TX_FIFO_CLEAR: u8 = 1 << 2;
46    pub const FIFO_CLEAR: u8 = RX_FIFO_CLEAR | TX_FIFO_CLEAR;
47}
48
49/// 线路控制寄存器(LCR)标志位
50mod lcr {
51    pub const EIGHT_BITS: u8 = 3 << 0;
52    pub const BAUD_LATCH: u8 = 1 << 7;
53}
54
55/// 线路状态寄存器(LSR)标志位
56mod lsr {
57    pub const RX_READY: u8 = 1 << 0;
58    pub const TX_IDLE: u8 = 1 << 5;
59}
60
61/// UART 驱动结构体
62#[derive(Debug, Clone, Copy)]
63pub struct Uart;
64
65impl Uart {
66    /// 创建一个新的 UART 实例
67    #[inline]
68    pub const fn new() -> Self {
69        Self
70    }
71
72    /// 初始化 UART 硬件
73    ///
74    /// 配置波特率 38.4K,8 数据位,启用 FIFO,禁用中断。
75    /// 返回 `Ok(())` 表示成功,`Err(UartError::InitFailed)` 表示失败。
76    pub fn init() -> Result<()> {
77        unsafe { write_reg(IER, 0) };
78        unsafe { write_reg(LCR, lcr::BAUD_LATCH) };
79        unsafe { write_reg(0, 0x03) };
80        unsafe { write_reg(1, 0x00) };
81        unsafe { write_reg(LCR, lcr::EIGHT_BITS) };
82        unsafe { write_reg(FCR, fcr::FIFO_ENABLE | fcr::FIFO_CLEAR) };
83        Ok(())
84    }
85
86    /// 同步输出字符,用于 panic 处理
87    ///
88    /// 参考 xv6 的 `uartputc_sync` 实现,轮询发送空闲并带有超时。
89    /// 在系统崩溃时确保输出,避免无限等待。
90    #[inline(never)]
91    pub fn put_char_sync(c: u8) -> Result<()> {
92        let mut timeout = 100_000;
93        while unsafe { read_reg(LSR) } & lsr::TX_IDLE == 0 {
94            timeout -= 1;
95            if timeout == 0 {
96                return Err(UartError::TxTimeout);
97            }
98        }
99        unsafe { write_reg(THR, c) };
100        Ok(())
101    }
102
103    /// 向 UART 输出单个字符
104    ///
105    /// 阻塞直到发送器准备就绪,轮询 LSR 寄存器直到 TX_IDLE 标志置位。
106    #[inline]
107    pub fn put_char(c: u8) {
108        while unsafe { read_reg(LSR) } & lsr::TX_IDLE == 0 {}
109        unsafe { write_reg(THR, c) };
110    }
111
112    /// 向 UART 输出字符串
113    #[inline]
114    pub fn put_str(s: &str) {
115        for c in s.bytes() {
116            Self::put_char(c);
117        }
118    }
119
120    /// 尝试从 UART 读取字符
121    ///
122    /// 如果有字符可用则返回 `Some(c)`,否则返回 `None`。
123    #[inline]
124    pub fn try_get_char() -> Option<u8> {
125        if unsafe { read_reg(LSR) } & lsr::RX_READY != 0 {
126            Some(unsafe { read_reg(RHR) })
127        } else {
128            None
129        }
130    }
131}
132
133/// 从 UART 寄存器读取一个字节
134#[inline]
135unsafe fn read_reg(offset: usize) -> u8 {
136    let addr = UART0 + offset;
137    unsafe { (addr as *const u8).read_volatile() }
138}
139
140/// 向 UART 寄存器写入一个字节
141#[inline]
142unsafe fn write_reg(offset: usize, value: u8) {
143    let addr = UART0 + offset;
144    unsafe { (addr as *mut u8).write_volatile(value) }
145}