X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/022c62cbbcf1ff40b23c92874f8670cddfec2414..508127e243122cf3ed67d2aaa472a1b4f1be055e:/target-m68k/translate.c diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 1c9b5ec8d4..a402bd847a 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -18,14 +18,19 @@ * License along with this library; if not, see . */ +#include "qemu/osdep.h" #include "cpu.h" #include "disas/disas.h" #include "tcg-op.h" -#include "qemu-log.h" +#include "qemu/log.h" +#include "exec/cpu_ldst.h" + +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" + +#include "trace-tcg.h" +#include "exec/log.h" -#include "helpers.h" -#define GEN_HELPER 1 -#include "helpers.h" //#define DEBUG_DISPATCH 1 @@ -42,6 +47,9 @@ #undef DEFO64 #undef DEFF64 +static TCGv_i32 cpu_halted; +static TCGv_i32 cpu_exception_index; + static TCGv_ptr cpu_env; static char cpu_reg_names[3*8*3 + 5*4]; @@ -76,6 +84,14 @@ void m68k_tcg_init(void) #undef DEFO64 #undef DEFF64 + cpu_halted = tcg_global_mem_new_i32(TCG_AREG0, + -offsetof(M68kCPU, env) + + offsetof(CPUState, halted), "HALTED"); + cpu_exception_index = tcg_global_mem_new_i32(TCG_AREG0, + -offsetof(M68kCPU, env) + + offsetof(CPUState, exception_index), + "EXCEPTION"); + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); p = cpu_reg_names; @@ -102,17 +118,6 @@ void m68k_tcg_init(void) NULL_QREG = tcg_global_mem_new(TCG_AREG0, -4, "NULL"); store_dummy = tcg_global_mem_new(TCG_AREG0, -8, "NULL"); - -#define GEN_HELPER 2 -#include "helpers.h" -} - -static inline void qemu_assert(int cond, const char *msg) -{ - if (!cond) { - fprintf (stderr, "badness: %s\n", msg); - abort(); - } } /* internal defines */ @@ -126,7 +131,6 @@ typedef struct DisasContext { uint32_t fpcr; struct TranslationBlock *tb; int singlestep_enabled; - int is_mem; TCGv_i64 mactmp; int done_mac; } DisasContext; @@ -176,7 +180,6 @@ static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign) { TCGv tmp; int index = IS_USER(s); - s->is_mem = 1; tmp = tcg_temp_new_i32(); switch(opsize) { case OS_BYTE: @@ -196,7 +199,7 @@ static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign) tcg_gen_qemu_ld32u(tmp, addr, index); break; default: - qemu_assert(0, "bad load size"); + g_assert_not_reached(); } gen_throws_exception = gen_last_qop; return tmp; @@ -206,7 +209,6 @@ static inline TCGv_i64 gen_load64(DisasContext * s, TCGv addr) { TCGv_i64 tmp; int index = IS_USER(s); - s->is_mem = 1; tmp = tcg_temp_new_i64(); tcg_gen_qemu_ldf64(tmp, addr, index); gen_throws_exception = gen_last_qop; @@ -217,7 +219,6 @@ static inline TCGv_i64 gen_load64(DisasContext * s, TCGv addr) static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val) { int index = IS_USER(s); - s->is_mem = 1; switch(opsize) { case OS_BYTE: tcg_gen_qemu_st8(val, addr, index); @@ -230,7 +231,7 @@ static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val) tcg_gen_qemu_st32(val, addr, index); break; default: - qemu_assert(0, "bad store size"); + g_assert_not_reached(); } gen_throws_exception = gen_last_qop; } @@ -238,7 +239,6 @@ static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val) static inline void gen_store64(DisasContext *s, TCGv addr, TCGv_i64 val) { int index = IS_USER(s); - s->is_mem = 1; tcg_gen_qemu_stf64(val, addr, index); gen_throws_exception = gen_last_qop; } @@ -294,8 +294,7 @@ static TCGv gen_addr_index(uint16_t ext, TCGv tmp) /* Handle a base + index + displacement effective addresss. A NULL_QREG base means pc-relative. */ -static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, int opsize, - TCGv base) +static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) { uint32_t offset; uint16_t ext; @@ -434,8 +433,7 @@ static inline int opsize_bytes(int opsize) case OS_SINGLE: return 4; case OS_DOUBLE: return 8; default: - qemu_assert(0, "bad operand size"); - return 0; + g_assert_not_reached(); } } @@ -462,8 +460,7 @@ static void gen_partset_reg(int opsize, TCGv reg, TCGv val) tcg_gen_mov_i32(reg, val); break; default: - qemu_assert(0, "Bad operand size"); - break; + g_assert_not_reached(); } } @@ -492,7 +489,7 @@ static inline TCGv gen_extend(TCGv val, int opsize, int sign) tmp = val; break; default: - qemu_assert(0, "Bad operand size"); + g_assert_not_reached(); } return tmp; } @@ -528,7 +525,7 @@ static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, return tmp; case 6: /* Indirect index + displacement. */ reg = AREG(insn, 0); - return gen_lea_indexed(env, s, opsize, reg); + return gen_lea_indexed(env, s, reg); case 7: /* Other */ switch (insn & 7) { case 0: /* Absolute short. */ @@ -544,7 +541,7 @@ static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, s->pc += 2; return tcg_const_i32(offset); case 3: /* pc index+displacement. */ - return gen_lea_indexed(env, s, opsize, NULL_QREG); + return gen_lea_indexed(env, s, NULL_QREG); case 4: /* Immediate. */ default: return NULL_QREG; @@ -574,7 +571,7 @@ static inline TCGv gen_ea_once(CPUM68KState *env, DisasContext *s, return gen_ldst(s, opsize, tmp, val, what); } -/* Generate code to load/store a value ito/from an EA. If VAL > 0 this is +/* Generate code to load/store a value from/into an EA. If VAL > 0 this is a write otherwise it is a read (0 == sign extend, -1 == zero extend). ADDRP is non-null for readwrite operands. */ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, @@ -666,7 +663,7 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, offset = read_im32(env, s); break; default: - qemu_assert(0, "Bad immediate operand"); + g_assert_not_reached(); } return tcg_const_i32(offset); default: @@ -678,7 +675,7 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, } /* This generates a conditional branch, clobbering all temporaries. */ -static void gen_jmpcc(DisasContext *s, int cond, int l1) +static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1) { TCGv tmp; @@ -783,7 +780,7 @@ static void gen_jmpcc(DisasContext *s, int cond, int l1) DISAS_INSN(scc) { - int l1; + TCGLabel *l1; int cond; TCGv reg; @@ -863,7 +860,7 @@ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(QREG_PC, dest); - tcg_gen_exit_tb((tcg_target_long)tb + n); + tcg_gen_exit_tb((uintptr_t)tb + n); } else { gen_jmp_im(s, dest); tcg_gen_exit_tb(0); @@ -883,8 +880,10 @@ DISAS_INSN(undef_fpu) DISAS_INSN(undef) { + M68kCPU *cpu = m68k_env_get_cpu(env); + gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED); - cpu_abort(env, "Illegal instruction: %04x @ %08x", insn, s->pc - 2); + cpu_abort(CPU(cpu), "Illegal instruction: %04x @ %08x", insn, s->pc - 2); } DISAS_INSN(mulw) @@ -1655,7 +1654,7 @@ DISAS_INSN(branch) int32_t offset; uint32_t base; int op; - int l1; + TCGLabel *l1; base = s->pc; op = (insn >> 8) & 0xf; @@ -1992,8 +1991,8 @@ DISAS_INSN(move_from_usp) gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); return; } - /* TODO: Implement USP. */ - gen_exception(s, s->pc - 2, EXCP_ILLEGAL); + tcg_gen_ld_i32(AREG(insn, 0), cpu_env, + offsetof(CPUM68KState, sp[M68K_USP])); } DISAS_INSN(move_to_usp) @@ -2002,8 +2001,8 @@ DISAS_INSN(move_to_usp) gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); return; } - /* TODO: Implement USP. */ - gen_exception(s, s->pc - 2, EXCP_ILLEGAL); + tcg_gen_st_i32(AREG(insn, 0), cpu_env, + offsetof(CPUM68KState, sp[M68K_USP])); } DISAS_INSN(halt) @@ -2024,7 +2023,7 @@ DISAS_INSN(stop) s->pc += 2; gen_set_sr_im(s, ext, 0); - tcg_gen_movi_i32(QREG_HALTED, 1); + tcg_gen_movi_i32(cpu_halted, 1); gen_exception(s, s->pc, EXCP_HLT); } @@ -2084,12 +2083,14 @@ DISAS_INSN(wddata) DISAS_INSN(wdebug) { + M68kCPU *cpu = m68k_env_get_cpu(env); + if (IS_USER(s)) { gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); return; } /* TODO: Implement wdebug. */ - qemu_assert(0, "WDEBUG not implemented"); + cpu_abort(CPU(cpu), "WDEBUG not implemented"); } DISAS_INSN(trap) @@ -2222,7 +2223,6 @@ DISAS_INSN(fpu) mask = 0x80; for (i = 0; i < 8; i++) { if (ext & mask) { - s->is_mem = 1; dest = FREG(i, 0); if (ext & (1 << 13)) { /* store */ @@ -2390,7 +2390,7 @@ DISAS_INSN(fbcc) uint32_t offset; uint32_t addr; TCGv flag; - int l1; + TCGLabel *l1; addr = s->pc; offset = cpu_ldsw_code(env, s->pc); @@ -2463,14 +2463,18 @@ DISAS_INSN(fbcc) DISAS_INSN(frestore) { + M68kCPU *cpu = m68k_env_get_cpu(env); + /* TODO: Implement frestore. */ - qemu_assert(0, "FRESTORE not implemented"); + cpu_abort(CPU(cpu), "FRESTORE not implemented"); } DISAS_INSN(fsave) { + M68kCPU *cpu = m68k_env_get_cpu(env); + /* TODO: Implement fsave. */ - qemu_assert(0, "FSAVE not implemented"); + cpu_abort(CPU(cpu), "FSAVE not implemented"); } static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper) @@ -2678,7 +2682,7 @@ DISAS_INSN(from_mac) if (s->env->macsr & MACSR_FI) { gen_helper_get_macf(rx, cpu_env, acc); } else if ((s->env->macsr & MACSR_OMC) == 0) { - tcg_gen_trunc_i64_i32(rx, acc); + tcg_gen_extrl_i64_i32(rx, acc); } else if (s->env->macsr & MACSR_SU) { gen_helper_get_macs(rx, acc); } else { @@ -2953,10 +2957,6 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) { uint16_t insn; - if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { - tcg_gen_debug_insn_start(s->pc); - } - insn = cpu_lduw_code(env, s->pc); s->pc += 2; @@ -2964,14 +2964,11 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) } /* generate intermediate code for basic block 'tb'. */ -static inline void -gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, - int search_pc) +void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb) { + M68kCPU *cpu = m68k_env_get_cpu(env); + CPUState *cs = CPU(cpu); DisasContext dc1, *dc = &dc1; - uint16_t *gen_opc_end; - CPUBreakpoint *bp; - int j, lj; target_ulong pc_start; int pc_offset; int num_insns; @@ -2982,63 +2979,56 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, dc->tb = tb; - gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; - dc->env = env; dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; dc->cc_op = CC_OP_DYNAMIC; - dc->singlestep_enabled = env->singlestep_enabled; + dc->singlestep_enabled = cs->singlestep_enabled; dc->fpcr = env->fpcr; dc->user = (env->sr & SR_S) == 0; - dc->is_mem = 0; dc->done_mac = 0; - lj = -1; num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) + if (max_insns == 0) { max_insns = CF_COUNT_MASK; + } + if (max_insns > TCG_MAX_INSNS) { + max_insns = TCG_MAX_INSNS; + } - gen_icount_start(); + gen_tb_start(tb); do { pc_offset = dc->pc - pc_start; gen_throws_exception = NULL; - if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { - QTAILQ_FOREACH(bp, &env->breakpoints, entry) { - if (bp->pc == dc->pc) { - gen_exception(dc, dc->pc, EXCP_DEBUG); - dc->is_jmp = DISAS_JUMP; - break; - } - } - if (dc->is_jmp) - break; - } - if (search_pc) { - j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; - if (lj < j) { - lj++; - while (lj < j) - tcg_ctx.gen_opc_instr_start[lj++] = 0; - } - tcg_ctx.gen_opc_pc[lj] = dc->pc; - tcg_ctx.gen_opc_instr_start[lj] = 1; - tcg_ctx.gen_opc_icount[lj] = num_insns; + tcg_gen_insn_start(dc->pc); + num_insns++; + + if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { + gen_exception(dc, dc->pc, EXCP_DEBUG); + dc->is_jmp = DISAS_JUMP; + /* The address covered by the breakpoint must be included in + [tb->pc, tb->pc + tb->size) in order to for it to be + properly cleared -- thus we increment the PC here so that + the logic setting tb->size below does the right thing. */ + dc->pc += 2; + break; } - if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + + if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); + } + dc->insn_pc = dc->pc; disas_m68k_insn(env, dc); - num_insns++; - } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end && - !env->singlestep_enabled && + } while (!dc->is_jmp && !tcg_op_buf_full() && + !cs->singlestep_enabled && !singlestep && (pc_offset) < (TARGET_PAGE_SIZE - 32) && num_insns < max_insns); if (tb->cflags & CF_LAST_IO) gen_io_end(); - if (unlikely(env->singlestep_enabled)) { + if (unlikely(cs->singlestep_enabled)) { /* Make sure the pc is updated, and raise a debug exception. */ if (!dc->is_jmp) { gen_flush_cc_op(dc); @@ -3063,44 +3053,25 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, break; } } - gen_icount_end(tb, num_insns); - *tcg_ctx.gen_opc_ptr = INDEX_op_end; + gen_tb_end(tb, num_insns); #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("----------------\n"); qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(env, pc_start, dc->pc - pc_start, 0); + log_target_disas(cs, pc_start, dc->pc - pc_start, 0); qemu_log("\n"); } #endif - if (search_pc) { - j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; - lj++; - while (lj <= j) - tcg_ctx.gen_opc_instr_start[lj++] = 0; - } else { - tb->size = dc->pc - pc_start; - tb->icount = num_insns; - } - - //optimize_flags(); - //expand_target_qops(); -} - -void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb) -{ - gen_intermediate_code_internal(env, tb, 0); -} - -void gen_intermediate_code_pc(CPUM68KState *env, TranslationBlock *tb) -{ - gen_intermediate_code_internal(env, tb, 1); + tb->size = dc->pc - pc_start; + tb->icount = num_insns; } -void cpu_dump_state(CPUM68KState *env, FILE *f, fprintf_function cpu_fprintf, - int flags) +void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, + int flags) { + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; int i; uint16_t sr; CPU_DoubleU u; @@ -3119,7 +3090,8 @@ void cpu_dump_state(CPUM68KState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result); } -void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb, int pc_pos) +void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb, + target_ulong *data) { - env->pc = tcg_ctx.gen_opc_pc[pc_pos]; + env->pc = data[0]; }