--- qemu/target-mips/translate.c 2018/04/24 16:49:37 1.1.1.6 +++ qemu/target-mips/translate.c 2018/04/24 19:31:31 1.1.1.15 @@ -4,6 +4,7 @@ * Copyright (c) 2004-2005 Jocelyn Mayer * Copyright (c) 2006 Marius Groeger (FPU operations) * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) + * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,8 +17,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License along with this library; if not, see . */ #include @@ -27,30 +27,16 @@ #include #include "cpu.h" -#include "exec-all.h" #include "disas.h" +#include "tcg-op.h" +#include "qemu-common.h" + +#include "helper.h" +#define GEN_HELPER 1 +#include "helper.h" //#define MIPS_DEBUG_DISAS //#define MIPS_DEBUG_SIGN_EXTENSIONS -//#define MIPS_SINGLE_STEP - -#ifdef USE_DIRECT_JUMP -#define TBPARAM(x) -#else -#define TBPARAM(x) (long)(x) -#endif - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc.h" -#undef DEF - NB_OPS, -}; - -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; - -#include "gen-op.h" /* MIPS major opcodes */ #define MASK_OP_MAJOR(op) (op & (0x3F << 26)) @@ -70,15 +56,18 @@ enum { OPC_ADDIU = (0x09 << 26), OPC_SLTI = (0x0A << 26), OPC_SLTIU = (0x0B << 26), + /* logic with immediate */ OPC_ANDI = (0x0C << 26), OPC_ORI = (0x0D << 26), OPC_XORI = (0x0E << 26), OPC_LUI = (0x0F << 26), + /* arithmetic with immediate */ OPC_DADDI = (0x18 << 26), OPC_DADDIU = (0x19 << 26), /* Jump and branches */ OPC_J = (0x02 << 26), OPC_JAL = (0x03 << 26), + OPC_JALS = OPC_JAL | 0x5, OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ OPC_BEQL = (0x14 << 26), OPC_BNE = (0x05 << 26), @@ -88,6 +77,7 @@ enum { OPC_BGTZ = (0x07 << 26), OPC_BGTZL = (0x17 << 26), OPC_JALX = (0x1D << 26), /* MIPS 16 only */ + OPC_JALXS = OPC_JALX | 0x5, /* Load and stores */ OPC_LDL = (0x1A << 26), OPC_LDR = (0x1B << 26), @@ -95,6 +85,7 @@ enum { OPC_LH = (0x21 << 26), OPC_LWL = (0x22 << 26), OPC_LW = (0x23 << 26), + OPC_LWPC = OPC_LW | 0x5, OPC_LBU = (0x24 << 26), OPC_LHU = (0x25 << 26), OPC_LWR = (0x26 << 26), @@ -109,6 +100,7 @@ enum { OPC_LL = (0x30 << 26), OPC_LLD = (0x34 << 26), OPC_LD = (0x37 << 26), + OPC_LDPC = OPC_LD | 0x5, OPC_SC = (0x38 << 26), OPC_SCD = (0x3C << 26), OPC_SD = (0x3F << 26), @@ -140,18 +132,23 @@ enum { /* SSNOP is SLL r0, r0, 1 */ /* EHB is SLL r0, r0, 3 */ OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */ + OPC_ROTR = OPC_SRL | (1 << 21), OPC_SRA = 0x03 | OPC_SPECIAL, OPC_SLLV = 0x04 | OPC_SPECIAL, OPC_SRLV = 0x06 | OPC_SPECIAL, /* also ROTRV */ + OPC_ROTRV = OPC_SRLV | (1 << 6), OPC_SRAV = 0x07 | OPC_SPECIAL, OPC_DSLLV = 0x14 | OPC_SPECIAL, OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */ + OPC_DROTRV = OPC_DSRLV | (1 << 6), OPC_DSRAV = 0x17 | OPC_SPECIAL, OPC_DSLL = 0x38 | OPC_SPECIAL, OPC_DSRL = 0x3A | OPC_SPECIAL, /* also DROTR */ + OPC_DROTR = OPC_DSRL | (1 << 21), OPC_DSRA = 0x3B | OPC_SPECIAL, OPC_DSLL32 = 0x3C | OPC_SPECIAL, OPC_DSRL32 = 0x3E | OPC_SPECIAL, /* also DROTR32 */ + OPC_DROTR32 = OPC_DSRL32 | (1 << 21), OPC_DSRA32 = 0x3F | OPC_SPECIAL, /* Multiplication / division */ OPC_MULT = 0x18 | OPC_SPECIAL, @@ -180,6 +177,8 @@ enum { /* Jumps */ OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */ OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */ + OPC_JALRC = OPC_JALR | (0x5 << 6), + OPC_JALRS = 0x10 | OPC_SPECIAL | (0x5 << 6), /* Traps */ OPC_TGE = 0x30 | OPC_SPECIAL, OPC_TGEU = 0x31 | OPC_SPECIAL, @@ -199,10 +198,10 @@ enum { OPC_MOVCI = 0x01 | OPC_SPECIAL, /* Special */ - OPC_PMON = 0x05 | OPC_SPECIAL, /* inofficial */ + OPC_PMON = 0x05 | OPC_SPECIAL, /* unofficial */ OPC_SYSCALL = 0x0C | OPC_SPECIAL, OPC_BREAK = 0x0D | OPC_SPECIAL, - OPC_SPIM = 0x0E | OPC_SPECIAL, /* inofficial */ + OPC_SPIM = 0x0E | OPC_SPECIAL, /* unofficial */ OPC_SYNC = 0x0F | OPC_SPECIAL, OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL, @@ -243,8 +242,10 @@ enum { OPC_BGEZ = (0x01 << 16) | OPC_REGIMM, OPC_BGEZL = (0x03 << 16) | OPC_REGIMM, OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM, + OPC_BLTZALS = OPC_BLTZAL | 0x5, /* microMIPS */ OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM, OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM, + OPC_BGEZALS = OPC_BGEZAL | 0x5, /* microMIPS */ OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM, OPC_TGEI = (0x08 << 16) | OPC_REGIMM, OPC_TGEIU = (0x09 << 16) | OPC_REGIMM, @@ -265,6 +266,19 @@ enum { OPC_MUL = 0x02 | OPC_SPECIAL2, OPC_MSUB = 0x04 | OPC_SPECIAL2, OPC_MSUBU = 0x05 | OPC_SPECIAL2, + /* Loongson 2F */ + OPC_MULT_G_2F = 0x10 | OPC_SPECIAL2, + OPC_DMULT_G_2F = 0x11 | OPC_SPECIAL2, + OPC_MULTU_G_2F = 0x12 | OPC_SPECIAL2, + OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2, + OPC_DIV_G_2F = 0x14 | OPC_SPECIAL2, + OPC_DDIV_G_2F = 0x15 | OPC_SPECIAL2, + OPC_DIVU_G_2F = 0x16 | OPC_SPECIAL2, + OPC_DDIVU_G_2F = 0x17 | OPC_SPECIAL2, + OPC_MOD_G_2F = 0x1c | OPC_SPECIAL2, + OPC_DMOD_G_2F = 0x1d | OPC_SPECIAL2, + OPC_MODU_G_2F = 0x1e | OPC_SPECIAL2, + OPC_DMODU_G_2F = 0x1f | OPC_SPECIAL2, /* Misc */ OPC_CLZ = 0x20 | OPC_SPECIAL2, OPC_CLO = 0x21 | OPC_SPECIAL2, @@ -291,6 +305,20 @@ enum { OPC_BSHFL = 0x20 | OPC_SPECIAL3, OPC_DBSHFL = 0x24 | OPC_SPECIAL3, OPC_RDHWR = 0x3B | OPC_SPECIAL3, + + /* Loongson 2E */ + OPC_MULT_G_2E = 0x18 | OPC_SPECIAL3, + OPC_MULTU_G_2E = 0x19 | OPC_SPECIAL3, + OPC_DIV_G_2E = 0x1A | OPC_SPECIAL3, + OPC_DIVU_G_2E = 0x1B | OPC_SPECIAL3, + OPC_DMULT_G_2E = 0x1C | OPC_SPECIAL3, + OPC_DMULTU_G_2E = 0x1D | OPC_SPECIAL3, + OPC_DDIV_G_2E = 0x1E | OPC_SPECIAL3, + OPC_DDIVU_G_2E = 0x1F | OPC_SPECIAL3, + OPC_MOD_G_2E = 0x22 | OPC_SPECIAL3, + OPC_MODU_G_2E = 0x23 | OPC_SPECIAL3, + OPC_DMOD_G_2E = 0x26 | OPC_SPECIAL3, + OPC_DMODU_G_2E = 0x27 | OPC_SPECIAL3, }; /* BSHFL opcodes */ @@ -357,6 +385,19 @@ enum { /* Coprocessor 1 (rs field) */ #define MASK_CP1(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) +/* Values for the fmt field in FP instructions */ +enum { + /* 0 - 15 are reserved */ + FMT_S = 16, /* single fp */ + FMT_D = 17, /* double fp */ + FMT_E = 18, /* extended fp */ + FMT_Q = 19, /* quad fp */ + FMT_W = 20, /* 32-bit fixed */ + FMT_L = 21, /* 64-bit fixed */ + FMT_PS = 22, /* paired single fp */ + /* 23 - 31 are reserved */ +}; + enum { OPC_MFC1 = (0x00 << 21) | OPC_CP1, OPC_DMFC1 = (0x01 << 21) | OPC_CP1, @@ -369,13 +410,13 @@ enum { OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1, OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1, - OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */ - OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */ - OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */ - OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */ - OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */ - OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */ - OPC_PS_FMT = (0x16 << 21) | OPC_CP1, /* 22: fmt=paired single fp */ + OPC_S_FMT = (FMT_S << 21) | OPC_CP1, + OPC_D_FMT = (FMT_D << 21) | OPC_CP1, + OPC_E_FMT = (FMT_E << 21) | OPC_CP1, + OPC_Q_FMT = (FMT_Q << 21) | OPC_CP1, + OPC_W_FMT = (FMT_W << 21) | OPC_CP1, + OPC_L_FMT = (FMT_L << 21) | OPC_CP1, + OPC_PS_FMT = (FMT_PS << 21) | OPC_CP1, }; #define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) @@ -437,155 +478,92 @@ enum { OPC_NMSUB_PS= 0x3E | OPC_CP3, }; +/* global register indices */ +static TCGv_ptr cpu_env; +static TCGv cpu_gpr[32], cpu_PC; +static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], cpu_ACX[MIPS_DSP_ACC]; +static TCGv cpu_dspctrl, btarget, bcond; +static TCGv_i32 hflags; +static TCGv_i32 fpu_fcr0, fpu_fcr31; + +static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; + +#include "gen-icount.h" + +#define gen_helper_0i(name, arg) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg); \ + gen_helper_##name(helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while(0) -const unsigned char *regnames[] = - { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; - -/* Warning: no function for r0 register (hard wired to zero) */ -#define GEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static always_inline void func(int n) \ -{ \ - NAME ## _table[n](); \ -} - -/* General purpose registers moves */ -GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); -GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr); -GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); - -GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); -GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); - -/* Moves to/from shadow registers */ -GEN32(gen_op_load_srsgpr_T0, gen_op_load_srsgpr_T0_gpr); -GEN32(gen_op_store_T0_srsgpr, gen_op_store_T0_srsgpr_gpr); +#define gen_helper_1i(name, arg1, arg2) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ + gen_helper_##name(arg1, helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while(0) -static const char *fregnames[] = - { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; +#define gen_helper_2i(name, arg1, arg2, arg3) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ + gen_helper_##name(arg1, arg2, helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while(0) -#define FGEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static always_inline void func(int n) \ -{ \ - NAME ## _table[n](); \ -} - -FGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); -FGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); - -FGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); -FGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); - -FGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); -FGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); - -FGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); -FGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); - -FGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); -FGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); - -FGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); -FGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); - -FGEN32(gen_op_load_fpr_WTH0, gen_op_load_fpr_WTH0_fpr); -FGEN32(gen_op_store_fpr_WTH0, gen_op_store_fpr_WTH0_fpr); - -FGEN32(gen_op_load_fpr_WTH1, gen_op_load_fpr_WTH1_fpr); -FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr); - -FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); -FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); - -#define FOP_CONDS(type, fmt) \ -static GenOpFunc1 * gen_op_cmp ## type ## _ ## fmt ## _table[16] = { \ - gen_op_cmp ## type ## _ ## fmt ## _f, \ - gen_op_cmp ## type ## _ ## fmt ## _un, \ - gen_op_cmp ## type ## _ ## fmt ## _eq, \ - gen_op_cmp ## type ## _ ## fmt ## _ueq, \ - gen_op_cmp ## type ## _ ## fmt ## _olt, \ - gen_op_cmp ## type ## _ ## fmt ## _ult, \ - gen_op_cmp ## type ## _ ## fmt ## _ole, \ - gen_op_cmp ## type ## _ ## fmt ## _ule, \ - gen_op_cmp ## type ## _ ## fmt ## _sf, \ - gen_op_cmp ## type ## _ ## fmt ## _ngle, \ - gen_op_cmp ## type ## _ ## fmt ## _seq, \ - gen_op_cmp ## type ## _ ## fmt ## _ngl, \ - gen_op_cmp ## type ## _ ## fmt ## _lt, \ - gen_op_cmp ## type ## _ ## fmt ## _nge, \ - gen_op_cmp ## type ## _ ## fmt ## _le, \ - gen_op_cmp ## type ## _ ## fmt ## _ngt, \ -}; \ -static always_inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \ -{ \ - gen_op_cmp ## type ## _ ## fmt ## _table[n](cc); \ -} - -FOP_CONDS(, d) -FOP_CONDS(abs, d) -FOP_CONDS(, s) -FOP_CONDS(abs, s) -FOP_CONDS(, ps) -FOP_CONDS(abs, ps) +#define gen_helper_3i(name, arg1, arg2, arg3, arg4) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg4); \ + gen_helper_##name(arg1, arg2, arg3, helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while(0) typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; uint32_t opcode; - uint32_t fp_status; + int singlestep_enabled; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; int bstate; target_ulong btarget; - void *last_T0_store; - int last_T0_gpr; } DisasContext; enum { BS_NONE = 0, /* We go out of the TB without reaching a branch or an - * exception condition - */ + * exception condition */ BS_STOP = 1, /* We want to stop translation for any reason */ BS_BRANCH = 2, /* We reached a branch condition */ BS_EXCP = 3, /* We reached an exception condition */ }; +static const char *regnames[] = + { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; + +static const char *regnames_HI[] = + { "HI0", "HI1", "HI2", "HI3", }; + +static const char *regnames_LO[] = + { "LO0", "LO1", "LO2", "LO3", }; + +static const char *regnames_ACX[] = + { "ACX0", "ACX1", "ACX2", "ACX3", }; + +static const char *fregnames[] = + { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; + #ifdef MIPS_DEBUG_DISAS -#define MIPS_DEBUG(fmt, args...) \ -do { \ - if (loglevel & CPU_LOG_TB_IN_ASM) { \ - fprintf(logfile, TARGET_FMT_lx ": %08x " fmt "\n", \ - ctx->pc, ctx->opcode , ##args); \ - } \ -} while (0) +#define MIPS_DEBUG(fmt, ...) \ + qemu_log_mask(CPU_LOG_TB_IN_ASM, \ + TARGET_FMT_lx ": %08x " fmt "\n", \ + ctx->pc, ctx->opcode , ## __VA_ARGS__) +#define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) #else -#define MIPS_DEBUG(fmt, args...) do { } while(0) +#define MIPS_DEBUG(fmt, ...) do { } while(0) +#define LOG_DISAS(...) do { } while (0) #endif #define MIPS_INVAL(op) \ @@ -594,201 +572,224 @@ do { ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \ } while (0) -#define GEN_LOAD_REG_T0(Rn) \ -do { \ - if (Rn == 0) { \ - gen_op_reset_T0(); \ - } else { \ - if (ctx->glue(last_T0, _store) != gen_opc_ptr \ - || ctx->glue(last_T0, _gpr) != Rn) { \ - gen_op_load_gpr_T0(Rn); \ - } \ - } \ -} while (0) +/* General purpose registers moves. */ +static inline void gen_load_gpr (TCGv t, int reg) +{ + if (reg == 0) + tcg_gen_movi_tl(t, 0); + else + tcg_gen_mov_tl(t, cpu_gpr[reg]); +} -#define GEN_LOAD_REG_T1(Rn) \ -do { \ - if (Rn == 0) { \ - gen_op_reset_T1(); \ - } else { \ - gen_op_load_gpr_T1(Rn); \ - } \ -} while (0) +static inline void gen_store_gpr (TCGv t, int reg) +{ + if (reg != 0) + tcg_gen_mov_tl(cpu_gpr[reg], t); +} -#define GEN_LOAD_REG_T2(Rn) \ -do { \ - if (Rn == 0) { \ - gen_op_reset_T2(); \ - } else { \ - gen_op_load_gpr_T2(Rn); \ - } \ -} while (0) +/* Moves to/from ACX register. */ +static inline void gen_load_ACX (TCGv t, int reg) +{ + tcg_gen_mov_tl(t, cpu_ACX[reg]); +} -#define GEN_LOAD_SRSREG_TN(Tn, Rn) \ -do { \ - if (Rn == 0) { \ - glue(gen_op_reset_, Tn)(); \ - } else { \ - glue(gen_op_load_srsgpr_, Tn)(Rn); \ - } \ -} while (0) +static inline void gen_store_ACX (TCGv t, int reg) +{ + tcg_gen_mov_tl(cpu_ACX[reg], t); +} -#if defined(TARGET_MIPS64) -#define GEN_LOAD_IMM_TN(Tn, Imm) \ -do { \ - if (Imm == 0) { \ - glue(gen_op_reset_, Tn)(); \ - } else if ((int32_t)Imm == Imm) { \ - glue(gen_op_set_, Tn)(Imm); \ - } else { \ - glue(gen_op_set64_, Tn)(((uint64_t)Imm) >> 32, (uint32_t)Imm); \ - } \ -} while (0) -#else -#define GEN_LOAD_IMM_TN(Tn, Imm) \ -do { \ - if (Imm == 0) { \ - glue(gen_op_reset_, Tn)(); \ - } else { \ - glue(gen_op_set_, Tn)(Imm); \ - } \ -} while (0) -#endif +/* Moves to/from shadow registers. */ +static inline void gen_load_srsgpr (int from, int to) +{ + TCGv t0 = tcg_temp_new(); -#define GEN_STORE_T0_REG(Rn) \ -do { \ - if (Rn != 0) { \ - glue(gen_op_store_T0,_gpr)(Rn); \ - ctx->glue(last_T0,_store) = gen_opc_ptr; \ - ctx->glue(last_T0,_gpr) = Rn; \ - } \ -} while (0) + if (from == 0) + tcg_gen_movi_tl(t0, 0); + else { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_ptr addr = tcg_temp_new_ptr(); -#define GEN_STORE_T1_REG(Rn) \ -do { \ - if (Rn != 0) \ - glue(gen_op_store_T1,_gpr)(Rn); \ -} while (0) + tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUState, CP0_SRSCtl)); + tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS); + tcg_gen_andi_i32(t2, t2, 0xf); + tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32); + tcg_gen_ext_i32_ptr(addr, t2); + tcg_gen_add_ptr(addr, cpu_env, addr); -#define GEN_STORE_TN_SRSREG(Rn, Tn) \ -do { \ - if (Rn != 0) { \ - glue(glue(gen_op_store_, Tn),_srsgpr)(Rn); \ - } \ -} while (0) + tcg_gen_ld_tl(t0, addr, sizeof(target_ulong) * from); + tcg_temp_free_ptr(addr); + tcg_temp_free_i32(t2); + } + gen_store_gpr(t0, to); + tcg_temp_free(t0); +} -#define GEN_LOAD_FREG_FTN(FTn, Fn) \ -do { \ - glue(gen_op_load_fpr_, FTn)(Fn); \ -} while (0) +static inline void gen_store_srsgpr (int from, int to) +{ + if (to != 0) { + TCGv t0 = tcg_temp_new(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_ptr addr = tcg_temp_new_ptr(); -#define GEN_STORE_FTN_FREG(Fn, FTn) \ -do { \ - glue(gen_op_store_fpr_, FTn)(Fn); \ -} while (0) + gen_load_gpr(t0, from); + tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUState, CP0_SRSCtl)); + tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS); + tcg_gen_andi_i32(t2, t2, 0xf); + tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32); + tcg_gen_ext_i32_ptr(addr, t2); + tcg_gen_add_ptr(addr, cpu_env, addr); + + tcg_gen_st_tl(t0, addr, sizeof(target_ulong) * to); + tcg_temp_free_ptr(addr); + tcg_temp_free_i32(t2); + tcg_temp_free(t0); + } +} -static always_inline void gen_save_pc(target_ulong pc) +/* Floating point register moves. */ +static inline void gen_load_fpr32 (TCGv_i32 t, int reg) { -#if defined(TARGET_MIPS64) - if (pc == (int32_t)pc) { - gen_op_save_pc(pc); + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].w[FP_ENDIAN_IDX])); +} + +static inline void gen_store_fpr32 (TCGv_i32 t, int reg) +{ + tcg_gen_st_i32(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].w[FP_ENDIAN_IDX])); +} + +static inline void gen_load_fpr32h (TCGv_i32 t, int reg) +{ + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].w[!FP_ENDIAN_IDX])); +} + +static inline void gen_store_fpr32h (TCGv_i32 t, int reg) +{ + tcg_gen_st_i32(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].w[!FP_ENDIAN_IDX])); +} + +static inline void gen_load_fpr64 (DisasContext *ctx, TCGv_i64 t, int reg) +{ + if (ctx->hflags & MIPS_HFLAG_F64) { + tcg_gen_ld_i64(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].d)); } else { - gen_op_save_pc64(pc >> 32, (uint32_t)pc); + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + gen_load_fpr32(t0, reg & ~1); + gen_load_fpr32(t1, reg | 1); + tcg_gen_concat_i32_i64(t, t0, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); } -#else - gen_op_save_pc(pc); -#endif } -static always_inline void gen_save_btarget(target_ulong btarget) +static inline void gen_store_fpr64 (DisasContext *ctx, TCGv_i64 t, int reg) { -#if defined(TARGET_MIPS64) - if (btarget == (int32_t)btarget) { - gen_op_save_btarget(btarget); + if (ctx->hflags & MIPS_HFLAG_F64) { + tcg_gen_st_i64(t, cpu_env, offsetof(CPUState, active_fpu.fpr[reg].d)); } else { - gen_op_save_btarget64(btarget >> 32, (uint32_t)btarget); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t1, t); + gen_store_fpr32(t1, reg & ~1); + tcg_gen_shri_i64(t0, t, 32); + tcg_gen_trunc_i64_i32(t1, t0); + gen_store_fpr32(t1, reg | 1); + tcg_temp_free_i32(t1); + tcg_temp_free_i64(t0); } -#else - gen_op_save_btarget(btarget); -#endif } -static always_inline void save_cpu_state (DisasContext *ctx, int do_save_pc) +static inline int get_fp_bit (int cc) { -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "hflags %08x saved %08x\n", - ctx->hflags, ctx->saved_hflags); - } -#endif + if (cc) + return 24 + cc; + else + return 23; +} + +/* Tests */ +static inline void gen_save_pc(target_ulong pc) +{ + tcg_gen_movi_tl(cpu_PC, pc); +} + +static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) +{ + LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); if (do_save_pc && ctx->pc != ctx->saved_pc) { gen_save_pc(ctx->pc); ctx->saved_pc = ctx->pc; } if (ctx->hflags != ctx->saved_hflags) { - gen_op_save_state(ctx->hflags); + tcg_gen_movi_i32(hflags, ctx->hflags); ctx->saved_hflags = ctx->hflags; - switch (ctx->hflags & MIPS_HFLAG_BMASK) { + switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { case MIPS_HFLAG_BR: - gen_op_save_breg_target(); break; case MIPS_HFLAG_BC: - gen_op_save_bcond(); - /* fall through */ case MIPS_HFLAG_BL: - /* bcond was already saved by the BL insn */ - /* fall through */ case MIPS_HFLAG_B: - gen_save_btarget(ctx->btarget); + tcg_gen_movi_tl(btarget, ctx->btarget); break; } } } -static always_inline void restore_cpu_state (CPUState *env, DisasContext *ctx) +static inline void restore_cpu_state (CPUState *env, DisasContext *ctx) { ctx->saved_hflags = ctx->hflags; - switch (ctx->hflags & MIPS_HFLAG_BMASK) { + switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { case MIPS_HFLAG_BR: - gen_op_restore_breg_target(); - break; - case MIPS_HFLAG_B: - ctx->btarget = env->btarget; break; case MIPS_HFLAG_BC: case MIPS_HFLAG_BL: + case MIPS_HFLAG_B: ctx->btarget = env->btarget; - gen_op_restore_bcond(); break; } } -static always_inline void generate_exception_err (DisasContext *ctx, int excp, int err) +static inline void +generate_exception_err (DisasContext *ctx, int excp, int err) { -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "%s: raise exception %d\n", __func__, excp); -#endif + TCGv_i32 texcp = tcg_const_i32(excp); + TCGv_i32 terr = tcg_const_i32(err); save_cpu_state(ctx, 1); - if (err == 0) - gen_op_raise_exception(excp); - else - gen_op_raise_exception_err(excp, err); - ctx->bstate = BS_EXCP; + gen_helper_raise_exception_err(texcp, terr); + tcg_temp_free_i32(terr); + tcg_temp_free_i32(texcp); } -static always_inline void generate_exception (DisasContext *ctx, int excp) +static inline void +generate_exception (DisasContext *ctx, int excp) { - generate_exception_err (ctx, excp, 0); + save_cpu_state(ctx, 1); + gen_helper_0i(raise_exception, excp); } -static always_inline void check_cp0_enabled(DisasContext *ctx) +/* Addresses computation */ +static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1) +{ + tcg_gen_add_tl(ret, arg0, arg1); + +#if defined(TARGET_MIPS64) + /* For compatibility with 32-bit code, data reference in user mode + with Status_UX = 0 should be casted to 32-bit and sign extended. + See the MIPS64 PRA manual, section 4.10. */ + if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && + !(ctx->hflags & MIPS_HFLAG_UX)) { + tcg_gen_ext32s_i64(ret, ret); + } +#endif +} + +static inline void check_cp0_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) - generate_exception_err(ctx, EXCP_CpU, 1); + generate_exception_err(ctx, EXCP_CpU, 0); } -static always_inline void check_cp1_enabled(DisasContext *ctx) +static inline void check_cp1_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU))) generate_exception_err(ctx, EXCP_CpU, 1); @@ -798,7 +799,7 @@ static always_inline void check_cp1_enab This is associated with the nabla symbol in the MIPS32 and MIPS64 opcode tables. */ -static always_inline void check_cop1x(DisasContext *ctx) +static inline void check_cop1x(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X))) generate_exception(ctx, EXCP_RI); @@ -807,7 +808,7 @@ static always_inline void check_cop1x(Di /* Verify that the processor is running with 64-bit floating-point operations enabled. */ -static always_inline void check_cp1_64bitmode(DisasContext *ctx) +static inline void check_cp1_64bitmode(DisasContext *ctx) { if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X))) generate_exception(ctx, EXCP_RI); @@ -824,7 +825,7 @@ static always_inline void check_cp1_64bi * Multiple 64 bit wide registers can be checked by calling * gen_op_cp1_registers(freg1 | freg2 | ... | fregN); */ -void check_cp1_registers(DisasContext *ctx, int regs) +static inline void check_cp1_registers(DisasContext *ctx, int regs) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1))) generate_exception(ctx, EXCP_RI); @@ -832,7 +833,7 @@ void check_cp1_registers(DisasContext *c /* This code generates a "reserved instruction" exception if the CPU does not support the instruction set corresponding to flags. */ -static always_inline void check_insn(CPUState *env, DisasContext *ctx, int flags) +static inline void check_insn(CPUState *env, DisasContext *ctx, int flags) { if (unlikely(!(env->insn_flags & flags))) generate_exception(ctx, EXCP_RI); @@ -840,266 +841,501 @@ static always_inline void check_insn(CPU /* This code generates a "reserved instruction" exception if 64-bit instructions are not enabled. */ -static always_inline void check_mips_64(DisasContext *ctx) +static inline void check_mips_64(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) generate_exception(ctx, EXCP_RI); } -#if defined(CONFIG_USER_ONLY) -#define op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) -#define OP_ST_TABLE(width) +/* Define small wrappers for gen_load_fpr* so that we have a uniform + calling interface for 32 and 64-bit FPRs. No sense in changing + all callers for gen_load_fpr32 when we need the CTX parameter for + this one use. */ +#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(x, y) +#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y) +#define FOP_CONDS(type, abs, fmt, ifmt, bits) \ +static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n, \ + int ft, int fs, int cc) \ +{ \ + TCGv_i##bits fp0 = tcg_temp_new_i##bits (); \ + TCGv_i##bits fp1 = tcg_temp_new_i##bits (); \ + switch (ifmt) { \ + case FMT_PS: \ + check_cp1_64bitmode(ctx); \ + break; \ + case FMT_D: \ + if (abs) { \ + check_cop1x(ctx); \ + } \ + check_cp1_registers(ctx, fs | ft); \ + break; \ + case FMT_S: \ + if (abs) { \ + check_cop1x(ctx); \ + } \ + break; \ + } \ + gen_ldcmp_fpr##bits (ctx, fp0, fs); \ + gen_ldcmp_fpr##bits (ctx, fp1, ft); \ + switch (n) { \ + case 0: gen_helper_2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc); break;\ + case 1: gen_helper_2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc); break;\ + case 2: gen_helper_2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc); break;\ + case 3: gen_helper_2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc); break;\ + case 4: gen_helper_2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc); break;\ + case 5: gen_helper_2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc); break;\ + case 6: gen_helper_2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc); break;\ + case 7: gen_helper_2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc); break;\ + case 8: gen_helper_2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc); break;\ + case 9: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\ + case 10: gen_helper_2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc); break;\ + case 11: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc); break;\ + case 12: gen_helper_2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc); break;\ + case 13: gen_helper_2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc); break;\ + case 14: gen_helper_2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc); break;\ + case 15: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc); break;\ + default: abort(); \ + } \ + tcg_temp_free_i##bits (fp0); \ + tcg_temp_free_i##bits (fp1); \ +} + +FOP_CONDS(, 0, d, FMT_D, 64) +FOP_CONDS(abs, 1, d, FMT_D, 64) +FOP_CONDS(, 0, s, FMT_S, 32) +FOP_CONDS(abs, 1, s, FMT_S, 32) +FOP_CONDS(, 0, ps, FMT_PS, 64) +FOP_CONDS(abs, 1, ps, FMT_PS, 64) +#undef FOP_CONDS +#undef gen_ldcmp_fpr32 +#undef gen_ldcmp_fpr64 + +/* load/store instructions. */ +#define OP_LD(insn,fname) \ +static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ +{ \ + tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ +} +OP_LD(lb,ld8s); +OP_LD(lbu,ld8u); +OP_LD(lh,ld16s); +OP_LD(lhu,ld16u); +OP_LD(lw,ld32s); +#if defined(TARGET_MIPS64) +OP_LD(lwu,ld32u); +OP_LD(ld,ld64); +#endif +#undef OP_LD + +#define OP_ST(insn,fname) \ +static inline void op_st_##insn(TCGv arg1, TCGv arg2, DisasContext *ctx) \ +{ \ + tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx); \ +} +OP_ST(sb,st8); +OP_ST(sh,st16); +OP_ST(sw,st32); +#if defined(TARGET_MIPS64) +OP_ST(sd,st64); +#endif +#undef OP_ST + +#ifdef CONFIG_USER_ONLY +#define OP_LD_ATOMIC(insn,fname) \ +static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ +{ \ + TCGv t0 = tcg_temp_new(); \ + tcg_gen_mov_tl(t0, arg1); \ + tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, lladdr)); \ + tcg_gen_st_tl(ret, cpu_env, offsetof(CPUState, llval)); \ + tcg_temp_free(t0); \ +} #else -#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_kernel, \ - &gen_op_l##width##_super, \ - &gen_op_l##width##_user, \ -} -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_s##width[] = { \ - &gen_op_s##width##_kernel, \ - &gen_op_s##width##_super, \ - &gen_op_s##width##_user, \ +#define OP_LD_ATOMIC(insn,fname) \ +static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ +{ \ + gen_helper_2i(insn, ret, arg1, ctx->mem_idx); \ } #endif +OP_LD_ATOMIC(ll,ld32s); +#if defined(TARGET_MIPS64) +OP_LD_ATOMIC(lld,ld64); +#endif +#undef OP_LD_ATOMIC +#ifdef CONFIG_USER_ONLY +#define OP_ST_ATOMIC(insn,fname,ldname,almask) \ +static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \ +{ \ + TCGv t0 = tcg_temp_new(); \ + int l1 = gen_new_label(); \ + int l2 = gen_new_label(); \ + \ + tcg_gen_andi_tl(t0, arg2, almask); \ + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); \ + tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \ + generate_exception(ctx, EXCP_AdES); \ + gen_set_label(l1); \ + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, lladdr)); \ + tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \ + tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20)); \ + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, llreg)); \ + tcg_gen_st_tl(arg1, cpu_env, offsetof(CPUState, llnewval)); \ + gen_helper_0i(raise_exception, EXCP_SC); \ + gen_set_label(l2); \ + tcg_gen_movi_tl(t0, 0); \ + gen_store_gpr(t0, rt); \ + tcg_temp_free(t0); \ +} +#else +#define OP_ST_ATOMIC(insn,fname,ldname,almask) \ +static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \ +{ \ + TCGv t0 = tcg_temp_new(); \ + gen_helper_3i(insn, t0, arg1, arg2, ctx->mem_idx); \ + gen_store_gpr(t0, rt); \ + tcg_temp_free(t0); \ +} +#endif +OP_ST_ATOMIC(sc,st32,ld32s,0x3); #if defined(TARGET_MIPS64) -OP_LD_TABLE(d); -OP_LD_TABLE(dl); -OP_LD_TABLE(dr); -OP_ST_TABLE(d); -OP_ST_TABLE(dl); -OP_ST_TABLE(dr); -OP_LD_TABLE(ld); -OP_ST_TABLE(cd); -OP_LD_TABLE(wu); -#endif -OP_LD_TABLE(w); -OP_LD_TABLE(wl); -OP_LD_TABLE(wr); -OP_ST_TABLE(w); -OP_ST_TABLE(wl); -OP_ST_TABLE(wr); -OP_LD_TABLE(h); -OP_LD_TABLE(hu); -OP_ST_TABLE(h); -OP_LD_TABLE(b); -OP_LD_TABLE(bu); -OP_ST_TABLE(b); -OP_LD_TABLE(l); -OP_ST_TABLE(c); -OP_LD_TABLE(wc1); -OP_ST_TABLE(wc1); -OP_LD_TABLE(dc1); -OP_ST_TABLE(dc1); -OP_LD_TABLE(uxc1); -OP_ST_TABLE(uxc1); +OP_ST_ATOMIC(scd,st64,ld64,0x7); +#endif +#undef OP_ST_ATOMIC -/* Load and store */ -static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, - int base, int16_t offset) +static void gen_base_offset_addr (DisasContext *ctx, TCGv addr, + int base, int16_t offset) { - const char *opn = "ldst"; - if (base == 0) { - GEN_LOAD_IMM_TN(T0, offset); + tcg_gen_movi_tl(addr, offset); } else if (offset == 0) { - gen_op_load_gpr_T0(base); + gen_load_gpr(addr, base); } else { - gen_op_load_gpr_T0(base); - gen_op_set_T1(offset); - gen_op_addr_add(); + tcg_gen_movi_tl(addr, offset); + gen_op_addr_add(ctx, addr, cpu_gpr[base], addr); } - /* Don't do NOP if destination is zero: we must perform the actual - memory access. */ +} + +static target_ulong pc_relative_pc (DisasContext *ctx) +{ + target_ulong pc = ctx->pc; + + if (ctx->hflags & MIPS_HFLAG_BMASK) { + int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4; + + pc -= branch_bytes; + } + + pc &= ~(target_ulong)3; + return pc; +} + +/* Load */ +static void gen_ld (CPUState *env, DisasContext *ctx, uint32_t opc, + int rt, int base, int16_t offset) +{ + const char *opn = "ld"; + TCGv t0, t1; + + if (rt == 0 && env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) { + /* Loongson CPU uses a load to zero register for prefetch. + We emulate it as a NOP. On other CPU we must perform the + actual memory access. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, base, offset); + switch (opc) { #if defined(TARGET_MIPS64) case OPC_LWU: - op_ldst(lwu); - GEN_STORE_T0_REG(rt); + save_cpu_state(ctx, 0); + op_ld_lwu(t0, t0, ctx); + gen_store_gpr(t0, rt); opn = "lwu"; break; case OPC_LD: - op_ldst(ld); - GEN_STORE_T0_REG(rt); + save_cpu_state(ctx, 0); + op_ld_ld(t0, t0, ctx); + gen_store_gpr(t0, rt); opn = "ld"; break; case OPC_LLD: - op_ldst(lld); - GEN_STORE_T0_REG(rt); - opn = "lld"; - break; - case OPC_SD: - GEN_LOAD_REG_T1(rt); - op_ldst(sd); - opn = "sd"; - break; - case OPC_SCD: save_cpu_state(ctx, 1); - GEN_LOAD_REG_T1(rt); - op_ldst(scd); - GEN_STORE_T0_REG(rt); - opn = "scd"; + op_ld_lld(t0, t0, ctx); + gen_store_gpr(t0, rt); + opn = "lld"; break; case OPC_LDL: - GEN_LOAD_REG_T1(rt); - op_ldst(ldl); - GEN_STORE_T1_REG(rt); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + gen_helper_3i(ldl, t1, t1, t0, ctx->mem_idx); + gen_store_gpr(t1, rt); opn = "ldl"; break; - case OPC_SDL: - GEN_LOAD_REG_T1(rt); - op_ldst(sdl); - opn = "sdl"; - break; case OPC_LDR: - GEN_LOAD_REG_T1(rt); - op_ldst(ldr); - GEN_STORE_T1_REG(rt); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + gen_helper_3i(ldr, t1, t1, t0, ctx->mem_idx); + gen_store_gpr(t1, rt); opn = "ldr"; break; - case OPC_SDR: - GEN_LOAD_REG_T1(rt); - op_ldst(sdr); - opn = "sdr"; + case OPC_LDPC: + save_cpu_state(ctx, 0); + tcg_gen_movi_tl(t1, pc_relative_pc(ctx)); + gen_op_addr_add(ctx, t0, t0, t1); + op_ld_ld(t0, t0, ctx); + gen_store_gpr(t0, rt); + opn = "ldpc"; break; #endif + case OPC_LWPC: + save_cpu_state(ctx, 0); + tcg_gen_movi_tl(t1, pc_relative_pc(ctx)); + gen_op_addr_add(ctx, t0, t0, t1); + op_ld_lw(t0, t0, ctx); + gen_store_gpr(t0, rt); + opn = "lwpc"; + break; case OPC_LW: - op_ldst(lw); - GEN_STORE_T0_REG(rt); + save_cpu_state(ctx, 0); + op_ld_lw(t0, t0, ctx); + gen_store_gpr(t0, rt); opn = "lw"; break; - case OPC_SW: - GEN_LOAD_REG_T1(rt); - op_ldst(sw); - opn = "sw"; - break; case OPC_LH: - op_ldst(lh); - GEN_STORE_T0_REG(rt); + save_cpu_state(ctx, 0); + op_ld_lh(t0, t0, ctx); + gen_store_gpr(t0, rt); opn = "lh"; break; - case OPC_SH: - GEN_LOAD_REG_T1(rt); - op_ldst(sh); - opn = "sh"; - break; case OPC_LHU: - op_ldst(lhu); - GEN_STORE_T0_REG(rt); + save_cpu_state(ctx, 0); + op_ld_lhu(t0, t0, ctx); + gen_store_gpr(t0, rt); opn = "lhu"; break; case OPC_LB: - op_ldst(lb); - GEN_STORE_T0_REG(rt); + save_cpu_state(ctx, 0); + op_ld_lb(t0, t0, ctx); + gen_store_gpr(t0, rt); opn = "lb"; break; - case OPC_SB: - GEN_LOAD_REG_T1(rt); - op_ldst(sb); - opn = "sb"; - break; case OPC_LBU: - op_ldst(lbu); - GEN_STORE_T0_REG(rt); + save_cpu_state(ctx, 0); + op_ld_lbu(t0, t0, ctx); + gen_store_gpr(t0, rt); opn = "lbu"; break; case OPC_LWL: - GEN_LOAD_REG_T1(rt); - op_ldst(lwl); - GEN_STORE_T1_REG(rt); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + gen_helper_3i(lwl, t1, t1, t0, ctx->mem_idx); + gen_store_gpr(t1, rt); opn = "lwl"; break; - case OPC_SWL: - GEN_LOAD_REG_T1(rt); - op_ldst(swl); - opn = "swr"; - break; case OPC_LWR: - GEN_LOAD_REG_T1(rt); - op_ldst(lwr); - GEN_STORE_T1_REG(rt); + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); + gen_helper_3i(lwr, t1, t1, t0, ctx->mem_idx); + gen_store_gpr(t1, rt); opn = "lwr"; break; + case OPC_LL: + save_cpu_state(ctx, 1); + op_ld_ll(t0, t0, ctx); + gen_store_gpr(t0, rt); + opn = "ll"; + break; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* Store */ +static void gen_st (DisasContext *ctx, uint32_t opc, int rt, + int base, int16_t offset) +{ + const char *opn = "st"; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, base, offset); + gen_load_gpr(t1, rt); + switch (opc) { +#if defined(TARGET_MIPS64) + case OPC_SD: + save_cpu_state(ctx, 0); + op_st_sd(t1, t0, ctx); + opn = "sd"; + break; + case OPC_SDL: + save_cpu_state(ctx, 1); + gen_helper_2i(sdl, t1, t0, ctx->mem_idx); + opn = "sdl"; + break; + case OPC_SDR: + save_cpu_state(ctx, 1); + gen_helper_2i(sdr, t1, t0, ctx->mem_idx); + opn = "sdr"; + break; +#endif + case OPC_SW: + save_cpu_state(ctx, 0); + op_st_sw(t1, t0, ctx); + opn = "sw"; + break; + case OPC_SH: + save_cpu_state(ctx, 0); + op_st_sh(t1, t0, ctx); + opn = "sh"; + break; + case OPC_SB: + save_cpu_state(ctx, 0); + op_st_sb(t1, t0, ctx); + opn = "sb"; + break; + case OPC_SWL: + save_cpu_state(ctx, 1); + gen_helper_2i(swl, t1, t0, ctx->mem_idx); + opn = "swl"; + break; case OPC_SWR: - GEN_LOAD_REG_T1(rt); - op_ldst(swr); + save_cpu_state(ctx, 1); + gen_helper_2i(swr, t1, t0, ctx->mem_idx); opn = "swr"; break; - case OPC_LL: - op_ldst(ll); - GEN_STORE_T0_REG(rt); - opn = "ll"; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + + +/* Store conditional */ +static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, + int base, int16_t offset) +{ + const char *opn = "st_cond"; + TCGv t0, t1; + + t0 = tcg_temp_local_new(); + + gen_base_offset_addr(ctx, t0, base, offset); + /* Don't do NOP if destination is zero: we must perform the actual + memory access. */ + + t1 = tcg_temp_local_new(); + gen_load_gpr(t1, rt); + switch (opc) { +#if defined(TARGET_MIPS64) + case OPC_SCD: + save_cpu_state(ctx, 1); + op_st_scd(t1, t0, rt, ctx); + opn = "scd"; break; +#endif case OPC_SC: save_cpu_state(ctx, 1); - GEN_LOAD_REG_T1(rt); - op_ldst(sc); - GEN_STORE_T0_REG(rt); + op_st_sc(t1, t0, rt, ctx); opn = "sc"; break; - default: - MIPS_INVAL(opn); - generate_exception(ctx, EXCP_RI); - return; } + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); + tcg_temp_free(t1); + tcg_temp_free(t0); } /* Load and store */ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, - int base, int16_t offset) + int base, int16_t offset) { const char *opn = "flt_ldst"; + TCGv t0 = tcg_temp_new(); - if (base == 0) { - GEN_LOAD_IMM_TN(T0, offset); - } else if (offset == 0) { - gen_op_load_gpr_T0(base); - } else { - gen_op_load_gpr_T0(base); - gen_op_set_T1(offset); - gen_op_addr_add(); - } + gen_base_offset_addr(ctx, t0, base, offset); /* Don't do NOP if destination is zero: we must perform the actual memory access. */ switch (opc) { case OPC_LWC1: - op_ldst(lwc1); - GEN_STORE_FTN_FREG(ft, WT0); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + tcg_gen_qemu_ld32s(t0, t0, ctx->mem_idx); + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32(fp0, ft); + tcg_temp_free_i32(fp0); + } opn = "lwc1"; break; case OPC_SWC1: - GEN_LOAD_FREG_FTN(WT0, ft); - op_ldst(swc1); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new(); + + gen_load_fpr32(fp0, ft); + tcg_gen_extu_i32_tl(t1, fp0); + tcg_gen_qemu_st32(t1, t0, ctx->mem_idx); + tcg_temp_free(t1); + tcg_temp_free_i32(fp0); + } opn = "swc1"; break; case OPC_LDC1: - op_ldst(ldc1); - GEN_STORE_FTN_FREG(ft, DT0); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx); + gen_store_fpr64(ctx, fp0, ft); + tcg_temp_free_i64(fp0); + } opn = "ldc1"; break; case OPC_SDC1: - GEN_LOAD_FREG_FTN(DT0, ft); - op_ldst(sdc1); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, ft); + tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx); + tcg_temp_free_i64(fp0); + } opn = "sdc1"; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); + out: + tcg_temp_free(t0); +} + +static void gen_cop1_ldst(CPUState *env, DisasContext *ctx, + uint32_t op, int rt, int rs, int16_t imm) +{ + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + check_cp1_enabled(ctx); + gen_flt_ldst(ctx, op, rt, rs, imm); + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } } /* Arithmetic with immediate operand */ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) { - target_ulong uimm; + target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ const char *opn = "imm arith"; if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { @@ -1108,186 +1344,243 @@ static void gen_arith_imm (CPUState *env MIPS_DEBUG("NOP"); return; } - uimm = (uint16_t)imm; switch (opc) { case OPC_ADDI: - case OPC_ADDIU: -#if defined(TARGET_MIPS64) - case OPC_DADDI: - case OPC_DADDIU: -#endif - case OPC_SLTI: - case OPC_SLTIU: - uimm = (target_long)imm; /* Sign extend to 32/64 bits */ - /* Fall through. */ - case OPC_ANDI: - case OPC_ORI: - case OPC_XORI: - GEN_LOAD_REG_T0(rs); - GEN_LOAD_IMM_TN(T1, uimm); - break; - case OPC_LUI: - GEN_LOAD_IMM_TN(T0, imm << 16); - break; - case OPC_SLL: - case OPC_SRA: - case OPC_SRL: -#if defined(TARGET_MIPS64) - case OPC_DSLL: - case OPC_DSRA: - case OPC_DSRL: - case OPC_DSLL32: - case OPC_DSRA32: - case OPC_DSRL32: -#endif - uimm &= 0x1f; - GEN_LOAD_REG_T0(rs); - GEN_LOAD_IMM_TN(T1, uimm); - break; - } - switch (opc) { - case OPC_ADDI: - save_cpu_state(ctx, 1); - gen_op_addo(); + { + TCGv t0 = tcg_temp_local_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + int l1 = gen_new_label(); + + gen_load_gpr(t1, rs); + tcg_gen_addi_tl(t0, t1, uimm); + tcg_gen_ext32s_tl(t0, t0); + + tcg_gen_xori_tl(t1, t1, ~uimm); + tcg_gen_xori_tl(t2, t0, uimm); + tcg_gen_and_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_temp_free(t1); + /* operands of same sign, result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + tcg_gen_ext32s_tl(t0, t0); + gen_store_gpr(t0, rt); + tcg_temp_free(t0); + } opn = "addi"; break; case OPC_ADDIU: - gen_op_add(); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + } else { + tcg_gen_movi_tl(cpu_gpr[rt], uimm); + } opn = "addiu"; break; #if defined(TARGET_MIPS64) case OPC_DADDI: - save_cpu_state(ctx, 1); - gen_op_daddo(); + { + TCGv t0 = tcg_temp_local_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + int l1 = gen_new_label(); + + gen_load_gpr(t1, rs); + tcg_gen_addi_tl(t0, t1, uimm); + + tcg_gen_xori_tl(t1, t1, ~uimm); + tcg_gen_xori_tl(t2, t0, uimm); + tcg_gen_and_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_temp_free(t1); + /* operands of same sign, result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + gen_store_gpr(t0, rt); + tcg_temp_free(t0); + } opn = "daddi"; break; case OPC_DADDIU: - gen_op_dadd(); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + } else { + tcg_gen_movi_tl(cpu_gpr[rt], uimm); + } opn = "daddiu"; break; #endif - case OPC_SLTI: - gen_op_lt(); - opn = "slti"; - break; - case OPC_SLTIU: - gen_op_ltu(); - opn = "sltiu"; - break; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); +} + +/* Logic with immediate operand */ +static void gen_logic_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t imm) +{ + target_ulong uimm; + const char *opn = "imm logic"; + + if (rt == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + uimm = (uint16_t)imm; + switch (opc) { case OPC_ANDI: - gen_op_and(); + if (likely(rs != 0)) + tcg_gen_andi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + else + tcg_gen_movi_tl(cpu_gpr[rt], 0); opn = "andi"; break; case OPC_ORI: - gen_op_or(); + if (rs != 0) + tcg_gen_ori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + else + tcg_gen_movi_tl(cpu_gpr[rt], uimm); opn = "ori"; break; case OPC_XORI: - gen_op_xor(); + if (likely(rs != 0)) + tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm); + else + tcg_gen_movi_tl(cpu_gpr[rt], uimm); opn = "xori"; break; case OPC_LUI: + tcg_gen_movi_tl(cpu_gpr[rt], imm << 16); opn = "lui"; break; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); +} + +/* Set on less than with immediate operand */ +static void gen_slt_imm (CPUState *env, uint32_t opc, int rt, int rs, int16_t imm) +{ + target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ + const char *opn = "imm arith"; + TCGv t0; + + if (rt == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + switch (opc) { + case OPC_SLTI: + tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, uimm); + opn = "slti"; + break; + case OPC_SLTIU: + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, uimm); + opn = "sltiu"; + break; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); + tcg_temp_free(t0); +} + +/* Shifts with immediate operand */ +static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc, + int rt, int rs, int16_t imm) +{ + target_ulong uimm = ((uint16_t)imm) & 0x1f; + const char *opn = "imm shift"; + TCGv t0; + + if (rt == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + switch (opc) { case OPC_SLL: - gen_op_sll(); + tcg_gen_shli_tl(t0, t0, uimm); + tcg_gen_ext32s_tl(cpu_gpr[rt], t0); opn = "sll"; break; case OPC_SRA: - gen_op_sra(); + tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm); opn = "sra"; break; case OPC_SRL: - switch ((ctx->opcode >> 21) & 0x1f) { - case 0: - gen_op_srl(); - opn = "srl"; - break; - case 1: - /* rotr is decoded as srl on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { - gen_op_rotr(); - opn = "rotr"; - } else { - gen_op_srl(); - opn = "srl"; - } - break; - default: - MIPS_INVAL("invalid srl flag"); - generate_exception(ctx, EXCP_RI); - break; + if (uimm != 0) { + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); + } else { + tcg_gen_ext32s_tl(cpu_gpr[rt], t0); + } + opn = "srl"; + break; + case OPC_ROTR: + if (uimm != 0) { + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t1, t0); + tcg_gen_rotri_i32(t1, t1, uimm); + tcg_gen_ext_i32_tl(cpu_gpr[rt], t1); + tcg_temp_free_i32(t1); + } else { + tcg_gen_ext32s_tl(cpu_gpr[rt], t0); } + opn = "rotr"; break; #if defined(TARGET_MIPS64) case OPC_DSLL: - gen_op_dsll(); + tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm); opn = "dsll"; break; case OPC_DSRA: - gen_op_dsra(); + tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm); opn = "dsra"; break; case OPC_DSRL: - switch ((ctx->opcode >> 21) & 0x1f) { - case 0: - gen_op_dsrl(); - opn = "dsrl"; - break; - case 1: - /* drotr is decoded as dsrl on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { - gen_op_drotr(); - opn = "drotr"; - } else { - gen_op_dsrl(); - opn = "dsrl"; - } - break; - default: - MIPS_INVAL("invalid dsrl flag"); - generate_exception(ctx, EXCP_RI); - break; + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm); + opn = "dsrl"; + break; + case OPC_DROTR: + if (uimm != 0) { + tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm); + } else { + tcg_gen_mov_tl(cpu_gpr[rt], t0); } + opn = "drotr"; break; case OPC_DSLL32: - gen_op_dsll32(); + tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm + 32); opn = "dsll32"; break; case OPC_DSRA32: - gen_op_dsra32(); + tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm + 32); opn = "dsra32"; break; case OPC_DSRL32: - switch ((ctx->opcode >> 21) & 0x1f) { - case 0: - gen_op_dsrl32(); - opn = "dsrl32"; - break; - case 1: - /* drotr32 is decoded as dsrl32 on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { - gen_op_drotr32(); - opn = "drotr32"; - } else { - gen_op_dsrl32(); - opn = "dsrl32"; - } - break; - default: - MIPS_INVAL("invalid dsrl32 flag"); - generate_exception(ctx, EXCP_RI); - break; - } + tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32); + opn = "dsrl32"; + break; + case OPC_DROTR32: + tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32); + opn = "drotr32"; break; #endif - default: - MIPS_INVAL(opn); - generate_exception(ctx, EXCP_RI); - return; } - GEN_STORE_T0_REG(rt); + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); + tcg_temp_free(t0); } /* Arithmetic */ @@ -1303,159 +1596,383 @@ static void gen_arith (CPUState *env, Di MIPS_DEBUG("NOP"); return; } - GEN_LOAD_REG_T0(rs); - /* Specialcase the conventional move operation. */ - if (rt == 0 && (opc == OPC_ADDU || opc == OPC_DADDU - || opc == OPC_SUBU || opc == OPC_DSUBU)) { - GEN_STORE_T0_REG(rd); - return; - } - GEN_LOAD_REG_T1(rt); + switch (opc) { case OPC_ADD: - save_cpu_state(ctx, 1); - gen_op_addo(); + { + TCGv t0 = tcg_temp_local_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + int l1 = gen_new_label(); + + gen_load_gpr(t1, rs); + gen_load_gpr(t2, rt); + tcg_gen_add_tl(t0, t1, t2); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_xor_tl(t1, t1, t2); + tcg_gen_xor_tl(t2, t0, t2); + tcg_gen_andc_tl(t1, t2, t1); + tcg_temp_free(t2); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_temp_free(t1); + /* operands of same sign, result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } opn = "add"; break; case OPC_ADDU: - gen_op_add(); + if (rs != 0 && rt != 0) { + tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } else if (rs == 0 && rt != 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); + } else if (rs != 0 && rt == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } opn = "addu"; break; case OPC_SUB: - save_cpu_state(ctx, 1); - gen_op_subo(); + { + TCGv t0 = tcg_temp_local_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + int l1 = gen_new_label(); + + gen_load_gpr(t1, rs); + gen_load_gpr(t2, rt); + tcg_gen_sub_tl(t0, t1, t2); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_xor_tl(t2, t1, t2); + tcg_gen_xor_tl(t1, t0, t1); + tcg_gen_and_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_temp_free(t1); + /* operands of different sign, first operand and result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } opn = "sub"; break; case OPC_SUBU: - gen_op_sub(); + if (rs != 0 && rt != 0) { + tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } else if (rs == 0 && rt != 0) { + tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } else if (rs != 0 && rt == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } opn = "subu"; break; #if defined(TARGET_MIPS64) case OPC_DADD: - save_cpu_state(ctx, 1); - gen_op_daddo(); + { + TCGv t0 = tcg_temp_local_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + int l1 = gen_new_label(); + + gen_load_gpr(t1, rs); + gen_load_gpr(t2, rt); + tcg_gen_add_tl(t0, t1, t2); + tcg_gen_xor_tl(t1, t1, t2); + tcg_gen_xor_tl(t2, t0, t2); + tcg_gen_andc_tl(t1, t2, t1); + tcg_temp_free(t2); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_temp_free(t1); + /* operands of same sign, result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } opn = "dadd"; break; case OPC_DADDU: - gen_op_dadd(); + if (rs != 0 && rt != 0) { + tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + } else if (rs == 0 && rt != 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); + } else if (rs != 0 && rt == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } opn = "daddu"; break; case OPC_DSUB: - save_cpu_state(ctx, 1); - gen_op_dsubo(); + { + TCGv t0 = tcg_temp_local_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + int l1 = gen_new_label(); + + gen_load_gpr(t1, rs); + gen_load_gpr(t2, rt); + tcg_gen_sub_tl(t0, t1, t2); + tcg_gen_xor_tl(t2, t1, t2); + tcg_gen_xor_tl(t1, t0, t1); + tcg_gen_and_tl(t1, t1, t2); + tcg_temp_free(t2); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_temp_free(t1); + /* operands of different sign, first operand and result different sign */ + generate_exception(ctx, EXCP_OVERFLOW); + gen_set_label(l1); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } opn = "dsub"; break; case OPC_DSUBU: - gen_op_dsub(); + if (rs != 0 && rt != 0) { + tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + } else if (rs == 0 && rt != 0) { + tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]); + } else if (rs != 0 && rt == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } opn = "dsubu"; break; #endif - case OPC_SLT: - gen_op_lt(); - opn = "slt"; + case OPC_MUL: + if (likely(rs != 0 && rt != 0)) { + tcg_gen_mul_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + opn = "mul"; break; - case OPC_SLTU: - gen_op_ltu(); - opn = "sltu"; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); +} + +/* Conditional move */ +static void gen_cond_move (CPUState *env, uint32_t opc, int rd, int rs, int rt) +{ + const char *opn = "cond move"; + int l1; + + if (rd == 0) { + /* If no destination, treat it as a NOP. + For add & sub, we must generate the overflow exception when needed. */ + MIPS_DEBUG("NOP"); + return; + } + + l1 = gen_new_label(); + switch (opc) { + case OPC_MOVN: + if (likely(rt != 0)) + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rt], 0, l1); + else + tcg_gen_br(l1); + opn = "movn"; break; + case OPC_MOVZ: + if (likely(rt != 0)) + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rt], 0, l1); + opn = "movz"; + break; + } + if (rs != 0) + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + else + tcg_gen_movi_tl(cpu_gpr[rd], 0); + gen_set_label(l1); + + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); +} + +/* Logic */ +static void gen_logic (CPUState *env, uint32_t opc, int rd, int rs, int rt) +{ + const char *opn = "logic"; + + if (rd == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + + switch (opc) { case OPC_AND: - gen_op_and(); + if (likely(rs != 0 && rt != 0)) { + tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } opn = "and"; break; case OPC_NOR: - gen_op_nor(); + if (rs != 0 && rt != 0) { + tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + } else if (rs == 0 && rt != 0) { + tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rt]); + } else if (rs != 0 && rt == 0) { + tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rs]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0)); + } opn = "nor"; break; case OPC_OR: - gen_op_or(); + if (likely(rs != 0 && rt != 0)) { + tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + } else if (rs == 0 && rt != 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); + } else if (rs != 0 && rt == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } opn = "or"; break; case OPC_XOR: - gen_op_xor(); + if (likely(rs != 0 && rt != 0)) { + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]); + } else if (rs == 0 && rt != 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]); + } else if (rs != 0 && rt == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } opn = "xor"; break; - case OPC_MUL: - gen_op_mul(); - opn = "mul"; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); +} + +/* Set on lower than */ +static void gen_slt (CPUState *env, uint32_t opc, int rd, int rs, int rt) +{ + const char *opn = "slt"; + TCGv t0, t1; + + if (rd == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + switch (opc) { + case OPC_SLT: + tcg_gen_setcond_tl(TCG_COND_LT, cpu_gpr[rd], t0, t1); + opn = "slt"; break; - case OPC_MOVN: - gen_op_movn(rd); - opn = "movn"; - goto print; - case OPC_MOVZ: - gen_op_movz(rd); - opn = "movz"; - goto print; + case OPC_SLTU: + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t0, t1); + opn = "sltu"; + break; + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* Shifts */ +static void gen_shift (CPUState *env, DisasContext *ctx, uint32_t opc, + int rd, int rs, int rt) +{ + const char *opn = "shifts"; + TCGv t0, t1; + + if (rd == 0) { + /* If no destination, treat it as a NOP. + For add & sub, we must generate the overflow exception when needed. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + switch (opc) { case OPC_SLLV: - gen_op_sllv(); + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_shl_tl(t0, t1, t0); + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); opn = "sllv"; break; case OPC_SRAV: - gen_op_srav(); + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); opn = "srav"; break; case OPC_SRLV: - switch ((ctx->opcode >> 6) & 0x1f) { - case 0: - gen_op_srlv(); - opn = "srlv"; - break; - case 1: - /* rotrv is decoded as srlv on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { - gen_op_rotrv(); - opn = "rotrv"; - } else { - gen_op_srlv(); - opn = "srlv"; - } - break; - default: - MIPS_INVAL("invalid srlv flag"); - generate_exception(ctx, EXCP_RI); - break; + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_shr_tl(t0, t1, t0); + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + opn = "srlv"; + break; + case OPC_ROTRV: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_andi_i32(t2, t2, 0x1f); + tcg_gen_rotr_i32(t2, t3, t2); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + opn = "rotrv"; } break; #if defined(TARGET_MIPS64) case OPC_DSLLV: - gen_op_dsllv(); + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_shl_tl(cpu_gpr[rd], t1, t0); opn = "dsllv"; break; case OPC_DSRAV: - gen_op_dsrav(); + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); opn = "dsrav"; break; case OPC_DSRLV: - switch ((ctx->opcode >> 6) & 0x1f) { - case 0: - gen_op_dsrlv(); - opn = "dsrlv"; - break; - case 1: - /* drotrv is decoded as dsrlv on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { - gen_op_drotrv(); - opn = "drotrv"; - } else { - gen_op_dsrlv(); - opn = "dsrlv"; - } - break; - default: - MIPS_INVAL("invalid dsrlv flag"); - generate_exception(ctx, EXCP_RI); - break; - } + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_shr_tl(cpu_gpr[rd], t1, t0); + opn = "dsrlv"; + break; + case OPC_DROTRV: + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0); + opn = "drotrv"; break; #endif - default: - MIPS_INVAL(opn); - generate_exception(ctx, EXCP_RI); - return; } - GEN_STORE_T0_REG(rd); - print: + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); + tcg_temp_free(t0); + tcg_temp_free(t1); } /* Arithmetic on HI/LO registers */ @@ -1470,30 +1987,29 @@ static void gen_HILO (DisasContext *ctx, } switch (opc) { case OPC_MFHI: - gen_op_load_HI(0); - GEN_STORE_T0_REG(reg); + tcg_gen_mov_tl(cpu_gpr[reg], cpu_HI[0]); opn = "mfhi"; break; case OPC_MFLO: - gen_op_load_LO(0); - GEN_STORE_T0_REG(reg); + tcg_gen_mov_tl(cpu_gpr[reg], cpu_LO[0]); opn = "mflo"; break; case OPC_MTHI: - GEN_LOAD_REG_T0(reg); - gen_op_store_HI(0); + if (reg != 0) + tcg_gen_mov_tl(cpu_HI[0], cpu_gpr[reg]); + else + tcg_gen_movi_tl(cpu_HI[0], 0); opn = "mthi"; break; case OPC_MTLO: - GEN_LOAD_REG_T0(reg); - gen_op_store_LO(0); + if (reg != 0) + tcg_gen_mov_tl(cpu_LO[0], cpu_gpr[reg]); + else + tcg_gen_movi_tl(cpu_LO[0], 0); opn = "mtlo"; break; - default: - MIPS_INVAL(opn); - generate_exception(ctx, EXCP_RI); - return; } + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s", opn, regnames[reg]); } @@ -1501,178 +2017,570 @@ static void gen_muldiv (DisasContext *ct int rs, int rt) { const char *opn = "mul/div"; + TCGv t0, t1; + + switch (opc) { + case OPC_DIV: + case OPC_DIVU: +#if defined(TARGET_MIPS64) + case OPC_DDIV: + case OPC_DDIVU: +#endif + t0 = tcg_temp_local_new(); + t1 = tcg_temp_local_new(); + break; + default: + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + break; + } - GEN_LOAD_REG_T0(rs); - GEN_LOAD_REG_T1(rt); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); switch (opc) { case OPC_DIV: - gen_op_div(); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2); + + tcg_gen_mov_tl(cpu_LO[0], t0); + tcg_gen_movi_tl(cpu_HI[0], 0); + tcg_gen_br(l1); + gen_set_label(l2); + tcg_gen_div_tl(cpu_LO[0], t0, t1); + tcg_gen_rem_tl(cpu_HI[0], t0, t1); + tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]); + tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]); + gen_set_label(l1); + } opn = "div"; break; case OPC_DIVU: - gen_op_divu(); + { + int l1 = gen_new_label(); + + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_divu_tl(cpu_LO[0], t0, t1); + tcg_gen_remu_tl(cpu_HI[0], t0, t1); + tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]); + tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]); + gen_set_label(l1); + } opn = "divu"; break; case OPC_MULT: - gen_op_mult(); + { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t2, t0); + tcg_gen_ext_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_temp_free_i64(t3); + tcg_gen_trunc_i64_tl(t0, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_tl(t1, t2); + tcg_temp_free_i64(t2); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "mult"; break; case OPC_MULTU: - gen_op_multu(); + { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(t2, t0); + tcg_gen_extu_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_temp_free_i64(t3); + tcg_gen_trunc_i64_tl(t0, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_tl(t1, t2); + tcg_temp_free_i64(t2); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "multu"; break; #if defined(TARGET_MIPS64) case OPC_DDIV: - gen_op_ddiv(); + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2); + tcg_gen_mov_tl(cpu_LO[0], t0); + tcg_gen_movi_tl(cpu_HI[0], 0); + tcg_gen_br(l1); + gen_set_label(l2); + tcg_gen_div_i64(cpu_LO[0], t0, t1); + tcg_gen_rem_i64(cpu_HI[0], t0, t1); + gen_set_label(l1); + } opn = "ddiv"; break; case OPC_DDIVU: - gen_op_ddivu(); + { + int l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_divu_i64(cpu_LO[0], t0, t1); + tcg_gen_remu_i64(cpu_HI[0], t0, t1); + gen_set_label(l1); + } opn = "ddivu"; break; case OPC_DMULT: - gen_op_dmult(); + gen_helper_dmult(t0, t1); opn = "dmult"; break; case OPC_DMULTU: - gen_op_dmultu(); + gen_helper_dmultu(t0, t1); opn = "dmultu"; break; #endif case OPC_MADD: - gen_op_madd(); + { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t2, t0); + tcg_gen_ext_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]); + tcg_gen_add_i64(t2, t2, t3); + tcg_temp_free_i64(t3); + tcg_gen_trunc_i64_tl(t0, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_tl(t1, t2); + tcg_temp_free_i64(t2); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "madd"; break; case OPC_MADDU: - gen_op_maddu(); + { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(t2, t0); + tcg_gen_extu_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]); + tcg_gen_add_i64(t2, t2, t3); + tcg_temp_free_i64(t3); + tcg_gen_trunc_i64_tl(t0, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_tl(t1, t2); + tcg_temp_free_i64(t2); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "maddu"; break; case OPC_MSUB: - gen_op_msub(); + { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t2, t0); + tcg_gen_ext_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]); + tcg_gen_sub_i64(t2, t3, t2); + tcg_temp_free_i64(t3); + tcg_gen_trunc_i64_tl(t0, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_tl(t1, t2); + tcg_temp_free_i64(t2); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "msub"; break; case OPC_MSUBU: - gen_op_msubu(); + { + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(t2, t0); + tcg_gen_extu_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]); + tcg_gen_sub_i64(t2, t3, t2); + tcg_temp_free_i64(t3); + tcg_gen_trunc_i64_tl(t0, t2); + tcg_gen_shri_i64(t2, t2, 32); + tcg_gen_trunc_i64_tl(t1, t2); + tcg_temp_free_i64(t2); + tcg_gen_ext32s_tl(cpu_LO[0], t0); + tcg_gen_ext32s_tl(cpu_HI[0], t1); + } opn = "msubu"; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); - return; + goto out; } + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]); + out: + tcg_temp_free(t0); + tcg_temp_free(t1); } static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { const char *opn = "mul vr54xx"; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); - GEN_LOAD_REG_T0(rs); - GEN_LOAD_REG_T1(rt); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); switch (opc) { case OPC_VR54XX_MULS: - gen_op_muls(); + gen_helper_muls(t0, t0, t1); opn = "muls"; - break; + break; case OPC_VR54XX_MULSU: - gen_op_mulsu(); + gen_helper_mulsu(t0, t0, t1); opn = "mulsu"; - break; + break; case OPC_VR54XX_MACC: - gen_op_macc(); + gen_helper_macc(t0, t0, t1); opn = "macc"; - break; + break; case OPC_VR54XX_MACCU: - gen_op_maccu(); + gen_helper_maccu(t0, t0, t1); opn = "maccu"; - break; + break; case OPC_VR54XX_MSAC: - gen_op_msac(); + gen_helper_msac(t0, t0, t1); opn = "msac"; - break; + break; case OPC_VR54XX_MSACU: - gen_op_msacu(); + gen_helper_msacu(t0, t0, t1); opn = "msacu"; - break; + break; case OPC_VR54XX_MULHI: - gen_op_mulhi(); + gen_helper_mulhi(t0, t0, t1); opn = "mulhi"; - break; + break; case OPC_VR54XX_MULHIU: - gen_op_mulhiu(); + gen_helper_mulhiu(t0, t0, t1); opn = "mulhiu"; - break; + break; case OPC_VR54XX_MULSHI: - gen_op_mulshi(); + gen_helper_mulshi(t0, t0, t1); opn = "mulshi"; - break; + break; case OPC_VR54XX_MULSHIU: - gen_op_mulshiu(); + gen_helper_mulshiu(t0, t0, t1); opn = "mulshiu"; - break; + break; case OPC_VR54XX_MACCHI: - gen_op_macchi(); + gen_helper_macchi(t0, t0, t1); opn = "macchi"; - break; + break; case OPC_VR54XX_MACCHIU: - gen_op_macchiu(); + gen_helper_macchiu(t0, t0, t1); opn = "macchiu"; - break; + break; case OPC_VR54XX_MSACHI: - gen_op_msachi(); + gen_helper_msachi(t0, t0, t1); opn = "msachi"; - break; + break; case OPC_VR54XX_MSACHIU: - gen_op_msachiu(); + gen_helper_msachiu(t0, t0, t1); opn = "msachiu"; - break; + break; default: MIPS_INVAL("mul vr54xx"); generate_exception(ctx, EXCP_RI); - return; + goto out; } - GEN_STORE_T0_REG(rd); + gen_store_gpr(t0, rd); + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); + + out: + tcg_temp_free(t0); + tcg_temp_free(t1); } static void gen_cl (DisasContext *ctx, uint32_t opc, int rd, int rs) { const char *opn = "CLx"; + TCGv t0; + if (rd == 0) { /* Treat as NOP. */ MIPS_DEBUG("NOP"); return; } - GEN_LOAD_REG_T0(rs); + t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); switch (opc) { case OPC_CLO: - gen_op_clo(); + gen_helper_clo(cpu_gpr[rd], t0); opn = "clo"; break; case OPC_CLZ: - gen_op_clz(); + gen_helper_clz(cpu_gpr[rd], t0); opn = "clz"; break; #if defined(TARGET_MIPS64) case OPC_DCLO: - gen_op_dclo(); + gen_helper_dclo(cpu_gpr[rd], t0); opn = "dclo"; break; case OPC_DCLZ: - gen_op_dclz(); + gen_helper_dclz(cpu_gpr[rd], t0); opn = "dclz"; break; #endif - default: - MIPS_INVAL(opn); - generate_exception(ctx, EXCP_RI); + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); + tcg_temp_free(t0); +} + +/* Godson integer instructions */ +static void gen_loongson_integer (DisasContext *ctx, uint32_t opc, + int rd, int rs, int rt) +{ + const char *opn = "loongson"; + TCGv t0, t1; + + if (rd == 0) { + /* Treat as NOP. */ + MIPS_DEBUG("NOP"); return; } - gen_op_store_T0_gpr(rd); + + switch (opc) { + case OPC_MULT_G_2E: + case OPC_MULT_G_2F: + case OPC_MULTU_G_2E: + case OPC_MULTU_G_2F: +#if defined(TARGET_MIPS64) + case OPC_DMULT_G_2E: + case OPC_DMULT_G_2F: + case OPC_DMULTU_G_2E: + case OPC_DMULTU_G_2F: +#endif + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + break; + default: + t0 = tcg_temp_local_new(); + t1 = tcg_temp_local_new(); + break; + } + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + + switch (opc) { + case OPC_MULT_G_2E: + case OPC_MULT_G_2F: + tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + opn = "mult.g"; + break; + case OPC_MULTU_G_2E: + case OPC_MULTU_G_2F: + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + opn = "multu.g"; + break; + case OPC_DIV_G_2E: + case OPC_DIV_G_2F: + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + int l3 = gen_new_label(); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + tcg_gen_movi_tl(cpu_gpr[rd], 0); + tcg_gen_br(l3); + gen_set_label(l1); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2); + tcg_gen_mov_tl(cpu_gpr[rd], t0); + tcg_gen_br(l3); + gen_set_label(l2); + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + gen_set_label(l3); + } + opn = "div.g"; + break; + case OPC_DIVU_G_2E: + case OPC_DIVU_G_2F: + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + tcg_gen_movi_tl(cpu_gpr[rd], 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + gen_set_label(l2); + } + opn = "divu.g"; + break; + case OPC_MOD_G_2E: + case OPC_MOD_G_2F: + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + int l3 = gen_new_label(); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2); + gen_set_label(l1); + tcg_gen_movi_tl(cpu_gpr[rd], 0); + tcg_gen_br(l3); + gen_set_label(l2); + tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + gen_set_label(l3); + } + opn = "mod.g"; + break; + case OPC_MODU_G_2E: + case OPC_MODU_G_2F: + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + tcg_gen_movi_tl(cpu_gpr[rd], 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + gen_set_label(l2); + } + opn = "modu.g"; + break; +#if defined(TARGET_MIPS64) + case OPC_DMULT_G_2E: + case OPC_DMULT_G_2F: + tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); + opn = "dmult.g"; + break; + case OPC_DMULTU_G_2E: + case OPC_DMULTU_G_2F: + tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); + opn = "dmultu.g"; + break; + case OPC_DDIV_G_2E: + case OPC_DDIV_G_2F: + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + int l3 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + tcg_gen_movi_tl(cpu_gpr[rd], 0); + tcg_gen_br(l3); + gen_set_label(l1); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2); + tcg_gen_mov_tl(cpu_gpr[rd], t0); + tcg_gen_br(l3); + gen_set_label(l2); + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + gen_set_label(l3); + } + opn = "ddiv.g"; + break; + case OPC_DDIVU_G_2E: + case OPC_DDIVU_G_2F: + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + tcg_gen_movi_tl(cpu_gpr[rd], 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); + gen_set_label(l2); + } + opn = "ddivu.g"; + break; + case OPC_DMOD_G_2E: + case OPC_DMOD_G_2F: + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + int l3 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2); + gen_set_label(l1); + tcg_gen_movi_tl(cpu_gpr[rd], 0); + tcg_gen_br(l3); + gen_set_label(l2); + tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); + gen_set_label(l3); + } + opn = "dmod.g"; + break; + case OPC_DMODU_G_2E: + case OPC_DMODU_G_2F: + { + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + tcg_gen_movi_tl(cpu_gpr[rd], 0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); + gen_set_label(l2); + } + opn = "dmodu.g"; + break; +#endif + } + + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); + tcg_temp_free(t0); + tcg_temp_free(t1); } /* Traps */ @@ -1680,6 +2588,8 @@ static void gen_trap (DisasContext *ctx, int rs, int rt, int16_t imm) { int cond; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); cond = 0; /* Load needed operands */ @@ -1692,8 +2602,8 @@ static void gen_trap (DisasContext *ctx, case OPC_TNE: /* Compare two registers */ if (rs != rt) { - GEN_LOAD_REG_T0(rs); - GEN_LOAD_REG_T1(rt); + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); cond = 1; } break; @@ -1705,8 +2615,8 @@ static void gen_trap (DisasContext *ctx, case OPC_TNEI: /* Compare register to immediate */ if (rs != 0 || imm != 0) { - GEN_LOAD_REG_T0(rs); - GEN_LOAD_IMM_TN(T1, (int32_t)imm); + gen_load_gpr(t0, rs); + tcg_gen_movi_tl(t1, (int32_t)imm); cond = 1; } break; @@ -1720,7 +2630,7 @@ static void gen_trap (DisasContext *ctx, case OPC_TGEU: /* rs >= rs unsigned */ case OPC_TGEIU: /* r0 >= 0 unsigned */ /* Always trap */ - gen_op_set_T0(1); + generate_exception(ctx, EXCP_TRAP); break; case OPC_TLT: /* rs < rs */ case OPC_TLTI: /* r0 < 0 */ @@ -1729,85 +2639,80 @@ static void gen_trap (DisasContext *ctx, case OPC_TNE: /* rs != rs */ case OPC_TNEI: /* r0 != 0 */ /* Never trap: treat as NOP. */ - return; - default: - MIPS_INVAL("trap"); - generate_exception(ctx, EXCP_RI); - return; + break; } } else { + int l1 = gen_new_label(); + switch (opc) { case OPC_TEQ: case OPC_TEQI: - gen_op_eq(); + tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l1); break; case OPC_TGE: case OPC_TGEI: - gen_op_ge(); + tcg_gen_brcond_tl(TCG_COND_LT, t0, t1, l1); break; case OPC_TGEU: case OPC_TGEIU: - gen_op_geu(); + tcg_gen_brcond_tl(TCG_COND_LTU, t0, t1, l1); break; case OPC_TLT: case OPC_TLTI: - gen_op_lt(); + tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1); break; case OPC_TLTU: case OPC_TLTIU: - gen_op_ltu(); + tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); break; case OPC_TNE: case OPC_TNEI: - gen_op_ne(); + tcg_gen_brcond_tl(TCG_COND_EQ, t0, t1, l1); break; - default: - MIPS_INVAL("trap"); - generate_exception(ctx, EXCP_RI); - return; } + generate_exception(ctx, EXCP_TRAP); + gen_set_label(l1); } - save_cpu_state(ctx, 1); - gen_op_trap(); - ctx->bstate = BS_STOP; + tcg_temp_free(t0); + tcg_temp_free(t1); } -static always_inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { TranslationBlock *tb; tb = ctx->tb; - if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && + likely(!ctx->singlestep_enabled)) { + tcg_gen_goto_tb(n); gen_save_pc(dest); - gen_op_set_T0((long)tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { gen_save_pc(dest); - gen_op_reset_T0(); + if (ctx->singlestep_enabled) { + save_cpu_state(ctx, 0); + gen_helper_0i(raise_exception, EXCP_DEBUG); + } + tcg_gen_exit_tb(0); } - gen_op_exit_tb(); } /* Branches (before delay slot) */ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, + int insn_bytes, int rs, int rt, int32_t offset) { - target_ulong btarget = -1; + target_ulong btgt = -1; int blink = 0; - int bcond = 0; + int bcond_compute = 0; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, - "Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", - ctx->pc); - } + LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); #endif generate_exception(ctx, EXCP_RI); - return; + goto out; } /* Load needed operands */ @@ -1818,14 +2723,15 @@ static void gen_compute_branch (DisasCon case OPC_BNEL: /* Compare two registers */ if (rs != rt) { - GEN_LOAD_REG_T0(rs); - GEN_LOAD_REG_T1(rt); - bcond = 1; + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; } - btarget = ctx->pc + 4 + offset; + btgt = ctx->pc + insn_bytes + offset; break; case OPC_BGEZ: case OPC_BGEZAL: + case OPC_BGEZALS: case OPC_BGEZALL: case OPC_BGEZL: case OPC_BGTZ: @@ -1834,38 +2740,44 @@ static void gen_compute_branch (DisasCon case OPC_BLEZL: case OPC_BLTZ: case OPC_BLTZAL: + case OPC_BLTZALS: case OPC_BLTZALL: case OPC_BLTZL: /* Compare to zero */ if (rs != 0) { - gen_op_load_gpr_T0(rs); - bcond = 1; + gen_load_gpr(t0, rs); + bcond_compute = 1; } - btarget = ctx->pc + 4 + offset; + btgt = ctx->pc + insn_bytes + offset; break; case OPC_J: case OPC_JAL: + case OPC_JALX: + case OPC_JALS: + case OPC_JALXS: /* Jump to immediate */ - btarget = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset; + btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset; break; case OPC_JR: case OPC_JALR: + case OPC_JALRC: + case OPC_JALRS: /* Jump to register */ if (offset != 0 && offset != 16) { /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the others are reserved. */ MIPS_INVAL("jump hint"); generate_exception(ctx, EXCP_RI); - return; + goto out; } - GEN_LOAD_REG_T2(rs); + gen_load_gpr(btarget, rs); break; default: MIPS_INVAL("branch/jump"); generate_exception(ctx, EXCP_RI); - return; + goto out; } - if (bcond == 0) { + if (bcond_compute == 0) { /* No condition to be computed */ switch (opc) { case OPC_BEQ: /* rx == rx */ @@ -1878,8 +2790,12 @@ static void gen_compute_branch (DisasCon ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways"); break; + case OPC_BGEZALS: case OPC_BGEZAL: /* 0 >= 0 */ case OPC_BGEZALL: /* 0 >= 0 likely */ + ctx->hflags |= (opc == OPC_BGEZALS + ? MIPS_HFLAG_BDS16 + : MIPS_HFLAG_BDS32); /* Always take and link */ blink = 31; ctx->hflags |= MIPS_HFLAG_B; @@ -1890,211 +2806,379 @@ static void gen_compute_branch (DisasCon case OPC_BLTZ: /* 0 < 0 */ /* Treat as NOP. */ MIPS_DEBUG("bnever (NOP)"); - return; + goto out; + case OPC_BLTZALS: case OPC_BLTZAL: /* 0 < 0 */ - GEN_LOAD_IMM_TN(T0, ctx->pc + 8); - gen_op_store_T0_gpr(31); + ctx->hflags |= (opc == OPC_BLTZALS + ? MIPS_HFLAG_BDS16 + : MIPS_HFLAG_BDS32); + /* Handle as an unconditional branch to get correct delay + slot checking. */ + blink = 31; + btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8); + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("bnever and link"); - return; + break; case OPC_BLTZALL: /* 0 < 0 likely */ - GEN_LOAD_IMM_TN(T0, ctx->pc + 8); - gen_op_store_T0_gpr(31); + tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 8); /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever, link and skip"); ctx->pc += 4; - return; + goto out; case OPC_BNEL: /* rx != rx likely */ case OPC_BGTZL: /* 0 > 0 likely */ case OPC_BLTZL: /* 0 < 0 likely */ /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever and skip"); ctx->pc += 4; - return; + goto out; case OPC_J: ctx->hflags |= MIPS_HFLAG_B; - MIPS_DEBUG("j " TARGET_FMT_lx, btarget); + MIPS_DEBUG("j " TARGET_FMT_lx, btgt); break; + case OPC_JALXS: + case OPC_JALX: + ctx->hflags |= MIPS_HFLAG_BX; + /* Fallthrough */ + case OPC_JALS: case OPC_JAL: blink = 31; ctx->hflags |= MIPS_HFLAG_B; - MIPS_DEBUG("jal " TARGET_FMT_lx, btarget); + ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS) + ? MIPS_HFLAG_BDS16 + : MIPS_HFLAG_BDS32); + MIPS_DEBUG("jal " TARGET_FMT_lx, btgt); break; case OPC_JR: ctx->hflags |= MIPS_HFLAG_BR; + if (insn_bytes == 4) + ctx->hflags |= MIPS_HFLAG_BDS32; MIPS_DEBUG("jr %s", regnames[rs]); break; + case OPC_JALRS: case OPC_JALR: + case OPC_JALRC: blink = rt; ctx->hflags |= MIPS_HFLAG_BR; + ctx->hflags |= (opc == OPC_JALRS + ? MIPS_HFLAG_BDS16 + : MIPS_HFLAG_BDS32); MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); break; default: MIPS_INVAL("branch/jump"); generate_exception(ctx, EXCP_RI); - return; + goto out; } } else { switch (opc) { case OPC_BEQ: - gen_op_eq(); + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); MIPS_DEBUG("beq %s, %s, " TARGET_FMT_lx, - regnames[rs], regnames[rt], btarget); + regnames[rs], regnames[rt], btgt); goto not_likely; case OPC_BEQL: - gen_op_eq(); + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); MIPS_DEBUG("beql %s, %s, " TARGET_FMT_lx, - regnames[rs], regnames[rt], btarget); + regnames[rs], regnames[rt], btgt); goto likely; case OPC_BNE: - gen_op_ne(); + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx, - regnames[rs], regnames[rt], btarget); + regnames[rs], regnames[rt], btgt); goto not_likely; case OPC_BNEL: - gen_op_ne(); + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx, - regnames[rs], regnames[rt], btarget); + regnames[rs], regnames[rt], btgt); goto likely; case OPC_BGEZ: - gen_op_gez(); - MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btarget); + tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); + MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btgt); goto not_likely; case OPC_BGEZL: - gen_op_gez(); - MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btarget); + tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); + MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; + case OPC_BGEZALS: case OPC_BGEZAL: - gen_op_gez(); - MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btarget); + ctx->hflags |= (opc == OPC_BGEZALS + ? MIPS_HFLAG_BDS16 + : MIPS_HFLAG_BDS32); + tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); + MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt); blink = 31; goto not_likely; case OPC_BGEZALL: - gen_op_gez(); + tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); blink = 31; - MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btarget); + MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; case OPC_BGTZ: - gen_op_gtz(); - MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btarget); + tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t0, 0); + MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btgt); goto not_likely; case OPC_BGTZL: - gen_op_gtz(); - MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btarget); + tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t0, 0); + MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; case OPC_BLEZ: - gen_op_lez(); - MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btarget); + tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t0, 0); + MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btgt); goto not_likely; case OPC_BLEZL: - gen_op_lez(); - MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btarget); + tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t0, 0); + MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; case OPC_BLTZ: - gen_op_ltz(); - MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btarget); + tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0); + MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btgt); goto not_likely; case OPC_BLTZL: - gen_op_ltz(); - MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btarget); + tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0); + MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; + case OPC_BLTZALS: case OPC_BLTZAL: - gen_op_ltz(); + ctx->hflags |= (opc == OPC_BLTZALS + ? MIPS_HFLAG_BDS16 + : MIPS_HFLAG_BDS32); + tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0); blink = 31; - MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btarget); + MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt); not_likely: ctx->hflags |= MIPS_HFLAG_BC; - gen_op_set_bcond(); break; case OPC_BLTZALL: - gen_op_ltz(); + tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0); blink = 31; - MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btarget); + MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btgt); likely: ctx->hflags |= MIPS_HFLAG_BL; - gen_op_set_bcond(); - gen_op_save_bcond(); break; default: MIPS_INVAL("conditional branch/jump"); generate_exception(ctx, EXCP_RI); - return; + goto out; } } MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx, - blink, ctx->hflags, btarget); + blink, ctx->hflags, btgt); - ctx->btarget = btarget; + ctx->btarget = btgt; if (blink > 0) { - GEN_LOAD_IMM_TN(T0, ctx->pc + 8); - gen_op_store_T0_gpr(blink); + int post_delay = insn_bytes; + int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16); + + if (opc != OPC_JALRC) + post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4); + + tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit); } + + out: + if (insn_bytes == 2) + ctx->hflags |= MIPS_HFLAG_B16; + tcg_temp_free(t0); + tcg_temp_free(t1); } /* special3 bitfield operations */ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, - int rs, int lsb, int msb) + int rs, int lsb, int msb) { - GEN_LOAD_REG_T1(rs); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + target_ulong mask; + + gen_load_gpr(t1, rs); switch (opc) { case OPC_EXT: if (lsb + msb > 31) goto fail; - gen_op_ext(lsb, msb + 1); + tcg_gen_shri_tl(t0, t1, lsb); + if (msb != 31) { + tcg_gen_andi_tl(t0, t0, (1 << (msb + 1)) - 1); + } else { + tcg_gen_ext32s_tl(t0, t0); + } break; #if defined(TARGET_MIPS64) case OPC_DEXTM: - if (lsb + msb > 63) - goto fail; - gen_op_dext(lsb, msb + 1 + 32); + tcg_gen_shri_tl(t0, t1, lsb); + if (msb != 31) { + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1 + 32)) - 1); + } break; case OPC_DEXTU: - if (lsb + msb > 63) - goto fail; - gen_op_dext(lsb + 32, msb + 1); + tcg_gen_shri_tl(t0, t1, lsb + 32); + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); break; case OPC_DEXT: - if (lsb + msb > 63) - goto fail; - gen_op_dext(lsb, msb + 1); + tcg_gen_shri_tl(t0, t1, lsb); + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); break; #endif case OPC_INS: if (lsb > msb) goto fail; - GEN_LOAD_REG_T0(rt); - gen_op_ins(lsb, msb - lsb + 1); + mask = ((msb - lsb + 1 < 32) ? ((1 << (msb - lsb + 1)) - 1) : ~0) << lsb; + gen_load_gpr(t0, rt); + tcg_gen_andi_tl(t0, t0, ~mask); + tcg_gen_shli_tl(t1, t1, lsb); + tcg_gen_andi_tl(t1, t1, mask); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_ext32s_tl(t0, t0); break; #if defined(TARGET_MIPS64) case OPC_DINSM: if (lsb > msb) goto fail; - GEN_LOAD_REG_T0(rt); - gen_op_dins(lsb, msb - lsb + 1 + 32); + mask = ((msb - lsb + 1 + 32 < 64) ? ((1ULL << (msb - lsb + 1 + 32)) - 1) : ~0ULL) << lsb; + gen_load_gpr(t0, rt); + tcg_gen_andi_tl(t0, t0, ~mask); + tcg_gen_shli_tl(t1, t1, lsb); + tcg_gen_andi_tl(t1, t1, mask); + tcg_gen_or_tl(t0, t0, t1); break; case OPC_DINSU: if (lsb > msb) goto fail; - GEN_LOAD_REG_T0(rt); - gen_op_dins(lsb + 32, msb - lsb + 1); + mask = ((1ULL << (msb - lsb + 1)) - 1) << (lsb + 32); + gen_load_gpr(t0, rt); + tcg_gen_andi_tl(t0, t0, ~mask); + tcg_gen_shli_tl(t1, t1, lsb + 32); + tcg_gen_andi_tl(t1, t1, mask); + tcg_gen_or_tl(t0, t0, t1); break; case OPC_DINS: if (lsb > msb) goto fail; - GEN_LOAD_REG_T0(rt); - gen_op_dins(lsb, msb - lsb + 1); + gen_load_gpr(t0, rt); + mask = ((1ULL << (msb - lsb + 1)) - 1) << lsb; + gen_load_gpr(t0, rt); + tcg_gen_andi_tl(t0, t0, ~mask); + tcg_gen_shli_tl(t1, t1, lsb); + tcg_gen_andi_tl(t1, t1, mask); + tcg_gen_or_tl(t0, t0, t1); break; #endif default: fail: MIPS_INVAL("bitops"); generate_exception(ctx, EXCP_RI); + tcg_temp_free(t0); + tcg_temp_free(t1); return; } - GEN_STORE_T0_REG(rt); + gen_store_gpr(t0, rt); + tcg_temp_free(t0); + tcg_temp_free(t1); } +static void gen_bshfl (DisasContext *ctx, uint32_t op2, int rt, int rd) +{ + TCGv t0; + + if (rd == 0) { + /* If no destination, treat it as a NOP. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, rt); + switch (op2) { + case OPC_WSBH: + { + TCGv t1 = tcg_temp_new(); + + tcg_gen_shri_tl(t1, t0, 8); + tcg_gen_andi_tl(t1, t1, 0x00FF00FF); + tcg_gen_shli_tl(t0, t0, 8); + tcg_gen_andi_tl(t0, t0, ~0x00FF00FF); + tcg_gen_or_tl(t0, t0, t1); + tcg_temp_free(t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + } + break; + case OPC_SEB: + tcg_gen_ext8s_tl(cpu_gpr[rd], t0); + break; + case OPC_SEH: + tcg_gen_ext16s_tl(cpu_gpr[rd], t0); + break; +#if defined(TARGET_MIPS64) + case OPC_DSBH: + { + TCGv t1 = tcg_temp_new(); + + tcg_gen_shri_tl(t1, t0, 8); + tcg_gen_andi_tl(t1, t1, 0x00FF00FF00FF00FFULL); + tcg_gen_shli_tl(t0, t0, 8); + tcg_gen_andi_tl(t0, t0, ~0x00FF00FF00FF00FFULL); + tcg_gen_or_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t1); + } + break; + case OPC_DSHD: + { + TCGv t1 = tcg_temp_new(); + + tcg_gen_shri_tl(t1, t0, 16); + tcg_gen_andi_tl(t1, t1, 0x0000FFFF0000FFFFULL); + tcg_gen_shli_tl(t0, t0, 16); + tcg_gen_andi_tl(t0, t0, ~0x0000FFFF0000FFFFULL); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_shri_tl(t1, t0, 32); + tcg_gen_shli_tl(t0, t0, 32); + tcg_gen_or_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t1); + } + break; +#endif + default: + MIPS_INVAL("bsfhl"); + generate_exception(ctx, EXCP_RI); + tcg_temp_free(t0); + return; + } + tcg_temp_free(t0); +} + +#ifndef CONFIG_USER_ONLY /* CP0 (MMU and control) */ -static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) +static inline void gen_mfc0_load32 (TCGv arg, target_ulong off) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + + tcg_gen_ld_i32(t0, cpu_env, off); + tcg_gen_ext_i32_tl(arg, t0); + tcg_temp_free_i32(t0); +} + +static inline void gen_mfc0_load64 (TCGv arg, target_ulong off) +{ + tcg_gen_ld_tl(arg, cpu_env, off); + tcg_gen_ext32s_tl(arg, arg); +} + +static inline void gen_mtc0_store32 (TCGv arg, target_ulong off) +{ + TCGv_i32 t0 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t0, arg); + tcg_gen_st_i32(t0, cpu_env, off); + tcg_temp_free_i32(t0); +} + +static inline void gen_mtc0_store64 (TCGv arg, target_ulong off) +{ + tcg_gen_ext32s_tl(arg, arg); + tcg_gen_st_tl(arg, cpu_env, off); +} + +static void gen_mfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; @@ -2105,22 +3189,22 @@ static void gen_mfc0 (CPUState *env, Dis case 0: switch (sel) { case 0: - gen_op_mfc0_index(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Index)); rn = "Index"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpcontrol(); + gen_helper_mfc0_mvpcontrol(arg); rn = "MVPControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpconf0(); + gen_helper_mfc0_mvpconf0(arg); rn = "MVPConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpconf1(); + gen_helper_mfc0_mvpconf1(arg); rn = "MVPConf1"; break; default: @@ -2130,42 +3214,42 @@ static void gen_mfc0 (CPUState *env, Dis case 1: switch (sel) { case 0: - gen_op_mfc0_random(); + gen_helper_mfc0_random(arg); rn = "Random"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpecontrol(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEControl)); rn = "VPEControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeconf0(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEConf0)); rn = "VPEConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeconf1(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEConf1)); rn = "VPEConf1"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_yqmask(); + gen_mfc0_load64(arg, offsetof(CPUState, CP0_YQMask)); rn = "YQMask"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeschedule(); + gen_mfc0_load64(arg, offsetof(CPUState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeschefback(); + gen_mfc0_load64(arg, offsetof(CPUState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeopt(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEOpt)); rn = "VPEOpt"; break; default: @@ -2175,42 +3259,43 @@ static void gen_mfc0 (CPUState *env, Dis case 2: switch (sel) { case 0: - gen_op_mfc0_entrylo0(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryLo0)); + tcg_gen_ext32s_tl(arg, arg); rn = "EntryLo0"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcstatus(); + gen_helper_mfc0_tcstatus(arg); rn = "TCStatus"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcbind(); + gen_helper_mfc0_tcbind(arg); rn = "TCBind"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcrestart(); + gen_helper_mfc0_tcrestart(arg); rn = "TCRestart"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tchalt(); + gen_helper_mfc0_tchalt(arg); rn = "TCHalt"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tccontext(); + gen_helper_mfc0_tccontext(arg); rn = "TCContext"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcschedule(); + gen_helper_mfc0_tcschedule(arg); rn = "TCSchedule"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcschefback(); + gen_helper_mfc0_tcschefback(arg); rn = "TCScheFBack"; break; default: @@ -2220,7 +3305,8 @@ static void gen_mfc0 (CPUState *env, Dis case 3: switch (sel) { case 0: - gen_op_mfc0_entrylo1(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryLo1)); + tcg_gen_ext32s_tl(arg, arg); rn = "EntryLo1"; break; default: @@ -2230,11 +3316,12 @@ static void gen_mfc0 (CPUState *env, Dis case 4: switch (sel) { case 0: - gen_op_mfc0_context(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_Context)); + tcg_gen_ext32s_tl(arg, arg); rn = "Context"; break; case 1: -// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */ +// gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -2244,12 +3331,12 @@ static void gen_mfc0 (CPUState *env, Dis case 5: switch (sel) { case 0: - gen_op_mfc0_pagemask(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_PageMask)); rn = "PageMask"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_pagegrain(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_PageGrain)); rn = "PageGrain"; break; default: @@ -2259,32 +3346,32 @@ static void gen_mfc0 (CPUState *env, Dis case 6: switch (sel) { case 0: - gen_op_mfc0_wired(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Wired)); rn = "Wired"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf0(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf0)); rn = "SRSConf0"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf1(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf1)); rn = "SRSConf1"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf2(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf2)); rn = "SRSConf2"; break; case 4: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf3(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf3)); rn = "SRSConf3"; break; case 5: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf4(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf4)); rn = "SRSConf4"; break; default: @@ -2295,7 +3382,7 @@ static void gen_mfc0 (CPUState *env, Dis switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_hwrena(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_HWREna)); rn = "HWREna"; break; default: @@ -2305,8 +3392,9 @@ static void gen_mfc0 (CPUState *env, Dis case 8: switch (sel) { case 0: - gen_op_mfc0_badvaddr(); - rn = "BadVaddr"; + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_BadVAddr)); + tcg_gen_ext32s_tl(arg, arg); + rn = "BadVAddr"; break; default: goto die; @@ -2315,7 +3403,16 @@ static void gen_mfc0 (CPUState *env, Dis case 9: switch (sel) { case 0: - gen_op_mfc0_count(); + /* Mark as an IO operation because we read the time. */ + if (use_icount) + gen_io_start(); + gen_helper_mfc0_count(arg); + if (use_icount) { + gen_io_end(); + } + /* Break the TB to be able to take timer interrupts immediately + after reading count. */ + ctx->bstate = BS_STOP; rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -2326,7 +3423,8 @@ static void gen_mfc0 (CPUState *env, Dis case 10: switch (sel) { case 0: - gen_op_mfc0_entryhi(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryHi)); + tcg_gen_ext32s_tl(arg, arg); rn = "EntryHi"; break; default: @@ -2336,7 +3434,7 @@ static void gen_mfc0 (CPUState *env, Dis case 11: switch (sel) { case 0: - gen_op_mfc0_compare(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Compare)); rn = "Compare"; break; /* 6,7 are implementation dependent */ @@ -2347,22 +3445,22 @@ static void gen_mfc0 (CPUState *env, Dis case 12: switch (sel) { case 0: - gen_op_mfc0_status(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Status)); rn = "Status"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_intctl(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_IntCtl)); rn = "IntCtl"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsctl(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSCtl)); rn = "SRSCtl"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsmap(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSMap)); rn = "SRSMap"; break; default: @@ -2372,7 +3470,7 @@ static void gen_mfc0 (CPUState *env, Dis case 13: switch (sel) { case 0: - gen_op_mfc0_cause(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Cause)); rn = "Cause"; break; default: @@ -2382,7 +3480,8 @@ static void gen_mfc0 (CPUState *env, Dis case 14: switch (sel) { case 0: - gen_op_mfc0_epc(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EPC)); + tcg_gen_ext32s_tl(arg, arg); rn = "EPC"; break; default: @@ -2392,12 +3491,12 @@ static void gen_mfc0 (CPUState *env, Dis case 15: switch (sel) { case 0: - gen_op_mfc0_prid(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_PRid)); rn = "PRid"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_ebase(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_EBase)); rn = "EBase"; break; default: @@ -2407,29 +3506,29 @@ static void gen_mfc0 (CPUState *env, Dis case 16: switch (sel) { case 0: - gen_op_mfc0_config0(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config0)); rn = "Config"; break; case 1: - gen_op_mfc0_config1(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config1)); rn = "Config1"; break; case 2: - gen_op_mfc0_config2(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config2)); rn = "Config2"; break; case 3: - gen_op_mfc0_config3(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config3)); rn = "Config3"; break; /* 4,5 are reserved */ /* 6,7 are implementation dependent */ case 6: - gen_op_mfc0_config6(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config6)); rn = "Config6"; break; case 7: - gen_op_mfc0_config7(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config7)); rn = "Config7"; break; default: @@ -2439,7 +3538,7 @@ static void gen_mfc0 (CPUState *env, Dis case 17: switch (sel) { case 0: - gen_op_mfc0_lladdr(); + gen_helper_mfc0_lladdr(arg); rn = "LLAddr"; break; default: @@ -2449,7 +3548,7 @@ static void gen_mfc0 (CPUState *env, Dis case 18: switch (sel) { case 0 ... 7: - gen_op_mfc0_watchlo(sel); + gen_helper_1i(mfc0_watchlo, arg, sel); rn = "WatchLo"; break; default: @@ -2459,7 +3558,7 @@ static void gen_mfc0 (CPUState *env, Dis case 19: switch (sel) { case 0 ...7: - gen_op_mfc0_watchhi(sel); + gen_helper_1i(mfc0_watchhi, arg, sel); rn = "WatchHi"; break; default: @@ -2471,7 +3570,8 @@ static void gen_mfc0 (CPUState *env, Dis case 0: #if defined(TARGET_MIPS64) check_insn(env, ctx, ISA_MIPS3); - gen_op_mfc0_xcontext(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_XContext)); + tcg_gen_ext32s_tl(arg, arg); rn = "XContext"; break; #endif @@ -2483,7 +3583,7 @@ static void gen_mfc0 (CPUState *env, Dis /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mfc0_framemask(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Framemask)); rn = "Framemask"; break; default: @@ -2491,29 +3591,29 @@ static void gen_mfc0 (CPUState *env, Dis } break; case 22: - /* ignored */ + tcg_gen_movi_tl(arg, 0); /* unimplemented */ rn = "'Diagnostic"; /* implementation dependent */ break; case 23: switch (sel) { case 0: - gen_op_mfc0_debug(); /* EJTAG support */ + gen_helper_mfc0_debug(arg); /* EJTAG support */ rn = "Debug"; break; case 1: -// gen_op_mfc0_tracecontrol(); /* PDtrace support */ +// gen_helper_mfc0_tracecontrol(arg); /* PDtrace support */ rn = "TraceControl"; // break; case 2: -// gen_op_mfc0_tracecontrol2(); /* PDtrace support */ +// gen_helper_mfc0_tracecontrol2(arg); /* PDtrace support */ rn = "TraceControl2"; // break; case 3: -// gen_op_mfc0_usertracedata(); /* PDtrace support */ +// gen_helper_mfc0_usertracedata(arg); /* PDtrace support */ rn = "UserTraceData"; // break; case 4: -// gen_op_mfc0_debug(); /* PDtrace support */ +// gen_helper_mfc0_tracebpc(arg); /* PDtrace support */ rn = "TraceBPC"; // break; default: @@ -2523,7 +3623,9 @@ static void gen_mfc0 (CPUState *env, Dis case 24: switch (sel) { case 0: - gen_op_mfc0_depc(); /* EJTAG support */ + /* EJTAG support */ + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_DEPC)); + tcg_gen_ext32s_tl(arg, arg); rn = "DEPC"; break; default: @@ -2533,35 +3635,35 @@ static void gen_mfc0 (CPUState *env, Dis case 25: switch (sel) { case 0: - gen_op_mfc0_performance0(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Performance0)); rn = "Performance0"; break; case 1: -// gen_op_mfc0_performance1(); +// gen_helper_mfc0_performance1(arg); rn = "Performance1"; // break; case 2: -// gen_op_mfc0_performance2(); +// gen_helper_mfc0_performance2(arg); rn = "Performance2"; // break; case 3: -// gen_op_mfc0_performance3(); +// gen_helper_mfc0_performance3(arg); rn = "Performance3"; // break; case 4: -// gen_op_mfc0_performance4(); +// gen_helper_mfc0_performance4(arg); rn = "Performance4"; // break; case 5: -// gen_op_mfc0_performance5(); +// gen_helper_mfc0_performance5(arg); rn = "Performance5"; // break; case 6: -// gen_op_mfc0_performance6(); +// gen_helper_mfc0_performance6(arg); rn = "Performance6"; // break; case 7: -// gen_op_mfc0_performance7(); +// gen_helper_mfc0_performance7(arg); rn = "Performance7"; // break; default: @@ -2569,12 +3671,13 @@ static void gen_mfc0 (CPUState *env, Dis } break; case 26: - rn = "ECC"; - break; + tcg_gen_movi_tl(arg, 0); /* unimplemented */ + rn = "ECC"; + break; case 27: switch (sel) { - /* ignored */ case 0 ... 3: + tcg_gen_movi_tl(arg, 0); /* unimplemented */ rn = "CacheErr"; break; default: @@ -2587,14 +3690,14 @@ static void gen_mfc0 (CPUState *env, Dis case 2: case 4: case 6: - gen_op_mfc0_taglo(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_TagLo)); rn = "TagLo"; break; case 1: case 3: case 5: case 7: - gen_op_mfc0_datalo(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_DataLo)); rn = "DataLo"; break; default: @@ -2607,14 +3710,14 @@ static void gen_mfc0 (CPUState *env, Dis case 2: case 4: case 6: - gen_op_mfc0_taghi(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_TagHi)); rn = "TagHi"; break; case 1: case 3: case 5: case 7: - gen_op_mfc0_datahi(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_DataHi)); rn = "DataHi"; break; default: @@ -2624,7 +3727,8 @@ static void gen_mfc0 (CPUState *env, Dis case 30: switch (sel) { case 0: - gen_op_mfc0_errorepc(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_ErrorEPC)); + tcg_gen_ext32s_tl(arg, arg); rn = "ErrorEPC"; break; default: @@ -2634,7 +3738,8 @@ static void gen_mfc0 (CPUState *env, Dis case 31: switch (sel) { case 0: - gen_op_mfc0_desave(); /* EJTAG support */ + /* EJTAG support */ + gen_mfc0_load32(arg, offsetof(CPUState, CP0_DESAVE)); rn = "DESAVE"; break; default: @@ -2644,41 +3749,35 @@ static void gen_mfc0 (CPUState *env, Dis default: goto die; } -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "mfc0 %s (reg %d sel %d)\n", - rn, reg, sel); - } -#endif + (void)rn; /* avoid a compiler warning */ + LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel); return; die: -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "mfc0 %s (reg %d sel %d)\n", - rn, reg, sel); - } -#endif + LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel); generate_exception(ctx, EXCP_RI); } -static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) +static void gen_mtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; if (sel != 0) check_insn(env, ctx, ISA_MIPS32); + if (use_icount) + gen_io_start(); + switch (reg) { case 0: switch (sel) { case 0: - gen_op_mtc0_index(); + gen_helper_mtc0_index(arg); rn = "Index"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_mvpcontrol(); + gen_helper_mtc0_mvpcontrol(arg); rn = "MVPControl"; break; case 2: @@ -2703,37 +3802,37 @@ static void gen_mtc0 (CPUState *env, Dis break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpecontrol(); + gen_helper_mtc0_vpecontrol(arg); rn = "VPEControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeconf0(); + gen_helper_mtc0_vpeconf0(arg); rn = "VPEConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeconf1(); + gen_helper_mtc0_vpeconf1(arg); rn = "VPEConf1"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_yqmask(); + gen_helper_mtc0_yqmask(arg); rn = "YQMask"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeschedule(); + gen_mtc0_store64(arg, offsetof(CPUState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeschefback(); + gen_mtc0_store64(arg, offsetof(CPUState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeopt(); + gen_helper_mtc0_vpeopt(arg); rn = "VPEOpt"; break; default: @@ -2743,42 +3842,42 @@ static void gen_mtc0 (CPUState *env, Dis case 2: switch (sel) { case 0: - gen_op_mtc0_entrylo0(); + gen_helper_mtc0_entrylo0(arg); rn = "EntryLo0"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcstatus(); + gen_helper_mtc0_tcstatus(arg); rn = "TCStatus"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcbind(); + gen_helper_mtc0_tcbind(arg); rn = "TCBind"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcrestart(); + gen_helper_mtc0_tcrestart(arg); rn = "TCRestart"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tchalt(); + gen_helper_mtc0_tchalt(arg); rn = "TCHalt"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tccontext(); + gen_helper_mtc0_tccontext(arg); rn = "TCContext"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcschedule(); + gen_helper_mtc0_tcschedule(arg); rn = "TCSchedule"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcschefback(); + gen_helper_mtc0_tcschefback(arg); rn = "TCScheFBack"; break; default: @@ -2788,7 +3887,7 @@ static void gen_mtc0 (CPUState *env, Dis case 3: switch (sel) { case 0: - gen_op_mtc0_entrylo1(); + gen_helper_mtc0_entrylo1(arg); rn = "EntryLo1"; break; default: @@ -2798,11 +3897,11 @@ static void gen_mtc0 (CPUState *env, Dis case 4: switch (sel) { case 0: - gen_op_mtc0_context(); + gen_helper_mtc0_context(arg); rn = "Context"; break; case 1: -// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */ +// gen_helper_mtc0_contextconfig(arg); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -2812,12 +3911,12 @@ static void gen_mtc0 (CPUState *env, Dis case 5: switch (sel) { case 0: - gen_op_mtc0_pagemask(); + gen_helper_mtc0_pagemask(arg); rn = "PageMask"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_pagegrain(); + gen_helper_mtc0_pagegrain(arg); rn = "PageGrain"; break; default: @@ -2827,32 +3926,32 @@ static void gen_mtc0 (CPUState *env, Dis case 6: switch (sel) { case 0: - gen_op_mtc0_wired(); + gen_helper_mtc0_wired(arg); rn = "Wired"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf0(); + gen_helper_mtc0_srsconf0(arg); rn = "SRSConf0"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf1(); + gen_helper_mtc0_srsconf1(arg); rn = "SRSConf1"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf2(); + gen_helper_mtc0_srsconf2(arg); rn = "SRSConf2"; break; case 4: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf3(); + gen_helper_mtc0_srsconf3(arg); rn = "SRSConf3"; break; case 5: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf4(); + gen_helper_mtc0_srsconf4(arg); rn = "SRSConf4"; break; default: @@ -2863,7 +3962,7 @@ static void gen_mtc0 (CPUState *env, Dis switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_hwrena(); + gen_helper_mtc0_hwrena(arg); rn = "HWREna"; break; default: @@ -2872,25 +3971,23 @@ static void gen_mtc0 (CPUState *env, Dis break; case 8: /* ignored */ - rn = "BadVaddr"; + rn = "BadVAddr"; break; case 9: switch (sel) { case 0: - gen_op_mtc0_count(); + gen_helper_mtc0_count(arg); rn = "Count"; break; /* 6,7 are implementation dependent */ default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 10: switch (sel) { case 0: - gen_op_mtc0_entryhi(); + gen_helper_mtc0_entryhi(arg); rn = "EntryHi"; break; default: @@ -2900,20 +3997,19 @@ static void gen_mtc0 (CPUState *env, Dis case 11: switch (sel) { case 0: - gen_op_mtc0_compare(); + gen_helper_mtc0_compare(arg); rn = "Compare"; break; /* 6,7 are implementation dependent */ default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 12: switch (sel) { case 0: - gen_op_mtc0_status(); + save_cpu_state(ctx, 1); + gen_helper_mtc0_status(arg); /* BS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->pc + 4); ctx->bstate = BS_EXCP; @@ -2921,21 +4017,21 @@ static void gen_mtc0 (CPUState *env, Dis break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_intctl(); + gen_helper_mtc0_intctl(arg); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsctl(); + gen_helper_mtc0_srsctl(arg); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsmap(); + gen_mtc0_store32(arg, offsetof(CPUState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSMap"; @@ -2947,19 +4043,18 @@ static void gen_mtc0 (CPUState *env, Dis case 13: switch (sel) { case 0: - gen_op_mtc0_cause(); + save_cpu_state(ctx, 1); + gen_helper_mtc0_cause(arg); rn = "Cause"; break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 14: switch (sel) { case 0: - gen_op_mtc0_epc(); + gen_mtc0_store64(arg, offsetof(CPUState, CP0_EPC)); rn = "EPC"; break; default: @@ -2974,7 +4069,7 @@ static void gen_mtc0 (CPUState *env, Dis break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_ebase(); + gen_helper_mtc0_ebase(arg); rn = "EBase"; break; default: @@ -2984,7 +4079,7 @@ static void gen_mtc0 (CPUState *env, Dis case 16: switch (sel) { case 0: - gen_op_mtc0_config0(); + gen_helper_mtc0_config0(arg); rn = "Config"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -2994,7 +4089,7 @@ static void gen_mtc0 (CPUState *env, Dis rn = "Config1"; break; case 2: - gen_op_mtc0_config2(); + gen_helper_mtc0_config2(arg); rn = "Config2"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -3021,7 +4116,7 @@ static void gen_mtc0 (CPUState *env, Dis case 17: switch (sel) { case 0: - /* ignored */ + gen_helper_mtc0_lladdr(arg); rn = "LLAddr"; break; default: @@ -3031,7 +4126,7 @@ static void gen_mtc0 (CPUState *env, Dis case 18: switch (sel) { case 0 ... 7: - gen_op_mtc0_watchlo(sel); + gen_helper_1i(mtc0_watchlo, arg, sel); rn = "WatchLo"; break; default: @@ -3041,7 +4136,7 @@ static void gen_mtc0 (CPUState *env, Dis case 19: switch (sel) { case 0 ... 7: - gen_op_mtc0_watchhi(sel); + gen_helper_1i(mtc0_watchhi, arg, sel); rn = "WatchHi"; break; default: @@ -3053,7 +4148,7 @@ static void gen_mtc0 (CPUState *env, Dis case 0: #if defined(TARGET_MIPS64) check_insn(env, ctx, ISA_MIPS3); - gen_op_mtc0_xcontext(); + gen_helper_mtc0_xcontext(arg); rn = "XContext"; break; #endif @@ -3065,7 +4160,7 @@ static void gen_mtc0 (CPUState *env, Dis /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mtc0_framemask(); + gen_helper_mtc0_framemask(arg); rn = "Framemask"; break; default: @@ -3079,20 +4174,20 @@ static void gen_mtc0 (CPUState *env, Dis case 23: switch (sel) { case 0: - gen_op_mtc0_debug(); /* EJTAG support */ + gen_helper_mtc0_debug(arg); /* EJTAG support */ /* BS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->pc + 4); ctx->bstate = BS_EXCP; rn = "Debug"; break; case 1: -// gen_op_mtc0_tracecontrol(); /* PDtrace support */ +// gen_helper_mtc0_tracecontrol(arg); /* PDtrace support */ rn = "TraceControl"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; // break; case 2: -// gen_op_mtc0_tracecontrol2(); /* PDtrace support */ +// gen_helper_mtc0_tracecontrol2(arg); /* PDtrace support */ rn = "TraceControl2"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -3100,13 +4195,13 @@ static void gen_mtc0 (CPUState *env, Dis case 3: /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; -// gen_op_mtc0_usertracedata(); /* PDtrace support */ +// gen_helper_mtc0_usertracedata(arg); /* PDtrace support */ rn = "UserTraceData"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; // break; case 4: -// gen_op_mtc0_debug(); /* PDtrace support */ +// gen_helper_mtc0_tracebpc(arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "TraceBPC"; @@ -3118,7 +4213,8 @@ static void gen_mtc0 (CPUState *env, Dis case 24: switch (sel) { case 0: - gen_op_mtc0_depc(); /* EJTAG support */ + /* EJTAG support */ + gen_mtc0_store64(arg, offsetof(CPUState, CP0_DEPC)); rn = "DEPC"; break; default: @@ -3128,35 +4224,35 @@ static void gen_mtc0 (CPUState *env, Dis case 25: switch (sel) { case 0: - gen_op_mtc0_performance0(); + gen_helper_mtc0_performance0(arg); rn = "Performance0"; break; case 1: -// gen_op_mtc0_performance1(); +// gen_helper_mtc0_performance1(arg); rn = "Performance1"; // break; case 2: -// gen_op_mtc0_performance2(); +// gen_helper_mtc0_performance2(arg); rn = "Performance2"; // break; case 3: -// gen_op_mtc0_performance3(); +// gen_helper_mtc0_performance3(arg); rn = "Performance3"; // break; case 4: -// gen_op_mtc0_performance4(); +// gen_helper_mtc0_performance4(arg); rn = "Performance4"; // break; case 5: -// gen_op_mtc0_performance5(); +// gen_helper_mtc0_performance5(arg); rn = "Performance5"; // break; case 6: -// gen_op_mtc0_performance6(); +// gen_helper_mtc0_performance6(arg); rn = "Performance6"; // break; case 7: -// gen_op_mtc0_performance7(); +// gen_helper_mtc0_performance7(arg); rn = "Performance7"; // break; default: @@ -3183,14 +4279,14 @@ static void gen_mtc0 (CPUState *env, Dis case 2: case 4: case 6: - gen_op_mtc0_taglo(); + gen_helper_mtc0_taglo(arg); rn = "TagLo"; break; case 1: case 3: case 5: case 7: - gen_op_mtc0_datalo(); + gen_helper_mtc0_datalo(arg); rn = "DataLo"; break; default: @@ -3203,14 +4299,14 @@ static void gen_mtc0 (CPUState *env, Dis case 2: case 4: case 6: - gen_op_mtc0_taghi(); + gen_helper_mtc0_taghi(arg); rn = "TagHi"; break; case 1: case 3: case 5: case 7: - gen_op_mtc0_datahi(); + gen_helper_mtc0_datahi(arg); rn = "DataHi"; break; default: @@ -3221,7 +4317,7 @@ static void gen_mtc0 (CPUState *env, Dis case 30: switch (sel) { case 0: - gen_op_mtc0_errorepc(); + gen_mtc0_store64(arg, offsetof(CPUState, CP0_ErrorEPC)); rn = "ErrorEPC"; break; default: @@ -3231,7 +4327,8 @@ static void gen_mtc0 (CPUState *env, Dis case 31: switch (sel) { case 0: - gen_op_mtc0_desave(); /* EJTAG support */ + /* EJTAG support */ + gen_mtc0_store32(arg, offsetof(CPUState, CP0_DESAVE)); rn = "DESAVE"; break; default: @@ -3243,26 +4340,22 @@ static void gen_mtc0 (CPUState *env, Dis default: goto die; } -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "mtc0 %s (reg %d sel %d)\n", - rn, reg, sel); + (void)rn; /* avoid a compiler warning */ + LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel); + /* For simplicity assume that all writes can cause interrupts. */ + if (use_icount) { + gen_io_end(); + ctx->bstate = BS_STOP; } -#endif return; die: -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "mtc0 %s (reg %d sel %d)\n", - rn, reg, sel); - } -#endif + LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel); generate_exception(ctx, EXCP_RI); } #if defined(TARGET_MIPS64) -static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) +static void gen_dmfc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; @@ -3273,22 +4366,22 @@ static void gen_dmfc0 (CPUState *env, Di case 0: switch (sel) { case 0: - gen_op_mfc0_index(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Index)); rn = "Index"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpcontrol(); + gen_helper_mfc0_mvpcontrol(arg); rn = "MVPControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpconf0(); + gen_helper_mfc0_mvpconf0(arg); rn = "MVPConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_mvpconf1(); + gen_helper_mfc0_mvpconf1(arg); rn = "MVPConf1"; break; default: @@ -3298,42 +4391,42 @@ static void gen_dmfc0 (CPUState *env, Di case 1: switch (sel) { case 0: - gen_op_mfc0_random(); + gen_helper_mfc0_random(arg); rn = "Random"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpecontrol(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEControl)); rn = "VPEControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeconf0(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEConf0)); rn = "VPEConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeconf1(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEConf1)); rn = "VPEConf1"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_yqmask(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_YQMask)); rn = "YQMask"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_vpeschedule(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_vpeschefback(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_vpeopt(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_VPEOpt)); rn = "VPEOpt"; break; default: @@ -3343,42 +4436,42 @@ static void gen_dmfc0 (CPUState *env, Di case 2: switch (sel) { case 0: - gen_op_dmfc0_entrylo0(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryLo0)); rn = "EntryLo0"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcstatus(); + gen_helper_mfc0_tcstatus(arg); rn = "TCStatus"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mfc0_tcbind(); + gen_helper_mfc0_tcbind(arg); rn = "TCBind"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tcrestart(); + gen_helper_dmfc0_tcrestart(arg); rn = "TCRestart"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tchalt(); + gen_helper_dmfc0_tchalt(arg); rn = "TCHalt"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tccontext(); + gen_helper_dmfc0_tccontext(arg); rn = "TCContext"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tcschedule(); + gen_helper_dmfc0_tcschedule(arg); rn = "TCSchedule"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_dmfc0_tcschefback(); + gen_helper_dmfc0_tcschefback(arg); rn = "TCScheFBack"; break; default: @@ -3388,7 +4481,7 @@ static void gen_dmfc0 (CPUState *env, Di case 3: switch (sel) { case 0: - gen_op_dmfc0_entrylo1(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryLo1)); rn = "EntryLo1"; break; default: @@ -3398,11 +4491,11 @@ static void gen_dmfc0 (CPUState *env, Di case 4: switch (sel) { case 0: - gen_op_dmfc0_context(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_Context)); rn = "Context"; break; case 1: -// gen_op_dmfc0_contextconfig(); /* SmartMIPS ASE */ +// gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -3412,12 +4505,12 @@ static void gen_dmfc0 (CPUState *env, Di case 5: switch (sel) { case 0: - gen_op_mfc0_pagemask(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_PageMask)); rn = "PageMask"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_pagegrain(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_PageGrain)); rn = "PageGrain"; break; default: @@ -3427,32 +4520,32 @@ static void gen_dmfc0 (CPUState *env, Di case 6: switch (sel) { case 0: - gen_op_mfc0_wired(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Wired)); rn = "Wired"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf0(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf0)); rn = "SRSConf0"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf1(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf1)); rn = "SRSConf1"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf2(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf2)); rn = "SRSConf2"; break; case 4: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf3(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf3)); rn = "SRSConf3"; break; case 5: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsconf4(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSConf4)); rn = "SRSConf4"; break; default: @@ -3463,7 +4556,7 @@ static void gen_dmfc0 (CPUState *env, Di switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_hwrena(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_HWREna)); rn = "HWREna"; break; default: @@ -3473,8 +4566,8 @@ static void gen_dmfc0 (CPUState *env, Di case 8: switch (sel) { case 0: - gen_op_dmfc0_badvaddr(); - rn = "BadVaddr"; + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_BadVAddr)); + rn = "BadVAddr"; break; default: goto die; @@ -3483,7 +4576,16 @@ static void gen_dmfc0 (CPUState *env, Di case 9: switch (sel) { case 0: - gen_op_mfc0_count(); + /* Mark as an IO operation because we read the time. */ + if (use_icount) + gen_io_start(); + gen_helper_mfc0_count(arg); + if (use_icount) { + gen_io_end(); + } + /* Break the TB to be able to take timer interrupts immediately + after reading count. */ + ctx->bstate = BS_STOP; rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -3494,7 +4596,7 @@ static void gen_dmfc0 (CPUState *env, Di case 10: switch (sel) { case 0: - gen_op_dmfc0_entryhi(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EntryHi)); rn = "EntryHi"; break; default: @@ -3504,7 +4606,7 @@ static void gen_dmfc0 (CPUState *env, Di case 11: switch (sel) { case 0: - gen_op_mfc0_compare(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Compare)); rn = "Compare"; break; /* 6,7 are implementation dependent */ @@ -3515,22 +4617,22 @@ static void gen_dmfc0 (CPUState *env, Di case 12: switch (sel) { case 0: - gen_op_mfc0_status(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Status)); rn = "Status"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_intctl(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_IntCtl)); rn = "IntCtl"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsctl(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSCtl)); rn = "SRSCtl"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_srsmap(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_SRSMap)); rn = "SRSMap"; break; default: @@ -3540,7 +4642,7 @@ static void gen_dmfc0 (CPUState *env, Di case 13: switch (sel) { case 0: - gen_op_mfc0_cause(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Cause)); rn = "Cause"; break; default: @@ -3550,7 +4652,7 @@ static void gen_dmfc0 (CPUState *env, Di case 14: switch (sel) { case 0: - gen_op_dmfc0_epc(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_EPC)); rn = "EPC"; break; default: @@ -3560,12 +4662,12 @@ static void gen_dmfc0 (CPUState *env, Di case 15: switch (sel) { case 0: - gen_op_mfc0_prid(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_PRid)); rn = "PRid"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mfc0_ebase(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_EBase)); rn = "EBase"; break; default: @@ -3575,22 +4677,30 @@ static void gen_dmfc0 (CPUState *env, Di case 16: switch (sel) { case 0: - gen_op_mfc0_config0(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config0)); rn = "Config"; break; case 1: - gen_op_mfc0_config1(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config1)); rn = "Config1"; break; case 2: - gen_op_mfc0_config2(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config2)); rn = "Config2"; break; case 3: - gen_op_mfc0_config3(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config3)); rn = "Config3"; break; /* 6,7 are implementation dependent */ + case 6: + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config6)); + rn = "Config6"; + break; + case 7: + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Config7)); + rn = "Config7"; + break; default: goto die; } @@ -3598,7 +4708,7 @@ static void gen_dmfc0 (CPUState *env, Di case 17: switch (sel) { case 0: - gen_op_dmfc0_lladdr(); + gen_helper_dmfc0_lladdr(arg); rn = "LLAddr"; break; default: @@ -3608,7 +4718,7 @@ static void gen_dmfc0 (CPUState *env, Di case 18: switch (sel) { case 0 ... 7: - gen_op_dmfc0_watchlo(sel); + gen_helper_1i(dmfc0_watchlo, arg, sel); rn = "WatchLo"; break; default: @@ -3618,7 +4728,7 @@ static void gen_dmfc0 (CPUState *env, Di case 19: switch (sel) { case 0 ... 7: - gen_op_mfc0_watchhi(sel); + gen_helper_1i(mfc0_watchhi, arg, sel); rn = "WatchHi"; break; default: @@ -3629,7 +4739,7 @@ static void gen_dmfc0 (CPUState *env, Di switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS3); - gen_op_dmfc0_xcontext(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_XContext)); rn = "XContext"; break; default: @@ -3640,7 +4750,7 @@ static void gen_dmfc0 (CPUState *env, Di /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mfc0_framemask(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Framemask)); rn = "Framemask"; break; default: @@ -3648,29 +4758,29 @@ static void gen_dmfc0 (CPUState *env, Di } break; case 22: - /* ignored */ + tcg_gen_movi_tl(arg, 0); /* unimplemented */ rn = "'Diagnostic"; /* implementation dependent */ break; case 23: switch (sel) { case 0: - gen_op_mfc0_debug(); /* EJTAG support */ + gen_helper_mfc0_debug(arg); /* EJTAG support */ rn = "Debug"; break; case 1: -// gen_op_dmfc0_tracecontrol(); /* PDtrace support */ +// gen_helper_dmfc0_tracecontrol(arg); /* PDtrace support */ rn = "TraceControl"; // break; case 2: -// gen_op_dmfc0_tracecontrol2(); /* PDtrace support */ +// gen_helper_dmfc0_tracecontrol2(arg); /* PDtrace support */ rn = "TraceControl2"; // break; case 3: -// gen_op_dmfc0_usertracedata(); /* PDtrace support */ +// gen_helper_dmfc0_usertracedata(arg); /* PDtrace support */ rn = "UserTraceData"; // break; case 4: -// gen_op_dmfc0_debug(); /* PDtrace support */ +// gen_helper_dmfc0_tracebpc(arg); /* PDtrace support */ rn = "TraceBPC"; // break; default: @@ -3680,7 +4790,8 @@ static void gen_dmfc0 (CPUState *env, Di case 24: switch (sel) { case 0: - gen_op_dmfc0_depc(); /* EJTAG support */ + /* EJTAG support */ + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_DEPC)); rn = "DEPC"; break; default: @@ -3690,35 +4801,35 @@ static void gen_dmfc0 (CPUState *env, Di case 25: switch (sel) { case 0: - gen_op_mfc0_performance0(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_Performance0)); rn = "Performance0"; break; case 1: -// gen_op_dmfc0_performance1(); +// gen_helper_dmfc0_performance1(arg); rn = "Performance1"; // break; case 2: -// gen_op_dmfc0_performance2(); +// gen_helper_dmfc0_performance2(arg); rn = "Performance2"; // break; case 3: -// gen_op_dmfc0_performance3(); +// gen_helper_dmfc0_performance3(arg); rn = "Performance3"; // break; case 4: -// gen_op_dmfc0_performance4(); +// gen_helper_dmfc0_performance4(arg); rn = "Performance4"; // break; case 5: -// gen_op_dmfc0_performance5(); +// gen_helper_dmfc0_performance5(arg); rn = "Performance5"; // break; case 6: -// gen_op_dmfc0_performance6(); +// gen_helper_dmfc0_performance6(arg); rn = "Performance6"; // break; case 7: -// gen_op_dmfc0_performance7(); +// gen_helper_dmfc0_performance7(arg); rn = "Performance7"; // break; default: @@ -3726,12 +4837,14 @@ static void gen_dmfc0 (CPUState *env, Di } break; case 26: - rn = "ECC"; - break; + tcg_gen_movi_tl(arg, 0); /* unimplemented */ + rn = "ECC"; + break; case 27: switch (sel) { /* ignored */ case 0 ... 3: + tcg_gen_movi_tl(arg, 0); /* unimplemented */ rn = "CacheErr"; break; default: @@ -3744,14 +4857,14 @@ static void gen_dmfc0 (CPUState *env, Di case 2: case 4: case 6: - gen_op_mfc0_taglo(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_TagLo)); rn = "TagLo"; break; case 1: case 3: case 5: case 7: - gen_op_mfc0_datalo(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_DataLo)); rn = "DataLo"; break; default: @@ -3764,14 +4877,14 @@ static void gen_dmfc0 (CPUState *env, Di case 2: case 4: case 6: - gen_op_mfc0_taghi(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_TagHi)); rn = "TagHi"; break; case 1: case 3: case 5: case 7: - gen_op_mfc0_datahi(); + gen_mfc0_load32(arg, offsetof(CPUState, CP0_DataHi)); rn = "DataHi"; break; default: @@ -3781,7 +4894,7 @@ static void gen_dmfc0 (CPUState *env, Di case 30: switch (sel) { case 0: - gen_op_dmfc0_errorepc(); + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUState, CP0_ErrorEPC)); rn = "ErrorEPC"; break; default: @@ -3791,7 +4904,8 @@ static void gen_dmfc0 (CPUState *env, Di case 31: switch (sel) { case 0: - gen_op_mfc0_desave(); /* EJTAG support */ + /* EJTAG support */ + gen_mfc0_load32(arg, offsetof(CPUState, CP0_DESAVE)); rn = "DESAVE"; break; default: @@ -3801,41 +4915,35 @@ static void gen_dmfc0 (CPUState *env, Di default: goto die; } -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "dmfc0 %s (reg %d sel %d)\n", - rn, reg, sel); - } -#endif + (void)rn; /* avoid a compiler warning */ + LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel); return; die: -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "dmfc0 %s (reg %d sel %d)\n", - rn, reg, sel); - } -#endif + LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel); generate_exception(ctx, EXCP_RI); } -static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) +static void gen_dmtc0 (CPUState *env, DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; if (sel != 0) check_insn(env, ctx, ISA_MIPS64); + if (use_icount) + gen_io_start(); + switch (reg) { case 0: switch (sel) { case 0: - gen_op_mtc0_index(); + gen_helper_mtc0_index(arg); rn = "Index"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_mvpcontrol(); + gen_helper_mtc0_mvpcontrol(arg); rn = "MVPControl"; break; case 2: @@ -3860,37 +4968,37 @@ static void gen_dmtc0 (CPUState *env, Di break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpecontrol(); + gen_helper_mtc0_vpecontrol(arg); rn = "VPEControl"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeconf0(); + gen_helper_mtc0_vpeconf0(arg); rn = "VPEConf0"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeconf1(); + gen_helper_mtc0_vpeconf1(arg); rn = "VPEConf1"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_yqmask(); + gen_helper_mtc0_yqmask(arg); rn = "YQMask"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeschedule(); + tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeschefback(); + tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_vpeopt(); + gen_helper_mtc0_vpeopt(arg); rn = "VPEOpt"; break; default: @@ -3900,42 +5008,42 @@ static void gen_dmtc0 (CPUState *env, Di case 2: switch (sel) { case 0: - gen_op_mtc0_entrylo0(); + gen_helper_mtc0_entrylo0(arg); rn = "EntryLo0"; break; case 1: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcstatus(); + gen_helper_mtc0_tcstatus(arg); rn = "TCStatus"; break; case 2: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcbind(); + gen_helper_mtc0_tcbind(arg); rn = "TCBind"; break; case 3: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcrestart(); + gen_helper_mtc0_tcrestart(arg); rn = "TCRestart"; break; case 4: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tchalt(); + gen_helper_mtc0_tchalt(arg); rn = "TCHalt"; break; case 5: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tccontext(); + gen_helper_mtc0_tccontext(arg); rn = "TCContext"; break; case 6: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcschedule(); + gen_helper_mtc0_tcschedule(arg); rn = "TCSchedule"; break; case 7: check_insn(env, ctx, ASE_MT); - gen_op_mtc0_tcschefback(); + gen_helper_mtc0_tcschefback(arg); rn = "TCScheFBack"; break; default: @@ -3945,7 +5053,7 @@ static void gen_dmtc0 (CPUState *env, Di case 3: switch (sel) { case 0: - gen_op_mtc0_entrylo1(); + gen_helper_mtc0_entrylo1(arg); rn = "EntryLo1"; break; default: @@ -3955,11 +5063,11 @@ static void gen_dmtc0 (CPUState *env, Di case 4: switch (sel) { case 0: - gen_op_mtc0_context(); + gen_helper_mtc0_context(arg); rn = "Context"; break; case 1: -// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */ +// gen_helper_mtc0_contextconfig(arg); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -3969,12 +5077,12 @@ static void gen_dmtc0 (CPUState *env, Di case 5: switch (sel) { case 0: - gen_op_mtc0_pagemask(); + gen_helper_mtc0_pagemask(arg); rn = "PageMask"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_pagegrain(); + gen_helper_mtc0_pagegrain(arg); rn = "PageGrain"; break; default: @@ -3984,32 +5092,32 @@ static void gen_dmtc0 (CPUState *env, Di case 6: switch (sel) { case 0: - gen_op_mtc0_wired(); + gen_helper_mtc0_wired(arg); rn = "Wired"; break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf0(); + gen_helper_mtc0_srsconf0(arg); rn = "SRSConf0"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf1(); + gen_helper_mtc0_srsconf1(arg); rn = "SRSConf1"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf2(); + gen_helper_mtc0_srsconf2(arg); rn = "SRSConf2"; break; case 4: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf3(); + gen_helper_mtc0_srsconf3(arg); rn = "SRSConf3"; break; case 5: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsconf4(); + gen_helper_mtc0_srsconf4(arg); rn = "SRSConf4"; break; default: @@ -4020,7 +5128,7 @@ static void gen_dmtc0 (CPUState *env, Di switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_hwrena(); + gen_helper_mtc0_hwrena(arg); rn = "HWREna"; break; default: @@ -4029,12 +5137,12 @@ static void gen_dmtc0 (CPUState *env, Di break; case 8: /* ignored */ - rn = "BadVaddr"; + rn = "BadVAddr"; break; case 9: switch (sel) { case 0: - gen_op_mtc0_count(); + gen_helper_mtc0_count(arg); rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -4047,7 +5155,7 @@ static void gen_dmtc0 (CPUState *env, Di case 10: switch (sel) { case 0: - gen_op_mtc0_entryhi(); + gen_helper_mtc0_entryhi(arg); rn = "EntryHi"; break; default: @@ -4057,7 +5165,7 @@ static void gen_dmtc0 (CPUState *env, Di case 11: switch (sel) { case 0: - gen_op_mtc0_compare(); + gen_helper_mtc0_compare(arg); rn = "Compare"; break; /* 6,7 are implementation dependent */ @@ -4070,7 +5178,8 @@ static void gen_dmtc0 (CPUState *env, Di case 12: switch (sel) { case 0: - gen_op_mtc0_status(); + save_cpu_state(ctx, 1); + gen_helper_mtc0_status(arg); /* BS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->pc + 4); ctx->bstate = BS_EXCP; @@ -4078,21 +5187,21 @@ static void gen_dmtc0 (CPUState *env, Di break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_intctl(); + gen_helper_mtc0_intctl(arg); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsctl(); + gen_helper_mtc0_srsctl(arg); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_srsmap(); + gen_mtc0_store32(arg, offsetof(CPUState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSMap"; @@ -4104,19 +5213,28 @@ static void gen_dmtc0 (CPUState *env, Di case 13: switch (sel) { case 0: - gen_op_mtc0_cause(); + save_cpu_state(ctx, 1); + /* Mark as an IO operation because we may trigger a software + interrupt. */ + if (use_icount) { + gen_io_start(); + } + gen_helper_mtc0_cause(arg); + if (use_icount) { + gen_io_end(); + } + /* Stop translation as we may have triggered an intetrupt */ + ctx->bstate = BS_STOP; rn = "Cause"; break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 14: switch (sel) { case 0: - gen_op_mtc0_epc(); + tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_EPC)); rn = "EPC"; break; default: @@ -4131,7 +5249,7 @@ static void gen_dmtc0 (CPUState *env, Di break; case 1: check_insn(env, ctx, ISA_MIPS32R2); - gen_op_mtc0_ebase(); + gen_helper_mtc0_ebase(arg); rn = "EBase"; break; default: @@ -4141,17 +5259,17 @@ static void gen_dmtc0 (CPUState *env, Di case 16: switch (sel) { case 0: - gen_op_mtc0_config0(); + gen_helper_mtc0_config0(arg); rn = "Config"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; break; case 1: - /* ignored */ + /* ignored, read only */ rn = "Config1"; break; case 2: - gen_op_mtc0_config2(); + gen_helper_mtc0_config2(arg); rn = "Config2"; /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -4169,7 +5287,7 @@ static void gen_dmtc0 (CPUState *env, Di case 17: switch (sel) { case 0: - /* ignored */ + gen_helper_mtc0_lladdr(arg); rn = "LLAddr"; break; default: @@ -4179,7 +5297,7 @@ static void gen_dmtc0 (CPUState *env, Di case 18: switch (sel) { case 0 ... 7: - gen_op_mtc0_watchlo(sel); + gen_helper_1i(mtc0_watchlo, arg, sel); rn = "WatchLo"; break; default: @@ -4189,7 +5307,7 @@ static void gen_dmtc0 (CPUState *env, Di case 19: switch (sel) { case 0 ... 7: - gen_op_mtc0_watchhi(sel); + gen_helper_1i(mtc0_watchhi, arg, sel); rn = "WatchHi"; break; default: @@ -4200,7 +5318,7 @@ static void gen_dmtc0 (CPUState *env, Di switch (sel) { case 0: check_insn(env, ctx, ISA_MIPS3); - gen_op_mtc0_xcontext(); + gen_helper_mtc0_xcontext(arg); rn = "XContext"; break; default: @@ -4211,7 +5329,7 @@ static void gen_dmtc0 (CPUState *env, Di /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mtc0_framemask(); + gen_helper_mtc0_framemask(arg); rn = "Framemask"; break; default: @@ -4225,32 +5343,32 @@ static void gen_dmtc0 (CPUState *env, Di case 23: switch (sel) { case 0: - gen_op_mtc0_debug(); /* EJTAG support */ + gen_helper_mtc0_debug(arg); /* EJTAG support */ /* BS_STOP isn't good enough here, hflags may have changed. */ gen_save_pc(ctx->pc + 4); ctx->bstate = BS_EXCP; rn = "Debug"; break; case 1: -// gen_op_mtc0_tracecontrol(); /* PDtrace support */ +// gen_helper_mtc0_tracecontrol(arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "TraceControl"; // break; case 2: -// gen_op_mtc0_tracecontrol2(); /* PDtrace support */ +// gen_helper_mtc0_tracecontrol2(arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "TraceControl2"; // break; case 3: -// gen_op_mtc0_usertracedata(); /* PDtrace support */ +// gen_helper_mtc0_usertracedata(arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "UserTraceData"; // break; case 4: -// gen_op_mtc0_debug(); /* PDtrace support */ +// gen_helper_mtc0_tracebpc(arg); /* PDtrace support */ /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "TraceBPC"; @@ -4262,7 +5380,8 @@ static void gen_dmtc0 (CPUState *env, Di case 24: switch (sel) { case 0: - gen_op_mtc0_depc(); /* EJTAG support */ + /* EJTAG support */ + tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_DEPC)); rn = "DEPC"; break; default: @@ -4272,35 +5391,35 @@ static void gen_dmtc0 (CPUState *env, Di case 25: switch (sel) { case 0: - gen_op_mtc0_performance0(); + gen_helper_mtc0_performance0(arg); rn = "Performance0"; break; case 1: -// gen_op_mtc0_performance1(); +// gen_helper_mtc0_performance1(arg); rn = "Performance1"; // break; case 2: -// gen_op_mtc0_performance2(); +// gen_helper_mtc0_performance2(arg); rn = "Performance2"; // break; case 3: -// gen_op_mtc0_performance3(); +// gen_helper_mtc0_performance3(arg); rn = "Performance3"; // break; case 4: -// gen_op_mtc0_performance4(); +// gen_helper_mtc0_performance4(arg); rn = "Performance4"; // break; case 5: -// gen_op_mtc0_performance5(); +// gen_helper_mtc0_performance5(arg); rn = "Performance5"; // break; case 6: -// gen_op_mtc0_performance6(); +// gen_helper_mtc0_performance6(arg); rn = "Performance6"; // break; case 7: -// gen_op_mtc0_performance7(); +// gen_helper_mtc0_performance7(arg); rn = "Performance7"; // break; default: @@ -4327,14 +5446,14 @@ static void gen_dmtc0 (CPUState *env, Di case 2: case 4: case 6: - gen_op_mtc0_taglo(); + gen_helper_mtc0_taglo(arg); rn = "TagLo"; break; case 1: case 3: case 5: case 7: - gen_op_mtc0_datalo(); + gen_helper_mtc0_datalo(arg); rn = "DataLo"; break; default: @@ -4347,14 +5466,14 @@ static void gen_dmtc0 (CPUState *env, Di case 2: case 4: case 6: - gen_op_mtc0_taghi(); + gen_helper_mtc0_taghi(arg); rn = "TagHi"; break; case 1: case 3: case 5: case 7: - gen_op_mtc0_datahi(); + gen_helper_mtc0_datahi(arg); rn = "DataHi"; break; default: @@ -4365,7 +5484,7 @@ static void gen_dmtc0 (CPUState *env, Di case 30: switch (sel) { case 0: - gen_op_mtc0_errorepc(); + tcg_gen_st_tl(arg, cpu_env, offsetof(CPUState, CP0_ErrorEPC)); rn = "ErrorEPC"; break; default: @@ -4375,7 +5494,8 @@ static void gen_dmtc0 (CPUState *env, Di case 31: switch (sel) { case 0: - gen_op_mtc0_desave(); /* EJTAG support */ + /* EJTAG support */ + gen_mtc0_store32(arg, offsetof(CPUState, CP0_DESAVE)); rn = "DESAVE"; break; default: @@ -4387,144 +5507,194 @@ static void gen_dmtc0 (CPUState *env, Di default: goto die; } -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "dmtc0 %s (reg %d sel %d)\n", - rn, reg, sel); + (void)rn; /* avoid a compiler warning */ + LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel); + /* For simplicity assume that all writes can cause interrupts. */ + if (use_icount) { + gen_io_end(); + ctx->bstate = BS_STOP; } -#endif return; die: -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "dmtc0 %s (reg %d sel %d)\n", - rn, reg, sel); - } -#endif + LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel); generate_exception(ctx, EXCP_RI); } #endif /* TARGET_MIPS64 */ -static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, +static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int rd, int u, int sel, int h) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + TCGv t0 = tcg_temp_local_new(); if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && - ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != - (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) - gen_op_set_T0(-1); + ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) != + (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) + tcg_gen_movi_tl(t0, -1); else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) - gen_op_set_T0(-1); + tcg_gen_movi_tl(t0, -1); else if (u == 0) { switch (rt) { + case 1: + switch (sel) { + case 1: + gen_helper_mftc0_vpecontrol(t0); + break; + case 2: + gen_helper_mftc0_vpeconf0(t0); + break; + default: + goto die; + break; + } + break; case 2: switch (sel) { case 1: - gen_op_mftc0_tcstatus(); + gen_helper_mftc0_tcstatus(t0); break; case 2: - gen_op_mftc0_tcbind(); + gen_helper_mftc0_tcbind(t0); break; case 3: - gen_op_mftc0_tcrestart(); + gen_helper_mftc0_tcrestart(t0); break; case 4: - gen_op_mftc0_tchalt(); + gen_helper_mftc0_tchalt(t0); break; case 5: - gen_op_mftc0_tccontext(); + gen_helper_mftc0_tccontext(t0); break; case 6: - gen_op_mftc0_tcschedule(); + gen_helper_mftc0_tcschedule(t0); break; case 7: - gen_op_mftc0_tcschefback(); + gen_helper_mftc0_tcschefback(t0); break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); break; } break; case 10: switch (sel) { case 0: - gen_op_mftc0_entryhi(); + gen_helper_mftc0_entryhi(t0); break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); break; } case 12: switch (sel) { case 0: - gen_op_mftc0_status(); + gen_helper_mftc0_status(t0); + break; + default: + gen_mfc0(env, ctx, t0, rt, sel); + break; + } + case 13: + switch (sel) { + case 0: + gen_helper_mftc0_cause(t0); + break; + default: + goto die; + break; + } + break; + case 14: + switch (sel) { + case 0: + gen_helper_mftc0_epc(t0); + break; + default: + goto die; + break; + } + break; + case 15: + switch (sel) { + case 1: + gen_helper_mftc0_ebase(t0); + break; + default: + goto die; + break; + } + break; + case 16: + switch (sel) { + case 0 ... 7: + gen_helper_mftc0_configx(t0, tcg_const_tl(sel)); break; default: - gen_mfc0(env, ctx, rt, sel); + goto die; break; } + break; case 23: switch (sel) { case 0: - gen_op_mftc0_debug(); + gen_helper_mftc0_debug(t0); break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); break; } break; default: - gen_mfc0(env, ctx, rt, sel); + gen_mfc0(env, ctx, t0, rt, sel); } } else switch (sel) { /* GPR registers. */ case 0: - gen_op_mftgpr(rt); + gen_helper_1i(mftgpr, t0, rt); break; /* Auxiliary CPU registers */ case 1: switch (rt) { case 0: - gen_op_mftlo(0); + gen_helper_1i(mftlo, t0, 0); break; case 1: - gen_op_mfthi(0); + gen_helper_1i(mfthi, t0, 0); break; case 2: - gen_op_mftacx(0); + gen_helper_1i(mftacx, t0, 0); break; case 4: - gen_op_mftlo(1); + gen_helper_1i(mftlo, t0, 1); break; case 5: - gen_op_mfthi(1); + gen_helper_1i(mfthi, t0, 1); break; case 6: - gen_op_mftacx(1); + gen_helper_1i(mftacx, t0, 1); break; case 8: - gen_op_mftlo(2); + gen_helper_1i(mftlo, t0, 2); break; case 9: - gen_op_mfthi(2); + gen_helper_1i(mfthi, t0, 2); break; case 10: - gen_op_mftacx(2); + gen_helper_1i(mftacx, t0, 2); break; case 12: - gen_op_mftlo(3); + gen_helper_1i(mftlo, t0, 3); break; case 13: - gen_op_mfthi(3); + gen_helper_1i(mfthi, t0, 3); break; case 14: - gen_op_mftacx(3); + gen_helper_1i(mftacx, t0, 3); break; case 16: - gen_op_mftdsp(); + gen_helper_mftdsp(t0); break; default: goto die; @@ -4534,16 +5704,22 @@ static void gen_mftr(CPUState *env, Disa case 2: /* XXX: For now we support only a single FPU context. */ if (h == 0) { - GEN_LOAD_FREG_FTN(WT0, rt); - gen_op_mfc1(); + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, rt); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free_i32(fp0); } else { - GEN_LOAD_FREG_FTN(WTH0, rt); - gen_op_mfhc1(); + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32h(fp0, rt); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free_i32(fp0); } break; case 3: /* XXX: For now we support only a single FPU context. */ - gen_op_cfc1(rt); + gen_helper_1i(cfc1, t0, rt); break; /* COP2: Not implemented. */ case 4: @@ -4552,143 +5728,171 @@ static void gen_mftr(CPUState *env, Disa default: goto die; } -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", - rt, u, sel, h); - } -#endif + LOG_DISAS("mftr (reg %d u %d sel %d h %d)\n", rt, u, sel, h); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); return; die: -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", - rt, u, sel, h); - } -#endif + tcg_temp_free(t0); + LOG_DISAS("mftr (reg %d u %d sel %d h %d)\n", rt, u, sel, h); generate_exception(ctx, EXCP_RI); } -static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, +static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, int rt, int u, int sel, int h) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + TCGv t0 = tcg_temp_local_new(); + gen_load_gpr(t0, rt); if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && - ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != - (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) + ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) != + (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE)))) /* NOP */ ; else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) /* NOP */ ; else if (u == 0) { switch (rd) { + case 1: + switch (sel) { + case 1: + gen_helper_mttc0_vpecontrol(t0); + break; + case 2: + gen_helper_mttc0_vpeconf0(t0); + break; + default: + goto die; + break; + } + break; case 2: switch (sel) { case 1: - gen_op_mttc0_tcstatus(); + gen_helper_mttc0_tcstatus(t0); break; case 2: - gen_op_mttc0_tcbind(); + gen_helper_mttc0_tcbind(t0); break; case 3: - gen_op_mttc0_tcrestart(); + gen_helper_mttc0_tcrestart(t0); break; case 4: - gen_op_mttc0_tchalt(); + gen_helper_mttc0_tchalt(t0); break; case 5: - gen_op_mttc0_tccontext(); + gen_helper_mttc0_tccontext(t0); break; case 6: - gen_op_mttc0_tcschedule(); + gen_helper_mttc0_tcschedule(t0); break; case 7: - gen_op_mttc0_tcschefback(); + gen_helper_mttc0_tcschefback(t0); break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); break; } break; case 10: switch (sel) { case 0: - gen_op_mttc0_entryhi(); + gen_helper_mttc0_entryhi(t0); break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); break; } case 12: switch (sel) { case 0: - gen_op_mttc0_status(); + gen_helper_mttc0_status(t0); + break; + default: + gen_mtc0(env, ctx, t0, rd, sel); + break; + } + case 13: + switch (sel) { + case 0: + gen_helper_mttc0_cause(t0); + break; + default: + goto die; + break; + } + break; + case 15: + switch (sel) { + case 1: + gen_helper_mttc0_ebase(t0); break; default: - gen_mtc0(env, ctx, rd, sel); + goto die; break; } + break; case 23: switch (sel) { case 0: - gen_op_mttc0_debug(); + gen_helper_mttc0_debug(t0); break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); break; } break; default: - gen_mtc0(env, ctx, rd, sel); + gen_mtc0(env, ctx, t0, rd, sel); } } else switch (sel) { /* GPR registers. */ case 0: - gen_op_mttgpr(rd); + gen_helper_1i(mttgpr, t0, rd); break; /* Auxiliary CPU registers */ case 1: switch (rd) { case 0: - gen_op_mttlo(0); + gen_helper_1i(mttlo, t0, 0); break; case 1: - gen_op_mtthi(0); + gen_helper_1i(mtthi, t0, 0); break; case 2: - gen_op_mttacx(0); + gen_helper_1i(mttacx, t0, 0); break; case 4: - gen_op_mttlo(1); + gen_helper_1i(mttlo, t0, 1); break; case 5: - gen_op_mtthi(1); + gen_helper_1i(mtthi, t0, 1); break; case 6: - gen_op_mttacx(1); + gen_helper_1i(mttacx, t0, 1); break; case 8: - gen_op_mttlo(2); + gen_helper_1i(mttlo, t0, 2); break; case 9: - gen_op_mtthi(2); + gen_helper_1i(mtthi, t0, 2); break; case 10: - gen_op_mttacx(2); + gen_helper_1i(mttacx, t0, 2); break; case 12: - gen_op_mttlo(3); + gen_helper_1i(mttlo, t0, 3); break; case 13: - gen_op_mtthi(3); + gen_helper_1i(mtthi, t0, 3); break; case 14: - gen_op_mttacx(3); + gen_helper_1i(mttacx, t0, 3); break; case 16: - gen_op_mttdsp(); + gen_helper_mttdsp(t0); break; default: goto die; @@ -4698,16 +5902,22 @@ static void gen_mttr(CPUState *env, Disa case 2: /* XXX: For now we support only a single FPU context. */ if (h == 0) { - gen_op_mtc1(); - GEN_STORE_FTN_FREG(rd, WT0); + TCGv_i32 fp0 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32(fp0, rd); + tcg_temp_free_i32(fp0); } else { - gen_op_mthc1(); - GEN_STORE_FTN_FREG(rd, WTH0); + TCGv_i32 fp0 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32h(fp0, rd); + tcg_temp_free_i32(fp0); } break; case 3: /* XXX: For now we support only a single FPU context. */ - gen_op_ctc1(rd); + gen_helper_1i(ctc1, t0, rd); break; /* COP2: Not implemented. */ case 4: @@ -4716,21 +5926,13 @@ static void gen_mttr(CPUState *env, Disa default: goto die; } -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", - rd, u, sel, h); - } -#endif + LOG_DISAS("mttr (reg %d u %d sel %d h %d)\n", rd, u, sel, h); + tcg_temp_free(t0); return; die: -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", - rd, u, sel, h); - } -#endif + tcg_temp_free(t0); + LOG_DISAS("mttr (reg %d u %d sel %d h %d)\n", rd, u, sel, h); generate_exception(ctx, EXCP_RI); } @@ -4744,14 +5946,17 @@ static void gen_cp0 (CPUState *env, Disa /* Treat as NOP. */ return; } - gen_mfc0(env, ctx, rd, ctx->opcode & 0x7); - gen_op_store_T0_gpr(rt); + gen_mfc0(env, ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); opn = "mfc0"; break; case OPC_MTC0: - GEN_LOAD_REG_T0(rt); - save_cpu_state(ctx, 1); - gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); + { + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_mtc0(env, ctx, t0, rd, ctx->opcode & 0x7); + tcg_temp_free(t0); + } opn = "mtc0"; break; #if defined(TARGET_MIPS64) @@ -4761,15 +5966,18 @@ static void gen_cp0 (CPUState *env, Disa /* Treat as NOP. */ return; } - gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7); - gen_op_store_T0_gpr(rt); + gen_dmfc0(env, ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); opn = "dmfc0"; break; case OPC_DMTC0: check_insn(env, ctx, ISA_MIPS3); - GEN_LOAD_REG_T0(rt); - save_cpu_state(ctx, 1); - gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); + { + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_dmtc0(env, ctx, t0, rd, ctx->opcode & 0x7); + tcg_temp_free(t0); + } opn = "dmtc0"; break; #endif @@ -4779,47 +5987,44 @@ static void gen_cp0 (CPUState *env, Disa /* Treat as NOP. */ return; } - gen_mftr(env, ctx, rt, (ctx->opcode >> 5) & 1, + gen_mftr(env, ctx, rt, rd, (ctx->opcode >> 5) & 1, ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); - gen_op_store_T0_gpr(rd); opn = "mftr"; break; case OPC_MTTR: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_T0(rt); - gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1, + gen_mttr(env, ctx, rd, rt, (ctx->opcode >> 5) & 1, ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); opn = "mttr"; break; case OPC_TLBWI: opn = "tlbwi"; - if (!env->tlb->do_tlbwi) + if (!env->tlb->helper_tlbwi) goto die; - gen_op_tlbwi(); + gen_helper_tlbwi(); break; case OPC_TLBWR: opn = "tlbwr"; - if (!env->tlb->do_tlbwr) + if (!env->tlb->helper_tlbwr) goto die; - gen_op_tlbwr(); + gen_helper_tlbwr(); break; case OPC_TLBP: opn = "tlbp"; - if (!env->tlb->do_tlbp) + if (!env->tlb->helper_tlbp) goto die; - gen_op_tlbp(); + gen_helper_tlbp(); break; case OPC_TLBR: opn = "tlbr"; - if (!env->tlb->do_tlbr) + if (!env->tlb->helper_tlbr) goto die; - gen_op_tlbr(); + gen_helper_tlbr(); break; case OPC_ERET: opn = "eret"; check_insn(env, ctx, ISA_MIPS2); - save_cpu_state(ctx, 1); - gen_op_eret(); + gen_helper_eret(); ctx->bstate = BS_EXCP; break; case OPC_DERET: @@ -4829,8 +6034,7 @@ static void gen_cp0 (CPUState *env, Disa MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); } else { - save_cpu_state(ctx, 1); - gen_op_deret(); + gen_helper_deret(); ctx->bstate = BS_EXCP; } break; @@ -4841,7 +6045,7 @@ static void gen_cp0 (CPUState *env, Disa ctx->pc += 4; save_cpu_state(ctx, 1); ctx->pc -= 4; - gen_op_wait(); + gen_helper_wait(); ctx->bstate = BS_EXCP; break; default: @@ -4850,8 +6054,10 @@ static void gen_cp0 (CPUState *env, Disa generate_exception(ctx, EXCP_RI); return; } + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); } +#endif /* !CONFIG_USER_ONLY */ /* CP1 Branches (before delay slot) */ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op, @@ -4859,6 +6065,7 @@ static void gen_compute_branch1 (CPUStat { target_ulong btarget; const char *opn = "cp1 cond branch"; + TCGv_i32 t0 = tcg_temp_new_i32(); if (cc != 0) check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); @@ -4867,154 +6074,431 @@ static void gen_compute_branch1 (CPUStat switch (op) { case OPC_BC1F: - gen_op_bc1f(cc); + tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); + tcg_gen_not_i32(t0, t0); + tcg_gen_andi_i32(t0, t0, 1); + tcg_gen_extu_i32_tl(bcond, t0); opn = "bc1f"; goto not_likely; case OPC_BC1FL: - gen_op_bc1f(cc); + tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); + tcg_gen_not_i32(t0, t0); + tcg_gen_andi_i32(t0, t0, 1); + tcg_gen_extu_i32_tl(bcond, t0); opn = "bc1fl"; goto likely; case OPC_BC1T: - gen_op_bc1t(cc); + tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); + tcg_gen_andi_i32(t0, t0, 1); + tcg_gen_extu_i32_tl(bcond, t0); opn = "bc1t"; goto not_likely; case OPC_BC1TL: - gen_op_bc1t(cc); + tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); + tcg_gen_andi_i32(t0, t0, 1); + tcg_gen_extu_i32_tl(bcond, t0); opn = "bc1tl"; likely: ctx->hflags |= MIPS_HFLAG_BL; - gen_op_set_bcond(); - gen_op_save_bcond(); break; case OPC_BC1FANY2: - gen_op_bc1any2f(cc); + { + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); + tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1)); + tcg_gen_nor_i32(t0, t0, t1); + tcg_temp_free_i32(t1); + tcg_gen_andi_i32(t0, t0, 1); + tcg_gen_extu_i32_tl(bcond, t0); + } opn = "bc1any2f"; goto not_likely; case OPC_BC1TANY2: - gen_op_bc1any2t(cc); + { + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); + tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1)); + tcg_gen_or_i32(t0, t0, t1); + tcg_temp_free_i32(t1); + tcg_gen_andi_i32(t0, t0, 1); + tcg_gen_extu_i32_tl(bcond, t0); + } opn = "bc1any2t"; goto not_likely; case OPC_BC1FANY4: - gen_op_bc1any4f(cc); + { + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); + tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1)); + tcg_gen_or_i32(t0, t0, t1); + tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+2)); + tcg_gen_or_i32(t0, t0, t1); + tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+3)); + tcg_gen_nor_i32(t0, t0, t1); + tcg_temp_free_i32(t1); + tcg_gen_andi_i32(t0, t0, 1); + tcg_gen_extu_i32_tl(bcond, t0); + } opn = "bc1any4f"; goto not_likely; case OPC_BC1TANY4: - gen_op_bc1any4t(cc); + { + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); + tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1)); + tcg_gen_or_i32(t0, t0, t1); + tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+2)); + tcg_gen_or_i32(t0, t0, t1); + tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+3)); + tcg_gen_or_i32(t0, t0, t1); + tcg_temp_free_i32(t1); + tcg_gen_andi_i32(t0, t0, 1); + tcg_gen_extu_i32_tl(bcond, t0); + } opn = "bc1any4t"; not_likely: ctx->hflags |= MIPS_HFLAG_BC; - gen_op_set_bcond(); break; default: MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); - return; + goto out; } + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, ctx->hflags, btarget); ctx->btarget = btarget; + + out: + tcg_temp_free_i32(t0); } /* Coprocessor 1 (FPU) */ #define FOP(func, fmt) (((fmt) << 21) | (func)) +enum fopcode { + OPC_ADD_S = FOP(0, FMT_S), + OPC_SUB_S = FOP(1, FMT_S), + OPC_MUL_S = FOP(2, FMT_S), + OPC_DIV_S = FOP(3, FMT_S), + OPC_SQRT_S = FOP(4, FMT_S), + OPC_ABS_S = FOP(5, FMT_S), + OPC_MOV_S = FOP(6, FMT_S), + OPC_NEG_S = FOP(7, FMT_S), + OPC_ROUND_L_S = FOP(8, FMT_S), + OPC_TRUNC_L_S = FOP(9, FMT_S), + OPC_CEIL_L_S = FOP(10, FMT_S), + OPC_FLOOR_L_S = FOP(11, FMT_S), + OPC_ROUND_W_S = FOP(12, FMT_S), + OPC_TRUNC_W_S = FOP(13, FMT_S), + OPC_CEIL_W_S = FOP(14, FMT_S), + OPC_FLOOR_W_S = FOP(15, FMT_S), + OPC_MOVCF_S = FOP(17, FMT_S), + OPC_MOVZ_S = FOP(18, FMT_S), + OPC_MOVN_S = FOP(19, FMT_S), + OPC_RECIP_S = FOP(21, FMT_S), + OPC_RSQRT_S = FOP(22, FMT_S), + OPC_RECIP2_S = FOP(28, FMT_S), + OPC_RECIP1_S = FOP(29, FMT_S), + OPC_RSQRT1_S = FOP(30, FMT_S), + OPC_RSQRT2_S = FOP(31, FMT_S), + OPC_CVT_D_S = FOP(33, FMT_S), + OPC_CVT_W_S = FOP(36, FMT_S), + OPC_CVT_L_S = FOP(37, FMT_S), + OPC_CVT_PS_S = FOP(38, FMT_S), + OPC_CMP_F_S = FOP (48, FMT_S), + OPC_CMP_UN_S = FOP (49, FMT_S), + OPC_CMP_EQ_S = FOP (50, FMT_S), + OPC_CMP_UEQ_S = FOP (51, FMT_S), + OPC_CMP_OLT_S = FOP (52, FMT_S), + OPC_CMP_ULT_S = FOP (53, FMT_S), + OPC_CMP_OLE_S = FOP (54, FMT_S), + OPC_CMP_ULE_S = FOP (55, FMT_S), + OPC_CMP_SF_S = FOP (56, FMT_S), + OPC_CMP_NGLE_S = FOP (57, FMT_S), + OPC_CMP_SEQ_S = FOP (58, FMT_S), + OPC_CMP_NGL_S = FOP (59, FMT_S), + OPC_CMP_LT_S = FOP (60, FMT_S), + OPC_CMP_NGE_S = FOP (61, FMT_S), + OPC_CMP_LE_S = FOP (62, FMT_S), + OPC_CMP_NGT_S = FOP (63, FMT_S), + + OPC_ADD_D = FOP(0, FMT_D), + OPC_SUB_D = FOP(1, FMT_D), + OPC_MUL_D = FOP(2, FMT_D), + OPC_DIV_D = FOP(3, FMT_D), + OPC_SQRT_D = FOP(4, FMT_D), + OPC_ABS_D = FOP(5, FMT_D), + OPC_MOV_D = FOP(6, FMT_D), + OPC_NEG_D = FOP(7, FMT_D), + OPC_ROUND_L_D = FOP(8, FMT_D), + OPC_TRUNC_L_D = FOP(9, FMT_D), + OPC_CEIL_L_D = FOP(10, FMT_D), + OPC_FLOOR_L_D = FOP(11, FMT_D), + OPC_ROUND_W_D = FOP(12, FMT_D), + OPC_TRUNC_W_D = FOP(13, FMT_D), + OPC_CEIL_W_D = FOP(14, FMT_D), + OPC_FLOOR_W_D = FOP(15, FMT_D), + OPC_MOVCF_D = FOP(17, FMT_D), + OPC_MOVZ_D = FOP(18, FMT_D), + OPC_MOVN_D = FOP(19, FMT_D), + OPC_RECIP_D = FOP(21, FMT_D), + OPC_RSQRT_D = FOP(22, FMT_D), + OPC_RECIP2_D = FOP(28, FMT_D), + OPC_RECIP1_D = FOP(29, FMT_D), + OPC_RSQRT1_D = FOP(30, FMT_D), + OPC_RSQRT2_D = FOP(31, FMT_D), + OPC_CVT_S_D = FOP(32, FMT_D), + OPC_CVT_W_D = FOP(36, FMT_D), + OPC_CVT_L_D = FOP(37, FMT_D), + OPC_CMP_F_D = FOP (48, FMT_D), + OPC_CMP_UN_D = FOP (49, FMT_D), + OPC_CMP_EQ_D = FOP (50, FMT_D), + OPC_CMP_UEQ_D = FOP (51, FMT_D), + OPC_CMP_OLT_D = FOP (52, FMT_D), + OPC_CMP_ULT_D = FOP (53, FMT_D), + OPC_CMP_OLE_D = FOP (54, FMT_D), + OPC_CMP_ULE_D = FOP (55, FMT_D), + OPC_CMP_SF_D = FOP (56, FMT_D), + OPC_CMP_NGLE_D = FOP (57, FMT_D), + OPC_CMP_SEQ_D = FOP (58, FMT_D), + OPC_CMP_NGL_D = FOP (59, FMT_D), + OPC_CMP_LT_D = FOP (60, FMT_D), + OPC_CMP_NGE_D = FOP (61, FMT_D), + OPC_CMP_LE_D = FOP (62, FMT_D), + OPC_CMP_NGT_D = FOP (63, FMT_D), + + OPC_CVT_S_W = FOP(32, FMT_W), + OPC_CVT_D_W = FOP(33, FMT_W), + OPC_CVT_S_L = FOP(32, FMT_L), + OPC_CVT_D_L = FOP(33, FMT_L), + OPC_CVT_PS_PW = FOP(38, FMT_W), + + OPC_ADD_PS = FOP(0, FMT_PS), + OPC_SUB_PS = FOP(1, FMT_PS), + OPC_MUL_PS = FOP(2, FMT_PS), + OPC_DIV_PS = FOP(3, FMT_PS), + OPC_ABS_PS = FOP(5, FMT_PS), + OPC_MOV_PS = FOP(6, FMT_PS), + OPC_NEG_PS = FOP(7, FMT_PS), + OPC_MOVCF_PS = FOP(17, FMT_PS), + OPC_MOVZ_PS = FOP(18, FMT_PS), + OPC_MOVN_PS = FOP(19, FMT_PS), + OPC_ADDR_PS = FOP(24, FMT_PS), + OPC_MULR_PS = FOP(26, FMT_PS), + OPC_RECIP2_PS = FOP(28, FMT_PS), + OPC_RECIP1_PS = FOP(29, FMT_PS), + OPC_RSQRT1_PS = FOP(30, FMT_PS), + OPC_RSQRT2_PS = FOP(31, FMT_PS), + + OPC_CVT_S_PU = FOP(32, FMT_PS), + OPC_CVT_PW_PS = FOP(36, FMT_PS), + OPC_CVT_S_PL = FOP(40, FMT_PS), + OPC_PLL_PS = FOP(44, FMT_PS), + OPC_PLU_PS = FOP(45, FMT_PS), + OPC_PUL_PS = FOP(46, FMT_PS), + OPC_PUU_PS = FOP(47, FMT_PS), + OPC_CMP_F_PS = FOP (48, FMT_PS), + OPC_CMP_UN_PS = FOP (49, FMT_PS), + OPC_CMP_EQ_PS = FOP (50, FMT_PS), + OPC_CMP_UEQ_PS = FOP (51, FMT_PS), + OPC_CMP_OLT_PS = FOP (52, FMT_PS), + OPC_CMP_ULT_PS = FOP (53, FMT_PS), + OPC_CMP_OLE_PS = FOP (54, FMT_PS), + OPC_CMP_ULE_PS = FOP (55, FMT_PS), + OPC_CMP_SF_PS = FOP (56, FMT_PS), + OPC_CMP_NGLE_PS = FOP (57, FMT_PS), + OPC_CMP_SEQ_PS = FOP (58, FMT_PS), + OPC_CMP_NGL_PS = FOP (59, FMT_PS), + OPC_CMP_LT_PS = FOP (60, FMT_PS), + OPC_CMP_NGE_PS = FOP (61, FMT_PS), + OPC_CMP_LE_PS = FOP (62, FMT_PS), + OPC_CMP_NGT_PS = FOP (63, FMT_PS), +}; + static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) { const char *opn = "cp1 move"; + TCGv t0 = tcg_temp_new(); switch (opc) { case OPC_MFC1: - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_mfc1(); - GEN_STORE_T0_REG(rt); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free_i32(fp0); + } + gen_store_gpr(t0, rt); opn = "mfc1"; break; case OPC_MTC1: - GEN_LOAD_REG_T0(rt); - gen_op_mtc1(); - GEN_STORE_FTN_FREG(fs, WT0); + gen_load_gpr(t0, rt); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32(fp0, fs); + tcg_temp_free_i32(fp0); + } opn = "mtc1"; break; case OPC_CFC1: - gen_op_cfc1(fs); - GEN_STORE_T0_REG(rt); + gen_helper_1i(cfc1, t0, fs); + gen_store_gpr(t0, rt); opn = "cfc1"; break; case OPC_CTC1: - GEN_LOAD_REG_T0(rt); - gen_op_ctc1(fs); + gen_load_gpr(t0, rt); + gen_helper_1i(ctc1, t0, fs); opn = "ctc1"; break; +#if defined(TARGET_MIPS64) case OPC_DMFC1: - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_dmfc1(); - GEN_STORE_T0_REG(rt); + gen_load_fpr64(ctx, t0, fs); + gen_store_gpr(t0, rt); opn = "dmfc1"; break; case OPC_DMTC1: - GEN_LOAD_REG_T0(rt); - gen_op_dmtc1(); - GEN_STORE_FTN_FREG(fs, DT0); + gen_load_gpr(t0, rt); + gen_store_fpr64(ctx, t0, fs); opn = "dmtc1"; break; +#endif case OPC_MFHC1: - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_mfhc1(); - GEN_STORE_T0_REG(rt); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32h(fp0, fs); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free_i32(fp0); + } + gen_store_gpr(t0, rt); opn = "mfhc1"; break; case OPC_MTHC1: - GEN_LOAD_REG_T0(rt); - gen_op_mthc1(); - GEN_STORE_FTN_FREG(fs, WTH0); + gen_load_gpr(t0, rt); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32h(fp0, fs); + tcg_temp_free_i32(fp0); + } opn = "mthc1"; break; default: MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); - return; + goto out; } + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); + + out: + tcg_temp_free(t0); } static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) { - uint32_t ccbit; + int l1; + TCGCond cond; + TCGv_i32 t0; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + if (tf) + cond = TCG_COND_EQ; + else + cond = TCG_COND_NE; + + l1 = gen_new_label(); + t0 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); + tcg_gen_brcondi_i32(cond, t0, 0, l1); + tcg_temp_free_i32(t0); + if (rs == 0) { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } else { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]); + } + gen_set_label(l1); +} + +static inline void gen_movcf_s (int fs, int fd, int cc, int tf) +{ + int cond; + TCGv_i32 t0 = tcg_temp_new_i32(); + int l1 = gen_new_label(); - GEN_LOAD_REG_T0(rd); - GEN_LOAD_REG_T1(rs); - if (cc) { - ccbit = 1 << (24 + cc); - } else - ccbit = 1 << 23; - if (!tf) - gen_op_movf(ccbit); + if (tf) + cond = TCG_COND_EQ; else - gen_op_movt(ccbit); - GEN_STORE_T0_REG(rd); + cond = TCG_COND_NE; + + tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); + tcg_gen_brcondi_i32(cond, t0, 0, l1); + gen_load_fpr32(t0, fs); + gen_store_fpr32(t0, fd); + gen_set_label(l1); + tcg_temp_free_i32(t0); } -#define GEN_MOVCF(fmt) \ -static void glue(gen_movcf_, fmt) (DisasContext *ctx, int cc, int tf) \ -{ \ - uint32_t ccbit; \ - \ - if (cc) { \ - ccbit = 1 << (24 + cc); \ - } else \ - ccbit = 1 << 23; \ - if (!tf) \ - glue(gen_op_float_movf_, fmt)(ccbit); \ - else \ - glue(gen_op_float_movt_, fmt)(ccbit); \ -} -GEN_MOVCF(d); -GEN_MOVCF(s); -GEN_MOVCF(ps); -#undef GEN_MOVCF +static inline void gen_movcf_d (DisasContext *ctx, int fs, int fd, int cc, int tf) +{ + int cond; + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i64 fp0; + int l1 = gen_new_label(); + + if (tf) + cond = TCG_COND_EQ; + else + cond = TCG_COND_NE; -static void gen_farith (DisasContext *ctx, uint32_t op1, + tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); + tcg_gen_brcondi_i32(cond, t0, 0, l1); + tcg_temp_free_i32(t0); + fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + gen_set_label(l1); +} + +static inline void gen_movcf_ps (int fs, int fd, int cc, int tf) +{ + int cond; + TCGv_i32 t0 = tcg_temp_new_i32(); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + if (tf) + cond = TCG_COND_EQ; + else + cond = TCG_COND_NE; + + tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); + tcg_gen_brcondi_i32(cond, t0, 0, l1); + gen_load_fpr32(t0, fs); + gen_store_fpr32(t0, fd); + gen_set_label(l1); + + tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc+1)); + tcg_gen_brcondi_i32(cond, t0, 0, l2); + gen_load_fpr32h(t0, fs); + gen_store_fpr32h(t0, fd); + tcg_temp_free_i32(t0); + gen_set_label(l2); +} + + +static void gen_farith (DisasContext *ctx, enum fopcode op1, int ft, int fs, int fd, int cc) { const char *opn = "farith"; @@ -5057,751 +6541,1179 @@ static void gen_farith (DisasContext *ct enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP; uint32_t func = ctx->opcode & 0x3f; - switch (ctx->opcode & FOP(0x3f, 0x1f)) { - case FOP(0, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_add_s(); - GEN_STORE_FTN_FREG(fd, WT2); + switch (op1) { + case OPC_ADD_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_add_s(fp0, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "add.s"; optype = BINOP; break; - case FOP(1, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_sub_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_SUB_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_sub_s(fp0, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "sub.s"; optype = BINOP; break; - case FOP(2, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_mul_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_MUL_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_mul_s(fp0, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "mul.s"; optype = BINOP; break; - case FOP(3, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_div_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_DIV_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_div_s(fp0, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "div.s"; optype = BINOP; break; - case FOP(4, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_sqrt_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_SQRT_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_sqrt_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "sqrt.s"; break; - case FOP(5, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_abs_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_ABS_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_abs_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "abs.s"; break; - case FOP(6, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_mov_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_MOV_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "mov.s"; break; - case FOP(7, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_chs_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_NEG_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_chs_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "neg.s"; break; - case FOP(8, 16): + case OPC_ROUND_L_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_roundl_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); + gen_helper_float_roundl_s(fp64, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } opn = "round.l.s"; break; - case FOP(9, 16): + case OPC_TRUNC_L_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_truncl_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); + gen_helper_float_truncl_s(fp64, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } opn = "trunc.l.s"; break; - case FOP(10, 16): + case OPC_CEIL_L_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_ceill_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); + gen_helper_float_ceill_s(fp64, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } opn = "ceil.l.s"; break; - case FOP(11, 16): + case OPC_FLOOR_L_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_floorl_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); + gen_helper_float_floorl_s(fp64, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } opn = "floor.l.s"; break; - case FOP(12, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_roundw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_ROUND_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_roundw_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "round.w.s"; break; - case FOP(13, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_truncw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_TRUNC_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_truncw_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "trunc.w.s"; break; - case FOP(14, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_ceilw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_CEIL_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_ceilw_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "ceil.w.s"; break; - case FOP(15, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_floorw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_FLOOR_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_floorw_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "floor.w.s"; break; - case FOP(17, 16): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_MOVCF_S: + gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.s"; break; - case FOP(18, 16): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - gen_op_float_movz_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_MOVZ_S: + { + int l1 = gen_new_label(); + TCGv_i32 fp0; + + if (ft != 0) { + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1); + } + fp0 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + gen_set_label(l1); + } opn = "movz.s"; break; - case FOP(19, 16): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - gen_op_float_movn_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_MOVN_S: + { + int l1 = gen_new_label(); + TCGv_i32 fp0; + + if (ft != 0) { + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1); + fp0 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + gen_set_label(l1); + } + } opn = "movn.s"; break; - case FOP(21, 16): + case OPC_RECIP_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_recip_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_recip_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "recip.s"; break; - case FOP(22, 16): + case OPC_RSQRT_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_rsqrt_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_rsqrt_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "rsqrt.s"; break; - case FOP(28, 16): + case OPC_RECIP2_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - gen_op_float_recip2_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, fd); + gen_helper_float_recip2_s(fp0, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "recip2.s"; break; - case FOP(29, 16): + case OPC_RECIP1_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_recip1_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_recip1_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "recip1.s"; break; - case FOP(30, 16): + case OPC_RSQRT1_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_rsqrt1_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_rsqrt1_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "rsqrt1.s"; break; - case FOP(31, 16): + case OPC_RSQRT2_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, ft); - gen_op_float_rsqrt2_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_rsqrt2_s(fp0, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "rsqrt2.s"; break; - case FOP(33, 16): + case OPC_CVT_D_S: check_cp1_registers(ctx, fd); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtd_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); + gen_helper_float_cvtd_s(fp64, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } opn = "cvt.d.s"; break; - case FOP(36, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtw_s(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_CVT_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_cvtw_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "cvt.w.s"; break; - case FOP(37, 16): + case OPC_CVT_L_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtl_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); + gen_helper_float_cvtl_s(fp64, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } opn = "cvt.l.s"; break; - case FOP(38, 16): + case OPC_CVT_PS_S: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT1, fs); - GEN_LOAD_FREG_FTN(WT0, ft); - gen_op_float_cvtps_s(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp64 = tcg_temp_new_i64(); + TCGv_i32 fp32_0 = tcg_temp_new_i32(); + TCGv_i32 fp32_1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp32_0, fs); + gen_load_fpr32(fp32_1, ft); + tcg_gen_concat_i32_i64(fp64, fp32_0, fp32_1); + tcg_temp_free_i32(fp32_1); + tcg_temp_free_i32(fp32_0); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } opn = "cvt.ps.s"; break; - case FOP(48, 16): - case FOP(49, 16): - case FOP(50, 16): - case FOP(51, 16): - case FOP(52, 16): - case FOP(53, 16): - case FOP(54, 16): - case FOP(55, 16): - case FOP(56, 16): - case FOP(57, 16): - case FOP(58, 16): - case FOP(59, 16): - case FOP(60, 16): - case FOP(61, 16): - case FOP(62, 16): - case FOP(63, 16): - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); + case OPC_CMP_F_S: + case OPC_CMP_UN_S: + case OPC_CMP_EQ_S: + case OPC_CMP_UEQ_S: + case OPC_CMP_OLT_S: + case OPC_CMP_ULT_S: + case OPC_CMP_OLE_S: + case OPC_CMP_ULE_S: + case OPC_CMP_SF_S: + case OPC_CMP_NGLE_S: + case OPC_CMP_SEQ_S: + case OPC_CMP_NGL_S: + case OPC_CMP_LT_S: + case OPC_CMP_NGE_S: + case OPC_CMP_LE_S: + case OPC_CMP_NGT_S: if (ctx->opcode & (1 << 6)) { - check_cop1x(ctx); - gen_cmpabs_s(func-48, cc); + gen_cmpabs_s(ctx, func-48, ft, fs, cc); opn = condnames_abs[func-48]; } else { - gen_cmp_s(func-48, cc); + gen_cmp_s(ctx, func-48, ft, fs, cc); opn = condnames[func-48]; } break; - case FOP(0, 17): + case OPC_ADD_D: check_cp1_registers(ctx, fs | ft | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_add_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_add_d(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "add.d"; optype = BINOP; break; - case FOP(1, 17): + case OPC_SUB_D: check_cp1_registers(ctx, fs | ft | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_sub_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_sub_d(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "sub.d"; optype = BINOP; break; - case FOP(2, 17): + case OPC_MUL_D: check_cp1_registers(ctx, fs | ft | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_mul_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_mul_d(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "mul.d"; optype = BINOP; break; - case FOP(3, 17): + case OPC_DIV_D: check_cp1_registers(ctx, fs | ft | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_div_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_div_d(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "div.d"; optype = BINOP; break; - case FOP(4, 17): + case OPC_SQRT_D: check_cp1_registers(ctx, fs | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_sqrt_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_sqrt_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "sqrt.d"; break; - case FOP(5, 17): + case OPC_ABS_D: check_cp1_registers(ctx, fs | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_abs_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_abs_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "abs.d"; break; - case FOP(6, 17): + case OPC_MOV_D: check_cp1_registers(ctx, fs | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_mov_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "mov.d"; break; - case FOP(7, 17): + case OPC_NEG_D: check_cp1_registers(ctx, fs | fd); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_chs_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_chs_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "neg.d"; break; - case FOP(8, 17): + case OPC_ROUND_L_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_roundl_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_roundl_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "round.l.d"; break; - case FOP(9, 17): + case OPC_TRUNC_L_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_truncl_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_truncl_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "trunc.l.d"; break; - case FOP(10, 17): + case OPC_CEIL_L_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_ceill_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_ceill_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "ceil.l.d"; break; - case FOP(11, 17): + case OPC_FLOOR_L_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_floorl_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_floorl_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "floor.l.d"; break; - case FOP(12, 17): + case OPC_ROUND_W_D: check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_roundw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); + gen_helper_float_roundw_d(fp32, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); + } opn = "round.w.d"; break; - case FOP(13, 17): + case OPC_TRUNC_W_D: check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_truncw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); + gen_helper_float_truncw_d(fp32, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); + } opn = "trunc.w.d"; break; - case FOP(14, 17): + case OPC_CEIL_W_D: check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_ceilw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); + gen_helper_float_ceilw_d(fp32, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); + } opn = "ceil.w.d"; break; - case FOP(15, 17): + case OPC_FLOOR_W_D: check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_floorw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); + gen_helper_float_floorw_d(fp32, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); + } opn = "floor.w.d"; break; - case FOP(17, 17): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, fd); - gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1); - GEN_STORE_FTN_FREG(fd, DT2); + case OPC_MOVCF_D: + gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.d"; break; - case FOP(18, 17): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, fd); - gen_op_float_movz_d(); - GEN_STORE_FTN_FREG(fd, DT2); + case OPC_MOVZ_D: + { + int l1 = gen_new_label(); + TCGv_i64 fp0; + + if (ft != 0) { + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1); + } + fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + gen_set_label(l1); + } opn = "movz.d"; break; - case FOP(19, 17): - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, fd); - gen_op_float_movn_d(); - GEN_STORE_FTN_FREG(fd, DT2); + case OPC_MOVN_D: + { + int l1 = gen_new_label(); + TCGv_i64 fp0; + + if (ft != 0) { + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1); + fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + gen_set_label(l1); + } + } opn = "movn.d"; break; - case FOP(21, 17): + case OPC_RECIP_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_recip_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_recip_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "recip.d"; break; - case FOP(22, 17): + case OPC_RSQRT_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_rsqrt_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_rsqrt_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "rsqrt.d"; break; - case FOP(28, 17): + case OPC_RECIP2_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, ft); - gen_op_float_recip2_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_recip2_d(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "recip2.d"; break; - case FOP(29, 17): + case OPC_RECIP1_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_recip1_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_recip1_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "recip1.d"; break; - case FOP(30, 17): + case OPC_RSQRT1_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_rsqrt1_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_rsqrt1_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "rsqrt1.d"; break; - case FOP(31, 17): + case OPC_RSQRT2_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT2, ft); - gen_op_float_rsqrt2_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_rsqrt2_d(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "rsqrt2.d"; break; - case FOP(48, 17): - case FOP(49, 17): - case FOP(50, 17): - case FOP(51, 17): - case FOP(52, 17): - case FOP(53, 17): - case FOP(54, 17): - case FOP(55, 17): - case FOP(56, 17): - case FOP(57, 17): - case FOP(58, 17): - case FOP(59, 17): - case FOP(60, 17): - case FOP(61, 17): - case FOP(62, 17): - case FOP(63, 17): - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); + case OPC_CMP_F_D: + case OPC_CMP_UN_D: + case OPC_CMP_EQ_D: + case OPC_CMP_UEQ_D: + case OPC_CMP_OLT_D: + case OPC_CMP_ULT_D: + case OPC_CMP_OLE_D: + case OPC_CMP_ULE_D: + case OPC_CMP_SF_D: + case OPC_CMP_NGLE_D: + case OPC_CMP_SEQ_D: + case OPC_CMP_NGL_D: + case OPC_CMP_LT_D: + case OPC_CMP_NGE_D: + case OPC_CMP_LE_D: + case OPC_CMP_NGT_D: if (ctx->opcode & (1 << 6)) { - check_cop1x(ctx); - check_cp1_registers(ctx, fs | ft); - gen_cmpabs_d(func-48, cc); + gen_cmpabs_d(ctx, func-48, ft, fs, cc); opn = condnames_abs[func-48]; } else { - check_cp1_registers(ctx, fs | ft); - gen_cmp_d(func-48, cc); + gen_cmp_d(ctx, func-48, ft, fs, cc); opn = condnames[func-48]; } break; - case FOP(32, 17): + case OPC_CVT_S_D: check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvts_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); + gen_helper_float_cvts_d(fp32, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); + } opn = "cvt.s.d"; break; - case FOP(36, 17): + case OPC_CVT_W_D: check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvtw_d(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); + gen_helper_float_cvtw_d(fp32, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); + } opn = "cvt.w.d"; break; - case FOP(37, 17): + case OPC_CVT_L_D: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvtl_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_cvtl_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "cvt.l.d"; break; - case FOP(32, 20): - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvts_w(); - GEN_STORE_FTN_FREG(fd, WT2); + case OPC_CVT_S_W: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_cvts_w(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "cvt.s.w"; break; - case FOP(33, 20): + case OPC_CVT_D_W: check_cp1_registers(ctx, fd); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtd_w(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); + gen_helper_float_cvtd_w(fp64, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } opn = "cvt.d.w"; break; - case FOP(32, 21): + case OPC_CVT_S_L: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvts_l(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); + gen_helper_float_cvts_l(fp32, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); + } opn = "cvt.s.l"; break; - case FOP(33, 21): + case OPC_CVT_D_L: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvtd_l(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_cvtd_l(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "cvt.d.l"; break; - case FOP(38, 20): + case OPC_CVT_PS_PW: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_cvtps_pw(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_cvtps_pw(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "cvt.ps.pw"; break; - case FOP(0, 22): + case OPC_ADD_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_add_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_add_ps(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "add.ps"; break; - case FOP(1, 22): + case OPC_SUB_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_sub_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_sub_ps(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "sub.ps"; break; - case FOP(2, 22): + case OPC_MUL_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_mul_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_mul_ps(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "mul.ps"; break; - case FOP(5, 22): + case OPC_ABS_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_abs_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_abs_ps(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "abs.ps"; break; - case FOP(6, 22): + case OPC_MOV_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_mov_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "mov.ps"; break; - case FOP(7, 22): + case OPC_NEG_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_chs_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_chs_ps(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "neg.ps"; break; - case FOP(17, 22): + case OPC_MOVCF_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); - gen_movcf_ps(ctx, (ft >> 2) & 0x7, ft & 0x1); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + gen_movcf_ps(fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.ps"; break; - case FOP(18, 22): + case OPC_MOVZ_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); - gen_op_float_movz_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + int l1 = gen_new_label(); + TCGv_i64 fp0; + + if (ft != 0) + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1); + fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + gen_set_label(l1); + } opn = "movz.ps"; break; - case FOP(19, 22): + case OPC_MOVN_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_REG_T0(ft); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); - gen_op_float_movn_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + int l1 = gen_new_label(); + TCGv_i64 fp0; + + if (ft != 0) { + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1); + fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + gen_set_label(l1); + } + } opn = "movn.ps"; break; - case FOP(24, 22): + case OPC_ADDR_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, ft); - GEN_LOAD_FREG_FTN(WTH0, ft); - GEN_LOAD_FREG_FTN(WT1, fs); - GEN_LOAD_FREG_FTN(WTH1, fs); - gen_op_float_addr_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, ft); + gen_load_fpr64(ctx, fp1, fs); + gen_helper_float_addr_ps(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "addr.ps"; break; - case FOP(26, 22): + case OPC_MULR_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, ft); - GEN_LOAD_FREG_FTN(WTH0, ft); - GEN_LOAD_FREG_FTN(WT1, fs); - GEN_LOAD_FREG_FTN(WTH1, fs); - gen_op_float_mulr_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, ft); + gen_load_fpr64(ctx, fp1, fs); + gen_helper_float_mulr_ps(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "mulr.ps"; break; - case FOP(28, 22): + case OPC_RECIP2_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); - gen_op_float_recip2_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, fd); + gen_helper_float_recip2_ps(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "recip2.ps"; break; - case FOP(29, 22): + case OPC_RECIP1_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_recip1_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_recip1_ps(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "recip1.ps"; break; - case FOP(30, 22): + case OPC_RSQRT1_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_rsqrt1_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_rsqrt1_ps(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "rsqrt1.ps"; break; - case FOP(31, 22): + case OPC_RSQRT2_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, ft); - GEN_LOAD_FREG_FTN(WTH2, ft); - gen_op_float_rsqrt2_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_rsqrt2_ps(fp0, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "rsqrt2.ps"; break; - case FOP(32, 22): + case OPC_CVT_S_PU: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_cvts_pu(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32h(fp0, fs); + gen_helper_float_cvts_pu(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "cvt.s.pu"; break; - case FOP(36, 22): + case OPC_CVT_PW_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - gen_op_float_cvtpw_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_cvtpw_ps(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "cvt.pw.ps"; break; - case FOP(40, 22): + case OPC_CVT_S_PL: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvts_pl(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_cvts_pl(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "cvt.s.pl"; break; - case FOP(44, 22): + case OPC_PLL_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_pll_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_store_fpr32h(fp0, fd); + gen_store_fpr32(fp1, fd); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + } opn = "pll.ps"; break; - case FOP(45, 22): + case OPC_PLU_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_plu_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32h(fp1, ft); + gen_store_fpr32(fp1, fd); + gen_store_fpr32h(fp0, fd); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + } opn = "plu.ps"; break; - case FOP(46, 22): + case OPC_PUL_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_pul_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32h(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_store_fpr32(fp1, fd); + gen_store_fpr32h(fp0, fd); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + } opn = "pul.ps"; break; - case FOP(47, 22): + case OPC_PUU_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WTH1, ft); - gen_op_float_puu_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32h(fp0, fs); + gen_load_fpr32h(fp1, ft); + gen_store_fpr32(fp1, fd); + gen_store_fpr32h(fp0, fd); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + } opn = "puu.ps"; break; - case FOP(48, 22): - case FOP(49, 22): - case FOP(50, 22): - case FOP(51, 22): - case FOP(52, 22): - case FOP(53, 22): - case FOP(54, 22): - case FOP(55, 22): - case FOP(56, 22): - case FOP(57, 22): - case FOP(58, 22): - case FOP(59, 22): - case FOP(60, 22): - case FOP(61, 22): - case FOP(62, 22): - case FOP(63, 22): - check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); + case OPC_CMP_F_PS: + case OPC_CMP_UN_PS: + case OPC_CMP_EQ_PS: + case OPC_CMP_UEQ_PS: + case OPC_CMP_OLT_PS: + case OPC_CMP_ULT_PS: + case OPC_CMP_OLE_PS: + case OPC_CMP_ULE_PS: + case OPC_CMP_SF_PS: + case OPC_CMP_NGLE_PS: + case OPC_CMP_SEQ_PS: + case OPC_CMP_NGL_PS: + case OPC_CMP_LT_PS: + case OPC_CMP_NGE_PS: + case OPC_CMP_LE_PS: + case OPC_CMP_NGT_PS: if (ctx->opcode & (1 << 6)) { - gen_cmpabs_ps(func-48, cc); + gen_cmpabs_ps(ctx, func-48, ft, fs, cc); opn = condnames_abs[func-48]; } else { - gen_cmp_ps(func-48, cc); + gen_cmp_ps(ctx, func-48, ft, fs, cc); opn = condnames[func-48]; } break; @@ -5810,6 +7722,7 @@ static void gen_farith (DisasContext *ct generate_exception (ctx, EXCP_RI); return; } + (void)opn; /* avoid a compiler warning */ switch (optype) { case BINOP: MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]); @@ -5829,68 +7742,100 @@ static void gen_flt3_ldst (DisasContext { const char *opn = "extended float load/store"; int store = 0; + TCGv t0 = tcg_temp_new(); if (base == 0) { - if (index == 0) - gen_op_reset_T0(); - else - GEN_LOAD_REG_T0(index); + gen_load_gpr(t0, index); } else if (index == 0) { - GEN_LOAD_REG_T0(base); + gen_load_gpr(t0, base); } else { - GEN_LOAD_REG_T0(base); - GEN_LOAD_REG_T1(index); - gen_op_addr_add(); + gen_load_gpr(t0, index); + gen_op_addr_add(ctx, t0, cpu_gpr[base], t0); } /* Don't do NOP if destination is zero: we must perform the actual memory access. */ + save_cpu_state(ctx, 0); switch (opc) { case OPC_LWXC1: check_cop1x(ctx); - op_ldst(lwc1); - GEN_STORE_FTN_FREG(fd, WT0); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + tcg_gen_qemu_ld32s(t0, t0, ctx->mem_idx); + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } opn = "lwxc1"; break; case OPC_LDXC1: check_cop1x(ctx); check_cp1_registers(ctx, fd); - op_ldst(ldc1); - GEN_STORE_FTN_FREG(fd, DT0); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "ldxc1"; break; case OPC_LUXC1: check_cp1_64bitmode(ctx); - op_ldst(luxc1); - GEN_STORE_FTN_FREG(fd, DT0); + tcg_gen_andi_tl(t0, t0, ~0x7); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } opn = "luxc1"; break; case OPC_SWXC1: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - op_ldst(swc1); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new(); + + gen_load_fpr32(fp0, fs); + tcg_gen_extu_i32_tl(t1, fp0); + tcg_gen_qemu_st32(t1, t0, ctx->mem_idx); + tcg_temp_free_i32(fp0); + tcg_temp_free(t1); + } opn = "swxc1"; store = 1; break; case OPC_SDXC1: check_cop1x(ctx); check_cp1_registers(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - op_ldst(sdc1); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx); + tcg_temp_free_i64(fp0); + } opn = "sdxc1"; store = 1; break; case OPC_SUXC1: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(DT0, fs); - op_ldst(suxc1); + tcg_gen_andi_tl(t0, t0, ~0x7); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx); + tcg_temp_free_i64(fp0); + } opn = "suxc1"; store = 1; break; - default: - MIPS_INVAL(opn); - generate_exception(ctx, EXCP_RI); - return; } + tcg_temp_free(t0); + (void)opn; (void)store; /* avoid compiler warnings */ MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd], regnames[index], regnames[base]); } @@ -5903,139 +7848,260 @@ static void gen_flt3_arith (DisasContext switch (opc) { case OPC_ALNV_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_REG_T0(fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - gen_op_float_alnv_ps(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv t0 = tcg_temp_local_new(); + TCGv_i32 fp = tcg_temp_new_i32(); + TCGv_i32 fph = tcg_temp_new_i32(); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + + gen_load_gpr(t0, fr); + tcg_gen_andi_tl(t0, t0, 0x7); + + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); + gen_load_fpr32(fp, fs); + gen_load_fpr32h(fph, fs); + gen_store_fpr32(fp, fd); + gen_store_fpr32h(fph, fd); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_brcondi_tl(TCG_COND_NE, t0, 4, l2); + tcg_temp_free(t0); +#ifdef TARGET_WORDS_BIGENDIAN + gen_load_fpr32(fp, fs); + gen_load_fpr32h(fph, ft); + gen_store_fpr32h(fp, fd); + gen_store_fpr32(fph, fd); +#else + gen_load_fpr32h(fph, fs); + gen_load_fpr32(fp, ft); + gen_store_fpr32(fph, fd); + gen_store_fpr32h(fp, fd); +#endif + gen_set_label(l2); + tcg_temp_free_i32(fp); + tcg_temp_free_i32(fph); + } opn = "alnv.ps"; break; case OPC_MADD_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - gen_op_float_muladd_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); + gen_helper_float_muladd_s(fp2, fp0, fp1, fp2); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + } opn = "madd.s"; break; case OPC_MADD_D: check_cop1x(ctx); check_cp1_registers(ctx, fd | fs | ft | fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - GEN_LOAD_FREG_FTN(DT2, fr); - gen_op_float_muladd_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + gen_helper_float_muladd_d(fp2, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + } opn = "madd.d"; break; case OPC_MADD_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - GEN_LOAD_FREG_FTN(WTH2, fr); - gen_op_float_muladd_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + gen_helper_float_muladd_ps(fp2, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + } opn = "madd.ps"; break; case OPC_MSUB_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - gen_op_float_mulsub_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); + gen_helper_float_mulsub_s(fp2, fp0, fp1, fp2); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + } opn = "msub.s"; break; case OPC_MSUB_D: check_cop1x(ctx); check_cp1_registers(ctx, fd | fs | ft | fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - GEN_LOAD_FREG_FTN(DT2, fr); - gen_op_float_mulsub_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + gen_helper_float_mulsub_d(fp2, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + } opn = "msub.d"; break; case OPC_MSUB_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - GEN_LOAD_FREG_FTN(WTH2, fr); - gen_op_float_mulsub_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + gen_helper_float_mulsub_ps(fp2, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + } opn = "msub.ps"; break; case OPC_NMADD_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - gen_op_float_nmuladd_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); + gen_helper_float_nmuladd_s(fp2, fp0, fp1, fp2); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + } opn = "nmadd.s"; break; case OPC_NMADD_D: check_cop1x(ctx); check_cp1_registers(ctx, fd | fs | ft | fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - GEN_LOAD_FREG_FTN(DT2, fr); - gen_op_float_nmuladd_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + gen_helper_float_nmuladd_d(fp2, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + } opn = "nmadd.d"; break; case OPC_NMADD_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - GEN_LOAD_FREG_FTN(WTH2, fr); - gen_op_float_nmuladd_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + gen_helper_float_nmuladd_ps(fp2, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + } opn = "nmadd.ps"; break; case OPC_NMSUB_S: check_cop1x(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - gen_op_float_nmulsub_s(); - GEN_STORE_FTN_FREG(fd, WT2); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); + gen_helper_float_nmulsub_s(fp2, fp0, fp1, fp2); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + } opn = "nmsub.s"; break; case OPC_NMSUB_D: check_cop1x(ctx); check_cp1_registers(ctx, fd | fs | ft | fr); - GEN_LOAD_FREG_FTN(DT0, fs); - GEN_LOAD_FREG_FTN(DT1, ft); - GEN_LOAD_FREG_FTN(DT2, fr); - gen_op_float_nmulsub_d(); - GEN_STORE_FTN_FREG(fd, DT2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + gen_helper_float_nmulsub_d(fp2, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + } opn = "nmsub.d"; break; case OPC_NMSUB_PS: check_cp1_64bitmode(ctx); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); - GEN_LOAD_FREG_FTN(WT2, fr); - GEN_LOAD_FREG_FTN(WTH2, fr); - gen_op_float_nmulsub_ps(); - GEN_STORE_FTN_FREG(fd, WT2); - GEN_STORE_FTN_FREG(fd, WTH2); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); + gen_helper_float_nmulsub_ps(fp2, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + } opn = "nmsub.ps"; break; default: @@ -6043,12 +8109,3578 @@ static void gen_flt3_arith (DisasContext generate_exception (ctx, EXCP_RI); return; } + (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr], fregnames[fs], fregnames[ft]); } +static void +gen_rdhwr (CPUState *env, DisasContext *ctx, int rt, int rd) +{ + TCGv t0; + + check_insn(env, ctx, ISA_MIPS32R2); + t0 = tcg_temp_new(); + + switch (rd) { + case 0: + save_cpu_state(ctx, 1); + gen_helper_rdhwr_cpunum(t0); + gen_store_gpr(t0, rt); + break; + case 1: + save_cpu_state(ctx, 1); + gen_helper_rdhwr_synci_step(t0); + gen_store_gpr(t0, rt); + break; + case 2: + save_cpu_state(ctx, 1); + gen_helper_rdhwr_cc(t0); + gen_store_gpr(t0, rt); + break; + case 3: + save_cpu_state(ctx, 1); + gen_helper_rdhwr_ccres(t0); + gen_store_gpr(t0, rt); + break; + case 29: +#if defined(CONFIG_USER_ONLY) + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, tls_value)); + gen_store_gpr(t0, rt); + break; +#else + /* XXX: Some CPUs implement this in hardware. + Not supported yet. */ +#endif + default: /* Invalid */ + MIPS_INVAL("rdhwr"); + generate_exception(ctx, EXCP_RI); + break; + } + tcg_temp_free(t0); +} + +static void handle_delay_slot (CPUState *env, DisasContext *ctx, + int insn_bytes) +{ + if (ctx->hflags & MIPS_HFLAG_BMASK) { + int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK; + /* Branches completion */ + ctx->hflags &= ~MIPS_HFLAG_BMASK; + ctx->bstate = BS_BRANCH; + save_cpu_state(ctx, 0); + /* FIXME: Need to clear can_do_io. */ + switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) { + case MIPS_HFLAG_B: + /* unconditional branch */ + MIPS_DEBUG("unconditional branch"); + if (proc_hflags & MIPS_HFLAG_BX) { + tcg_gen_xori_i32(hflags, hflags, MIPS_HFLAG_M16); + } + gen_goto_tb(ctx, 0, ctx->btarget); + break; + case MIPS_HFLAG_BL: + /* blikely taken case */ + MIPS_DEBUG("blikely branch taken"); + gen_goto_tb(ctx, 0, ctx->btarget); + break; + case MIPS_HFLAG_BC: + /* Conditional branch */ + MIPS_DEBUG("conditional branch"); + { + int l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1); + gen_goto_tb(ctx, 1, ctx->pc + insn_bytes); + gen_set_label(l1); + gen_goto_tb(ctx, 0, ctx->btarget); + } + break; + case MIPS_HFLAG_BR: + /* unconditional branch to register */ + MIPS_DEBUG("branch to register"); + if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) { + TCGv t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_andi_tl(t0, btarget, 0x1); + tcg_gen_trunc_tl_i32(t1, t0); + tcg_temp_free(t0); + tcg_gen_andi_i32(hflags, hflags, ~(uint32_t)MIPS_HFLAG_M16); + tcg_gen_shli_i32(t1, t1, MIPS_HFLAG_M16_SHIFT); + tcg_gen_or_i32(hflags, hflags, t1); + tcg_temp_free_i32(t1); + + tcg_gen_andi_tl(cpu_PC, btarget, ~(target_ulong)0x1); + } else { + tcg_gen_mov_tl(cpu_PC, btarget); + } + if (ctx->singlestep_enabled) { + save_cpu_state(ctx, 0); + gen_helper_0i(raise_exception, EXCP_DEBUG); + } + tcg_gen_exit_tb(0); + break; + default: + MIPS_DEBUG("unknown branch"); + break; + } + } +} + /* ISA extensions (ASEs) */ /* MIPS16 extension to MIPS32 */ + +/* MIPS16 major opcodes */ +enum { + M16_OPC_ADDIUSP = 0x00, + M16_OPC_ADDIUPC = 0x01, + M16_OPC_B = 0x02, + M16_OPC_JAL = 0x03, + M16_OPC_BEQZ = 0x04, + M16_OPC_BNEQZ = 0x05, + M16_OPC_SHIFT = 0x06, + M16_OPC_LD = 0x07, + M16_OPC_RRIA = 0x08, + M16_OPC_ADDIU8 = 0x09, + M16_OPC_SLTI = 0x0a, + M16_OPC_SLTIU = 0x0b, + M16_OPC_I8 = 0x0c, + M16_OPC_LI = 0x0d, + M16_OPC_CMPI = 0x0e, + M16_OPC_SD = 0x0f, + M16_OPC_LB = 0x10, + M16_OPC_LH = 0x11, + M16_OPC_LWSP = 0x12, + M16_OPC_LW = 0x13, + M16_OPC_LBU = 0x14, + M16_OPC_LHU = 0x15, + M16_OPC_LWPC = 0x16, + M16_OPC_LWU = 0x17, + M16_OPC_SB = 0x18, + M16_OPC_SH = 0x19, + M16_OPC_SWSP = 0x1a, + M16_OPC_SW = 0x1b, + M16_OPC_RRR = 0x1c, + M16_OPC_RR = 0x1d, + M16_OPC_EXTEND = 0x1e, + M16_OPC_I64 = 0x1f +}; + +/* I8 funct field */ +enum { + I8_BTEQZ = 0x0, + I8_BTNEZ = 0x1, + I8_SWRASP = 0x2, + I8_ADJSP = 0x3, + I8_SVRS = 0x4, + I8_MOV32R = 0x5, + I8_MOVR32 = 0x7 +}; + +/* RRR f field */ +enum { + RRR_DADDU = 0x0, + RRR_ADDU = 0x1, + RRR_DSUBU = 0x2, + RRR_SUBU = 0x3 +}; + +/* RR funct field */ +enum { + RR_JR = 0x00, + RR_SDBBP = 0x01, + RR_SLT = 0x02, + RR_SLTU = 0x03, + RR_SLLV = 0x04, + RR_BREAK = 0x05, + RR_SRLV = 0x06, + RR_SRAV = 0x07, + RR_DSRL = 0x08, + RR_CMP = 0x0a, + RR_NEG = 0x0b, + RR_AND = 0x0c, + RR_OR = 0x0d, + RR_XOR = 0x0e, + RR_NOT = 0x0f, + RR_MFHI = 0x10, + RR_CNVT = 0x11, + RR_MFLO = 0x12, + RR_DSRA = 0x13, + RR_DSLLV = 0x14, + RR_DSRLV = 0x16, + RR_DSRAV = 0x17, + RR_MULT = 0x18, + RR_MULTU = 0x19, + RR_DIV = 0x1a, + RR_DIVU = 0x1b, + RR_DMULT = 0x1c, + RR_DMULTU = 0x1d, + RR_DDIV = 0x1e, + RR_DDIVU = 0x1f +}; + +/* I64 funct field */ +enum { + I64_LDSP = 0x0, + I64_SDSP = 0x1, + I64_SDRASP = 0x2, + I64_DADJSP = 0x3, + I64_LDPC = 0x4, + I64_DADDIU5 = 0x5, + I64_DADDIUPC = 0x6, + I64_DADDIUSP = 0x7 +}; + +/* RR ry field for CNVT */ +enum { + RR_RY_CNVT_ZEB = 0x0, + RR_RY_CNVT_ZEH = 0x1, + RR_RY_CNVT_ZEW = 0x2, + RR_RY_CNVT_SEB = 0x4, + RR_RY_CNVT_SEH = 0x5, + RR_RY_CNVT_SEW = 0x6, +}; + +static int xlat (int r) +{ + static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; + + return map[r]; +} + +static void gen_mips16_save (DisasContext *ctx, + int xsregs, int aregs, + int do_ra, int do_s0, int do_s1, + int framesize) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int args, astatic; + + switch (aregs) { + case 0: + case 1: + case 2: + case 3: + case 11: + args = 0; + break; + case 4: + case 5: + case 6: + case 7: + args = 1; + break; + case 8: + case 9: + case 10: + args = 2; + break; + case 12: + case 13: + args = 3; + break; + case 14: + args = 4; + break; + default: + generate_exception(ctx, EXCP_RI); + return; + } + + switch (args) { + case 4: + gen_base_offset_addr(ctx, t0, 29, 12); + gen_load_gpr(t1, 7); + op_st_sw(t1, t0, ctx); + /* Fall through */ + case 3: + gen_base_offset_addr(ctx, t0, 29, 8); + gen_load_gpr(t1, 6); + op_st_sw(t1, t0, ctx); + /* Fall through */ + case 2: + gen_base_offset_addr(ctx, t0, 29, 4); + gen_load_gpr(t1, 5); + op_st_sw(t1, t0, ctx); + /* Fall through */ + case 1: + gen_base_offset_addr(ctx, t0, 29, 0); + gen_load_gpr(t1, 4); + op_st_sw(t1, t0, ctx); + } + + gen_load_gpr(t0, 29); + +#define DECR_AND_STORE(reg) do { \ + tcg_gen_subi_tl(t0, t0, 4); \ + gen_load_gpr(t1, reg); \ + op_st_sw(t1, t0, ctx); \ + } while (0) + + if (do_ra) { + DECR_AND_STORE(31); + } + + switch (xsregs) { + case 7: + DECR_AND_STORE(30); + /* Fall through */ + case 6: + DECR_AND_STORE(23); + /* Fall through */ + case 5: + DECR_AND_STORE(22); + /* Fall through */ + case 4: + DECR_AND_STORE(21); + /* Fall through */ + case 3: + DECR_AND_STORE(20); + /* Fall through */ + case 2: + DECR_AND_STORE(19); + /* Fall through */ + case 1: + DECR_AND_STORE(18); + } + + if (do_s1) { + DECR_AND_STORE(17); + } + if (do_s0) { + DECR_AND_STORE(16); + } + + switch (aregs) { + case 0: + case 4: + case 8: + case 12: + case 14: + astatic = 0; + break; + case 1: + case 5: + case 9: + case 13: + astatic = 1; + break; + case 2: + case 6: + case 10: + astatic = 2; + break; + case 3: + case 7: + astatic = 3; + break; + case 11: + astatic = 4; + break; + default: + generate_exception(ctx, EXCP_RI); + return; + } + + if (astatic > 0) { + DECR_AND_STORE(7); + if (astatic > 1) { + DECR_AND_STORE(6); + if (astatic > 2) { + DECR_AND_STORE(5); + if (astatic > 3) { + DECR_AND_STORE(4); + } + } + } + } +#undef DECR_AND_STORE + + tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_mips16_restore (DisasContext *ctx, + int xsregs, int aregs, + int do_ra, int do_s0, int do_s1, + int framesize) +{ + int astatic; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + tcg_gen_addi_tl(t0, cpu_gpr[29], framesize); + +#define DECR_AND_LOAD(reg) do { \ + tcg_gen_subi_tl(t0, t0, 4); \ + op_ld_lw(t1, t0, ctx); \ + gen_store_gpr(t1, reg); \ + } while (0) + + if (do_ra) { + DECR_AND_LOAD(31); + } + + switch (xsregs) { + case 7: + DECR_AND_LOAD(30); + /* Fall through */ + case 6: + DECR_AND_LOAD(23); + /* Fall through */ + case 5: + DECR_AND_LOAD(22); + /* Fall through */ + case 4: + DECR_AND_LOAD(21); + /* Fall through */ + case 3: + DECR_AND_LOAD(20); + /* Fall through */ + case 2: + DECR_AND_LOAD(19); + /* Fall through */ + case 1: + DECR_AND_LOAD(18); + } + + if (do_s1) { + DECR_AND_LOAD(17); + } + if (do_s0) { + DECR_AND_LOAD(16); + } + + switch (aregs) { + case 0: + case 4: + case 8: + case 12: + case 14: + astatic = 0; + break; + case 1: + case 5: + case 9: + case 13: + astatic = 1; + break; + case 2: + case 6: + case 10: + astatic = 2; + break; + case 3: + case 7: + astatic = 3; + break; + case 11: + astatic = 4; + break; + default: + generate_exception(ctx, EXCP_RI); + return; + } + + if (astatic > 0) { + DECR_AND_LOAD(7); + if (astatic > 1) { + DECR_AND_LOAD(6); + if (astatic > 2) { + DECR_AND_LOAD(5); + if (astatic > 3) { + DECR_AND_LOAD(4); + } + } + } + } +#undef DECR_AND_LOAD + + tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_addiupc (DisasContext *ctx, int rx, int imm, + int is_64_bit, int extended) +{ + TCGv t0; + + if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) { + generate_exception(ctx, EXCP_RI); + return; + } + + t0 = tcg_temp_new(); + + tcg_gen_movi_tl(t0, pc_relative_pc(ctx)); + tcg_gen_addi_tl(cpu_gpr[rx], t0, imm); + if (!is_64_bit) { + tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]); + } + + tcg_temp_free(t0); +} + +#if defined(TARGET_MIPS64) +static void decode_i64_mips16 (CPUState *env, DisasContext *ctx, + int ry, int funct, int16_t offset, + int extended) +{ + switch (funct) { + case I64_LDSP: + check_mips_64(ctx); + offset = extended ? offset : offset << 3; + gen_ld(env, ctx, OPC_LD, ry, 29, offset); + break; + case I64_SDSP: + check_mips_64(ctx); + offset = extended ? offset : offset << 3; + gen_st(ctx, OPC_SD, ry, 29, offset); + break; + case I64_SDRASP: + check_mips_64(ctx); + offset = extended ? offset : (ctx->opcode & 0xff) << 3; + gen_st(ctx, OPC_SD, 31, 29, offset); + break; + case I64_DADJSP: + check_mips_64(ctx); + offset = extended ? offset : ((int8_t)ctx->opcode) << 3; + gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29, offset); + break; + case I64_LDPC: + if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) { + generate_exception(ctx, EXCP_RI); + } else { + offset = extended ? offset : offset << 3; + gen_ld(env, ctx, OPC_LDPC, ry, 0, offset); + } + break; + case I64_DADDIU5: + check_mips_64(ctx); + offset = extended ? offset : ((int8_t)(offset << 3)) >> 3; + gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry, offset); + break; + case I64_DADDIUPC: + check_mips_64(ctx); + offset = extended ? offset : offset << 2; + gen_addiupc(ctx, ry, offset, 1, extended); + break; + case I64_DADDIUSP: + check_mips_64(ctx); + offset = extended ? offset : offset << 2; + gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29, offset); + break; + } +} +#endif + +static int decode_extended_mips16_opc (CPUState *env, DisasContext *ctx, + int *is_branch) +{ + int extend = lduw_code(ctx->pc + 2); + int op, rx, ry, funct, sa; + int16_t imm, offset; + + ctx->opcode = (ctx->opcode << 16) | extend; + op = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 22) & 0x1f; + funct = (ctx->opcode >> 8) & 0x7; + rx = xlat((ctx->opcode >> 8) & 0x7); + ry = xlat((ctx->opcode >> 5) & 0x7); + offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11 + | ((ctx->opcode >> 21) & 0x3f) << 5 + | (ctx->opcode & 0x1f)); + + /* The extended opcodes cleverly reuse the opcodes from their 16-bit + counterparts. */ + switch (op) { + case M16_OPC_ADDIUSP: + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm); + break; + case M16_OPC_ADDIUPC: + gen_addiupc(ctx, rx, imm, 0, 1); + break; + case M16_OPC_B: + gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_BEQZ: + gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_BNEQZ: + gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_SHIFT: + switch (ctx->opcode & 0x3) { + case 0x0: + gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa); + break; + case 0x1: +#if defined(TARGET_MIPS64) + check_mips_64(ctx); + gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa); +#else + generate_exception(ctx, EXCP_RI); +#endif + break; + case 0x2: + gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa); + break; + case 0x3: + gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa); + break; + } + break; +#if defined(TARGET_MIPS64) + case M16_OPC_LD: + check_mips_64(ctx); + gen_ld(env, ctx, OPC_LD, ry, rx, offset); + break; +#endif + case M16_OPC_RRIA: + imm = ctx->opcode & 0xf; + imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4; + imm = imm | ((ctx->opcode >> 16) & 0xf) << 11; + imm = (int16_t) (imm << 1) >> 1; + if ((ctx->opcode >> 4) & 0x1) { +#if defined(TARGET_MIPS64) + check_mips_64(ctx); + gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm); +#else + generate_exception(ctx, EXCP_RI); +#endif + } else { + gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm); + } + break; + case M16_OPC_ADDIU8: + gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm); + break; + case M16_OPC_SLTI: + gen_slt_imm(env, OPC_SLTI, 24, rx, imm); + break; + case M16_OPC_SLTIU: + gen_slt_imm(env, OPC_SLTIU, 24, rx, imm); + break; + case M16_OPC_I8: + switch (funct) { + case I8_BTEQZ: + gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1); + break; + case I8_BTNEZ: + gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1); + break; + case I8_SWRASP: + gen_st(ctx, OPC_SW, 31, 29, imm); + break; + case I8_ADJSP: + gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm); + break; + case I8_SVRS: + { + int xsregs = (ctx->opcode >> 24) & 0x7; + int aregs = (ctx->opcode >> 16) & 0xf; + int do_ra = (ctx->opcode >> 6) & 0x1; + int do_s0 = (ctx->opcode >> 5) & 0x1; + int do_s1 = (ctx->opcode >> 4) & 0x1; + int framesize = (((ctx->opcode >> 20) & 0xf) << 4 + | (ctx->opcode & 0xf)) << 3; + + if (ctx->opcode & (1 << 7)) { + gen_mips16_save(ctx, xsregs, aregs, + do_ra, do_s0, do_s1, + framesize); + } else { + gen_mips16_restore(ctx, xsregs, aregs, + do_ra, do_s0, do_s1, + framesize); + } + } + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case M16_OPC_LI: + tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm); + break; + case M16_OPC_CMPI: + tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm); + break; +#if defined(TARGET_MIPS64) + case M16_OPC_SD: + gen_st(ctx, OPC_SD, ry, rx, offset); + break; +#endif + case M16_OPC_LB: + gen_ld(env, ctx, OPC_LB, ry, rx, offset); + break; + case M16_OPC_LH: + gen_ld(env, ctx, OPC_LH, ry, rx, offset); + break; + case M16_OPC_LWSP: + gen_ld(env, ctx, OPC_LW, rx, 29, offset); + break; + case M16_OPC_LW: + gen_ld(env, ctx, OPC_LW, ry, rx, offset); + break; + case M16_OPC_LBU: + gen_ld(env, ctx, OPC_LBU, ry, rx, offset); + break; + case M16_OPC_LHU: + gen_ld(env, ctx, OPC_LHU, ry, rx, offset); + break; + case M16_OPC_LWPC: + gen_ld(env, ctx, OPC_LWPC, rx, 0, offset); + break; +#if defined(TARGET_MIPS64) + case M16_OPC_LWU: + gen_ld(env, ctx, OPC_LWU, ry, rx, offset); + break; +#endif + case M16_OPC_SB: + gen_st(ctx, OPC_SB, ry, rx, offset); + break; + case M16_OPC_SH: + gen_st(ctx, OPC_SH, ry, rx, offset); + break; + case M16_OPC_SWSP: + gen_st(ctx, OPC_SW, rx, 29, offset); + break; + case M16_OPC_SW: + gen_st(ctx, OPC_SW, ry, rx, offset); + break; +#if defined(TARGET_MIPS64) + case M16_OPC_I64: + decode_i64_mips16(env, ctx, ry, funct, offset, 1); + break; +#endif + default: + generate_exception(ctx, EXCP_RI); + break; + } + + return 4; +} + +static int decode_mips16_opc (CPUState *env, DisasContext *ctx, + int *is_branch) +{ + int rx, ry; + int sa; + int op, cnvt_op, op1, offset; + int funct; + int n_bytes; + + op = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 2) & 0x7; + sa = sa == 0 ? 8 : sa; + rx = xlat((ctx->opcode >> 8) & 0x7); + cnvt_op = (ctx->opcode >> 5) & 0x7; + ry = xlat((ctx->opcode >> 5) & 0x7); + op1 = offset = ctx->opcode & 0x1f; + + n_bytes = 2; + + switch (op) { + case M16_OPC_ADDIUSP: + { + int16_t imm = ((uint8_t) ctx->opcode) << 2; + + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm); + } + break; + case M16_OPC_ADDIUPC: + gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2, 0, 0); + break; + case M16_OPC_B: + offset = (ctx->opcode & 0x7ff) << 1; + offset = (int16_t)(offset << 4) >> 4; + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_JAL: + offset = lduw_code(ctx->pc + 2); + offset = (((ctx->opcode & 0x1f) << 21) + | ((ctx->opcode >> 5) & 0x1f) << 16 + | offset) << 2; + op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS; + gen_compute_branch(ctx, op, 4, rx, ry, offset); + n_bytes = 4; + *is_branch = 1; + break; + case M16_OPC_BEQZ: + gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_BNEQZ: + gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_SHIFT: + switch (ctx->opcode & 0x3) { + case 0x0: + gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa); + break; + case 0x1: +#if defined(TARGET_MIPS64) + check_mips_64(ctx); + gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa); +#else + generate_exception(ctx, EXCP_RI); +#endif + break; + case 0x2: + gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa); + break; + case 0x3: + gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa); + break; + } + break; +#if defined(TARGET_MIPS64) + case M16_OPC_LD: + check_mips_64(ctx); + gen_ld(env, ctx, OPC_LD, ry, rx, offset << 3); + break; +#endif + case M16_OPC_RRIA: + { + int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4; + + if ((ctx->opcode >> 4) & 1) { +#if defined(TARGET_MIPS64) + check_mips_64(ctx); + gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm); +#else + generate_exception(ctx, EXCP_RI); +#endif + } else { + gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm); + } + } + break; + case M16_OPC_ADDIU8: + { + int16_t imm = (int8_t) ctx->opcode; + + gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm); + } + break; + case M16_OPC_SLTI: + { + int16_t imm = (uint8_t) ctx->opcode; + + gen_slt_imm(env, OPC_SLTI, 24, rx, imm); + } + break; + case M16_OPC_SLTIU: + { + int16_t imm = (uint8_t) ctx->opcode; + + gen_slt_imm(env, OPC_SLTIU, 24, rx, imm); + } + break; + case M16_OPC_I8: + { + int reg32; + + funct = (ctx->opcode >> 8) & 0x7; + switch (funct) { + case I8_BTEQZ: + gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0, + ((int8_t)ctx->opcode) << 1); + break; + case I8_BTNEZ: + gen_compute_branch(ctx, OPC_BNE, 2, 24, 0, + ((int8_t)ctx->opcode) << 1); + break; + case I8_SWRASP: + gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); + break; + case I8_ADJSP: + gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, + ((int8_t)ctx->opcode) << 3); + break; + case I8_SVRS: + { + int do_ra = ctx->opcode & (1 << 6); + int do_s0 = ctx->opcode & (1 << 5); + int do_s1 = ctx->opcode & (1 << 4); + int framesize = ctx->opcode & 0xf; + + if (framesize == 0) { + framesize = 128; + } else { + framesize = framesize << 3; + } + + if (ctx->opcode & (1 << 7)) { + gen_mips16_save(ctx, 0, 0, + do_ra, do_s0, do_s1, framesize); + } else { + gen_mips16_restore(ctx, 0, 0, + do_ra, do_s0, do_s1, framesize); + } + } + break; + case I8_MOV32R: + { + int rz = xlat(ctx->opcode & 0x7); + + reg32 = (((ctx->opcode >> 3) & 0x3) << 3) | + ((ctx->opcode >> 5) & 0x7); + gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0); + } + break; + case I8_MOVR32: + reg32 = ctx->opcode & 0x1f; + gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + } + break; + case M16_OPC_LI: + { + int16_t imm = (uint8_t) ctx->opcode; + + gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm); + } + break; + case M16_OPC_CMPI: + { + int16_t imm = (uint8_t) ctx->opcode; + + gen_logic_imm(env, OPC_XORI, 24, rx, imm); + } + break; +#if defined(TARGET_MIPS64) + case M16_OPC_SD: + check_mips_64(ctx); + gen_st(ctx, OPC_SD, ry, rx, offset << 3); + break; +#endif + case M16_OPC_LB: + gen_ld(env, ctx, OPC_LB, ry, rx, offset); + break; + case M16_OPC_LH: + gen_ld(env, ctx, OPC_LH, ry, rx, offset << 1); + break; + case M16_OPC_LWSP: + gen_ld(env, ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2); + break; + case M16_OPC_LW: + gen_ld(env, ctx, OPC_LW, ry, rx, offset << 2); + break; + case M16_OPC_LBU: + gen_ld(env, ctx, OPC_LBU, ry, rx, offset); + break; + case M16_OPC_LHU: + gen_ld(env, ctx, OPC_LHU, ry, rx, offset << 1); + break; + case M16_OPC_LWPC: + gen_ld(env, ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2); + break; +#if defined (TARGET_MIPS64) + case M16_OPC_LWU: + check_mips_64(ctx); + gen_ld(env, ctx, OPC_LWU, ry, rx, offset << 2); + break; +#endif + case M16_OPC_SB: + gen_st(ctx, OPC_SB, ry, rx, offset); + break; + case M16_OPC_SH: + gen_st(ctx, OPC_SH, ry, rx, offset << 1); + break; + case M16_OPC_SWSP: + gen_st(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2); + break; + case M16_OPC_SW: + gen_st(ctx, OPC_SW, ry, rx, offset << 2); + break; + case M16_OPC_RRR: + { + int rz = xlat((ctx->opcode >> 2) & 0x7); + int mips32_op; + + switch (ctx->opcode & 0x3) { + case RRR_ADDU: + mips32_op = OPC_ADDU; + break; + case RRR_SUBU: + mips32_op = OPC_SUBU; + break; +#if defined(TARGET_MIPS64) + case RRR_DADDU: + mips32_op = OPC_DADDU; + check_mips_64(ctx); + break; + case RRR_DSUBU: + mips32_op = OPC_DSUBU; + check_mips_64(ctx); + break; +#endif + default: + generate_exception(ctx, EXCP_RI); + goto done; + } + + gen_arith(env, ctx, mips32_op, rz, rx, ry); + done: + ; + } + break; + case M16_OPC_RR: + switch (op1) { + case RR_JR: + { + int nd = (ctx->opcode >> 7) & 0x1; + int link = (ctx->opcode >> 6) & 0x1; + int ra = (ctx->opcode >> 5) & 0x1; + + if (link) { + op = nd ? OPC_JALRC : OPC_JALRS; + } else { + op = OPC_JR; + } + + gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0); + if (!nd) { + *is_branch = 1; + } + } + break; + case RR_SDBBP: + /* XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(env, ctx, ISA_MIPS32); + if (!(ctx->hflags & MIPS_HFLAG_DM)) { + generate_exception(ctx, EXCP_DBp); + } else { + generate_exception(ctx, EXCP_DBp); + } + break; + case RR_SLT: + gen_slt(env, OPC_SLT, 24, rx, ry); + break; + case RR_SLTU: + gen_slt(env, OPC_SLTU, 24, rx, ry); + break; + case RR_BREAK: + generate_exception(ctx, EXCP_BREAK); + break; + case RR_SLLV: + gen_shift(env, ctx, OPC_SLLV, ry, rx, ry); + break; + case RR_SRLV: + gen_shift(env, ctx, OPC_SRLV, ry, rx, ry); + break; + case RR_SRAV: + gen_shift(env, ctx, OPC_SRAV, ry, rx, ry); + break; +#if defined (TARGET_MIPS64) + case RR_DSRL: + check_mips_64(ctx); + gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa); + break; +#endif + case RR_CMP: + gen_logic(env, OPC_XOR, 24, rx, ry); + break; + case RR_NEG: + gen_arith(env, ctx, OPC_SUBU, rx, 0, ry); + break; + case RR_AND: + gen_logic(env, OPC_AND, rx, rx, ry); + break; + case RR_OR: + gen_logic(env, OPC_OR, rx, rx, ry); + break; + case RR_XOR: + gen_logic(env, OPC_XOR, rx, rx, ry); + break; + case RR_NOT: + gen_logic(env, OPC_NOR, rx, ry, 0); + break; + case RR_MFHI: + gen_HILO(ctx, OPC_MFHI, rx); + break; + case RR_CNVT: + switch (cnvt_op) { + case RR_RY_CNVT_ZEB: + tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; + case RR_RY_CNVT_ZEH: + tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; + case RR_RY_CNVT_SEB: + tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; + case RR_RY_CNVT_SEH: + tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; +#if defined (TARGET_MIPS64) + case RR_RY_CNVT_ZEW: + check_mips_64(ctx); + tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; + case RR_RY_CNVT_SEW: + check_mips_64(ctx); + tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; +#endif + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case RR_MFLO: + gen_HILO(ctx, OPC_MFLO, rx); + break; +#if defined (TARGET_MIPS64) + case RR_DSRA: + check_mips_64(ctx); + gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa); + break; + case RR_DSLLV: + check_mips_64(ctx); + gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry); + break; + case RR_DSRLV: + check_mips_64(ctx); + gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry); + break; + case RR_DSRAV: + check_mips_64(ctx); + gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry); + break; +#endif + case RR_MULT: + gen_muldiv(ctx, OPC_MULT, rx, ry); + break; + case RR_MULTU: + gen_muldiv(ctx, OPC_MULTU, rx, ry); + break; + case RR_DIV: + gen_muldiv(ctx, OPC_DIV, rx, ry); + break; + case RR_DIVU: + gen_muldiv(ctx, OPC_DIVU, rx, ry); + break; +#if defined (TARGET_MIPS64) + case RR_DMULT: + check_mips_64(ctx); + gen_muldiv(ctx, OPC_DMULT, rx, ry); + break; + case RR_DMULTU: + check_mips_64(ctx); + gen_muldiv(ctx, OPC_DMULTU, rx, ry); + break; + case RR_DDIV: + check_mips_64(ctx); + gen_muldiv(ctx, OPC_DDIV, rx, ry); + break; + case RR_DDIVU: + check_mips_64(ctx); + gen_muldiv(ctx, OPC_DDIVU, rx, ry); + break; +#endif + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case M16_OPC_EXTEND: + decode_extended_mips16_opc(env, ctx, is_branch); + n_bytes = 4; + break; +#if defined(TARGET_MIPS64) + case M16_OPC_I64: + funct = (ctx->opcode >> 8) & 0x7; + decode_i64_mips16(env, ctx, ry, funct, offset, 0); + break; +#endif + default: + generate_exception(ctx, EXCP_RI); + break; + } + + return n_bytes; +} + +/* microMIPS extension to MIPS32 */ + +/* microMIPS32 major opcodes */ + +enum { + POOL32A = 0x00, + POOL16A = 0x01, + LBU16 = 0x02, + MOVE16 = 0x03, + ADDI32 = 0x04, + LBU32 = 0x05, + SB32 = 0x06, + LB32 = 0x07, + + POOL32B = 0x08, + POOL16B = 0x09, + LHU16 = 0x0a, + ANDI16 = 0x0b, + ADDIU32 = 0x0c, + LHU32 = 0x0d, + SH32 = 0x0e, + LH32 = 0x0f, + + POOL32I = 0x10, + POOL16C = 0x11, + LWSP16 = 0x12, + POOL16D = 0x13, + ORI32 = 0x14, + POOL32F = 0x15, + POOL32S = 0x16, + DADDIU32 = 0x17, + + POOL32C = 0x18, + LWGP16 = 0x19, + LW16 = 0x1a, + POOL16E = 0x1b, + XORI32 = 0x1c, + JALS32 = 0x1d, + ADDIUPC = 0x1e, + POOL48A = 0x1f, + + /* 0x20 is reserved */ + RES_20 = 0x20, + POOL16F = 0x21, + SB16 = 0x22, + BEQZ16 = 0x23, + SLTI32 = 0x24, + BEQ32 = 0x25, + SWC132 = 0x26, + LWC132 = 0x27, + + /* 0x28 and 0x29 are reserved */ + RES_28 = 0x28, + RES_29 = 0x29, + SH16 = 0x2a, + BNEZ16 = 0x2b, + SLTIU32 = 0x2c, + BNE32 = 0x2d, + SDC132 = 0x2e, + LDC132 = 0x2f, + + /* 0x30 and 0x31 are reserved */ + RES_30 = 0x30, + RES_31 = 0x31, + SWSP16 = 0x32, + B16 = 0x33, + ANDI32 = 0x34, + J32 = 0x35, + SD32 = 0x36, + LD32 = 0x37, + + /* 0x38 and 0x39 are reserved */ + RES_38 = 0x38, + RES_39 = 0x39, + SW16 = 0x3a, + LI16 = 0x3b, + JALX32 = 0x3c, + JAL32 = 0x3d, + SW32 = 0x3e, + LW32 = 0x3f +}; + +/* POOL32A encoding of minor opcode field */ + +enum { + /* These opcodes are distinguished only by bits 9..6; those bits are + * what are recorded below. */ + SLL32 = 0x0, + SRL32 = 0x1, + SRA = 0x2, + ROTR = 0x3, + + SLLV = 0x0, + SRLV = 0x1, + SRAV = 0x2, + ROTRV = 0x3, + ADD = 0x4, + ADDU32 = 0x5, + SUB = 0x6, + SUBU32 = 0x7, + MUL = 0x8, + AND = 0x9, + OR32 = 0xa, + NOR = 0xb, + XOR32 = 0xc, + SLT = 0xd, + SLTU = 0xe, + + MOVN = 0x0, + MOVZ = 0x1, + LWXS = 0x4, + + /* The following can be distinguished by their lower 6 bits. */ + INS = 0x0c, + EXT = 0x2c, + POOL32AXF = 0x3c +}; + +/* POOL32AXF encoding of minor opcode field extension */ + +enum { + /* bits 11..6 */ + TEQ = 0x00, + TGE = 0x08, + TGEU = 0x10, + TLT = 0x20, + TLTU = 0x28, + TNE = 0x30, + + MFC0 = 0x03, + MTC0 = 0x0b, + + /* bits 13..12 for 0x01 */ + MFHI_ACC = 0x0, + MFLO_ACC = 0x1, + MTHI_ACC = 0x2, + MTLO_ACC = 0x3, + + /* bits 13..12 for 0x2a */ + MADD_ACC = 0x0, + MADDU_ACC = 0x1, + MSUB_ACC = 0x2, + MSUBU_ACC = 0x3, + + /* bits 13..12 for 0x32 */ + MULT_ACC = 0x0, + MULTU_ACC = 0x0, + + /* bits 15..12 for 0x2c */ + SEB = 0x2, + SEH = 0x3, + CLO = 0x4, + CLZ = 0x5, + RDHWR = 0x6, + WSBH = 0x7, + MULT = 0x8, + MULTU = 0x9, + DIV = 0xa, + DIVU = 0xb, + MADD = 0xc, + MADDU = 0xd, + MSUB = 0xe, + MSUBU = 0xf, + + /* bits 15..12 for 0x34 */ + MFC2 = 0x4, + MTC2 = 0x5, + MFHC2 = 0x8, + MTHC2 = 0x9, + CFC2 = 0xc, + CTC2 = 0xd, + + /* bits 15..12 for 0x3c */ + JALR = 0x0, + JR = 0x0, /* alias */ + JALR_HB = 0x1, + JALRS = 0x4, + JALRS_HB = 0x5, + + /* bits 15..12 for 0x05 */ + RDPGPR = 0xe, + WRPGPR = 0xf, + + /* bits 15..12 for 0x0d */ + TLBP = 0x0, + TLBR = 0x1, + TLBWI = 0x2, + TLBWR = 0x3, + WAIT = 0x9, + IRET = 0xd, + DERET = 0xe, + ERET = 0xf, + + /* bits 15..12 for 0x15 */ + DMT = 0x0, + DVPE = 0x1, + EMT = 0x2, + EVPE = 0x3, + + /* bits 15..12 for 0x1d */ + DI = 0x4, + EI = 0x5, + + /* bits 15..12 for 0x2d */ + SYNC = 0x6, + SYSCALL = 0x8, + SDBBP = 0xd, + + /* bits 15..12 for 0x35 */ + MFHI32 = 0x0, + MFLO32 = 0x1, + MTHI32 = 0x2, + MTLO32 = 0x3, +}; + +/* POOL32B encoding of minor opcode field (bits 15..12) */ + +enum { + LWC2 = 0x0, + LWP = 0x1, + LDP = 0x4, + LWM32 = 0x5, + CACHE = 0x6, + LDM = 0x7, + SWC2 = 0x8, + SWP = 0x9, + SDP = 0xc, + SWM32 = 0xd, + SDM = 0xf +}; + +/* POOL32C encoding of minor opcode field (bits 15..12) */ + +enum { + LWL = 0x0, + SWL = 0x8, + LWR = 0x1, + SWR = 0x9, + PREF = 0x2, + /* 0xa is reserved */ + LL = 0x3, + SC = 0xb, + LDL = 0x4, + SDL = 0xc, + LDR = 0x5, + SDR = 0xd, + /* 0x6 is reserved */ + LWU = 0xe, + LLD = 0x7, + SCD = 0xf +}; + +/* POOL32F encoding of minor opcode field (bits 5..0) */ + +enum { + /* These are the bit 7..6 values */ + ADD_FMT = 0x0, + MOVN_FMT = 0x0, + + SUB_FMT = 0x1, + MOVZ_FMT = 0x1, + + MUL_FMT = 0x2, + + DIV_FMT = 0x3, + + /* These are the bit 8..6 values */ + RSQRT2_FMT = 0x0, + MOVF_FMT = 0x0, + + LWXC1 = 0x1, + MOVT_FMT = 0x1, + + PLL_PS = 0x2, + SWXC1 = 0x2, + + PLU_PS = 0x3, + LDXC1 = 0x3, + + PUL_PS = 0x4, + SDXC1 = 0x4, + RECIP2_FMT = 0x4, + + PUU_PS = 0x5, + LUXC1 = 0x5, + + CVT_PS_S = 0x6, + SUXC1 = 0x6, + ADDR_PS = 0x6, + PREFX = 0x6, + + MULR_PS = 0x7, + + MADD_S = 0x01, + MADD_D = 0x09, + MADD_PS = 0x11, + ALNV_PS = 0x19, + MSUB_S = 0x21, + MSUB_D = 0x29, + MSUB_PS = 0x31, + + NMADD_S = 0x02, + NMADD_D = 0x0a, + NMADD_PS = 0x12, + NMSUB_S = 0x22, + NMSUB_D = 0x2a, + NMSUB_PS = 0x32, + + POOL32FXF = 0x3b, + + CABS_COND_FMT = 0x1c, /* MIPS3D */ + C_COND_FMT = 0x3c +}; + +/* POOL32Fxf encoding of minor opcode extension field */ + +enum { + CVT_L = 0x04, + RSQRT_FMT = 0x08, + FLOOR_L = 0x0c, + CVT_PW_PS = 0x1c, + CVT_W = 0x24, + SQRT_FMT = 0x28, + FLOOR_W = 0x2c, + CVT_PS_PW = 0x3c, + CFC1 = 0x40, + RECIP_FMT = 0x48, + CEIL_L = 0x4c, + CTC1 = 0x60, + CEIL_W = 0x6c, + MFC1 = 0x80, + CVT_S_PL = 0x84, + TRUNC_L = 0x8c, + MTC1 = 0xa0, + CVT_S_PU = 0xa4, + TRUNC_W = 0xac, + MFHC1 = 0xc0, + ROUND_L = 0xcc, + MTHC1 = 0xe0, + ROUND_W = 0xec, + + MOV_FMT = 0x01, + MOVF = 0x05, + ABS_FMT = 0x0d, + RSQRT1_FMT = 0x1d, + MOVT = 0x25, + NEG_FMT = 0x2d, + CVT_D = 0x4d, + RECIP1_FMT = 0x5d, + CVT_S = 0x6d +}; + +/* POOL32I encoding of minor opcode field (bits 25..21) */ + +enum { + BLTZ = 0x00, + BLTZAL = 0x01, + BGEZ = 0x02, + BGEZAL = 0x03, + BLEZ = 0x04, + BNEZC = 0x05, + BGTZ = 0x06, + BEQZC = 0x07, + TLTI = 0x08, + TGEI = 0x09, + TLTIU = 0x0a, + TGEIU = 0x0b, + TNEI = 0x0c, + LUI = 0x0d, + TEQI = 0x0e, + SYNCI = 0x10, + BLTZALS = 0x11, + BGEZALS = 0x13, + BC2F = 0x14, + BC2T = 0x15, + BPOSGE64 = 0x1a, + BPOSGE32 = 0x1b, + /* These overlap and are distinguished by bit16 of the instruction */ + BC1F = 0x1c, + BC1T = 0x1d, + BC1ANY2F = 0x1c, + BC1ANY2T = 0x1d, + BC1ANY4F = 0x1e, + BC1ANY4T = 0x1f +}; + +/* POOL16A encoding of minor opcode field */ + +enum { + ADDU16 = 0x0, + SUBU16 = 0x1 +}; + +/* POOL16B encoding of minor opcode field */ + +enum { + SLL16 = 0x0, + SRL16 = 0x1 +}; + +/* POOL16C encoding of minor opcode field */ + +enum { + NOT16 = 0x00, + XOR16 = 0x04, + AND16 = 0x08, + OR16 = 0x0c, + LWM16 = 0x10, + SWM16 = 0x14, + JR16 = 0x18, + JRC16 = 0x1a, + JALR16 = 0x1c, + JALR16S = 0x1e, + MFHI16 = 0x20, + MFLO16 = 0x24, + BREAK16 = 0x28, + SDBBP16 = 0x2c, + JRADDIUSP = 0x30 +}; + +/* POOL16D encoding of minor opcode field */ + +enum { + ADDIUS5 = 0x0, + ADDIUSP = 0x1 +}; + +/* POOL16E encoding of minor opcode field */ + +enum { + ADDIUR2 = 0x0, + ADDIUR1SP = 0x1 +}; + +static int mmreg (int r) +{ + static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; + + return map[r]; +} + +/* Used for 16-bit store instructions. */ +static int mmreg2 (int r) +{ + static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; + + return map[r]; +} + +#define uMIPS_RD(op) ((op >> 7) & 0x7) +#define uMIPS_RS(op) ((op >> 4) & 0x7) +#define uMIPS_RS2(op) uMIPS_RS(op) +#define uMIPS_RS1(op) ((op >> 1) & 0x7) +#define uMIPS_RD5(op) ((op >> 5) & 0x1f) +#define uMIPS_RS5(op) (op & 0x1f) + +/* Signed immediate */ +#define SIMM(op, start, width) \ + ((int32_t)(((op >> start) & ((~0U) >> (32-width))) \ + << (32-width)) \ + >> (32-width)) +/* Zero-extended immediate */ +#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32-width))) + +static void gen_addiur1sp (CPUState *env, DisasContext *ctx) +{ + int rd = mmreg(uMIPS_RD(ctx->opcode)); + + gen_arith_imm(env, ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2); +} + +static void gen_addiur2 (CPUState *env, DisasContext *ctx) +{ + static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 }; + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + + gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]); +} + +static void gen_addiusp (CPUState *env, DisasContext *ctx) +{ + int encoded = ZIMM(ctx->opcode, 1, 9); + int decoded; + + if (encoded <= 1) { + decoded = 256 + encoded; + } else if (encoded <= 255) { + decoded = encoded; + } else if (encoded <= 509) { + decoded = encoded - 512; + } else { + decoded = encoded - 768; + } + + gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, decoded << 2); +} + +static void gen_addius5 (CPUState *env, DisasContext *ctx) +{ + int imm = SIMM(ctx->opcode, 1, 4); + int rd = (ctx->opcode >> 5) & 0x1f; + + gen_arith_imm(env, ctx, OPC_ADDIU, rd, rd, imm); +} + +static void gen_andi16 (CPUState *env, DisasContext *ctx) +{ + static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16, + 31, 32, 63, 64, 255, 32768, 65535 }; + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + int encoded = ZIMM(ctx->opcode, 0, 4); + + gen_logic_imm(env, OPC_ANDI, rd, rs, decoded_imm[encoded]); +} + +static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, + int base, int16_t offset) +{ + TCGv t0, t1; + TCGv_i32 t2; + + if (ctx->hflags & MIPS_HFLAG_BMASK) { + generate_exception(ctx, EXCP_RI); + return; + } + + t0 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, base, offset); + + t1 = tcg_const_tl(reglist); + t2 = tcg_const_i32(ctx->mem_idx); + + save_cpu_state(ctx, 1); + switch (opc) { + case LWM32: + gen_helper_lwm(t0, t1, t2); + break; + case SWM32: + gen_helper_swm(t0, t1, t2); + break; +#ifdef TARGET_MIPS64 + case LDM: + gen_helper_ldm(t0, t1, t2); + break; + case SDM: + gen_helper_sdm(t0, t1, t2); + break; +#endif + } + MIPS_DEBUG("%s, %x, %d(%s)", opn, reglist, offset, regnames[base]); + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free_i32(t2); +} + + +static void gen_pool16c_insn (CPUState *env, DisasContext *ctx, int *is_branch) +{ + int rd = mmreg((ctx->opcode >> 3) & 0x7); + int rs = mmreg(ctx->opcode & 0x7); + int opc; + + switch (((ctx->opcode) >> 4) & 0x3f) { + case NOT16 + 0: + case NOT16 + 1: + case NOT16 + 2: + case NOT16 + 3: + gen_logic(env, OPC_NOR, rd, rs, 0); + break; + case XOR16 + 0: + case XOR16 + 1: + case XOR16 + 2: + case XOR16 + 3: + gen_logic(env, OPC_XOR, rd, rd, rs); + break; + case AND16 + 0: + case AND16 + 1: + case AND16 + 2: + case AND16 + 3: + gen_logic(env, OPC_AND, rd, rd, rs); + break; + case OR16 + 0: + case OR16 + 1: + case OR16 + 2: + case OR16 + 3: + gen_logic(env, OPC_OR, rd, rd, rs); + break; + case LWM16 + 0: + case LWM16 + 1: + case LWM16 + 2: + case LWM16 + 3: + { + static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; + int offset = ZIMM(ctx->opcode, 0, 4); + + gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3], + 29, offset << 2); + } + break; + case SWM16 + 0: + case SWM16 + 1: + case SWM16 + 2: + case SWM16 + 3: + { + static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; + int offset = ZIMM(ctx->opcode, 0, 4); + + gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3], + 29, offset << 2); + } + break; + case JR16 + 0: + case JR16 + 1: + { + int reg = ctx->opcode & 0x1f; + + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); + } + *is_branch = 1; + break; + case JRC16 + 0: + case JRC16 + 1: + { + int reg = ctx->opcode & 0x1f; + + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); + /* Let normal delay slot handling in our caller take us + to the branch target. */ + } + break; + case JALR16 + 0: + case JALR16 + 1: + opc = OPC_JALR; + goto do_jalr; + case JALR16S + 0: + case JALR16S + 1: + opc = OPC_JALRS; + do_jalr: + { + int reg = ctx->opcode & 0x1f; + + gen_compute_branch(ctx, opc, 2, reg, 31, 0); + } + *is_branch = 1; + break; + case MFHI16 + 0: + case MFHI16 + 1: + gen_HILO(ctx, OPC_MFHI, uMIPS_RS5(ctx->opcode)); + break; + case MFLO16 + 0: + case MFLO16 + 1: + gen_HILO(ctx, OPC_MFLO, uMIPS_RS5(ctx->opcode)); + break; + case BREAK16: + generate_exception(ctx, EXCP_BREAK); + break; + case SDBBP16: + /* XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(env, ctx, ISA_MIPS32); + if (!(ctx->hflags & MIPS_HFLAG_DM)) { + generate_exception(ctx, EXCP_DBp); + } else { + generate_exception(ctx, EXCP_DBp); + } + break; + case JRADDIUSP + 0: + case JRADDIUSP + 1: + { + int imm = ZIMM(ctx->opcode, 0, 5); + + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0); + gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm << 2); + /* Let normal delay slot handling in our caller take us + to the branch target. */ + } + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } +} + +static void gen_ldxs (DisasContext *ctx, int base, int index, int rd) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t0, base); + + if (index != 0) { + gen_load_gpr(t1, index); + tcg_gen_shli_tl(t1, t1, 2); + gen_op_addr_add(ctx, t0, t1, t0); + } + + save_cpu_state(ctx, 0); + op_ld_lw(t1, t0, ctx); + gen_store_gpr(t1, rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd, + int base, int16_t offset) +{ + const char *opn = "ldst_pair"; + TCGv t0, t1; + + if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31 || rd == base) { + generate_exception(ctx, EXCP_RI); + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, base, offset); + + switch (opc) { + case LWP: + save_cpu_state(ctx, 0); + op_ld_lw(t1, t0, ctx); + gen_store_gpr(t1, rd); + tcg_gen_movi_tl(t1, 4); + gen_op_addr_add(ctx, t0, t0, t1); + op_ld_lw(t1, t0, ctx); + gen_store_gpr(t1, rd+1); + opn = "lwp"; + break; + case SWP: + save_cpu_state(ctx, 0); + gen_load_gpr(t1, rd); + op_st_sw(t1, t0, ctx); + tcg_gen_movi_tl(t1, 4); + gen_op_addr_add(ctx, t0, t0, t1); + gen_load_gpr(t1, rd+1); + op_st_sw(t1, t0, ctx); + opn = "swp"; + break; +#ifdef TARGET_MIPS64 + case LDP: + save_cpu_state(ctx, 0); + op_ld_ld(t1, t0, ctx); + gen_store_gpr(t1, rd); + tcg_gen_movi_tl(t1, 8); + gen_op_addr_add(ctx, t0, t0, t1); + op_ld_ld(t1, t0, ctx); + gen_store_gpr(t1, rd+1); + opn = "ldp"; + break; + case SDP: + save_cpu_state(ctx, 0); + gen_load_gpr(t1, rd); + op_st_sd(t1, t0, ctx); + tcg_gen_movi_tl(t1, 8); + gen_op_addr_add(ctx, t0, t0, t1); + gen_load_gpr(t1, rd+1); + op_st_sd(t1, t0, ctx); + opn = "sdp"; + break; +#endif + } + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s, %s, %d(%s)", opn, regnames[rd], offset, regnames[base]); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_pool32axf (CPUState *env, DisasContext *ctx, int rt, int rs, + int *is_branch) +{ + int extension = (ctx->opcode >> 6) & 0x3f; + int minor = (ctx->opcode >> 12) & 0xf; + uint32_t mips32_op; + + switch (extension) { + case TEQ: + mips32_op = OPC_TEQ; + goto do_trap; + case TGE: + mips32_op = OPC_TGE; + goto do_trap; + case TGEU: + mips32_op = OPC_TGEU; + goto do_trap; + case TLT: + mips32_op = OPC_TLT; + goto do_trap; + case TLTU: + mips32_op = OPC_TLTU; + goto do_trap; + case TNE: + mips32_op = OPC_TNE; + do_trap: + gen_trap(ctx, mips32_op, rs, rt, -1); + break; +#ifndef CONFIG_USER_ONLY + case MFC0: + case MFC0 + 32: + if (rt == 0) { + /* Treat as NOP. */ + break; + } + gen_mfc0(env, ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7); + break; + case MTC0: + case MTC0 + 32: + { + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_mtc0(env, ctx, t0, rs, (ctx->opcode >> 11) & 0x7); + tcg_temp_free(t0); + } + break; +#endif + case 0x2c: + switch (minor) { + case SEB: + gen_bshfl(ctx, OPC_SEB, rs, rt); + break; + case SEH: + gen_bshfl(ctx, OPC_SEH, rs, rt); + break; + case CLO: + mips32_op = OPC_CLO; + goto do_cl; + case CLZ: + mips32_op = OPC_CLZ; + do_cl: + check_insn(env, ctx, ISA_MIPS32); + gen_cl(ctx, mips32_op, rt, rs); + break; + case RDHWR: + gen_rdhwr(env, ctx, rt, rs); + break; + case WSBH: + gen_bshfl(ctx, OPC_WSBH, rs, rt); + break; + case MULT: + mips32_op = OPC_MULT; + goto do_muldiv; + case MULTU: + mips32_op = OPC_MULTU; + goto do_muldiv; + case DIV: + mips32_op = OPC_DIV; + goto do_muldiv; + case DIVU: + mips32_op = OPC_DIVU; + goto do_muldiv; + case MADD: + mips32_op = OPC_MADD; + goto do_muldiv; + case MADDU: + mips32_op = OPC_MADDU; + goto do_muldiv; + case MSUB: + mips32_op = OPC_MSUB; + goto do_muldiv; + case MSUBU: + mips32_op = OPC_MSUBU; + do_muldiv: + check_insn(env, ctx, ISA_MIPS32); + gen_muldiv(ctx, mips32_op, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x34: + switch (minor) { + case MFC2: + case MTC2: + case MFHC2: + case MTHC2: + case CFC2: + case CTC2: + generate_exception_err(ctx, EXCP_CpU, 2); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x3c: + switch (minor) { + case JALR: + case JALR_HB: + gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0); + *is_branch = 1; + break; + case JALRS: + case JALRS_HB: + gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0); + *is_branch = 1; + break; + default: + goto pool32axf_invalid; + } + break; + case 0x05: + switch (minor) { + case RDPGPR: + check_insn(env, ctx, ISA_MIPS32R2); + gen_load_srsgpr(rt, rs); + break; + case WRPGPR: + check_insn(env, ctx, ISA_MIPS32R2); + gen_store_srsgpr(rt, rs); + break; + default: + goto pool32axf_invalid; + } + break; +#ifndef CONFIG_USER_ONLY + case 0x0d: + switch (minor) { + case TLBP: + mips32_op = OPC_TLBP; + goto do_cp0; + case TLBR: + mips32_op = OPC_TLBR; + goto do_cp0; + case TLBWI: + mips32_op = OPC_TLBWI; + goto do_cp0; + case TLBWR: + mips32_op = OPC_TLBWR; + goto do_cp0; + case WAIT: + mips32_op = OPC_WAIT; + goto do_cp0; + case DERET: + mips32_op = OPC_DERET; + goto do_cp0; + case ERET: + mips32_op = OPC_ERET; + do_cp0: + gen_cp0(env, ctx, mips32_op, rt, rs); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x1d: + switch (minor) { + case DI: + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_helper_di(t0); + gen_store_gpr(t0, rs); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + tcg_temp_free(t0); + } + break; + case EI: + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_helper_ei(t0); + gen_store_gpr(t0, rs); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + tcg_temp_free(t0); + } + break; + default: + goto pool32axf_invalid; + } + break; +#endif + case 0x2d: + switch (minor) { + case SYNC: + /* NOP */ + break; + case SYSCALL: + generate_exception(ctx, EXCP_SYSCALL); + ctx->bstate = BS_STOP; + break; + case SDBBP: + check_insn(env, ctx, ISA_MIPS32); + if (!(ctx->hflags & MIPS_HFLAG_DM)) { + generate_exception(ctx, EXCP_DBp); + } else { + generate_exception(ctx, EXCP_DBp); + } + break; + default: + goto pool32axf_invalid; + } + break; + case 0x35: + switch (minor) { + case MFHI32: + gen_HILO(ctx, OPC_MFHI, rs); + break; + case MFLO32: + gen_HILO(ctx, OPC_MFLO, rs); + break; + case MTHI32: + gen_HILO(ctx, OPC_MTHI, rs); + break; + case MTLO32: + gen_HILO(ctx, OPC_MTLO, rs); + break; + default: + goto pool32axf_invalid; + } + break; + default: + pool32axf_invalid: + MIPS_INVAL("pool32axf"); + generate_exception(ctx, EXCP_RI); + break; + } +} + +/* Values for microMIPS fmt field. Variable-width, depending on which + formats the instruction supports. */ + +enum { + FMT_SD_S = 0, + FMT_SD_D = 1, + + FMT_SDPS_S = 0, + FMT_SDPS_D = 1, + FMT_SDPS_PS = 2, + + FMT_SWL_S = 0, + FMT_SWL_W = 1, + FMT_SWL_L = 2, + + FMT_DWL_D = 0, + FMT_DWL_W = 1, + FMT_DWL_L = 2 +}; + +static void gen_pool32fxf (CPUState *env, DisasContext *ctx, int rt, int rs) +{ + int extension = (ctx->opcode >> 6) & 0x3ff; + uint32_t mips32_op; + +#define FLOAT_1BIT_FMT(opc, fmt) (fmt << 8) | opc +#define FLOAT_2BIT_FMT(opc, fmt) (fmt << 7) | opc +#define COND_FLOAT_MOV(opc, cond) (cond << 7) | opc + + switch (extension) { + case FLOAT_1BIT_FMT(CFC1, 0): + mips32_op = OPC_CFC1; + goto do_cp1; + case FLOAT_1BIT_FMT(CTC1, 0): + mips32_op = OPC_CTC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MFC1, 0): + mips32_op = OPC_MFC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MTC1, 0): + mips32_op = OPC_MTC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MFHC1, 0): + mips32_op = OPC_MFHC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MTHC1, 0): + mips32_op = OPC_MTHC1; + do_cp1: + gen_cp1(ctx, mips32_op, rt, rs); + break; + + /* Reciprocal square root */ + case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S): + mips32_op = OPC_RSQRT_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D): + mips32_op = OPC_RSQRT_D; + goto do_unaryfp; + + /* Square root */ + case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S): + mips32_op = OPC_SQRT_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D): + mips32_op = OPC_SQRT_D; + goto do_unaryfp; + + /* Reciprocal */ + case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S): + mips32_op = OPC_RECIP_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D): + mips32_op = OPC_RECIP_D; + goto do_unaryfp; + + /* Floor */ + case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S): + mips32_op = OPC_FLOOR_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D): + mips32_op = OPC_FLOOR_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S): + mips32_op = OPC_FLOOR_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D): + mips32_op = OPC_FLOOR_W_D; + goto do_unaryfp; + + /* Ceiling */ + case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S): + mips32_op = OPC_CEIL_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D): + mips32_op = OPC_CEIL_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S): + mips32_op = OPC_CEIL_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D): + mips32_op = OPC_CEIL_W_D; + goto do_unaryfp; + + /* Truncation */ + case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S): + mips32_op = OPC_TRUNC_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D): + mips32_op = OPC_TRUNC_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S): + mips32_op = OPC_TRUNC_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D): + mips32_op = OPC_TRUNC_W_D; + goto do_unaryfp; + + /* Round */ + case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S): + mips32_op = OPC_ROUND_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D): + mips32_op = OPC_ROUND_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S): + mips32_op = OPC_ROUND_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D): + mips32_op = OPC_ROUND_W_D; + goto do_unaryfp; + + /* Integer to floating-point conversion */ + case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S): + mips32_op = OPC_CVT_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D): + mips32_op = OPC_CVT_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S): + mips32_op = OPC_CVT_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D): + mips32_op = OPC_CVT_W_D; + goto do_unaryfp; + + /* Paired-foo conversions */ + case FLOAT_1BIT_FMT(CVT_S_PL, 0): + mips32_op = OPC_CVT_S_PL; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_S_PU, 0): + mips32_op = OPC_CVT_S_PU; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_PW_PS, 0): + mips32_op = OPC_CVT_PW_PS; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_PS_PW, 0): + mips32_op = OPC_CVT_PS_PW; + goto do_unaryfp; + + /* Floating-point moves */ + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S): + mips32_op = OPC_MOV_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D): + mips32_op = OPC_MOV_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS): + mips32_op = OPC_MOV_PS; + goto do_unaryfp; + + /* Absolute value */ + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S): + mips32_op = OPC_ABS_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D): + mips32_op = OPC_ABS_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS): + mips32_op = OPC_ABS_PS; + goto do_unaryfp; + + /* Negation */ + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S): + mips32_op = OPC_NEG_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D): + mips32_op = OPC_NEG_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS): + mips32_op = OPC_NEG_PS; + goto do_unaryfp; + + /* Reciprocal square root step */ + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S): + mips32_op = OPC_RSQRT1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D): + mips32_op = OPC_RSQRT1_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS): + mips32_op = OPC_RSQRT1_PS; + goto do_unaryfp; + + /* Reciprocal step */ + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S): + mips32_op = OPC_RECIP1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D): + mips32_op = OPC_RECIP1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS): + mips32_op = OPC_RECIP1_PS; + goto do_unaryfp; + + /* Conversions from double */ + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S): + mips32_op = OPC_CVT_D_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W): + mips32_op = OPC_CVT_D_W; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L): + mips32_op = OPC_CVT_D_L; + goto do_unaryfp; + + /* Conversions from single */ + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D): + mips32_op = OPC_CVT_S_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W): + mips32_op = OPC_CVT_S_W; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L): + mips32_op = OPC_CVT_S_L; + do_unaryfp: + gen_farith(ctx, mips32_op, -1, rs, rt, 0); + break; + + /* Conditional moves on floating-point codes */ + case COND_FLOAT_MOV(MOVT, 0): + case COND_FLOAT_MOV(MOVT, 1): + case COND_FLOAT_MOV(MOVT, 2): + case COND_FLOAT_MOV(MOVT, 3): + case COND_FLOAT_MOV(MOVT, 4): + case COND_FLOAT_MOV(MOVT, 5): + case COND_FLOAT_MOV(MOVT, 6): + case COND_FLOAT_MOV(MOVT, 7): + gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1); + break; + case COND_FLOAT_MOV(MOVF, 0): + case COND_FLOAT_MOV(MOVF, 1): + case COND_FLOAT_MOV(MOVF, 2): + case COND_FLOAT_MOV(MOVF, 3): + case COND_FLOAT_MOV(MOVF, 4): + case COND_FLOAT_MOV(MOVF, 5): + case COND_FLOAT_MOV(MOVF, 6): + case COND_FLOAT_MOV(MOVF, 7): + gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0); + break; + default: + MIPS_INVAL("pool32fxf"); + generate_exception(ctx, EXCP_RI); + break; + } +} + +static void decode_micromips32_opc (CPUState *env, DisasContext *ctx, + uint16_t insn_hw1, int *is_branch) +{ + int32_t offset; + uint16_t insn; + int rt, rs, rd, rr; + int16_t imm; + uint32_t op, minor, mips32_op; + uint32_t cond, fmt, cc; + + insn = lduw_code(ctx->pc + 2); + ctx->opcode = (ctx->opcode << 16) | insn; + + rt = (ctx->opcode >> 21) & 0x1f; + rs = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + rr = (ctx->opcode >> 6) & 0x1f; + imm = (int16_t) ctx->opcode; + + op = (ctx->opcode >> 26) & 0x3f; + switch (op) { + case POOL32A: + minor = ctx->opcode & 0x3f; + switch (minor) { + case 0x00: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + case SLL32: + mips32_op = OPC_SLL; + goto do_shifti; + case SRA: + mips32_op = OPC_SRA; + goto do_shifti; + case SRL32: + mips32_op = OPC_SRL; + goto do_shifti; + case ROTR: + mips32_op = OPC_ROTR; + do_shifti: + gen_shift_imm(env, ctx, mips32_op, rt, rs, rd); + break; + default: + goto pool32a_invalid; + } + break; + case 0x10: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + /* Arithmetic */ + case ADD: + mips32_op = OPC_ADD; + goto do_arith; + case ADDU32: + mips32_op = OPC_ADDU; + goto do_arith; + case SUB: + mips32_op = OPC_SUB; + goto do_arith; + case SUBU32: + mips32_op = OPC_SUBU; + goto do_arith; + case MUL: + mips32_op = OPC_MUL; + do_arith: + gen_arith(env, ctx, mips32_op, rd, rs, rt); + break; + /* Shifts */ + case SLLV: + mips32_op = OPC_SLLV; + goto do_shift; + case SRLV: + mips32_op = OPC_SRLV; + goto do_shift; + case SRAV: + mips32_op = OPC_SRAV; + goto do_shift; + case ROTRV: + mips32_op = OPC_ROTRV; + do_shift: + gen_shift(env, ctx, mips32_op, rd, rs, rt); + break; + /* Logical operations */ + case AND: + mips32_op = OPC_AND; + goto do_logic; + case OR32: + mips32_op = OPC_OR; + goto do_logic; + case NOR: + mips32_op = OPC_NOR; + goto do_logic; + case XOR32: + mips32_op = OPC_XOR; + do_logic: + gen_logic(env, mips32_op, rd, rs, rt); + break; + /* Set less than */ + case SLT: + mips32_op = OPC_SLT; + goto do_slt; + case SLTU: + mips32_op = OPC_SLTU; + do_slt: + gen_slt(env, mips32_op, rd, rs, rt); + break; + default: + goto pool32a_invalid; + } + break; + case 0x18: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + /* Conditional moves */ + case MOVN: + mips32_op = OPC_MOVN; + goto do_cmov; + case MOVZ: + mips32_op = OPC_MOVZ; + do_cmov: + gen_cond_move(env, mips32_op, rd, rs, rt); + break; + case LWXS: + gen_ldxs(ctx, rs, rt, rd); + break; + default: + goto pool32a_invalid; + } + break; + case INS: + gen_bitops(ctx, OPC_INS, rt, rs, rr, rd); + return; + case EXT: + gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd); + return; + case POOL32AXF: + gen_pool32axf(env, ctx, rt, rs, is_branch); + break; + case 0x07: + generate_exception(ctx, EXCP_BREAK); + break; + default: + pool32a_invalid: + MIPS_INVAL("pool32a"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case POOL32B: + minor = (ctx->opcode >> 12) & 0xf; + switch (minor) { + case CACHE: + /* Treat as no-op. */ + break; + case LWC2: + case SWC2: + /* COP2: Not implemented. */ + generate_exception_err(ctx, EXCP_CpU, 2); + break; + case LWP: + case SWP: +#ifdef TARGET_MIPS64 + case LDP: + case SDP: +#endif + gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; + case LWM32: + case SWM32: +#ifdef TARGET_MIPS64 + case LDM: + case SDM: +#endif + gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; + default: + MIPS_INVAL("pool32b"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case POOL32F: + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + minor = ctx->opcode & 0x3f; + check_cp1_enabled(ctx); + switch (minor) { + case ALNV_PS: + mips32_op = OPC_ALNV_PS; + goto do_madd; + case MADD_S: + mips32_op = OPC_MADD_S; + goto do_madd; + case MADD_D: + mips32_op = OPC_MADD_D; + goto do_madd; + case MADD_PS: + mips32_op = OPC_MADD_PS; + goto do_madd; + case MSUB_S: + mips32_op = OPC_MSUB_S; + goto do_madd; + case MSUB_D: + mips32_op = OPC_MSUB_D; + goto do_madd; + case MSUB_PS: + mips32_op = OPC_MSUB_PS; + goto do_madd; + case NMADD_S: + mips32_op = OPC_NMADD_S; + goto do_madd; + case NMADD_D: + mips32_op = OPC_NMADD_D; + goto do_madd; + case NMADD_PS: + mips32_op = OPC_NMADD_PS; + goto do_madd; + case NMSUB_S: + mips32_op = OPC_NMSUB_S; + goto do_madd; + case NMSUB_D: + mips32_op = OPC_NMSUB_D; + goto do_madd; + case NMSUB_PS: + mips32_op = OPC_NMSUB_PS; + do_madd: + gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt); + break; + case CABS_COND_FMT: + cond = (ctx->opcode >> 6) & 0xf; + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 10) & 0x3; + switch (fmt) { + case 0x0: + gen_cmpabs_s(ctx, cond, rt, rs, cc); + break; + case 0x1: + gen_cmpabs_d(ctx, cond, rt, rs, cc); + break; + case 0x2: + gen_cmpabs_ps(ctx, cond, rt, rs, cc); + break; + default: + goto pool32f_invalid; + } + break; + case C_COND_FMT: + cond = (ctx->opcode >> 6) & 0xf; + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 10) & 0x3; + switch (fmt) { + case 0x0: + gen_cmp_s(ctx, cond, rt, rs, cc); + break; + case 0x1: + gen_cmp_d(ctx, cond, rt, rs, cc); + break; + case 0x2: + gen_cmp_ps(ctx, cond, rt, rs, cc); + break; + default: + goto pool32f_invalid; + } + break; + case POOL32FXF: + gen_pool32fxf(env, ctx, rt, rs); + break; + case 0x00: + /* PLL foo */ + switch ((ctx->opcode >> 6) & 0x7) { + case PLL_PS: + mips32_op = OPC_PLL_PS; + goto do_ps; + case PLU_PS: + mips32_op = OPC_PLU_PS; + goto do_ps; + case PUL_PS: + mips32_op = OPC_PUL_PS; + goto do_ps; + case PUU_PS: + mips32_op = OPC_PUU_PS; + goto do_ps; + case CVT_PS_S: + mips32_op = OPC_CVT_PS_S; + do_ps: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x08: + /* [LS][WDU]XC1 */ + switch ((ctx->opcode >> 6) & 0x7) { + case LWXC1: + mips32_op = OPC_LWXC1; + goto do_ldst_cp1; + case SWXC1: + mips32_op = OPC_SWXC1; + goto do_ldst_cp1; + case LDXC1: + mips32_op = OPC_LDXC1; + goto do_ldst_cp1; + case SDXC1: + mips32_op = OPC_SDXC1; + goto do_ldst_cp1; + case LUXC1: + mips32_op = OPC_LUXC1; + goto do_ldst_cp1; + case SUXC1: + mips32_op = OPC_SUXC1; + do_ldst_cp1: + gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + break; + case 0x18: + /* 3D insns */ + fmt = (ctx->opcode >> 9) & 0x3; + switch ((ctx->opcode >> 6) & 0x7) { + case RSQRT2_FMT: + switch (fmt) { + case FMT_SDPS_S: + mips32_op = OPC_RSQRT2_S; + goto do_3d; + case FMT_SDPS_D: + mips32_op = OPC_RSQRT2_D; + goto do_3d; + case FMT_SDPS_PS: + mips32_op = OPC_RSQRT2_PS; + goto do_3d; + default: + goto pool32f_invalid; + } + break; + case RECIP2_FMT: + switch (fmt) { + case FMT_SDPS_S: + mips32_op = OPC_RECIP2_S; + goto do_3d; + case FMT_SDPS_D: + mips32_op = OPC_RECIP2_D; + goto do_3d; + case FMT_SDPS_PS: + mips32_op = OPC_RECIP2_PS; + goto do_3d; + default: + goto pool32f_invalid; + } + break; + case ADDR_PS: + mips32_op = OPC_ADDR_PS; + goto do_3d; + case MULR_PS: + mips32_op = OPC_MULR_PS; + do_3d: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x20: + /* MOV[FT].fmt and PREFX */ + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 9) & 0x3; + switch ((ctx->opcode >> 6) & 0x7) { + case MOVF_FMT: + switch (fmt) { + case FMT_SDPS_S: + gen_movcf_s(rs, rt, cc, 0); + break; + case FMT_SDPS_D: + gen_movcf_d(ctx, rs, rt, cc, 0); + break; + case FMT_SDPS_PS: + gen_movcf_ps(rs, rt, cc, 0); + break; + default: + goto pool32f_invalid; + } + break; + case MOVT_FMT: + switch (fmt) { + case FMT_SDPS_S: + gen_movcf_s(rs, rt, cc, 1); + break; + case FMT_SDPS_D: + gen_movcf_d(ctx, rs, rt, cc, 1); + break; + case FMT_SDPS_PS: + gen_movcf_ps(rs, rt, cc, 1); + break; + default: + goto pool32f_invalid; + } + break; + case PREFX: + break; + default: + goto pool32f_invalid; + } + break; +#define FINSN_3ARG_SDPS(prfx) \ + switch ((ctx->opcode >> 8) & 0x3) { \ + case FMT_SDPS_S: \ + mips32_op = OPC_##prfx##_S; \ + goto do_fpop; \ + case FMT_SDPS_D: \ + mips32_op = OPC_##prfx##_D; \ + goto do_fpop; \ + case FMT_SDPS_PS: \ + mips32_op = OPC_##prfx##_PS; \ + goto do_fpop; \ + default: \ + goto pool32f_invalid; \ + } + case 0x30: + /* regular FP ops */ + switch ((ctx->opcode >> 6) & 0x3) { + case ADD_FMT: + FINSN_3ARG_SDPS(ADD); + break; + case SUB_FMT: + FINSN_3ARG_SDPS(SUB); + break; + case MUL_FMT: + FINSN_3ARG_SDPS(MUL); + break; + case DIV_FMT: + fmt = (ctx->opcode >> 8) & 0x3; + if (fmt == 1) { + mips32_op = OPC_DIV_D; + } else if (fmt == 0) { + mips32_op = OPC_DIV_S; + } else { + goto pool32f_invalid; + } + goto do_fpop; + default: + goto pool32f_invalid; + } + break; + case 0x38: + /* cmovs */ + switch ((ctx->opcode >> 6) & 0x3) { + case MOVN_FMT: + FINSN_3ARG_SDPS(MOVN); + break; + case MOVZ_FMT: + FINSN_3ARG_SDPS(MOVZ); + break; + default: + goto pool32f_invalid; + } + break; + do_fpop: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + pool32f_invalid: + MIPS_INVAL("pool32f"); + generate_exception(ctx, EXCP_RI); + break; + } + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } + break; + case POOL32I: + minor = (ctx->opcode >> 21) & 0x1f; + switch (minor) { + case BLTZ: + mips32_op = OPC_BLTZ; + goto do_branch; + case BLTZAL: + mips32_op = OPC_BLTZAL; + goto do_branch; + case BLTZALS: + mips32_op = OPC_BLTZALS; + goto do_branch; + case BGEZ: + mips32_op = OPC_BGEZ; + goto do_branch; + case BGEZAL: + mips32_op = OPC_BGEZAL; + goto do_branch; + case BGEZALS: + mips32_op = OPC_BGEZALS; + goto do_branch; + case BLEZ: + mips32_op = OPC_BLEZ; + goto do_branch; + case BGTZ: + mips32_op = OPC_BGTZ; + do_branch: + gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1); + *is_branch = 1; + break; + + /* Traps */ + case TLTI: + mips32_op = OPC_TLTI; + goto do_trapi; + case TGEI: + mips32_op = OPC_TGEI; + goto do_trapi; + case TLTIU: + mips32_op = OPC_TLTIU; + goto do_trapi; + case TGEIU: + mips32_op = OPC_TGEIU; + goto do_trapi; + case TNEI: + mips32_op = OPC_TNEI; + goto do_trapi; + case TEQI: + mips32_op = OPC_TEQI; + do_trapi: + gen_trap(ctx, mips32_op, rs, -1, imm); + break; + + case BNEZC: + case BEQZC: + gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, + 4, rs, 0, imm << 1); + /* Compact branches don't have a delay slot, so just let + the normal delay slot handling take us to the branch + target. */ + break; + case LUI: + gen_logic_imm(env, OPC_LUI, rs, -1, imm); + break; + case SYNCI: + break; + case BC2F: + case BC2T: + /* COP2: Not implemented. */ + generate_exception_err(ctx, EXCP_CpU, 2); + break; + case BC1F: + mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F; + goto do_cp1branch; + case BC1T: + mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T; + goto do_cp1branch; + case BC1ANY4F: + mips32_op = OPC_BC1FANY4; + goto do_cp1mips3d; + case BC1ANY4T: + mips32_op = OPC_BC1TANY4; + do_cp1mips3d: + check_cop1x(ctx); + check_insn(env, ctx, ASE_MIPS3D); + /* Fall through */ + do_cp1branch: + gen_compute_branch1(env, ctx, mips32_op, + (ctx->opcode >> 18) & 0x7, imm << 1); + *is_branch = 1; + break; + case BPOSGE64: + case BPOSGE32: + /* MIPS DSP: not implemented */ + /* Fall through */ + default: + MIPS_INVAL("pool32i"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case POOL32C: + minor = (ctx->opcode >> 12) & 0xf; + switch (minor) { + case LWL: + mips32_op = OPC_LWL; + goto do_ld_lr; + case SWL: + mips32_op = OPC_SWL; + goto do_st_lr; + case LWR: + mips32_op = OPC_LWR; + goto do_ld_lr; + case SWR: + mips32_op = OPC_SWR; + goto do_st_lr; +#if defined(TARGET_MIPS64) + case LDL: + mips32_op = OPC_LDL; + goto do_ld_lr; + case SDL: + mips32_op = OPC_SDL; + goto do_st_lr; + case LDR: + mips32_op = OPC_LDR; + goto do_ld_lr; + case SDR: + mips32_op = OPC_SDR; + goto do_st_lr; + case LWU: + mips32_op = OPC_LWU; + goto do_ld_lr; + case LLD: + mips32_op = OPC_LLD; + goto do_ld_lr; +#endif + case LL: + mips32_op = OPC_LL; + goto do_ld_lr; + do_ld_lr: + gen_ld(env, ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; + do_st_lr: + gen_st(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; + case SC: + gen_st_cond(ctx, OPC_SC, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; +#if defined(TARGET_MIPS64) + case SCD: + gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; +#endif + case PREF: + /* Treat as no-op */ + break; + default: + MIPS_INVAL("pool32c"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case ADDI32: + mips32_op = OPC_ADDI; + goto do_addi; + case ADDIU32: + mips32_op = OPC_ADDIU; + do_addi: + gen_arith_imm(env, ctx, mips32_op, rt, rs, imm); + break; + + /* Logical operations */ + case ORI32: + mips32_op = OPC_ORI; + goto do_logici; + case XORI32: + mips32_op = OPC_XORI; + goto do_logici; + case ANDI32: + mips32_op = OPC_ANDI; + do_logici: + gen_logic_imm(env, mips32_op, rt, rs, imm); + break; + + /* Set less than immediate */ + case SLTI32: + mips32_op = OPC_SLTI; + goto do_slti; + case SLTIU32: + mips32_op = OPC_SLTIU; + do_slti: + gen_slt_imm(env, mips32_op, rt, rs, imm); + break; + case JALX32: + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; + gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset); + *is_branch = 1; + break; + case JALS32: + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; + gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset); + *is_branch = 1; + break; + case BEQ32: + gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1); + *is_branch = 1; + break; + case BNE32: + gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1); + *is_branch = 1; + break; + case J32: + gen_compute_branch(ctx, OPC_J, 4, rt, rs, + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); + *is_branch = 1; + break; + case JAL32: + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); + *is_branch = 1; + break; + /* Floating point (COP1) */ + case LWC132: + mips32_op = OPC_LWC1; + goto do_cop1; + case LDC132: + mips32_op = OPC_LDC1; + goto do_cop1; + case SWC132: + mips32_op = OPC_SWC1; + goto do_cop1; + case SDC132: + mips32_op = OPC_SDC1; + do_cop1: + gen_cop1_ldst(env, ctx, mips32_op, rt, rs, imm); + break; + case ADDIUPC: + { + int reg = mmreg(ZIMM(ctx->opcode, 23, 3)); + int offset = SIMM(ctx->opcode, 0, 23) << 2; + + gen_addiupc(ctx, reg, offset, 0, 0); + } + break; + /* Loads and stores */ + case LB32: + mips32_op = OPC_LB; + goto do_ld; + case LBU32: + mips32_op = OPC_LBU; + goto do_ld; + case LH32: + mips32_op = OPC_LH; + goto do_ld; + case LHU32: + mips32_op = OPC_LHU; + goto do_ld; + case LW32: + mips32_op = OPC_LW; + goto do_ld; +#ifdef TARGET_MIPS64 + case LD32: + mips32_op = OPC_LD; + goto do_ld; + case SD32: + mips32_op = OPC_SD; + goto do_st; +#endif + case SB32: + mips32_op = OPC_SB; + goto do_st; + case SH32: + mips32_op = OPC_SH; + goto do_st; + case SW32: + mips32_op = OPC_SW; + goto do_st; + do_ld: + gen_ld(env, ctx, mips32_op, rt, rs, imm); + break; + do_st: + gen_st(ctx, mips32_op, rt, rs, imm); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } +} + +static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branch) +{ + uint32_t op; + + /* make sure instructions are on a halfword boundary */ + if (ctx->pc & 0x1) { + env->CP0_BadVAddr = ctx->pc; + generate_exception(ctx, EXCP_AdEL); + ctx->bstate = BS_STOP; + return 2; + } + + op = (ctx->opcode >> 10) & 0x3f; + /* Enforce properly-sized instructions in a delay slot */ + if (ctx->hflags & MIPS_HFLAG_BMASK) { + int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT; + + switch (op) { + case POOL32A: + case POOL32B: + case POOL32I: + case POOL32C: + case ADDI32: + case ADDIU32: + case ORI32: + case XORI32: + case SLTI32: + case SLTIU32: + case ANDI32: + case JALX32: + case LBU32: + case LHU32: + case POOL32F: + case JALS32: + case BEQ32: + case BNE32: + case J32: + case JAL32: + case SB32: + case SH32: + case POOL32S: + case ADDIUPC: + case SWC132: + case SDC132: + case SD32: + case SW32: + case LB32: + case LH32: + case DADDIU32: + case POOL48A: /* ??? */ + case LWC132: + case LDC132: + case LD32: + case LW32: + if (bits & MIPS_HFLAG_BDS16) { + generate_exception(ctx, EXCP_RI); + /* Just stop translation; the user is confused. */ + ctx->bstate = BS_STOP; + return 2; + } + break; + case POOL16A: + case POOL16B: + case POOL16C: + case LWGP16: + case POOL16F: + case LBU16: + case LHU16: + case LWSP16: + case LW16: + case SB16: + case SH16: + case SWSP16: + case SW16: + case MOVE16: + case ANDI16: + case POOL16D: + case POOL16E: + case BEQZ16: + case BNEZ16: + case B16: + case LI16: + if (bits & MIPS_HFLAG_BDS32) { + generate_exception(ctx, EXCP_RI); + /* Just stop translation; the user is confused. */ + ctx->bstate = BS_STOP; + return 2; + } + break; + default: + break; + } + } + switch (op) { + case POOL16A: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs1 = mmreg(uMIPS_RS1(ctx->opcode)); + int rs2 = mmreg(uMIPS_RS2(ctx->opcode)); + uint32_t opc = 0; + + switch (ctx->opcode & 0x1) { + case ADDU16: + opc = OPC_ADDU; + break; + case SUBU16: + opc = OPC_SUBU; + break; + } + + gen_arith(env, ctx, opc, rd, rs1, rs2); + } + break; + case POOL16B: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + int amount = (ctx->opcode >> 1) & 0x7; + uint32_t opc = 0; + amount = amount == 0 ? 8 : amount; + + switch (ctx->opcode & 0x1) { + case SLL16: + opc = OPC_SLL; + break; + case SRL16: + opc = OPC_SRL; + break; + } + + gen_shift_imm(env, ctx, opc, rd, rs, amount); + } + break; + case POOL16C: + gen_pool16c_insn(env, ctx, is_branch); + break; + case LWGP16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = 28; /* GP */ + int16_t offset = SIMM(ctx->opcode, 0, 7) << 2; + + gen_ld(env, ctx, OPC_LW, rd, rb, offset); + } + break; + case POOL16F: + if (ctx->opcode & 1) { + generate_exception(ctx, EXCP_RI); + } else { + /* MOVEP */ + int enc_dest = uMIPS_RD(ctx->opcode); + int enc_rt = uMIPS_RS2(ctx->opcode); + int enc_rs = uMIPS_RS1(ctx->opcode); + int rd, rs, re, rt; + static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 }; + static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 }; + static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 }; + + rd = rd_enc[enc_dest]; + re = re_enc[enc_dest]; + rs = rs_rt_enc[enc_rs]; + rt = rs_rt_enc[enc_rt]; + + gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0); + gen_arith_imm(env, ctx, OPC_ADDIU, re, rt, 0); + } + break; + case LBU16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4); + offset = (offset == 0xf ? -1 : offset); + + gen_ld(env, ctx, OPC_LBU, rd, rb, offset); + } + break; + case LHU16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; + + gen_ld(env, ctx, OPC_LHU, rd, rb, offset); + } + break; + case LWSP16: + { + int rd = (ctx->opcode >> 5) & 0x1f; + int rb = 29; /* SP */ + int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; + + gen_ld(env, ctx, OPC_LW, rd, rb, offset); + } + break; + case LW16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; + + gen_ld(env, ctx, OPC_LW, rd, rb, offset); + } + break; + case SB16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4); + + gen_st(ctx, OPC_SB, rd, rb, offset); + } + break; + case SH16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; + + gen_st(ctx, OPC_SH, rd, rb, offset); + } + break; + case SWSP16: + { + int rd = (ctx->opcode >> 5) & 0x1f; + int rb = 29; /* SP */ + int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; + + gen_st(ctx, OPC_SW, rd, rb, offset); + } + break; + case SW16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; + + gen_st(ctx, OPC_SW, rd, rb, offset); + } + break; + case MOVE16: + { + int rd = uMIPS_RD5(ctx->opcode); + int rs = uMIPS_RS5(ctx->opcode); + + gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0); + } + break; + case ANDI16: + gen_andi16(env, ctx); + break; + case POOL16D: + switch (ctx->opcode & 0x1) { + case ADDIUS5: + gen_addius5(env, ctx); + break; + case ADDIUSP: + gen_addiusp(env, ctx); + break; + } + break; + case POOL16E: + switch (ctx->opcode & 0x1) { + case ADDIUR2: + gen_addiur2(env, ctx); + break; + case ADDIUR1SP: + gen_addiur1sp(env, ctx); + break; + } + break; + case B16: + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, + SIMM(ctx->opcode, 0, 10) << 1); + *is_branch = 1; + break; + case BNEZ16: + case BEQZ16: + gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, + mmreg(uMIPS_RD(ctx->opcode)), + 0, SIMM(ctx->opcode, 0, 7) << 1); + *is_branch = 1; + break; + case LI16: + { + int reg = mmreg(uMIPS_RD(ctx->opcode)); + int imm = ZIMM(ctx->opcode, 0, 7); + + imm = (imm == 0x7f ? -1 : imm); + tcg_gen_movi_tl(cpu_gpr[reg], imm); + } + break; + case RES_20: + case RES_28: + case RES_29: + case RES_30: + case RES_31: + case RES_38: + case RES_39: + generate_exception(ctx, EXCP_RI); + break; + default: + decode_micromips32_opc (env, ctx, op, is_branch); + return 4; + } + + return 2; +} + /* SmartMIPS extension to MIPS32 */ #if defined(TARGET_MIPS64) @@ -6057,7 +11689,7 @@ static void gen_flt3_arith (DisasContext #endif -static void decode_opc (CPUState *env, DisasContext *ctx) +static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch) { int32_t offset; int rs, rt, rd, sa; @@ -6071,16 +11703,20 @@ static void decode_opc (CPUState *env, D return; } - if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { - int l1; - /* Handle blikely not taken case */ + /* Handle blikely not taken case */ + if ((ctx->hflags & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BL) { + int l1 = gen_new_label(); + MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4); - l1 = gen_new_label(); - gen_op_jnz_T2(l1); - gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); + tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1); + tcg_gen_movi_i32(hflags, ctx->hflags & ~MIPS_HFLAG_BMASK); gen_goto_tb(ctx, 1, ctx->pc + 4); gen_set_label(l1); } + + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) + tcg_gen_debug_insn_start(ctx->pc); + op = MASK_OP_MAJOR(ctx->opcode); rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; @@ -6091,18 +11727,65 @@ static void decode_opc (CPUState *env, D case OPC_SPECIAL: op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { - case OPC_SLL: /* Arithmetic with immediate */ - case OPC_SRL ... OPC_SRA: - gen_arith_imm(env, ctx, op1, rd, rt, sa); + case OPC_SLL: /* Shift with immediate */ + case OPC_SRA: + gen_shift_imm(env, ctx, op1, rd, rt, sa); break; - case OPC_MOVZ ... OPC_MOVN: - check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); - case OPC_SLLV: /* Arithmetic */ - case OPC_SRLV ... OPC_SRAV: - case OPC_ADD ... OPC_NOR: - case OPC_SLT ... OPC_SLTU: + case OPC_SRL: + switch ((ctx->opcode >> 21) & 0x1f) { + case 1: + /* rotr is decoded as srl on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + op1 = OPC_ROTR; + } + /* Fallthrough */ + case 0: + gen_shift_imm(env, ctx, op1, rd, rt, sa); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_MOVN: /* Conditional move */ + case OPC_MOVZ: + check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32 | + INSN_LOONGSON2E | INSN_LOONGSON2F); + gen_cond_move(env, op1, rd, rs, rt); + break; + case OPC_ADD ... OPC_SUBU: gen_arith(env, ctx, op1, rd, rs, rt); break; + case OPC_SLLV: /* Shifts */ + case OPC_SRAV: + gen_shift(env, ctx, op1, rd, rs, rt); + break; + case OPC_SRLV: + switch ((ctx->opcode >> 6) & 0x1f) { + case 1: + /* rotrv is decoded as srlv on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + op1 = OPC_ROTRV; + } + /* Fallthrough */ + case 0: + gen_shift(env, ctx, op1, rd, rs, rt); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_SLT: /* Set on less than */ + case OPC_SLTU: + gen_slt(env, op1, rd, rs, rt); + break; + case OPC_AND: /* Logic*/ + case OPC_OR: + case OPC_NOR: + case OPC_XOR: + gen_logic(env, op1, rd, rs, rt); + break; case OPC_MULT ... OPC_DIVU: if (sa) { check_insn(env, ctx, INSN_VR54XX); @@ -6112,8 +11795,9 @@ static void decode_opc (CPUState *env, D gen_muldiv(ctx, op1, rs, rt); break; case OPC_JR ... OPC_JALR: - gen_compute_branch(ctx, op1, rs, rd, sa); - return; + gen_compute_branch(ctx, op1, 4, rs, rd, sa); + *is_branch = 1; + break; case OPC_TGE ... OPC_TEQ: /* Traps */ case OPC_TNE: gen_trap(ctx, op1, rs, rt, -1); @@ -6131,11 +11815,12 @@ static void decode_opc (CPUState *env, D MIPS_INVAL("PMON / selsl"); generate_exception(ctx, EXCP_RI); #else - gen_op_pmon(sa); + gen_helper_0i(pmon, sa); #endif break; case OPC_SYSCALL: generate_exception(ctx, EXCP_SYSCALL); + ctx->bstate = BS_STOP; break; case OPC_BREAK: generate_exception(ctx, EXCP_BREAK); @@ -6157,7 +11842,6 @@ static void decode_opc (CPUState *env, D case OPC_MOVCI: check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); if (env->CP0_Config1 & (1 << CP0C1_FP)) { - save_cpu_state(ctx, 1); check_cp1_enabled(ctx); gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, (ctx->opcode >> 16) & 1); @@ -6169,20 +11853,78 @@ static void decode_opc (CPUState *env, D #if defined(TARGET_MIPS64) /* MIPS64 specific opcodes */ case OPC_DSLL: - case OPC_DSRL ... OPC_DSRA: + case OPC_DSRA: case OPC_DSLL32: - case OPC_DSRL32 ... OPC_DSRA32: + case OPC_DSRA32: check_insn(env, ctx, ISA_MIPS3); check_mips_64(ctx); - gen_arith_imm(env, ctx, op1, rd, rt, sa); + gen_shift_imm(env, ctx, op1, rd, rt, sa); + break; + case OPC_DSRL: + switch ((ctx->opcode >> 21) & 0x1f) { + case 1: + /* drotr is decoded as dsrl on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + op1 = OPC_DROTR; + } + /* Fallthrough */ + case 0: + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift_imm(env, ctx, op1, rd, rt, sa); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_DSRL32: + switch ((ctx->opcode >> 21) & 0x1f) { + case 1: + /* drotr32 is decoded as dsrl32 on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + op1 = OPC_DROTR32; + } + /* Fallthrough */ + case 0: + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift_imm(env, ctx, op1, rd, rt, sa); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } break; - case OPC_DSLLV: - case OPC_DSRLV ... OPC_DSRAV: case OPC_DADD ... OPC_DSUBU: check_insn(env, ctx, ISA_MIPS3); check_mips_64(ctx); gen_arith(env, ctx, op1, rd, rs, rt); break; + case OPC_DSLLV: + case OPC_DSRAV: + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift(env, ctx, op1, rd, rs, rt); + break; + case OPC_DSRLV: + switch ((ctx->opcode >> 6) & 0x1f) { + case 1: + /* drotrv is decoded as dsrlv on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + op1 = OPC_DROTRV; + } + /* Fallthrough */ + case 0: + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift(env, ctx, op1, rd, rs, rt); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + break; case OPC_DMULT ... OPC_DDIVU: check_insn(env, ctx, ISA_MIPS3); check_mips_64(ctx); @@ -6206,7 +11948,8 @@ static void decode_opc (CPUState *env, D case OPC_MUL: gen_arith(env, ctx, op1, rd, rs, rt); break; - case OPC_CLZ ... OPC_CLO: + case OPC_CLO: + case OPC_CLZ: check_insn(env, ctx, ISA_MIPS32); gen_cl(ctx, op1, rd, rs); break; @@ -6222,12 +11965,31 @@ static void decode_opc (CPUState *env, D } /* Treat as NOP. */ break; + case OPC_DIV_G_2F: + case OPC_DIVU_G_2F: + case OPC_MULT_G_2F: + case OPC_MULTU_G_2F: + case OPC_MOD_G_2F: + case OPC_MODU_G_2F: + check_insn(env, ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; #if defined(TARGET_MIPS64) - case OPC_DCLZ ... OPC_DCLO: + case OPC_DCLO: + case OPC_DCLZ: check_insn(env, ctx, ISA_MIPS64); check_mips_64(ctx); gen_cl(ctx, op1, rd, rs); break; + case OPC_DMULT_G_2F: + case OPC_DMULTU_G_2F: + case OPC_DDIV_G_2F: + case OPC_DDIVU_G_2F: + case OPC_DMOD_G_2F: + case OPC_DMODU_G_2F: + check_insn(env, ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; #endif default: /* Invalid */ MIPS_INVAL("special2"); @@ -6236,78 +11998,51 @@ static void decode_opc (CPUState *env, D } break; case OPC_SPECIAL3: - op1 = MASK_SPECIAL3(ctx->opcode); - switch (op1) { - case OPC_EXT: - case OPC_INS: - check_insn(env, ctx, ISA_MIPS32R2); - gen_bitops(ctx, op1, rt, rs, sa, rd); - break; - case OPC_BSHFL: - check_insn(env, ctx, ISA_MIPS32R2); - op2 = MASK_BSHFL(ctx->opcode); - switch (op2) { - case OPC_WSBH: - GEN_LOAD_REG_T1(rt); - gen_op_wsbh(); - break; - case OPC_SEB: - GEN_LOAD_REG_T1(rt); - gen_op_seb(); - break; - case OPC_SEH: - GEN_LOAD_REG_T1(rt); - gen_op_seh(); - break; - default: /* Invalid */ - MIPS_INVAL("bshfl"); - generate_exception(ctx, EXCP_RI); - break; - } - GEN_STORE_T0_REG(rd); + op1 = MASK_SPECIAL3(ctx->opcode); + switch (op1) { + case OPC_EXT: + case OPC_INS: + check_insn(env, ctx, ISA_MIPS32R2); + gen_bitops(ctx, op1, rt, rs, sa, rd); break; - case OPC_RDHWR: + case OPC_BSHFL: check_insn(env, ctx, ISA_MIPS32R2); - switch (rd) { - case 0: - save_cpu_state(ctx, 1); - gen_op_rdhwr_cpunum(); - break; - case 1: - save_cpu_state(ctx, 1); - gen_op_rdhwr_synci_step(); - break; - case 2: - save_cpu_state(ctx, 1); - gen_op_rdhwr_cc(); - break; - case 3: - save_cpu_state(ctx, 1); - gen_op_rdhwr_ccres(); - break; - case 29: -#if defined (CONFIG_USER_ONLY) - gen_op_tls_value(); - break; -#endif - default: /* Invalid */ - MIPS_INVAL("rdhwr"); - generate_exception(ctx, EXCP_RI); - break; - } - GEN_STORE_T0_REG(rt); + op2 = MASK_BSHFL(ctx->opcode); + gen_bshfl(ctx, op2, rt, rd); + break; + case OPC_RDHWR: + gen_rdhwr(env, ctx, rt, rd); break; case OPC_FORK: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_T0(rt); - GEN_LOAD_REG_T1(rs); - gen_op_fork(); + { + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + gen_helper_fork(t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } break; case OPC_YIELD: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_T0(rs); - gen_op_yield(); - GEN_STORE_T0_REG(rd); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_load_gpr(t0, rs); + gen_helper_yield(t0, t0); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } + break; + case OPC_DIV_G_2E ... OPC_DIVU_G_2E: + case OPC_MULT_G_2E ... OPC_MULTU_G_2E: + case OPC_MOD_G_2E ... OPC_MODU_G_2E: + check_insn(env, ctx, INSN_LOONGSON2E); + gen_loongson_integer(ctx, op1, rd, rs, rt); break; #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: @@ -6320,21 +12055,13 @@ static void decode_opc (CPUState *env, D check_insn(env, ctx, ISA_MIPS64R2); check_mips_64(ctx); op2 = MASK_DBSHFL(ctx->opcode); - switch (op2) { - case OPC_DSBH: - GEN_LOAD_REG_T1(rt); - gen_op_dsbh(); - break; - case OPC_DSHD: - GEN_LOAD_REG_T1(rt); - gen_op_dshd(); - break; - default: /* Invalid */ - MIPS_INVAL("dbshfl"); - generate_exception(ctx, EXCP_RI); - break; - } - GEN_STORE_T0_REG(rd); + gen_bshfl(ctx, op2, rt, rd); + break; + case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: + case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: + case OPC_DMOD_G_2E ... OPC_DMODU_G_2E: + check_insn(env, ctx, INSN_LOONGSON2E); + gen_loongson_integer(ctx, op1, rd, rs, rt); break; #endif default: /* Invalid */ @@ -6348,8 +12075,9 @@ static void decode_opc (CPUState *env, D switch (op1) { case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */ case OPC_BLTZAL ... OPC_BGEZALL: - gen_compute_branch(ctx, op1, rs, -1, imm << 2); - return; + gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); + *is_branch = 1; + break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TNEI: gen_trap(ctx, op1, rs, -1, imm); @@ -6376,60 +12104,74 @@ static void decode_opc (CPUState *env, D case OPC_DMFC0: case OPC_DMTC0: #endif +#ifndef CONFIG_USER_ONLY gen_cp0(env, ctx, op1, rt, rd); +#endif /* !CONFIG_USER_ONLY */ break; case OPC_C0_FIRST ... OPC_C0_LAST: +#ifndef CONFIG_USER_ONLY gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); +#endif /* !CONFIG_USER_ONLY */ break; case OPC_MFMC0: - op2 = MASK_MFMC0(ctx->opcode); - switch (op2) { - case OPC_DMT: - check_insn(env, ctx, ASE_MT); - gen_op_dmt(); - break; - case OPC_EMT: - check_insn(env, ctx, ASE_MT); - gen_op_emt(); - break; - case OPC_DVPE: - check_insn(env, ctx, ASE_MT); - gen_op_dvpe(); - break; - case OPC_EVPE: - check_insn(env, ctx, ASE_MT); - gen_op_evpe(); - break; - case OPC_DI: - check_insn(env, ctx, ISA_MIPS32R2); - save_cpu_state(ctx, 1); - gen_op_di(); - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; - break; - case OPC_EI: - check_insn(env, ctx, ISA_MIPS32R2); - save_cpu_state(ctx, 1); - gen_op_ei(); - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; - break; - default: /* Invalid */ - MIPS_INVAL("mfmc0"); - generate_exception(ctx, EXCP_RI); - break; +#ifndef CONFIG_USER_ONLY + { + TCGv t0 = tcg_temp_new(); + + op2 = MASK_MFMC0(ctx->opcode); + switch (op2) { + case OPC_DMT: + check_insn(env, ctx, ASE_MT); + gen_helper_dmt(t0); + gen_store_gpr(t0, rt); + break; + case OPC_EMT: + check_insn(env, ctx, ASE_MT); + gen_helper_emt(t0); + gen_store_gpr(t0, rt); + break; + case OPC_DVPE: + check_insn(env, ctx, ASE_MT); + gen_helper_dvpe(t0); + gen_store_gpr(t0, rt); + break; + case OPC_EVPE: + check_insn(env, ctx, ASE_MT); + gen_helper_evpe(t0); + gen_store_gpr(t0, rt); + break; + case OPC_DI: + check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); + gen_helper_di(t0); + gen_store_gpr(t0, rt); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case OPC_EI: + check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); + gen_helper_ei(t0); + gen_store_gpr(t0, rt); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + default: /* Invalid */ + MIPS_INVAL("mfmc0"); + generate_exception(ctx, EXCP_RI); + break; + } + tcg_temp_free(t0); } - GEN_STORE_T0_REG(rt); +#endif /* !CONFIG_USER_ONLY */ break; case OPC_RDPGPR: check_insn(env, ctx, ISA_MIPS32R2); - GEN_LOAD_SRSREG_TN(T0, rt); - GEN_STORE_T0_REG(rd); + gen_load_srsgpr(rt, rd); break; case OPC_WRPGPR: check_insn(env, ctx, ISA_MIPS32R2); - GEN_LOAD_REG_T0(rt); - GEN_STORE_TN_SRSREG(rd, T0); + gen_store_srsgpr(rt, rd); break; default: MIPS_INVAL("cp0"); @@ -6437,23 +12179,40 @@ static void decode_opc (CPUState *env, D break; } break; - case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */ + case OPC_ADDI: /* Arithmetic with immediate opcode */ + case OPC_ADDIU: gen_arith_imm(env, ctx, op, rt, rs, imm); break; + case OPC_SLTI: /* Set on less than with immediate opcode */ + case OPC_SLTIU: + gen_slt_imm(env, op, rt, rs, imm); + break; + case OPC_ANDI: /* Arithmetic with immediate opcode */ + case OPC_LUI: + case OPC_ORI: + case OPC_XORI: + gen_logic_imm(env, op, rt, rs, imm); + break; case OPC_J ... OPC_JAL: /* Jump */ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, op, rs, rt, offset); - return; + gen_compute_branch(ctx, op, 4, rs, rt, offset); + *is_branch = 1; + break; case OPC_BEQ ... OPC_BGTZ: /* Branch */ case OPC_BEQL ... OPC_BGTZL: - gen_compute_branch(ctx, op, rs, rt, imm << 2); - return; + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); + *is_branch = 1; + break; case OPC_LB ... OPC_LWR: /* Load and stores */ + case OPC_LL: + gen_ld(env, ctx, op, rt, rs, imm); + break; case OPC_SB ... OPC_SW: case OPC_SWR: - case OPC_LL: + gen_st(ctx, op, rt, rs, imm); + break; case OPC_SC: - gen_ldst(ctx, op, rt, rs, imm); + gen_st_cond(ctx, op, rt, rs, imm); break; case OPC_CACHE: check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32); @@ -6469,18 +12228,11 @@ static void decode_opc (CPUState *env, D case OPC_LDC1: case OPC_SWC1: case OPC_SDC1: - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - save_cpu_state(ctx, 1); - check_cp1_enabled(ctx); - gen_flt_ldst(ctx, op, rt, rs, imm); - } else { - generate_exception_err(ctx, EXCP_CpU, 1); - } + gen_cop1_ldst(env, ctx, op, rt, rs, imm); break; case OPC_CP1: if (env->CP0_Config1 & (1 << CP0C1_FP)) { - save_cpu_state(ctx, 1); check_cp1_enabled(ctx); op1 = MASK_CP1(ctx->opcode); switch (op1) { @@ -6508,13 +12260,14 @@ static void decode_opc (CPUState *env, D case OPC_BC1: gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); - return; + *is_branch = 1; + break; case OPC_S_FMT: case OPC_D_FMT: case OPC_W_FMT: case OPC_L_FMT: case OPC_PS_FMT: - gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa, + gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, (imm >> 8) & 0x7); break; default: @@ -6539,7 +12292,6 @@ static void decode_opc (CPUState *env, D case OPC_CP3: if (env->CP0_Config1 & (1 << CP0C1_FP)) { - save_cpu_state(ctx, 1); check_cp1_enabled(ctx); op1 = MASK_CP3(ctx->opcode); switch (op1) { @@ -6583,24 +12335,36 @@ static void decode_opc (CPUState *env, D /* MIPS64 opcodes */ case OPC_LWU: case OPC_LDL ... OPC_LDR: - case OPC_SDL ... OPC_SDR: case OPC_LLD: case OPC_LD: - case OPC_SCD: + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_ld(env, ctx, op, rt, rs, imm); + break; + case OPC_SDL ... OPC_SDR: case OPC_SD: check_insn(env, ctx, ISA_MIPS3); check_mips_64(ctx); - gen_ldst(ctx, op, rt, rs, imm); + gen_st(ctx, op, rt, rs, imm); break; - case OPC_DADDI ... OPC_DADDIU: + case OPC_SCD: + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_st_cond(ctx, op, rt, rs, imm); + break; + case OPC_DADDI: + case OPC_DADDIU: check_insn(env, ctx, ISA_MIPS3); check_mips_64(ctx); gen_arith_imm(env, ctx, op, rt, rs, imm); break; #endif case OPC_JALX: - check_insn(env, ctx, ASE_MIPS16); - /* MIPS16: Not implemented. */ + check_insn(env, ctx, ASE_MIPS16 | ASE_MICROMIPS); + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; + gen_compute_branch(ctx, op, 4, rs, rt, offset); + *is_branch = 1; + break; case OPC_MDMX: check_insn(env, ctx, ASE_MDMX); /* MDMX: Not implemented. */ @@ -6609,97 +12373,53 @@ static void decode_opc (CPUState *env, D generate_exception(ctx, EXCP_RI); break; } - if (ctx->hflags & MIPS_HFLAG_BMASK) { - int hflags = ctx->hflags & MIPS_HFLAG_BMASK; - /* Branches completion */ - ctx->hflags &= ~MIPS_HFLAG_BMASK; - ctx->bstate = BS_BRANCH; - save_cpu_state(ctx, 0); - switch (hflags) { - case MIPS_HFLAG_B: - /* unconditional branch */ - MIPS_DEBUG("unconditional branch"); - gen_goto_tb(ctx, 0, ctx->btarget); - break; - case MIPS_HFLAG_BL: - /* blikely taken case */ - MIPS_DEBUG("blikely branch taken"); - gen_goto_tb(ctx, 0, ctx->btarget); - break; - case MIPS_HFLAG_BC: - /* Conditional branch */ - MIPS_DEBUG("conditional branch"); - { - int l1; - l1 = gen_new_label(); - gen_op_jnz_T2(l1); - gen_goto_tb(ctx, 1, ctx->pc + 4); - gen_set_label(l1); - gen_goto_tb(ctx, 0, ctx->btarget); - } - break; - case MIPS_HFLAG_BR: - /* unconditional branch to register */ - MIPS_DEBUG("branch to register"); - gen_op_breg(); - gen_op_reset_T0(); - gen_op_exit_tb(); - break; - default: - MIPS_DEBUG("unknown branch"); - break; - } - } } -static always_inline int +static inline void gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) { DisasContext ctx; target_ulong pc_start; uint16_t *gen_opc_end; + CPUBreakpoint *bp; int j, lj = -1; + int num_insns; + int max_insns; + int insn_bytes; + int is_branch; - if (search_pc && loglevel) - fprintf (logfile, "search pc %d\n", search_pc); + if (search_pc) + qemu_log("search pc %d\n", search_pc); pc_start = tb->pc; - gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; - nb_gen_labels = 0; ctx.pc = pc_start; ctx.saved_pc = -1; + ctx.singlestep_enabled = env->singlestep_enabled; ctx.tb = tb; ctx.bstate = BS_NONE; /* Restore delay slot state from the tb context. */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ restore_cpu_state(env, &ctx); -#if defined(CONFIG_USER_ONLY) - ctx.mem_idx = MIPS_HFLAG_UM; +#ifdef CONFIG_USER_ONLY + ctx.mem_idx = MIPS_HFLAG_UM; #else - ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; + ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; #endif -#ifdef DEBUG_DISAS - if (loglevel & CPU_LOG_TB_CPU) { - fprintf(logfile, "------------------------------------------------\n"); - /* FIXME: This may print out stale hflags from env... */ - cpu_dump_state(env, logfile, fprintf, 0); - } -#endif -#ifdef MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "\ntb %p idx %d hflags %04x\n", - tb, ctx.mem_idx, ctx.hflags); -#endif - while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == ctx.pc) { + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags); + gen_icount_start(); + while (ctx.bstate == BS_NONE) { + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == ctx.pc) { save_cpu_state(&ctx, 1); ctx.bstate = BS_BRANCH; - gen_op_debug(); + gen_helper_0i(raise_exception, EXCP_DEBUG); /* Include the breakpoint location or the tb won't * be flushed when it must be. */ ctx.pc += 4; @@ -6718,28 +12438,61 @@ gen_intermediate_code_internal (CPUState gen_opc_pc[lj] = ctx.pc; gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK; gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; + } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); + + is_branch = 0; + if (!(ctx.hflags & MIPS_HFLAG_M16)) { + ctx.opcode = ldl_code(ctx.pc); + insn_bytes = 4; + decode_opc(env, &ctx, &is_branch); + } else if (env->insn_flags & ASE_MICROMIPS) { + ctx.opcode = lduw_code(ctx.pc); + insn_bytes = decode_micromips_opc(env, &ctx, &is_branch); + } else if (env->insn_flags & ASE_MIPS16) { + ctx.opcode = lduw_code(ctx.pc); + insn_bytes = decode_mips16_opc(env, &ctx, &is_branch); + } else { + generate_exception(&ctx, EXCP_RI); + ctx.bstate = BS_STOP; + break; + } + if (!is_branch) { + handle_delay_slot(env, &ctx, insn_bytes); } - ctx.opcode = ldl_code(ctx.pc); - decode_opc(env, &ctx); - ctx.pc += 4; + ctx.pc += insn_bytes; - if (env->singlestep_enabled) + num_insns++; + + /* Execute a branch and its delay slot as a single instruction. + This is what GDB expects and is consistent with what the + hardware does (e.g. if a delay slot instruction faults, the + reported PC is the PC of the branch). */ + if (env->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) break; if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) break; -#if defined (MIPS_SINGLE_STEP) - break; -#endif + if (gen_opc_ptr >= gen_opc_end) + break; + + if (num_insns >= max_insns) + break; + + if (singlestep) + break; } - if (env->singlestep_enabled) { + if (tb->cflags & CF_LAST_IO) + gen_io_end(); + if (env->singlestep_enabled && ctx.bstate != BS_BRANCH) { save_cpu_state(&ctx, ctx.bstate == BS_NONE); - gen_op_debug(); + gen_helper_0i(raise_exception, EXCP_DEBUG); } else { - switch (ctx.bstate) { + switch (ctx.bstate) { case BS_STOP: - gen_op_interrupt_restart(); gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_NONE: @@ -6747,17 +12500,15 @@ gen_intermediate_code_internal (CPUState gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_EXCP: - gen_op_interrupt_restart(); - gen_op_reset_T0(); - gen_op_exit_tb(); + tcg_gen_exit_tb(0); break; case BS_BRANCH: default: break; - } + } } done_generating: - ctx.last_T0_store = NULL; + gen_icount_end(tb, num_insns); *gen_opc_ptr = INDEX_op_end; if (search_pc) { j = gen_opc_ptr - gen_opc_buf; @@ -6766,132 +12517,116 @@ done_generating: gen_opc_instr_start[lj++] = 0; } else { tb->size = ctx.pc - pc_start; + tb->icount = num_insns; } #ifdef DEBUG_DISAS -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "\n"); -#endif - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, ctx.pc - pc_start, 0); - fprintf(logfile, "\n"); - } - if (loglevel & CPU_LOG_TB_OP) { - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } - if (loglevel & CPU_LOG_TB_CPU) { - fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags); + LOG_DISAS("\n"); + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + log_target_disas(pc_start, ctx.pc - pc_start, 0); + qemu_log("\n"); } #endif - - return 0; } -int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 0); + gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) { - return gen_intermediate_code_internal(env, tb, 1); + gen_intermediate_code_internal(env, tb, 1); } -void fpu_dump_state(CPUState *env, FILE *f, - int (*fpu_fprintf)(FILE *f, const char *fmt, ...), - int flags) +static void fpu_dump_state(CPUState *env, FILE *f, fprintf_function fpu_fprintf, + int flags) { int i; int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); -#define printfpr(fp) \ - do { \ - if (is_fpu64) \ - fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu: %13g\n", \ - (fp)->w[FP_ENDIAN_IDX], (fp)->d, (fp)->fd, \ - (fp)->fs[FP_ENDIAN_IDX], (fp)->fs[!FP_ENDIAN_IDX]); \ - else { \ - fpr_t tmp; \ - tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ - tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ - fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu:%13g\n", \ - tmp.w[FP_ENDIAN_IDX], tmp.d, tmp.fd, \ - tmp.fs[FP_ENDIAN_IDX], tmp.fs[!FP_ENDIAN_IDX]); \ - } \ +#define printfpr(fp) \ + do { \ + if (is_fpu64) \ + fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu: %13g\n", \ + (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ + (double)(fp)->fd, \ + (double)(fp)->fs[FP_ENDIAN_IDX], \ + (double)(fp)->fs[!FP_ENDIAN_IDX]); \ + else { \ + fpr_t tmp; \ + tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ + tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ + fpu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu:%13g\n", \ + tmp.w[FP_ENDIAN_IDX], tmp.d, \ + (double)tmp.fd, \ + (double)tmp.fs[FP_ENDIAN_IDX], \ + (double)tmp.fs[!FP_ENDIAN_IDX]); \ + } \ } while(0) - fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n", - env->fpu->fcr0, env->fpu->fcr31, is_fpu64, env->fpu->fp_status, - get_float_exception_flags(&env->fpu->fp_status)); - fpu_fprintf(f, "FT0: "); printfpr(&env->fpu->ft0); - fpu_fprintf(f, "FT1: "); printfpr(&env->fpu->ft1); - fpu_fprintf(f, "FT2: "); printfpr(&env->fpu->ft2); + fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n", + env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, + get_float_exception_flags(&env->active_fpu.fp_status)); for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { fpu_fprintf(f, "%3s: ", fregnames[i]); - printfpr(&env->fpu->fpr[i]); + printfpr(&env->active_fpu.fpr[i]); } #undef printfpr } -void dump_fpu (CPUState *env) -{ - if (loglevel) { - fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC[env->current_tc], env->HI[0][env->current_tc], env->LO[0][env->current_tc], env->hflags, env->btarget, env->bcond); - fpu_dump_state(env, logfile, fprintf, 0); - } -} - #if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) /* Debug help: The architecture requires 32bit code to maintain proper - sign-extened values on 64bit machines. */ + sign-extended values on 64bit machines. */ #define SIGN_EXT_P(val) ((((val) & ~0x7fffffff) == 0) || (((val) & ~0x7fffffff) == ~0x7fffffff)) -void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - int flags) +static void +cpu_mips_check_sign_extensions (CPUState *env, FILE *f, + fprintf_function cpu_fprintf, + int flags) { int i; - if (!SIGN_EXT_P(env->PC[env->current_tc])) - cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC[env->current_tc]); - if (!SIGN_EXT_P(env->HI[0][env->current_tc])) - cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[0][env->current_tc]); - if (!SIGN_EXT_P(env->LO[0][env->current_tc])) - cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[0][env->current_tc]); + if (!SIGN_EXT_P(env->active_tc.PC)) + cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->active_tc.PC); + if (!SIGN_EXT_P(env->active_tc.HI[0])) + cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->active_tc.HI[0]); + if (!SIGN_EXT_P(env->active_tc.LO[0])) + cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->active_tc.LO[0]); if (!SIGN_EXT_P(env->btarget)) cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget); for (i = 0; i < 32; i++) { - if (!SIGN_EXT_P(env->gpr[i][env->current_tc])) - cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i][env->current_tc]); + if (!SIGN_EXT_P(env->active_tc.gpr[i])) + cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->active_tc.gpr[i]); } if (!SIGN_EXT_P(env->CP0_EPC)) cpu_fprintf(f, "BROKEN: EPC=0x" TARGET_FMT_lx "\n", env->CP0_EPC); - if (!SIGN_EXT_P(env->CP0_LLAddr)) - cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->CP0_LLAddr); + if (!SIGN_EXT_P(env->lladdr)) + cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->lladdr); } #endif -void cpu_dump_state (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; - cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond); + cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx + " LO=0x" TARGET_FMT_lx " ds %04x " + TARGET_FMT_lx " " TARGET_FMT_ld "\n", + env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0], + env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { if ((i & 3) == 0) cpu_fprintf(f, "GPR%02d:", i); - cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i][env->current_tc]); + cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]); if ((i & 3) == 3) cpu_fprintf(f, "\n"); } @@ -6899,7 +12634,7 @@ void cpu_dump_state (CPUState *env, FILE cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", env->CP0_Status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n", - env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); + env->CP0_Config0, env->CP0_Config1, env->lladdr); if (env->hflags & MIPS_HFLAG_FPU) fpu_dump_state(env, f, cpu_fprintf, flags); #if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) @@ -6907,6 +12642,58 @@ void cpu_dump_state (CPUState *env, FILE #endif } +static void mips_tcg_init(void) +{ + int i; + static int inited; + + /* Initialize various static tables. */ + if (inited) + return; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + TCGV_UNUSED(cpu_gpr[0]); + for (i = 1; i < 32; i++) + cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.gpr[i]), + regnames[i]); + cpu_PC = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.PC), "PC"); + for (i = 0; i < MIPS_DSP_ACC; i++) { + cpu_HI[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.HI[i]), + regnames_HI[i]); + cpu_LO[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.LO[i]), + regnames_LO[i]); + cpu_ACX[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.ACX[i]), + regnames_ACX[i]); + } + cpu_dspctrl = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, active_tc.DSPControl), + "DSPControl"); + bcond = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, bcond), "bcond"); + btarget = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, btarget), "btarget"); + hflags = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, hflags), "hflags"); + + fpu_fcr0 = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, active_fpu.fcr0), + "fcr0"); + fpu_fcr31 = tcg_global_mem_new_i32(TCG_AREG0, + offsetof(CPUState, active_fpu.fcr31), + "fcr31"); + + /* register helpers */ +#define GEN_HELPER 2 +#include "helper.h" + + inited = 1; +} + #include "translate_init.c" CPUMIPSState *cpu_mips_init (const char *cpu_model) @@ -6917,36 +12704,98 @@ CPUMIPSState *cpu_mips_init (const char def = cpu_mips_find_by_name(cpu_model); if (!def) return NULL; - env = qemu_mallocz(sizeof(CPUMIPSState)); - if (!env) - return NULL; + env = g_malloc0(sizeof(CPUMIPSState)); env->cpu_model = def; + env->cpu_model_str = cpu_model; cpu_exec_init(env); - env->cpu_model_str = cpu_model; +#ifndef CONFIG_USER_ONLY + mmu_init(env, def); +#endif + fpu_init(env, def); + mvp_init(env, def); + mips_tcg_init(); cpu_reset(env); + qemu_init_vcpu(env); return env; } void cpu_reset (CPUMIPSState *env) { - memset(env, 0, offsetof(CPUMIPSState, breakpoints)); + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + log_cpu_state(env, 0); + } + memset(env, 0, offsetof(CPUMIPSState, breakpoints)); tlb_flush(env, 1); - /* Minimal init */ -#if !defined(CONFIG_USER_ONLY) + /* Reset registers to their default values */ + env->CP0_PRid = env->cpu_model->CP0_PRid; + env->CP0_Config0 = env->cpu_model->CP0_Config0; +#ifdef TARGET_WORDS_BIGENDIAN + env->CP0_Config0 |= (1 << CP0C0_BE); +#endif + env->CP0_Config1 = env->cpu_model->CP0_Config1; + env->CP0_Config2 = env->cpu_model->CP0_Config2; + env->CP0_Config3 = env->cpu_model->CP0_Config3; + env->CP0_Config6 = env->cpu_model->CP0_Config6; + env->CP0_Config7 = env->cpu_model->CP0_Config7; + env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask + << env->cpu_model->CP0_LLAddr_shift; + env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift; + env->SYNCI_Step = env->cpu_model->SYNCI_Step; + env->CCRes = env->cpu_model->CCRes; + env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask; + env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask; + env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl; + env->current_tc = 0; + env->SEGBITS = env->cpu_model->SEGBITS; + env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1); +#if defined(TARGET_MIPS64) + if (env->cpu_model->insn_flags & ISA_MIPS3) { + env->SEGMask |= 3ULL << 62; + } +#endif + env->PABITS = env->cpu_model->PABITS; + env->PAMask = (target_ulong)((1ULL << env->cpu_model->PABITS) - 1); + env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask; + env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0; + env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask; + env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1; + env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask; + env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2; + env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask; + env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3; + env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask; + env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4; + env->insn_flags = env->cpu_model->insn_flags; + +#if defined(CONFIG_USER_ONLY) + env->hflags = MIPS_HFLAG_UM; + /* Enable access to the SYNCI_Step register. */ + env->CP0_HWREna |= (1 << 1); + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + env->hflags |= MIPS_HFLAG_FPU; + } +#ifdef TARGET_MIPS64 + if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { + env->hflags |= MIPS_HFLAG_F64; + } +#endif +#else if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, - * come back to the jump. */ - env->CP0_ErrorEPC = env->PC[env->current_tc] - 4; + come back to the jump. */ + env->CP0_ErrorEPC = env->active_tc.PC - 4; } else { - env->CP0_ErrorEPC = env->PC[env->current_tc]; + env->CP0_ErrorEPC = env->active_tc.PC; } - env->PC[env->current_tc] = (int32_t)0xBFC00000; + env->active_tc.PC = (int32_t)0xBFC00000; + env->CP0_Random = env->tlb->nb_tlb - 1; + env->tlb->tlb_in_use = env->tlb->nb_tlb; env->CP0_Wired = 0; - /* SMP not implemented */ - env->CP0_EBase = 0x80000000; + env->CP0_EBase = 0x80000000 | (env->cpu_index & 0x3FF); env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); /* vectored interrupts not implemented, timer on int 7, no performance counters. */ @@ -6963,13 +12812,45 @@ void cpu_reset (CPUMIPSState *env) } /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); -#endif - env->exception_index = EXCP_NONE; -#if defined(CONFIG_USER_ONLY) - env->hflags = MIPS_HFLAG_UM; - env->user_mode_only = 1; -#else env->hflags = MIPS_HFLAG_CP0; + + if (env->CP0_Config3 & (1 << CP0C3_MT)) { + int i; + + /* Only TC0 on VPE 0 starts as active. */ + for (i = 0; i < ARRAY_SIZE(env->tcs); i++) { + env->tcs[i].CP0_TCBind = env->cpu_index << CP0TCBd_CurVPE; + env->tcs[i].CP0_TCHalt = 1; + } + env->active_tc.CP0_TCHalt = 1; + env->halted = 1; + + if (!env->cpu_index) { + /* VPE0 starts up enabled. */ + env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); + env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); + + /* TC0 starts up unhalted. */ + env->halted = 0; + env->active_tc.CP0_TCHalt = 0; + env->tcs[0].CP0_TCHalt = 0; + /* With thread 0 active. */ + env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A); + env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A); + } + } +#endif +#if defined(TARGET_MIPS64) + if (env->cpu_model->insn_flags & ISA_MIPS3) { + env->hflags |= MIPS_HFLAG_64; + } #endif - cpu_mips_register(env, env->cpu_model); + env->exception_index = EXCP_NONE; +} + +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) +{ + env->active_tc.PC = gen_opc_pc[pc_pos]; + env->hflags &= ~MIPS_HFLAG_BMASK; + env->hflags |= gen_opc_hflags[pc_pos]; }