mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-11 09:31:34 +11:00
Merge pull request #262 from corwinkuiper/allocator-trait
implement allocator api so we can allocate to (ew/iw)ram
This commit is contained in:
commit
cc17d4e78d
|
@ -1,5 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(allocator_api)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
@ -8,7 +9,11 @@ use alloc::boxed::Box;
|
||||||
#[agb::entry]
|
#[agb::entry]
|
||||||
fn main(_gba: agb::Gba) -> ! {
|
fn main(_gba: agb::Gba) -> ! {
|
||||||
loop {
|
loop {
|
||||||
|
let a = Box::new_in(1, agb::EWRAM_ALLOC);
|
||||||
let b = Box::new(1);
|
let b = Box::new(1);
|
||||||
agb::println!("dynamic allocation made to {:?}", &*b as *const _);
|
let c = Box::new_in(3, agb::IWRAM_ALLOC);
|
||||||
|
agb::println!("ewram allocation made to {:?}", &*a as *const _);
|
||||||
|
agb::println!("global allocation made to {:?}", &*b as *const _);
|
||||||
|
agb::println!("iwram allocation made to {:?}", &*c as *const _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -63,6 +63,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//! the linked list in order of pointer. Blocks are then merged after every
|
//! the linked list in order of pointer. Blocks are then merged after every
|
||||||
//! free.
|
//! free.
|
||||||
|
|
||||||
use core::alloc::{GlobalAlloc, Layout};
|
use core::alloc::{Allocator, GlobalAlloc, Layout};
|
||||||
|
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
@ -43,13 +43,13 @@ struct BlockAllocatorState {
|
||||||
first_free_block: Option<SendNonNull<Block>>,
|
first_free_block: Option<SendNonNull<Block>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct BlockAllocator {
|
pub struct BlockAllocator {
|
||||||
inner_allocator: BumpAllocator,
|
inner_allocator: BumpAllocator,
|
||||||
state: Mutex<RefCell<BlockAllocatorState>>,
|
state: Mutex<RefCell<BlockAllocatorState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockAllocator {
|
impl BlockAllocator {
|
||||||
pub const unsafe fn new(start: StartEnd) -> Self {
|
pub(crate) const unsafe fn new(start: StartEnd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner_allocator: BumpAllocator::new(start),
|
inner_allocator: BumpAllocator::new(start),
|
||||||
state: Mutex::new(RefCell::new(BlockAllocatorState {
|
state: Mutex::new(RefCell::new(BlockAllocatorState {
|
||||||
|
@ -216,3 +216,21 @@ unsafe impl GlobalAlloc for BlockAllocator {
|
||||||
self.dealloc(ptr, layout);
|
self.dealloc(ptr, layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Allocator for BlockAllocator {
|
||||||
|
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
|
||||||
|
match unsafe { self.alloc(layout) } {
|
||||||
|
None => Err(core::alloc::AllocError),
|
||||||
|
Some(p) => Ok(unsafe {
|
||||||
|
NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
|
||||||
|
p.as_ptr(),
|
||||||
|
layout.size(),
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
|
||||||
|
self.dealloc(ptr.as_ptr(), layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ impl<T> DerefMut for SendNonNull<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const EWRAM_END: usize = 0x0204_0000;
|
const EWRAM_END: usize = 0x0204_0000;
|
||||||
|
const IWRAM_END: usize = 0x0300_8000;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static GLOBAL_ALLOC: BlockAllocator = unsafe {
|
static GLOBAL_ALLOC: BlockAllocator = unsafe {
|
||||||
|
@ -42,8 +43,59 @@ static GLOBAL_ALLOC: BlockAllocator = unsafe {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This is the allocator for the External Working Ram. This is currently
|
||||||
|
/// equivalent to the Global Allocator (where things are allocated if no allocator is provided). This implements the allocator trait, so
|
||||||
|
/// is meant to be used in specifying where certain structures should be
|
||||||
|
/// allocated.
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// #![feature(allocator_api)]
|
||||||
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # use agb::EWRAM_ALLOC;
|
||||||
|
/// # extern crate alloc;
|
||||||
|
/// # use alloc::vec::Vec;
|
||||||
|
/// # fn foo(gba: &mut agb::Gba) {
|
||||||
|
/// let mut v = Vec::new_in(EWRAM_ALLOC);
|
||||||
|
/// v.push("hello, world");
|
||||||
|
/// assert!(
|
||||||
|
/// (0x0200_0000..0x0204_0000).contains(&(v.as_ptr() as usize)),
|
||||||
|
/// "the address of the vector is inside ewram"
|
||||||
|
/// );
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub static EWRAM_ALLOC: &BlockAllocator = &GLOBAL_ALLOC;
|
||||||
|
|
||||||
|
/// This is the allocator for the Internal Working Ram. This implements the
|
||||||
|
/// allocator trait, so is meant to be used in specifying where certain
|
||||||
|
/// structures should be allocated.
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// #![feature(allocator_api)]
|
||||||
|
/// # #![no_std]
|
||||||
|
/// # #![no_main]
|
||||||
|
/// # use agb::IWRAM_ALLOC;
|
||||||
|
/// # extern crate alloc;
|
||||||
|
/// # use alloc::vec::Vec;
|
||||||
|
/// # fn foo(gba: &mut agb::Gba) {
|
||||||
|
/// let mut v = Vec::new_in(IWRAM_ALLOC);
|
||||||
|
/// v.push("hello, world");
|
||||||
|
/// assert!(
|
||||||
|
/// (0x0300_0000..0x0300_8000).contains(&(v.as_ptr() as usize)),
|
||||||
|
/// "the address of the vector is inside iwram"
|
||||||
|
/// );
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub static IWRAM_ALLOC: &BlockAllocator = &__IWRAM_ALLOC;
|
||||||
|
static __IWRAM_ALLOC: BlockAllocator = unsafe {
|
||||||
|
BlockAllocator::new(StartEnd {
|
||||||
|
start: iwram_data_end,
|
||||||
|
end: || IWRAM_END,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(any(test, feature = "testing"))]
|
#[cfg(any(test, feature = "testing"))]
|
||||||
pub unsafe fn number_of_blocks() -> u32 {
|
pub(crate) unsafe fn number_of_blocks() -> u32 {
|
||||||
GLOBAL_ALLOC.number_of_blocks()
|
GLOBAL_ALLOC.number_of_blocks()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +108,16 @@ fn alloc_error(layout: Layout) -> ! {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iwram_data_end() -> usize {
|
||||||
|
extern "C" {
|
||||||
|
static __iwram_end: usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This seems completely wrong, but without the &, rust generates
|
||||||
|
// a double dereference :/. Maybe a bug in nightly?
|
||||||
|
(unsafe { &__iwram_end }) as *const _ as usize
|
||||||
|
}
|
||||||
|
|
||||||
fn data_end() -> usize {
|
fn data_end() -> usize {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static __ewram_data_end: usize;
|
static __ewram_data_end: usize;
|
||||||
|
@ -150,4 +212,28 @@ mod test {
|
||||||
"data end should be smaller than 0x0203_0000"
|
"data end should be smaller than 0x0203_0000"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn should_return_data_end_somewhere_in_iwram(_gba: &mut crate::Gba) {
|
||||||
|
let data_end = iwram_data_end();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
(0x0300_0000..0x0300_8000).contains(&data_end),
|
||||||
|
"iwram data end should be in iwram, instead was {}",
|
||||||
|
data_end
|
||||||
|
);
|
||||||
|
crate::println!("data end was {:#010X}", data_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn allocate_to_iwram_works(_gba: &mut crate::Gba) {
|
||||||
|
let a = Box::new_in(1, IWRAM_ALLOC);
|
||||||
|
let p = &*a as *const i32;
|
||||||
|
let addr = p as usize;
|
||||||
|
assert!(
|
||||||
|
(0x0300_0000..0x0300_8000).contains(&addr),
|
||||||
|
"address of allocation should be within iwram, instead at {:?}",
|
||||||
|
p
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
reexport_test_harness_main = "test_main"
|
reexport_test_harness_main = "test_main"
|
||||||
)]
|
)]
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
|
#![feature(allocator_api)]
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
#![deny(clippy::must_use_candidate)]
|
#![deny(clippy::must_use_candidate)]
|
||||||
#![deny(clippy::trivially_copy_pass_by_ref)]
|
#![deny(clippy::trivially_copy_pass_by_ref)]
|
||||||
|
@ -189,6 +190,8 @@ pub mod syscall;
|
||||||
/// Interactions with the internal timers
|
/// Interactions with the internal timers
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
||||||
|
pub use {agb_alloc::EWRAM_ALLOC, agb_alloc::IWRAM_ALLOC};
|
||||||
|
|
||||||
#[cfg(not(any(test, feature = "testing")))]
|
#[cfg(not(any(test, feature = "testing")))]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
#[allow(unused_must_use)]
|
#[allow(unused_must_use)]
|
||||||
|
|
|
@ -65,6 +65,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -63,6 +63,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -65,6 +65,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -63,6 +63,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -65,6 +65,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -65,6 +65,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -63,6 +63,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -65,6 +65,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
|
@ -63,6 +63,7 @@ SECTIONS {
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss .bss.*);
|
*(.bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
__iwram_end = ABSOLUTE(.);
|
||||||
} > iwram
|
} > iwram
|
||||||
|
|
||||||
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
__iwram_rom_length_bytes = __iwram_data_end - __iwram_data_start;
|
||||||
|
|
Loading…
Reference in a new issue