Path: blob/master/yabause/src/dreamcast/sh2rec/sh2rec_mem.c
2 views
/* Copyright 2010 Lawrence Sebald12This file is part of Yabause.34Yabause is free software; you can redistribute it and/or modify5it under the terms of the GNU General Public License as published by6the Free Software Foundation; either version 2 of the License, or7(at your option) any later version.89Yabause is distributed in the hope that it will be useful,10but WITHOUT ANY WARRANTY; without even the implied warranty of11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12GNU General Public License for more details.1314You should have received a copy of the GNU General Public License15along with Yabause; if not, write to the Free Software16Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA17*/1819#include <stdio.h>20#include <stdlib.h>21#include <inttypes.h>2223#include "sh2rec_mem.h"2425typedef struct block_s {26uint8_t *ptr;27int size;28struct block_s *prev;29struct block_s *next;30} sh2rec_mem_block;3132typedef struct usedblock_s {33sh2rec_mem_block base;34sh2rec_mem_block *freespace;35} sh2rec_mem_usedblock;3637typedef struct allocblock_s {38struct allocblock_s *next;39} sh2rec_mem_allocblock;4041static sh2rec_mem_block *freeblocks = NULL;42static sh2rec_mem_usedblock *usedblocks = NULL;43static sh2rec_mem_usedblock *usedblocks_tail = NULL;44static sh2rec_mem_allocblock *allocblocks = NULL;4546static int cur_allocation = 0;4748#define BSSIZE (sizeof(sh2rec_mem_allocblock) + sizeof(sh2rec_mem_block) + \49sizeof(sh2rec_mem_usedblock))5051int sh2rec_mem_init(void) {52sh2rec_mem_block *initblock;53sh2rec_mem_allocblock *allocblock;54uint8_t *block;5556/* Allocate our initial space for storing rec'd instructions in */57block = (uint8_t *)malloc(SH2REC_MEM_INITIAL);5859#ifdef DEBUG60if(!block) {61return -1;62}63#endif6465/* Carve our structures out of the beginning of the block */66allocblock = (sh2rec_mem_allocblock *)block;67initblock = (sh2rec_mem_block *)(block + sizeof(sh2rec_mem_allocblock));68cur_allocation = SH2REC_MEM_INITIAL;6970/* Fill in the rest of the structs */71initblock->size = SH2REC_MEM_INITIAL - sizeof(sh2rec_mem_allocblock) -72sizeof(sh2rec_mem_block);73initblock->prev = NULL;74initblock->next = NULL;7576allocblock->next = NULL;77allocblocks = allocblock;7879/* The whole block is free, so put it in the free list */80freeblocks = initblock;8182return 0;83}8485void sh2rec_mem_shutdown(void) {86sh2rec_mem_allocblock *i, *tmp;8788/* Loop through and free any blocks we allocated */89i = allocblocks;90while(i) {91tmp = i->next;92free(i);93i = tmp;94}9596/* Clean up the stale pointers */97allocblocks = NULL;98freeblocks = NULL;99usedblocks = NULL;100}101102void *sh2rec_mem_alloc(int sz) {103sh2rec_mem_block *i;104sh2rec_mem_usedblock *rv;105sh2rec_mem_allocblock *b;106int szlook = sz + SH2REC_MEM_FUDGE + sizeof(sh2rec_mem_usedblock);107uint8_t *block;108109/* Look for a free block of enough size */110i = freeblocks;111while(i) {112if(i->size >= szlook) {113/* We've found a candidate, so, start working with it */114rv = (sh2rec_mem_usedblock *)i->ptr;115rv->freespace = i;116rv->base.ptr = i->ptr + sizeof(sh2rec_mem_usedblock);117rv->base.size = sz;118rv->base.prev = (sh2rec_mem_block *)usedblocks_tail;119rv->base.next = NULL;120121/* Update the tail */122if(usedblocks_tail) {123usedblocks_tail->base.next = (sh2rec_mem_block *)rv;124}125126usedblocks_tail = rv;127128/* The freeblock is now smaller, so reflect that */129i->size -= sz + sizeof(sh2rec_mem_usedblock);130131return rv;132}133134i = i->next;135}136137/* We didn't find one, so allocate a new block */138block = malloc(SH2REC_MEM_ALLOCSZ);139140#ifdef DEBUG141if(!block) {142return NULL;143}144#endif145146/* Fill in the allocblock */147b = (sh2rec_mem_allocblock *)block;148b->next = allocblocks;149allocblocks = b;150151/* Now, create a freeblock, and work from that */152i = (sh2rec_mem_block *)(block + sizeof(sh2rec_mem_allocblock));153i->ptr = block + BSSIZE + sz;154i->prev = NULL;155i->next = freeblocks;156i->size = SH2REC_MEM_ALLOCSZ - BSSIZE - sz;157freeblocks = i;158159/* Create the usedblock */160rv = (sh2rec_mem_usedblock *)(i->ptr - sz);161rv->freespace = i;162rv->base.ptr = i->ptr;163rv->base.size = sz;164rv->base.prev = (sh2rec_mem_block *)usedblocks_tail;165rv->base.next = NULL;166167/* Update the tail */168if(usedblocks_tail) {169usedblocks_tail->base.next = (sh2rec_mem_block *)rv;170}171172usedblocks_tail = rv;173174/* Keep track of our allocation */175cur_allocation += SH2REC_MEM_ALLOCSZ;176177return rv;178}179180int sh2rec_mem_expand(void *block, int amt) {181sh2rec_mem_usedblock *b = (sh2rec_mem_usedblock *)block;182183/* If the freeblock has space, allow it */184if(b->freespace->size > amt) {185b->freespace->size -= amt;186b->base.size += amt;187b->freespace->ptr += amt;188return 1;189}190191return 0;192}193194void sh2rec_mem_free(void *block) {195sh2rec_mem_usedblock *b = (sh2rec_mem_usedblock *)block;196197/* Remove the usedblock from the chain */198if(b->base.next) {199b->base.next->prev = b->base.prev;200}201202if(b->base.prev) {203b->base.prev->next = b->base.next;204}205206if(b == usedblocks) {207usedblocks = (sh2rec_mem_usedblock *)b->base.next;208}209210if(b == usedblocks_tail) {211usedblocks_tail = (sh2rec_mem_usedblock *)b->base.prev;212}213214/* Treat the usedblock like its a freeblock (it is an extension of the215freeblock), and just link it into the free blocks list */216b->freespace = NULL;217b->base.next = freeblocks;218b->base.prev = NULL;219b->base.size += sizeof(sh2rec_mem_usedblock) - sizeof(sh2rec_mem_block);220freeblocks = (sh2rec_mem_block *)b;221}222223224