Start a basic allocator with a super simple test

This commit is contained in:
Gwilym Kuiper 2021-08-16 21:02:55 +01:00
parent 1c07268f11
commit 7062610aba
2 changed files with 81 additions and 1 deletions

76
agb/src/agb_alloc/mod.rs Normal file
View file

@ -0,0 +1,76 @@
use core::alloc::{GlobalAlloc, Layout};
use super::interrupt::Mutex;
extern "C" {
static __ewram_data_end: usize;
}
fn get_data_end() -> usize {
// TODO: This seems completely wrong, but without the &, rust generates
// a double dereference :/. Maybe a bug in nightly?
(unsafe { &__ewram_data_end }) as *const _ as usize
}
struct BumpAllocator {
current_ptr: Mutex<*mut u8>,
}
impl BumpAllocator {
fn alloc_safe(&self, layout: Layout) -> *mut u8 {
let mut current_ptr = self.current_ptr.lock();
let mut ptr = *current_ptr as usize;
if ptr == 0 {
ptr = get_data_end();
}
let alignment_bitmask = layout.align() - 1;
let fixup = ptr & alignment_bitmask;
let amount_to_add = layout.align() - fixup;
let resulting_ptr = ptr + amount_to_add;
*current_ptr = (resulting_ptr + layout.size()) as *mut _;
resulting_ptr as *mut _
}
}
unsafe impl GlobalAlloc for BumpAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.alloc_safe(layout)
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
}
#[alloc_error_handler]
fn alloc_error(layout: Layout) -> ! {
panic!(
"Failed to allocate size {} with alignment {}",
layout.size(),
layout.align()
);
}
#[global_allocator]
static GLOBAL_ALLOC: BumpAllocator = BumpAllocator {
current_ptr: Mutex::new(core::ptr::null_mut()),
};
#[cfg(test)]
mod test {
use alloc::boxed::Box;
#[test_case]
fn test_box(_gba: &mut crate::Gba) {
let first_box = Box::new(1);
let second_box = Box::new(2);
assert!(&*first_box as *const _ < &*second_box as *const _);
assert_eq!(*first_box, 1);
assert_eq!(*second_box, 2);
}
}

View file

@ -4,15 +4,17 @@
#![feature(asm)] #![feature(asm)]
#![deny(clippy::all)] #![deny(clippy::all)]
#![feature(custom_test_frameworks)] #![feature(custom_test_frameworks)]
#![feature(alloc_error_handler)]
#![test_runner(crate::test_runner)] #![test_runner(crate::test_runner)]
#![reexport_test_harness_main = "test_main"] #![reexport_test_harness_main = "test_main"]
//! # agb //! # agb
//! `agb` is a library for making games on the Game Boy Advance using the Rust //! `agb` is a library for making games on the Game Boy Advance using the Rust
//! programming language. It attempts to be a high level abstraction over the //! programming language. It attempts to be a high level abstraction over the
//! internal workings of the Game Boy Advance whilst still being high //! internal workings of the Game Boy Advance whilst still being high
//! performance and memory efficient. //! performance and memory efficient.
extern crate alloc;
/// Implements everything relating to things that are displayed on screen. /// Implements everything relating to things that are displayed on screen.
pub mod display; pub mod display;
/// Button inputs to the system. /// Button inputs to the system.
@ -32,6 +34,8 @@ pub mod mgba;
pub mod number; pub mod number;
mod single; mod single;
mod agb_alloc;
/// System BIOS calls / syscalls. /// System BIOS calls / syscalls.
pub mod syscall; pub mod syscall;