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
use core::ptr::{read_volatile, write_volatile};
use reg::{marker, RawAlias, RawValue, RegionAlias};
pub trait RawPointer<R, A> {
unsafe fn new(address: usize) -> Self;
fn get(&self) -> usize;
fn read_raw(&self) -> u32 {
unsafe { read_volatile(self.get() as *const u32) }
}
fn write_raw(&self, value: u32) {
unsafe {
write_volatile(self.get() as *mut u32, value);
}
}
}
pub trait ThreadPointer<R, A>: RawPointer<R, A> {
fn modify_raw<F>(&self, f: F)
where
F: Fn(u32) -> u32;
}
pub trait ValuePointer<R, A>: ThreadPointer<R, A> {
type Value: RawValue<R>;
fn read(&self) -> Self::Value {
Self::Value::new(self.read_raw())
}
fn write<F>(&self, f: F)
where
F: Fn(&mut Self::Value) -> &Self::Value,
{
self.write_raw(f(&mut Self::Value::new(0)).get());
}
fn modify<F>(&self, f: F)
where
F: Fn(&mut Self::Value) -> &Self::Value,
{
self.modify_raw(|x| f(&mut Self::Value::new(x)).get());
}
}
pub trait AliasPointer<R, A>: RawPointer<R, A> {
type Alias: RawAlias<R>;
fn bits(&self) -> Self::Alias {
unsafe { Self::Alias::new(self.get()) }
}
}
impl<T, R, A> ThreadPointer<R, A> for T
where
T: RawPointer<R, A>,
{
default fn modify_raw<F>(&self, f: F)
where
F: Fn(u32) -> u32,
{
let address = self.get() as *mut u32;
let mut value: u32;
let mut status: u32;
loop {
unsafe {
asm!("
ldrex $0, [$1]
" : "=r"(value)
: "r"(address)
:
: "volatile");
}
value = f(value);
unsafe {
asm!("
strex $0, $1, [$2]
" : "=r"(status)
: "r"(value), "r"(address)
:
: "volatile");
}
if status == 0 {
break;
}
}
}
}
impl<T, R> ThreadPointer<R, marker::Single> for T
where
T: RawPointer<R, marker::Single>,
{
fn modify_raw<F>(&self, f: F)
where
F: Fn(u32) -> u32,
{
self.write_raw(f(self.read_raw()));
}
}