regs macros

This commit is contained in:
Astro 2019-05-06 23:56:53 +02:00
parent 9b414e2408
commit 55957eea09
5 changed files with 224 additions and 123 deletions

View File

@ -7,6 +7,7 @@
use panic_abort as _; use panic_abort as _;
use r0::zero_bss; use r0::zero_bss;
mod regs;
mod cortex_a9; mod cortex_a9;
mod slcr; mod slcr;
mod uart; mod uart;

108
src/regs.rs Normal file
View File

@ -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<F: FnOnce(Self::R, Self::W) -> 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<F: FnOnce(Self::R, Self::W) -> 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
}
}
);
}

View File

@ -1,13 +1,11 @@
use core::ops::RangeInclusive;
use volatile_register::{RO, WO, RW}; use volatile_register::{RO, WO, RW};
use bit_field::BitField;
use crate::{register, register_bit, register_bits, regs::Register};
#[repr(packed)] register!(uart_clk_ctrl, UartClkCtrl, u32);
pub struct UartClkCtrl { register_bit!(uart_clk_ctrl, clkact0, 0);
pub reg: RW<u32>, register_bit!(uart_clk_ctrl, clkact1, 1);
} register_bits!(uart_clk_ctrl, divisor, u8, 8, 13);
impl UartClkCtrl { impl UartClkCtrl {
const ADDR: *mut Self = 0xF8000154 as *mut _; const ADDR: *mut Self = 0xF8000154 as *mut _;
@ -15,26 +13,19 @@ impl UartClkCtrl {
unsafe { &mut *Self::ADDR } unsafe { &mut *Self::ADDR }
} }
const DIVISOR: RangeInclusive<usize> = 8..=13;
const CLKACT1: usize = 1;
const CLKACT0: usize = 0;
pub fn enable_uart0(&self) { pub fn enable_uart0(&self) {
unsafe { self.modify(|_, w| {
self.reg.modify(|mut x| { w.clkact0(true)
x.set_bits(Self::DIVISOR, 0x14); .divisor(0x14)
x.set_bit(Self::CLKACT0, true); })
x
})
}
} }
} }
#[repr(packed)] register!(uart_rst_ctrl, UartRstCtrl, u32);
pub struct UartRstCtrl { register_bit!(uart_rst_ctrl, uart0_ref_rst, 3);
pub reg: RW<u32>, 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 { impl UartRstCtrl {
const ADDR: *mut Self = 0xF8000228 as *mut _; const ADDR: *mut Self = 0xF8000228 as *mut _;
@ -42,29 +33,13 @@ impl UartRstCtrl {
unsafe { &mut *Self::ADDR } 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) { 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) { 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<T: BitField + Copy>(reg: &RW<T>, 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
});
}

View File

@ -11,9 +11,9 @@ impl Uart {
uart_rst_ctrl.reset_uart0(); uart_rst_ctrl.reset_uart0();
// TODO: Route UART 0 RxD/TxD Signals to MIO Pins // TODO: Route UART 0 RxD/TxD Signals to MIO Pins
// a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14. // a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14.
// b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0. // b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0.
// c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1. // 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. // d. Disable UART 1 Reference clock, slcr.UART_CLK_CTRL [CLKACT1] bit = 0.
let uart_clk_ctrl = super::slcr::UartClkCtrl::new(); let uart_clk_ctrl = super::slcr::UartClkCtrl::new();
uart_clk_ctrl.enable_uart0(); uart_clk_ctrl.enable_uart0();

View File

@ -1,28 +1,61 @@
use volatile_register::{RO, WO, RW}; use volatile_register::{RO, WO, RW};
use bit_field::BitField; 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)] #[repr(packed)]
pub struct RegisterBlock { pub struct RegisterBlock {
pub control: RW<u32>, control: Control,
pub mode: RW<u32>, mode: Mode,
pub intrpt_en: RW<u32>, intrpt_en: RW<u32>,
pub intrpt_dis: RW<u32>, intrpt_dis: RW<u32>,
pub intrpt_mask: RO<u32>, intrpt_mask: RO<u32>,
pub chnl_int_sts: WO<u32>, chnl_int_sts: WO<u32>,
pub baud_rate_gen: RW<u32>, baud_rate_gen: BaudRateGen,
pub rcvr_timeout: RW<u32>, rcvr_timeout: RW<u32>,
pub rcvr_fifo_trigger_level: RW<u32>, rcvr_fifo_trigger_level: RW<u32>,
pub modem_ctrl: RW<u32>, modem_ctrl: RW<u32>,
pub modem_sts: RW<u32>, modem_sts: RW<u32>,
pub channel_sts: RO<u32>, channel_sts: ChannelSts,
pub tx_rx_fifo: RW<u32>, tx_rx_fifo: TxRxFifo,
pub baud_rate_divider: RW<u32>, baud_rate_divider: BaudRateDiv,
pub flow_delay: RW<u32>, flow_delay: RW<u32>,
pub reserved0: RO<u32>, reserved0: RO<u32>,
pub reserved1: RO<u32>, reserved1: RO<u32>,
pub tx_fifo_trigger_level: RW<u32>, tx_fifo_trigger_level: RW<u32>,
} }
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 { impl RegisterBlock {
const UART0: *mut Self = 0xE0000000 as *mut _; const UART0: *mut Self = 0xE0000000 as *mut _;
const UART1: *mut Self = 0xE0001000 as *mut _; const UART1: *mut Self = 0xE0001000 as *mut _;
@ -36,90 +69,74 @@ impl RegisterBlock {
} }
pub fn configure(&self) { pub fn configure(&self) {
unsafe { // Confiugre UART character frame
// Confiugre UART character frame // * Disable clock-divider
// * Disable clock-divider // * 8-bit
// * 8-bit // * 1 stop bit
// * no parity // * Normal channel mode
// * 1 stop bit // * no parity
// * Normal channel mode let parity_mode = ParityMode::ForceTo0;
self.mode.write(0x20); self.mode.write(Mode::zeroed().par(parity_mode as u8));
// Configure the Buad Rate // Configure the Baud Rate
self.disable_rx(); self.disable_rx();
self.disable_tx(); self.disable_tx();
// 9,600 baud // 9,600 baud
self.baud_rate_gen.write(651); self.baud_rate_gen.write(BaudRateGen::zeroed().cd(651));
self.baud_rate_divider.write(7); self.baud_rate_divider.write(BaudRateDiv::zeroed().bdiv(7));
self.reset_rx(); self.reset_rx();
self.reset_tx(); self.reset_tx();
self.enable_rx(); self.enable_rx();
self.enable_tx(); self.enable_tx();
}
} }
pub unsafe fn write_byte(&self, value: u8) { pub fn write_byte(&self, value: u8) {
self.tx_rx_fifo.write(value.into()); self.tx_rx_fifo.write(TxRxFifo::zeroed().data(value.into()));
} }
const CONTROL_RXEN: usize = 2; fn disable_rx(&self) {
const CONTROL_RXDIS: usize = 3; self.control.modify(|_, w| {
const CONTROL_TXEN: usize = 4; w.rxen(false)
const CONTROL_TXDIS: usize = 5; .rxdis(true)
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
}) })
} }
unsafe fn disable_tx(&self) { fn disable_tx(&self) {
self.control.modify(|mut x| { self.control.modify(|_, w| {
x.set_bit(Self::CONTROL_TXEN, false); w.txen(false)
x.set_bit(Self::CONTROL_TXDIS, true); .txdis(true)
x
}) })
} }
unsafe fn enable_rx(&self) { fn enable_rx(&self) {
self.control.modify(|mut x| { self.control.modify(|_, w| {
x.set_bit(Self::CONTROL_RXEN, true); w.rxen(true)
x.set_bit(Self::CONTROL_RXDIS, false); .rxdis(false)
x
}) })
} }
unsafe fn enable_tx(&self) { fn enable_tx(&self) {
self.control.modify(|mut x| { self.control.modify(|_, w| {
x.set_bit(Self::CONTROL_TXEN, true); w.txen(true)
x.set_bit(Self::CONTROL_TXDIS, false); .txdis(false)
x
}) })
} }
unsafe fn reset_rx(&self) { fn reset_rx(&self) {
self.control.modify(|mut x| { self.control.modify(|_, w| {
x.set_bit(Self::CONTROL_RXRST, true); w.rxrst(true)
x
}) })
} }
unsafe fn reset_tx(&self) { fn reset_tx(&self) {
self.control.modify(|mut x| { self.control.modify(|_, w| {
x.set_bit(Self::CONTROL_TXRST, true); w.txrst(true)
x
}) })
} }
const CHANNEL_STS_TXFULL: usize = 4;
pub fn tx_fifo_full(&self) -> bool { pub fn tx_fifo_full(&self) -> bool {
self.channel_sts.read().get_bit(Self::CHANNEL_STS_TXFULL) self.channel_sts.read().txfull()
} }
} }