Path: blob/master/yabause/src/dreamcast/sh2rec/sh2rec_htab.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 <string.h>22#include <inttypes.h>2324#include "core.h"25#include "sh2core.h"26#include "sh2rec.h"27#include "sh2rec_htab.h"28#include "sh2rec_mem.h"2930typedef struct htab_entry {31sh2rec_block_t block;3233struct htab_entry *next;34} htab_entry_t;3536/* The actual hash table. It can't be resized dynamically, and is essentially37just an array of singly-linked lists. */38static htab_entry_t *table[SH2REC_HTAB_ENTRIES];3940/* Internal functions */41static void htab_free_chain(htab_entry_t *ent) {42htab_entry_t *i, *tmp;4344i = ent;45while(i) {46tmp = i->next;47free(i->block.block);48free(i);49i = tmp;50}51}5253/* Hash an address into something slightly nicer to work with. The large54constant in here is about 2^32 / phi (where phi is the golden ratio). Why use55the golden ratio? Because its always fun to use in code. */56static inline int hash_addr(u32 addr) {57return ((addr ^ 2654435761U) >> 2) & (SH2REC_HTAB_ENTRIES - 1);58}5960/* Public functions */61void sh2rec_htab_init(void) {62memset(table, 0, sizeof(htab_entry_t *) * SH2REC_HTAB_ENTRIES);63}6465void sh2rec_htab_reset(void) {66int i;6768for(i = 0; i < SH2REC_HTAB_ENTRIES; ++i) {69if(table[i]) {70htab_free_chain(table[i]);71}72}7374memset(table, 0, sizeof(htab_entry_t *) * SH2REC_HTAB_ENTRIES);75}7677sh2rec_block_t *sh2rec_htab_lookup(u32 addr) {78htab_entry_t *i = table[hash_addr(addr)];7980/* Look through the chain for the entry we're after */81while(i) {82if(i->block.start_pc == addr) {83return &i->block;84}8586i = i->next;87}8889/* Didn't find it, punt. */90return NULL;91}9293/* Create a new block assuming an old one does not exist. */94sh2rec_block_t *sh2rec_htab_block_create(u32 addr, int length) {95uint8_t *ptr;96htab_entry_t *ent;97int index = hash_addr(addr);9899ptr = (uint8_t *)sh2rec_mem_alloc(length + sizeof(htab_entry_t));100101#ifdef DEBUG102if(!ptr) {103return NULL;104}105#endif106107/* Allocate space for the block */108ent = (htab_entry_t *)ptr;109ent->block.block = (u16 *)(ptr + sizeof(htab_entry_t));110111/* Fill in the struct */112ent->block.start_pc = addr;113ent->block.cycles = 0;114ent->block.pc = addr;115ent->block.length = length;116ent->block.ptr = ent->block.block;117118/* Put the item in the list (puts it at the head of the index in the table119where it would go) */120ent->next = table[index];121table[index] = ent;122123return &ent->block;124}125126void sh2rec_htab_block_remove(u32 addr) {127int index = hash_addr(addr);128htab_entry_t *i, *tmp, *last;129130i = table[index];131last = NULL;132133/* Look through everything for the entry we're supposed to remove */134while(i) {135tmp = i->next;136137/* Is this the entry we're looking for? */138if(i->block.start_pc == addr) {139/* Unhook the entry from the list */140if(last) {141last->next = tmp;142}143else {144table[index] = tmp;145}146147/* Free any memory used by the block */148sh2rec_mem_free(i);149150return;151}152153last = i;154i = tmp;155}156}157158159