Skip to content

Commit 09b91d2

Browse files
committed
add more cache/MMU maintenance regs
1 parent cdf224f commit 09b91d2

File tree

17 files changed

+574
-7
lines changed

17 files changed

+574
-7
lines changed

cortex-ar/src/cache.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use arbitrary_int::u3;
2+
3+
use crate::register::{Dccimvac, Dccisw, Dccmvac, Dccsw, Dcimvac, Dcisw, SysRegWrite};
4+
5+
/// Invalidate the full L1 data cache.
6+
///
7+
/// ## Generics
8+
///
9+
/// - A: log2(ASSOCIATIVITY) rounded up to the next integer if necessary. For example, a 4-way
10+
/// associative cache will have a value of 2 and a 8-way associative cache will have a value of
11+
/// 3.
12+
/// - N: log2(LINE LENGTH). For example, a 32-byte line length (4 words) will have a value of
13+
/// 5.
14+
/// - S: log2(NUM OF SETS). For systems with a fixed cache size, the number of sets can be
15+
/// calculated using `CACHE SIZE / (LINE LENGTH * ASSOCIATIVITY)`.
16+
/// For example, a 4-way associative 32kB L1 cache with a 32-byte line length (4 words) will
17+
/// have 32768 / (32 * 4) == 256 sets and S will have a value of 8.
18+
#[inline]
19+
pub fn invalidate_l1_data_cache<const A: usize, const N: usize, const S: usize>() {
20+
let ways = 1 << A;
21+
let sets = 1 << S;
22+
23+
for set in 0..sets {
24+
for way in 0..ways {
25+
unsafe { Dcisw::write(Dcisw::new::<A, N>(way, set, u3::new(0))) };
26+
}
27+
}
28+
}
29+
30+
/// Clean the full L1 data cache.
31+
///
32+
/// ## Generics
33+
///
34+
/// - A: log2(ASSOCIATIVITY) rounded up to the next integer if necessary. For example, a 4-way
35+
/// associative cache will have a value of 2 and a 8-way associative cache will have a value of
36+
/// 3.
37+
/// - N: log2(LINE LENGTH). For example, a 32-byte line length (4 words) will have a value of
38+
/// 5.
39+
/// - S: log2(NUM OF SETS). For systems with a fixed cache size, the number of sets can be
40+
/// calculated using `CACHE SIZE / (LINE LENGTH * ASSOCIATIVITY)`.
41+
/// For example, a 4-way associative 32kB L1 cache with a 32-byte line length (4 words) will
42+
/// have 32768 / (32 * 4) == 256 sets and S will have a value of 8.
43+
#[inline]
44+
pub fn clean_l1_data_cache<const A: usize, const N: usize, const S: usize>() {
45+
let ways = 1 << A;
46+
let sets = 1 << S;
47+
48+
for set in 0..sets {
49+
for way in 0..ways {
50+
unsafe { Dccsw::write(Dccsw::new::<A, N>(way, set, u3::new(0))) };
51+
}
52+
}
53+
}
54+
55+
/// Clean and Invalidate the full L1 data cache.
56+
///
57+
/// ## Generics
58+
///
59+
/// - A: log2(ASSOCIATIVITY) rounded up to the next integer if necessary. For example, a 4-way
60+
/// associative cache will have a value of 2 and a 8-way associative cache will have a value of
61+
/// 3.
62+
/// - N: log2(LINE LENGTH). For example, a 32-byte line length (4 words) will have a value of
63+
/// 5.
64+
/// - S: log2(NUM OF SETS). For systems with a fixed cache size, the number of sets can be
65+
/// calculated using `CACHE SIZE / (LINE LENGTH * ASSOCIATIVITY)`.
66+
/// For example, a 4-way associative 32kB L1 cache with a 32-byte line length (4 words) will
67+
/// have 32768 / (32 * 4) == 256 sets and S will have a value of 8.
68+
#[inline]
69+
pub fn clean_and_invalidate_l1_data_cache<const A: usize, const N: usize, const S: usize>() {
70+
let ways = 1 << A;
71+
let sets = 1 << S;
72+
73+
for set in 0..sets {
74+
for way in 0..ways {
75+
unsafe { Dccisw::write(Dccisw::new::<A, N>(way, set, u3::new(0))) };
76+
}
77+
}
78+
}
79+
80+
#[inline]
81+
pub fn invalidate_data_cache_line_to_poc(addr: u32) {
82+
unsafe {
83+
Dcimvac::write_raw(addr);
84+
}
85+
}
86+
87+
#[inline]
88+
pub fn clean_data_cache_line_to_poc(addr: u32) {
89+
unsafe {
90+
Dccmvac::write_raw(addr);
91+
}
92+
}
93+
94+
#[inline]
95+
pub fn clean_and_invalidate_data_cache_line_to_poc(addr: u32) {
96+
unsafe {
97+
Dccimvac::write_raw(addr);
98+
}
99+
}

