aarch32_cpu/register/
drsr.rs

1//! Code for managing DRSR (*Data Region Size and Enable Register*)
2
3use arbitrary_int::prelude::*;
4
5use crate::register::{SysReg, SysRegRead, SysRegWrite};
6
7/// The size of a region
8#[derive(Debug, PartialEq, Eq)]
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[bitbybit::bitenum(u5, exhaustive = true)]
12pub enum RegionSize {
13    /// A value of 0 is not permitted, this value is reserved and unpredictable.
14    Invalid = 0,
15    /// N = 1 => 4 bytes
16    _4B = 1,
17    /// N = 2 => 8 bytes
18    _8B = 2,
19    /// N = 3 => 16 bytes
20    _16B = 3,
21    /// N = 4 => 32 BYTES
22    _32B = 4,
23    /// N = 5 => 64 bytes
24    _64B = 5,
25    /// N = 6 => 128 bytes
26    _128B = 6,
27    /// N = 7 => 256 bytes
28    _256B = 7,
29    /// N = 8 => 512 bytes
30    _512b = 8,
31    /// N = 9 => 1 KiB
32    _1K = 9,
33    /// N = 10 => 2 KiB
34    _2K = 10,
35    /// N = 11 => 4 KiB
36    _4K = 11,
37    /// N = 12 => 8 KiB
38    _8K = 12,
39    /// N = 13 => 16 KiB
40    _16K = 13,
41    /// N = 14 => 32 KiB
42    _32K = 14,
43    /// N = 15 => 64 KiB
44    _64K = 15,
45    /// N = 16 => 128 KiB
46    _128K = 16,
47    /// N = 17 => 256 KiB
48    _256K = 17,
49    /// N = 18 => 512 KiB
50    _512K = 18,
51    /// N = 19 => 1 MiB
52    _1M = 19,
53    /// N = 20 => 2 MiB
54    _2M = 20,
55    /// N = 21 => 4 MiB
56    _4M = 21,
57    /// N = 22 => 8 MiB
58    _8M = 22,
59    /// N = 23 => 16 MiB
60    _16M = 23,
61    /// N = 24 => 32 MiB
62    _32M = 24,
63    /// N = 25 => 64 MiB
64    _64M = 25,
65    /// N = 26 => 128 MiB
66    _128M = 26,
67    /// N = 27 => 256 MiB
68    _256M = 27,
69    /// N = 28 => 512 MiB
70    _512M = 28,
71    /// N = 29 => 1 GiB
72    _1G = 29,
73    /// N = 30 => 2 GiB
74    _2G = 30,
75    /// N = 31 => 4 GiB
76    _4G = 31,
77}
78
79impl RegionSize {
80    pub fn is_aligned(&self, addr: *const u8) -> bool {
81        let addr = addr as usize;
82        if *self == RegionSize::_4G {
83            // only one address allowed for 4GB region size
84            addr == 0
85        } else {
86            let n = self.raw_value().as_u8();
87            let mask = (1 << (n + 1)) - 1;
88            (addr & mask) == 0
89        }
90    }
91}
92
93/// DRSR (*Data Region Size and Enable Register*)
94#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"))]
95pub struct Drsr {
96    /// Sub-region bitmask
97    ///
98    /// The region is divided into exactly eight equal sized subregions.
99    /// Subregion 0 is the subregion at the least significant address.
100    ///
101    /// A 1 bit means that sub-region is disabled.
102    ///
103    /// Only applies to regions sized 256 bytes or larger.
104    #[bits(8..=15, rw)]
105    subregion_mask: u8,
106    /// Region Size
107    #[bits(1..=5, rw)]
108    region_size: RegionSize,
109    /// Is region enabled?
110    #[bits(0..=0, rw)]
111    enabled: bool,
112}
113
114impl SysReg for Drsr {
115    const CP: u32 = 15;
116    const CRN: u32 = 6;
117    const OP1: u32 = 0;
118    const CRM: u32 = 1;
119    const OP2: u32 = 2;
120}
121
122impl crate::register::SysRegRead for Drsr {}
123
124impl Drsr {
125    #[inline]
126    /// Reads DRSR (*Data Region Size and Enable Register*)
127    ///
128    /// Set RGNR to control which region this reads.
129    pub fn read() -> Drsr {
130        unsafe { Self::new_with_raw_value(<Self as SysRegRead>::read_raw()) }
131    }
132}
133
134impl crate::register::SysRegWrite for Drsr {}
135
136impl Drsr {
137    #[inline]
138    /// Writes DRSR (*Data Region Size and Enable Register*)
139    ///
140    /// Set RGNR to control which region this affects.
141    pub fn write(value: Drsr) {
142        unsafe { <Self as SysRegWrite>::write_raw(value.raw_value()) }
143    }
144}
145
146#[cfg(test)]
147mod test {
148    use super::*;
149    #[test]
150    fn aligned_4g() {
151        let addr: *const u8 = core::ptr::null();
152        assert!(RegionSize::_4G.is_aligned(addr));
153    }
154
155    #[test]
156    fn aligned_1g() {
157        let addr = 0x4000_0000 as *const u8;
158        assert!(RegionSize::_1G.is_aligned(addr));
159        let addr = 0x4000_0001 as *const u8;
160        assert!(!RegionSize::_1G.is_aligned(addr));
161    }
162
163    #[test]
164    fn aligned_256b() {
165        let addr = 0x100 as *const u8;
166        assert!(RegionSize::_256B.is_aligned(addr));
167        let addr = 0x80 as *const u8;
168        assert!(!RegionSize::_256B.is_aligned(addr));
169    }
170}