#![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"
);
}
}
}