Skip to content

Commit d72975a

Browse files
committed
Rework ICachce API
1 parent 4e781e4 commit d72975a

File tree

1 file changed

+101
-63
lines changed

1 file changed

+101
-63
lines changed

src/icache.rs

Lines changed: 101 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
//! Instruction Cache management
22
//!
3-
//! To enable the the ICACHE:
3+
//! To enable the ICACHE in the default N-way set associative mode:
44
//!
55
//! ```
66
//! let dp = ...; // Device peripherals
7-
//! let mut icache = dp.ICACHE.constrain();
7+
//! let mut icache = dp.ICACHE.enable();
8+
//! ```
9+
//!
10+
//! To enable the ICACHE in a specific mode (e.g. Direct-mapped):
811
//!
9-
//! icache.enable();
12+
//! ```
13+
//! let dp = ...; // Device peripherals
14+
//! let mut icache = dp.ICACHE.enable_direct_mapped();
1015
//! ```
1116
//!
1217
//! To invalidate the cache, use the ICache::invalidate() method:
@@ -27,16 +32,47 @@
2732
//! let hit_count = icache.hit_count();
2833
//! let miss_count = icache.miss_count();
2934
//! ```
35+
//!
36+
//! Using interrupts to trigger cache invalidation and determine when it is
37+
//! complete:
38+
//!
39+
//! ```
40+
//! icache.start_invalidation();
41+
//!
42+
//! // In interrupt context
43+
//! if icache.check_event(Event::CacheInvalidationFinished) {
44+
//! icache.clear_irq(Event::CacheInvalidationFinished)
45+
//! }
46+
//! ```
47+
//!
3048
3149
use crate::stm32::ICACHE;
3250

