use core::mem::size_of;
#[cfg(not(feature = "testing"))]
use crate::phys::addrs::OCRAM2;
pub type ScopeUnit = u32;
const MEMORY_MINIMUM: u32 = 0x0_0FFC;
const MEMORY_MAXIMUM: u32 = 0x7_FFFF - 0x0_0FFC; const MEMORY_BEGIN_OFFSET: u32 = MEMORY_MINIMUM; pub static mut MEMORY_SCOPE: ScopeUnit = 0x1337; static mut MEMORY_OFFSET: u32 = MEMORY_BEGIN_OFFSET;
static mut MEMORY_PAGES: Option<*mut Mempage> = None;
static mut IS_OVERRUN: bool = false;
#[repr(C)]
pub struct Mempage {
pub size: usize,
pub scope: ScopeUnit,
pub used: bool,
pub next: Option<*mut Mempage>,
pub ptr: *mut u32,
}
#[cfg(not(feature = "testing"))]
impl Mempage {
pub const fn new(size: usize, ptr: *mut u32) -> Self {
return Mempage {
size: size,
used: true,
ptr: ptr,
scope: 0x1337,
next: None,
};
}
pub fn ref_count() -> usize {
let mut count = 0;
unsafe {
let mut ptr = MEMORY_PAGES;
while ptr.is_some() {
let node = ptr.unwrap();
if (*node).used == true {
count += 1;
}
ptr = (*node).next;
}
}
return count;
}
pub fn reclaim_fast(bytes: usize) -> *mut u32 {
unsafe {
let mut ptr = MEMORY_PAGES;
while ptr.is_some() {
let node = ptr.unwrap();
if (*node).size >= bytes && (*node).used == false {
(*node).used = true;
(*node).scope = MEMORY_SCOPE;
return node as *mut u32;
}
ptr = (*node).next;
}
}
loop {
crate::err(crate::PanicType::Memfault);
}
}
pub fn free_scope(scope: ScopeUnit) {
unsafe {
let mut ptr = MEMORY_PAGES;
while ptr.is_some() {
let node = ptr.unwrap();
if (*node).scope == scope && (*node).used == true {
Mempage::free((*node).ptr as u32);
}
ptr = (*node).next;
}
}
}
pub fn free(ptr: u32) {
let bytes = size_of::<Mempage>() as u32;
let addr = (ptr - bytes) as *mut Mempage;
unsafe {
(*addr).used = false;
}
}
pub fn add_page<T>(bytes: usize) -> *mut T {
let page_bytes = size_of::<Mempage>();
let mut total_bytes = page_bytes + bytes;
while total_bytes % 4 != 0 {
total_bytes += 1;
}
let next_page = alloc_bytes(total_bytes) as *mut Mempage;
let item_ptr = ((next_page as u32) + page_bytes as u32) as *mut T;
if is_overrun() {
return item_ptr;
}
unsafe {
(*next_page) = Mempage {
size: total_bytes,
ptr: item_ptr as *mut u32,
used: true,
scope: MEMORY_SCOPE,
next: None,
};
match MEMORY_PAGES {
None => {
MEMORY_PAGES = Some(next_page);
}
Some(head) => {
(*next_page).next = Some(head);
MEMORY_PAGES = Some(next_page);
}
}
}
return item_ptr;
}
}
pub fn is_overrun() -> bool {
return unsafe { IS_OVERRUN };
}
#[cfg(not(feature = "testing"))]
pub fn memtest() {
for addr in MEMORY_BEGIN_OFFSET..MEMORY_MAXIMUM / 4 {
unsafe {
let ptr = (OCRAM2 + addr * 4) as *mut u32;
*ptr = 0;
}
}
}
#[cfg(not(feature = "testing"))]
pub fn zero(addr: u32, bytes: u32) {
for byte in 0..bytes {
unsafe {
let ptr = (addr + byte) as *mut u8;
*ptr = 0;
}
}
}
#[cfg(not(feature = "testing"))]
pub fn copy(src: u32, dest: u32, len: u32) {
for byte in 0..len {
unsafe {
let src_ptr = (src + byte) as *mut u8;
let dst_ptr = (dest + byte) as *mut u8;
*dst_ptr = *src_ptr;
}
}
}
#[cfg(not(feature = "testing"))]
fn alloc_bytes(bytes: usize) -> *mut u32 {
unsafe {
if MEMORY_OFFSET + bytes as u32 >= MEMORY_MAXIMUM {
IS_OVERRUN = true;
return Mempage::reclaim_fast(bytes);
}
let ptr = (OCRAM2 + MEMORY_OFFSET) as *mut u32;
MEMORY_OFFSET += bytes as u32;
return ptr;
}
}
#[cfg(not(feature = "testing"))]
pub fn alloc<T>() -> *mut T {
let bytes = size_of::<T>();
return Mempage::add_page(bytes);
}
#[cfg(not(feature = "testing"))]
pub fn free<T>(ptr: *mut T) {
let zero_ptr = ptr as u32;
Mempage::free(zero_ptr);
}
#[cfg(not(feature = "testing"))]
#[macro_export]
macro_rules! using {
($x: block) => {
{
let original_scope: ScopeUnit = unsafe { MEMORY_SCOPE.clone() };
let current_scope: ScopeUnit = crate::code_hash();
unsafe { MEMORY_SCOPE = current_scope };
$x
Mempage::free_scope(current_scope);
unsafe { MEMORY_SCOPE = original_scope; }
}
}
}
#[cfg(not(feature = "testing"))]
pub fn ref_count() -> usize {
return Mempage::ref_count();
}
#[cfg(feature = "testing")]
pub fn ref_count() -> usize {
return 0;
}
#[cfg(feature = "testing")]
#[macro_export]
macro_rules! using {
($x: block) => {{
$x
}};
}
#[cfg(feature = "testing")]
pub fn alloc<T>() -> *mut T {
return unsafe { std::alloc::alloc(std::alloc::Layout::new::<T>()) as *mut T };
}
#[cfg(feature = "testing")]
pub fn free<T>(_ptr: *mut T) {
}
#[cfg(feature = "testing")]
pub fn zero(addr: u32, bytes: u32) {}
#[cfg(feature = "testing")]
pub fn copy(src: u32, dest: u32, len: u32) {}