diff --git a/src/386_dynarec.c b/src/386_dynarec.c index 5396f5f..c00b443 100644 --- a/src/386_dynarec.c +++ b/src/386_dynarec.c @@ -1292,7 +1292,7 @@ void exec386_dynarec(int cycs) int valid_block = 0; trap = 0; - if (block) + if (block && !abrt) { page_t *page = &pages[phys_addr >> 12]; @@ -1301,7 +1301,23 @@ void exec386_dynarec(int cycs) also catch any page faults at this stage*/ valid_block = (block->pc == cs + pc) && (block->_cs == cs) && (block->use32 == use32) && (block->phys == phys_addr) && (block->stack32 == stack32); - + if (!valid_block) + { + uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + if (page->code_present_mask & mask) + { + /*Walk page tree to see if we find the correct block*/ + codeblock_t *new_block = codeblock_tree_find(phys_addr); + if (new_block) + { + valid_block = (new_block->pc == cs + pc) && (new_block->_cs == cs) && + (new_block->use32 == use32) && (new_block->phys == phys_addr) && (new_block->stack32 == stack32); + if (valid_block) + block = new_block; + } + } + } if (valid_block && (block->page_mask & page->dirty_mask)) { codegen_check_flush(page, page->dirty_mask, phys_addr); @@ -1337,6 +1353,7 @@ void exec386_dynarec(int cycs) { void (*code)() = (void *)&block->data[BLOCK_START]; + codeblock_hash[hash] = block; // if (output) pclog("Run block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%08x %04x %08x %08x %016llx %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, get_phys(cs+pc), block->phys, block->page_mask, block->endpc); inrecomp=1; diff --git a/src/codegen.h b/src/codegen.h index bab424b..961bef5 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -1,3 +1,5 @@ +#include "mem.h" + #ifdef __amd64__ #include "codegen_x86-64.h" #elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 @@ -39,6 +41,10 @@ typedef struct codeblock_t struct codeblock_t *prev, *next; struct codeblock_t *prev_2, *next_2; + /*Pointers for codeblock tree, used to search for blocks when hash lookup + fails.*/ + struct codeblock_t *parent, *left, *right; + uint32_t pc; uint32_t _cs; uint32_t endpc; @@ -52,6 +58,138 @@ typedef struct codeblock_t uint8_t data[2048]; } codeblock_t; +static inline codeblock_t *codeblock_tree_find(uint32_t phys) +{ + codeblock_t *block = pages[phys >> 12].head; + + while (block) + { + if (phys == block->phys) + return block; + else if (phys < block->phys) + block = block->left; + else + block = block->right; + } +} + +static inline void codeblock_tree_add(codeblock_t *new_block) +{ + codeblock_t *block = pages[new_block->phys >> 12].head; + + if (!block) + { + pages[new_block->phys >> 12].head = new_block; + new_block->parent = new_block->left = new_block->right = NULL; + } + else + { + codeblock_t *old_block = NULL; + while (block) + { + old_block = block; + + if (new_block->phys < old_block->phys) + block = block->left; + else + block = block->right; + } + + if (new_block->phys < old_block->phys) + old_block->left = new_block; + else + old_block->right = new_block; + + new_block->parent = old_block; + new_block->left = new_block->right = NULL; + } +} + +static inline void codeblock_tree_delete(codeblock_t *block) +{ + while (1) + { + codeblock_t *parent = block->parent; + + if (!block->left && !block->right) + { + /*Easy case - remove from parent*/ + if (parent) + { + if (parent->left == block) + parent->left = NULL; + if (parent->right == block) + parent->right = NULL; + } + return; + } + else if (!block->left) + { + /*Only left node*/ + if (!parent) + pages[block->phys >> 12].head = block->left; + else + { + if (parent->left == block) + parent->left = block->left; + if (parent->right == block) + parent->right = block->left; + } + return; + } + else if (!block->right) + { + /*Only right node*/ + if (!parent) + pages[block->phys >> 12].head = block->right; + else + { + if (parent->left == block) + parent->left = block->right; + if (parent->right == block) + parent->right = block->right; + } + return; + } + else + { + /*Difficult case - node has two children. Walk right child to find lowest node*/ + codeblock_t *lowest = block->right; + codeblock_t *old_parent; + + while (lowest->left) + lowest = lowest->left; + old_parent = lowest->parent; + + /*Replace deleted node with lowest node*/ + if (!parent) + pages[block->phys >> 12].head = lowest; + else + { + if (parent->left == block) + parent->left = lowest; + if (parent->right == block) + parent->right = lowest; + } + lowest->parent = parent; + + if (old_parent = block) + { + return; + } + else + { + /*Replace old lowest node with deleted node, and loop*/ + if (old_parent->left == lowest) + old_parent->left = block->left; + if (old_parent->right == lowest) + old_parent->right = block->right; + block->parent = old_parent; + } + } + } +} + #define PAGE_MASK_MASK 63 #define PAGE_MASK_SHIFT 6 diff --git a/src/codegen_x86.c b/src/codegen_x86.c index 8a0af7e..4a0410a 100644 --- a/src/codegen_x86.c +++ b/src/codegen_x86.c @@ -126,6 +126,8 @@ static void delete_block(codeblock_t *block) fatal("Deleting deleted block\n"); block->pc = 0; + codeblock_tree_delete(block); + if (block->prev) { block->prev->next = block->next; @@ -425,6 +427,8 @@ void codegen_block_end() // pclog("End block %i\n", block_num); recomp_page = -1; + + codeblock_tree_add(block); } void codegen_flush() diff --git a/src/mem.h b/src/mem.h index 631197a..102b057 100644 --- a/src/mem.h +++ b/src/mem.h @@ -1,3 +1,6 @@ +#ifndef _MEM_H_ +#define _MEM_H_ + typedef struct mem_mapping_t { struct mem_mapping_t *prev, *next; @@ -110,6 +113,9 @@ typedef struct page_t struct codeblock_t *block, *block_2; + /*Head of codeblock tree associated with this page*/ + struct codeblock_t *head; + uint64_t code_present_mask, dirty_mask; } page_t; @@ -156,3 +162,5 @@ void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p); void mem_reset_page_blocks(); extern mem_mapping_t ram_low_mapping; + +#endif