Rework self modifying code handling.

Code blocks now have a varying level of granularity in the page and dirty masks.
Most blocks have 64-byte granularity, but blocks that are repeatedly modified
drop to 1-byte granularity. This reduces the maximum size of the affected block
significantly, but reduces recompilation due to data located too close to code.

If the block is still marked as dirty, then it is recompiled without any
immediate instruction parameters being baked into the recompiled code, instead
being fetched from the RAM array as needed. This severely reduces recompilation
rates on some SMC-heavy games, eg Duke Nukem 3D, System Shock, Screamer etc,
giving a major speedup.
This commit is contained in:
SarahW 2019-03-16 14:53:26 +00:00
commit ab124776a0
36 changed files with 1719 additions and 233 deletions

View file

@ -73,6 +73,14 @@ extern uint8_t *block_write_data;
#define CODEBLOCK_WAS_RECOMPILED 4
/*Code block is in free list and is not valid*/
#define CODEBLOCK_IN_FREE_LIST 8
/*Code block spans two pages, page_mask2 and dirty_mask2 are valid*/
#define CODEBLOCK_HAS_PAGE2 0x10
/*Code block is using a byte mask for code present and dirty*/
#define CODEBLOCK_BYTE_MASK 0x20
/*Code block is in dirty list*/
#define CODEBLOCK_IN_DIRTY_LIST 0x40
/*Code block is not inlining immediate parameters, parameters must be fetched from memory*/
#define CODEBLOCK_NO_IMMEDIATES 0x80
#define BLOCK_PC_INVALID 0xffffffff
@ -277,10 +285,33 @@ static inline void codeblock_tree_delete(codeblock_t *block)
}
}
#define PAGE_MASK_INDEX_MASK 3
#define PAGE_MASK_INDEX_SHIFT 10
#define PAGE_MASK_MASK 63
#define PAGE_MASK_SHIFT 4
#define PAGE_MASK_SHIFT 6
void codegen_mark_code_present_multibyte(codeblock_t *block, uint32_t start_pc, int len);
static inline void codegen_mark_code_present(codeblock_t *block, uint32_t start_pc, int len)
{
if (len == 1)
{
if (block->flags & CODEBLOCK_BYTE_MASK)
{
if (!((start_pc ^ block->pc) & ~0x3f)) /*Starts in second page*/
block->page_mask |= ((uint64_t)1 << (start_pc & PAGE_MASK_MASK));
else
block->page_mask2 |= ((uint64_t)1 << (start_pc & PAGE_MASK_MASK));
}
else
{
if (!((start_pc ^ block->pc) & ~0xfff)) /*Starts in second page*/
block->page_mask |= ((uint64_t)1 << ((start_pc >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK));
else
block->page_mask2 |= ((uint64_t)1 << ((start_pc >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK));
}
}
else
codegen_mark_code_present_multibyte(block, start_pc, len);
}
void codegen_init();
void codegen_close();