1use bitrs::{bitfield_repr, layout, multilayout};
6use regio::arm64::{SysReg, spec};
7
8pub const CTR_EL0: SysReg<spec::CTR_EL0, CacheTypeRegister> = SysReg::new();
10
11#[bitfield_repr(u8)]
13#[derive(Clone, Copy)]
14pub enum L1ICachePolicy {
15 Vpipt = 0b00,
16 Aivivt = 0b01,
17 Vipt = 0b10,
18 Pipt = 0b11,
19}
20
21layout!({
22 pub struct CacheTypeRegister(u64);
24 {
25 let __ @ 63..38;
26 let tmin_line @ 37..32;
27 let __ @ 31 = 1;
28 let __ @ 30;
29 let dic @ 29;
30 let idc @ 28;
31 let cwg @ 27..24;
32 let erg @ 23..20;
33
34 let dmin_line @ 19..16;
36
37 let l1_ip @ 15..14: L1ICachePolicy;
38 let __ @ 13..4;
39
40 let imin_line @ 3..0;
42 }
43});
44
45impl CacheTypeRegister {
46 pub const fn dcache_line_size(&self) -> usize {
48 (1 << self.dmin_line()) * size_of::<u32>()
49 }
50
51 pub const fn icache_line_size(&self) -> usize {
53 (1 << self.imin_line()) * size_of::<u32>()
54 }
55}
56
57pub const DCZID_EL0: SysReg<spec::DCZID_EL0, DataCacheZeroIdRegister> = SysReg::new();
59
60layout!({
61 pub struct DataCacheZeroIdRegister(u64);
63 {
64 let __ @ 63..5;
65 let dzp @ 4;
66 let bz @ 3..0;
67 }
68});
69
70impl DataCacheZeroIdRegister {
71 pub fn zva_line_size(&self) -> usize {
73 (1 << self.bz()) * size_of::<u32>()
74 }
75}
76
77pub const CLIDR_EL1: SysReg<spec::CLIDR_EL1, CacheLevelIdRegister> = SysReg::new();
79
80#[bitfield_repr(u8)]
83#[derive(Clone, Copy)]
84pub enum CacheType {
85 None = 0b000,
87 Instruction = 0b001,
88 Data = 0b010,
89 Separate = 0b011,
91 Unified = 0b100,
92}
93
94impl CacheType {
95 pub const fn has_instruction_cache(self) -> bool {
96 matches!(self, Self::Instruction | Self::Separate)
97 }
98
99 pub const fn has_data_cache(self) -> bool {
100 matches!(self, Self::Data | Self::Separate)
101 }
102}
103
104#[bitfield_repr(u8)]
107#[derive(Clone, Copy)]
108pub enum TagCacheType {
109 None = 0b00,
110 Separate = 0b01,
112 UnifiedLines = 0b10,
115 SeparateLines = 0b11,
118}
119
120layout!({
121 pub struct CacheLevelIdRegister(u64);
123 {
124 let __ @ 63..47;
125 let ttype7 @ 46..45: TagCacheType; let ttype6 @ 44..43: TagCacheType;
127 let ttype5 @ 42..41: TagCacheType;
128 let ttype4 @ 40..39: TagCacheType;
129 let ttype3 @ 38..37: TagCacheType;
130 let ttype2 @ 36..35: TagCacheType;
131 let ttype1 @ 34..33: TagCacheType;
132 let icb @ 32..30; let lou_u @ 29..27; let loc @ 26..24; let lou_is @ 23..21; let ctype7 @ 20..18: CacheType; let ctype6 @ 17..15: CacheType;
138 let ctype5 @ 14..12: CacheType;
139 let ctype4 @ 11..9: CacheType;
140 let ctype3 @ 8..6: CacheType;
141 let ctype2 @ 5..3: CacheType;
142 let ctype1 @ 2..0: CacheType;
143 }
144});
145
146impl CacheLevelIdRegister {
147 pub const MAX_LEVELS: usize = 7;
149
150 pub fn cache_type(&self, level: usize) -> CacheType {
156 match level {
157 0 => self.ctype1(),
158 1 => self.ctype2(),
159 2 => self.ctype3(),
160 3 => self.ctype4(),
161 4 => self.ctype5(),
162 5 => self.ctype6(),
163 6 => self.ctype7(),
164 _ => panic!("cache level {level} out of range"),
165 }
166 }
167
168 pub fn tag_cache_type(&self, level: usize) -> TagCacheType {
173 match level {
174 0 => self.ttype1(),
175 1 => self.ttype2(),
176 2 => self.ttype3(),
177 3 => self.ttype4(),
178 4 => self.ttype5(),
179 5 => self.ttype6(),
180 6 => self.ttype7(),
181 _ => panic!("cache level {level} out of range"),
182 }
183 }
184}
185
186pub const CCSIDR_EL1: SysReg<spec::CCSIDR_EL1, CacheSizeIdRegister> = SysReg::new();
191
192pub const CCSIDR_EL1_CCIDX: SysReg<spec::CCSIDR_EL1, CacheSizeIdRegisterCcidx> = SysReg::new();
196
197multilayout!({
198 #[bitrs(legacy)]
200 pub struct CacheSizeIdRegister(u64);
201
202 #[bitrs(ccidx)]
204 pub struct CacheSizeIdRegisterCcidx(u64);
205
206 #[legacy]
207 {
208 let __ @ 63..28;
209 let num_sets @ 27..13; let associativity @ 12..3; }
212
213 #[ccidx]
214 {
215 let __ @ 63..56;
216 let num_sets @ 55..32; let __ @ 31..24;
218 let associativity @ 23..3; }
220
221 {
222 let line_size @ 2..0;
224 }
225});
226
227macro_rules! impl_cache_size_id {
228 ($($layout:ty),*) => {
229 $(
230 impl $layout {
231 pub const fn sets(&self) -> u32 {
233 self.num_sets() as u32 + 1
234 }
235
236 pub const fn ways(&self) -> u32 {
238 self.associativity() as u32 + 1
239 }
240
241 pub const fn line_size_bytes(&self) -> usize {
243 1 << (self.line_size() as usize + 4)
244 }
245 }
246 )*
247 };
248}
249
250impl_cache_size_id!(CacheSizeIdRegister, CacheSizeIdRegisterCcidx);
251
252pub const CSSELR_EL1: SysReg<spec::CSSELR_EL1, CacheSizeSelectionRegister> = SysReg::new();
254
255layout!({
256 pub struct CacheSizeSelectionRegister(u64);
258 {
259 let __ @ 63..5;
260 let tnd @ 4; let level @ 3..1; let ind @ 0; }
264});
265
266impl CacheSizeSelectionRegister {
267 pub fn select(level: u8, instruction: bool) -> Self {
270 *Self::new().set_level(level).set_ind(instruction)
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 #[test]
279 fn cache_type_el0() {
280 let ctr = *CacheTypeRegister::new().set_dmin_line(4).set_imin_line(4);
281 assert_eq!(ctr.dcache_line_size(), 64);
282 assert_eq!(ctr.icache_line_size(), 64);
283 }
284
285 #[test]
286 fn data_cache_zero_id_el0() {
287 let dczid = *DataCacheZeroIdRegister::new().set_bz(4);
288 assert_eq!(dczid.zva_line_size(), 64);
289 }
290
291 #[test]
292 fn cache_level_id_el1() {
293 let clidr = *CacheLevelIdRegister::new()
294 .set_ctype1(CacheType::Separate)
295 .set_ctype2(CacheType::Unified)
296 .set_ttype2(TagCacheType::UnifiedLines)
297 .set_loc(2)
298 .set_lou_is(1);
299 assert_eq!(clidr.cache_type(0), CacheType::Separate);
300 assert_eq!(clidr.cache_type(1), CacheType::Unified);
301 assert_eq!(clidr.cache_type(2), CacheType::None);
302 assert_eq!(clidr.tag_cache_type(0), TagCacheType::None);
303 assert_eq!(clidr.tag_cache_type(1), TagCacheType::UnifiedLines);
304 assert_eq!(clidr.loc(), 2);
305 assert_eq!(clidr.lou_is(), 1);
306 assert!(CacheType::Separate.has_instruction_cache());
307 assert!(CacheType::Separate.has_data_cache());
308 assert!(!CacheType::Instruction.has_data_cache());
309 assert!(!CacheType::Unified.has_data_cache());
310 }
311
312 #[test]
313 fn cache_size_id_el1() {
314 let ccsidr =
315 *CacheSizeIdRegister::new().set_num_sets(63).set_associativity(3).set_line_size(2);
316 assert_eq!(ccsidr.sets(), 64);
317 assert_eq!(ccsidr.ways(), 4);
318 assert_eq!(ccsidr.line_size_bytes(), 64);
319
320 let ccsidr = *CacheSizeIdRegisterCcidx::new()
321 .set_num_sets(2047)
322 .set_associativity(15)
323 .set_line_size(3);
324 assert_eq!(ccsidr.sets(), 2048);
325 assert_eq!(ccsidr.ways(), 16);
326 assert_eq!(ccsidr.line_size_bytes(), 128);
327 }
328
329 #[test]
330 fn cache_size_selection_el1() {
331 let csselr = CacheSizeSelectionRegister::select(2, true);
332 assert_eq!(csselr.bits(), 0b101);
333 assert_eq!(csselr.level(), 2);
334 assert!(csselr.ind());
335 }
336}