block allocator implementation and example
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
// block_alloc.dsa
|
||||
// Fixed-size block allocator
|
||||
//
|
||||
// Memory layout:
|
||||
// [base + 0]: free list head pointer (pointer to first free block, or 0 if none)
|
||||
// [base + 4]: block size
|
||||
// [base + 8]: total blocks
|
||||
// [base + 12]: base address of block pool
|
||||
// [base + 16+]: block pool (each block starts with a 4-byte next pointer)
|
||||
//
|
||||
// Usage:
|
||||
// include block_alloc "./lib/memory/block_alloc.dsa"
|
||||
//
|
||||
// For init:
|
||||
// push num_blocks (e.g., 32)
|
||||
// push block_size (e.g., 64 bytes)
|
||||
// call block_alloc::init
|
||||
// pop block_size
|
||||
// pop num_blocks
|
||||
// ; result in spr+8 (allocator handle)
|
||||
//
|
||||
// For alloc:
|
||||
// push allocator_handle
|
||||
// call block_alloc::alloc
|
||||
// pop allocator_handle
|
||||
// ; result in spr+8 (pointer to block, or 0 if out of memory)
|
||||
//
|
||||
// For free:
|
||||
// push block_pointer
|
||||
// push allocator_handle
|
||||
// call block_alloc::free
|
||||
// pop allocator_handle
|
||||
// pop block_pointer
|
||||
|
||||
dw heap_start: 0x30000 // Start of our heap area
|
||||
|
||||
// Initialize the allocator
|
||||
// Args: block_size, num_blocks
|
||||
// Returns: allocator handle (pointer to metadata)
|
||||
init:
|
||||
push bpr
|
||||
mov spr, bpr
|
||||
|
||||
ldw bpr, rg0, 8 // block_size
|
||||
ldw bpr, rg1, 12 // num_blocks
|
||||
|
||||
// Allocate metadata (16 bytes) + pool space
|
||||
ldw heap_start, rg2 // base address for this allocator
|
||||
mov rg2, rg3 // save base in rg3
|
||||
|
||||
// Calculate total size needed: 16 + (block_size * num_blocks)
|
||||
// We'll use a simple multiplication by repeated addition
|
||||
mov rg0, rg4 // block_size to rg4
|
||||
mov rg1, rg5 // num_blocks to rg5
|
||||
lli 0, acc // accumulator for multiplication
|
||||
|
||||
_multiply_loop:
|
||||
cmp rg5, zero
|
||||
jeq _multiply_done
|
||||
add acc, rg4, acc
|
||||
dec rg5
|
||||
jmp _multiply_loop
|
||||
|
||||
_multiply_done:
|
||||
// acc now contains block_size * num_blocks
|
||||
addi acc, 16 // add metadata size
|
||||
|
||||
// Update heap_start for next allocation
|
||||
add rg2, acc, acc
|
||||
stw acc, heap_start
|
||||
|
||||
// Now set up metadata at rg3 (base)
|
||||
// [base + 0]: free list head (will point to first block)
|
||||
// [base + 4]: block_size
|
||||
// [base + 8]: total blocks
|
||||
// [base + 12]: pool base address
|
||||
|
||||
addi rg3, 16, rg6 // rg6 = pool base
|
||||
|
||||
stw rg6, rg3 // store pool base as free list head initially
|
||||
stw rg0, rg3, 4 // store block_size
|
||||
stw rg1, rg3, 8 // store total blocks
|
||||
stw rg6, rg3, 12 // store pool base address
|
||||
|
||||
// Now initialize the free list
|
||||
// Each block's first 4 bytes point to the next block
|
||||
// rg6 = current block pointer
|
||||
// rg0 = block_size
|
||||
// rg1 = num_blocks (counter)
|
||||
|
||||
dec rg1 // we'll count down from num_blocks-1
|
||||
|
||||
_init_loop:
|
||||
cmp rg1, zero
|
||||
jeq _init_loop_done
|
||||
|
||||
// Calculate next block address: current + block_size
|
||||
add rg6, rg0, rg7 // rg7 = next block address
|
||||
|
||||
// Store next pointer at current block
|
||||
stw rg7, rg6
|
||||
|
||||
// Move to next block
|
||||
mov rg7, rg6
|
||||
dec rg1
|
||||
jmp _init_loop
|
||||
|
||||
_init_loop_done:
|
||||
// Last block points to null (0)
|
||||
lli 0, acc
|
||||
stw acc, rg6
|
||||
|
||||
// Return allocator handle (base address - 16 to get back to metadata start)
|
||||
stw rg3, bpr, 8
|
||||
|
||||
mov bpr, spr
|
||||
pop bpr
|
||||
return
|
||||
|
||||
|
||||
// Allocate a block
|
||||
// Args: allocator_handle
|
||||
// Returns: pointer to block (or 0 if out of memory)
|
||||
alloc:
|
||||
push bpr
|
||||
mov spr, bpr
|
||||
|
||||
ldw bpr, rg0, 8 // allocator handle (metadata base)
|
||||
|
||||
// Load free list head
|
||||
ldw rg0, rg1 // rg1 = free list head
|
||||
|
||||
// Check if free list is empty
|
||||
cmp rg1, zero
|
||||
jeq _alloc_fail
|
||||
|
||||
// Free list is not empty, pop the first block
|
||||
// Load the next pointer from the block we're allocating
|
||||
ldw rg1, rg2 // rg2 = next free block
|
||||
|
||||
// Update free list head to point to next block
|
||||
stw rg2, rg0
|
||||
|
||||
// Return the allocated block (rg1)
|
||||
stw rg1, bpr, 8
|
||||
jmp _alloc_done
|
||||
|
||||
_alloc_fail:
|
||||
// No free blocks, return 0
|
||||
lli 0, acc
|
||||
stw acc, bpr, 8
|
||||
|
||||
_alloc_done:
|
||||
mov bpr, spr
|
||||
pop bpr
|
||||
return
|
||||
|
||||
|
||||
// Free a block
|
||||
// Args: allocator_handle, block_pointer
|
||||
// Returns: nothing (but could return error code if block is invalid)
|
||||
free:
|
||||
push bpr
|
||||
mov spr, bpr
|
||||
|
||||
ldw bpr, rg0, 8 // allocator handle
|
||||
ldw bpr, rg6, 12 // pointer to the block pointer to free
|
||||
ldw rg6, rg1 // rg1 = block pointer to free
|
||||
|
||||
// Load current free list head
|
||||
ldw rg0, rg2 // rg2 = current head
|
||||
|
||||
// Set the freed block's next pointer to current head
|
||||
stw rg2, rg1
|
||||
|
||||
// Update free list head to point to freed block
|
||||
stw rg1, rg0
|
||||
|
||||
// Update the freed block's previous pointer to NULL
|
||||
lli 0, rg1
|
||||
stw rg1, rg6
|
||||
|
||||
mov bpr, spr
|
||||
pop bpr
|
||||
return
|
||||
|
||||
|
||||
// Debug function: get stats
|
||||
// Args: allocator_handle
|
||||
// Returns: nothing (but could populate a stats structure)
|
||||
get_stats:
|
||||
push bpr
|
||||
mov spr, bpr
|
||||
|
||||
ldw bpr, rg0, 8 // allocator handle
|
||||
|
||||
// Count free blocks by traversing the free list
|
||||
ldw rg0, rg1 // rg1 = free list head
|
||||
lli 0, rg2 // rg2 = counter
|
||||
|
||||
count_loop:
|
||||
cmp rg1, zero
|
||||
jeq count_done
|
||||
|
||||
inc rg2
|
||||
ldw rg1, rg1 // move to next block
|
||||
jmp count_loop
|
||||
|
||||
count_done:
|
||||
// rg2 now contains number of free blocks
|
||||
// Could store this somewhere or return it
|
||||
stw rg2, bpr, 8
|
||||
|
||||
mov bpr, spr
|
||||
pop bpr
|
||||
return
|
||||
+32
-4
@@ -1,9 +1,37 @@
|
||||
include print: "./lib/io/print.dsa";
|
||||
include fib: "./lib/maths/fib.dsa";
|
||||
include alloc: "./lib/memory/block_alloc.dsa";
|
||||
|
||||
fn main() -> u32 {
|
||||
let x: u32 = 6;
|
||||
let allocator: u32 = alloc::init(64, 32);
|
||||
|
||||
let y: u32 = fib::fib_n(x);
|
||||
print::print_num(y);
|
||||
print::print_hex_word(allocator);
|
||||
|
||||
print::print_newline();
|
||||
|
||||
let ptr: u32 = alloc::alloc(allocator);
|
||||
print::print_hex_word(ptr);
|
||||
*ptr = 200;
|
||||
|
||||
print::print_newline();
|
||||
|
||||
let p2: u32 = alloc::alloc(allocator);
|
||||
print::print_hex_word(p2);
|
||||
print::print_newline();
|
||||
print::print_num(*ptr);
|
||||
|
||||
alloc::free(allocator, &ptr);
|
||||
let ptr3: u32 = alloc::alloc(allocator);
|
||||
|
||||
print::print_newline();
|
||||
|
||||
print::print_hex_word(ptr3);
|
||||
|
||||
print::print_newline();
|
||||
print::print_hex_word(ptr);
|
||||
|
||||
if ptr == 0 {
|
||||
print::print("successful free of ptr");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user