 73f395fa88
			
		
	
	
		73f395fa88
		
	
	
	
	
		
			
			compatiblity -> compatibility continously -> continuously existance -> existence usefull -> useful shoudl -> should Signed-off-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
		
			
				
	
	
		
			3566 lines
		
	
	
		
			107 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3566 lines
		
	
	
		
			107 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  Alpha emulation cpu translation for qemu.
 | |
|  *
 | |
|  *  Copyright (c) 2007 Jocelyn Mayer
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * 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, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #include "cpu.h"
 | |
| #include "disas/disas.h"
 | |
| #include "qemu/host-utils.h"
 | |
| #include "tcg-op.h"
 | |
| 
 | |
| #include "helper.h"
 | |
| #define GEN_HELPER 1
 | |
| #include "helper.h"
 | |
| 
 | |
| #undef ALPHA_DEBUG_DISAS
 | |
| #define CONFIG_SOFTFLOAT_INLINE
 | |
| 
 | |
| #ifdef ALPHA_DEBUG_DISAS
 | |
| #  define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
 | |
| #else
 | |
| #  define LOG_DISAS(...) do { } while (0)
 | |
| #endif
 | |
| 
 | |
| typedef struct DisasContext DisasContext;
 | |
| struct DisasContext {
 | |
|     struct TranslationBlock *tb;
 | |
|     uint64_t pc;
 | |
|     int mem_idx;
 | |
| 
 | |
|     /* Current rounding mode for this TB.  */
 | |
|     int tb_rm;
 | |
|     /* Current flush-to-zero setting for this TB.  */
 | |
|     int tb_ftz;
 | |
| 
 | |
|     /* implver value for this CPU.  */
 | |
|     int implver;
 | |
| 
 | |
|     bool singlestep_enabled;
 | |
| };
 | |
| 
 | |
| /* Return values from translate_one, indicating the state of the TB.
 | |
|    Note that zero indicates that we are not exiting the TB.  */
 | |
| 
 | |
| typedef enum {
 | |
|     NO_EXIT,
 | |
| 
 | |
|     /* We have emitted one or more goto_tb.  No fixup required.  */
 | |
|     EXIT_GOTO_TB,
 | |
| 
 | |
|     /* We are not using a goto_tb (for whatever reason), but have updated
 | |
|        the PC (for whatever reason), so there's no need to do it again on
 | |
|        exiting the TB.  */
 | |
|     EXIT_PC_UPDATED,
 | |
| 
 | |
|     /* We are exiting the TB, but have neither emitted a goto_tb, nor
 | |
|        updated the PC for the next instruction to be executed.  */
 | |
|     EXIT_PC_STALE,
 | |
| 
 | |
|     /* We are ending the TB with a noreturn function call, e.g. longjmp.
 | |
|        No following code will be executed.  */
 | |
|     EXIT_NORETURN,
 | |
| } ExitStatus;
 | |
| 
 | |
| /* global register indexes */
 | |
| static TCGv_ptr cpu_env;
 | |
| static TCGv cpu_ir[31];
 | |
| static TCGv cpu_fir[31];
 | |
| static TCGv cpu_pc;
 | |
| static TCGv cpu_lock_addr;
 | |
| static TCGv cpu_lock_st_addr;
 | |
| static TCGv cpu_lock_value;
 | |
| static TCGv cpu_unique;
 | |
| #ifndef CONFIG_USER_ONLY
 | |
| static TCGv cpu_sysval;
 | |
| static TCGv cpu_usp;
 | |
| #endif
 | |
| 
 | |
| /* register names */
 | |
| static char cpu_reg_names[10*4+21*5 + 10*5+21*6];
 | |
| 
 | |
| #include "exec/gen-icount.h"
 | |
| 
 | |
| void alpha_translate_init(void)
 | |
| {
 | |
|     int i;
 | |
|     char *p;
 | |
|     static int done_init = 0;
 | |
| 
 | |
|     if (done_init)
 | |
|         return;
 | |
| 
 | |
|     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
 | |
| 
 | |
|     p = cpu_reg_names;
 | |
|     for (i = 0; i < 31; i++) {
 | |
|         sprintf(p, "ir%d", i);
 | |
|         cpu_ir[i] = tcg_global_mem_new_i64(TCG_AREG0,
 | |
|                                            offsetof(CPUAlphaState, ir[i]), p);
 | |
|         p += (i < 10) ? 4 : 5;
 | |
| 
 | |
|         sprintf(p, "fir%d", i);
 | |
|         cpu_fir[i] = tcg_global_mem_new_i64(TCG_AREG0,
 | |
|                                             offsetof(CPUAlphaState, fir[i]), p);
 | |
|         p += (i < 10) ? 5 : 6;
 | |
|     }
 | |
| 
 | |
|     cpu_pc = tcg_global_mem_new_i64(TCG_AREG0,
 | |
|                                     offsetof(CPUAlphaState, pc), "pc");
 | |
| 
 | |
|     cpu_lock_addr = tcg_global_mem_new_i64(TCG_AREG0,
 | |
| 					   offsetof(CPUAlphaState, lock_addr),
 | |
| 					   "lock_addr");
 | |
|     cpu_lock_st_addr = tcg_global_mem_new_i64(TCG_AREG0,
 | |
| 					      offsetof(CPUAlphaState, lock_st_addr),
 | |
| 					      "lock_st_addr");
 | |
|     cpu_lock_value = tcg_global_mem_new_i64(TCG_AREG0,
 | |
| 					    offsetof(CPUAlphaState, lock_value),
 | |
| 					    "lock_value");
 | |
| 
 | |
|     cpu_unique = tcg_global_mem_new_i64(TCG_AREG0,
 | |
|                                         offsetof(CPUAlphaState, unique), "unique");
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|     cpu_sysval = tcg_global_mem_new_i64(TCG_AREG0,
 | |
|                                         offsetof(CPUAlphaState, sysval), "sysval");
 | |
|     cpu_usp = tcg_global_mem_new_i64(TCG_AREG0,
 | |
|                                      offsetof(CPUAlphaState, usp), "usp");
 | |
| #endif
 | |
| 
 | |
|     done_init = 1;
 | |
| }
 | |
| 
 | |
| static void gen_excp_1(int exception, int error_code)
 | |
| {
 | |
|     TCGv_i32 tmp1, tmp2;
 | |
| 
 | |
|     tmp1 = tcg_const_i32(exception);
 | |
|     tmp2 = tcg_const_i32(error_code);
 | |
|     gen_helper_excp(cpu_env, tmp1, tmp2);
 | |
|     tcg_temp_free_i32(tmp2);
 | |
|     tcg_temp_free_i32(tmp1);
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
 | |
| {
 | |
|     tcg_gen_movi_i64(cpu_pc, ctx->pc);
 | |
|     gen_excp_1(exception, error_code);
 | |
|     return EXIT_NORETURN;
 | |
| }
 | |
| 
 | |
| static inline ExitStatus gen_invalid(DisasContext *ctx)
 | |
| {
 | |
|     return gen_excp(ctx, EXCP_OPCDEC, 0);
 | |
| }
 | |
| 
 | |
| static inline void gen_qemu_ldf(TCGv t0, TCGv t1, int flags)
 | |
| {
 | |
|     TCGv_i32 tmp32 = tcg_temp_new_i32();
 | |
|     tcg_gen_qemu_ld_i32(tmp32, t1, flags, MO_LEUL);
 | |
|     gen_helper_memory_to_f(t0, tmp32);
 | |
|     tcg_temp_free_i32(tmp32);
 | |
| }
 | |
| 
 | |
| static inline void gen_qemu_ldg(TCGv t0, TCGv t1, int flags)
 | |
| {
 | |
|     TCGv tmp = tcg_temp_new();
 | |
|     tcg_gen_qemu_ld_i64(tmp, t1, flags, MO_LEQ);
 | |
|     gen_helper_memory_to_g(t0, tmp);
 | |
|     tcg_temp_free(tmp);
 | |
| }
 | |
| 
 | |
| static inline void gen_qemu_lds(TCGv t0, TCGv t1, int flags)
 | |
| {
 | |
|     TCGv_i32 tmp32 = tcg_temp_new_i32();
 | |
|     tcg_gen_qemu_ld_i32(tmp32, t1, flags, MO_LEUL);
 | |
|     gen_helper_memory_to_s(t0, tmp32);
 | |
|     tcg_temp_free_i32(tmp32);
 | |
| }
 | |
| 
 | |
| static inline void gen_qemu_ldl_l(TCGv t0, TCGv t1, int flags)
 | |
| {
 | |
|     tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LESL);
 | |
|     tcg_gen_mov_i64(cpu_lock_addr, t1);
 | |
|     tcg_gen_mov_i64(cpu_lock_value, t0);
 | |
| }
 | |
| 
 | |
| static inline void gen_qemu_ldq_l(TCGv t0, TCGv t1, int flags)
 | |
| {
 | |
|     tcg_gen_qemu_ld_i64(t0, t1, flags, MO_LEQ);
 | |
|     tcg_gen_mov_i64(cpu_lock_addr, t1);
 | |
|     tcg_gen_mov_i64(cpu_lock_value, t0);
 | |
| }
 | |
| 
 | |
| static inline void gen_load_mem(DisasContext *ctx,
 | |
|                                 void (*tcg_gen_qemu_load)(TCGv t0, TCGv t1,
 | |
|                                                           int flags),
 | |
|                                 int ra, int rb, int32_t disp16, int fp,
 | |
|                                 int clear)
 | |
