diff --git a/resources/dsa/lib/memory/block_alloc.dsa b/resources/dsa/lib/memory/block_alloc.dsa new file mode 100644 index 0000000..69eaa7e --- /dev/null +++ b/resources/dsa/lib/memory/block_alloc.dsa @@ -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 diff --git a/resources/dsa/main.dsc b/resources/dsa/main.dsc index 0e0b119..72cfd71 100644 --- a/resources/dsa/main.dsc +++ b/resources/dsa/main.dsc @@ -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; } \ No newline at end of file