diff --git a/src/main.rs b/src/main.rs index 1ebd35c3..d3b777e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use panic_abort as _; use r0::zero_bss; +mod regs; mod cortex_a9; mod slcr; mod uart; diff --git a/src/regs.rs b/src/regs.rs new file mode 100644 index 00000000..4a0265fc --- /dev/null +++ b/src/regs.rs @@ -0,0 +1,108 @@ +//! Interface to peripheral registers akin to the code that svd2rust +//! generates. + +use volatile_register::{RO, WO, RW}; +use bit_field::BitField; + +pub trait Register { + type R; + type W; + + fn read(&self) -> Self::R; + fn write(&self, w: Self::W); + fn modify Self::W>(&self, f: F); +} + +#[macro_export] +macro_rules! register { + ($mod_name: ident, $struct_name: ident, $inner: ty) => ( + #[repr(packed)] + pub struct $struct_name { + inner: RW<$inner>, + } + + pub mod $mod_name { + pub struct Read { + pub inner: $inner, + } + pub struct Write { + pub inner: $inner, + } + } + + impl $struct_name { + pub fn zeroed() -> $mod_name::Write { + $mod_name::Write { inner: 0 } + } + } + + impl crate::regs::Register for $struct_name { + type R = $mod_name::Read; + type W = $mod_name::Write; + + fn read(&self) -> Self::R { + let inner = self.inner.read(); + $mod_name::Read { inner } + } + + fn write(&self, w: Self::W) { + unsafe { + self.inner.write(w.inner); + } + } + + fn modify Self::W>(&self, f: F) { + unsafe { + self.inner.modify(|inner| { + f($mod_name::Read { inner }, $mod_name::Write { inner }) + .inner + }); + } + } + } + ); +} + +#[macro_export] +macro_rules! register_bit { + ($mod_name: ident, $name: ident, $bit: expr) => ( + impl $mod_name::Read { + fn $name(&self) -> bool { + use bit_field::BitField; + + self.inner.get_bit($bit) + } + } + + impl $mod_name::Write { + fn $name(mut self, value: bool) -> Self { + use bit_field::BitField; + + self.inner.set_bit($bit, value); + self + } + } + ); +} + +#[macro_export] +macro_rules! register_bits { + ($mod_name: ident, $name: ident, $type: ty, $bit_begin: expr, $bit_end: expr) => ( + impl $mod_name::Read { + fn $name(&self) -> $type { + use bit_field::BitField; + + self.inner.get_bits($bit_begin..=$bit_end) as $type + } + } + + impl $mod_name::Write { + fn $name(mut self, value: $type) -> Self { + use bit_field::BitField; + + self.inner.set_bits($bit_begin..=$bit_end, value.into()); + self + } + } + ); +} diff --git a/src/slcr.rs b/src/slcr.rs index b95c35c6..cc31b146 100644 --- a/src/slcr.rs +++ b/src/slcr.rs @@ -1,40 +1,31 @@ -use core::ops::RangeInclusive; use volatile_register::{RO, WO, RW}; -use bit_field::BitField; +use crate::{register, register_bit, register_bits, regs::Register}; -#[repr(packed)] -pub struct UartClkCtrl { - pub reg: RW, -} - +register!(uart_clk_ctrl, UartClkCtrl, u32); +register_bit!(uart_clk_ctrl, clkact0, 0); +register_bit!(uart_clk_ctrl, clkact1, 1); +register_bits!(uart_clk_ctrl, divisor, u8, 8, 13); impl UartClkCtrl { const ADDR: *mut Self = 0xF8000154 as *mut _; pub fn new() -> &'static mut Self { unsafe { &mut *Self::ADDR } } - - const DIVISOR: RangeInclusive = 8..=13; - const CLKACT1: usize = 1; - const CLKACT0: usize = 0; pub fn enable_uart0(&self) { - unsafe { - self.reg.modify(|mut x| { - x.set_bits(Self::DIVISOR, 0x14); - x.set_bit(Self::CLKACT0, true); - x - }) - } + self.modify(|_, w| { + w.clkact0(true) + .divisor(0x14) + }) } } -#[repr(packed)] -pub struct UartRstCtrl { - pub reg: RW, -} - +register!(uart_rst_ctrl, UartRstCtrl, u32); +register_bit!(uart_rst_ctrl, uart0_ref_rst, 3); +register_bit!(uart_rst_ctrl, uart1_ref_rst, 2); +register_bit!(uart_rst_ctrl, uart0_cpu1x_rst, 1); +register_bit!(uart_rst_ctrl, uart1_cpu1x_rst, 0); impl UartRstCtrl { const ADDR: *mut Self = 0xF8000228 as *mut _; @@ -42,29 +33,13 @@ impl UartRstCtrl { unsafe { &mut *Self::ADDR } } - const UART1_REF_RST: usize = 3; - const UART0_REF_RST: usize = 2; - const UART1_CPU1X_RST: usize = 1; - const UART0_CPU1X_RST: usize = 0; - pub fn reset_uart0(&self) { - unsafe { toggle(&self.reg, Self::UART0_REF_RST); } + self.modify(|_, w| w.uart0_ref_rst(true)); + self.modify(|_, w| w.uart0_ref_rst(false)); } pub fn reset_uart1(&self) { - unsafe { toggle(&self.reg, Self::UART1_REF_RST); } + self.modify(|_, w| w.uart1_ref_rst(true)); + self.modify(|_, w| w.uart1_ref_rst(false)); } } - -unsafe fn toggle(reg: &RW, bit: usize) { - reg.modify(|x| { - let mut x = x.clone(); - x.set_bit(bit, true); - x - }); - reg.modify(|x| { - let mut x = x.clone(); - x.set_bit(bit, false); - x - }); -} diff --git a/src/uart/mod.rs b/src/uart/mod.rs index f8ba3288..77ba127e 100644 --- a/src/uart/mod.rs +++ b/src/uart/mod.rs @@ -11,9 +11,9 @@ impl Uart { uart_rst_ctrl.reset_uart0(); // TODO: Route UART 0 RxD/TxD Signals to MIO Pins -// a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14. -// b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0. -// c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1. + // a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14. + // b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0. + // c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1. // d. Disable UART 1 Reference clock, slcr.UART_CLK_CTRL [CLKACT1] bit = 0. let uart_clk_ctrl = super::slcr::UartClkCtrl::new(); uart_clk_ctrl.enable_uart0(); diff --git a/src/uart/regs.rs b/src/uart/regs.rs index 0b1e6fb6..b9ea6046 100644 --- a/src/uart/regs.rs +++ b/src/uart/regs.rs @@ -1,28 +1,61 @@ use volatile_register::{RO, WO, RW}; use bit_field::BitField; +use crate::{register, register_bit, register_bits, regs::Register}; + +#[repr(u8)] +pub enum ParityMode { + EvenParity = 0b000, + OddParity = 0b001, + ForceTo0 = 0b010, + ForceTo1 = 0b011, +} + #[repr(packed)] pub struct RegisterBlock { - pub control: RW, - pub mode: RW, - pub intrpt_en: RW, - pub intrpt_dis: RW, - pub intrpt_mask: RO, - pub chnl_int_sts: WO, - pub baud_rate_gen: RW, - pub rcvr_timeout: RW, - pub rcvr_fifo_trigger_level: RW, - pub modem_ctrl: RW, - pub modem_sts: RW, - pub channel_sts: RO, - pub tx_rx_fifo: RW, - pub baud_rate_divider: RW, - pub flow_delay: RW, - pub reserved0: RO, - pub reserved1: RO, - pub tx_fifo_trigger_level: RW, + control: Control, + mode: Mode, + intrpt_en: RW, + intrpt_dis: RW, + intrpt_mask: RO, + chnl_int_sts: WO, + baud_rate_gen: BaudRateGen, + rcvr_timeout: RW, + rcvr_fifo_trigger_level: RW, + modem_ctrl: RW, + modem_sts: RW, + channel_sts: ChannelSts, + tx_rx_fifo: TxRxFifo, + baud_rate_divider: BaudRateDiv, + flow_delay: RW, + reserved0: RO, + reserved1: RO, + tx_fifo_trigger_level: RW, } +register!(control, Control, u32); +register_bit!(control, rxrst, 0); +register_bit!(control, txrst, 1); +register_bit!(control, rxen, 2); +register_bit!(control, rxdis, 3); +register_bit!(control, txen, 4); +register_bit!(control, txdis, 5); + +register!(mode, Mode, u32); +register_bits!(mode, par, u8, 3, 5); + +register!(baud_rate_gen, BaudRateGen, u32); +register_bits!(baud_rate_gen, cd, u16, 0, 15); + +register!(channel_sts, ChannelSts, u32); +register_bit!(channel_sts, txfull, 4); + +register!(tx_rx_fifo, TxRxFifo, u32); +register_bits!(tx_rx_fifo, data, u32, 0, 31); + +register!(baud_rate_div, BaudRateDiv, u32); +register_bits!(baud_rate_div, bdiv, u8, 0, 7); + impl RegisterBlock { const UART0: *mut Self = 0xE0000000 as *mut _; const UART1: *mut Self = 0xE0001000 as *mut _; @@ -36,90 +69,74 @@ impl RegisterBlock { } pub fn configure(&self) { - unsafe { - // Confiugre UART character frame - // * Disable clock-divider - // * 8-bit - // * no parity - // * 1 stop bit - // * Normal channel mode - self.mode.write(0x20); + // Confiugre UART character frame + // * Disable clock-divider + // * 8-bit + // * 1 stop bit + // * Normal channel mode + // * no parity + let parity_mode = ParityMode::ForceTo0; + self.mode.write(Mode::zeroed().par(parity_mode as u8)); - // Configure the Buad Rate - self.disable_rx(); - self.disable_tx(); + // Configure the Baud Rate + self.disable_rx(); + self.disable_tx(); - // 9,600 baud - self.baud_rate_gen.write(651); - self.baud_rate_divider.write(7); + // 9,600 baud + self.baud_rate_gen.write(BaudRateGen::zeroed().cd(651)); + self.baud_rate_divider.write(BaudRateDiv::zeroed().bdiv(7)); - self.reset_rx(); - self.reset_tx(); - self.enable_rx(); - self.enable_tx(); - } + self.reset_rx(); + self.reset_tx(); + self.enable_rx(); + self.enable_tx(); } - pub unsafe fn write_byte(&self, value: u8) { - self.tx_rx_fifo.write(value.into()); + pub fn write_byte(&self, value: u8) { + self.tx_rx_fifo.write(TxRxFifo::zeroed().data(value.into())); } - const CONTROL_RXEN: usize = 2; - const CONTROL_RXDIS: usize = 3; - const CONTROL_TXEN: usize = 4; - const CONTROL_TXDIS: usize = 5; - const CONTROL_TXRST: usize = 1; - const CONTROL_RXRST: usize = 0; - - unsafe fn disable_rx(&self) { - self.control.modify(|mut x| { - x.set_bit(Self::CONTROL_RXEN, false); - x.set_bit(Self::CONTROL_RXDIS, true); - x + fn disable_rx(&self) { + self.control.modify(|_, w| { + w.rxen(false) + .rxdis(true) }) } - unsafe fn disable_tx(&self) { - self.control.modify(|mut x| { - x.set_bit(Self::CONTROL_TXEN, false); - x.set_bit(Self::CONTROL_TXDIS, true); - x + fn disable_tx(&self) { + self.control.modify(|_, w| { + w.txen(false) + .txdis(true) }) } - unsafe fn enable_rx(&self) { - self.control.modify(|mut x| { - x.set_bit(Self::CONTROL_RXEN, true); - x.set_bit(Self::CONTROL_RXDIS, false); - x + fn enable_rx(&self) { + self.control.modify(|_, w| { + w.rxen(true) + .rxdis(false) }) } - unsafe fn enable_tx(&self) { - self.control.modify(|mut x| { - x.set_bit(Self::CONTROL_TXEN, true); - x.set_bit(Self::CONTROL_TXDIS, false); - x + fn enable_tx(&self) { + self.control.modify(|_, w| { + w.txen(true) + .txdis(false) }) } - unsafe fn reset_rx(&self) { - self.control.modify(|mut x| { - x.set_bit(Self::CONTROL_RXRST, true); - x + fn reset_rx(&self) { + self.control.modify(|_, w| { + w.rxrst(true) }) } - unsafe fn reset_tx(&self) { - self.control.modify(|mut x| { - x.set_bit(Self::CONTROL_TXRST, true); - x + fn reset_tx(&self) { + self.control.modify(|_, w| { + w.txrst(true) }) } - - const CHANNEL_STS_TXFULL: usize = 4; pub fn tx_fifo_full(&self) -> bool { - self.channel_sts.read().get_bit(Self::CHANNEL_STS_TXFULL) + self.channel_sts.read().txfull() } }