| {
 | |
|     TCGv addr, va;
 | |
| 
 | |
|     /* LDQ_U with ra $31 is UNOP.  Other various loads are forms of
 | |
|        prefetches, which we can treat as nops.  No worries about
 | |
|        missed exceptions here.  */
 | |
|     if (unlikely(ra == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     addr = tcg_temp_new();
 | |
|     if (rb != 31) {
 | |
|         tcg_gen_addi_i64(addr, cpu_ir[rb], disp16);
 | |
|         if (clear) {
 | |
|             tcg_gen_andi_i64(addr, addr, ~0x7);
 | |
|         }
 | |
|     } else {
 | |
|         if (clear) {
 | |
|             disp16 &= ~0x7;
 | |
|         }
 | |
|         tcg_gen_movi_i64(addr, disp16);
 | |
|     }
 | |
| 
 | |
|     va = (fp ? cpu_fir[ra] : cpu_ir[ra]);
 | |
|     tcg_gen_qemu_load(va, addr, ctx->mem_idx);
 | |
| 
 | |
|     tcg_temp_free(addr);
 | |
| }
 | |
| 
 | |
| static inline void gen_qemu_stf(TCGv t0, TCGv t1, int flags)
 | |
| {
 | |
|     TCGv_i32 tmp32 = tcg_temp_new_i32();
 | |
|     gen_helper_f_to_memory(tmp32, t0);
 | |
|     tcg_gen_qemu_st_i32(tmp32, t1, flags, MO_LEUL);
 | |
|     tcg_temp_free_i32(tmp32);
 | |
| }
 | |
| 
 | |
| static inline void gen_qemu_stg(TCGv t0, TCGv t1, int flags)
 | |
| {
 | |
|     TCGv tmp = tcg_temp_new();
 | |
|     gen_helper_g_to_memory(tmp, t0);
 | |
|     tcg_gen_qemu_st_i64(tmp, t1, flags, MO_LEQ);
 | |
|     tcg_temp_free(tmp);
 | |
| }
 | |
| 
 | |
| static inline void gen_qemu_sts(TCGv t0, TCGv t1, int flags)
 | |
| {
 | |
|     TCGv_i32 tmp32 = tcg_temp_new_i32();
 | |
|     gen_helper_s_to_memory(tmp32, t0);
 | |
|     tcg_gen_qemu_st_i32(tmp32, t1, flags, MO_LEUL);
 | |
|     tcg_temp_free_i32(tmp32);
 | |
| }
 | |
| 
 | |
| static inline void gen_store_mem(DisasContext *ctx,
 | |
|                                  void (*tcg_gen_qemu_store)(TCGv t0, TCGv t1,
 | |
|                                                             int flags),
 | |
|                                  int ra, int rb, int32_t disp16, int fp,
 | |
|                                  int clear)
 | |
| {
 | |
|     TCGv addr, va;
 | |
| 
 | |
|     addr = tcg_temp_new();
 | |
|     if (rb != 31) {
 | |
|         tcg_gen_addi_i64(addr, cpu_ir[rb], disp16);
 | |
|         if (clear) {
 | |
|             tcg_gen_andi_i64(addr, addr, ~0x7);
 | |
|         }
 | |
|     } else {
 | |
|         if (clear) {
 | |
|             disp16 &= ~0x7;
 | |
|         }
 | |
|         tcg_gen_movi_i64(addr, disp16);
 | |
|     }
 | |
| 
 | |
|     if (ra == 31) {
 | |
|         va = tcg_const_i64(0);
 | |
|     } else {
 | |
|         va = (fp ? cpu_fir[ra] : cpu_ir[ra]);
 | |
|     }
 | |
|     tcg_gen_qemu_store(va, addr, ctx->mem_idx);
 | |
| 
 | |
|     tcg_temp_free(addr);
 | |
|     if (ra == 31) {
 | |
|         tcg_temp_free(va);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
 | |
|                                         int32_t disp16, int quad)
 | |
| {
 | |
|     TCGv addr;
 | |
| 
 | |
|     if (ra == 31) {
 | |
|         /* ??? Don't bother storing anything.  The user can't tell
 | |
|            the difference, since the zero register always reads zero.  */
 | |
|         return NO_EXIT;
 | |
|     }
 | |
| 
 | |
| #if defined(CONFIG_USER_ONLY)
 | |
|     addr = cpu_lock_st_addr;
 | |
| #else
 | |
|     addr = tcg_temp_local_new();
 | |
| #endif
 | |
| 
 | |
|     if (rb != 31) {
 | |
|         tcg_gen_addi_i64(addr, cpu_ir[rb], disp16);
 | |
|     } else {
 | |
|         tcg_gen_movi_i64(addr, disp16);
 | |
|     }
 | |
| 
 | |
| #if defined(CONFIG_USER_ONLY)
 | |
|     /* ??? This is handled via a complicated version of compare-and-swap
 | |
|        in the cpu_loop.  Hopefully one day we'll have a real CAS opcode
 | |
|        in TCG so that this isn't necessary.  */
 | |
|     return gen_excp(ctx, quad ? EXCP_STQ_C : EXCP_STL_C, ra);
 | |
| #else
 | |
|     /* ??? In system mode we are never multi-threaded, so CAS can be
 | |
|        implemented via a non-atomic load-compare-store sequence.  */
 | |
|     {
 | |
|         int lab_fail, lab_done;
 | |
|         TCGv val;
 | |
| 
 | |
|         lab_fail = gen_new_label();
 | |
|         lab_done = gen_new_label();
 | |
|         tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
 | |
| 
 | |
|         val = tcg_temp_new();
 | |
|         tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, quad ? MO_LEQ : MO_LESL);
 | |
|         tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail);
 | |
| 
 | |
|         tcg_gen_qemu_st_i64(cpu_ir[ra], addr, ctx->mem_idx,
 | |
|                             quad ? MO_LEQ : MO_LEUL);
 | |
|         tcg_gen_movi_i64(cpu_ir[ra], 1);
 | |
|         tcg_gen_br(lab_done);
 | |
| 
 | |
|         gen_set_label(lab_fail);
 | |
|         tcg_gen_movi_i64(cpu_ir[ra], 0);
 | |
| 
 | |
|         gen_set_label(lab_done);
 | |
|         tcg_gen_movi_i64(cpu_lock_addr, -1);
 | |
| 
 | |
|         tcg_temp_free(addr);
 | |
|         return NO_EXIT;
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static bool in_superpage(DisasContext *ctx, int64_t addr)
 | |
| {
 | |
|     return ((ctx->tb->flags & TB_FLAGS_USER_MODE) == 0
 | |
|             && addr < 0
 | |
|             && ((addr >> 41) & 3) == 2
 | |
|             && addr >> TARGET_VIRT_ADDR_SPACE_BITS == addr >> 63);
 | |
| }
 | |
| 
 | |
| static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
 | |
| {
 | |
|     /* Suppress goto_tb in the case of single-steping and IO.  */
 | |
|     if (ctx->singlestep_enabled || (ctx->tb->cflags & CF_LAST_IO)) {
 | |
|         return false;
 | |
|     }
 | |
|     /* If the destination is in the superpage, the page perms can't change.  */
 | |
|     if (in_superpage(ctx, dest)) {
 | |
|         return true;
 | |
|     }
 | |
|     /* Check for the dest on the same page as the start of the TB.  */
 | |
|     return ((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0;
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
 | |
| {
 | |
|     uint64_t dest = ctx->pc + (disp << 2);
 | |
| 
 | |
|     if (ra != 31) {
 | |
|         tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
 | |
|     }
 | |
| 
 | |
|     /* Notice branch-to-next; used to initialize RA with the PC.  */
 | |
|     if (disp == 0) {
 | |
|         return 0;
 | |
|     } else if (use_goto_tb(ctx, dest)) {
 | |
|         tcg_gen_goto_tb(0);
 | |
|         tcg_gen_movi_i64(cpu_pc, dest);
 | |
|         tcg_gen_exit_tb((uintptr_t)ctx->tb);
 | |
|         return EXIT_GOTO_TB;
 | |
|     } else {
 | |
|         tcg_gen_movi_i64(cpu_pc, dest);
 | |
|         return EXIT_PC_UPDATED;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond,
 | |
|                                      TCGv cmp, int32_t disp)
 | |
| {
 | |
|     uint64_t dest = ctx->pc + (disp << 2);
 | |
|     int lab_true = gen_new_label();
 | |
| 
 | |
|     if (use_goto_tb(ctx, dest)) {
 | |
|         tcg_gen_brcondi_i64(cond, cmp, 0, lab_true);
 | |
| 
 | |
|         tcg_gen_goto_tb(0);
 | |
|         tcg_gen_movi_i64(cpu_pc, ctx->pc);
 | |
|         tcg_gen_exit_tb((uintptr_t)ctx->tb);
 | |
| 
 | |
|         gen_set_label(lab_true);
 | |
|         tcg_gen_goto_tb(1);
 | |
|         tcg_gen_movi_i64(cpu_pc, dest);
 | |
|         tcg_gen_exit_tb((uintptr_t)ctx->tb + 1);
 | |
| 
 | |
|         return EXIT_GOTO_TB;
 | |
|     } else {
 | |
|         TCGv_i64 z = tcg_const_i64(0);
 | |
|         TCGv_i64 d = tcg_const_i64(dest);
 | |
|         TCGv_i64 p = tcg_const_i64(ctx->pc);
 | |
| 
 | |
|         tcg_gen_movcond_i64(cond, cpu_pc, cmp, z, d, p);
 | |
| 
 | |
|         tcg_temp_free_i64(z);
 | |
|         tcg_temp_free_i64(d);
 | |
|         tcg_temp_free_i64(p);
 | |
|         return EXIT_PC_UPDATED;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_bcond(DisasContext *ctx, TCGCond cond, int ra,
 | |
|                             int32_t disp, int mask)
 | |
| {
 | |
|     TCGv cmp_tmp;
 | |
| 
 | |
|     if (unlikely(ra == 31)) {
 | |
|         cmp_tmp = tcg_const_i64(0);
 | |
|     } else {
 | |
|         cmp_tmp = tcg_temp_new();
 | |
|         if (mask) {
 | |
|             tcg_gen_andi_i64(cmp_tmp, cpu_ir[ra], 1);
 | |
|         } else {
 | |
|             tcg_gen_mov_i64(cmp_tmp, cpu_ir[ra]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return gen_bcond_internal(ctx, cond, cmp_tmp, disp);
 | |
| }
 | |
| 
 | |
| /* Fold -0.0 for comparison with COND.  */
 | |
| 
 | |
| static void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src)
 | |
| {
 | |
|     uint64_t mzero = 1ull << 63;
 | |
| 
 | |
|     switch (cond) {
 | |
|     case TCG_COND_LE:
 | |
|     case TCG_COND_GT:
 | |
|         /* For <= or >, the -0.0 value directly compares the way we want.  */
 | |
|         tcg_gen_mov_i64(dest, src);
 | |
|         break;
 | |
| 
 | |
|     case TCG_COND_EQ:
 | |
|     case TCG_COND_NE:
 | |
|         /* For == or !=, we can simply mask off the sign bit and compare.  */
 | |
|         tcg_gen_andi_i64(dest, src, mzero - 1);
 | |
|         break;
 | |
| 
 | |
|     case TCG_COND_GE:
 | |
|     case TCG_COND_LT:
 | |
|         /* For >= or <, map -0.0 to +0.0 via comparison and mask.  */
 | |
|         tcg_gen_setcondi_i64(TCG_COND_NE, dest, src, mzero);
 | |
|         tcg_gen_neg_i64(dest, dest);
 | |
|         tcg_gen_and_i64(dest, dest, src);
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         abort();
 | |
|     }
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_fbcond(DisasContext *ctx, TCGCond cond, int ra,
 | |
|                              int32_t disp)
 | |
| {
 | |
|     TCGv cmp_tmp;
 | |
| 
 | |
|     if (unlikely(ra == 31)) {
 | |
|         /* Very uncommon case, but easier to optimize it to an integer
 | |
|            comparison than continuing with the floating point comparison.  */
 | |
|         return gen_bcond(ctx, cond, ra, disp, 0);
 | |
|     }
 | |
| 
 | |
|     cmp_tmp = tcg_temp_new();
 | |
|     gen_fold_mzero(cond, cmp_tmp, cpu_fir[ra]);
 | |
|     return gen_bcond_internal(ctx, cond, cmp_tmp, disp);
 | |
| }
 | |
| 
 | |
| static void gen_cmov(TCGCond cond, int ra, int rb, int rc,
 | |
|                      int islit, uint8_t lit, int mask)
 | |
| {
 | |
|     TCGv_i64 c1, z, v1;
 | |
| 
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (ra == 31) {
 | |
|         /* Very uncommon case - Do not bother to optimize.  */
 | |
|         c1 = tcg_const_i64(0);
 | |
|     } else if (mask) {
 | |
|         c1 = tcg_const_i64(1);
 | |
|         tcg_gen_and_i64(c1, c1, cpu_ir[ra]);
 | |
|     } else {
 | |
|         c1 = cpu_ir[ra];
 | |
|     }
 | |
|     if (islit) {
 | |
|         v1 = tcg_const_i64(lit);
 | |
|     } else {
 | |
|         v1 = cpu_ir[rb];
 | |
|     }
 | |
|     z = tcg_const_i64(0);
 | |
| 
 | |
|     tcg_gen_movcond_i64(cond, cpu_ir[rc], c1, z, v1, cpu_ir[rc]);
 | |
| 
 | |
|     tcg_temp_free_i64(z);
 | |
|     if (ra == 31 || mask) {
 | |
|         tcg_temp_free_i64(c1);
 | |
|     }
 | |
|     if (islit) {
 | |
|         tcg_temp_free_i64(v1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void gen_fcmov(TCGCond cond, int ra, int rb, int rc)
 | |
| {
 | |
|     TCGv_i64 c1, z, v1;
 | |
| 
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     c1 = tcg_temp_new_i64();
 | |
|     if (unlikely(ra == 31)) {
 | |
|         tcg_gen_movi_i64(c1, 0);
 | |
|     } else {
 | |
|         gen_fold_mzero(cond, c1, cpu_fir[ra]);
 | |
|     }
 | |
|     if (rb == 31) {
 | |
|         v1 = tcg_const_i64(0);
 | |
|     } else {
 | |
|         v1 = cpu_fir[rb];
 | |
|     }
 | |
|     z = tcg_const_i64(0);
 | |
| 
 | |
|     tcg_gen_movcond_i64(cond, cpu_fir[rc], c1, z, v1, cpu_fir[rc]);
 | |
| 
 | |
|     tcg_temp_free_i64(z);
 | |
|     tcg_temp_free_i64(c1);
 | |
|     if (rb == 31) {
 | |
|         tcg_temp_free_i64(v1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| #define QUAL_RM_N       0x080   /* Round mode nearest even */
 | |
| #define QUAL_RM_C       0x000   /* Round mode chopped */
 | |
| #define QUAL_RM_M       0x040   /* Round mode minus infinity */
 | |
| #define QUAL_RM_D       0x0c0   /* Round mode dynamic */
 | |
| #define QUAL_RM_MASK    0x0c0
 | |
| 
 | |
| #define QUAL_U          0x100   /* Underflow enable (fp output) */
 | |
| #define QUAL_V          0x100   /* Overflow enable (int output) */
 | |
| #define QUAL_S          0x400   /* Software completion enable */
 | |
| #define QUAL_I          0x200   /* Inexact detection enable */
 | |
| 
 | |
| static void gen_qual_roundmode(DisasContext *ctx, int fn11)
 | |
| {
 | |
|     TCGv_i32 tmp;
 | |
| 
 | |
|     fn11 &= QUAL_RM_MASK;
 | |
|     if (fn11 == ctx->tb_rm) {
 | |
|         return;
 | |
|     }
 | |
|     ctx->tb_rm = fn11;
 | |
| 
 | |
|     tmp = tcg_temp_new_i32();
 | |
|     switch (fn11) {
 | |
|     case QUAL_RM_N:
 | |
|         tcg_gen_movi_i32(tmp, float_round_nearest_even);
 | |
|         break;
 | |
|     case QUAL_RM_C:
 | |
|         tcg_gen_movi_i32(tmp, float_round_to_zero);
 | |
|         break;
 | |
|     case QUAL_RM_M:
 | |
|         tcg_gen_movi_i32(tmp, float_round_down);
 | |
|         break;
 | |
|     case QUAL_RM_D:
 | |
|         tcg_gen_ld8u_i32(tmp, cpu_env,
 | |
|                          offsetof(CPUAlphaState, fpcr_dyn_round));
 | |
|         break;
 | |
|     }
 | |
| 
 | |
| #if defined(CONFIG_SOFTFLOAT_INLINE)
 | |
|     /* ??? The "fpu/softfloat.h" interface is to call set_float_rounding_mode.
 | |
|        With CONFIG_SOFTFLOAT that expands to an out-of-line call that just
 | |
|        sets the one field.  */
 | |
|     tcg_gen_st8_i32(tmp, cpu_env,
 | |
|                     offsetof(CPUAlphaState, fp_status.float_rounding_mode));
 | |
| #else
 | |
|     gen_helper_setroundmode(tmp);
 | |
| #endif
 | |
| 
 | |
|     tcg_temp_free_i32(tmp);
 | |
| }
 | |
| 
 | |
| static void gen_qual_flushzero(DisasContext *ctx, int fn11)
 | |
| {
 | |
|     TCGv_i32 tmp;
 | |
| 
 | |
|     fn11 &= QUAL_U;
 | |
|     if (fn11 == ctx->tb_ftz) {
 | |
|         return;
 | |
|     }
 | |
|     ctx->tb_ftz = fn11;
 | |
| 
 | |
|     tmp = tcg_temp_new_i32();
 | |
|     if (fn11) {
 | |
|         /* Underflow is enabled, use the FPCR setting.  */
 | |
|         tcg_gen_ld8u_i32(tmp, cpu_env,
 | |
|                          offsetof(CPUAlphaState, fpcr_flush_to_zero));
 | |
|     } else {
 | |
|         /* Underflow is disabled, force flush-to-zero.  */
 | |
|         tcg_gen_movi_i32(tmp, 1);
 | |
|     }
 | |
| 
 | |
| #if defined(CONFIG_SOFTFLOAT_INLINE)
 | |
|     tcg_gen_st8_i32(tmp, cpu_env,
 | |
|                     offsetof(CPUAlphaState, fp_status.flush_to_zero));
 | |
| #else
 | |
|     gen_helper_setflushzero(tmp);
 | |
| #endif
 | |
| 
 | |
|     tcg_temp_free_i32(tmp);
 | |
| }
 | |
| 
 | |
| static TCGv gen_ieee_input(int reg, int fn11, int is_cmp)
 | |
| {
 | |
|     TCGv val;
 | |
|     if (reg == 31) {
 | |
|         val = tcg_const_i64(0);
 | |
|     } else {
 | |
|         if ((fn11 & QUAL_S) == 0) {
 | |
|             if (is_cmp) {
 | |
|                 gen_helper_ieee_input_cmp(cpu_env, cpu_fir[reg]);
 | |
|             } else {
 | |
|                 gen_helper_ieee_input(cpu_env, cpu_fir[reg]);
 | |
|             }
 | |
|         }
 | |
|         val = tcg_temp_new();
 | |
|         tcg_gen_mov_i64(val, cpu_fir[reg]);
 | |
|     }
 | |
|     return val;
 | |
| }
 | |
| 
 | |
| static void gen_fp_exc_clear(void)
 | |
| {
 | |
| #if defined(CONFIG_SOFTFLOAT_INLINE)
 | |
|     TCGv_i32 zero = tcg_const_i32(0);
 | |
|     tcg_gen_st8_i32(zero, cpu_env,
 | |
|                     offsetof(CPUAlphaState, fp_status.float_exception_flags));
 | |
|     tcg_temp_free_i32(zero);
 | |
| #else
 | |
|     gen_helper_fp_exc_clear(cpu_env);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
 | |
| {
 | |
|     /* ??? We ought to be able to do something with imprecise exceptions.
 | |
|        E.g. notice we're still in the trap shadow of something within the
 | |
|        TB and do not generate the code to signal the exception; end the TB
 | |
|        when an exception is forced to arrive, either by consumption of a
 | |
|        register value or TRAPB or EXCB.  */
 | |
|     TCGv_i32 exc = tcg_temp_new_i32();
 | |
|     TCGv_i32 reg;
 | |
| 
 | |
| #if defined(CONFIG_SOFTFLOAT_INLINE)
 | |
|     tcg_gen_ld8u_i32(exc, cpu_env,
 | |
|                      offsetof(CPUAlphaState, fp_status.float_exception_flags));
 | |
| #else
 | |
|     gen_helper_fp_exc_get(exc, cpu_env);
 | |
| #endif
 | |
| 
 | |
|     if (ignore) {
 | |
|         tcg_gen_andi_i32(exc, exc, ~ignore);
 | |
|     }
 | |
| 
 | |
|     /* ??? Pass in the regno of the destination so that the helper can
 | |
|        set EXC_MASK, which contains a bitmask of destination registers
 | |
|        that have caused arithmetic traps.  A simple userspace emulation
 | |
|        does not require this.  We do need it for a guest kernel's entArith,
 | |
|        or if we were to do something clever with imprecise exceptions.  */
 | |
|     reg = tcg_const_i32(rc + 32);
 | |
| 
 | |
|     if (fn11 & QUAL_S) {
 | |
|         gen_helper_fp_exc_raise_s(cpu_env, exc, reg);
 | |
|     } else {
 | |
|         gen_helper_fp_exc_raise(cpu_env, exc, reg);
 | |
|     }
 | |
| 
 | |
|     tcg_temp_free_i32(reg);
 | |
|     tcg_temp_free_i32(exc);
 | |
| }
 | |
| 
 | |
| static inline void gen_fp_exc_raise(int rc, int fn11)
 | |
| {
 | |
|     gen_fp_exc_raise_ignore(rc, fn11, fn11 & QUAL_I ? 0 : float_flag_inexact);
 | |
| }
 | |
| 
 | |
| static void gen_fcvtlq(int rb, int rc)
 | |
| {
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
|     if (unlikely(rb == 31)) {
 | |
|         tcg_gen_movi_i64(cpu_fir[rc], 0);
 | |
|     } else {
 | |
|         TCGv tmp = tcg_temp_new();
 | |
| 
 | |
|         /* The arithmetic right shift here, plus the sign-extended mask below
 | |
|            yields a sign-extended result without an explicit ext32s_i64.  */
 | |
|         tcg_gen_sari_i64(tmp, cpu_fir[rb], 32);
 | |
|         tcg_gen_shri_i64(cpu_fir[rc], cpu_fir[rb], 29);
 | |
|         tcg_gen_andi_i64(tmp, tmp, (int32_t)0xc0000000);
 | |
|         tcg_gen_andi_i64(cpu_fir[rc], cpu_fir[rc], 0x3fffffff);
 | |
|         tcg_gen_or_i64(cpu_fir[rc], cpu_fir[rc], tmp);
 | |
| 
 | |
|         tcg_temp_free(tmp);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void gen_fcvtql(int rb, int rc)
 | |
| {
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
|     if (unlikely(rb == 31)) {
 | |
|         tcg_gen_movi_i64(cpu_fir[rc], 0);
 | |
|     } else {
 | |
|         TCGv tmp = tcg_temp_new();
 | |
| 
 | |
|         tcg_gen_andi_i64(tmp, cpu_fir[rb], 0xC0000000);
 | |
|         tcg_gen_andi_i64(cpu_fir[rc], cpu_fir[rb], 0x3FFFFFFF);
 | |
|         tcg_gen_shli_i64(tmp, tmp, 32);
 | |
|         tcg_gen_shli_i64(cpu_fir[rc], cpu_fir[rc], 29);
 | |
|         tcg_gen_or_i64(cpu_fir[rc], cpu_fir[rc], tmp);
 | |
| 
 | |
|         tcg_temp_free(tmp);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void gen_fcvtql_v(DisasContext *ctx, int rb, int rc)
 | |
| {
 | |
|     if (rb != 31) {
 | |
|         int lab = gen_new_label();
 | |
|         TCGv tmp = tcg_temp_new();
 | |
| 
 | |
|         tcg_gen_ext32s_i64(tmp, cpu_fir[rb]);
 | |
|         tcg_gen_brcond_i64(TCG_COND_EQ, tmp, cpu_fir[rb], lab);
 | |
|         gen_excp(ctx, EXCP_ARITH, EXC_M_IOV);
 | |
| 
 | |
|         gen_set_label(lab);
 | |
|     }
 | |
|     gen_fcvtql(rb, rc);
 | |
| }
 | |
| 
 | |
| #define FARITH2(name)                                                   \
 | |
|     static inline void glue(gen_f, name)(int rb, int rc)                \
 | |
|     {                                                                   \
 | |
|         if (unlikely(rc == 31)) {                                       \
 | |
|             return;                                                     \
 | |
|         }                                                               \
 | |
|         if (rb != 31) {                                                 \
 | |
|             gen_helper_ ## name(cpu_fir[rc], cpu_env, cpu_fir[rb]);     \
 | |
|         } else {                                                        \
 | |
|             TCGv tmp = tcg_const_i64(0);                                \
 | |
|             gen_helper_ ## name(cpu_fir[rc], cpu_env, tmp);             \
 | |
|             tcg_temp_free(tmp);                                         \
 | |
|         }                                                               \
 | |
|     }
 | |
| 
 | |
| /* ??? VAX instruction qualifiers ignored.  */
 | |
| FARITH2(sqrtf)
 | |
| FARITH2(sqrtg)
 | |
| FARITH2(cvtgf)
 | |
| FARITH2(cvtgq)
 | |
| FARITH2(cvtqf)
 | |
| FARITH2(cvtqg)
 | |
| 
 | |
| static void gen_ieee_arith2(DisasContext *ctx,
 | |
|                             void (*helper)(TCGv, TCGv_ptr, TCGv),
 | |
|                             int rb, int rc, int fn11)
 | |
| {
 | |
|     TCGv vb;
 | |
| 
 | |
|     /* ??? This is wrong: the instruction is not a nop, it still may
 | |
|        raise exceptions.  */
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     gen_qual_roundmode(ctx, fn11);
 | |
|     gen_qual_flushzero(ctx, fn11);
 | |
|     gen_fp_exc_clear();
 | |
| 
 | |
|     vb = gen_ieee_input(rb, fn11, 0);
 | |
|     helper(cpu_fir[rc], cpu_env, vb);
 | |
|     tcg_temp_free(vb);
 | |
| 
 | |
|     gen_fp_exc_raise(rc, fn11);
 | |
| }
 | |
| 
 | |
| #define IEEE_ARITH2(name)                                       \
 | |
| static inline void glue(gen_f, name)(DisasContext *ctx,         \
 | |
|                                      int rb, int rc, int fn11)  \
 | |
| {                                                               \
 | |
|     gen_ieee_arith2(ctx, gen_helper_##name, rb, rc, fn11);      \
 | |
| }
 | |
| IEEE_ARITH2(sqrts)
 | |
| IEEE_ARITH2(sqrtt)
 | |
| IEEE_ARITH2(cvtst)
 | |
| IEEE_ARITH2(cvtts)
 | |
| 
 | |
| static void gen_fcvttq(DisasContext *ctx, int rb, int rc, int fn11)
 | |
| {
 | |
|     TCGv vb;
 | |
|     int ignore = 0;
 | |
| 
 | |
|     /* ??? This is wrong: the instruction is not a nop, it still may
 | |
|        raise exceptions.  */
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     /* No need to set flushzero, since we have an integer output.  */
 | |
|     gen_fp_exc_clear();
 | |
|     vb = gen_ieee_input(rb, fn11, 0);
 | |
| 
 | |
|     /* Almost all integer conversions use cropped rounding, and most
 | |
|        also do not have integer overflow enabled.  Special case that.  */
 | |
|     switch (fn11) {
 | |
|     case QUAL_RM_C:
 | |
|         gen_helper_cvttq_c(cpu_fir[rc], cpu_env, vb);
 | |
|         break;
 | |
|     case QUAL_V | QUAL_RM_C:
 | |
|     case QUAL_S | QUAL_V | QUAL_RM_C:
 | |
|         ignore = float_flag_inexact;
 | |
|         /* FALLTHRU */
 | |
|     case QUAL_S | QUAL_V | QUAL_I | QUAL_RM_C:
 | |
|         gen_helper_cvttq_svic(cpu_fir[rc], cpu_env, vb);
 | |
|         break;
 | |
|     default:
 | |
|         gen_qual_roundmode(ctx, fn11);
 | |
|         gen_helper_cvttq(cpu_fir[rc], cpu_env, vb);
 | |
|         ignore |= (fn11 & QUAL_V ? 0 : float_flag_overflow);
 | |
|         ignore |= (fn11 & QUAL_I ? 0 : float_flag_inexact);
 | |
|         break;
 | |
|     }
 | |
|     tcg_temp_free(vb);
 | |
| 
 | |
|     gen_fp_exc_raise_ignore(rc, fn11, ignore);
 | |
| }
 | |
| 
 | |
| static void gen_ieee_intcvt(DisasContext *ctx,
 | |
|                             void (*helper)(TCGv, TCGv_ptr, TCGv),
 | |
| 			    int rb, int rc, int fn11)
 | |
| {
 | |
|     TCGv vb;
 | |
| 
 | |
|     /* ??? This is wrong: the instruction is not a nop, it still may
 | |
|        raise exceptions.  */
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     gen_qual_roundmode(ctx, fn11);
 | |
| 
 | |
|     if (rb == 31) {
 | |
|         vb = tcg_const_i64(0);
 | |
|     } else {
 | |
|         vb = cpu_fir[rb];
 | |
|     }
 | |
| 
 | |
|     /* The only exception that can be raised by integer conversion
 | |
|        is inexact.  Thus we only need to worry about exceptions when
 | |
|        inexact handling is requested.  */
 | |
|     if (fn11 & QUAL_I) {
 | |
|         gen_fp_exc_clear();
 | |
|         helper(cpu_fir[rc], cpu_env, vb);
 | |
|         gen_fp_exc_raise(rc, fn11);
 | |
|     } else {
 | |
|         helper(cpu_fir[rc], cpu_env, vb);
 | |
|     }
 | |
| 
 | |
|     if (rb == 31) {
 | |
|         tcg_temp_free(vb);
 | |
|     }
 | |
| }
 | |
| 
 | |
| #define IEEE_INTCVT(name)                                       \
 | |
| static inline void glue(gen_f, name)(DisasContext *ctx,         \
 | |
|                                      int rb, int rc, int fn11)  \
 | |
| {                                                               \
 | |
|     gen_ieee_intcvt(ctx, gen_helper_##name, rb, rc, fn11);      \
 | |
| }
 | |
| IEEE_INTCVT(cvtqs)
 | |
| IEEE_INTCVT(cvtqt)
 | |
| 
 | |
| static void gen_cpys_internal(int ra, int rb, int rc, int inv_a, uint64_t mask)
 | |
| {
 | |
|     TCGv va, vb, vmask;
 | |
|     int za = 0, zb = 0;
 | |
| 
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     vmask = tcg_const_i64(mask);
 | |
| 
 | |
|     TCGV_UNUSED_I64(va);
 | |
|     if (ra == 31) {
 | |
|         if (inv_a) {
 | |
|             va = vmask;
 | |
|         } else {
 | |
|             za = 1;
 | |
|         }
 | |
|     } else {
 | |
|         va = tcg_temp_new_i64();
 | |
|         tcg_gen_mov_i64(va, cpu_fir[ra]);
 | |
|         if (inv_a) {
 | |
|             tcg_gen_andc_i64(va, vmask, va);
 | |
|         } else {
 | |
|             tcg_gen_and_i64(va, va, vmask);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     TCGV_UNUSED_I64(vb);
 | |
|     if (rb == 31) {
 | |
|         zb = 1;
 | |
|     } else {
 | |
|         vb = tcg_temp_new_i64();
 | |
|         tcg_gen_andc_i64(vb, cpu_fir[rb], vmask);
 | |
|     }
 | |
| 
 | |
|     switch (za << 1 | zb) {
 | |
|     case 0 | 0:
 | |
|         tcg_gen_or_i64(cpu_fir[rc], va, vb);
 | |
|         break;
 | |
|     case 0 | 1:
 | |
|         tcg_gen_mov_i64(cpu_fir[rc], va);
 | |
|         break;
 | |
|     case 2 | 0:
 | |
|         tcg_gen_mov_i64(cpu_fir[rc], vb);
 | |
|         break;
 | |
|     case 2 | 1:
 | |
|         tcg_gen_movi_i64(cpu_fir[rc], 0);
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     tcg_temp_free(vmask);
 | |
|     if (ra != 31) {
 | |
|         tcg_temp_free(va);
 | |
|     }
 | |
|     if (rb != 31) {
 | |
|         tcg_temp_free(vb);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static inline void gen_fcpys(int ra, int rb, int rc)
 | |
| {
 | |
|     gen_cpys_internal(ra, rb, rc, 0, 0x8000000000000000ULL);
 | |
| }
 | |
| 
 | |
| static inline void gen_fcpysn(int ra, int rb, int rc)
 | |
| {
 | |
|     gen_cpys_internal(ra, rb, rc, 1, 0x8000000000000000ULL);
 | |
| }
 | |
| 
 | |
| static inline void gen_fcpyse(int ra, int rb, int rc)
 | |
| {
 | |
|     gen_cpys_internal(ra, rb, rc, 0, 0xFFF0000000000000ULL);
 | |
| }
 | |
| 
 | |
| #define FARITH3(name)                                                   \
 | |
|     static inline void glue(gen_f, name)(int ra, int rb, int rc)        \
 | |
|     {                                                                   \
 | |
|         TCGv va, vb;                                                    \
 | |
|                                                                         \
 | |
|         if (unlikely(rc == 31)) {                                       \
 | |
|             return;                                                     \
 | |
|         }                                                               \
 | |
|         if (ra == 31) {                                                 \
 | |
|             va = tcg_const_i64(0);                                      \
 | |
|         } else {                                                        \
 | |
|             va = cpu_fir[ra];                                           \
 | |
|         }                                                               \
 | |
|         if (rb == 31) {                                                 \
 | |
|             vb = tcg_const_i64(0);                                      \
 | |
|         } else {                                                        \
 | |
|             vb = cpu_fir[rb];                                           \
 | |
|         }                                                               \
 | |
|                                                                         \
 | |
|         gen_helper_ ## name(cpu_fir[rc], cpu_env, va, vb);              \
 | |
|                                                                         \
 | |
|         if (ra == 31) {                                                 \
 | |
|             tcg_temp_free(va);                                          \
 | |
|         }                                                               \
 | |
|         if (rb == 31) {                                                 \
 | |
|             tcg_temp_free(vb);                                          \
 | |
|         }                                                               \
 | |
|     }
 | |
| 
 | |
| /* ??? VAX instruction qualifiers ignored.  */
 | |
| FARITH3(addf)
 | |
| FARITH3(subf)
 | |
| FARITH3(mulf)
 | |
| FARITH3(divf)
 | |
| FARITH3(addg)
 | |
| FARITH3(subg)
 | |
| FARITH3(mulg)
 | |
| FARITH3(divg)
 | |
| FARITH3(cmpgeq)
 | |
| FARITH3(cmpglt)
 | |
| FARITH3(cmpgle)
 | |
| 
 | |
| static void gen_ieee_arith3(DisasContext *ctx,
 | |
|                             void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv),
 | |
|                             int ra, int rb, int rc, int fn11)
 | |
| {
 | |
|     TCGv va, vb;
 | |
| 
 | |
|     /* ??? This is wrong: the instruction is not a nop, it still may
 | |
|        raise exceptions.  */
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     gen_qual_roundmode(ctx, fn11);
 | |
|     gen_qual_flushzero(ctx, fn11);
 | |
|     gen_fp_exc_clear();
 | |
| 
 | |
|     va = gen_ieee_input(ra, fn11, 0);
 | |
|     vb = gen_ieee_input(rb, fn11, 0);
 | |
|     helper(cpu_fir[rc], cpu_env, va, vb);
 | |
|     tcg_temp_free(va);
 | |
|     tcg_temp_free(vb);
 | |
| 
 | |
|     gen_fp_exc_raise(rc, fn11);
 | |
| }
 | |
| 
 | |
| #define IEEE_ARITH3(name)                                               \
 | |
| static inline void glue(gen_f, name)(DisasContext *ctx,                 \
 | |
|                                      int ra, int rb, int rc, int fn11)  \
 | |
| {                                                                       \
 | |
|     gen_ieee_arith3(ctx, gen_helper_##name, ra, rb, rc, fn11);          \
 | |
| }
 | |
| IEEE_ARITH3(adds)
 | |
| IEEE_ARITH3(subs)
 | |
| IEEE_ARITH3(muls)
 | |
| IEEE_ARITH3(divs)
 | |
| IEEE_ARITH3(addt)
 | |
| IEEE_ARITH3(subt)
 | |
| IEEE_ARITH3(mult)
 | |
| IEEE_ARITH3(divt)
 | |
| 
 | |
| static void gen_ieee_compare(DisasContext *ctx,
 | |
|                              void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv),
 | |
|                              int ra, int rb, int rc, int fn11)
 | |
| {
 | |
|     TCGv va, vb;
 | |
| 
 | |
|     /* ??? This is wrong: the instruction is not a nop, it still may
 | |
|        raise exceptions.  */
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     gen_fp_exc_clear();
 | |
| 
 | |
|     va = gen_ieee_input(ra, fn11, 1);
 | |
|     vb = gen_ieee_input(rb, fn11, 1);
 | |
|     helper(cpu_fir[rc], cpu_env, va, vb);
 | |
|     tcg_temp_free(va);
 | |
|     tcg_temp_free(vb);
 | |
| 
 | |
|     gen_fp_exc_raise(rc, fn11);
 | |
| }
 | |
| 
 | |
| #define IEEE_CMP3(name)                                                 \
 | |
| static inline void glue(gen_f, name)(DisasContext *ctx,                 \
 | |
|                                      int ra, int rb, int rc, int fn11)  \
 | |
| {                                                                       \
 | |
|     gen_ieee_compare(ctx, gen_helper_##name, ra, rb, rc, fn11);         \
 | |
| }
 | |
| IEEE_CMP3(cmptun)
 | |
| IEEE_CMP3(cmpteq)
 | |
| IEEE_CMP3(cmptlt)
 | |
| IEEE_CMP3(cmptle)
 | |
| 
 | |
| static inline uint64_t zapnot_mask(uint8_t lit)
 | |
| {
 | |
|     uint64_t mask = 0;
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < 8; ++i) {
 | |
|         if ((lit >> i) & 1)
 | |
|             mask |= 0xffull << (i * 8);
 | |
|     }
 | |
|     return mask;
 | |
| }
 | |
| 
 | |
| /* Implement zapnot with an immediate operand, which expands to some
 | |
|    form of immediate AND.  This is a basic building block in the
 | |
|    definition of many of the other byte manipulation instructions.  */
 | |
| static void gen_zapnoti(TCGv dest, TCGv src, uint8_t lit)
 | |
| {
 | |
|     switch (lit) {
 | |
|     case 0x00:
 | |
|         tcg_gen_movi_i64(dest, 0);
 | |
|         break;
 | |
|     case 0x01:
 | |
|         tcg_gen_ext8u_i64(dest, src);
 | |
|         break;
 | |
|     case 0x03:
 | |
|         tcg_gen_ext16u_i64(dest, src);
 | |
|         break;
 | |
|     case 0x0f:
 | |
|         tcg_gen_ext32u_i64(dest, src);
 | |
|         break;
 | |
|     case 0xff:
 | |
|         tcg_gen_mov_i64(dest, src);
 | |
|         break;
 | |
|     default:
 | |
|         tcg_gen_andi_i64 (dest, src, zapnot_mask (lit));
 | |
|         break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static inline void gen_zapnot(int ra, int rb, int rc, int islit, uint8_t lit)
 | |
| {
 | |
|     if (unlikely(rc == 31))
 | |
|         return;
 | |
|     else if (unlikely(ra == 31))
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|     else if (islit)
 | |
|         gen_zapnoti(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|     else
 | |
|         gen_helper_zapnot (cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
| }
 | |
| 
 | |
| static inline void gen_zap(int ra, int rb, int rc, int islit, uint8_t lit)
 | |
| {
 | |
|     if (unlikely(rc == 31))
 | |
|         return;
 | |
|     else if (unlikely(ra == 31))
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|     else if (islit)
 | |
|         gen_zapnoti(cpu_ir[rc], cpu_ir[ra], ~lit);
 | |
|     else
 | |
|         gen_helper_zap (cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* EXTWH, EXTLH, EXTQH */
 | |
| static void gen_ext_h(int ra, int rb, int rc, int islit,
 | |
|                       uint8_t lit, uint8_t byte_mask)
 | |
| {
 | |
|     if (unlikely(rc == 31))
 | |
|         return;
 | |
|     else if (unlikely(ra == 31))
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|     else {
 | |
|         if (islit) {
 | |
|             lit = (64 - (lit & 7) * 8) & 0x3f;
 | |
|             tcg_gen_shli_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|         } else {
 | |
|             TCGv tmp1 = tcg_temp_new();
 | |
|             tcg_gen_andi_i64(tmp1, cpu_ir[rb], 7);
 | |
|             tcg_gen_shli_i64(tmp1, tmp1, 3);
 | |
|             tcg_gen_neg_i64(tmp1, tmp1);
 | |
|             tcg_gen_andi_i64(tmp1, tmp1, 0x3f);
 | |
|             tcg_gen_shl_i64(cpu_ir[rc], cpu_ir[ra], tmp1);
 | |
|             tcg_temp_free(tmp1);
 | |
|         }
 | |
|         gen_zapnoti(cpu_ir[rc], cpu_ir[rc], byte_mask);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* EXTBL, EXTWL, EXTLL, EXTQL */
 | |
| static void gen_ext_l(int ra, int rb, int rc, int islit,
 | |
|                       uint8_t lit, uint8_t byte_mask)
 | |
| {
 | |
|     if (unlikely(rc == 31))
 | |
|         return;
 | |
|     else if (unlikely(ra == 31))
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|     else {
 | |
|         if (islit) {
 | |
|             tcg_gen_shri_i64(cpu_ir[rc], cpu_ir[ra], (lit & 7) * 8);
 | |
|         } else {
 | |
|             TCGv tmp = tcg_temp_new();
 | |
|             tcg_gen_andi_i64(tmp, cpu_ir[rb], 7);
 | |
|             tcg_gen_shli_i64(tmp, tmp, 3);
 | |
|             tcg_gen_shr_i64(cpu_ir[rc], cpu_ir[ra], tmp);
 | |
|             tcg_temp_free(tmp);
 | |
|         }
 | |
|         gen_zapnoti(cpu_ir[rc], cpu_ir[rc], byte_mask);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* INSWH, INSLH, INSQH */
 | |
| static void gen_ins_h(int ra, int rb, int rc, int islit,
 | |
|                       uint8_t lit, uint8_t byte_mask)
 | |
| {
 | |
|     if (unlikely(rc == 31))
 | |
|         return;
 | |
|     else if (unlikely(ra == 31) || (islit && (lit & 7) == 0))
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|     else {
 | |
|         TCGv tmp = tcg_temp_new();
 | |
| 
 | |
|         /* The instruction description has us left-shift the byte mask
 | |
|            and extract bits <15:8> and apply that zap at the end.  This
 | |
|            is equivalent to simply performing the zap first and shifting
 | |
|            afterward.  */
 | |
|         gen_zapnoti (tmp, cpu_ir[ra], byte_mask);
 | |
| 
 | |
|         if (islit) {
 | |
|             /* Note that we have handled the lit==0 case above.  */
 | |
|             tcg_gen_shri_i64 (cpu_ir[rc], tmp, 64 - (lit & 7) * 8);
 | |
|         } else {
 | |
|             TCGv shift = tcg_temp_new();
 | |
| 
 | |
|             /* If (B & 7) == 0, we need to shift by 64 and leave a zero.
 | |
|                Do this portably by splitting the shift into two parts:
 | |
|                shift_count-1 and 1.  Arrange for the -1 by using
 | |
|                ones-complement instead of twos-complement in the negation:
 | |
|                ~((B & 7) * 8) & 63.  */
 | |
| 
 | |
|             tcg_gen_andi_i64(shift, cpu_ir[rb], 7);
 | |
|             tcg_gen_shli_i64(shift, shift, 3);
 | |
|             tcg_gen_not_i64(shift, shift);
 | |
|             tcg_gen_andi_i64(shift, shift, 0x3f);
 | |
| 
 | |
|             tcg_gen_shr_i64(cpu_ir[rc], tmp, shift);
 | |
|             tcg_gen_shri_i64(cpu_ir[rc], cpu_ir[rc], 1);
 | |
|             tcg_temp_free(shift);
 | |
|         }
 | |
|         tcg_temp_free(tmp);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* INSBL, INSWL, INSLL, INSQL */
 | |
| static void gen_ins_l(int ra, int rb, int rc, int islit,
 | |
|                       uint8_t lit, uint8_t byte_mask)
 | |
| {
 | |
|     if (unlikely(rc == 31))
 | |
|         return;
 | |
|     else if (unlikely(ra == 31))
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|     else {
 | |
|         TCGv tmp = tcg_temp_new();
 | |
| 
 | |
|         /* The instruction description has us left-shift the byte mask
 | |
|            the same number of byte slots as the data and apply the zap
 | |
|            at the end.  This is equivalent to simply performing the zap
 | |
|            first and shifting afterward.  */
 | |
|         gen_zapnoti (tmp, cpu_ir[ra], byte_mask);
 | |
| 
 | |
|         if (islit) {
 | |
|             tcg_gen_shli_i64(cpu_ir[rc], tmp, (lit & 7) * 8);
 | |
|         } else {
 | |
|             TCGv shift = tcg_temp_new();
 | |
|             tcg_gen_andi_i64(shift, cpu_ir[rb], 7);
 | |
|             tcg_gen_shli_i64(shift, shift, 3);
 | |
|             tcg_gen_shl_i64(cpu_ir[rc], tmp, shift);
 | |
|             tcg_temp_free(shift);
 | |
|         }
 | |
|         tcg_temp_free(tmp);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* MSKWH, MSKLH, MSKQH */
 | |
| static void gen_msk_h(int ra, int rb, int rc, int islit,
 | |
|                       uint8_t lit, uint8_t byte_mask)
 | |
| {
 | |
|     if (unlikely(rc == 31))
 | |
|         return;
 | |
|     else if (unlikely(ra == 31))
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|     else if (islit) {
 | |
|         gen_zapnoti (cpu_ir[rc], cpu_ir[ra], ~((byte_mask << (lit & 7)) >> 8));
 | |
|     } else {
 | |
|         TCGv shift = tcg_temp_new();
 | |
|         TCGv mask = tcg_temp_new();
 | |
| 
 | |
|         /* The instruction description is as above, where the byte_mask
 | |
|            is shifted left, and then we extract bits <15:8>.  This can be
 | |
|            emulated with a right-shift on the expanded byte mask.  This
 | |
|            requires extra care because for an input <2:0> == 0 we need a
 | |
|            shift of 64 bits in order to generate a zero.  This is done by
 | |
|            splitting the shift into two parts, the variable shift - 1
 | |
|            followed by a constant 1 shift.  The code we expand below is
 | |
|            equivalent to ~((B & 7) * 8) & 63.  */
 | |
| 
 | |
|         tcg_gen_andi_i64(shift, cpu_ir[rb], 7);
 | |
|         tcg_gen_shli_i64(shift, shift, 3);
 | |
|         tcg_gen_not_i64(shift, shift);
 | |
|         tcg_gen_andi_i64(shift, shift, 0x3f);
 | |
|         tcg_gen_movi_i64(mask, zapnot_mask (byte_mask));
 | |
|         tcg_gen_shr_i64(mask, mask, shift);
 | |
|         tcg_gen_shri_i64(mask, mask, 1);
 | |
| 
 | |
|         tcg_gen_andc_i64(cpu_ir[rc], cpu_ir[ra], mask);
 | |
| 
 | |
|         tcg_temp_free(mask);
 | |
|         tcg_temp_free(shift);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* MSKBL, MSKWL, MSKLL, MSKQL */
 | |
| static void gen_msk_l(int ra, int rb, int rc, int islit,
 | |
|                       uint8_t lit, uint8_t byte_mask)
 | |
| {
 | |
|     if (unlikely(rc == 31))
 | |
|         return;
 | |
|     else if (unlikely(ra == 31))
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|     else if (islit) {
 | |
|         gen_zapnoti (cpu_ir[rc], cpu_ir[ra], ~(byte_mask << (lit & 7)));
 | |
|     } else {
 | |
|         TCGv shift = tcg_temp_new();
 | |
|         TCGv mask = tcg_temp_new();
 | |
| 
 | |
|         tcg_gen_andi_i64(shift, cpu_ir[rb], 7);
 | |
|         tcg_gen_shli_i64(shift, shift, 3);
 | |
|         tcg_gen_movi_i64(mask, zapnot_mask (byte_mask));
 | |
|         tcg_gen_shl_i64(mask, mask, shift);
 | |
| 
 | |
|         tcg_gen_andc_i64(cpu_ir[rc], cpu_ir[ra], mask);
 | |
| 
 | |
|         tcg_temp_free(mask);
 | |
|         tcg_temp_free(shift);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Code to call arith3 helpers */
 | |
| #define ARITH3(name)                                                  \
 | |
| static inline void glue(gen_, name)(int ra, int rb, int rc, int islit,\
 | |
|                                     uint8_t lit)                      \
 | |
| {                                                                     \
 | |
|     if (unlikely(rc == 31))                                           \
 | |
|         return;                                                       \
 | |
|                                                                       \
 | |
|     if (ra != 31) {                                                   \
 | |
|         if (islit) {                                                  \
 | |
|             TCGv tmp = tcg_const_i64(lit);                            \
 | |
|             gen_helper_ ## name(cpu_ir[rc], cpu_ir[ra], tmp);         \
 | |
|             tcg_temp_free(tmp);                                       \
 | |
|         } else                                                        \
 | |
|             gen_helper_ ## name (cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); \
 | |
|     } else {                                                          \
 | |
|         TCGv tmp1 = tcg_const_i64(0);                                 \
 | |
|         if (islit) {                                                  \
 | |
|             TCGv tmp2 = tcg_const_i64(lit);                           \
 | |
|             gen_helper_ ## name (cpu_ir[rc], tmp1, tmp2);             \
 | |
|             tcg_temp_free(tmp2);                                      \
 | |
|         } else                                                        \
 | |
|             gen_helper_ ## name (cpu_ir[rc], tmp1, cpu_ir[rb]);       \
 | |
|         tcg_temp_free(tmp1);                                          \
 | |
|     }                                                                 \
 | |
| }
 | |
| ARITH3(cmpbge)
 | |
| ARITH3(minub8)
 | |
| ARITH3(minsb8)
 | |
| ARITH3(minuw4)
 | |
| ARITH3(minsw4)
 | |
| ARITH3(maxub8)
 | |
| ARITH3(maxsb8)
 | |
| ARITH3(maxuw4)
 | |
| ARITH3(maxsw4)
 | |
| ARITH3(perr)
 | |
| 
 | |
| /* Code to call arith3 helpers */
 | |
| #define ARITH3_EX(name)                                                 \
 | |
|     static inline void glue(gen_, name)(int ra, int rb, int rc,         \
 | |
|                                         int islit, uint8_t lit)         \
 | |
|     {                                                                   \
 | |
|         if (unlikely(rc == 31)) {                                       \
 | |
|             return;                                                     \
 | |
|         }                                                               \
 | |
|         if (ra != 31) {                                                 \
 | |
|             if (islit) {                                                \
 | |
|                 TCGv tmp = tcg_const_i64(lit);                          \
 | |
|                 gen_helper_ ## name(cpu_ir[rc], cpu_env,                \
 | |
|                                     cpu_ir[ra], tmp);                   \
 | |
|                 tcg_temp_free(tmp);                                     \
 | |
|             } else {                                                    \
 | |
|                 gen_helper_ ## name(cpu_ir[rc], cpu_env,                \
 | |
|                                     cpu_ir[ra], cpu_ir[rb]);            \
 | |
|             }                                                           \
 | |
|         } else {                                                        \
 | |
|             TCGv tmp1 = tcg_const_i64(0);                               \
 | |
|             if (islit) {                                                \
 | |
|                 TCGv tmp2 = tcg_const_i64(lit);                         \
 | |
|                 gen_helper_ ## name(cpu_ir[rc], cpu_env, tmp1, tmp2);   \
 | |
|                 tcg_temp_free(tmp2);                                    \
 | |
|             } else {                                                    \
 | |
|                 gen_helper_ ## name(cpu_ir[rc], cpu_env, tmp1, cpu_ir[rb]); \
 | |
|             }                                                           \
 | |
|             tcg_temp_free(tmp1);                                        \
 | |
|         }                                                               \
 | |
|     }
 | |
| ARITH3_EX(addlv)
 | |
| ARITH3_EX(sublv)
 | |
| ARITH3_EX(addqv)
 | |
| ARITH3_EX(subqv)
 | |
| ARITH3_EX(mullv)
 | |
| ARITH3_EX(mulqv)
 | |
| 
 | |
| #define MVIOP2(name)                                    \
 | |
| static inline void glue(gen_, name)(int rb, int rc)     \
 | |
| {                                                       \
 | |
|     if (unlikely(rc == 31))                             \
 | |
|         return;                                         \
 | |
|     if (unlikely(rb == 31))                             \
 | |
|         tcg_gen_movi_i64(cpu_ir[rc], 0);                \
 | |
|     else                                                \
 | |
|         gen_helper_ ## name (cpu_ir[rc], cpu_ir[rb]);   \
 | |
| }
 | |
| MVIOP2(pklb)
 | |
| MVIOP2(pkwb)
 | |
| MVIOP2(unpkbl)
 | |
| MVIOP2(unpkbw)
 | |
| 
 | |
| static void gen_cmp(TCGCond cond, int ra, int rb, int rc,
 | |
|                     int islit, uint8_t lit)
 | |
| {
 | |
|     TCGv va, vb;
 | |
| 
 | |
|     if (unlikely(rc == 31)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (ra == 31) {
 | |
|         va = tcg_const_i64(0);
 | |
|     } else {
 | |
|         va = cpu_ir[ra];
 | |
|     }
 | |
|     if (islit) {
 | |
|         vb = tcg_const_i64(lit);
 | |
|     } else {
 | |
|         vb = cpu_ir[rb];
 | |
|     }
 | |
| 
 | |
|     tcg_gen_setcond_i64(cond, cpu_ir[rc], va, vb);
 | |
| 
 | |
|     if (ra == 31) {
 | |
|         tcg_temp_free(va);
 | |
|     }
 | |
|     if (islit) {
 | |
|         tcg_temp_free(vb);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void gen_rx(int ra, int set)
 | |
| {
 | |
|     TCGv_i32 tmp;
 | |
| 
 | |
|     if (ra != 31) {
 | |
|         tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, offsetof(CPUAlphaState, intr_flag));
 | |
|     }
 | |
| 
 | |
|     tmp = tcg_const_i32(set);
 | |
|     tcg_gen_st8_i32(tmp, cpu_env, offsetof(CPUAlphaState, intr_flag));
 | |
|     tcg_temp_free_i32(tmp);
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
 | |
| {
 | |
|     /* We're emulating OSF/1 PALcode.  Many of these are trivial access
 | |
|        to internal cpu registers.  */
 | |
| 
 | |
|     /* Unprivileged PAL call */
 | |
|     if (palcode >= 0x80 && palcode < 0xC0) {
 | |
|         switch (palcode) {
 | |
|         case 0x86:
 | |
|             /* IMB */
 | |
|             /* No-op inside QEMU.  */
 | |
|             break;
 | |
|         case 0x9E:
 | |
|             /* RDUNIQUE */
 | |
|             tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_unique);
 | |
|             break;
 | |
|         case 0x9F:
 | |
|             /* WRUNIQUE */
 | |
|             tcg_gen_mov_i64(cpu_unique, cpu_ir[IR_A0]);
 | |
|             break;
 | |
|         default:
 | |
|             palcode &= 0xbf;
 | |
|             goto do_call_pal;
 | |
|         }
 | |
|         return NO_EXIT;
 | |
|     }
 | |
| 
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|     /* Privileged PAL code */
 | |
|     if (palcode < 0x40 && (ctx->tb->flags & TB_FLAGS_USER_MODE) == 0) {
 | |
|         switch (palcode) {
 | |
|         case 0x01:
 | |
|             /* CFLUSH */
 | |
|             /* No-op inside QEMU.  */
 | |
|             break;
 | |
|         case 0x02:
 | |
|             /* DRAINA */
 | |
|             /* No-op inside QEMU.  */
 | |
|             break;
 | |
|         case 0x2D:
 | |
|             /* WRVPTPTR */
 | |
|             tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, offsetof(CPUAlphaState, vptptr));
 | |
|             break;
 | |
|         case 0x31:
 | |
|             /* WRVAL */
 | |
|             tcg_gen_mov_i64(cpu_sysval, cpu_ir[IR_A0]);
 | |
|             break;
 | |
|         case 0x32:
 | |
|             /* RDVAL */
 | |
|             tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_sysval);
 | |
|             break;
 | |
| 
 | |
|         case 0x35: {
 | |
|             /* SWPIPL */
 | |
|             TCGv tmp;
 | |
| 
 | |
|             /* Note that we already know we're in kernel mode, so we know
 | |
|                that PS only contains the 3 IPL bits.  */
 | |
|             tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUAlphaState, ps));
 | |
| 
 | |
|             /* But make sure and store only the 3 IPL bits from the user.  */
 | |
|             tmp = tcg_temp_new();
 | |
|             tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], PS_INT_MASK);
 | |
|             tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, ps));
 | |
|             tcg_temp_free(tmp);
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case 0x36:
 | |
|             /* RDPS */
 | |
|             tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUAlphaState, ps));
 | |
|             break;
 | |
|         case 0x38:
 | |
|             /* WRUSP */
 | |
|             tcg_gen_mov_i64(cpu_usp, cpu_ir[IR_A0]);
 | |
|             break;
 | |
|         case 0x3A:
 | |
|             /* RDUSP */
 | |
|             tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_usp);
 | |
|             break;
 | |
|         case 0x3C:
 | |
|             /* WHAMI */
 | |
|             tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env,
 | |
|                 -offsetof(AlphaCPU, env) + offsetof(CPUState, cpu_index));
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             palcode &= 0x3f;
 | |
|             goto do_call_pal;
 | |
|         }
 | |
|         return NO_EXIT;
 | |
|     }
 | |
| #endif
 | |
|     return gen_invalid(ctx);
 | |
| 
 | |
|  do_call_pal:
 | |
| #ifdef CONFIG_USER_ONLY
 | |
|     return gen_excp(ctx, EXCP_CALL_PAL, palcode);
 | |
| #else
 | |
|     {
 | |
|         TCGv pc = tcg_const_i64(ctx->pc);
 | |
|         TCGv entry = tcg_const_i64(palcode & 0x80
 | |
|                                    ? 0x2000 + (palcode - 0x80) * 64
 | |
|                                    : 0x1000 + palcode * 64);
 | |
| 
 | |
|         gen_helper_call_pal(cpu_env, pc, entry);
 | |
| 
 | |
|         tcg_temp_free(entry);
 | |
|         tcg_temp_free(pc);
 | |
| 
 | |
|         /* Since the destination is running in PALmode, we don't really
 | |
|            need the page permissions check.  We'll see the existence of
 | |
|            the page when we create the TB, and we'll flush all TBs if
 | |
|            we change the PAL base register.  */
 | |
|         if (!ctx->singlestep_enabled && !(ctx->tb->cflags & CF_LAST_IO)) {
 | |
|             tcg_gen_goto_tb(0);
 | |
|             tcg_gen_exit_tb((uintptr_t)ctx->tb);
 | |
|             return EXIT_GOTO_TB;
 | |
|         }
 | |
| 
 | |
|         return EXIT_PC_UPDATED;
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #ifndef CONFIG_USER_ONLY
 | |
| 
 | |
| #define PR_BYTE         0x100000
 | |
| #define PR_LONG         0x200000
 | |
| 
 | |
| static int cpu_pr_data(int pr)
 | |
| {
 | |
|     switch (pr) {
 | |
|     case  0: return offsetof(CPUAlphaState, ps) | PR_BYTE;
 | |
|     case  1: return offsetof(CPUAlphaState, fen) | PR_BYTE;
 | |
|     case  2: return offsetof(CPUAlphaState, pcc_ofs) | PR_LONG;
 | |
|     case  3: return offsetof(CPUAlphaState, trap_arg0);
 | |
|     case  4: return offsetof(CPUAlphaState, trap_arg1);
 | |
|     case  5: return offsetof(CPUAlphaState, trap_arg2);
 | |
|     case  6: return offsetof(CPUAlphaState, exc_addr);
 | |
|     case  7: return offsetof(CPUAlphaState, palbr);
 | |
|     case  8: return offsetof(CPUAlphaState, ptbr);
 | |
|     case  9: return offsetof(CPUAlphaState, vptptr);
 | |
|     case 10: return offsetof(CPUAlphaState, unique);
 | |
|     case 11: return offsetof(CPUAlphaState, sysval);
 | |
|     case 12: return offsetof(CPUAlphaState, usp);
 | |
| 
 | |
|     case 32 ... 39:
 | |
|         return offsetof(CPUAlphaState, shadow[pr - 32]);
 | |
|     case 40 ... 63:
 | |
|         return offsetof(CPUAlphaState, scratch[pr - 40]);
 | |
| 
 | |
|     case 251:
 | |
|         return offsetof(CPUAlphaState, alarm_expire);
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_mfpr(int ra, int regno)
 | |
| {
 | |
|     int data = cpu_pr_data(regno);
 | |
| 
 | |
|     /* In our emulated PALcode, these processor registers have no
 | |
|        side effects from reading.  */
 | |
|     if (ra == 31) {
 | |
|         return NO_EXIT;
 | |
|     }
 | |
| 
 | |
|     /* Special help for VMTIME and WALLTIME.  */
 | |
|     if (regno == 250 || regno == 249) {
 | |
| 	void (*helper)(TCGv) = gen_helper_get_walltime;
 | |
| 	if (regno == 249) {
 | |
| 		helper = gen_helper_get_vmtime;
 | |
| 	}
 | |
|         if (use_icount) {
 | |
|             gen_io_start();
 | |
|             helper(cpu_ir[ra]);
 | |
|             gen_io_end();
 | |
|             return EXIT_PC_STALE;
 | |
|         } else {
 | |
|             helper(cpu_ir[ra]);
 | |
|             return NO_EXIT;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* The basic registers are data only, and unknown registers
 | |
|        are read-zero, write-ignore.  */
 | |
|     if (data == 0) {
 | |
|         tcg_gen_movi_i64(cpu_ir[ra], 0);
 | |
|     } else if (data & PR_BYTE) {
 | |
|         tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, data & ~PR_BYTE);
 | |
|     } else if (data & PR_LONG) {
 | |
|         tcg_gen_ld32s_i64(cpu_ir[ra], cpu_env, data & ~PR_LONG);
 | |
|     } else {
 | |
|         tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data);
 | |
|     }
 | |
|     return NO_EXIT;
 | |
| }
 | |
| 
 | |
| static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
 | |
| {
 | |
|     TCGv tmp;
 | |
|     int data;
 | |
| 
 | |
|     if (rb == 31) {
 | |
|         tmp = tcg_const_i64(0);
 | |
|     } else {
 | |
|         tmp = cpu_ir[rb];
 | |
|     }
 | |
| 
 | |
|     switch (regno) {
 | |
|     case 255:
 | |
|         /* TBIA */
 | |
|         gen_helper_tbia(cpu_env);
 | |
|         break;
 | |
| 
 | |
|     case 254:
 | |
|         /* TBIS */
 | |
|         gen_helper_tbis(cpu_env, tmp);
 | |
|         break;
 | |
| 
 | |
|     case 253:
 | |
|         /* WAIT */
 | |
|         tmp = tcg_const_i64(1);
 | |
|         tcg_gen_st32_i64(tmp, cpu_env, -offsetof(AlphaCPU, env) +
 | |
|                                        offsetof(CPUState, halted));
 | |
|         return gen_excp(ctx, EXCP_HLT, 0);
 | |
| 
 | |
|     case 252:
 | |
|         /* HALT */
 | |
|         gen_helper_halt(tmp);
 | |
|         return EXIT_PC_STALE;
 | |
| 
 | |
|     case 251:
 | |
|         /* ALARM */
 | |
|         gen_helper_set_alarm(cpu_env, tmp);
 | |
|         break;
 | |
| 
 | |
|     case 7:
 | |
|         /* PALBR */
 | |
|         tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUAlphaState, palbr));
 | |
|         /* Changing the PAL base register implies un-chaining all of the TBs
 | |
|            that ended with a CALL_PAL.  Since the base register usually only
 | |
|            changes during boot, flushing everything works well.  */
 | |
|         gen_helper_tb_flush(cpu_env);
 | |
|         return EXIT_PC_STALE;
 | |
| 
 | |
|     default:
 | |
|         /* The basic registers are data only, and unknown registers
 | |
|            are read-zero, write-ignore.  */
 | |
|         data = cpu_pr_data(regno);
 | |
|         if (data != 0) {
 | |
|             if (data & PR_BYTE) {
 | |
|                 tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
 | |
|             } else if (data & PR_LONG) {
 | |
|                 tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG);
 | |
|             } else {
 | |
|                 tcg_gen_st_i64(tmp, cpu_env, data);
 | |
|             }
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     if (rb == 31) {
 | |
|         tcg_temp_free(tmp);
 | |
|     }
 | |
| 
 | |
|     return NO_EXIT;
 | |
| }
 | |
| #endif /* !USER_ONLY*/
 | |
| 
 | |
| static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
 | |
| {
 | |
|     uint32_t palcode;
 | |
|     int32_t disp21, disp16;
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|     int32_t disp12;
 | |
| #endif
 | |
|     uint16_t fn11;
 | |
|     uint8_t opc, ra, rb, rc, fpfn, fn7, islit, real_islit;
 | |
|     uint8_t lit;
 | |
|     ExitStatus ret;
 | |
| 
 | |
|     /* Decode all instruction fields */
 | |
|     opc = insn >> 26;
 | |
|     ra = (insn >> 21) & 0x1F;
 | |
|     rb = (insn >> 16) & 0x1F;
 | |
|     rc = insn & 0x1F;
 | |
|     real_islit = islit = (insn >> 12) & 1;
 | |
|     if (rb == 31 && !islit) {
 | |
|         islit = 1;
 | |
|         lit = 0;
 | |
|     } else
 | |
|         lit = (insn >> 13) & 0xFF;
 | |
|     palcode = insn & 0x03FFFFFF;
 | |
|     disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11;
 | |
|     disp16 = (int16_t)(insn & 0x0000FFFF);
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|     disp12 = (int32_t)((insn & 0x00000FFF) << 20) >> 20;
 | |
| #endif
 | |
|     fn11 = (insn >> 5) & 0x000007FF;
 | |
|     fpfn = fn11 & 0x3F;
 | |
|     fn7 = (insn >> 5) & 0x0000007F;
 | |
|     LOG_DISAS("opc %02x ra %2d rb %2d rc %2d disp16 %6d\n",
 | |
|               opc, ra, rb, rc, disp16);
 | |
| 
 | |
|     ret = NO_EXIT;
 | |
|     switch (opc) {
 | |
|     case 0x00:
 | |
|         /* CALL_PAL */
 | |
|         ret = gen_call_pal(ctx, palcode);
 | |
|         break;
 | |
|     case 0x01:
 | |
|         /* OPC01 */
 | |
|         goto invalid_opc;
 | |
|     case 0x02:
 | |
|         /* OPC02 */
 | |
|         goto invalid_opc;
 | |
|     case 0x03:
 | |
|         /* OPC03 */
 | |
|         goto invalid_opc;
 | |
|     case 0x04:
 | |
|         /* OPC04 */
 | |
|         goto invalid_opc;
 | |
|     case 0x05:
 | |
|         /* OPC05 */
 | |
|         goto invalid_opc;
 | |
|     case 0x06:
 | |
|         /* OPC06 */
 | |
|         goto invalid_opc;
 | |
|     case 0x07:
 | |
|         /* OPC07 */
 | |
|         goto invalid_opc;
 | |
|     case 0x08:
 | |
|         /* LDA */
 | |
|         if (likely(ra != 31)) {
 | |
|             if (rb != 31)
 | |
|                 tcg_gen_addi_i64(cpu_ir[ra], cpu_ir[rb], disp16);
 | |
|             else
 | |
|                 tcg_gen_movi_i64(cpu_ir[ra], disp16);
 | |
|         }
 | |
|         break;
 | |
|     case 0x09:
 | |
|         /* LDAH */
 | |
|         if (likely(ra != 31)) {
 | |
|             if (rb != 31)
 | |
|                 tcg_gen_addi_i64(cpu_ir[ra], cpu_ir[rb], disp16 << 16);
 | |
|             else
 | |
|                 tcg_gen_movi_i64(cpu_ir[ra], disp16 << 16);
 | |
|         }
 | |
|         break;
 | |
|     case 0x0A:
 | |
|         /* LDBU */
 | |
|         if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
 | |
|             gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0);
 | |
|             break;
 | |
|         }
 | |
|         goto invalid_opc;
 | |
|     case 0x0B:
 | |
|         /* LDQ_U */
 | |
|         gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1);
 | |
|         break;
 | |
|     case 0x0C:
 | |
|         /* LDWU */
 | |
|         if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
 | |
|             gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0);
 | |
|             break;
 | |
|         }
 | |
|         goto invalid_opc;
 | |
|     case 0x0D:
 | |
|         /* STW */
 | |
|         gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0);
 | |
|         break;
 | |
|     case 0x0E:
 | |
|         /* STB */
 | |
|         gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, disp16, 0, 0);
 | |
|         break;
 | |
|     case 0x0F:
 | |
|         /* STQ_U */
 | |
|         gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 1);
 | |
|         break;
 | |
|     case 0x10:
 | |
|         switch (fn7) {
 | |
|         case 0x00:
 | |
|             /* ADDL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit) {
 | |
|                         tcg_gen_addi_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                         tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
 | |
|                     } else {
 | |
|                         tcg_gen_add_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                         tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
 | |
|                     }
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], lit);
 | |
|                     else
 | |
|                         tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x02:
 | |
|             /* S4ADDL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv tmp = tcg_temp_new();
 | |
|                     tcg_gen_shli_i64(tmp, cpu_ir[ra], 2);
 | |
|                     if (islit)
 | |
|                         tcg_gen_addi_i64(tmp, tmp, lit);
 | |
|                     else
 | |
|                         tcg_gen_add_i64(tmp, tmp, cpu_ir[rb]);
 | |
|                     tcg_gen_ext32s_i64(cpu_ir[rc], tmp);
 | |
|                     tcg_temp_free(tmp);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], lit);
 | |
|                     else
 | |
|                         tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x09:
 | |
|             /* SUBL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_subi_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                     else
 | |
|                         tcg_gen_sub_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                     tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], -lit);
 | |
|                     else {
 | |
|                         tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                         tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x0B:
 | |
|             /* S4SUBL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv tmp = tcg_temp_new();
 | |
|                     tcg_gen_shli_i64(tmp, cpu_ir[ra], 2);
 | |
|                     if (islit)
 | |
|                         tcg_gen_subi_i64(tmp, tmp, lit);
 | |
|                     else
 | |
|                         tcg_gen_sub_i64(tmp, tmp, cpu_ir[rb]);
 | |
|                     tcg_gen_ext32s_i64(cpu_ir[rc], tmp);
 | |
|                     tcg_temp_free(tmp);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], -lit);
 | |
|                     else {
 | |
|                         tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                         tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x0F:
 | |
|             /* CMPBGE */
 | |
|             gen_cmpbge(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x12:
 | |
|             /* S8ADDL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv tmp = tcg_temp_new();
 | |
|                     tcg_gen_shli_i64(tmp, cpu_ir[ra], 3);
 | |
|                     if (islit)
 | |
|                         tcg_gen_addi_i64(tmp, tmp, lit);
 | |
|                     else
 | |
|                         tcg_gen_add_i64(tmp, tmp, cpu_ir[rb]);
 | |
|                     tcg_gen_ext32s_i64(cpu_ir[rc], tmp);
 | |
|                     tcg_temp_free(tmp);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], lit);
 | |
|                     else
 | |
|                         tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x1B:
 | |
|             /* S8SUBL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv tmp = tcg_temp_new();
 | |
|                     tcg_gen_shli_i64(tmp, cpu_ir[ra], 3);
 | |
|                     if (islit)
 | |
|                         tcg_gen_subi_i64(tmp, tmp, lit);
 | |
|                     else
 | |
|                        tcg_gen_sub_i64(tmp, tmp, cpu_ir[rb]);
 | |
|                     tcg_gen_ext32s_i64(cpu_ir[rc], tmp);
 | |
|                     tcg_temp_free(tmp);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], -lit);
 | |
|                     else
 | |
|                         tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                         tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x1D:
 | |
|             /* CMPULT */
 | |
|             gen_cmp(TCG_COND_LTU, ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x20:
 | |
|             /* ADDQ */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_addi_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                     else
 | |
|                         tcg_gen_add_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], lit);
 | |
|                     else
 | |
|                         tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x22:
 | |
|             /* S4ADDQ */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv tmp = tcg_temp_new();
 | |
|                     tcg_gen_shli_i64(tmp, cpu_ir[ra], 2);
 | |
|                     if (islit)
 | |
|                         tcg_gen_addi_i64(cpu_ir[rc], tmp, lit);
 | |
|                     else
 | |
|                         tcg_gen_add_i64(cpu_ir[rc], tmp, cpu_ir[rb]);
 | |
|                     tcg_temp_free(tmp);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], lit);
 | |
|                     else
 | |
|                         tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x29:
 | |
|             /* SUBQ */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_subi_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                     else
 | |
|                         tcg_gen_sub_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], -lit);
 | |
|                     else
 | |
|                         tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x2B:
 | |
|             /* S4SUBQ */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv tmp = tcg_temp_new();
 | |
|                     tcg_gen_shli_i64(tmp, cpu_ir[ra], 2);
 | |
|                     if (islit)
 | |
|                         tcg_gen_subi_i64(cpu_ir[rc], tmp, lit);
 | |
|                     else
 | |
|                         tcg_gen_sub_i64(cpu_ir[rc], tmp, cpu_ir[rb]);
 | |
|                     tcg_temp_free(tmp);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], -lit);
 | |
|                     else
 | |
|                         tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x2D:
 | |
|             /* CMPEQ */
 | |
|             gen_cmp(TCG_COND_EQ, ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x32:
 | |
|             /* S8ADDQ */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv tmp = tcg_temp_new();
 | |
|                     tcg_gen_shli_i64(tmp, cpu_ir[ra], 3);
 | |
|                     if (islit)
 | |
|                         tcg_gen_addi_i64(cpu_ir[rc], tmp, lit);
 | |
|                     else
 | |
|                         tcg_gen_add_i64(cpu_ir[rc], tmp, cpu_ir[rb]);
 | |
|                     tcg_temp_free(tmp);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], lit);
 | |
|                     else
 | |
|                         tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x3B:
 | |
|             /* S8SUBQ */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv tmp = tcg_temp_new();
 | |
|                     tcg_gen_shli_i64(tmp, cpu_ir[ra], 3);
 | |
|                     if (islit)
 | |
|                         tcg_gen_subi_i64(cpu_ir[rc], tmp, lit);
 | |
|                     else
 | |
|                         tcg_gen_sub_i64(cpu_ir[rc], tmp, cpu_ir[rb]);
 | |
|                     tcg_temp_free(tmp);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], -lit);
 | |
|                     else
 | |
|                         tcg_gen_neg_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x3D:
 | |
|             /* CMPULE */
 | |
|             gen_cmp(TCG_COND_LEU, ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x40:
 | |
|             /* ADDL/V */
 | |
|             gen_addlv(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x49:
 | |
|             /* SUBL/V */
 | |
|             gen_sublv(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x4D:
 | |
|             /* CMPLT */
 | |
|             gen_cmp(TCG_COND_LT, ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x60:
 | |
|             /* ADDQ/V */
 | |
|             gen_addqv(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x69:
 | |
|             /* SUBQ/V */
 | |
|             gen_subqv(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x6D:
 | |
|             /* CMPLE */
 | |
|             gen_cmp(TCG_COND_LE, ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x11:
 | |
|         switch (fn7) {
 | |
|         case 0x00:
 | |
|             /* AND */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra == 31)
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|                 else if (islit)
 | |
|                     tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                 else
 | |
|                     tcg_gen_and_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|             }
 | |
|             break;
 | |
|         case 0x08:
 | |
|             /* BIC */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[ra], ~lit);
 | |
|                     else
 | |
|                         tcg_gen_andc_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                 } else
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|             }
 | |
|             break;
 | |
|         case 0x14:
 | |
|             /* CMOVLBS */
 | |
|             gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 1);
 | |
|             break;
 | |
|         case 0x16:
 | |
|             /* CMOVLBC */
 | |
|             gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 1);
 | |
|             break;
 | |
|         case 0x20:
 | |
|             /* BIS */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_ori_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                     else
 | |
|                         tcg_gen_or_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], lit);
 | |
|                     else
 | |
|                         tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x24:
 | |
|             /* CMOVEQ */
 | |
|             gen_cmov(TCG_COND_EQ, ra, rb, rc, islit, lit, 0);
 | |
|             break;
 | |
|         case 0x26:
 | |
|             /* CMOVNE */
 | |
|             gen_cmov(TCG_COND_NE, ra, rb, rc, islit, lit, 0);
 | |
|             break;
 | |
|         case 0x28:
 | |
|             /* ORNOT */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_ori_i64(cpu_ir[rc], cpu_ir[ra], ~lit);
 | |
|                     else
 | |
|                         tcg_gen_orc_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], ~lit);
 | |
|                     else
 | |
|                         tcg_gen_not_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x40:
 | |
|             /* XOR */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_xori_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                     else
 | |
|                         tcg_gen_xor_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], lit);
 | |
|                     else
 | |
|                         tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x44:
 | |
|             /* CMOVLT */
 | |
|             gen_cmov(TCG_COND_LT, ra, rb, rc, islit, lit, 0);
 | |
|             break;
 | |
|         case 0x46:
 | |
|             /* CMOVGE */
 | |
|             gen_cmov(TCG_COND_GE, ra, rb, rc, islit, lit, 0);
 | |
|             break;
 | |
|         case 0x48:
 | |
|             /* EQV */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_xori_i64(cpu_ir[rc], cpu_ir[ra], ~lit);
 | |
|                     else
 | |
|                         tcg_gen_eqv_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                 } else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], ~lit);
 | |
|                     else
 | |
|                         tcg_gen_not_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x61:
 | |
|             /* AMASK */
 | |
|             if (likely(rc != 31)) {
 | |
|                 uint64_t amask = ctx->tb->flags >> TB_FLAGS_AMASK_SHIFT;
 | |
| 
 | |
|                 if (islit) {
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], lit & ~amask);
 | |
|                 } else {
 | |
|                     tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[rb], ~amask);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x64:
 | |
|             /* CMOVLE */
 | |
|             gen_cmov(TCG_COND_LE, ra, rb, rc, islit, lit, 0);
 | |
|             break;
 | |
|         case 0x66:
 | |
|             /* CMOVGT */
 | |
|             gen_cmov(TCG_COND_GT, ra, rb, rc, islit, lit, 0);
 | |
|             break;
 | |
|         case 0x6C:
 | |
|             /* IMPLVER */
 | |
|             if (rc != 31) {
 | |
|                 tcg_gen_movi_i64(cpu_ir[rc], ctx->implver);
 | |
|             }
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x12:
 | |
|         switch (fn7) {
 | |
|         case 0x02:
 | |
|             /* MSKBL */
 | |
|             gen_msk_l(ra, rb, rc, islit, lit, 0x01);
 | |
|             break;
 | |
|         case 0x06:
 | |
|             /* EXTBL */
 | |
|             gen_ext_l(ra, rb, rc, islit, lit, 0x01);
 | |
|             break;
 | |
|         case 0x0B:
 | |
|             /* INSBL */
 | |
|             gen_ins_l(ra, rb, rc, islit, lit, 0x01);
 | |
|             break;
 | |
|         case 0x12:
 | |
|             /* MSKWL */
 | |
|             gen_msk_l(ra, rb, rc, islit, lit, 0x03);
 | |
|             break;
 | |
|         case 0x16:
 | |
|             /* EXTWL */
 | |
|             gen_ext_l(ra, rb, rc, islit, lit, 0x03);
 | |
|             break;
 | |
|         case 0x1B:
 | |
|             /* INSWL */
 | |
|             gen_ins_l(ra, rb, rc, islit, lit, 0x03);
 | |
|             break;
 | |
|         case 0x22:
 | |
|             /* MSKLL */
 | |
|             gen_msk_l(ra, rb, rc, islit, lit, 0x0f);
 | |
|             break;
 | |
|         case 0x26:
 | |
|             /* EXTLL */
 | |
|             gen_ext_l(ra, rb, rc, islit, lit, 0x0f);
 | |
|             break;
 | |
|         case 0x2B:
 | |
|             /* INSLL */
 | |
|             gen_ins_l(ra, rb, rc, islit, lit, 0x0f);
 | |
|             break;
 | |
|         case 0x30:
 | |
|             /* ZAP */
 | |
|             gen_zap(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x31:
 | |
|             /* ZAPNOT */
 | |
|             gen_zapnot(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x32:
 | |
|             /* MSKQL */
 | |
|             gen_msk_l(ra, rb, rc, islit, lit, 0xff);
 | |
|             break;
 | |
|         case 0x34:
 | |
|             /* SRL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_shri_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f);
 | |
|                     else {
 | |
|                         TCGv shift = tcg_temp_new();
 | |
|                         tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f);
 | |
|                         tcg_gen_shr_i64(cpu_ir[rc], cpu_ir[ra], shift);
 | |
|                         tcg_temp_free(shift);
 | |
|                     }
 | |
|                 } else
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|             }
 | |
|             break;
 | |
|         case 0x36:
 | |
|             /* EXTQL */
 | |
|             gen_ext_l(ra, rb, rc, islit, lit, 0xff);
 | |
|             break;
 | |
|         case 0x39:
 | |
|             /* SLL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_shli_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f);
 | |
|                     else {
 | |
|                         TCGv shift = tcg_temp_new();
 | |
|                         tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f);
 | |
|                         tcg_gen_shl_i64(cpu_ir[rc], cpu_ir[ra], shift);
 | |
|                         tcg_temp_free(shift);
 | |
|                     }
 | |
|                 } else
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|             }
 | |
|             break;
 | |
|         case 0x3B:
 | |
|             /* INSQL */
 | |
|             gen_ins_l(ra, rb, rc, islit, lit, 0xff);
 | |
|             break;
 | |
|         case 0x3C:
 | |
|             /* SRA */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     if (islit)
 | |
|                         tcg_gen_sari_i64(cpu_ir[rc], cpu_ir[ra], lit & 0x3f);
 | |
|                     else {
 | |
|                         TCGv shift = tcg_temp_new();
 | |
|                         tcg_gen_andi_i64(shift, cpu_ir[rb], 0x3f);
 | |
|                         tcg_gen_sar_i64(cpu_ir[rc], cpu_ir[ra], shift);
 | |
|                         tcg_temp_free(shift);
 | |
|                     }
 | |
|                 } else
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|             }
 | |
|             break;
 | |
|         case 0x52:
 | |
|             /* MSKWH */
 | |
|             gen_msk_h(ra, rb, rc, islit, lit, 0x03);
 | |
|             break;
 | |
|         case 0x57:
 | |
|             /* INSWH */
 | |
|             gen_ins_h(ra, rb, rc, islit, lit, 0x03);
 | |
|             break;
 | |
|         case 0x5A:
 | |
|             /* EXTWH */
 | |
|             gen_ext_h(ra, rb, rc, islit, lit, 0x03);
 | |
|             break;
 | |
|         case 0x62:
 | |
|             /* MSKLH */
 | |
|             gen_msk_h(ra, rb, rc, islit, lit, 0x0f);
 | |
|             break;
 | |
|         case 0x67:
 | |
|             /* INSLH */
 | |
|             gen_ins_h(ra, rb, rc, islit, lit, 0x0f);
 | |
|             break;
 | |
|         case 0x6A:
 | |
|             /* EXTLH */
 | |
|             gen_ext_h(ra, rb, rc, islit, lit, 0x0f);
 | |
|             break;
 | |
|         case 0x72:
 | |
|             /* MSKQH */
 | |
|             gen_msk_h(ra, rb, rc, islit, lit, 0xff);
 | |
|             break;
 | |
|         case 0x77:
 | |
|             /* INSQH */
 | |
|             gen_ins_h(ra, rb, rc, islit, lit, 0xff);
 | |
|             break;
 | |
|         case 0x7A:
 | |
|             /* EXTQH */
 | |
|             gen_ext_h(ra, rb, rc, islit, lit, 0xff);
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x13:
 | |
|         switch (fn7) {
 | |
|         case 0x00:
 | |
|             /* MULL */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra == 31)
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|                 else {
 | |
|                     if (islit)
 | |
|                         tcg_gen_muli_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                     else
 | |
|                         tcg_gen_mul_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                     tcg_gen_ext32s_i64(cpu_ir[rc], cpu_ir[rc]);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x20:
 | |
|             /* MULQ */
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra == 31)
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|                 else if (islit)
 | |
|                     tcg_gen_muli_i64(cpu_ir[rc], cpu_ir[ra], lit);
 | |
|                 else
 | |
|                     tcg_gen_mul_i64(cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|             }
 | |
|             break;
 | |
|         case 0x30:
 | |
|             /* UMULH */
 | |
|             {
 | |
|                 TCGv low;
 | |
|                 if (unlikely(rc == 31)){
 | |
|                     break;
 | |
|                 }
 | |
|                 if (ra == 31) {
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|                     break;
 | |
|                 }
 | |
|                 low = tcg_temp_new();
 | |
|                 if (islit) {
 | |
|                     tcg_gen_movi_tl(low, lit);
 | |
|                     tcg_gen_mulu2_i64(low, cpu_ir[rc], cpu_ir[ra], low);
 | |
|                 } else {
 | |
|                     tcg_gen_mulu2_i64(low, cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]);
 | |
|                 }
 | |
|                 tcg_temp_free(low);
 | |
|             }
 | |
|             break;
 | |
|         case 0x40:
 | |
|             /* MULL/V */
 | |
|             gen_mullv(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         case 0x60:
 | |
|             /* MULQ/V */
 | |
|             gen_mulqv(ra, rb, rc, islit, lit);
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x14:
 | |
|         switch (fpfn) { /* fn11 & 0x3F */
 | |
|         case 0x04:
 | |
|             /* ITOFS */
 | |
|             if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
 | |
|                 goto invalid_opc;
 | |
|             }
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv_i32 tmp = tcg_temp_new_i32();
 | |
|                     tcg_gen_trunc_i64_i32(tmp, cpu_ir[ra]);
 | |
|                     gen_helper_memory_to_s(cpu_fir[rc], tmp);
 | |
|                     tcg_temp_free_i32(tmp);
 | |
|                 } else
 | |
|                     tcg_gen_movi_i64(cpu_fir[rc], 0);
 | |
|             }
 | |
|             break;
 | |
|         case 0x0A:
 | |
|             /* SQRTF */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
 | |
|                 gen_fsqrtf(rb, rc);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x0B:
 | |
|             /* SQRTS */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
 | |
|                 gen_fsqrts(ctx, rb, rc, fn11);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x14:
 | |
|             /* ITOFF */
 | |
|             if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
 | |
|                 goto invalid_opc;
 | |
|             }
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31) {
 | |
|                     TCGv_i32 tmp = tcg_temp_new_i32();
 | |
|                     tcg_gen_trunc_i64_i32(tmp, cpu_ir[ra]);
 | |
|                     gen_helper_memory_to_f(cpu_fir[rc], tmp);
 | |
|                     tcg_temp_free_i32(tmp);
 | |
|                 } else
 | |
|                     tcg_gen_movi_i64(cpu_fir[rc], 0);
 | |
|             }
 | |
|             break;
 | |
|         case 0x24:
 | |
|             /* ITOFT */
 | |
|             if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
 | |
|                 goto invalid_opc;
 | |
|             }
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31)
 | |
|                     tcg_gen_mov_i64(cpu_fir[rc], cpu_ir[ra]);
 | |
|                 else
 | |
|                     tcg_gen_movi_i64(cpu_fir[rc], 0);
 | |
|             }
 | |
|             break;
 | |
|         case 0x2A:
 | |
|             /* SQRTG */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
 | |
|                 gen_fsqrtg(rb, rc);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x02B:
 | |
|             /* SQRTT */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
 | |
|                 gen_fsqrtt(ctx, rb, rc, fn11);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x15:
 | |
|         /* VAX floating point */
 | |
|         /* XXX: rounding mode and trap are ignored (!) */
 | |
|         switch (fpfn) { /* fn11 & 0x3F */
 | |
|         case 0x00:
 | |
|             /* ADDF */
 | |
|             gen_faddf(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x01:
 | |
|             /* SUBF */
 | |
|             gen_fsubf(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x02:
 | |
|             /* MULF */
 | |
|             gen_fmulf(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x03:
 | |
|             /* DIVF */
 | |
|             gen_fdivf(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x1E:
 | |
|             /* CVTDG */
 | |
| #if 0 // TODO
 | |
|             gen_fcvtdg(rb, rc);
 | |
| #else
 | |
|             goto invalid_opc;
 | |
| #endif
 | |
|             break;
 | |
|         case 0x20:
 | |
|             /* ADDG */
 | |
|             gen_faddg(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x21:
 | |
|             /* SUBG */
 | |
|             gen_fsubg(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x22:
 | |
|             /* MULG */
 | |
|             gen_fmulg(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x23:
 | |
|             /* DIVG */
 | |
|             gen_fdivg(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x25:
 | |
|             /* CMPGEQ */
 | |
|             gen_fcmpgeq(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x26:
 | |
|             /* CMPGLT */
 | |
|             gen_fcmpglt(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x27:
 | |
|             /* CMPGLE */
 | |
|             gen_fcmpgle(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x2C:
 | |
|             /* CVTGF */
 | |
|             gen_fcvtgf(rb, rc);
 | |
|             break;
 | |
|         case 0x2D:
 | |
|             /* CVTGD */
 | |
| #if 0 // TODO
 | |
|             gen_fcvtgd(rb, rc);
 | |
| #else
 | |
|             goto invalid_opc;
 | |
| #endif
 | |
|             break;
 | |
|         case 0x2F:
 | |
|             /* CVTGQ */
 | |
|             gen_fcvtgq(rb, rc);
 | |
|             break;
 | |
|         case 0x3C:
 | |
|             /* CVTQF */
 | |
|             gen_fcvtqf(rb, rc);
 | |
|             break;
 | |
|         case 0x3E:
 | |
|             /* CVTQG */
 | |
|             gen_fcvtqg(rb, rc);
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x16:
 | |
|         /* IEEE floating-point */
 | |
|         switch (fpfn) { /* fn11 & 0x3F */
 | |
|         case 0x00:
 | |
|             /* ADDS */
 | |
|             gen_fadds(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x01:
 | |
|             /* SUBS */
 | |
|             gen_fsubs(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x02:
 | |
|             /* MULS */
 | |
|             gen_fmuls(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x03:
 | |
|             /* DIVS */
 | |
|             gen_fdivs(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x20:
 | |
|             /* ADDT */
 | |
|             gen_faddt(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x21:
 | |
|             /* SUBT */
 | |
|             gen_fsubt(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x22:
 | |
|             /* MULT */
 | |
|             gen_fmult(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x23:
 | |
|             /* DIVT */
 | |
|             gen_fdivt(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x24:
 | |
|             /* CMPTUN */
 | |
|             gen_fcmptun(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x25:
 | |
|             /* CMPTEQ */
 | |
|             gen_fcmpteq(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x26:
 | |
|             /* CMPTLT */
 | |
|             gen_fcmptlt(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x27:
 | |
|             /* CMPTLE */
 | |
|             gen_fcmptle(ctx, ra, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x2C:
 | |
|             if (fn11 == 0x2AC || fn11 == 0x6AC) {
 | |
|                 /* CVTST */
 | |
|                 gen_fcvtst(ctx, rb, rc, fn11);
 | |
|             } else {
 | |
|                 /* CVTTS */
 | |
|                 gen_fcvtts(ctx, rb, rc, fn11);
 | |
|             }
 | |
|             break;
 | |
|         case 0x2F:
 | |
|             /* CVTTQ */
 | |
|             gen_fcvttq(ctx, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x3C:
 | |
|             /* CVTQS */
 | |
|             gen_fcvtqs(ctx, rb, rc, fn11);
 | |
|             break;
 | |
|         case 0x3E:
 | |
|             /* CVTQT */
 | |
|             gen_fcvtqt(ctx, rb, rc, fn11);
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x17:
 | |
|         switch (fn11) {
 | |
|         case 0x010:
 | |
|             /* CVTLQ */
 | |
|             gen_fcvtlq(rb, rc);
 | |
|             break;
 | |
|         case 0x020:
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra == rb) {
 | |
|                     /* FMOV */
 | |
|                     if (ra == 31)
 | |
|                         tcg_gen_movi_i64(cpu_fir[rc], 0);
 | |
|                     else
 | |
|                         tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[ra]);
 | |
|                 } else {
 | |
|                     /* CPYS */
 | |
|                     gen_fcpys(ra, rb, rc);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0x021:
 | |
|             /* CPYSN */
 | |
|             gen_fcpysn(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x022:
 | |
|             /* CPYSE */
 | |
|             gen_fcpyse(ra, rb, rc);
 | |
|             break;
 | |
|         case 0x024:
 | |
|             /* MT_FPCR */
 | |
|             if (likely(ra != 31))
 | |
|                 gen_helper_store_fpcr(cpu_env, cpu_fir[ra]);
 | |
|             else {
 | |
|                 TCGv tmp = tcg_const_i64(0);
 | |
|                 gen_helper_store_fpcr(cpu_env, tmp);
 | |
|                 tcg_temp_free(tmp);
 | |
|             }
 | |
|             break;
 | |
|         case 0x025:
 | |
|             /* MF_FPCR */
 | |
|             if (likely(ra != 31))
 | |
|                 gen_helper_load_fpcr(cpu_fir[ra], cpu_env);
 | |
|             break;
 | |
|         case 0x02A:
 | |
|             /* FCMOVEQ */
 | |
|             gen_fcmov(TCG_COND_EQ, ra, rb, rc);
 | |
|             break;
 | |
|         case 0x02B:
 | |
|             /* FCMOVNE */
 | |
|             gen_fcmov(TCG_COND_NE, ra, rb, rc);
 | |
|             break;
 | |
|         case 0x02C:
 | |
|             /* FCMOVLT */
 | |
|             gen_fcmov(TCG_COND_LT, ra, rb, rc);
 | |
|             break;
 | |
|         case 0x02D:
 | |
|             /* FCMOVGE */
 | |
|             gen_fcmov(TCG_COND_GE, ra, rb, rc);
 | |
|             break;
 | |
|         case 0x02E:
 | |
|             /* FCMOVLE */
 | |
|             gen_fcmov(TCG_COND_LE, ra, rb, rc);
 | |
|             break;
 | |
|         case 0x02F:
 | |
|             /* FCMOVGT */
 | |
|             gen_fcmov(TCG_COND_GT, ra, rb, rc);
 | |
|             break;
 | |
|         case 0x030:
 | |
|             /* CVTQL */
 | |
|             gen_fcvtql(rb, rc);
 | |
|             break;
 | |
|         case 0x130:
 | |
|             /* CVTQL/V */
 | |
|         case 0x530:
 | |
|             /* CVTQL/SV */
 | |
|             /* ??? I'm pretty sure there's nothing that /sv needs to do that
 | |
|                /v doesn't do.  The only thing I can think is that /sv is a
 | |
|                valid instruction merely for completeness in the ISA.  */
 | |
|             gen_fcvtql_v(ctx, rb, rc);
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x18:
 | |
|         switch ((uint16_t)disp16) {
 | |
|         case 0x0000:
 | |
|             /* TRAPB */
 | |
|             /* No-op.  */
 | |
|             break;
 | |
|         case 0x0400:
 | |
|             /* EXCB */
 | |
|             /* No-op.  */
 | |
|             break;
 | |
|         case 0x4000:
 | |
|             /* MB */
 | |
|             /* No-op */
 | |
|             break;
 | |
|         case 0x4400:
 | |
|             /* WMB */
 | |
|             /* No-op */
 | |
|             break;
 | |
|         case 0x8000:
 | |
|             /* FETCH */
 | |
|             /* No-op */
 | |
|             break;
 | |
|         case 0xA000:
 | |
|             /* FETCH_M */
 | |
|             /* No-op */
 | |
|             break;
 | |
|         case 0xC000:
 | |
|             /* RPCC */
 | |
|             if (ra != 31) {
 | |
|                 if (use_icount) {
 | |
|                     gen_io_start();
 | |
|                     gen_helper_load_pcc(cpu_ir[ra], cpu_env);
 | |
|                     gen_io_end();
 | |
|                     ret = EXIT_PC_STALE;
 | |
|                 } else {
 | |
|                     gen_helper_load_pcc(cpu_ir[ra], cpu_env);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         case 0xE000:
 | |
|             /* RC */
 | |
|             gen_rx(ra, 0);
 | |
|             break;
 | |
|         case 0xE800:
 | |
|             /* ECB */
 | |
|             break;
 | |
|         case 0xF000:
 | |
|             /* RS */
 | |
|             gen_rx(ra, 1);
 | |
|             break;
 | |
|         case 0xF800:
 | |
|             /* WH64 */
 | |
|             /* No-op */
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x19:
 | |
|         /* HW_MFPR (PALcode) */
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|         if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
 | |
|             return gen_mfpr(ra, insn & 0xffff);
 | |
|         }
 | |
| #endif
 | |
|         goto invalid_opc;
 | |
|     case 0x1A:
 | |
|         /* JMP, JSR, RET, JSR_COROUTINE.  These only differ by the branch
 | |
|            prediction stack action, which of course we don't implement.  */
 | |
|         if (rb != 31) {
 | |
|             tcg_gen_andi_i64(cpu_pc, cpu_ir[rb], ~3);
 | |
|         } else {
 | |
|             tcg_gen_movi_i64(cpu_pc, 0);
 | |
|         }
 | |
|         if (ra != 31) {
 | |
|             tcg_gen_movi_i64(cpu_ir[ra], ctx->pc);
 | |
|         }
 | |
|         ret = EXIT_PC_UPDATED;
 | |
|         break;
 | |
|     case 0x1B:
 | |
|         /* HW_LD (PALcode) */
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|         if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
 | |
|             TCGv addr;
 | |
| 
 | |
|             if (ra == 31) {
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             addr = tcg_temp_new();
 | |
|             if (rb != 31)
 | |
|                 tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
 | |
|             else
 | |
|                 tcg_gen_movi_i64(addr, disp12);
 | |
|             switch ((insn >> 12) & 0xF) {
 | |
|             case 0x0:
 | |
|                 /* Longword physical access (hw_ldl/p) */
 | |
|                 gen_helper_ldl_phys(cpu_ir[ra], addr);
 | |
|                 break;
 | |
|             case 0x1:
 | |
|                 /* Quadword physical access (hw_ldq/p) */
 | |
|                 gen_helper_ldq_phys(cpu_ir[ra], addr);
 | |
|                 break;
 | |
|             case 0x2:
 | |
|                 /* Longword physical access with lock (hw_ldl_l/p) */
 | |
|                 gen_helper_ldl_l_phys(cpu_ir[ra], cpu_env, addr);
 | |
|                 break;
 | |
|             case 0x3:
 | |
|                 /* Quadword physical access with lock (hw_ldq_l/p) */
 | |
|                 gen_helper_ldq_l_phys(cpu_ir[ra], cpu_env, addr);
 | |
|                 break;
 | |
|             case 0x4:
 | |
|                 /* Longword virtual PTE fetch (hw_ldl/v) */
 | |
|                 goto invalid_opc;
 | |
|             case 0x5:
 | |
|                 /* Quadword virtual PTE fetch (hw_ldq/v) */
 | |
|                 goto invalid_opc;
 | |
|                 break;
 | |
|             case 0x6:
 | |
|                 /* Incpu_ir[ra]id */
 | |
|                 goto invalid_opc;
 | |
|             case 0x7:
 | |
|                 /* Incpu_ir[ra]id */
 | |
|                 goto invalid_opc;
 | |
|             case 0x8:
 | |
|                 /* Longword virtual access (hw_ldl) */
 | |
|                 goto invalid_opc;
 | |
|             case 0x9:
 | |
|                 /* Quadword virtual access (hw_ldq) */
 | |
|                 goto invalid_opc;
 | |
|             case 0xA:
 | |
|                 /* Longword virtual access with protection check (hw_ldl/w) */
 | |
|                 tcg_gen_qemu_ld_i64(cpu_ir[ra], addr, MMU_KERNEL_IDX, MO_LESL);
 | |
|                 break;
 | |
|             case 0xB:
 | |
|                 /* Quadword virtual access with protection check (hw_ldq/w) */
 | |
|                 tcg_gen_qemu_ld_i64(cpu_ir[ra], addr, MMU_KERNEL_IDX, MO_LEQ);
 | |
|                 break;
 | |
|             case 0xC:
 | |
|                 /* Longword virtual access with alt access mode (hw_ldl/a)*/
 | |
|                 goto invalid_opc;
 | |
|             case 0xD:
 | |
|                 /* Quadword virtual access with alt access mode (hw_ldq/a) */
 | |
|                 goto invalid_opc;
 | |
|             case 0xE:
 | |
|                 /* Longword virtual access with alternate access mode and
 | |
|                    protection checks (hw_ldl/wa) */
 | |
|                 tcg_gen_qemu_ld_i64(cpu_ir[ra], addr, MMU_USER_IDX, MO_LESL);
 | |
|                 break;
 | |
|             case 0xF:
 | |
|                 /* Quadword virtual access with alternate access mode and
 | |
|                    protection checks (hw_ldq/wa) */
 | |
|                 tcg_gen_qemu_ld_i64(cpu_ir[ra], addr, MMU_USER_IDX, MO_LEQ);
 | |
|                 break;
 | |
|             }
 | |
|             tcg_temp_free(addr);
 | |
|             break;
 | |
|         }
 | |
| #endif
 | |
|         goto invalid_opc;
 | |
|     case 0x1C:
 | |
|         switch (fn7) {
 | |
|         case 0x00:
 | |
|             /* SEXTB */
 | |
|             if ((ctx->tb->flags & TB_FLAGS_AMASK_BWX) == 0) {
 | |
|                 goto invalid_opc;
 | |
|             }
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (islit)
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int8_t)lit));
 | |
|                 else
 | |
|                     tcg_gen_ext8s_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|             }
 | |
|             break;
 | |
|         case 0x01:
 | |
|             /* SEXTW */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
 | |
|                 if (likely(rc != 31)) {
 | |
|                     if (islit) {
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit));
 | |
|                     } else {
 | |
|                         tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]);
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x30:
 | |
|             /* CTPOP */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
 | |
|                 if (likely(rc != 31)) {
 | |
|                     if (islit) {
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit));
 | |
|                     } else {
 | |
|                         gen_helper_ctpop(cpu_ir[rc], cpu_ir[rb]);
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x31:
 | |
|             /* PERR */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_perr(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x32:
 | |
|             /* CTLZ */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
 | |
|                 if (likely(rc != 31)) {
 | |
|                     if (islit) {
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], clz64(lit));
 | |
|                     } else {
 | |
|                         gen_helper_ctlz(cpu_ir[rc], cpu_ir[rb]);
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x33:
 | |
|             /* CTTZ */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
 | |
|                 if (likely(rc != 31)) {
 | |
|                     if (islit) {
 | |
|                         tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit));
 | |
|                     } else {
 | |
|                         gen_helper_cttz(cpu_ir[rc], cpu_ir[rb]);
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x34:
 | |
|             /* UNPKBW */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 if (real_islit || ra != 31) {
 | |
|                     goto invalid_opc;
 | |
|                 }
 | |
|                 gen_unpkbw(rb, rc);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x35:
 | |
|             /* UNPKBL */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 if (real_islit || ra != 31) {
 | |
|                     goto invalid_opc;
 | |
|                 }
 | |
|                 gen_unpkbl(rb, rc);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x36:
 | |
|             /* PKWB */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 if (real_islit || ra != 31) {
 | |
|                     goto invalid_opc;
 | |
|                 }
 | |
|                 gen_pkwb(rb, rc);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x37:
 | |
|             /* PKLB */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 if (real_islit || ra != 31) {
 | |
|                     goto invalid_opc;
 | |
|                 }
 | |
|                 gen_pklb(rb, rc);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x38:
 | |
|             /* MINSB8 */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_minsb8(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x39:
 | |
|             /* MINSW4 */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_minsw4(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x3A:
 | |
|             /* MINUB8 */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_minub8(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x3B:
 | |
|             /* MINUW4 */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_minuw4(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x3C:
 | |
|             /* MAXUB8 */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_maxub8(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x3D:
 | |
|             /* MAXUW4 */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_maxuw4(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x3E:
 | |
|             /* MAXSB8 */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_maxsb8(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x3F:
 | |
|             /* MAXSW4 */
 | |
|             if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
 | |
|                 gen_maxsw4(ra, rb, rc, islit, lit);
 | |
|                 break;
 | |
|             }
 | |
|             goto invalid_opc;
 | |
|         case 0x70:
 | |
|             /* FTOIT */
 | |
|             if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
 | |
|                 goto invalid_opc;
 | |
|             }
 | |
|             if (likely(rc != 31)) {
 | |
|                 if (ra != 31)
 | |
|                     tcg_gen_mov_i64(cpu_ir[rc], cpu_fir[ra]);
 | |
|                 else
 | |
|                     tcg_gen_movi_i64(cpu_ir[rc], 0);
 | |
|             }
 | |
|             break;
 | |
|         case 0x78:
 | |
|             /* FTOIS */
 | |
|             if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
 | |
|                 goto invalid_opc;
 | |
|             }
 | |
|             if (rc != 31) {
 | |
|                 TCGv_i32 tmp1 = tcg_temp_new_i32();
 | |
|                 if (ra != 31)
 | |
|                     gen_helper_s_to_memory(tmp1, cpu_fir[ra]);
 | |
|                 else {
 | |
|                     TCGv tmp2 = tcg_const_i64(0);
 | |
|                     gen_helper_s_to_memory(tmp1, tmp2);
 | |
|                     tcg_temp_free(tmp2);
 | |
|                 }
 | |
|                 tcg_gen_ext_i32_i64(cpu_ir[rc], tmp1);
 | |
|                 tcg_temp_free_i32(tmp1);
 | |
|             }
 | |
|             break;
 | |
|         default:
 | |
|             goto invalid_opc;
 | |
|         }
 | |
|         break;
 | |
|     case 0x1D:
 | |
|         /* HW_MTPR (PALcode) */
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|         if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
 | |
|             return gen_mtpr(ctx, rb, insn & 0xffff);
 | |
|         }
 | |
| #endif
 | |
|         goto invalid_opc;
 | |
|     case 0x1E:
 | |
|         /* HW_RET (PALcode) */
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|         if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
 | |
|             if (rb == 31) {
 | |
|                 /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return
 | |
|                    address from EXC_ADDR.  This turns out to be useful for our
 | |
|                    emulation PALcode, so continue to accept it.  */
 | |
|                 TCGv tmp = tcg_temp_new();
 | |
|                 tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUAlphaState, exc_addr));
 | |
|                 gen_helper_hw_ret(cpu_env, tmp);
 | |
|                 tcg_temp_free(tmp);
 | |
|             } else {
 | |
|                 gen_helper_hw_ret(cpu_env, cpu_ir[rb]);
 | |
|             }
 | |
|             ret = EXIT_PC_UPDATED;
 | |
|             break;
 | |
|         }
 | |
| #endif
 | |
|         goto invalid_opc;
 | |
|     case 0x1F:
 | |
|         /* HW_ST (PALcode) */
 | |
| #ifndef CONFIG_USER_ONLY
 | |
|         if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
 | |
|             TCGv addr, val;
 | |
|             addr = tcg_temp_new();
 | |
|             if (rb != 31)
 | |
|                 tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
 | |
|             else
 | |
|                 tcg_gen_movi_i64(addr, disp12);
 | |
|             if (ra != 31)
 | |
|                 val = cpu_ir[ra];
 | |
|             else {
 | |
|                 val = tcg_temp_new();
 | |
|                 tcg_gen_movi_i64(val, 0);
 | |
|             }
 | |
|             switch ((insn >> 12) & 0xF) {
 | |
|             case 0x0:
 | |
|                 /* Longword physical access */
 | |
|                 gen_helper_stl_phys(addr, val);
 | |
|                 break;
 | |
|             case 0x1:
 | |
|                 /* Quadword physical access */
 | |
|                 gen_helper_stq_phys(addr, val);
 | |
|                 break;
 | |
|             case 0x2:
 | |
|                 /* Longword physical access with lock */
 | |
|                 gen_helper_stl_c_phys(val, cpu_env, addr, val);
 | |
|                 break;
 | |
|             case 0x3:
 | |
|                 /* Quadword physical access with lock */
 | |
|                 gen_helper_stq_c_phys(val, cpu_env, addr, val);
 | |
|                 break;
 | |
|             case 0x4:
 | |
|                 /* Longword virtual access */
 | |
|                 goto invalid_opc;
 | |
|             case 0x5:
 | |
|                 /* Quadword virtual access */
 | |
|                 goto invalid_opc;
 | |
|             case 0x6:
 | |
|                 /* Invalid */
 | |
|                 goto invalid_opc;
 | |
|             case 0x7:
 | |
|                 /* Invalid */
 | |
|                 goto invalid_opc;
 | |
|             case 0x8:
 | |
|                 /* Invalid */
 | |
|                 goto invalid_opc;
 | |
|             case 0x9:
 | |
|                 /* Invalid */
 | |
|                 goto invalid_opc;
 | |
|             case 0xA:
 | |
|                 /* Invalid */
 | |
|                 goto invalid_opc;
 | |
|             case 0xB:
 | |
|                 /* Invalid */
 | |
|                 goto invalid_opc;
 | |
|             case 0xC:
 | |
|                 /* Longword virtual access with alternate access mode */
 | |
|                 goto invalid_opc;
 | |
|             case 0xD:
 | |
|                 /* Quadword virtual access with alternate access mode */
 | |
|                 goto invalid_opc;
 | |
|             case 0xE:
 | |
|                 /* Invalid */
 | |
|                 goto invalid_opc;
 | |
|             case 0xF:
 | |
|                 /* Invalid */
 | |
|                 goto invalid_opc;
 | |
|             }
 | |
|             if (ra == 31)
 | |
|                 tcg_temp_free(val);
 | |
|             tcg_temp_free(addr);
 | |
|             break;
 | |
|         }
 | |
| #endif
 | |
|         goto invalid_opc;
 | |
|     case 0x20:
 | |
|         /* LDF */
 | |
|         gen_load_mem(ctx, &gen_qemu_ldf, ra, rb, disp16, 1, 0);
 | |
|         break;
 | |
|     case 0x21:
 | |
|         /* LDG */
 | |
|         gen_load_mem(ctx, &gen_qemu_ldg, ra, rb, disp16, 1, 0);
 | |
|         break;
 | |
|     case 0x22:
 | |
|         /* LDS */
 | |
|         gen_load_mem(ctx, &gen_qemu_lds, ra, rb, disp16, 1, 0);
 | |
|         break;
 | |
|     case 0x23:
 | |
|         /* LDT */
 | |
|         gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 1, 0);
 | |
|         break;
 | |
|     case 0x24:
 | |
|         /* STF */
 | |
|         gen_store_mem(ctx, &gen_qemu_stf, ra, rb, disp16, 1, 0);
 | |
|         break;
 | |
|     case 0x25:
 | |
|         /* STG */
 | |
|         gen_store_mem(ctx, &gen_qemu_stg, ra, rb, disp16, 1, 0);
 | |
|         break;
 | |
|     case 0x26:
 | |
|         /* STS */
 | |
|         gen_store_mem(ctx, &gen_qemu_sts, ra, rb, disp16, 1, 0);
 | |
|         break;
 | |
|     case 0x27:
 | |
|         /* STT */
 | |
|         gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 1, 0);
 | |
|         break;
 | |
|     case 0x28:
 | |
|         /* LDL */
 | |
|         gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, disp16, 0, 0);
 | |
|         break;
 | |
|     case 0x29:
 | |
|         /* LDQ */
 | |
|         gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 0);
 | |
|         break;
 | |
|     case 0x2A:
 | |
|         /* LDL_L */
 | |
|         gen_load_mem(ctx, &gen_qemu_ldl_l, ra, rb, disp16, 0, 0);
 | |
|         break;
 | |
|     case 0x2B:
 | |
|         /* LDQ_L */
 | |
|         gen_load_mem(ctx, &gen_qemu_ldq_l, ra, rb, disp16, 0, 0);
 | |
|         break;
 | |
|     case 0x2C:
 | |
|         /* STL */
 | |
|         gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, disp16, 0, 0);
 | |
|         break;
 | |
|     case 0x2D:
 | |
|         /* STQ */
 | |
|         gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 0);
 | |
|         break;
 | |
|     case 0x2E:
 | |
|         /* STL_C */
 | |
|         ret = gen_store_conditional(ctx, ra, rb, disp16, 0);
 | |
|         break;
 | |
|     case 0x2F:
 | |
|         /* STQ_C */
 | |
|         ret = gen_store_conditional(ctx, ra, rb, disp16, 1);
 | |
|         break;
 | |
|     case 0x30:
 | |
|         /* BR */
 | |
|         ret = gen_bdirect(ctx, ra, disp21);
 | |
|         break;
 | |
|     case 0x31: /* FBEQ */
 | |
|         ret = gen_fbcond(ctx, TCG_COND_EQ, ra, disp21);
 | |
|         break;
 | |
|     case 0x32: /* FBLT */
 | |
|         ret = gen_fbcond(ctx, TCG_COND_LT, ra, disp21);
 | |
|         break;
 | |
|     case 0x33: /* FBLE */
 | |
|         ret = gen_fbcond(ctx, TCG_COND_LE, ra, disp21);
 | |
|         break;
 | |
|     case 0x34:
 | |
|         /* BSR */
 | |
|         ret = gen_bdirect(ctx, ra, disp21);
 | |
|         break;
 | |
|     case 0x35: /* FBNE */
 | |
|         ret = gen_fbcond(ctx, TCG_COND_NE, ra, disp21);
 | |
|         break;
 | |
|     case 0x36: /* FBGE */
 | |
|         ret = gen_fbcond(ctx, TCG_COND_GE, ra, disp21);
 | |
|         break;
 | |
|     case 0x37: /* FBGT */
 | |
|         ret = gen_fbcond(ctx, TCG_COND_GT, ra, disp21);
 | |
|         break;
 | |
|     case 0x38:
 | |
|         /* BLBC */
 | |
|         ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 1);
 | |
|         break;
 | |
|     case 0x39:
 | |
|         /* BEQ */
 | |
|         ret = gen_bcond(ctx, TCG_COND_EQ, ra, disp21, 0);
 | |
|         break;
 | |
|     case 0x3A:
 | |
|         /* BLT */
 | |
|         ret = gen_bcond(ctx, TCG_COND_LT, ra, disp21, 0);
 | |
|         break;
 | |
|     case 0x3B:
 | |
|         /* BLE */
 | |
|         ret = gen_bcond(ctx, TCG_COND_LE, ra, disp21, 0);
 | |
|         break;
 | |
|     case 0x3C:
 | |
|         /* BLBS */
 | |
|         ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 1);
 | |
|         break;
 | |
|     case 0x3D:
 | |
|         /* BNE */
 | |
|         ret = gen_bcond(ctx, TCG_COND_NE, ra, disp21, 0);
 | |
|         break;
 | |
|     case 0x3E:
 | |
|         /* BGE */
 | |
|         ret = gen_bcond(ctx, TCG_COND_GE, ra, disp21, 0);
 | |
|         break;
 | |
|     case 0x3F:
 | |
|         /* BGT */
 | |
|         ret = gen_bcond(ctx, TCG_COND_GT, ra, disp21, 0);
 | |
|         break;
 | |
|     invalid_opc:
 | |
|         ret = gen_invalid(ctx);
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static inline void gen_intermediate_code_internal(AlphaCPU *cpu,
 | |
|                                                   TranslationBlock *tb,
 | |
|                                                   bool search_pc)
 | |
| {
 | |
|     CPUState *cs = CPU(cpu);
 | |
|     CPUAlphaState *env = &cpu->env;
 | |
|     DisasContext ctx, *ctxp = &ctx;
 | |
|     target_ulong pc_start;
 | |
|     target_ulong pc_mask;
 | |
|     uint32_t insn;
 | |
|     uint16_t *gen_opc_end;
 | |
|     CPUBreakpoint *bp;
 | |
|     int j, lj = -1;
 | |
|     ExitStatus ret;
 | |
|     int num_insns;
 | |
|     int max_insns;
 | |
| 
 | |
|     pc_start = tb->pc;
 | |
|     gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
 | |
| 
 | |
|     ctx.tb = tb;
 | |
|     ctx.pc = pc_start;
 | |
|     ctx.mem_idx = cpu_mmu_index(env);
 | |
|     ctx.implver = env->implver;
 | |
|     ctx.singlestep_enabled = cs->singlestep_enabled;
 | |
| 
 | |
|     /* ??? Every TB begins with unset rounding mode, to be initialized on
 | |
|        the first fp insn of the TB.  Alternately we could define a proper
 | |
|        default for every TB (e.g. QUAL_RM_N or QUAL_RM_D) and make sure
 | |
|        to reset the FP_STATUS to that default at the end of any TB that
 | |
|        changes the default.  We could even (gasp) dynamiclly figure out
 | |
|        what default would be most efficient given the running program.  */
 | |
|     ctx.tb_rm = -1;
 | |
|     /* Similarly for flush-to-zero.  */
 | |
|     ctx.tb_ftz = -1;
 | |
| 
 | |
|     num_insns = 0;
 | |
|     max_insns = tb->cflags & CF_COUNT_MASK;
 | |
|     if (max_insns == 0) {
 | |
|         max_insns = CF_COUNT_MASK;
 | |
|     }
 | |
| 
 | |
|     if (in_superpage(&ctx, pc_start)) {
 | |
|         pc_mask = (1ULL << 41) - 1;
 | |
|     } else {
 | |
|         pc_mask = ~TARGET_PAGE_MASK;
 | |
|     }
 | |
| 
 | |
|     gen_tb_start();
 | |
|     do {
 | |
|         if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
 | |
|             QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
 | |
|                 if (bp->pc == ctx.pc) {
 | |
|                     gen_excp(&ctx, EXCP_DEBUG, 0);
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if (search_pc) {
 | |
|             j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
 | |
|             if (lj < j) {
 | |
|                 lj++;
 | |
|                 while (lj < j)
 | |
|                     tcg_ctx.gen_opc_instr_start[lj++] = 0;
 | |
|             }
 | |
|             tcg_ctx.gen_opc_pc[lj] = ctx.pc;
 | |
|             tcg_ctx.gen_opc_instr_start[lj] = 1;
 | |
|             tcg_ctx.gen_opc_icount[lj] = num_insns;
 | |
|         }
 | |
|         if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
 | |
|             gen_io_start();
 | |
|         insn = cpu_ldl_code(env, ctx.pc);
 | |
|         num_insns++;
 | |
| 
 | |
| 	if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
 | |
|             tcg_gen_debug_insn_start(ctx.pc);
 | |
|         }
 | |
| 
 | |
|         ctx.pc += 4;
 | |
|         ret = translate_one(ctxp, insn);
 | |
| 
 | |
|         /* If we reach a page boundary, are single stepping,
 | |
|            or exhaust instruction count, stop generation.  */
 | |
|         if (ret == NO_EXIT
 | |
|             && ((ctx.pc & pc_mask) == 0
 | |
|                 || tcg_ctx.gen_opc_ptr >= gen_opc_end
 | |
|                 || num_insns >= max_insns
 | |
|                 || singlestep
 | |
|                 || ctx.singlestep_enabled)) {
 | |
|             ret = EXIT_PC_STALE;
 | |
|         }
 | |
|     } while (ret == NO_EXIT);
 | |
| 
 | |
|     if (tb->cflags & CF_LAST_IO) {
 | |
|         gen_io_end();
 | |
|     }
 | |
| 
 | |
|     switch (ret) {
 | |
|     case EXIT_GOTO_TB:
 | |
|     case EXIT_NORETURN:
 | |
|         break;
 | |
|     case EXIT_PC_STALE:
 | |
|         tcg_gen_movi_i64(cpu_pc, ctx.pc);
 | |
|         /* FALLTHRU */
 | |
|     case EXIT_PC_UPDATED:
 | |
|         if (ctx.singlestep_enabled) {
 | |
|             gen_excp_1(EXCP_DEBUG, 0);
 | |
|         } else {
 | |
|             tcg_gen_exit_tb(0);
 | |
|         }
 | |
|         break;
 | |
|     default:
 | |
|         abort();
 | |
|     }
 | |
| 
 | |
|     gen_tb_end(tb, num_insns);
 | |
|     *tcg_ctx.gen_opc_ptr = INDEX_op_end;
 | |
|     if (search_pc) {
 | |
|         j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
 | |
|         lj++;
 | |
|         while (lj <= j)
 | |
|             tcg_ctx.gen_opc_instr_start[lj++] = 0;
 | |
|     } else {
 | |
|         tb->size = ctx.pc - pc_start;
 | |
|         tb->icount = num_insns;
 | |
|     }
 | |
| 
 | |
| #ifdef DEBUG_DISAS
 | |
|     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
 | |
|         qemu_log("IN: %s\n", lookup_symbol(pc_start));
 | |
|         log_target_disas(env, pc_start, ctx.pc - pc_start, 1);
 | |
|         qemu_log("\n");
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void gen_intermediate_code (CPUAlphaState *env, struct TranslationBlock *tb)
 | |
| {
 | |
|     gen_intermediate_code_internal(alpha_env_get_cpu(env), tb, false);
 | |
| }
 | |
| 
 | |
| void gen_intermediate_code_pc (CPUAlphaState *env, struct TranslationBlock *tb)
 | |
| {
 | |
|     gen_intermediate_code_internal(alpha_env_get_cpu(env), tb, true);
 | |
| }
 | |
| 
 | |
| void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, int pc_pos)
 | |
| {
 | |
|     env->pc = tcg_ctx.gen_opc_pc[pc_pos];
 | |
| }
 |