Skip to main content

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    /// Check address alignment
81    ///
82    /// Reports whether an address is aligned according to this region size
83    pub fn is_aligned(&self, addr: *const u8) -> bool {
84        let addr = addr as usize;
85        if *self == RegionSize::_4G {
86            // only one address allowed for 4GB region size
87            addr == 0
88        } else {
89            let n = self.raw_value().as_u8();
90            let mask = (1 << (n + 1)) - 1;
91            (addr & mask) == 0
92        }
93    }
94}
95
96/// DRSR (*Data Region Size and Enable Register*)
97#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"))]
98pub struct Drsr {
99    /// Sub-region bitmask
100    ///
101    /// The region is divided into exactly eight equal sized subregions.
102    /// Subregion 0 is the subregion at the least significant address.
103    ///
104    /// A 1 bit means that sub-region is disabled.
105    ///
106    /// Only applies to regions sized 256 bytes or larger.
107    #[bits(8..=15, rw)]
108    subregion_mask: u8,
109    /// Region Size
110    #[bits(1..=5, rw)]
111    region_size: RegionSize,
112    /// Is region enabled?
113    #[bits(0..=0, rw)]
114    enabled: bool,
115}
116
117impl SysReg for Drsr {
118    const CP: u32 = 15;
119    const CRN: u32 = 6;
120    const OP1: u32 = 0;
121    const CRM: u32 = 1;
122    const OP2: u32 = 2;
123}
124
125impl crate::register::SysRegRead for Drsr {}
126
127impl Drsr {
128    #[inline]
129    /// Reads DRSR (*Data Region Size and Enable Register*)
130    ///
131    /// Set RGNR to control which region this reads.
132    pub fn read() -> Drsr {
133        Self::new_with_raw_value(<Self as SysRegRead>::read_raw())
134    }
135}
136
137impl crate::register::SysRegWrite for Drsr {}
138
139impl Drsr {
140    #[inline]
141    /// Writes DRSR (*Data Region Size and Enable Register*)
142    ///
143    /// Set RGNR to control which region this affects.
144    pub fn write(value: Drsr) {
145        unsafe { <Self as SysRegWrite>::write_raw(value.raw_value()) }
146    }
147}
148
149#[cfg(test)]
150mod test {
151    use super::*;
152    #[test]
153    fn aligned_4g() {
154        let addr: *const u8 = core::ptr::null();
155        assert!(RegionSize::_4G.is_aligned(addr));
156    }
157
158    #[test]
159    fn aligned_1g() {
160        let addr = 0x4000_0000 as *const u8;
161        assert!(RegionSize::_1G.is_aligned(addr));
162        let addr = 0x4000_0001 as *const u8;
163        assert!(!RegionSize::_1G.is_aligned(addr));
164    }
165
166    #[test]
167    fn aligned_256b() {
168        let addr = 0x100 as *const u8;
169        assert!(RegionSize::_256B.is_aligned(addr));
170        let addr = 0x80 as *const u8;
171        assert!(!RegionSize::_256B.is_aligned(addr));
172    }
173}