blob: fc2d8cbb7f5fa6db99b5ca715557e2753dbb6fab [file] [edit]
// Licensed under the Apache-2.0 license
use crate::{RealMmio, RealMmioMut, Uint, UintType};
#[inline(always)]
pub unsafe fn read_volatile_array<const LEN: usize, T: Uint>(dst: *mut T, src: *mut T) {
match (T::TYPE, LEN) {
(UintType::U32, 12) => copy_12words(dst as *mut u32, src as *const u32),
(UintType::U32, 16) => copy_16words(dst as *mut u32, src as *const u32),
_ => super::read_volatile_slice(&RealMmio::default(), dst, src, LEN),
}
}
#[inline(always)]
pub unsafe fn write_volatile_array<const LEN: usize, T: Uint>(dst: *mut T, src: *const [T; LEN]) {
match (T::TYPE, LEN) {
(UintType::U32, 12) => copy_12words(dst as *mut u32, src as *const u32),
(UintType::U32, 16) => copy_16words(dst as *mut u32, src as *const u32),
_ => super::write_volatile_slice(&RealMmioMut::default(), dst, &*src),
}
}
#[inline(never)]
unsafe fn copy_16words(dest: *mut u32, val: *const u32) {
core::arch::asm!(
"lw {tmp0}, 0({s})",
"lw {tmp1}, 4({s})",
"lw {tmp2}, 8({s})",
"lw {tmp3}, 12({s})",
"sw {tmp0}, 0({d})",
"sw {tmp1}, 4({d})",
"sw {tmp2}, 8({d})",
"sw {tmp3}, 12({d})",
"lw {tmp0}, 16({s})",
"lw {tmp1}, 20({s})",
"lw {tmp2}, 24({s})",
"lw {tmp3}, 28({s})",
"sw {tmp0}, 16({d})",
"sw {tmp1}, 20({d})",
"sw {tmp2}, 24({d})",
"sw {tmp3}, 28({d})",
"lw {tmp0}, 32({s})",
"lw {tmp1}, 36({s})",
"lw {tmp2}, 40({s})",
"lw {tmp3}, 44({s})",
"sw {tmp0}, 32({d})",
"sw {tmp1}, 36({d})",
"sw {tmp2}, 40({d})",
"sw {tmp3}, 44({d})",
"lw {tmp0}, 48({s})",
"lw {tmp1}, 52({s})",
"lw {tmp2}, 56({s})",
"lw {tmp3}, 60({s})",
"sw {tmp0}, 48({d})",
"sw {tmp1}, 52({d})",
"sw {tmp2}, 56({d})",
"sw {tmp3}, 60({d})",
s = in(reg) val,
d = in(reg) dest,
tmp0 = out(reg) _,
tmp1 = out(reg) _,
tmp2 = out(reg) _,
tmp3 = out(reg) _,
);
}
#[inline(never)]
unsafe fn copy_12words(dest: *mut u32, val: *const u32) {
core::arch::asm!(
"lw {tmp0}, 0({s})",
"lw {tmp1}, 4({s})",
"lw {tmp2}, 8({s})",
"lw {tmp3}, 12({s})",
"sw {tmp0}, 0({d})",
"sw {tmp1}, 4({d})",
"sw {tmp2}, 8({d})",
"sw {tmp3}, 12({d})",
"lw {tmp0}, 16({s})",
"lw {tmp1}, 20({s})",
"lw {tmp2}, 24({s})",
"lw {tmp3}, 28({s})",
"sw {tmp0}, 16({d})",
"sw {tmp1}, 20({d})",
"sw {tmp2}, 24({d})",
"sw {tmp3}, 28({d})",
"lw {tmp0}, 32({s})",
"lw {tmp1}, 36({s})",
"lw {tmp2}, 40({s})",
"lw {tmp3}, 44({s})",
"sw {tmp0}, 32({d})",
"sw {tmp1}, 36({d})",
"sw {tmp2}, 40({d})",
"sw {tmp3}, 44({d})",
s = in(reg) val,
d = in(reg) dest,
tmp0 = out(reg) _,
tmp1 = out(reg) _,
tmp2 = out(reg) _,
tmp3 = out(reg) _,
);
}
#[cfg(test)]
mod test {
use super::*;
// To test, run "cargo install cross", then "cross test --target riscv64gc-unknown-linux-gnu"
#[test]
fn test_read_volatile_array_12_u32() {
let mut src: [u32; 12] = [
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2,
];
let mut dest = [0x5555_5555_u32; 14];
unsafe {
read_volatile_array::<12, u32>(dest.as_mut_ptr().add(1), src.as_mut_ptr() as *mut u32)
};
assert_eq!(
dest,
[
0x55555555, 0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23,
0x27fc0139, 0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0x55555555
]
);
assert_eq!(
src,
[
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2,
],
);
}
#[test]
fn test_read_volatile_array_12_u8() {
let mut src: [u8; 12] = [
0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f,
];
let mut dest = [0x55_u8; 14];
unsafe {
read_volatile_array::<12, u8>(dest.as_mut_ptr().add(1), src.as_mut_ptr() as *mut u8)
};
assert_eq!(
dest,
[0x55, 0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f, 0x55,]
);
assert_eq!(
src,
[0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f,]
);
}
#[test]
fn test_read_volatile_array_16_u32() {
let mut src: [u32; 16] = [
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4, 0x44e612a1,
0x46690857, 0x3bfe2428,
];
let mut dest = [0x5555_5555; 18];
unsafe {
read_volatile_array::<16, u32>(dest.as_mut_ptr().add(1), src.as_mut_ptr() as *mut u32)
};
assert_eq!(
dest,
[
0x55555555, 0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23,
0x27fc0139, 0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4,
0x44e612a1, 0x46690857, 0x3bfe2428, 0x55555555
]
);
assert_eq!(
src,
[
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4, 0x44e612a1,
0x46690857, 0x3bfe2428,
]
);
}
#[test]
fn test_read_volatile_array_16_u8() {
let mut src: [u8; 16] = [
0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f, 0xc4, 0x4c,
0x6a, 0x28,
];
let mut dest = [0x55_u8; 18];
unsafe {
read_volatile_array::<16, u8>(dest.as_mut_ptr().add(1), src.as_mut_ptr() as *mut u8)
};
assert_eq!(
dest,
[
0x55, 0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f, 0xc4,
0x4c, 0x6a, 0x28, 0x55,
]
);
assert_eq!(
src,
[
0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f, 0xc4, 0x4c,
0x6a, 0x28,
]
);
}
#[test]
fn test_read_volatile_array_15_u32() {
let mut src: [u32; 15] = [
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4, 0x44e612a1,
0x46690857,
];
let mut dest = [0x5555_5555; 17];
unsafe {
read_volatile_array::<15, u32>(dest.as_mut_ptr().add(1), src.as_mut_ptr() as *mut u32)
};
assert_eq!(
dest,
[
0x55555555, 0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23,
0x27fc0139, 0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4,
0x44e612a1, 0x46690857, 0x55555555,
]
);
assert_eq!(
src,
[
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4, 0x44e612a1,
0x46690857,
]
);
}
#[test]
fn test_write_volatile_array_12_u32() {
let src: [u32; 12] = [
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2,
];
let mut dest = [0x5555_5555_u32; 14];
unsafe { write_volatile_array::<12, u32>(dest.as_mut_ptr().add(1), &src) };
assert_eq!(
dest,
[
0x55555555, 0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23,
0x27fc0139, 0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0x55555555
]
)
}
#[test]
fn test_write_volatile_array_12_u8() {
let src: [u8; 12] = [
0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f,
];
let mut dest = [0x55_u8; 14];
unsafe { write_volatile_array::<12, u8>(dest.as_mut_ptr().add(1), &src) };
assert_eq!(
dest,
[0x55, 0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f, 0x55,]
)
}
#[test]
fn test_write_volatile_array_16_u32() {
let src = [
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4, 0x44e612a1,
0x46690857, 0x3bfe2428,
];
let mut dest = [0x5555_5555; 18];
unsafe { write_volatile_array::<16, u32>(dest.as_mut_ptr().add(1), &src) };
assert_eq!(
dest,
[
0x55555555, 0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23,
0x27fc0139, 0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4,
0x44e612a1, 0x46690857, 0x3bfe2428, 0x55555555
]
)
}
#[test]
fn test_write_volatile_array_16_u8() {
let src: [u8; 16] = [
0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f, 0xc4, 0x4c,
0x6a, 0x28,
];
let mut dest = [0x55_u8; 18];
unsafe { write_volatile_array::<16, u8>(dest.as_mut_ptr().add(1), &src) };
assert_eq!(
dest,
[
0x55, 0xe3, 0xc3, 0x63, 0xe7, 0x00, 0x87, 0x50, 0xdf, 0xda, 0xff, 0x76, 0x7f, 0xc4,
0x4c, 0x6a, 0x28, 0x55,
]
)
}
#[test]
fn test_write_volatile_array_15_u32() {
let src: [u32; 15] = [
0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23, 0x27fc0139,
0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4, 0x44e612a1,
0x46690857,
];
let mut dest = [0x5555_5555; 17];
unsafe { write_volatile_array::<15, u32>(dest.as_mut_ptr().add(1), &src) };
assert_eq!(
dest,
[
0x55555555, 0xcf3ae93b, 0x3a5f6465, 0x0bbcb2c1, 0xad82403e, 0xdc0454aa, 0x038b0e23,
0x27fc0139, 0x4fd1b300, 0x627ec17f, 0x9f58d0fc, 0x05f7b36c, 0x588179e2, 0xb039d6b4,
0x44e612a1, 0x46690857, 0x55555555,
]
)
}
}