tock_registers/
local_register.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Module containing the [`LocalRegisterCopy`] type. Please refer to
6//! its documentation.
7
8use core::fmt;
9use core::marker::PhantomData;
10
11use crate::fields::{Field, FieldValue, TryFromValue};
12use crate::{RegisterLongName, UIntLike};
13
14/// A read-write copy of register contents.
15///
16/// This behaves very similarly to a read-write register, but instead of doing a
17/// volatile read to MMIO to get the value for each function call, a copy of the
18/// register contents are stored locally in memory. This allows a peripheral to
19/// do a single read on a register, and then check which bits are set without
20/// having to do a full MMIO read each time. It also allows the value of the
21/// register to be "cached" in case the peripheral driver needs to clear the
22/// register in hardware yet still be able to check the bits.  You can write to
23/// a local register, which will modify the stored value, but will not modify
24/// any hardware because it operates only on local copy.
25///
26/// This type does not implement the [`Readable`](crate::interfaces::Readable)
27/// and [`Writeable`](crate::interfaces::Writeable) traits because it requires a
28/// mutable reference to modify the contained value. It still mirrors the
29/// interface which would be exposed by a type implementing
30/// [`Readable`](crate::interfaces::Readable),
31/// [`Writeable`](crate::interfaces::Writeable) and
32/// [`ReadWriteable`](crate::interfaces::ReadWriteable).
33#[derive(Copy, Clone)]
34pub struct LocalRegisterCopy<T: UIntLike, R: RegisterLongName = ()> {
35    value: T,
36    associated_register: PhantomData<R>,
37}
38
39impl<T: UIntLike, R: RegisterLongName> LocalRegisterCopy<T, R> {
40    pub const fn new(value: T) -> Self {
41        LocalRegisterCopy {
42            value,
43            associated_register: PhantomData,
44        }
45    }
46
47    /// Get the raw register value
48    #[inline]
49    pub fn get(&self) -> T {
50        self.value
51    }
52
53    /// Set the raw register value
54    #[inline]
55    pub fn set(&mut self, value: T) {
56        self.value = value;
57    }
58
59    /// Read the value of the given field
60    #[inline]
61    pub fn read(&self, field: Field<T, R>) -> T {
62        field.read(self.get())
63    }
64
65    /// Read value of the given field as an enum member
66    #[inline]
67    pub fn read_as_enum<E: TryFromValue<T, EnumType = E>>(&self, field: Field<T, R>) -> Option<E> {
68        field.read_as_enum(self.get())
69    }
70
71    /// Write the value of one or more fields, overwriting the other fields with
72    /// zero
73    #[inline]
74    pub fn write(&mut self, field: FieldValue<T, R>) {
75        self.set(field.value);
76    }
77
78    /// Write the value of one or more fields, leaving the other fields
79    /// unchanged
80    #[inline]
81    pub fn modify(&mut self, field: FieldValue<T, R>) {
82        self.set(field.modify(self.get()));
83    }
84
85    /// Check if one or more bits in a field are set
86    #[inline]
87    pub fn is_set(&self, field: Field<T, R>) -> bool {
88        field.is_set(self.get())
89    }
90
91    /// Check if any bits corresponding to the mask in the passed `FieldValue`
92    /// are set.
93    #[inline]
94    pub fn any_matching_bits_set(&self, field: FieldValue<T, R>) -> bool {
95        field.any_matching_bits_set(self.get())
96    }
97
98    /// Check if all specified parts of a field match
99    #[inline]
100    pub fn matches_all(&self, field: FieldValue<T, R>) -> bool {
101        field.matches_all(self.get())
102    }
103
104    /// Check if any of the passed parts of a field exactly match the contained
105    /// value. This allows for matching on unset bits, or matching on specific
106    /// values in multi-bit fields.
107    #[inline]
108    pub fn matches_any(&self, fields: &[FieldValue<T, R>]) -> bool {
109        fields
110            .iter()
111            .any(|field| self.get() & field.mask() == field.value)
112    }
113
114    /// Do a bitwise AND operation of the stored value and the passed in value
115    /// and return a new LocalRegisterCopy.
116    #[inline]
117    pub fn bitand(&self, rhs: T) -> LocalRegisterCopy<T, R> {
118        LocalRegisterCopy::new(self.value & rhs)
119    }
120
121    #[inline]
122    pub fn debug(&self) -> crate::debug::RegisterDebugValue<T, R>
123    where
124        R: crate::debug::RegisterDebugInfo<T>,
125    {
126        crate::debug::RegisterDebugValue {
127            data: self.get(),
128            _reg: core::marker::PhantomData,
129        }
130    }
131}
132
133impl<T: UIntLike + fmt::Debug, R: RegisterLongName> fmt::Debug for LocalRegisterCopy<T, R> {
134    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135        write!(f, "{:?}", self.value)
136    }
137}
138
139// Helper macro to implement From<LocalRegisterCopy<T: UIntLike>, R>>
140// for <T: UIntLike>
141macro_rules! From_impl_for {
142    ($type:ty) => {
143        impl<R: RegisterLongName> From<LocalRegisterCopy<$type, R>> for $type {
144            fn from(r: LocalRegisterCopy<$type, R>) -> $type {
145                r.value
146            }
147        }
148    };
149}
150
151From_impl_for!(u8);
152From_impl_for!(u16);
153From_impl_for!(u32);
154From_impl_for!(u64);
155From_impl_for!(u128);
156From_impl_for!(usize);