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
#![cfg_attr(feature = "std", allow(unreachable_code, unused_variables))]
use core::{
fmt::{self, Write},
slice,
};
const ADDRESS_BASE: usize = 0xE000_0000;
#[derive(Clone, Copy)]
pub struct Port {
address: usize,
}
pub trait Integer: Copy {
fn write(self, address: usize);
}
impl Port {
pub fn new(address: usize) -> Self {
assert!(address < 0x20);
Self {
address: ADDRESS_BASE + (address << 2),
}
}
pub fn write_bytes(self, bytes: &[u8]) {
fn write_slice<T: Integer>(port: Port, slice: &[T]) {
for item in slice {
port.write(*item);
}
}
let mut end = bytes.len();
if end < 4 {
return write_slice(self, bytes);
}
let mut start = bytes.as_ptr() as usize;
let mut rem = start & 0b11;
end += start;
if rem != 0 {
rem = 0b100 - rem;
write_slice(self, unsafe {
slice::from_raw_parts(start as *const u8, rem)
});
start += rem;
}
rem = end & 0b11;
end -= rem;
write_slice(self, unsafe {
slice::from_raw_parts(start as *const u32, end - start >> 2)
});
write_slice(self, unsafe {
slice::from_raw_parts(end as *const u8, rem)
});
}
pub fn write<T: Integer>(self, value: T) -> Self {
value.write(self.address);
self
}
}
impl Write for Port {
fn write_str(&mut self, string: &str) -> fmt::Result {
self.write_bytes(string.as_bytes());
Ok(())
}
}
impl Integer for u8 {
fn write(self, address: usize) {
#[cfg(feature = "std")]
return unimplemented!();
unsafe {
asm!("
0:
ldrexb r0, [$1]
cmp r0, #0
itt ne
strexbne r0, $0, [$1]
cmpne r0, #1
beq 0b
" :
: "r"(self), "r"(address as *mut Self)
: "r0", "cc"
: "volatile"
);
}
}
}
impl Integer for u16 {
fn write(self, address: usize) {
#[cfg(feature = "std")]
return unimplemented!();
unsafe {
asm!("
0:
ldrexh r0, [$1]
cmp r0, #0
itt ne
strexhne r0, $0, [$1]
cmpne r0, #1
beq 0b
" :
: "r"(self), "r"(address as *mut Self)
: "r0", "cc"
: "volatile"
);
}
}
}
impl Integer for u32 {
fn write(self, address: usize) {
#[cfg(feature = "std")]
return unimplemented!();
unsafe {
asm!("
0:
ldrex r0, [$1]
cmp r0, #0
itt ne
strexne r0, $0, [$1]
cmpne r0, #1
beq 0b
" :
: "r"(self), "r"(address as *mut Self)
: "r0", "cc"
: "volatile"
);
}
}
}