Skip to content

Commit

Permalink
Rework ICachce API
Browse files Browse the repository at this point in the history
  • Loading branch information
astapleton committed Oct 11, 2024
1 parent 4e781e4 commit d72975a
Showing 1 changed file with 101 additions and 63 deletions.
164 changes: 101 additions & 63 deletions src/icache.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
//! Instruction Cache management
//!
//! To enable the the ICACHE:
//! To enable the ICACHE in the default N-way set associative mode:
//!
//! ```
//! let dp = ...; // Device peripherals
//! let mut icache = dp.ICACHE.constrain();
//! let mut icache = dp.ICACHE.enable();
//! ```
//!
//! To enable the ICACHE in a specific mode (e.g. Direct-mapped):
//!
//! icache.enable();
//! ```
//! let dp = ...; // Device peripherals
//! let mut icache = dp.ICACHE.enable_direct_mapped();
//! ```
//!
//! To invalidate the cache, use the ICache::invalidate() method:
Expand All @@ -27,16 +32,47 @@
//! let hit_count = icache.hit_count();
//! let miss_count = icache.miss_count();
//! ```
//!
//! Using interrupts to trigger cache invalidation and determine when it is
//! complete:
//!
//! ```
//! icache.start_invalidation();
//!
//! // In interrupt context
//! if icache.check_event(Event::CacheInvalidationFinished) {
//! icache.clear_irq(Event::CacheInvalidationFinished)
//! }
//! ```
//!

use crate::stm32::ICACHE;