cortex-ar/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod critical_section;
77
#[cfg(target_arch = "arm")]
88
pub mod asm;
99

10+
pub mod cache;
1011
pub mod interrupt;
1112
pub mod mmu;
1213
pub mod register;

cortex-ar/src/register/bpiall.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//! BPIALL: Invalidate all entries from branch predictors
2+
3+
use crate::register::SysReg;
4+
5+
/// BPIALL: Invalidate all entries from branch predictors
6+
pub struct BpIAll;
7+
8+
impl SysReg for BpIAll {
9+
const CP: u32 = 15;
10+
const CRN: u32 = 7;
11+
const OP1: u32 = 0;
12+
const CRM: u32 = 5;
13+
const OP2: u32 = 6;
14+
}
15+
16+
impl crate::register::SysRegWrite for BpIAll {}
17+
18+
impl BpIAll {
19+
#[inline]
20+
pub fn write() {
21+
unsafe { <Self as crate::register::SysRegWrite>::write_raw(0) }
22+
}
23+
}

cortex-ar/src/register/ccsidr.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,42 @@
11
//! Code for managing CCSIDR (*Current Cache Size ID Register*)
22
33
use crate::register::{SysReg, SysRegRead};
4+
use arbitrary_int::{u10, u15, u3};
45

56
/// CCSIDR (*Current Cache Size ID Register*)
6-
pub struct Ccsidr(pub u32);
7+
#[bitbybit::bitfield(u32)]
8+
#[derive(Debug)]
9+
pub struct Ccsidr {
10+
#[bit(31, rw)]
11+
write_through: bool,
12+
#[bit(30, rw)]
13+
write_back: bool,
14+
#[bit(29, rw)]
15+
read_alloc: bool,
16+
#[bit(28, rw)]
17+
write_alloc: bool,
18+
#[bits(13..=27, rw)]
19+
num_sets: u15,
20+
#[bits(3..=12, rw)]
21+
associativity: u10,
22+
#[bits(0..=2, rw)]
23+
line_size: u3,
24+
}
25+
726
impl SysReg for Ccsidr {
827
const CP: u32 = 15;
928
const CRN: u32 = 0;
1029
const OP1: u32 = 1;
1130
const CRM: u32 = 0;
1231
const OP2: u32 = 0;
1332
}
33+
1434
impl crate::register::SysRegRead for Ccsidr {}
35+
1536
impl Ccsidr {
1637
#[inline]
1738
/// Reads CCSIDR (*Current Cache Size ID Register*)
1839
pub fn read() -> Ccsidr {
19-
unsafe { Self(<Self as SysRegRead>::read_raw()) }
40+
unsafe { Self::new_with_raw_value(<Self as SysRegRead>::read_raw()) }
2041
}
2142
}

cortex-ar/src/register/csselr.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
11
//! Code for managing CSSELR (*Cache Size Selection Register*)
2+
use arbitrary_int::u3;
23

34
use crate::register::{SysReg, SysRegRead, SysRegWrite};
45