33-
pub trait ICacheExt {
34-
fn constrain(self) -> ICache;
51+
pub enum Event {
52+
CacheError,
53+
CacheInvalidationFinished,
54+
}
55+
56+
pub trait ICacheExt: Sized {
57+
/// Enable in N-way set associative mode (default)
58+
fn enable_n_way(self) -> ICache;
59+
60+
/// Enable in direct mapped mode
61+
fn enable_direct_mapped(self) -> ICache;
62+
63+
/// Enable in default mode (N-way set associative)
64+
fn enable(self) -> ICache {
65+
self.enable_n_way()
66+
}
3567
}
3668

3769
impl ICacheExt for ICACHE {
38-
fn constrain(self) -> ICache {
39-
ICache::new(self)
70+
fn enable_n_way(self) -> ICache {
71+
ICache::new(self).enable_n_way()
72+
}
73+
74+
fn enable_direct_mapped(self) -> ICache {
75+
ICache::new(self).enable_direct_mapped()
4076
}
4177
}
4278

@@ -49,85 +85,106 @@ impl ICache {
4985
Self { icache }
5086
}
5187

52-
pub fn is_enabled(&self) -> bool {
53-
cortex_m::asm::dsb();
54-
cortex_m::asm::isb();
55-
56-
self.icache.cr().read().en().bit_is_set()
57-
}
58-
5988
fn wait_for_busy_complete(&self) {
6089
while self.icache.sr().read().busyf().bit_is_set() {}
6190
}
6291

63-
/// Enable ICACHE in default operating mode (N-way associative)
64-
pub fn enable(&mut self) {
65-
self.enable_n_way()
66-
}
67-
6892
/// Enable the ICACHE in N-way associative mode
69-
pub fn enable_n_way(&mut self) {
70-
if self.is_enabled() {
71-
return;
72-
}
73-
93+
fn enable_n_way(self) -> Self {
7494
// Wait for any ongoing cache invalidation operation to complete
7595
self.wait_for_busy_complete();
7696

7797
self.icache
7898
.cr()
7999
.write(|w| w.waysel().set_bit().en().set_bit());
100+
101+
self
80102
}
81103

82104
/// Enable the ICACHE in 1-way associative mode (direct mapping)
83-
pub fn enable_direct_mapped(&mut self) {
84-
if self.is_enabled() {
85-
return;
86-
}
87-
105+
fn enable_direct_mapped(self) -> Self {
88106
// Wait for any ongoing cache invalidation operation to complete
89107
self.wait_for_busy_complete();
90108

91109
self.icache
92110
.cr()
93111
.write(|w| w.waysel().clear_bit().en().set_bit());
112+
113+
self
94114
}
95115

96116
/// Disable the ICACHE
97-
pub fn disable(&mut self) {
98-
if !self.is_enabled() {
99-
return;
100-
}
101-
117+
pub fn disable(mut self) -> ICACHE {
102118
// Restore cache mode to default (N-way associative)
103119
self.icache
104120
.cr()
105121
.write(|w| w.waysel().set_bit().en().clear_bit());
106122

123+
// Disable interrupts
124+
self.icache
125+
.ier()
126+
.modify(|_, w| w.errie().clear_bit().bsyendie().clear_bit());
127+
107128
self.invalidate();
108129

109130
cortex_m::asm::dsb();
110131
cortex_m::asm::isb();
132+
133+
self.free()
111134
}
112135

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

118141
self.wait_for_busy_complete();
119142

120143
cortex_m::asm::dsb();
121144
cortex_m::asm::isb();
122145
}
123146

124-
/// Enable the cache hit counter. The number of hits can be queried with ICache::hit_counter()
125-
pub fn enable_hit_counter(&mut self) {
126-
assert!(
127-
self.is_enabled(),
128-
"ICACHE must be enabled before enabling the hit counter"
129-
);
147+
/// Start cache invalidation
148+
pub fn start_cache_invalidation(&mut self) {
149+
self.icache.cr().modify(|_, w| w.cacheinv().set_bit());
150+
}
151+
152+
/// Enable interrupts for the given event
153+
pub fn listen(&mut self, event: Event) {
154+
self.icache.ier().modify(|_, w| match event {
155+
Event::CacheError => w.errie().set_bit(),
156+
Event::CacheInvalidationFinished => w.bsyendie().set_bit(),
157+
});
158+
}
159+
160+
/// Disable interrupts for the given event
161+
pub fn unlisten(&mut self, event: Event) {
162+
self.icache.ier().modify(|_, w| match event {
163+
Event::CacheError => w.errie().clear_bit(),
164+
Event::CacheInvalidationFinished => w.bsyendie().clear_bit(),
165+
});
166+
}
167+
168+
/// Clear the IRQ for the given event
169+
pub fn clear_irq(&mut self, event: Event) {
170+
self.icache.fcr().write(|w| match event {
171+
Event::CacheError => w.cerrf().set_bit(),
172+
Event::CacheInvalidationFinished => w.cbsyendf().set_bit(),
173+
});
174+
}
175+
176+
/// Check whether an interrupt event has occurred. Returns true if it has.
177+
/// Clear the event IRQ by calling `clear_event`
178+
pub fn check_event(&mut self, event: Event) -> bool {
179+
let sr = self.icache.sr().read();
180+
match event {
181+
Event::CacheError => sr.errf().bit_is_set(),
182+
Event::CacheInvalidationFinished => sr.bsyendf().bit_is_set(),
183+
}
184+
}
130185

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

142199
/// Reset the hit counter
143200
pub fn reset_hit_counter(&mut self) {
144-
if !self.is_enabled() {
145-
return;
146-
}
147201
self.icache.cr().modify(|_, w| w.hitmrst().set_bit());
148202
}
149203

150204
/// Disable the hit counter. The hit counter is disabled when the peripheral
151205
/// is disabled
152-
pub fn disable_hit_counter(&mut self) {
153-
// Disabling the ICACHE disables the hitmem counter
154-
if !self.is_enabled() {
155-
return;
156-
}
206+
pub fn stop_hit_counter(&mut self) {
157207
self.icache.cr().modify(|_, w| w.hitmen().clear_bit());
158208
}
159209

160210
/// Enable the cache miss counter
161-
pub fn enable_miss_counter(&mut self) {
162-
assert!(
163-
self.is_enabled(),
164-
"ICACHE must be enabled before enabling the miss counter"
165-
);
166-
211+
pub fn start_miss_counter(&mut self) {
167212
// Enable and reset the miss counter
168213
self.icache
169214
.cr()
@@ -177,19 +222,12 @@ impl ICache {
177222

178223
/// Reset the miss counter
179224
pub fn reset_miss_counter(&mut self) {
180-
if !self.is_enabled() {
181-
return;
182-
}
183225
self.icache.cr().modify(|_, w| w.missmrst().set_bit());
184226
}
185227

186228
/// Disable the miss counter. The miss counter is disabled when the ICACHE
187229
/// is disabled
188-
pub fn disable_miss_counter(&mut self) {
189-
// Disabling the ICACHE disables the missmem counter
190-
if !self.is_enabled() {
191-
return;
192-
}
230+
pub fn stop_miss_counter(&mut self) {
193231
self.icache.cr().modify(|_, w| w.missmen().clear_bit());
194232
}
195233

0 commit comments

Comments
 (0)