pub trait ICacheExt {
fn constrain(self) -> ICache;
pub enum Event {
CacheError,
CacheInvalidationFinished,
}

pub trait ICacheExt: Sized {
/// Enable in N-way set associative mode (default)
fn enable_n_way(self) -> ICache;

/// Enable in direct mapped mode
fn enable_direct_mapped(self) -> ICache;

/// Enable in default mode (N-way set associative)
fn enable(self) -> ICache {
self.enable_n_way()
}
}

impl ICacheExt for ICACHE {
fn constrain(self) -> ICache {
ICache::new(self)
fn enable_n_way(self) -> ICache {
ICache::new(self).enable_n_way()
}

fn enable_direct_mapped(self) -> ICache {
ICache::new(self).enable_direct_mapped()
}
}

Expand All @@ -49,85 +85,106 @@ impl ICache {
Self { icache }
}

pub fn is_enabled(&self) -> bool {
cortex_m::asm::dsb();
cortex_m::asm::isb();

self.icache.cr().read().en().bit_is_set()
}

fn wait_for_busy_complete(&self) {
while self.icache.sr().read().busyf().bit_is_set() {}
}

/// Enable ICACHE in default operating mode (N-way associative)
pub fn enable(&mut self) {
self.enable_n_way()
}

/// Enable the ICACHE in N-way associative mode
pub fn enable_n_way(&mut self) {
if self.is_enabled() {
return;
}

fn enable_n_way(self) -> Self {
// Wait for any ongoing cache invalidation operation to complete
self.wait_for_busy_complete();

self.icache
.cr()
.write(|w| w.waysel().set_bit().en().set_bit());

self
}

/// Enable the ICACHE in 1-way associative mode (direct mapping)
pub fn enable_direct_mapped(&mut self) {
if self.is_enabled() {
return;
}

fn enable_direct_mapped(self) -> Self {
// Wait for any ongoing cache invalidation operation to complete
self.wait_for_busy_complete();

self.icache
.cr()
.write(|w| w.waysel().clear_bit().en().set_bit());

self
}

/// Disable the ICACHE
pub fn disable(&mut self) {
if !self.is_enabled() {
return;
}

pub fn disable(mut self) -> ICACHE {
// Restore cache mode to default (N-way associative)
self.icache
.cr()
.write(|w| w.waysel().set_bit().en().clear_bit());

// Disable interrupts
self.icache
.ier()
.modify(|_, w| w.errie().clear_bit().bsyendie().clear_bit());

self.invalidate();

cortex_m::asm::dsb();
cortex_m::asm::isb();

self.free()
}

/// Invalidate the ICACHE. This will block while the cache is being
/// invalidated
pub fn invalidate(&mut self) {
self.icache.cr().modify(|_, w| w.cacheinv().set_bit());
self.start_cache_invalidation();

self.wait_for_busy_complete();

cortex_m::asm::dsb();
cortex_m::asm::isb();
}

/// Enable the cache hit counter. The number of hits can be queried with ICache::hit_counter()
pub fn enable_hit_counter(&mut self) {
assert!(
self.is_enabled(),
"ICACHE must be enabled before enabling the hit counter"
);
/// Start cache invalidation
pub fn start_cache_invalidation(&mut self) {
self.icache.cr().modify(|_, w| w.cacheinv().set_bit());
}

/// Enable interrupts for the given event
pub fn listen(&mut self, event: Event) {
self.icache.ier().modify(|_, w| match event {
Event::CacheError => w.errie().set_bit(),
Event::CacheInvalidationFinished => w.bsyendie().set_bit(),
});
}

/// Disable interrupts for the given event
pub fn unlisten(&mut self, event: Event) {
self.icache.ier().modify(|_, w| match event {
Event::CacheError => w.errie().clear_bit(),
Event::CacheInvalidationFinished => w.bsyendie().clear_bit(),
});
}

/// Clear the IRQ for the given event
pub fn clear_irq(&mut self, event: Event) {
self.icache.fcr().write(|w| match event {
Event::CacheError => w.cerrf().set_bit(),
Event::CacheInvalidationFinished => w.cbsyendf().set_bit(),
});
}

/// Check whether an interrupt event has occurred. Returns true if it has.
/// Clear the event IRQ by calling `clear_event`
pub fn check_event(&mut self, event: Event) -> bool {
let sr = self.icache.sr().read();
match event {
Event::CacheError => sr.errf().bit_is_set(),
Event::CacheInvalidationFinished => sr.bsyendf().bit_is_set(),
}
}

/// Enable the cache hit counter. The number of hits can be queried with ICache::hit_counter()
pub fn start_hit_counter(&mut self) {
// Enable and reset the cache hit counter
self.icache
.cr()
Expand All @@ -141,29 +198,17 @@ impl ICache {

/// Reset the hit counter
pub fn reset_hit_counter(&mut self) {
if !self.is_enabled() {
return;
}
self.icache.cr().modify(|_, w| w.hitmrst().set_bit());
}

/// Disable the hit counter. The hit counter is disabled when the peripheral
/// is disabled
pub fn disable_hit_counter(&mut self) {
// Disabling the ICACHE disables the hitmem counter
if !self.is_enabled() {
return;
}
pub fn stop_hit_counter(&mut self) {
self.icache.cr().modify(|_, w| w.hitmen().clear_bit());
}

/// Enable the cache miss counter
pub fn enable_miss_counter(&mut self) {
assert!(
self.is_enabled(),
"ICACHE must be enabled before enabling the miss counter"
);

pub fn start_miss_counter(&mut self) {
// Enable and reset the miss counter
self.icache
.cr()
Expand All @@ -177,19 +222,12 @@ impl ICache {

/// Reset the miss counter
pub fn reset_miss_counter(&mut self) {
if !self.is_enabled() {
return;
}
self.icache.cr().modify(|_, w| w.missmrst().set_bit());
}

/// Disable the miss counter. The miss counter is disabled when the ICACHE
/// is disabled
pub fn disable_miss_counter(&mut self) {
// Disabling the ICACHE disables the missmem counter
if !self.is_enabled() {
return;
}
pub fn stop_miss_counter(&mut self) {
self.icache.cr().modify(|_, w| w.missmen().clear_bit());
}

Expand Down

0 comments on commit d72975a

Please sign in to comment.