diff --git a/src/jit/frontend/sh4/sh4_frontend.c b/src/jit/frontend/sh4/sh4_frontend.c index c684d1a8..92d227de 100644 --- a/src/jit/frontend/sh4/sh4_frontend.c +++ b/src/jit/frontend/sh4/sh4_frontend.c @@ -22,26 +22,28 @@ struct sh4_frontend { static void sh4_analyze_block(const struct sh4_guest *guest, struct jit_block *block) { - uint32_t addr = block->guest_addr; + uint32_t offset = 0; block->guest_size = 0; block->num_cycles = 0; block->num_instrs = 0; while (1) { + uint32_t addr = block->guest_addr + offset; uint32_t data = guest->r16(guest->space, addr); + union sh4_instr instr = {data}; struct jit_opdef *def = sh4_get_opdef(data); - addr += 2; + offset += 2; block->guest_size += 2; block->num_cycles += def->cycles; block->num_instrs++; if (def->flags & SH4_FLAG_DELAYED) { - uint32_t delay_data = guest->r16(guest->space, addr); + uint32_t delay_data = guest->r16(guest->space, addr + 2); struct jit_opdef *delay_def = sh4_get_opdef(delay_data); - addr += 2; + offset += 2; block->guest_size += 2; block->num_cycles += delay_def->cycles; block->num_instrs++; @@ -50,11 +52,65 @@ static void sh4_analyze_block(const struct sh4_guest *guest, CHECK(!(delay_def->flags & SH4_FLAG_DELAYED)); } - /* stop emitting once a branch has been hit. in addition, if fpscr has - changed, stop emitting since the fpu state is invalidated. also, if - sr has changed, stop emitting as there are interrupts that possibly - need to be handled */ - if (def->flags & (SH4_FLAG_SET_PC | SH4_FLAG_SET_FPSCR | SH4_FLAG_SET_SR)) { + /* stop emitting once a branch is hit and save off branch information */ + if (def->flags & SH4_FLAG_SET_PC) { + if (def->op == SH4_OP_BF) { + uint32_t dest_addr = ((int8_t)instr.disp_8.disp * 2) + addr + 4; + block->branch_type = BRANCH_STATIC_FALSE; + block->branch_addr = dest_addr; + block->next_addr = addr + 4; + } else if (def->op == SH4_OP_BFS) { + uint32_t dest_addr = ((int8_t)instr.disp_8.disp * 2) + addr + 4; + block->branch_type = BRANCH_STATIC_FALSE; + block->branch_addr = dest_addr; + block->next_addr = addr + 4; + } else if (def->op == SH4_OP_BT) { + uint32_t dest_addr = ((int8_t)instr.disp_8.disp * 2) + addr + 4; + block->branch_type = BRANCH_STATIC_TRUE; + block->branch_addr = dest_addr; + block->next_addr = addr + 4; + } else if (def->op == SH4_OP_BTS) { + uint32_t dest_addr = ((int8_t)instr.disp_8.disp * 2) + addr + 4; + block->branch_type = BRANCH_STATIC_TRUE; + block->branch_addr = dest_addr; + block->next_addr = addr + 4; + } else if (def->op == SH4_OP_BRA) { + /* 12-bit displacement must be sign extended */ + int32_t disp = ((instr.disp_12.disp & 0xfff) << 20) >> 20; + uint32_t dest_addr = (disp * 2) + addr + 4; + block->branch_type = BRANCH_STATIC; + block->branch_addr = dest_addr; + } else if (def->op == SH4_OP_BRAF) { + block->branch_type = BRANCH_DYNAMIC; + } else if (def->op == SH4_OP_BSR) { + /* 12-bit displacement must be sign extended */ + int32_t disp = ((instr.disp_12.disp & 0xfff) << 20) >> 20; + uint32_t ret_addr = addr + 4; + uint32_t dest_addr = ret_addr + disp * 2; + block->branch_type = BRANCH_STATIC; + block->branch_addr = dest_addr; + } else if (def->op == SH4_OP_BSRF) { + block->branch_type = BRANCH_DYNAMIC; + } else if (def->op == SH4_OP_JMP) { + block->branch_type = BRANCH_DYNAMIC; + } else if (def->op == SH4_OP_JSR) { + block->branch_type = BRANCH_DYNAMIC; + } else if (def->op == SH4_OP_RTS) { + block->branch_type = BRANCH_DYNAMIC; + } else if (def->op == SH4_OP_RTE) { + block->branch_type = BRANCH_DYNAMIC; + } else if (def->op == SH4_OP_TRAPA) { + block->branch_type = BRANCH_DYNAMIC; + } else { + LOG_FATAL("unexpected branch op"); + } + break; + } + + /* if fpscr has changed, stop emitting since the fpu state is invalidated. + also, if sr has changed, stop emitting as there are interrupts that + possibly need to be handled */ + if (def->flags & (SH4_FLAG_SET_FPSCR | SH4_FLAG_SET_SR)) { break; } } diff --git a/src/jit/frontend/sh4/sh4_instr.h b/src/jit/frontend/sh4/sh4_instr.h index 922197a5..42e6eae7 100644 --- a/src/jit/frontend/sh4/sh4_instr.h +++ b/src/jit/frontend/sh4/sh4_instr.h @@ -1065,8 +1065,7 @@ INSTR(BT) { /* BTS disp */ INSTR(BTS) { /* 8-bit displacement must be sign extended */ - int32_t disp = (int32_t)(int8_t)i.disp_8.disp; - uint32_t dest_addr = (disp * 2) + addr + 4; + uint32_t dest_addr = ((int8_t)i.disp_8.disp * 2) + addr + 4; I32 cond = LOAD_T_I32(); DELAY_INSTR(); BRANCH_TRUE_IMM_I32(cond, dest_addr); @@ -1317,6 +1316,11 @@ INSTR(LDSMPR) { NEXT_INSTR(); } +/* LDTLB */ +INSTR(LDTLB) { + LDTLB(); +} + /* MOVCA.L R0,@Rn */ INSTR(MOVCAL) { I32 ea = LOAD_GPR_I32(i.def.rn); @@ -1379,11 +1383,6 @@ INSTR(SLEEP) { SLEEP(); } -/* LDTLB */ -INSTR(LDTLB) { - LDTLB(); -} - /* STC SR,Rn */ INSTR(STCSR) { I32 v = LOAD_SR_I32(); diff --git a/src/jit/frontend/sh4/sh4_instr.inc b/src/jit/frontend/sh4/sh4_instr.inc index fc72babd..a52df133 100644 --- a/src/jit/frontend/sh4/sh4_instr.inc +++ b/src/jit/frontend/sh4/sh4_instr.inc @@ -135,7 +135,6 @@ SH4_INSTR(RTS, "rts", 0000000000001011, 2, SH4_FL // system control instructions -SH4_INSTR(LDTLB, "ldtlb", 0000000000111000, 1, 0) SH4_INSTR(CLRMAC, "clrmac", 0000000000101000, 1, 0) SH4_INSTR(CLRS, "clrs", 0000000001001000, 1, 0) SH4_INSTR(CLRT, "clrt", 0000000000001000, 1, 0) @@ -159,6 +158,7 @@ SH4_INSTR(LDSPR, "lds rn, pr", 0100mmmm00101010, 2, 0) SH4_INSTR(LDSMMACH, "lds.l @rn+, mach", 0100mmmm00000110, 1, SH4_FLAG_LOAD) SH4_INSTR(LDSMMACL, "lds.l @rn+, macl", 0100mmmm00010110, 1, SH4_FLAG_LOAD) SH4_INSTR(LDSMPR, "lds.l @rn+, pr", 0100mmmm00100110, 2, SH4_FLAG_LOAD) +SH4_INSTR(LDTLB, "ldtlb", 0000000000111000, 1, 0) SH4_INSTR(MOVCAL, "movca.l r0, @rn", 0000nnnn11000011, 1, SH4_FLAG_STORE) SH4_INSTR(NOP, "nop", 0000000000001001, 1, 0) SH4_INSTR(OCBI, "ocbi", 0000nnnn10010011, 1, 0) diff --git a/src/jit/jit.h b/src/jit/jit.h index c2a8b9ff..a50bfe02 100644 --- a/src/jit/jit.h +++ b/src/jit/jit.h @@ -17,6 +17,15 @@ struct val; typedef uint32_t (*mem_read_cb)(void *, uint32_t, uint32_t); typedef void (*mem_write_cb)(void *, uint32_t, uint32_t, uint32_t); +enum { + BRANCH_STATIC, + BRANCH_STATIC_TRUE, + BRANCH_STATIC_FALSE, + BRANCH_DYNAMIC, + BRANCH_DYNAMIC_TRUE, + BRANCH_DYNAMIC_FALSE, +}; + struct jit_block { /* address of source block in guest memory */ uint32_t guest_addr; @@ -29,6 +38,13 @@ struct jit_block { /* compile with fastmem support */ int fastmem; + /* destination address of terminating branch */ + int branch_type; + uint32_t branch_addr; + + /* address of next instruction after branch */ + uint32_t next_addr; + /* number of guest instructions in block */ int num_instrs;