Convert to TranslatorOps

I've updated the series to fix conflicts with:
 
 21528149eb target/m68k: Add trailing '\n' to qemu_log() call
 07ea28b418 tcg: Pass tb and index to tcg_gen_exit_tb separately
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJbHlOUAAoJEPMMOL0/L748GSsP/RcvWEDEW5ty4jHVi5tVerfq
 nKTafwiErmcQkcw9caZ+d3+cxKphGQ5iKbROlILXF+yWehKPx62iyOVH+O6gfWu7
 Y/sDxOj21+4D5zm9TE5uYP8KJ7tFyLm8UrQ9pu70NFScu+sPU3cxBVlSmermtSLv
 CXnXQGLeyAIPsSvy+3sPXql0RSi+0+xB6B2yUt1hedI5OHejuC25N7mhPvEDlykq
 +DkEbZc7c/+mq1xfwrA27fLmkq15S8Kxye0HwJWnEZgaqO2dYZWPp5+xIXkp6uK3
 1AoAGLyt4jUlwlZbvK/VVEaI4N8NYmCd57/SVmiR9tWwx62eI3xZhRm/8B+Mzpv2
 U/NdPpP9DrrIJ0mV5QT3HTT3lv1MRfVXetRXlpLaQ1SipBwn74ZPzpvFdrO1qv+0
 98x2MB0FxGCo7+YRM/LfQXvoBeVF4dx64o7CJW2ETv9qjNBURrPQ+HW+4rhU91qR
 6m7XqR4tyoZ6H1zLrkLZDZ5YX8IpZd5A2Ukn0QgEL5txcXM7aqlB0YcYV031AU4d
 nJBUGiGUm1BphWuF2qwoUaafNQx56aWhMzdH3mTBHFGiQm90K5n6Zr8t4HD9/+w+
 UAXvM8a8plja/veRcZJLgdkcgvrOaW07Zxr4etl6UUXvMi+mFWttJhgXyQjJdMNI
 DhbAKw8VH6tJ2qfX3fhD
 =Lqby
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-3.0-pull-request' into staging

Convert to TranslatorOps

I've updated the series to fix conflicts with:

21528149eb target/m68k: Add trailing '\n' to qemu_log() call
07ea28b418 tcg: Pass tb and index to tcg_gen_exit_tb separately

# gpg: Signature made Mon 11 Jun 2018 11:48:52 BST
# gpg:                using RSA key F30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>"
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier/tags/m68k-for-3.0-pull-request:
  target/m68k: Merge disas_m68k_insn into m68k_tr_translate_insn
  target/m68k: Improve ending TB at page boundaries
  target/m68k: Convert to TranslatorOps
  target/m68k: Convert to DisasContextBase
  target/m68k: Rename DISAS_UPDATE and gen_lookup_tb
  target/m68k: Use lookup_and_goto_tb for DISAS_JUMP
  target/m68k: Remove DISAS_JUMP_NEXT as unused
  target/m68k: Replace DISAS_TB_JUMP with DISAS_NORETURN
  target/m68k: Use DISAS_NORETURN for exceptions

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-06-11 12:46:16 +01:00
commit 9f55925b8f

View File

