Skip to content

Commit fe615a1

Browse files
committed
icache: Add ICACHE management
1 parent 526ceba commit fe615a1

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

src/icache.rs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
//! Instruction Cache management
2+
//!
3+
//! To enable the the ICACHE:
4+
//!
5+
//! ```
6+
//! let dp = ...; // Device peripherals
7+
//! let mut icache = dp.ICACHE.constrain();
8+
//!
9+
//! icache.enable();
10+
//! ```
11+
//!
12+
//! To invalidate the cache, use the ICache::invalidate() method:
13+
//!
14+
//! ```
15+
//! icache.invalidate();
16+
//! ```
17+
//!
18+
//! Performance monitoring of the cache is possible using the cache hit and
19+
//! miss counters:
20+
//!
21+
//! ```
22+
//! icache.enable_hit_counter();
23+
//! icache.enable_miss_counter();
24+
//!
25+
//! // do something
26+
//!
27+
//! let hit_count = icache.hit_count();
28+
//! let miss_count = icache.miss_count();
29+
//! ```
30+
31+
use crate::stm32::ICACHE;
32+
33+
pub trait ICacheExt {
34+
fn constrain(self) -> ICache;
35+
}
36+
37+
impl ICacheExt for ICACHE {
38+
fn constrain(self) -> ICache {
39+
ICache::new(self)
40+
}
41+
}
42+
43+
pub struct ICache {
44+
icache: ICACHE,
45+
}
46+
47+
impl ICache {
48+
fn new(icache: ICACHE) -> Self {
49+
Self { icache }
50+
}
51+
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+
59+
fn wait_for_busy_complete(&self) {
60+
while self.icache.sr().read().busyf().bit_is_set() {}
61+
}
62+
63+
/// Enable ICACHE in default operating mode (N-way associative)
64+
pub fn enable(&mut self) {
65+
self.enable_n_way()
66+
}
67+
68+
/// 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+
74+
// Wait for any ongoing cache invalidation operation to complete
75+
self.wait_for_busy_complete();
76+
77+
self.icache
78+
.cr()
79+
.write(|w| w.waysel().set_bit().en().set_bit());
80+
}
81+
82+
/// 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+
88+
// Wait for any ongoing cache invalidation operation to complete
89+
self.wait_for_busy_complete();
90+
91+
self.icache
92+
.cr()
93+
.write(|w| w.waysel().clear_bit().en().set_bit());
94+
}
95+
96+
/// Disable the ICACHE
97+
pub fn disable(&mut self) {
98+
if !self.is_enabled() {
99+
return;
100+
}
101+
102+
// Restore cache mode to default (N-way associative)
103+
self.icache
104+
.cr()
105+
.write(|w| w.waysel().set_bit().en().clear_bit());
106+
107+
self.invalidate();
108+
109+
cortex_m::asm::dsb();
110+
cortex_m::asm::isb();
111+
}
112+
113+
/// Invalidate the ICACHE. This will block while the cache is being
114+
/// invalidated
115+
pub fn invalidate(&mut self) {
116+
self.icache.cr().modify(|_, w| w.cacheinv().set_bit());
117+
118+
self.wait_for_busy_complete();
119+
120+
cortex_m::asm::dsb();
121+
cortex_m::asm::isb();
122+
}
123+
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+
);
130+
131+
// Enable and reset the cache hit counter
132+
self.icache
133+
.cr()
134+
.modify(|_, w| w.hitmrst().set_bit().hitmen().set_bit());
135+
}
136+
137+
/// Get the current value of the hit counter
138+
pub fn hit_count(&self) -> u32 {
139+
self.icache.hmonr().read().hitmon().bits()
140+
}
141+
142+
/// Reset the hit counter
143+
pub fn reset_hit_counter(&mut self) {
144+
if !self.is_enabled() {
145+
return;
146+
}
147+
self.icache.cr().modify(|_, w| w.hitmrst().set_bit());
148+
}
149+
150+
/// Disable the hit counter. The hit counter is disabled when the peripheral
151+
/// 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+
}
157+
self.icache.cr().modify(|_, w| w.hitmen().clear_bit());
158+
}
159+
160+
/// 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+
167+
// Enable and reset the miss counter
168+
self.icache
169+
.cr()
170+
.modify(|_, w| w.missmrst().set_bit().missmen().set_bit());
171+
}
172+
173+
/// Get the current value of the miss counter
174+
pub fn miss_count(&self) -> u16 {
175+
self.icache.mmonr().read().missmon().bits()
176+
}
177+
178+
/// Reset the miss counter
179+
pub fn reset_miss_counter(&mut self) {
180+
if !self.is_enabled() {
181+
return;
182+
}
183+
self.icache.cr().modify(|_, w| w.missmrst().set_bit());
184+
}
185+
186+
/// Disable the miss counter. The miss counter is disabled when the ICACHE
187+
/// 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+
}
193+
self.icache.cr().modify(|_, w| w.missmen().clear_bit());
194+
}
195+
196+
// Deconstruct and return ICACHE
197+
pub fn free(self) -> ICACHE {
198+
self.icache
199+
}
200+
}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ pub mod rcc;
5252
#[cfg(feature = "device-selected")]
5353
pub mod gpio;
5454

55+
#[cfg(feature = "device-selected")]
56+
pub mod icache;
57+
5558
/// Get the name of the type without the module prefix(es)
5659
fn stripped_type_name<T>() -> &'static str {
5760
let s = core::any::type_name::<T>();

src/prelude.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Prelude
22
3+
pub use crate::icache::ICacheExt as _stm32h5xx_hal_delay_ICacheExt;
34
pub use crate::gpio::GpioExt as _stm32h5xx_hal_gpio_GpioExt;
45
pub use crate::pwr::PwrExt as _stm32h5xx_hal_pwr_PwrExt;
56
pub use crate::rcc::RccExt as _stm32h5xx_hal_rcc_RccExt;

0 commit comments

Comments
 (0)