use core::mem::size_of;
use core::ptr::{read_volatile, write_volatile};
#[crate::ram(uninitialized)]
static mut EXTERNAL_RAM_SIZE: core::mem::MaybeUninit<Option<usize>> =
core::mem::MaybeUninit::uninit();
const CACHE_LINE_SIZE: usize = 32;
const NR_CACHE_LINES: usize = 1024;
const RAM_STEPS: usize = 8;
extern "C" {
static mut _external_bss_start: u32;
static mut _external_bss_end: u32;
static _external_ram_start: u32;
static _external_ram_end: u32;
static mut _external_heap_start: u32;
}
pub fn get_size() -> usize {
unsafe { EXTERNAL_RAM_SIZE.assume_init().unwrap() }
}
pub(super) unsafe fn init() {
EXTERNAL_RAM_SIZE = core::mem::MaybeUninit::new(Some(calculate_external_ram_size()));
if &_external_heap_start as *const u32 > (&_external_ram_start as *const u32).add(get_size()) {
panic!("External RAM too small for data");
}
xtensa_lx_rt::zero_bss(&mut _external_bss_start, &mut _external_bss_end);
}
unsafe fn calculate_external_ram_size() -> usize {
let ram_start_addr: usize = &_external_ram_start as *const u32 as usize;
let ram_end_addr: usize = &_external_ram_end as *const u32 as usize;
let ram: *mut u32 = ram_start_addr as _;
let mut buffer = [0u32; RAM_STEPS];
let step_size = (ram_end_addr - ram_start_addr) / RAM_STEPS / size_of::<u32>();
for i in 0..RAM_STEPS {
buffer[i] = read_volatile(ram.add(i * step_size));
write_volatile(ram.add(i * step_size), 0xdeadbeef + i as u32);
}
for i in (1..=NR_CACHE_LINES).step_by(CACHE_LINE_SIZE) {
let addr = ram.add(i * CACHE_LINE_SIZE / size_of::<u32>());
write_volatile(addr, read_volatile(addr));
}
let mut ram_size = 0;
let mut end_found = false;
for i in 0..RAM_STEPS {
if !end_found && read_volatile(ram.add(i * step_size)) == 0xdeadbeef + i as u32 {
ram_size += step_size;
} else {
end_found = true;
}
write_volatile(ram.add(i * step_size), buffer[i]);
}
ram_size * size_of::<u32>()
}