6+
#[bitbybit::bitenum(u1, exhaustive = true)]
7+
#[derive(Debug, PartialEq, Eq)]
8+
pub enum CacheType {
9+
DataOrUnified = 0,
10+
Instruction = 1,
11+
}
12+
513
/// CSSELR (*Cache Size Selection Register*)
6-
pub struct Csselr(pub u32);
14+
#[bitbybit::bitfield(u32)]
15+
#[derive(Debug, PartialEq, Eq)]
16+
pub struct Csselr {
17+
/// 0 for L1 cache, 1 for L2, etc.
18+
#[bits(1..=3, rw)]
19+
level: u3,
20+
#[bit(0, rw)]
21+
cache_type: CacheType,
22+
}
23+
724
impl SysReg for Csselr {
825
const CP: u32 = 15;
926
const CRN: u32 = 0;
@@ -16,7 +33,7 @@ impl Csselr {
1633
#[inline]
1734
/// Reads CSSELR (*Cache Size Selection Register*)
1835
pub fn read() -> Csselr {
19-
unsafe { Self(<Self as SysRegRead>::read_raw()) }
36+
unsafe { Self::new_with_raw_value(<Self as SysRegRead>::read_raw()) }
2037
}
2138
}
2239
impl crate::register::SysRegWrite for Csselr {}
@@ -29,7 +46,7 @@ impl Csselr {
2946
/// Ensure that this value is appropriate for this register
3047
pub unsafe fn write(value: Self) {
3148
unsafe {
32-
<Self as SysRegWrite>::write_raw(value.0);
49+
<Self as SysRegWrite>::write_raw(value.raw_value());
3350
}
3451
}
3552
}

cortex-ar/src/register/dc_sw_ops.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use arbitrary_int::u3;
2+
3+
/// Create input data register value for cache maintenance operations by set and way.
4+
///
5+
/// ## Generics
6+
///
7+
/// - A: log2(ASSOCIATIVITY) rounded up to the next integer if necessary. For example, a 4-way
8+
/// associative cache will have a value of 2 and a 8-way associative cache will have a value of
9+
/// 4.
10+
/// - N: log2(LINE LENGTH). For example, a 32-byte line length (4 words) will have a value of
11+
/// 5.
12+
#[inline]
13+
pub const fn new<const A: usize, const N: usize>(way: u8, set: u16, level: u3) -> u32 {
14+
if A == 0 {
15+
(set << N) as u32 | level.value() as u32
16+
} else {
17+
(way << (32 - A)) as u32 | (set << N) as u32 | level.value() as u32
18+
}
19+
}
20+
21+
/// Create input data register value for cache maintenance operations by set and way.
22+
/// Returns [None] on invalid input.
23+
///
24+
/// # Arguments
25+
///
26+
/// - a: log2(ASSOCIATIVITY) rounded up to the next integer if necessary. For example, a 4-way
27+
/// associative cache will have a value of 2 and a 8-way associative cache will have a value of
28+
/// 4.
29+
/// - n: log2(LINE LENGTH). For example, a 32-byte line length (4 words) will have a value of
30+
/// 5.
31+
#[inline]
32+
pub const fn new_with_offsets(a: usize, way: u8, n: usize, set: u16, level: u3) -> u32 {
33+
if a == 0 {
34+
(set << n) as u32 | level.value() as u32
35+
} else {
36+
(way << (32 - a)) as u32 | (set << n) as u32 | level.value() as u32
37+
}
38+
}

cortex-ar/src/register/dccimvac.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//! DCCIMVAC (*Clean And Invalidate Data Cache Or Unified Cache Line by MVA to Point of Coherence.*)
2+
use crate::register::{SysReg, SysRegWrite};
3+
4+
pub struct Dccimvac(pub u32);
5+
6+
impl Dccimvac {
7+
#[inline]
8+
pub const fn new(addr: u32) -> Self {
9+
Self(addr)
10+
}
11+
}
12+
13+
impl SysReg for Dccimvac {
14+
const CP: u32 = 15;
15+
const CRN: u32 = 7;
16+
const OP1: u32 = 0;
17+
const CRM: u32 = 14;
18+
const OP2: u32 = 1;
19+
}
20+
21+
impl crate::register::SysRegWrite for Dccimvac {}
22+
23+
impl Dccimvac {
24+
#[inline]
25+
/// Writes DCCIMVAC (*Clean And Invalidate Data Cache Or Unified Cache Line by MVA to Point of Coherence.*)
26+
///
27+
/// # Safety
28+
///
29+
/// Ensure that this value is appropriate for this register. Generally, the address passed
30+
/// to the write call should be aligned to the cache line size.
31+
pub unsafe fn write(value: Self) {
32+
unsafe {
33+
<Self as SysRegWrite>::write_raw(value.0);
34+
}
35+
}
36+
}

cortex-ar/src/register/dccisw.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! DCCISW (*Clean and Invalidate Data or Unified cache line by Set/Way.*)
2+
3+
use arbitrary_int::u3;
4+
5+
use crate::register::{SysReg, SysRegWrite};
6+
7+
pub struct Dccisw(pub u32);
8+
9+
impl Dccisw {
10+
/// Create DCCISW value for cache cleaning and invalidation by set and way.
11+
///
12+
/// ## Generics
13+
///
14+
/// - A: log2(ASSOCIATIVITY) rounded up to the next integer if necessary. For example, a 4-way
15+
/// associative cache will have a value of 2 and a 8-way associative cache will have a value of
16+
/// 3.
17+
/// - N: log2(LINE LENGTH). For example, a 32-byte line length (4 words) will have a value of
18+
/// 5.
19+
#[inline]
20+
pub const fn new<const A: usize, const N: usize>(way: u8, set: u16, level: u3) -> Self {
21+
Self(super::dc_sw_ops::new::<A, N>(way, set, level))
22+
}
23+
24+
/// Create DCCISW value for cache cleaning and invalidation by set and way.
25+
/// Returns [None] on invalid input.
26+
///
27+
/// # Arguments
28+
///
29+
/// - a: log2(ASSOCIATIVITY) rounded up to the next integer if necessary. For example, a 4-way
30+
/// associative cache will have a value of 2 and a 8-way associative cache will have a value of
31+
/// 3.
32+
/// - n: log2(LINE LENGTH). For example, a 32-byte line length (4 words) will have a value of
33+
/// 5.
34+
#[inline]
35+
pub const fn new_with_offsets(a: usize, way: u8, n: usize, set: u16, level: u3) -> Self {
36+
Self(super::dc_sw_ops::new_with_offsets(a, way, n, set, level))
37+
}
38+
}
39+
impl SysReg for Dccisw {
40+
const CP: u32 = 15;
41+
const CRN: u32 = 7;
42+
const OP1: u32 = 0;
43+
const CRM: u32 = 14;
44+
const OP2: u32 = 2;
45+
}
46+
47+
impl crate::register::SysRegWrite for Dccisw {}
48+
49+
impl Dccisw {
50+
#[inline]
51+
/// Writes DCCISW (*Clean and Invalidate data or unified cache line by set/way.*)
52+
///
53+
/// # Safety
54+
///
55+
/// Ensure that this value is appropriate for this register
56+
pub unsafe fn write(value: Self) {
57+
unsafe {
58+
<Self as SysRegWrite>::write_raw(value.0);
59+
}
60+
}
61+
}

cortex-ar/src/register/dccmvac.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//! DCCMVAC (*Clean Data Cache Or Unified Cache Line by MVA to Point of Coherence.*)
2+
use crate::register::{SysReg, SysRegWrite};
3+
4+
pub struct Dccmvac(pub u32);
5+
6+
impl Dccmvac {
7+
#[inline]
8+
pub const fn new(addr: u32) -> Self {
9+
Self(addr)
10+
}
11+
}
12+
13+
impl SysReg for Dccmvac {
14+
const CP: u32 = 15;
15+
const CRN: u32 = 7;
16+
const OP1: u32 = 0;
17+
const CRM: u32 = 10;
18+
const OP2: u32 = 1;
19+
}
20+
21+
impl crate::register::SysRegWrite for Dccmvac {}
22+
23+
impl Dccmvac {
24+
#[inline]
25+
/// Writes DCCMVAC (*Clean Data Cache Or Unified Cache Line by MVA to Point of Coherence.*)
26+
///
27+
/// # Safety
28+
///
29+
/// Ensure that this value is appropriate for this register. Generally, the address passed
30+
/// to the write call should be aligned to the cache line size.
31+
pub unsafe fn write(value: Self) {
32+
unsafe {
33+
<Self as SysRegWrite>::write_raw(value.0);
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)