mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
sh2 drc, block management bugfixes and cleanup
This commit is contained in:
parent
397ccdc6cf
commit
49daa9e093
1 changed files with 77 additions and 82 deletions
|
@ -943,20 +943,14 @@ static struct block_desc *dr_find_inactive_block(int tcache_id, u16 crc,
|
||||||
u32 addr, int size, u32 addr_lit, int size_lit)
|
u32 addr, int size, u32 addr_lit, int size_lit)
|
||||||
{
|
{
|
||||||
struct block_list **head = &inactive_blocks[tcache_id];
|
struct block_list **head = &inactive_blocks[tcache_id];
|
||||||
struct block_list *prev = NULL, *current = *head;
|
struct block_list *current;
|
||||||
|
|
||||||
for (; current != NULL; prev = current, current = current->next) {
|
for (current = *head; current != NULL; current = current->next) {
|
||||||
struct block_desc *block = current->block;
|
struct block_desc *block = current->block;
|
||||||
if (block->crc == crc && block->addr == addr && block->size == size &&
|
if (block->crc == crc && block->addr == addr && block->size == size &&
|
||||||
block->addr_lit == addr_lit && block->size_lit == size_lit)
|
block->addr_lit == addr_lit && block->size_lit == size_lit)
|
||||||
{
|
{
|
||||||
if (prev == NULL)
|
rm_from_block_lists(block);
|
||||||
*head = current->next;
|
|
||||||
else
|
|
||||||
prev->next = current->next;
|
|
||||||
block->list = NULL; // should now be empty
|
|
||||||
current->next = blist_free;
|
|
||||||
blist_free = current;
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1031,6 +1025,47 @@ static void *dr_failure(void)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LINK_BRANCHES
|
||||||
|
static void dr_block_link(struct block_entry *be, struct block_link *bl, int emit_jump)
|
||||||
|
{
|
||||||
|
dbg(2, "- %slink from %p to pc %08x entry %p", emit_jump ? "":"early ",
|
||||||
|
bl->jump, bl->target_pc, be->tcache_ptr);
|
||||||
|
|
||||||
|
if (emit_jump)
|
||||||
|
emith_jump_patch(bl->jump, be->tcache_ptr);
|
||||||
|
// could sync arm caches here, but that's unnecessary
|
||||||
|
|
||||||
|
// move bl to block_entry
|
||||||
|
bl->target = be;
|
||||||
|
bl->prev = NULL;
|
||||||
|
if (be->links)
|
||||||
|
be->links->prev = bl;
|
||||||
|
bl->next = be->links;
|
||||||
|
be->links = bl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dr_block_unlink(struct block_link *bl, int emit_jump)
|
||||||
|
{
|
||||||
|
dbg(2,"- unlink from %p to pc %08x", bl->jump, bl->target_pc);
|
||||||
|
|
||||||
|
if (bl->target) {
|
||||||
|
if (emit_jump) {
|
||||||
|
emith_jump_patch(bl->jump, sh2_drc_dispatcher);
|
||||||
|
// update cpu caches since the previous jump target doesn't exist anymore
|
||||||
|
host_instructions_updated(bl->jump, bl->jump+4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bl->prev)
|
||||||
|
bl->prev->next = bl->next;
|
||||||
|
else
|
||||||
|
bl->target->links = bl->next;
|
||||||
|
if (bl->next)
|
||||||
|
bl->next->prev = bl->prev;
|
||||||
|
bl->target = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void *dr_prepare_ext_branch(struct block_entry *owner, u32 pc, int is_slave, int tcache_id)
|
static void *dr_prepare_ext_branch(struct block_entry *owner, u32 pc, int is_slave, int tcache_id)
|
||||||
{
|
{
|
||||||
#if LINK_BRANCHES
|
#if LINK_BRANCHES
|
||||||
|
@ -1064,13 +1099,7 @@ static void *dr_prepare_ext_branch(struct block_entry *owner, u32 pc, int is_sla
|
||||||
owner->o_links = bl;
|
owner->o_links = bl;
|
||||||
|
|
||||||
if (be != NULL) {
|
if (be != NULL) {
|
||||||
dbg(2, "- early link from %p to pc %08x entry %p", bl->jump, pc, be->tcache_ptr);
|
dr_block_link(be, bl, 0); // jump not yet emitted by translate()
|
||||||
bl->target = be;
|
|
||||||
bl->prev = NULL;
|
|
||||||
if (be->links)
|
|
||||||
be->links->prev = bl;
|
|
||||||
bl->next = be->links;
|
|
||||||
be->links = bl;
|
|
||||||
return be->tcache_ptr;
|
return be->tcache_ptr;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1092,23 +1121,12 @@ static void dr_link_blocks(struct block_entry *be, int tcache_id)
|
||||||
|
|
||||||
while (bl != NULL) {
|
while (bl != NULL) {
|
||||||
next = bl->next;
|
next = bl->next;
|
||||||
if (bl->target_pc == pc) {
|
if (bl->target_pc == pc && (!bl->tcache_id || bl->tcache_id == tcache_id)) {
|
||||||
dbg(2, "- link from %p to pc %08x entry %p", bl->jump, pc, be->tcache_ptr);
|
rm_from_hashlist_unresolved(bl, bl->tcache_id);
|
||||||
// move bl from unresolved_links to block_entry
|
dr_block_link(be, bl, 1);
|
||||||
rm_from_hashlist_unresolved(bl, tcache_id);
|
|
||||||
|
|
||||||
emith_jump_patch(bl->jump, be->tcache_ptr);
|
|
||||||
bl->target = be;
|
|
||||||
bl->prev = NULL;
|
|
||||||
if (be->links)
|
|
||||||
be->links->prev = bl;
|
|
||||||
bl->next = be->links;
|
|
||||||
be->links = bl;
|
|
||||||
}
|
}
|
||||||
bl = next;
|
bl = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// could sync arm caches here, but that's unnecessary
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1119,22 +1137,13 @@ static void dr_link_outgoing(struct block_entry *be, int tcache_id, int is_slave
|
||||||
int target_tcache_id;
|
int target_tcache_id;
|
||||||
|
|
||||||
for (bl = be->o_links; bl; bl = bl->o_next) {
|
for (bl = be->o_links; bl; bl = bl->o_next) {
|
||||||
be = dr_get_entry(bl->target_pc, is_slave, &target_tcache_id);
|
if (bl->target == NULL) {
|
||||||
if (!target_tcache_id || target_tcache_id == tcache_id) {
|
be = dr_get_entry(bl->target_pc, is_slave, &target_tcache_id);
|
||||||
if (be) {
|
if (be != NULL && (!target_tcache_id || target_tcache_id == tcache_id)) {
|
||||||
dbg(2, "- link from %p to pc %08x entry %p", bl->jump, bl->target_pc, be->tcache_ptr);
|
// remove bl from unresolved_links (must've been since target was NULL)
|
||||||
emith_jump_patch(bl->jump, be->tcache_ptr);
|
rm_from_hashlist_unresolved(bl, bl->tcache_id);
|
||||||
bl->target = be;
|
dr_block_link(be, bl, 1);
|
||||||
bl->prev = NULL;
|
|
||||||
if (be->links)
|
|
||||||
be->links->prev = bl;
|
|
||||||
bl->next = be->links;
|
|
||||||
be->links = bl;
|
|
||||||
} else {
|
|
||||||
emith_jump_patch(bl->jump, sh2_drc_dispatcher);
|
|
||||||
add_to_hashlist_unresolved(bl, tcache_id);
|
|
||||||
}
|
}
|
||||||
host_instructions_updated(bl->jump, bl->jump+4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -4381,65 +4390,48 @@ static void sh2_smc_rm_block_entry(struct block_desc *bd, int tcache_id, u32 nol
|
||||||
struct block_link *bl;
|
struct block_link *bl;
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
dbg(2, " killing entry %08x-%08x,%08x-%08x, blkid %d,%d",
|
free = free || nolit; // block is invalid if literals are overwritten
|
||||||
|
dbg(2," %sing block %08x-%08x,%08x-%08x, blkid %d,%d", free?"delet":"disabl",
|
||||||
bd->addr, bd->addr + bd->size, bd->addr_lit, bd->addr_lit + bd->size_lit,
|
bd->addr, bd->addr + bd->size, bd->addr_lit, bd->addr_lit + bd->size_lit,
|
||||||
tcache_id, bd - block_tables[tcache_id]);
|
tcache_id, bd - block_tables[tcache_id]);
|
||||||
if (bd->addr == 0 || bd->entry_count == 0) {
|
if (bd->addr == 0 || bd->entry_count == 0) {
|
||||||
dbg(1, " killing dead block!? %08x", bd->addr);
|
dbg(1, " killing dead block!? %08x", bd->addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free = free || nolit; // block is invalid if literals are overwritten
|
|
||||||
|
|
||||||
// remove from hash table, make incoming links unresolved, revoke outgoing links
|
// remove from hash table, make incoming links unresolved
|
||||||
for (i = 0; i < bd->entry_count; i++) {
|
if (bd->active) {
|
||||||
if (bd->active)
|
for (i = 0; i < bd->entry_count; i++) {
|
||||||
rm_from_hashlist(&bd->entryp[i], tcache_id);
|
rm_from_hashlist(&bd->entryp[i], tcache_id);
|
||||||
|
|
||||||
for (bl = bd->entryp[i].o_links; bl != NULL; ) {
|
while ((bl = bd->entryp[i].links) != NULL) {
|
||||||
if (bl->target) {
|
dr_block_unlink(bl, 1);
|
||||||
if (bl->prev)
|
add_to_hashlist_unresolved(bl, tcache_id);
|
||||||
bl->prev->next = bl->next;
|
}
|
||||||
else
|
|
||||||
bl->target->links = bl->next;
|
|
||||||
if (bl->next)
|
|
||||||
bl->next->prev = bl->prev;
|
|
||||||
bl->target = NULL;
|
|
||||||
} else if (bd->active)
|
|
||||||
rm_from_hashlist_unresolved(bl, tcache_id);
|
|
||||||
bl = bl->o_next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (bl = bd->entryp[i].links; bl != NULL; ) {
|
|
||||||
struct block_link *bl_next = bl->next;
|
|
||||||
dbg(2, "- unlink from %p to pc %08x", bl->jump, bl->target_pc);
|
|
||||||
emith_jump_patch(bl->jump, sh2_drc_dispatcher);
|
|
||||||
// update cpu caches since the previous jump target doesn't exist anymore
|
|
||||||
host_instructions_updated(bl->jump, bl->jump+4);
|
|
||||||
|
|
||||||
add_to_hashlist_unresolved(bl, tcache_id);
|
|
||||||
bl = bl_next;
|
|
||||||
}
|
|
||||||
bd->entryp[i].links = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bd->active)
|
|
||||||
dr_mark_memory(-1, bd, tcache_id, nolit);
|
dr_mark_memory(-1, bd, tcache_id, nolit);
|
||||||
|
add_to_block_list(&inactive_blocks[tcache_id], bd);
|
||||||
|
}
|
||||||
|
bd->active = 0;
|
||||||
|
|
||||||
if (free) {
|
if (free) {
|
||||||
while ((bl = bd->entryp[0].o_links) != NULL) {
|
// revoke outgoing links
|
||||||
bd->entryp[0].o_links = bl->next;
|
for (bl = bd->entryp[0].o_links; bl != NULL; bl = bl->o_next) {
|
||||||
|
if (bl->target)
|
||||||
|
dr_block_unlink(bl, 0);
|
||||||
|
else
|
||||||
|
rm_from_hashlist_unresolved(bl, tcache_id);
|
||||||
bl->jump = NULL;
|
bl->jump = NULL;
|
||||||
bl->next = blink_free[bl->tcache_id];
|
bl->next = blink_free[bl->tcache_id];
|
||||||
blink_free[bl->tcache_id] = bl;
|
blink_free[bl->tcache_id] = bl;
|
||||||
}
|
}
|
||||||
bd->entryp[0].o_links = NULL;
|
bd->entryp[0].o_links = NULL;
|
||||||
|
// invalidate block
|
||||||
rm_from_block_lists(bd);
|
rm_from_block_lists(bd);
|
||||||
bd->addr = bd->size = bd->addr_lit = bd->size_lit = 0;
|
bd->addr = bd->size = bd->addr_lit = bd->size_lit = 0;
|
||||||
bd->entry_count = 0;
|
bd->entry_count = 0;
|
||||||
} else {
|
|
||||||
add_to_block_list(&inactive_blocks[tcache_id], bd);
|
|
||||||
}
|
}
|
||||||
bd->active = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sh2_smc_rm_blocks(u32 a, int tcache_id, u32 shift)
|
static void sh2_smc_rm_blocks(u32 a, int tcache_id, u32 shift)
|
||||||
|
@ -4454,10 +4446,12 @@ static void sh2_smc_rm_blocks(u32 a, int tcache_id, u32 shift)
|
||||||
int removed = 0;
|
int removed = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// need to check cached and writethrough area
|
// ignore cache-through
|
||||||
a &= wtmask;
|
a &= wtmask;
|
||||||
|
|
||||||
blist = &inval_lookup[tcache_id][(a & mask) / INVAL_PAGE_SIZE];
|
blist = &inval_lookup[tcache_id][(a & mask) / INVAL_PAGE_SIZE];
|
||||||
entry = *blist;
|
entry = *blist;
|
||||||
|
// go through the block list for this range
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
next = entry->next;
|
next = entry->next;
|
||||||
block = entry->block;
|
block = entry->block;
|
||||||
|
@ -4465,6 +4459,7 @@ static void sh2_smc_rm_blocks(u32 a, int tcache_id, u32 shift)
|
||||||
end_addr = start_addr + block->size;
|
end_addr = start_addr + block->size;
|
||||||
start_lit = block->addr_lit & wtmask;
|
start_lit = block->addr_lit & wtmask;
|
||||||
end_lit = start_lit + block->size_lit;
|
end_lit = start_lit + block->size_lit;
|
||||||
|
// disable/delete block if it covers the modified address
|
||||||
if ((start_addr <= a && a < end_addr) ||
|
if ((start_addr <= a && a < end_addr) ||
|
||||||
(start_lit <= a && a < end_lit))
|
(start_lit <= a && a < end_lit))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue