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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*
DISCLAIMER
This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products.
No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
applicable laws, including copyright laws.
THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED
OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY
LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT,
INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR
ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability
of this software. By using this software, you agree to the additional terms and conditions found by accessing the
following link:
http://www.renesas.com/disclaimer
*/
// Generated from SVD 1.00.00, with svd2pac 0.6.0 on Thu, 24 Jul 2025 04:55:39 +0000
use std::sync::OnceLock;
thread_local! {
/// Function that will be called when reading from a register using
/// though the PAC API.
///
/// The function parameters are the following:
/// - a u64 representing the register address
/// - a u64 representing the read mask (i.e. how many bits are read)
/// This is necessary due to the way that the generated PACs handles
/// generic register sizes.
pub(crate) static READ_FN: OnceLock<fn(usize,usize)->u64> = OnceLock::new();
/// Function that will be called when writing to a register using
/// though the PAC API.
///
/// The function parameters are the following:
/// - a u64 representing the register address
/// - a u64 representing the write mask (i.e. how many bits are read)
/// This is necessary due to the way that the generated PACs handles
/// generic register sizes.
/// - a u64 representing the value that gets written to the register
pub (crate) static WRITE_FN: OnceLock<fn(usize,usize,u64)> = OnceLock::new();
pub (crate) static LDMST: OnceLock<fn(usize,u64)> = OnceLock::new();
}
/// Macro to generate the setters for the thread_local static
/// register access functions.
macro_rules! set_access_fn {
($CONST_ID:ident,$fn_id:ident,$fn_literal:literal,$access_fn_type:ty,$doc:literal) => {
#[doc=$doc]
pub fn $fn_id(fun: $access_fn_type) -> Result<(), String> {
$CONST_ID.with(|function| {
function.set(fun).or_else(|_| {
Err(format!(
"The thread local {} can only be set once.",
$fn_literal
))
})
})
}
};
}
set_access_fn!(
READ_FN,
set_read_fn,
"read_fn",
fn(usize, usize) -> u64,
"Set the function that is called when a read to a register happens\n through the PAC API.\n The function is called with the following arguments (in order):\n - a u64 representing the register address\n - a u64 representing the read mask (i.e. how many bits are read)\n This is necessary due to the way that the generated PACs handle\n generic register sizes.\n"
);
set_access_fn!(
WRITE_FN,
set_write_fn,
"write_fn",
fn(usize, usize, u64),
"Set the function that is called when a write to a register happens\n through the PAC API.\n The function is called with the following arguments (in order):\n - a u64 representing the register address\n - a u64 representing the write mask (i.e. how many bits are read)\n This is necessary due to the way that the generated PACs handle\n generic register sizes.\n - a u64 representing the value that gets written to the register\n"
);
// # Why does this exist?
//
// When writing tests, it is useful to be able to read/write registers that
// are normally **read-only/write-only**.
// Especially when simulating registers on non-embedded targets
// one might want to provide a test value to an input buffer register, or
// read a value from a write only resister to check its value.
//
// The two traits: `ReadOnlyWrite` and `WriteOnlyRead` defined in this
// module, provide exactly that functionality to every [`Reg<T, A: Access>`](crate::common::Reg).
//
// By importing this module, all read-only registers become `ReadOnlyWrite`
// and all write-only registers become `WriteOnlyRead`.
// With these new markers the following functions are unlocked:
// - `read_write_only` (like read but for **write-only** registers)
// - `write_read_only` (like write but for **read-only** registers)
// - `init_read_only` (like init but for **read-only** registers)
// - `modify_read_only` (like modify but for **read-only** registers)
// - `modify_write_only` (like modify but for **write-only** registers)
//
// This separates these special register accesses form the ones allowed as by
// the SVD-spec of the target device. The separation is reinforced by keeping
// the trait in a separate module, requiring an explicit import of the module.
// The module should not be imported in productive code, only in test code.
//
// # Alternative Solution
//
// In previous commits, an alternative solution in common.rs as tested:
// ```rust,ignore
// #[cfg(feature = "tracing")]
// impl Read for W {}
// #[cfg(feature = "tracing")]
// impl Write for R {}
// ```
// We found that the usual setup for projects that depend on the generated PAC
// ends up looking like this:
// ```toml
// [dependencies]
// pac_for_chip = { version = "x.x.x" }
// [dev-dependencies]
// pac_for_chip = { version = "x.x.x", features = ["tracing"] }
// ```
//
// Unfortunately, rust-analyzer was not smart enough to **not** suggest
// `read()/write()` for registers that are write-only/read-only when writing
// **non**-test code (i.e. code that would end up in an embedded build).
// `cargo` would not allow you to build in release mode (i.e. for embedded)
// and spit out errors that some registers cannot be read from/written to.
//
// This could cause confusion as to why rust-analyzer suggests these functions
// and cargo failing to build.
/// Allow reading and writing registers that are read-only/write-only.
///
/// Don't ever use this module unless you know what you are doing. This allows
/// reading/writing registers that are write-/read-only respectively.
///
/// Use this module when writing tests where you want to read/write simulated
/// registers to check their contents or simulate an external input to a
/// read-only buffer register.
#[cfg(feature = "tracing")]
pub mod insanely_unsafe {
use crate::common::sealed::{CastFrom, RegSpec};
use crate::common::{Access, R, Read, Reg, W, Write};
use crate::{RegValueT, RegisterValue};
pub trait WriteOnlyRead: Access {}
impl WriteOnlyRead for W {}
pub trait ReadOnlyWrite: Access {}
impl ReadOnlyWrite for R {}
impl<T: RegSpec, A: WriteOnlyRead> Reg<T, A> {
/// Read a **write-only** register.
///
/// # Safety
/// Reading from a write-only register can cause undefined behavior on target devices.
/// This function shall only ever be used on non-embedded devices when simulating registers.
#[inline(always)]
pub unsafe fn read_write_only(&self) -> RegValueT<T> {
let val = {
let mut buf: u64 = 0x0;
super::READ_FN.with(|rf| {
buf = rf.get().unwrap()(self.addr(), std::mem::size_of::<T::DataType>());
});
T::DataType::cast_from(buf)
};
<RegValueT<_> as RegisterValue<_>>::new(val)
}
}
impl<T: RegSpec, A: ReadOnlyWrite> Reg<T, A> {
/// Write register value back to **read-only** register.
///
/// # Arguments
///
/// * `reg_value` - A string slice that holds the name of the person
///
/// # Safety
/// Write operation on a **read-only** register can cause undefined
/// behavior. This function shall only ever be used on non-embedded targets
/// (e.g. when simulating registers).
#[inline(always)]
pub unsafe fn write_read_only(&self, reg_value: RegValueT<T>) {
super::WRITE_FN.with(|wf| {
wf.get().unwrap()(
self.addr(),
std::mem::size_of::<T::DataType>(),
reg_value.data.into(),
)
});
}
}
impl<T: Default + RegSpec, A: ReadOnlyWrite> Reg<T, A>
where
RegValueT<T>: Default,
{
/// Init **read-only** register with value returned by the closure.
///
/// # Arguments
///
/// * `f` - Closure that receive as input a register value initialized with register value at Power On Reset.
///
/// # Safety
/// This is extremely unsafe and shall only ever be used on non-embedded
/// devices in order init simulated registers.
///
#[inline(always)]
/// Write value computed by closure that receive as input the reset value of register
pub unsafe fn init_read_only(&self, f: impl FnOnce(RegValueT<T>) -> RegValueT<T>) {
let val = RegValueT::<T>::default();
let res = f(val);
self.write_read_only(res);
}
}
impl<T: RegSpec, A: WriteOnlyRead + Write> Reg<T, A> {
#[inline(always)]
/// Don't ever use this on embedded targets. Only use for unit tests on
/// host machines.
/// Write register with value returned by the closure.
///
/// # Arguments
///
/// * `f` - Closure that receive as input a register value read from register.
///
/// # Safety
/// Write operation could cause undefined behavior for some peripheral. Developer shall read device user manual.
/// Register is Send and Sync to allow complete freedom. Developer is responsible for proper use with multithreaded tests.
///
pub unsafe fn modify_write_only(&self, f: impl FnOnce(RegValueT<T>) -> RegValueT<T>) {
let val = self.read_write_only();
let res = f(val);
self.write(res);
}
}
impl<T: RegSpec, A: Read + ReadOnlyWrite> Reg<T, A> {
#[inline(always)]
/// Write a **read-only** register with value returned by the closure.
///
/// # Arguments
///
/// * `f` - Closure that receive as input a register value read from register.
///
/// # Safety
/// Write operation on **read-only** registers can cause undefined
/// behavior on embedded devices. See module level safety warnings for explanation when to use this function.
/// Write operation could cause undefined behavior for some peripheral. Developer shall read device user manual.
/// Register is Send and Sync to allow complete freedom. Developer is responsible for proper use with multithreaded tests.
///
pub unsafe fn modify_read_only(&self, f: impl FnOnce(RegValueT<T>) -> RegValueT<T>) {
let val = self.read();
let res = f(val);
self.write_read_only(res);
}
}
}