Skip to content

Commit

Permalink
Use bitbybit for CSPR.
Browse files Browse the repository at this point in the history
The API has enough const fns that we can construct the constants we need for assembly language use. Except for the bitmask for the processor mode field in CSPR, but I can hard-code that one value.
  • Loading branch information
jonathanpallant committed Jan 28, 2025
1 parent 52091d2 commit b7ae5df
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 139 deletions.
59 changes: 47 additions & 12 deletions cortex-r-rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
#![no_std]

use cortex_r::register::cpsr::{Cpsr, ProcessorMode};

/// Our default exception handler.
///
/// We end up here if an exception fires and the weak 'PROVIDE' in the link.x
Expand Down Expand Up @@ -283,9 +285,13 @@ core::arch::global_asm!(
rfefd sp!
.size _asm_irq_handler, . - _asm_irq_handler
"#,
svc_mode = const cortex_r::register::Cpsr::SVC_MODE,
irq_mode = const cortex_r::register::Cpsr::IRQ_MODE,
t_bit = const cortex_r::register::Cpsr::T_BIT,
svc_mode = const ProcessorMode::Svc as u8,
irq_mode = const ProcessorMode::Irq as u8,
t_bit = const {
Cpsr::new_with_raw_value(0)
.with_t(true)
.raw_value()
},
);

/// This macro expands to code to turn on the FPU
Expand Down Expand Up @@ -386,11 +392,35 @@ core::arch::global_asm!(
b .
.size _el1_start, . - _el1_start
"#,
fiq_mode = const cortex_r::register::Cpsr::FIQ_MODE | cortex_r::register::Cpsr::I_BIT | cortex_r::register::Cpsr::F_BIT,
irq_mode = const cortex_r::register::Cpsr::IRQ_MODE | cortex_r::register::Cpsr::I_BIT | cortex_r::register::Cpsr::F_BIT,
svc_mode = const cortex_r::register::Cpsr::SVC_MODE | cortex_r::register::Cpsr::I_BIT | cortex_r::register::Cpsr::F_BIT,
sys_mode = const cortex_r::register::Cpsr::SYS_MODE | cortex_r::register::Cpsr::I_BIT | cortex_r::register::Cpsr::F_BIT,
te_bit = const cortex_r::register::Sctlr::TE_BIT
fiq_mode = const {
Cpsr::new_with_raw_value(0)
.with_mode(ProcessorMode::Fiq)
.with_i(true)
.with_f(true)
.raw_value()
},
irq_mode = const {
Cpsr::new_with_raw_value(0)
.with_mode(ProcessorMode::Irq)
.with_i(true)
.with_f(true)
.raw_value()
},
svc_mode = const {
Cpsr::new_with_raw_value(0)
.with_mode(ProcessorMode::Svc)
.with_i(true)
.with_f(true)
.raw_value()
},
sys_mode = const {
Cpsr::new_with_raw_value(0)
.with_mode(ProcessorMode::Sys)
.with_i(true)
.with_f(true)
.raw_value()
},
te_bit = const cortex_r::register::Sctlr::TE_BIT,
);

