tock_registers/
fields.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//! Register bitfield types and macros
6//!
7//! To conveniently access and manipulate fields of a register, this
8//! library provides types and macros to describe and access bitfields
9//! of a register. This can be especially useful in conjuction with
10//! the APIs defined in [`interfaces`](crate::interfaces), which make
11//! use of these types and hence allow to access and manipulate
12//! bitfields of proper registers directly.
13//!
14//! A specific section (bitfield) in a register is described by the
15//! [`Field`] type, consisting of an unshifted bitmask over the base
16//! register [`UIntLike`](crate::UIntLike) type, and a shift
17//! parameter. It is further associated with a specific
18//! [`RegisterLongName`], which can prevent its use with incompatible
19//! registers.
20//!
21//! A value of a section of a register is described by the
22//! [`FieldValue`] type. It stores the information of the respective
23//! section in the register, as well as the associated value. A
24//! [`FieldValue`] can be created from a [`Field`] through the
25//! [`val`](Field::val) method.
26//!
27//! ## `register_bitfields` macro
28//!
29//! For defining register layouts with an associated
30//! [`RegisterLongName`](crate::RegisterLongName), along with
31//! [`Field`]s and matching [`FieldValue`]s, a convenient macro-based
32//! interface can be used.
33//!
34//! The following example demonstrates how two registers can be
35//! defined, over a `u32` base type:
36//!
37//! ```rust
38//! # use tock_registers::register_bitfields;
39//! # use tock_registers::registers::InMemoryRegister;
40//! # use tock_registers::interfaces::{Readable, ReadWriteable};
41//! register_bitfields![u32,
42//!     Uart [
43//!         ENABLE OFFSET(0) NUMBITS(4) [
44//!             ON = 8,
45//!             OFF = 0
46//!         ]
47//!     ],
48//!     Psel [
49//!         PIN OFFSET(0) NUMBITS(6),
50//!         CONNECT OFFSET(31) NUMBITS(1)
51//!     ],
52//! ];
53//!
54//! // In this scope, `Uart` is a module, representing the register and
55//! // its fields. `Uart::Register` is a `RegisterLongName` type
56//! // identifying this register. `Uart::ENABLE` is a field covering the
57//! // first 4 bits of this register. `Uart::ENABLE::ON` is a
58//! // `FieldValue` over that field, with the associated value 8.
59//! // We can now use the types like so:
60//! let reg: InMemoryRegister<u32, Uart::Register> = InMemoryRegister::new(0);
61//! assert!(reg.read(Uart::ENABLE) == 0x00000000);
62//! reg.modify(Uart::ENABLE::ON);
63//! assert!(reg.get() == 0x00000008);
64//! ```
65
66// The register interface uses `+` in a way that is fine for bitfields, but
67// looks unusual (and perhaps problematic) to a linter. We just ignore those
68// lints for this file.
69#![allow(clippy::suspicious_op_assign_impl)]
70#![allow(clippy::suspicious_arithmetic_impl)]
71
72use core::marker::PhantomData;
73use core::ops::{Add, AddAssign};
74
75use crate::{RegisterLongName, UIntLike};
76
77/// Specific section of a register.
78///
79/// For the Field, the mask is unshifted, ie. the LSB should always be set.
80pub struct Field<T: UIntLike, R: RegisterLongName> {
81    pub mask: T,
82    pub shift: usize,
83    associated_register: PhantomData<R>,
84}
85
86impl<T: UIntLike, R: RegisterLongName> Field<T, R> {
87    pub const fn new(mask: T, shift: usize) -> Field<T, R> {
88        Field {
89            mask: mask,
90            shift: shift,
91            associated_register: PhantomData,
92        }
93    }
94
95    #[inline]
96    pub fn read(self, val: T) -> T {
97        (val & (self.mask << self.shift)) >> self.shift
98    }
99
100    #[inline]
101    /// Check if one or more bits in a field are set
102    pub fn is_set(self, val: T) -> bool {
103        val & (self.mask << self.shift) != T::zero()
104    }
105
106    #[inline]
107    /// Read value of the field as an enum member
108    ///
109    /// This method expects to be passed the unasked and unshifted register
110    /// value, extracts the field value by calling [`Field::read`] and
111    /// subsequently passes that value to the [`TryFromValue`] implementation on
112    /// the passed enum type.
113    ///
114    /// The [`register_bitfields!`](crate::register_bitfields) macro will
115    /// generate an enum containing the various named field variants and
116    /// implementing the required [`TryFromValue`] trait. It is accessible as
117    /// `$REGISTER_NAME::$FIELD_NAME::Value`.
118    ///
119    /// This method can be useful to symbolically represent read register field
120    /// states throughout the codebase and to enforce exhaustive matches over
121    /// all defined valid register field values.
122    ///
123    /// ## Usage Example
124    ///
125    /// ```rust
126    /// # use tock_registers::interfaces::Readable;
127    /// # use tock_registers::registers::InMemoryRegister;
128    /// # use tock_registers::register_bitfields;
129    /// register_bitfields![u8,
130    ///     EXAMPLEREG [
131    ///         TESTFIELD OFFSET(3) NUMBITS(3) [
132    ///             Foo = 2,
133    ///             Bar = 3,
134    ///             Baz = 6,
135    ///         ],
136    ///     ],
137    /// ];
138    ///
139    /// assert_eq!(
140    ///     EXAMPLEREG::TESTFIELD.read_as_enum::<EXAMPLEREG::TESTFIELD::Value>(0x9C).unwrap(),
141    ///     EXAMPLEREG::TESTFIELD::Value::Bar
142    /// );
143    /// ```
144    pub fn read_as_enum<E: TryFromValue<T, EnumType = E>>(self, val: T) -> Option<E> {
145        E::try_from_value(self.read(val))
146    }
147}
148
149// #[derive(Copy, Clone)] won't work here because it will use
150// incorrect bounds, as a result of using a PhantomData over the
151// generic R. The PhantomData<R> implements Copy regardless of whether
152// R does, but the #[derive(Copy, Clone)] generates
153//
154//    #[automatically_derived]
155//    #[allow(unused_qualifications)]
156//    impl<T: ::core::marker::Copy + UIntLike,
157//         R: ::core::marker::Copy + RegisterLongName>
158//            ::core::marker::Copy for Field<T, R> {}
159//
160// , so Field will only implement Copy if R: Copy.
161//
162// Manually implementing Clone and Copy works around this issue.
163//
164// Relevant Rust issue: https://github.com/rust-lang/rust/issues/26925
165impl<T: UIntLike, R: RegisterLongName> Clone for Field<T, R> {
166    fn clone(&self) -> Self {
167        *self
168    }
169}
170impl<T: UIntLike, R: RegisterLongName> Copy for Field<T, R> {}
171
172macro_rules! Field_impl_for {
173    ($type:ty) => {
174        impl<R: RegisterLongName> Field<$type, R> {
175            pub const fn val(&self, value: $type) -> FieldValue<$type, R> {
176                FieldValue::<$type, R>::new(self.mask, self.shift, value)
177            }
178        }
179    };
180}
181
182Field_impl_for!(u8);
183Field_impl_for!(u16);
184Field_impl_for!(u32);
185Field_impl_for!(u64);
186Field_impl_for!(u128);
187Field_impl_for!(usize);
188
189/// Values for the specific register fields.
190///
191/// For the FieldValue, the masks and values are shifted into their actual
192/// location in the register.
193#[derive(Copy, Clone)]
194pub struct FieldValue<T: UIntLike, R: RegisterLongName> {
195    mask: T,
196    pub value: T,
197    associated_register: PhantomData<R>,
198}
199
200macro_rules! FieldValue_impl_for {
201    ($type:ty) => {
202        // Necessary to split the implementation of new() out because the bitwise
203        // math isn't treated as const when the type is generic.
204        // Tracking issue: https://github.com/rust-lang/rfcs/pull/2632
205        impl<R: RegisterLongName> FieldValue<$type, R> {
206            pub const fn new(mask: $type, shift: usize, value: $type) -> Self {
207                FieldValue {
208                    mask: mask << shift,
209                    value: (value & mask) << shift,
210                    associated_register: PhantomData,
211                }
212            }
213        }
214
215        // Necessary to split the implementation of From<> out because of the orphan rule
216        // for foreign trait implementation (see [E0210](https://doc.rust-lang.org/error-index.html#E0210)).
217        impl<R: RegisterLongName> From<FieldValue<$type, R>> for $type {
218            fn from(val: FieldValue<$type, R>) -> $type {
219                val.value
220            }
221        }
222    };
223}
224
225FieldValue_impl_for!(u8);
226FieldValue_impl_for!(u16);
227FieldValue_impl_for!(u32);
228FieldValue_impl_for!(u64);
229FieldValue_impl_for!(u128);
230FieldValue_impl_for!(usize);
231
232impl<T: UIntLike, R: RegisterLongName> FieldValue<T, R> {
233    #[inline]
234    pub fn none() -> Self {
235        Self {
236            mask: T::zero(),
237            value: T::zero(),
238            associated_register: PhantomData,
239        }
240    }
241
242    /// Get the raw bitmask represented by this FieldValue.
243    #[inline]
244    pub const fn mask(&self) -> T {
245        self.mask as T
246    }
247
248    #[inline]
249    pub fn read(&self, field: Field<T, R>) -> T {
250        field.read(self.value)
251    }
252
253    /// Modify fields in a register value
254    #[inline]
255    pub fn modify(self, val: T) -> T {
256        (val & !self.mask) | self.value
257    }
258
259    /// Check if any of the bits covered by the mask for this
260    /// `FieldValue` and set in the `FieldValue` are also set
261    /// in the passed value
262    #[inline]
263    pub fn any_matching_bits_set(&self, val: T) -> bool {
264        val & self.mask & self.value != T::zero()
265    }
266
267    /// Check if all specified parts of a field match
268    #[inline]
269    pub fn matches_all(&self, val: T) -> bool {
270        val & self.mask == self.value
271    }
272}
273
274// Combine two fields with the addition operator
275impl<T: UIntLike, R: RegisterLongName> Add for FieldValue<T, R> {
276    type Output = Self;
277
278    #[inline]
279    fn add(self, rhs: Self) -> Self {
280        FieldValue {
281            mask: self.mask | rhs.mask,
282            value: self.value | rhs.value,
283            associated_register: PhantomData,
284        }
285    }
286}
287
288// Combine two fields with the += operator
289impl<T: UIntLike, R: RegisterLongName> AddAssign for FieldValue<T, R> {
290    #[inline]
291    fn add_assign(&mut self, rhs: FieldValue<T, R>) {
292        self.mask |= rhs.mask;
293        self.value |= rhs.value;
294    }
295}
296
297/// Conversion of raw register value into enumerated values member.
298/// Implemented inside register_bitfields! macro for each bit field.
299pub trait TryFromValue<V> {
300    type EnumType;
301
302    fn try_from_value(v: V) -> Option<Self::EnumType>;
303}
304
305/// Helper macro for computing bitmask of variable number of bits
306#[macro_export]
307macro_rules! bitmask {
308    ($numbits:expr) => {
309        (1 << ($numbits - 1)) + ((1 << ($numbits - 1)) - 1)
310    };
311}
312
313/// Helper macro for defining register fields.
314#[macro_export]
315macro_rules! register_bitmasks {
316    {
317        // BITFIELD_NAME OFFSET(x)
318        $(#[$outer:meta])*
319        $valtype:ident, $reg_desc:ident, [
320            $( $(#[$inner:meta])* $field:ident OFFSET($offset:expr)),+ $(,)?
321        ]
322    } => {
323        $(#[$outer])*
324        $( $crate::register_bitmasks!($valtype, $reg_desc, $(#[$inner])* $field, $offset, 1, []); )*
325    };
326    {
327        // BITFIELD_NAME OFFSET
328        // All fields are 1 bit
329        $(#[$outer:meta])*
330        $valtype:ident, $reg_desc:ident, [
331            $( $(#[$inner:meta])* $field:ident $offset:expr ),+ $(,)?
332        ]
333    } => {
334        $(#[$outer])*
335        $( $crate::register_bitmasks!($valtype, $reg_desc, $(#[$inner])* $field, $offset, 1, []); )*
336    };
337
338    {
339        // BITFIELD_NAME OFFSET(x) NUMBITS(y)
340        $(#[$outer:meta])*
341        $valtype:ident, $reg_desc:ident, [
342            $( $(#[$inner:meta])* $field:ident OFFSET($offset:expr) NUMBITS($numbits:expr) ),+ $(,)?
343        ]
344    } => {
345        $(#[$outer])*
346        $( $crate::register_bitmasks!($valtype, $reg_desc, $(#[$inner])* $field, $offset, $numbits, []); )*
347    };
348
349    {
350        // BITFIELD_NAME OFFSET(x) NUMBITS(y) []
351        $(#[$outer:meta])*
352        $valtype:ident, $reg_desc:ident, [
353            $( $(#[$inner:meta])* $field:ident OFFSET($offset:expr) NUMBITS($numbits:expr)
354               $values:tt ),+ $(,)?
355        ]
356    } => {
357        $(#[$outer])*
358        $( $crate::register_bitmasks!($valtype, $reg_desc, $(#[$inner])* $field, $offset, $numbits,
359                              $values); )*
360    };
361    {
362        $valtype:ident, $reg_desc:ident, $(#[$outer:meta])* $field:ident,
363                    $offset:expr, $numbits:expr,
364                    [$( $(#[$inner:meta])* $valname:ident = $value:expr ),+ $(,)?]
365    } => { // this match arm is duplicated below with an allowance for 0 elements in the valname -> value array,
366        // to seperately support the case of zero-variant enums not supporting non-default
367        // representations.
368        #[allow(non_upper_case_globals)]
369        #[allow(unused)]
370        pub const $field: Field<$valtype, $reg_desc> =
371            Field::<$valtype, $reg_desc>::new($crate::bitmask!($numbits), $offset);
372
373        #[allow(non_snake_case)]
374        #[allow(unused)]
375        $(#[$outer])*
376        pub mod $field {
377            #[allow(unused_imports)]
378            use $crate::fields::{TryFromValue, FieldValue};
379            use super::$reg_desc;
380
381            $(
382            #[allow(non_upper_case_globals)]
383            #[allow(unused)]
384            $(#[$inner])*
385            pub const $valname: FieldValue<$valtype, $reg_desc> =
386                FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
387                    $offset, $value);
388            )*
389
390            #[allow(non_upper_case_globals)]
391            #[allow(unused)]
392            pub const SET: FieldValue<$valtype, $reg_desc> =
393                FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
394                    $offset, $crate::bitmask!($numbits));
395
396            #[allow(non_upper_case_globals)]
397            #[allow(unused)]
398            pub const CLEAR: FieldValue<$valtype, $reg_desc> =
399                FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
400                    $offset, 0);
401
402            #[allow(dead_code)]
403            #[allow(non_camel_case_types)]
404            #[derive(Copy, Clone, Debug, Eq, PartialEq)]
405            #[repr($valtype)] // so that values larger than isize::MAX can be stored
406            $(#[$outer])*
407            pub enum Value {
408                $(
409                    $(#[$inner])*
410                    $valname = $value,
411                )*
412            }
413
414            impl TryFromValue<$valtype> for Value {
415                type EnumType = Value;
416
417                fn try_from_value(v: $valtype) -> Option<Self::EnumType> {
418                    match v {
419                        $(
420                            $(#[$inner])*
421                            x if x == Value::$valname as $valtype => Some(Value::$valname),
422                        )*
423
424                        _ => Option::None
425                    }
426                }
427            }
428
429            impl From<Value> for FieldValue<$valtype, $reg_desc> {
430                fn from(v: Value) -> Self {
431                    Self::new($crate::bitmask!($numbits), $offset, v as $valtype)
432                }
433            }
434        }
435    };
436    {
437        $valtype:ident, $reg_desc:ident, $(#[$outer:meta])* $field:ident,
438                    $offset:expr, $numbits:expr,
439                    []
440    } => { //same pattern as previous match arm, for 0 elements in array. Removes code associated with array.
441        #[allow(non_upper_case_globals)]
442        #[allow(unused)]
443        pub const $field: Field<$valtype, $reg_desc> =
444            Field::<$valtype, $reg_desc>::new($crate::bitmask!($numbits), $offset);
445
446        #[allow(non_snake_case)]
447        #[allow(unused)]
448        $(#[$outer])*
449        pub mod $field {
450            #[allow(unused_imports)]
451            use $crate::fields::{FieldValue, TryFromValue};
452            use super::$reg_desc;
453
454            #[allow(non_upper_case_globals)]
455            #[allow(unused)]
456            pub const SET: FieldValue<$valtype, $reg_desc> =
457                FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
458                    $offset, $crate::bitmask!($numbits));
459
460            #[allow(non_upper_case_globals)]
461            #[allow(unused)]
462            pub const CLEAR: FieldValue<$valtype, $reg_desc> =
463                FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
464                    $offset, 0);
465
466            #[allow(dead_code)]
467            #[allow(non_camel_case_types)]
468            $(#[$outer])*
469            pub enum Value {}
470
471            impl TryFromValue<$valtype> for Value {
472                type EnumType = Value;
473
474                fn try_from_value(_v: $valtype) -> Option<Self::EnumType> {
475                    Option::None
476                }
477            }
478        }
479    };
480}
481
482/// Define register types and fields.
483#[macro_export]
484macro_rules! register_bitfields {
485    {
486        $valtype:ident, $( $(#[$inner:meta])* $vis:vis $reg:ident $fields:tt ),* $(,)?
487    } => {
488        $(
489            #[allow(non_snake_case)]
490            $(#[$inner])*
491            $vis mod $reg {
492                // Visibility note: This is left always `pub` as it is not
493                // meaningful to restrict access to the `Register` element of
494                // the register module if the module itself is in scope
495                //
496                // (if you can access $reg, you can access $reg::Register)
497                #[derive(Clone, Copy)]
498                pub struct Register;
499                impl $crate::RegisterLongName for Register {}
500
501                use $crate::fields::Field;
502
503                $crate::register_bitmasks!( $valtype, Register, $fields );
504            }
505        )*
506    }
507}
508
509#[cfg(test)]
510mod tests {
511    #[derive(Debug, PartialEq, Eq)]
512    enum Foo {
513        Foo0,
514        Foo1,
515        Foo2,
516        Foo3,
517        Foo4,
518        Foo5,
519        Foo6,
520        Foo7,
521    }
522
523    impl crate::fields::TryFromValue<u16> for Foo {
524        type EnumType = Foo;
525
526        fn try_from_value(v: u16) -> Option<Self::EnumType> {
527            Self::try_from_value(v as u32)
528        }
529    }
530    impl crate::fields::TryFromValue<u32> for Foo {
531        type EnumType = Foo;
532
533        fn try_from_value(v: u32) -> Option<Self::EnumType> {
534            match v {
535                0 => Some(Foo::Foo0),
536                1 => Some(Foo::Foo1),
537                2 => Some(Foo::Foo2),
538                3 => Some(Foo::Foo3),
539                4 => Some(Foo::Foo4),
540                5 => Some(Foo::Foo5),
541                6 => Some(Foo::Foo6),
542                7 => Some(Foo::Foo7),
543                _ => None,
544            }
545        }
546    }
547
548    mod field {
549        use super::Foo;
550        use crate::fields::{Field, TryFromValue};
551
552        #[test]
553        fn test_new() {
554            let field8 = Field::<u8, ()>::new(0x12, 3);
555            assert_eq!(field8.mask, 0x12_u8);
556            assert_eq!(field8.shift, 3);
557            let field16 = Field::<u16, ()>::new(0x1234, 5);
558            assert_eq!(field16.mask, 0x1234_u16);
559            assert_eq!(field16.shift, 5);
560            let field32 = Field::<u32, ()>::new(0x12345678, 9);
561            assert_eq!(field32.mask, 0x12345678_u32);
562            assert_eq!(field32.shift, 9);
563            let field64 = Field::<u64, ()>::new(0x12345678_9abcdef0, 1);
564            assert_eq!(field64.mask, 0x12345678_9abcdef0_u64);
565            assert_eq!(field64.shift, 1);
566            let field128 = Field::<u128, ()>::new(0x12345678_9abcdef0_0fedcba9_87654321, 1);
567            assert_eq!(field128.mask, 0x12345678_9abcdef0_0fedcba9_87654321_u128);
568            assert_eq!(field128.shift, 1);
569        }
570
571        #[test]
572        fn test_read() {
573            let field = Field::<u32, ()>::new(0xFF, 4);
574            assert_eq!(field.read(0x123), 0x12);
575            let field = Field::<u32, ()>::new(0xF0F, 4);
576            assert_eq!(field.read(0x1234), 0x103);
577        }
578
579        #[test]
580        fn test_is_set() {
581            let field = Field::<u16, ()>::new(0xFF, 4);
582            assert_eq!(field.is_set(0), false);
583            assert_eq!(field.is_set(0xFFFF), true);
584            assert_eq!(field.is_set(0x0FF0), true);
585            assert_eq!(field.is_set(0x1000), false);
586            assert_eq!(field.is_set(0x0100), true);
587            assert_eq!(field.is_set(0x0010), true);
588            assert_eq!(field.is_set(0x0001), false);
589
590            for shift in 0..24 {
591                let field = Field::<u32, ()>::new(0xFF, shift);
592                for x in 1..=0xFF {
593                    assert_eq!(field.is_set(x << shift), true);
594                }
595                assert_eq!(field.is_set(!(0xFF << shift)), false);
596            }
597        }
598
599        #[test]
600        fn test_read_as_enum() {
601            let field = Field::<u16, ()>::new(0x7, 4);
602            assert_eq!(field.read_as_enum(0x1234), Some(Foo::Foo3));
603            assert_eq!(field.read_as_enum(0x5678), Some(Foo::Foo7));
604            assert_eq!(field.read_as_enum(0xFFFF), Some(Foo::Foo7));
605            assert_eq!(field.read_as_enum(0x0000), Some(Foo::Foo0));
606            assert_eq!(field.read_as_enum(0x0010), Some(Foo::Foo1));
607            assert_eq!(field.read_as_enum(0x1204), Some(Foo::Foo0));
608
609            for shift in 0..29 {
610                let field = Field::<u32, ()>::new(0x7, shift);
611                for x in 0..8 {
612                    assert_eq!(field.read_as_enum(x << shift), Foo::try_from_value(x));
613                }
614            }
615        }
616    }
617
618    mod field_value {
619        use crate::fields::Field;
620
621        #[test]
622        fn test_from() {
623            let field = Field::<u32, ()>::new(0xFF, 4);
624            assert_eq!(u32::from(field.val(0)), 0);
625            assert_eq!(u32::from(field.val(0xFFFFFFFF)), 0xFF0);
626            assert_eq!(u32::from(field.val(0x12)), 0x120);
627            assert_eq!(u32::from(field.val(0x123)), 0x230);
628
629            for shift in 0..32 {
630                let field = Field::<u32, ()>::new(0xFF, shift);
631                for x in 0..=0xFF {
632                    assert_eq!(u32::from(field.val(x)), x << shift);
633                }
634            }
635        }
636
637        #[test]
638        fn test_read_same_field() {
639            let field = Field::<u32, ()>::new(0xFF, 4);
640            assert_eq!(field.val(0).read(field), 0);
641            assert_eq!(field.val(0xFFFFFFFF).read(field), 0xFF);
642            assert_eq!(field.val(0x12).read(field), 0x12);
643            assert_eq!(field.val(0x123).read(field), 0x23);
644
645            for shift in 0..24 {
646                let field = Field::<u32, ()>::new(0xFF, shift);
647                for x in 0..=0xFF {
648                    assert_eq!(field.val(x).read(field), x);
649                }
650            }
651        }
652
653        #[test]
654        fn test_read_disjoint_fields() {
655            for shift in 0..24 {
656                let field1 = Field::<u32, ()>::new(0xF0, shift);
657                let field2 = Field::<u32, ()>::new(0x0F, shift);
658                for x in 0..=0xFF {
659                    assert_eq!(field1.val(x).read(field2), 0);
660                    assert_eq!(field2.val(x).read(field1), 0);
661                }
662            }
663            for shift in 0..24 {
664                let field1 = Field::<u32, ()>::new(0xF, shift);
665                let field2 = Field::<u32, ()>::new(0xF, shift + 4);
666                for x in 0..=0xFF {
667                    assert_eq!(field1.val(x).read(field2), 0);
668                    assert_eq!(field2.val(x).read(field1), 0);
669                }
670            }
671        }
672
673        #[test]
674        fn test_modify() {
675            let field = Field::<u32, ()>::new(0xFF, 4);
676            assert_eq!(field.val(0x23).modify(0x0000), 0x0230);
677            assert_eq!(field.val(0x23).modify(0xFFFF), 0xF23F);
678            assert_eq!(field.val(0x23).modify(0x1234), 0x1234);
679            assert_eq!(field.val(0x23).modify(0x5678), 0x5238);
680        }
681
682        #[test]
683        fn test_any_matching_bits_set() {
684            let field = Field::<u32, ()>::new(0xFF, 4);
685            assert_eq!(field.val(0x23).any_matching_bits_set(0x1234), true);
686            assert_eq!(field.val(0x23).any_matching_bits_set(0x5678), true);
687            assert_eq!(field.val(0x23).any_matching_bits_set(0x5008), false);
688
689            for shift in 0..24 {
690                let field = Field::<u32, ()>::new(0xFF, shift);
691                let field_value = field.val(0xff);
692                for y in 1..=0xff {
693                    assert_eq!(field_value.any_matching_bits_set(y << shift), true,);
694                }
695                assert_eq!(field_value.any_matching_bits_set(0), false);
696                assert_eq!(field_value.any_matching_bits_set(!(0xFF << shift)), false);
697            }
698        }
699
700        #[test]
701        fn test_matches_all() {
702            let field = Field::<u32, ()>::new(0xFF, 4);
703            assert_eq!(field.val(0x23).matches_all(0x1234), true);
704            assert_eq!(field.val(0x23).matches_all(0x5678), false);
705
706            for shift in 0..24 {
707                let field = Field::<u32, ()>::new(0xFF, shift);
708                for x in 0..=0xFF {
709                    assert_eq!(field.val(x).matches_all(x << shift), true);
710                    assert_eq!(field.val(x + 1).matches_all(x << shift), false);
711                }
712            }
713        }
714
715        #[test]
716        fn test_matches_any() {
717            register_bitfields! {
718                u32,
719
720                TEST [
721                    FLAG OFFSET(18) NUMBITS(1) [],
722                    SIZE OFFSET(0) NUMBITS(2) [
723                        Byte = 0,
724                        Halfword = 1,
725                        Word = 2
726                    ],
727                ]
728            }
729
730            let value: crate::LocalRegisterCopy<u32, TEST::Register> =
731                crate::LocalRegisterCopy::new(2);
732            assert!(value.matches_any(&[TEST::SIZE::Word]));
733            assert!(!value.matches_any(&[TEST::SIZE::Halfword]));
734            assert!(!value.matches_any(&[TEST::SIZE::Byte]));
735            assert!(value.matches_any(&[TEST::SIZE::Word, TEST::FLAG::SET]));
736            assert!(value.matches_any(&[TEST::SIZE::Halfword, TEST::FLAG::CLEAR]));
737            assert!(!value.matches_any(&[TEST::SIZE::Halfword, TEST::FLAG::SET]));
738            let value: crate::LocalRegisterCopy<u32, TEST::Register> =
739                crate::LocalRegisterCopy::new(266241);
740            assert!(value.matches_any(&[TEST::FLAG::SET]));
741            assert!(!value.matches_any(&[TEST::FLAG::CLEAR]));
742        }
743
744        #[test]
745        fn test_add_disjoint_fields() {
746            let field1 = Field::<u32, ()>::new(0xFF, 24);
747            let field2 = Field::<u32, ()>::new(0xFF, 16);
748            let field3 = Field::<u32, ()>::new(0xFF, 8);
749            let field4 = Field::<u32, ()>::new(0xFF, 0);
750            assert_eq!(
751                u32::from(
752                    field1.val(0x12) + field2.val(0x34) + field3.val(0x56) + field4.val(0x78)
753                ),
754                0x12345678
755            );
756
757            for shift in 0..24 {
758                let field1 = Field::<u32, ()>::new(0xF, shift);
759                let field2 = Field::<u32, ()>::new(0xF, shift + 4);
760                for x in 0..=0xF {
761                    for y in 0..=0xF {
762                        assert_eq!(
763                            u32::from(field1.val(x) + field2.val(y)),
764                            (x | (y << 4)) << shift
765                        );
766                    }
767                }
768            }
769        }
770
771        #[test]
772        fn test_add_assign_disjoint_fields() {
773            let field1 = Field::<u32, ()>::new(0xFF, 24);
774            let field2 = Field::<u32, ()>::new(0xFF, 16);
775            let field3 = Field::<u32, ()>::new(0xFF, 8);
776            let field4 = Field::<u32, ()>::new(0xFF, 0);
777
778            let mut value = field1.val(0x12);
779            value += field2.val(0x34);
780            value += field3.val(0x56);
781            value += field4.val(0x78);
782            assert_eq!(u32::from(value), 0x12345678);
783
784            for shift in 0..24 {
785                let field1 = Field::<u32, ()>::new(0xF, shift);
786                let field2 = Field::<u32, ()>::new(0xF, shift + 4);
787                for x in 0..=0xF {
788                    for y in 0..=0xF {
789                        let mut value = field1.val(x);
790                        value += field2.val(y);
791                        assert_eq!(u32::from(value), (x | (y << 4)) << shift);
792                    }
793                }
794            }
795        }
796    }
797
798    // TODO: More unit tests here.
799}