avr_boot/
address.rs

1use core::convert::From;
2
3/// 16 or 24 bit program memory address
4///
5/// Used internally to provide correct page allignment and efficient storage.
6/// Use u16.into() or u32.into() to suit your target MCU's address space size.
7///
8/// Although this struct is always 3 bytes in size, on an MCU with <65kB of flash memory,
9/// the highest byte is optimised away completely, taking it's effective size down to only 2 bytes.
10#[derive(Copy, Clone, PartialEq, Eq, Debug)]
11pub struct Address {
12    base: u16,
13    ramp: u8,
14}
15
16impl Address {
17    const PCWORD_MASK: u16 = (crate::SPM_PAGESIZE_BYTES - 1) as u16;
18    const PCPAGE_MASK: u16 = !Self::PCWORD_MASK;
19
20    fn new(base: u32) -> Self {
21        Self {
22            base: base as u16,
23            ramp: (base >> 16) as u8,
24        }
25    }
26
27    /// Mask off the PCWORD part of the address, leaving only PCPAGE.  
28    ///
29    /// The resulting address is aligned to the start of the page.
30    pub fn into_page_aligned(self) -> Self {
31        Self {
32            base: self.base & Self::PCPAGE_MASK,
33            ramp: self.ramp,
34        }
35    }
36
37    /// The word byte index within the page: technically PCWORD << 1
38    pub fn word(&self) -> u16 {
39        self.base & Self::PCWORD_MASK
40    }
41
42    /// The extended byte of the address, usually written to RAMPZ on MCUs with extended addressing
43    pub fn ramp(&self) -> u8 {
44        self.ramp
45    }
46}
47
48impl From<u16> for Address {
49    fn from(i: u16) -> Self {
50        Self::new(i as u32)
51    }
52}
53
54impl From<u8> for Address {
55    fn from(i: u8) -> Self {
56        Self::new(i as u32)
57    }
58}
59
60impl From<u32> for Address {
61    fn from(i: u32) -> Self {
62        Self::new(i)
63    }
64}
65
66impl From<Address> for u32 {
67    fn from(address: Address) -> u32 {
68        address.base as u32 + ((address.ramp as u32) << 16)
69    }
70}
71
72impl From<Address> for u16 {
73    fn from(address: Address) -> u16 {
74        address.base
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn it_aligns_addess_to_page() {
84        let start_address = crate::SPM_PAGESIZE_BYTES as u32 * 8 + 17;
85        let address: Address = start_address.into();
86
87        assert_eq!(
88            address.into_page_aligned(),
89            Address::new(crate::SPM_PAGESIZE_BYTES as u32 * 8)
90        );
91    }
92
93    #[test]
94    fn it_masks_pcword_part() {
95        let start_address = crate::SPM_PAGESIZE_BYTES as u32 * 8 + 17;
96        let address: Address = start_address.into();
97
98        assert_eq!(address.word(), 17);
99    }
100}