@ -111,14 +111,11 @@ void m68k_tcg_init(void)
/* internal defines */ /* internal defines */
typedef struct DisasContext { typedef struct DisasContext {
DisasContextBase base;
CPUM68KState *env; CPUM68KState *env;
target_ulong insn_pc; /* Start of the current instruction. */
target_ulong pc; target_ulong pc;
int is_jmp;
CCOp cc_op; /* Current CC operation */ CCOp cc_op; /* Current CC operation */
int cc_op_synced; int cc_op_synced;
struct TranslationBlock *tb;
int singlestep_enabled;
TCGv_i64 mactmp; TCGv_i64 mactmp;
int done_mac; int done_mac;
int writeback_mask; int writeback_mask;
@ -198,17 +195,15 @@ static void do_writebacks(DisasContext *s)
/* is_jmp field values */ /* is_jmp field values */
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ #define DISAS_EXIT DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
#define DISAS_JUMP_NEXT DISAS_TARGET_3
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1 #define IS_USER(s) 1
#else #else
#define IS_USER(s) (!(s->tb->flags & TB_FLAGS_MSR_S)) #define IS_USER(s) (!(s->base.tb->flags & TB_FLAGS_MSR_S))
#define SFC_INDEX(s) ((s->tb->flags & TB_FLAGS_SFC_S) ? \ #define SFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_SFC_S) ? \
MMU_KERNEL_IDX : MMU_USER_IDX) MMU_KERNEL_IDX : MMU_USER_IDX)
#define DFC_INDEX(s) ((s->tb->flags & TB_FLAGS_DFC_S) ? \ #define DFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_DFC_S) ? \
MMU_KERNEL_IDX : MMU_USER_IDX) MMU_KERNEL_IDX : MMU_USER_IDX)
#endif #endif
@ -280,7 +275,7 @@ static void gen_jmp_im(DisasContext *s, uint32_t dest)
{ {
update_cc_op(s); update_cc_op(s);
tcg_gen_movi_i32(QREG_PC, dest); tcg_gen_movi_i32(QREG_PC, dest);
s->is_jmp = DISAS_JUMP; s->base.is_jmp = DISAS_JUMP;
} }
/* Generate a jump to the address in qreg DEST. */ /* Generate a jump to the address in qreg DEST. */
@ -288,26 +283,26 @@ static void gen_jmp(DisasContext *s, TCGv dest)
{ {
update_cc_op(s); update_cc_op(s);
tcg_gen_mov_i32(QREG_PC, dest); tcg_gen_mov_i32(QREG_PC, dest);
s->is_jmp = DISAS_JUMP; s->base.is_jmp = DISAS_JUMP;
} }
static void gen_raise_exception(int nr) static void gen_exception(DisasContext *s, uint32_t dest, int nr)
{ {
TCGv_i32 tmp = tcg_const_i32(nr); TCGv_i32 tmp;
update_cc_op(s);
tcg_gen_movi_i32(QREG_PC, dest);
tmp = tcg_const_i32(nr);
gen_helper_raise_exception(cpu_env, tmp); gen_helper_raise_exception(cpu_env, tmp);
tcg_temp_free_i32(tmp); tcg_temp_free_i32(tmp);
}
static void gen_exception(DisasContext *s, uint32_t where, int nr) s->base.is_jmp = DISAS_NORETURN;
{
gen_jmp_im(s, where);
gen_raise_exception(nr);
} }
static inline void gen_addr_fault(DisasContext *s) static inline void gen_addr_fault(DisasContext *s)
{ {
gen_exception(s, s->insn_pc, EXCP_ADDRESS); gen_exception(s, s->base.pc_next, EXCP_ADDRESS);
} }
/* Generate a load from the specified address. Narrow values are /* Generate a load from the specified address. Narrow values are
@ -1005,7 +1000,7 @@ static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
break; break;
case OS_EXTENDED: case OS_EXTENDED:
if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) { if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP); gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
break; break;
} }
tcg_gen_qemu_ld32u(tmp, addr, index); tcg_gen_qemu_ld32u(tmp, addr, index);
@ -1019,7 +1014,7 @@ static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
/* unimplemented data type on 68040/ColdFire /* unimplemented data type on 68040/ColdFire
* FIXME if needed for another FPU * FIXME if needed for another FPU
*/ */
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP); gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
break; break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
@ -1059,7 +1054,7 @@ static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
break; break;
case OS_EXTENDED: case OS_EXTENDED:
if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) { if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP); gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
break; break;
} }
tcg_gen_ld16u_i32(tmp, fp, offsetof(FPReg, l.upper)); tcg_gen_ld16u_i32(tmp, fp, offsetof(FPReg, l.upper));
@ -1073,7 +1068,7 @@ static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
/* unimplemented data type on 68040/ColdFire /* unimplemented data type on 68040/ColdFire
* FIXME if needed for another FPU * FIXME if needed for another FPU
*/ */
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP); gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
break; break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
@ -1205,7 +1200,7 @@ static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
break; break;
case OS_EXTENDED: case OS_EXTENDED:
if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) { if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP); gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
break; break;
} }
tmp = tcg_const_i32(read_im32(env, s) >> 16); tmp = tcg_const_i32(read_im32(env, s) >> 16);
@ -1219,7 +1214,7 @@ static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
/* unimplemented data type on 68040/ColdFire /* unimplemented data type on 68040/ColdFire
* FIXME if needed for another FPU * FIXME if needed for another FPU
*/ */
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP); gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
break; break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
@ -1448,11 +1443,11 @@ static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1)
} }
/* Force a TB lookup after an instruction that changes the CPU state. */ /* Force a TB lookup after an instruction that changes the CPU state. */
static void gen_lookup_tb(DisasContext *s) static void gen_exit_tb(DisasContext *s)
{ {
update_cc_op(s); update_cc_op(s);
tcg_gen_movi_i32(QREG_PC, s->pc); tcg_gen_movi_i32(QREG_PC, s->pc);
s->is_jmp = DISAS_UPDATE; s->base.is_jmp = DISAS_EXIT;
} }
#define SRC_EA(env, result, opsize, op_sign, addrp) do { \ #define SRC_EA(env, result, opsize, op_sign, addrp) do { \
@ -1476,8 +1471,8 @@ static void gen_lookup_tb(DisasContext *s)
static inline bool use_goto_tb(DisasContext *s, uint32_t dest) static inline bool use_goto_tb(DisasContext *s, uint32_t dest)
{ {
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || return (s->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)
(s->insn_pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); || (s->base.pc_next & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
#else #else
return true; return true;
#endif #endif
@ -1486,17 +1481,17 @@ static inline bool use_goto_tb(DisasContext *s, uint32_t dest)
/* Generate a jump to an immediate address. */ /* Generate a jump to an immediate address. */
static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
{ {
if (unlikely(s->singlestep_enabled)) { if (unlikely(s->base.singlestep_enabled)) {
gen_exception(s, dest, EXCP_DEBUG); gen_exception(s, dest, EXCP_DEBUG);
} else if (use_goto_tb(s, dest)) { } else if (use_goto_tb(s, dest)) {
tcg_gen_goto_tb(n); tcg_gen_goto_tb(n);
tcg_gen_movi_i32(QREG_PC, dest); tcg_gen_movi_i32(QREG_PC, dest);
tcg_gen_exit_tb(s->tb, n); tcg_gen_exit_tb(s->base.tb, n);
} else { } else {
gen_jmp_im(s, dest); gen_jmp_im(s, dest);
tcg_gen_exit_tb(NULL, 0); tcg_gen_exit_tb(NULL, 0);
} }
s->is_jmp = DISAS_TB_JUMP; s->base.is_jmp = DISAS_NORETURN;
} }
DISAS_INSN(scc) DISAS_INSN(scc)
@ -1543,12 +1538,12 @@ DISAS_INSN(dbcc)
DISAS_INSN(undef_mac) DISAS_INSN(undef_mac)
{ {
gen_exception(s, s->insn_pc, EXCP_LINEA); gen_exception(s, s->base.pc_next, EXCP_LINEA);
} }
DISAS_INSN(undef_fpu) DISAS_INSN(undef_fpu)
{ {
gen_exception(s, s->insn_pc, EXCP_LINEF); gen_exception(s, s->base.pc_next, EXCP_LINEF);
} }
DISAS_INSN(undef) DISAS_INSN(undef)
@ -1557,8 +1552,8 @@ DISAS_INSN(undef)
for the 680x0 series, as well as those that are implemented for the 680x0 series, as well as those that are implemented
but actually illegal for CPU32 or pre-68020. */ but actually illegal for CPU32 or pre-68020. */
qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n", qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n",
insn, s->insn_pc); insn, s->base.pc_next);
gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED); gen_exception(s, s->base.pc_next, EXCP_UNSUPPORTED);
} }
DISAS_INSN(mulw) DISAS_INSN(mulw)
@ -1618,7 +1613,7 @@ DISAS_INSN(divl)
if (ext & 0x400) { if (ext & 0x400) {
if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) { if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
gen_exception(s, s->insn_pc, EXCP_ILLEGAL); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
return; return;
} }
@ -2312,7 +2307,7 @@ DISAS_INSN(arith_im)
break; break;
case OS_WORD: case OS_WORD:
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
src1 = gen_get_sr(s); src1 = gen_get_sr(s);
@ -2481,7 +2476,7 @@ DISAS_INSN(cas2w)
(REG(ext1, 6) << 3) | (REG(ext1, 6) << 3) |
(REG(ext2, 0) << 6) | (REG(ext2, 0) << 6) |
(REG(ext1, 0) << 9)); (REG(ext1, 0) << 9));
if (tb_cflags(s->tb) & CF_PARALLEL) { if (tb_cflags(s->base.tb) & CF_PARALLEL) {
gen_helper_exit_atomic(cpu_env); gen_helper_exit_atomic(cpu_env);
} else { } else {
gen_helper_cas2w(cpu_env, regs, addr1, addr2); gen_helper_cas2w(cpu_env, regs, addr1, addr2);
@ -2531,7 +2526,7 @@ DISAS_INSN(cas2l)
(REG(ext1, 6) << 3) | (REG(ext1, 6) << 3) |
(REG(ext2, 0) << 6) | (REG(ext2, 0) << 6) |
(REG(ext1, 0) << 9)); (REG(ext1, 0) << 9));
if (tb_cflags(s->tb) & CF_PARALLEL) { if (tb_cflags(s->base.tb) & CF_PARALLEL) {
gen_helper_cas2l_parallel(cpu_env, regs, addr1, addr2); gen_helper_cas2l_parallel(cpu_env, regs, addr1, addr2);
} else { } else {
gen_helper_cas2l(cpu_env, regs, addr1, addr2); gen_helper_cas2l(cpu_env, regs, addr1, addr2);
@ -2722,7 +2717,7 @@ DISAS_INSN(swap)
DISAS_INSN(bkpt) DISAS_INSN(bkpt)
{ {
gen_exception(s, s->insn_pc, EXCP_DEBUG); gen_exception(s, s->base.pc_next, EXCP_DEBUG);
} }
DISAS_INSN(pea) DISAS_INSN(pea)
@ -2775,7 +2770,7 @@ DISAS_INSN(pulse)
DISAS_INSN(illegal) DISAS_INSN(illegal)
{ {
gen_exception(s, s->insn_pc, EXCP_ILLEGAL); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
} }
/* ??? This should be atomic. */ /* ??? This should be atomic. */
@ -2805,7 +2800,7 @@ DISAS_INSN(mull)
if (ext & 0x400) { if (ext & 0x400) {
if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) { if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED); gen_exception(s, s->base.pc_next, EXCP_UNSUPPORTED);
return; return;
} }
@ -2906,7 +2901,7 @@ DISAS_INSN(unlk)
DISAS_INSN(reset) DISAS_INSN(reset)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
@ -4377,7 +4372,7 @@ DISAS_INSN(chk)
} }
/* fallthru */ /* fallthru */
default: default:
gen_exception(s, s->insn_pc, EXCP_ILLEGAL); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
return; return;
} }
SRC_EA(env, src, opsize, 1, NULL); SRC_EA(env, src, opsize, 1, NULL);
@ -4404,13 +4399,13 @@ DISAS_INSN(chk2)
opsize = OS_LONG; opsize = OS_LONG;
break; break;
default: default:
gen_exception(s, s->insn_pc, EXCP_ILLEGAL); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
return; return;
} }
ext = read_im16(env, s); ext = read_im16(env, s);
if ((ext & 0x0800) == 0) { if ((ext & 0x0800) == 0) {
gen_exception(s, s->insn_pc, EXCP_ILLEGAL); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
return; return;
} }
@ -4470,7 +4465,7 @@ DISAS_INSN(move16_reg)
ext = read_im16(env, s); ext = read_im16(env, s);
if ((ext & (1 << 15)) == 0) { if ((ext & (1 << 15)) == 0) {
gen_exception(s, s->insn_pc, EXCP_ILLEGAL); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
} }
m68k_copy_line(AREG(ext, 12), AREG(insn, 0), index); m68k_copy_line(AREG(ext, 12), AREG(insn, 0), index);
@ -4532,7 +4527,7 @@ DISAS_INSN(move_from_sr)
TCGv sr; TCGv sr;
if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) { if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
sr = gen_get_sr(s); sr = gen_get_sr(s);
@ -4549,7 +4544,7 @@ DISAS_INSN(moves)
int extend; int extend;
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
@ -4602,17 +4597,17 @@ DISAS_INSN(moves)
DISAS_INSN(move_to_sr) DISAS_INSN(move_to_sr)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
gen_move_to_sr(env, s, insn, false); gen_move_to_sr(env, s, insn, false);
gen_lookup_tb(s); gen_exit_tb(s);
} }
DISAS_INSN(move_from_usp) DISAS_INSN(move_from_usp)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
tcg_gen_ld_i32(AREG(insn, 0), cpu_env, tcg_gen_ld_i32(AREG(insn, 0), cpu_env,
@ -4622,7 +4617,7 @@ DISAS_INSN(move_from_usp)
DISAS_INSN(move_to_usp) DISAS_INSN(move_to_usp)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
tcg_gen_st_i32(AREG(insn, 0), cpu_env, tcg_gen_st_i32(AREG(insn, 0), cpu_env,
@ -4632,7 +4627,7 @@ DISAS_INSN(move_to_usp)
DISAS_INSN(halt) DISAS_INSN(halt)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
@ -4644,7 +4639,7 @@ DISAS_INSN(stop)
uint16_t ext; uint16_t ext;
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
@ -4658,10 +4653,10 @@ DISAS_INSN(stop)
DISAS_INSN(rte) DISAS_INSN(rte)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
gen_exception(s, s->insn_pc, EXCP_RTE); gen_exception(s, s->base.pc_next, EXCP_RTE);
} }
DISAS_INSN(cf_movec) DISAS_INSN(cf_movec)
@ -4670,7 +4665,7 @@ DISAS_INSN(cf_movec)
TCGv reg; TCGv reg;
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
@ -4682,7 +4677,7 @@ DISAS_INSN(cf_movec)
reg = DREG(ext, 12); reg = DREG(ext, 12);
} }
gen_helper_cf_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg); gen_helper_cf_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg);
gen_lookup_tb(s); gen_exit_tb(s);
} }
DISAS_INSN(m68k_movec) DISAS_INSN(m68k_movec)
@ -4691,7 +4686,7 @@ DISAS_INSN(m68k_movec)
TCGv reg; TCGv reg;
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
@ -4707,13 +4702,13 @@ DISAS_INSN(m68k_movec)
} else { } else {
gen_helper_m68k_movec_from(reg, cpu_env, tcg_const_i32(ext & 0xfff)); gen_helper_m68k_movec_from(reg, cpu_env, tcg_const_i32(ext & 0xfff));
} }
gen_lookup_tb(s); gen_exit_tb(s);
} }
DISAS_INSN(intouch) DISAS_INSN(intouch)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
/* ICache fetch. Implement as no-op. */ /* ICache fetch. Implement as no-op. */
@ -4722,7 +4717,7 @@ DISAS_INSN(intouch)
DISAS_INSN(cpushl) DISAS_INSN(cpushl)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
/* Cache push/invalidate. Implement as no-op. */ /* Cache push/invalidate. Implement as no-op. */
@ -4731,7 +4726,7 @@ DISAS_INSN(cpushl)
DISAS_INSN(cpush) DISAS_INSN(cpush)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
/* Cache push/invalidate. Implement as no-op. */ /* Cache push/invalidate. Implement as no-op. */
@ -4740,7 +4735,7 @@ DISAS_INSN(cpush)
DISAS_INSN(cinv) DISAS_INSN(cinv)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
/* Invalidate cache line. Implement as no-op. */ /* Invalidate cache line. Implement as no-op. */
@ -4752,7 +4747,7 @@ DISAS_INSN(pflush)
TCGv opmode; TCGv opmode;
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
@ -4766,7 +4761,7 @@ DISAS_INSN(ptest)
TCGv is_read; TCGv is_read;
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
is_read = tcg_const_i32((insn >> 5) & 1); is_read = tcg_const_i32((insn >> 5) & 1);
@ -4777,7 +4772,7 @@ DISAS_INSN(ptest)
DISAS_INSN(wddata) DISAS_INSN(wddata)
{ {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
} }
DISAS_INSN(wdebug) DISAS_INSN(wdebug)
@ -4785,7 +4780,7 @@ DISAS_INSN(wdebug)
M68kCPU *cpu = m68k_env_get_cpu(env); M68kCPU *cpu = m68k_env_get_cpu(env);
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
/* TODO: Implement wdebug. */ /* TODO: Implement wdebug. */
@ -4795,7 +4790,7 @@ DISAS_INSN(wdebug)
DISAS_INSN(trap) DISAS_INSN(trap)
{ {
gen_exception(s, s->insn_pc, EXCP_TRAP0 + (insn & 0xf)); gen_exception(s, s->base.pc_next, EXCP_TRAP0 + (insn & 0xf));
} }
static void gen_load_fcr(DisasContext *s, TCGv res, int reg) static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
@ -4862,7 +4857,7 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
switch (mode) { switch (mode) {
case 0: /* Dn */ case 0: /* Dn */
if (mask != M68K_FPIAR && mask != M68K_FPSR && mask != M68K_FPCR) { if (mask != M68K_FPIAR && mask != M68K_FPSR && mask != M68K_FPCR) {
gen_exception(s, s->insn_pc, EXCP_ILLEGAL); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
return; return;
} }
if (is_write) { if (is_write) {
@ -4873,7 +4868,7 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
return; return;
case 1: /* An, only with FPIAR */ case 1: /* An, only with FPIAR */
if (mask != M68K_FPIAR) { if (mask != M68K_FPIAR) {
gen_exception(s, s->insn_pc, EXCP_ILLEGAL); gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
return; return;
} }
if (is_write) { if (is_write) {
@ -5431,7 +5426,7 @@ DISAS_INSN(frestore)
TCGv addr; TCGv addr;
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
if (m68k_feature(s->env, M68K_FEATURE_M68040)) { if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
@ -5445,7 +5440,7 @@ DISAS_INSN(frestore)
DISAS_INSN(fsave) DISAS_INSN(fsave)
{ {
if (IS_USER(s)) { if (IS_USER(s)) {
gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
return; return;
} }
@ -5751,7 +5746,7 @@ DISAS_INSN(to_macsr)
TCGv val; TCGv val;
SRC_EA(env, val, OS_LONG, 0, NULL); SRC_EA(env, val, OS_LONG, 0, NULL);
gen_helper_set_macsr(cpu_env, val); gen_helper_set_macsr(cpu_env, val);
gen_lookup_tb(s); gen_exit_tb(s);
} }
DISAS_INSN(to_mask) DISAS_INSN(to_mask)
@ -6054,121 +6049,130 @@ void register_m68k_insns (CPUM68KState *env)
#undef INSN #undef INSN
} }
/* ??? Some of this implementation is not exception safe. We should always static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
write back the result to memory before setting the condition codes. */
static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
{ {
uint16_t insn = read_im16(env, s); DisasContext *dc = container_of(dcbase, DisasContext, base);
opcode_table[insn](env, s, insn); CPUM68KState *env = cpu->env_ptr;
do_writebacks(s);
do_release(s);
}
/* generate intermediate code for basic block 'tb'. */
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
{
CPUM68KState *env = cs->env_ptr;
DisasContext dc1, *dc = &dc1;
target_ulong pc_start;
int pc_offset;
int num_insns;
int max_insns;
/* generate intermediate code */
pc_start = tb->pc;
dc->tb = tb;
dc->env = env; dc->env = env;
dc->is_jmp = DISAS_NEXT; dc->pc = dc->base.pc_first;
dc->pc = pc_start;
dc->cc_op = CC_OP_DYNAMIC; dc->cc_op = CC_OP_DYNAMIC;
dc->cc_op_synced = 1; dc->cc_op_synced = 1;
dc->singlestep_enabled = cs->singlestep_enabled;
dc->done_mac = 0; dc->done_mac = 0;
dc->writeback_mask = 0; dc->writeback_mask = 0;
num_insns = 0;
max_insns = tb_cflags(tb) & CF_COUNT_MASK;
if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
}
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS;
}
init_release_array(dc); init_release_array(dc);
}
gen_tb_start(tb); static void m68k_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
do { {
pc_offset = dc->pc - pc_start; }
tcg_gen_insn_start(dc->pc, dc->cc_op);
num_insns++;
if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { static void m68k_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
gen_exception(dc, dc->pc, EXCP_DEBUG); {
dc->is_jmp = DISAS_JUMP; DisasContext *dc = container_of(dcbase, DisasContext, base);
/* The address covered by the breakpoint must be included in tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
[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. */ static bool m68k_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
dc->pc += 2; const CPUBreakpoint *bp)
break; {
DisasContext *dc = container_of(dcbase, DisasContext, base);
gen_exception(dc, dc->base.pc_next, EXCP_DEBUG);
/* 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->base.pc_next += 2;
return true;
}
static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUM68KState *env = cpu->env_ptr;
uint16_t insn = read_im16(env, dc);
opcode_table[insn](env, dc, insn);
do_writebacks(dc);
do_release(dc);
dc->base.pc_next = dc->pc;
if (dc->base.is_jmp == DISAS_NEXT) {
/* Stop translation when the next insn might touch a new page.
* This ensures that prefetch aborts at the right place.
*
* We cannot determine the size of the next insn without
* completely decoding it. However, the maximum insn size
* is 32 bytes, so end if we do not have that much remaining.
* This may produce several small TBs at the end of each page,
* but they will all be linked with goto_tb.
*
* ??? ColdFire maximum is 4 bytes; MC68000's maximum is also
* smaller than MC68020's.
*/
target_ulong start_page_offset
= dc->pc - (dc->base.pc_first & TARGET_PAGE_MASK);
if (start_page_offset >= TARGET_PAGE_SIZE - 32) {
dc->base.is_jmp = DISAS_TOO_MANY;
} }
}
}
if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
gen_io_start(); {
} DisasContext *dc = container_of(dcbase, DisasContext, base);
dc->insn_pc = dc->pc; if (dc->base.is_jmp == DISAS_NORETURN) {
disas_m68k_insn(env, dc); return;
} while (!dc->is_jmp && !tcg_op_buf_full() && }
!cs->singlestep_enabled && if (dc->base.singlestep_enabled) {
!singlestep &&
(pc_offset) < (TARGET_PAGE_SIZE - 32) &&
num_insns < max_insns);
if (tb_cflags(tb) & CF_LAST_IO)
gen_io_end();
if (unlikely(cs->singlestep_enabled)) {
/* Make sure the pc is updated, and raise a debug exception. */
if (!dc->is_jmp) {
update_cc_op(dc);
tcg_gen_movi_i32(QREG_PC, dc->pc);
}
gen_helper_raise_exception(cpu_env, tcg_const_i32(EXCP_DEBUG)); gen_helper_raise_exception(cpu_env, tcg_const_i32(EXCP_DEBUG));
} else { return;
switch(dc->is_jmp) {
case DISAS_NEXT:
update_cc_op(dc);
gen_jmp_tb(dc, 0, dc->pc);
break;
default:
case DISAS_JUMP:
case DISAS_UPDATE:
update_cc_op(dc);
/* indicate that the hash table must be used to find the next TB */
tcg_gen_exit_tb(NULL, 0);
break;
case DISAS_TB_JUMP:
/* nothing more to generate */
break;
}
} }
gen_tb_end(tb, num_insns);
#ifdef DEBUG_DISAS switch (dc->base.is_jmp) {
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) case DISAS_TOO_MANY:
&& qemu_log_in_addr_range(pc_start)) { update_cc_op(dc);
qemu_log_lock(); gen_jmp_tb(dc, 0, dc->pc);
qemu_log("----------------\n"); break;
qemu_log("IN: %s\n", lookup_symbol(pc_start)); case DISAS_JUMP:
log_target_disas(cs, pc_start, dc->pc - pc_start); /* We updated CC_OP and PC in gen_jmp/gen_jmp_im. */
qemu_log("\n"); tcg_gen_lookup_and_goto_ptr();
qemu_log_unlock(); break;
case DISAS_EXIT:
/* We updated CC_OP and PC in gen_exit_tb, but also modified
other state that may require returning to the main loop. */
tcg_gen_exit_tb(NULL, 0);
break;
default:
g_assert_not_reached();
} }
#endif }
tb->size = dc->pc - pc_start;
tb->icount = num_insns; static void m68k_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
{
qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
}
static const TranslatorOps m68k_tr_ops = {
.init_disas_context = m68k_tr_init_disas_context,
.tb_start = m68k_tr_tb_start,
.insn_start = m68k_tr_insn_start,
.breakpoint_check = m68k_tr_breakpoint_check,
.translate_insn = m68k_tr_translate_insn,
.tb_stop = m68k_tr_tb_stop,
.disas_log = m68k_tr_disas_log,
};
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
{
DisasContext dc;
translator_loop(&m68k_tr_ops, &dc.base, cpu, tb);
} }
static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low) static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low)