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 r0::zero_bss;
mod regs;
mod cortex_a9;
mod slcr;
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 bit_field::BitField;
use crate::{register, register_bit, register_bits, regs::Register};
#[repr(packed)]
pub struct UartClkCtrl {
pub reg: RW<u32>,
}
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 _;
@ -15,26 +13,19 @@ impl UartClkCtrl {
unsafe { &mut *Self::ADDR }
}
const DIVISOR: RangeInclusive<usize> = 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<u32>,
}
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<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();
// 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();

View File

@ -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<u32>,
pub mode: RW<u32>,
pub intrpt_en: RW<u32>,
pub intrpt_dis: RW<u32>,
pub intrpt_mask: RO<u32>,
pub chnl_int_sts: WO<u32>,
pub baud_rate_gen: RW<u32>,
pub rcvr_timeout: RW<u32>,
pub rcvr_fifo_trigger_level: RW<u32>,
pub modem_ctrl: RW<u32>,
pub modem_sts: RW<u32>,
pub channel_sts: RO<u32>,
pub tx_rx_fifo: RW<u32>,
pub baud_rate_divider: RW<u32>,
pub flow_delay: RW<u32>,
pub reserved0: RO<u32>,
pub reserved1: RO<u32>,
pub tx_fifo_trigger_level: RW<u32>,
control: Control,
mode: Mode,
intrpt_en: RW<u32>,
intrpt_dis: RW<u32>,
intrpt_mask: RO<u32>,
chnl_int_sts: WO<u32>,
baud_rate_gen: BaudRateGen,
rcvr_timeout: RW<u32>,
rcvr_fifo_trigger_level: RW<u32>,
modem_ctrl: RW<u32>,
modem_sts: RW<u32>,
channel_sts: ChannelSts,
tx_rx_fifo: TxRxFifo,
baud_rate_divider: BaudRateDiv,
flow_delay: RW<u32>,
reserved0: RO<u32>,
reserved1: RO<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 {
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);
// * no parity
let parity_mode = ParityMode::ForceTo0;
self.mode.write(Mode::zeroed().par(parity_mode as u8));
// Configure the Buad Rate
// 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);
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();
}
pub fn write_byte(&self, value: u8) {
self.tx_rx_fifo.write(TxRxFifo::zeroed().data(value.into()));
}
pub unsafe fn write_byte(&self, value: u8) {
self.tx_rx_fifo.write(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()
}
}