// Start-up code for Armv7-R.
Expand Down Expand Up @@ -427,7 +457,7 @@ core::arch::global_asm!(
_default_start:
// Are we in EL2? If not, skip the EL2 setup portion
mrs r0, cpsr
and r0, r0, {cpsr_mode_mask}
and r0, r0, 0x1F
cmp r0, {cpsr_mode_hyp}
bne 1f
// Set stack pointer
Expand Down Expand Up @@ -457,8 +487,13 @@ core::arch::global_asm!(
ldr pc, =_el1_start
.size _default_start, . - _default_start
"#,
cpsr_mode_mask = const cortex_r::register::Cpsr::MODE_BITS,
cpsr_mode_hyp = const cortex_r::register::Cpsr::HYP_MODE,
cpsr_mode_hyp = const ProcessorMode::Hyp as u8,
hactlr_bits = const cortex_r::register::Hactlr::CPUACTLR_BIT | cortex_r::register::Hactlr::CDBGDCI_BIT | cortex_r::register::Hactlr::FLASHIFREGIONR_BIT | cortex_r::register::Hactlr::PERIPHPREGIONR_BIT | cortex_r::register::Hactlr::QOSR_BIT | cortex_r::register::Hactlr::BUSTIMEOUTR_BIT | cortex_r::register::Hactlr::INTMONR_BIT | cortex_r::register::Hactlr::ERR_BIT | cortex_r::register::Hactlr::TESTR1_BIT,
sys_mode = const cortex_r::register::Cpsr::SYS_MODE | cortex_r::register::Cpsr::I_BIT | cortex_r::register::Cpsr::F_BIT,
sys_mode = const {
Cpsr::new_with_raw_value(0)
.with_mode(ProcessorMode::Sys)
.with_i(true)
.with_f(true)
.raw_value()
}
);
2 changes: 2 additions & 0 deletions cortex-r/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ rust-version = "1.82"
version = "0.1.0"

[dependencies]
arbitrary-int = "1.3.0"
bitbybit = "1.3.3"
critical-section = { version = "1.2.0", features = ["restore-state-bool"], optional = true }
defmt = { version = "0.3", optional = true }

Expand Down
190 changes: 64 additions & 126 deletions cortex-r/src/register/cpsr.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,70 @@
//! Code for managing the *Current Program Status Register*
#[derive(Debug)]
#[bitbybit::bitenum(u5, exhaustive = false)]
pub enum ProcessorMode {
/// User Mode
Usr = 0b10000,
/// FIQ Mode
Fiq = 0b10001,
/// IRQ Mode
Irq = 0b10010,
/// Supervisor Mode
Svc = 0b10011,
/// Monitor Mode
Mon = 0b10110,
/// Abort Mode
Abt = 0b10111,
/// Hyp Mode
Hyp = 0b11010,
/// Undefined Mode
Und = 0b11011,
/// System Mode
Sys = 0b11111,
}

/// The *Current Program Status Register* (CPSR)
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct Cpsr(u32);
#[bitbybit::bitfield(u32)]
pub struct Cpsr {
/// Negative Result from ALU
#[bits(31..=31, r)]
n: bool,
/// Zero Result from ALU
#[bits(30..=30, r)]
z: bool,
/// ALU operation Carry Out
#[bits(29..=29, r)]
c: bool,
/// ALU operation Overflow
#[bits(28..=28, r)]
v: bool,
/// Cumulative Saturation
#[bits(27..=27, r)]
q: bool,
/// Jazelle State
#[bits(24..=24, r)]
j: bool,
/// Endianness
#[bits(9..=9, rw)]
e: bool,
/// Asynchronous Aborts
#[bits(8..=8, rw)]
a: bool,
/// Interrupts Enabled
#[bits(7..=7, rw)]
i: bool,
/// Fast Interrupts Enabled
#[bits(6..=6, rw)]
f: bool,
/// Thumb state
#[bits(5..=5, rw)]
t: bool,
/// Processor Mode
#[bits(0..=4, rw)]
mode: Option<ProcessorMode>,
}

impl Cpsr {
/// The bitmask for Negative Result from ALU
pub const N_BIT: u32 = 1 << 31;
/// The bitmask for Zero Result from ALU
pub const Z_BIT: u32 = 1 << 30;
/// The bitmask for ALU operation Carry Out
pub const C_BIT: u32 = 1 << 29;
/// The bitmask for ALU operation Overflow
pub const V_BIT: u32 = 1 << 28;
/// The bitmask for Cumulative Saturation
pub const Q_BIT: u32 = 1 << 27;
/// The bitmask for Jazelle State
pub const J_BIT: u32 = 1 << 24;
/// The bitmask for Endianness
pub const E_BIT: u32 = 1 << 9;
/// The bitmask for Asynchronous Aborts
pub const A_BIT: u32 = 1 << 8;
/// The bitmask for Interrupts Enabled
pub const I_BIT: u32 = 1 << 7;
/// The bitmask for Fast Interrupts Enabled
pub const F_BIT: u32 = 1 << 6;
/// The bitmask for Thumb state
pub const T_BIT: u32 = 1 << 5;
/// The bitmask for Processor Mode
pub const MODE_BITS: u32 = 0b11111;
/// The bits for User Mode
pub const USR_MODE: u32 = 0b10000;
/// The bits for FIQ Mode
pub const FIQ_MODE: u32 = 0b10001;
/// The bits for IRQ Mode
pub const IRQ_MODE: u32 = 0b10010;
/// The bits for Supervisor Mode
pub const SVC_MODE: u32 = 0b10011;
/// The bits for Monitor Mode
pub const MON_MODE: u32 = 0b10110;
/// The bits for Abort Mode
pub const ABT_MODE: u32 = 0b10111;
/// The bits for Hyp Mode
pub const HYP_MODE: u32 = 0b11010;
/// The bits for Undefined Mode
pub const UND_MODE: u32 = 0b11011;
/// The bits for System Mode
pub const SYS_MODE: u32 = 0b11111;

/// Reads the *Current Program Status Register*
#[inline]
pub fn read() -> Self {
Expand All @@ -62,93 +78,15 @@ impl Cpsr {
{
r = 0;
}
Self(r)
}

/// Is the N bit set?
#[inline]
pub fn n(self) -> bool {
(self.0 & Self::N_BIT) != 0
}

/// Is the Z bit set?
#[inline]
pub fn z(self) -> bool {
(self.0 & Self::Z_BIT) != 0
}

/// Is the C bit set?
#[inline]
pub fn c(self) -> bool {
(self.0 & Self::C_BIT) != 0
}

/// Is the V bit set?
#[inline]
pub fn v(self) -> bool {
(self.0 & Self::V_BIT) != 0
}

/// Is the Q bit set?
#[inline]
pub fn q(self) -> bool {
(self.0 & Self::Q_BIT) != 0
}

/// Is the J bit set?
#[inline]
pub fn j(self) -> bool {
(self.0 & Self::J_BIT) != 0
}

/// Is the E bit set?
#[inline]
pub fn e(self) -> bool {
(self.0 & Self::E_BIT) != 0
}

/// Is the A bit set?
#[inline]
pub fn a(self) -> bool {
(self.0 & Self::A_BIT) != 0
}

/// Is the I bit set?
#[inline]
pub fn i(self) -> bool {
(self.0 & Self::I_BIT) != 0
}

/// Is the F bit set?
#[inline]
pub fn f(self) -> bool {
(self.0 & Self::F_BIT) != 0
}

/// Is the T bit set?
#[inline]
pub fn t(self) -> bool {
(self.0 & Self::T_BIT) != 0
}

/// Get the current mode
#[inline]
pub fn mode(self) -> u8 {
(self.0 & Self::MODE_BITS) as u8
}

/// Are we in supervisor mode?
#[inline]
pub fn is_supervisor_mode(self) -> bool {
self.mode() == 0b10011
Self::new_with_raw_value(r)
}
}

impl core::fmt::Debug for Cpsr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"CPSR {{ N={} Z={} C={} V={} Q={} J={} E={} A={} I={} F={} T={} MODE={:#02x} }}",
"CPSR {{ N={} Z={} C={} V={} Q={} J={} E={} A={} I={} F={} T={} MODE={:?} }}",
self.n() as u8,
self.z() as u8,
self.c() as u8,
Expand Down
2 changes: 1 addition & 1 deletion cortex-r/src/register/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod cbar;
#[doc(inline)]
pub use cbar::Cbar;

mod cpsr;
pub mod cpsr;
#[doc(inline)]
pub use cpsr::Cpsr;

Expand Down

0 comments on commit b7ae5df

Please sign in to comment.