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 print: "./lib/io/print.dsa";
|
||||||
include fib: "./lib/maths/fib.dsa";
|
include alloc: "./lib/memory/block_alloc.dsa";
|
||||||
|
|
||||||
fn main() -> u32 {
|
fn main() -> u32 {
|
||||||
let x: u32 = 6;
|
let allocator: u32 = alloc::init(64, 32);
|
||||||
|
|
||||||
let y: u32 = fib::fib_n(x);
|
print::print_hex_word(allocator);
|
||||||
print::print_num(y);
|
|
||||||
|
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