tock_registers/registers.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Implementation of included register types.
//!
//! This module provides a standard set of register types, which can
//! describe different access levels:
//!
//! - [`ReadWrite`] for registers which can be read and written to
//! - [`ReadOnly`] for registers which can only be read
//! - [`WriteOnly`] for registers which can only be written to
//! - [`Aliased`] for registers which can be both read and written,
//! but represent different registers depending on the operation
//! - [`InMemoryRegister`] provide a register-type in RAM using
//! volatile operations
//!
//! These types can be disabled by removing the `register_types` crate
//! feature (part of the default features). This is useful if this
//! crate should be used only as an interface library, or if all
//! unsafe code should be disabled.
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use crate::interfaces::{Readable, Writeable};
use crate::{RegisterLongName, UIntLike};
/// Read/Write registers.
///
/// For accessing and manipulating the register contents, the
/// [`Readable`], [`Writeable`] and
/// [`ReadWriteable`](crate::interfaces::ReadWriteable) traits are
/// implemented.
// To successfully alias this structure onto hardware registers in memory, this
// struct must be exactly the size of the `T` and is thus marked
// `repr(transparent)` over an `UnsafeCell<T>`, which itself is
// `repr(transparent)` over `T`.
//
// This struct is constructed by casting a pointer to it (or, implicitly, by
// casting a pointer to a larger struct that containts this type). As such, it
// does not have a public constructor and Rust thinks it's dead code and should
// be removed. We `allow(dead_code)` here to suppress this warning.
#[allow(dead_code)]
#[repr(transparent)]
pub struct ReadWrite<T: UIntLike, R: RegisterLongName = ()> {
value: UnsafeCell<T>,
associated_register: PhantomData<R>,
}
impl<T: UIntLike, R: RegisterLongName> Readable for ReadWrite<T, R> {
type T = T;
type R = R;
#[inline]
fn get(&self) -> Self::T {
unsafe { ::core::ptr::read_volatile(self.value.get()) }
}
}
impl<T: UIntLike, R: RegisterLongName> Writeable for ReadWrite<T, R> {
type T = T;
type R = R;
#[inline]
fn set(&self, value: T) {
unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
}
}
/// Read-only registers.
///
/// For accessing the register contents the [`Readable`] trait is
/// implemented.
// To successfully alias this structure onto hardware registers in memory, this
// struct must be exactly the size of the `T` and is thus marked
// `repr(transparent)` over an `UnsafeCell<T>`, which itself is
// `repr(transparent)` over `T`.
//
// This struct is constructed by casting a pointer to it (or, implicitly, by
// casting a pointer to a larger struct that containts this type). As such, it
// does not have a public constructor and Rust thinks it's dead code and should
// be removed. We `allow(dead_code)` here to suppress this warning.
#[allow(dead_code)]
#[repr(transparent)]
pub struct ReadOnly<T: UIntLike, R: RegisterLongName = ()> {
value: T,
associated_register: PhantomData<R>,
}
impl<T: UIntLike, R: RegisterLongName> Readable for ReadOnly<T, R> {
type T = T;
type R = R;
#[inline]
fn get(&self) -> T {
unsafe { ::core::ptr::read_volatile(&self.value) }
}
}
/// Write-only registers.
///
/// For setting the register contents the [`Writeable`] trait is
/// implemented.
// To successfully alias this structure onto hardware registers in memory, this
// struct must be exactly the size of the `T` and is thus marked
// `repr(transparent)` over an `UnsafeCell<T>`, which itself is
// `repr(transparent)` over `T`.
//
// This struct is constructed by casting a pointer to it (or, implicitly, by
// casting a pointer to a larger struct that containts this type). As such, it
// does not have a public constructor and Rust thinks it's dead code and should
// be removed. We `allow(dead_code)` here to suppress this warning.
#[allow(dead_code)]
#[repr(transparent)]
pub struct WriteOnly<T: UIntLike, R: RegisterLongName = ()> {
value: UnsafeCell<T>,
associated_register: PhantomData<R>,
}
impl<T: UIntLike, R: RegisterLongName> Writeable for WriteOnly<T, R> {
type T = T;
type R = R;
#[inline]
fn set(&self, value: T) {
unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
}
}
/// Read-only and write-only registers aliased to the same address.
///
/// Unlike the [`ReadWrite`] register, this represents a register
/// which has different meanings based on if it is written or read.
/// This might be found on a device where control and status registers
/// are accessed via the same memory address via writes and reads,
/// respectively.
///
/// This register implements [`Readable`] and [`Writeable`], but in
/// general does not implement
/// [`ReadWriteable`](crate::interfaces::ReadWriteable) (only if the
/// type parameters `R` and `W` are identical, in which case a
/// [`ReadWrite`] register might be a better choice).
// To successfully alias this structure onto hardware registers in memory, this
// struct must be exactly the size of the `T` and is thus marked
// `repr(transparent)` over an `UnsafeCell<T>`, which itself is
// `repr(transparent)` over `T`.
//
// This struct is constructed by casting a pointer to it (or, implicitly, by
// casting a pointer to a larger struct that containts this type). As such, it
// does not have a public constructor and Rust thinks it's dead code and should
// be removed. We `allow(dead_code)` here to suppress this warning.
#[allow(dead_code)]
#[repr(transparent)]
pub struct Aliased<T: UIntLike, R: RegisterLongName = (), W: RegisterLongName = ()> {
value: UnsafeCell<T>,
associated_register: PhantomData<(R, W)>,
}
impl<T: UIntLike, R: RegisterLongName, W: RegisterLongName> Readable for Aliased<T, R, W> {
type T = T;
type R = R;
#[inline]
fn get(&self) -> Self::T {
unsafe { ::core::ptr::read_volatile(self.value.get()) }
}
}
impl<T: UIntLike, R: RegisterLongName, W: RegisterLongName> Writeable for Aliased<T, R, W> {
type T = T;
type R = W;
#[inline]
fn set(&self, value: Self::T) {
unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
}
}
/// In memory volatile register.
///
/// Like [`ReadWrite`], but can be safely constructed using the
/// [`InMemoryRegister::new`] method. It will always be initialized to
/// the passed in, well-defined initial value.
///
/// For accessing and manipulating the register contents, the
/// [`Readable`], [`Writeable`] and
/// [`ReadWriteable`](crate::interfaces::ReadWriteable) traits are
/// implemented.
// To successfully alias this structure onto hardware registers in memory, this
// struct must be exactly the size of the `T`.
#[repr(transparent)]
pub struct InMemoryRegister<T: UIntLike, R: RegisterLongName = ()> {
value: UnsafeCell<T>,
associated_register: PhantomData<R>,
}
impl<T: UIntLike, R: RegisterLongName> InMemoryRegister<T, R> {
pub const fn new(value: T) -> Self {
InMemoryRegister {
value: UnsafeCell::new(value),
associated_register: PhantomData,
}
}
}
impl<T: UIntLike, R: RegisterLongName> Readable for InMemoryRegister<T, R> {
type T = T;
type R = R;
#[inline]
fn get(&self) -> Self::T {
unsafe { ::core::ptr::read_volatile(self.value.get()) }
}
}
impl<T: UIntLike, R: RegisterLongName> Writeable for InMemoryRegister<T, R> {
type T = T;
type R = R;
#[inline]
fn set(&self, value: T) {
unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
}
}