@@ -22,7 +22,7 @@
#include "qemu-common.h"
-#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__)
+#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) || defined(__alpha__)
#define WORDS_ALIGNED
#endif
@@ -0,0 +1,1477 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * code review modification:
+ * 1. $15 is deleted from reserved register set and add to tcg_target_reg_alloc_order[]
+ * 2. $25 is deleted from tcg_target_reg_alloc_order[]
+ * 3. callee-clobbered register set bug fixed
+ * 4. tcg_out_ld/st bug fixed
+ * 5. translation of INDEX_op_exit_tb bug fixed
+ * 6. translation of INDEX_op_goto_tb bug fixed
+ * 7. tcg_out_brcond() bug fixed
+ * 8. patch_reloc() rewritten
+ * 9. qemu_ld/st() bug fixed
+ * 10. mul() ???
+ * 11. be careful about register order, like tcg_out_mov()
+ * 12. remove INDEX_op_mov(i)_i32/i64 from tcg_out_op(), they are already implemented in tcg.c
+ * 13. icache flush not implemented ???
+*/
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
+ "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+ "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
+};
+#endif
+
+/*
+ * $26 ~ $31 are special, reserved,
+ * and $25 is deliberately reserved for jcc operation
+ * and $0 is usually used for return function result, better allocate it later
+ * and $15 is used for cpu_env pointer, allocate it at last
+*/
+static const int tcg_target_reg_alloc_order[] = {
+ TCG_REG_1, TCG_REG_2, TCG_REG_3, TCG_REG_4, TCG_REG_5, TCG_REG_6,
+ TCG_REG_7, TCG_REG_8, TCG_REG_22, TCG_REG_23, TCG_REG_24,
+ TCG_REG_9, TCG_REG_10, TCG_REG_11, TCG_REG_12, TCG_REG_13, TCG_REG_14,
+ TCG_REG_16, TCG_REG_17, TCG_REG_18, TCG_REG_19, TCG_REG_20, TCG_REG_21,
+ TCG_REG_0, TCG_REG_15
+};
+
+/*
+ * according to alpha calling convention, these 6 registers are used for
+ * function parameter passing. if function has more than 6 parameters, remained
+ * ones are stored on stack.
+*/
+static const int tcg_target_call_iarg_regs[6] = {
+ TCG_REG_16, TCG_REG_17, TCG_REG_18, TCG_REG_19, TCG_REG_20, TCG_REG_21
+ };
+
+/*
+ * according to alpha calling convention, $0 is used for returning function result.
+*/
+static const int tcg_target_call_oarg_regs[1] = { TCG_REG_0 };
+
+/*
+ * save the address of TB's epilogue.
+*/
+static uint8_t *tb_ret_addr;
+
+/*
+ * op-code and func-code for jump insn
+*/
+#define CONTROL_CALL 0x01A
+#define CONTROL_RET 0x01A
+#define CONTROL_JMP 0x01A
+
+#define FUNC_JMP 0x00
+#define FUNC_CALL 0x01
+#define FUNC_RET 0x02
+
+#define CONTROL_BR 0x30
+#define CONTROL_BSR 0x34
+#define CONTROL_BEQ 0x39
+#define CONTROL_BNE 0x3D
+#define CONTROL_BLT 0x3A
+#define CONTROL_BLE 0x3B
+#define CONTROL_BGT 0x3F
+#define CONTROL_BGE 0x3E
+#define CONTROL_BLBC 0x38
+#define CONTROL_BLBS 0x3C
+
+#define ALPHA_ARITH 0x10
+
+#define ARITH_ADDL 0x00
+#define ARITH_SUBL 0x09
+#define ARITH_ADDQ 0x20
+#define ARITH_SUBQ 0x29
+#define ARITH_CMPEQ 0x2D
+#define ARITH_CMPLT 0x4D
+#define ARITH_CMPLE 0x6D
+#define ARITH_CMPULT 0x1D
+#define ARITH_CMPULE 0x3D
+
+#define ALPHA_MUL 0x13
+
+#define ARITH_MULL 0x00
+#define ARITH_MULQ 0x20
+
+#define ALPHA_LOGIC 0x11
+
+#define ARITH_AND 0x00
+#define ARITH_BIC 0x08
+#define ARITH_BIS 0x20
+#define ARITH_ORNOT 0x28
+#define ARITH_XOR 0x40
+#define ARITH_EQV 0x48
+
+#define ALPHA_SHIFT 0x12
+
+#define ARITH_SLL 0x39
+#define ARITH_SRL 0x34
+#define ARITH_SRA 0x3C
+
+#define ALPHA_SEXT 0x1C
+
+#define ARITH_SEXTB 0x00
+#define ARITH_SEXTW 0x01
+
+#define ALPHA_LDA 0x08
+#define ALPHA_LDAH 0x09
+#define ALPHA_LDBU 0x0A
+#define ALPHA_LDWU 0x0C
+#define ALPHA_LDL 0x28
+#define ALPHA_LDQ 0x29
+#define ALPHA_STB 0x0E
+#define ALPHA_STW 0x0D
+#define ALPHA_STL 0x2C
+#define ALPHA_STQ 0x2D
+
+/*
+ * return the # of regs used for parameter passing on procedure calling.
+ * note that alpha use $16~$21 to transfer the first 6 paramenters of a procedure.
+*/
+static inline int tcg_target_get_call_iarg_regs_count(int flags)
+{
+ return 6;
+}
+
+/*
+ * given constraint, return available register set. this function is called once
+ * for each op at qemu's initialization stage.
+*/
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+{
+ const char *ct_str = *pct_str;
+
+ switch(ct_str[0])
+ {
+ case 'r':
+ /* constaint 'r' means any register is okay */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ break;
+
+ case 'L':
+ /*
+ * constranit 'L' is used for qemu_ld/st, which has 2 meanings:
+ * 1st, we the argument need to be allocated a register.
+ * 2nd, we should reserve some registers that belong to caller-clobbered
+ * list for qemu_ld/st local usage, so these registers must not be
+ * allocated to the argument that the 'L' constraint is describing.
+ *
+ * note that op qemu_ld/st has the TCG_OPF_CALL_CLOBBER flag, and
+ * tcg will free all callee-clobbered registers before generate target
+ * insn for qemu_ld/st, so we can use these register directly without
+ * warrying about destroying their content.
+ */
+ ct->ct |= TCG_CT_REG;
+ tcg_regset_set32(ct->u.regs, 0, 0xffffffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_0);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_16);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_17);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_18);
+ break;
+
+ default:
+ return -1;
+ }
+
+ ct_str++;
+ *pct_str = ct_str;
+ return 0;
+}
+
+/*
+ * whether op's input argument may use constant
+*/
+static inline int tcg_target_const_match( \
+ tcg_target_long val, const TCGArgConstraint *arg_ct)
+{
+ int ct;
+ ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * construct insn with following format.
+ * (suitable for conditional branch insn)
+ *
+ * 31 26 25 21 20 0
+ * ------------------------------------------------------
+ * | OpCode | Ra | Disp |
+ * ------------------------------------------------------
+*/
+static inline void tcg_out_inst2(TCGContext *s, int Opcode, int Ra, int Disp)
+{
+ uint32_t v;
+
+ v = ( ( Opcode & 0x3f ) << 26 )
+ | ( ( Ra & 0x1f ) << 21 )
+ | ( Disp & 0x1fffff) ;
+
+ tcg_out32(s, v);
+}
+
+/*
+ * construct insn with following format.
+ * (used for ld/st or lda/ldah insn)
+ *
+ * 31 26 25 21 20 16 15 0
+ * ------------------------------------------------------
+ * | OpCode | Ra | Rb | Disp |
+ * ------------------------------------------------------
+*/
+static inline void tcg_out_inst3_disp(TCGContext *s, int Opcode, int Ra, int Rb, int Disp)
+{
+ uint32_t v;
+
+ v = ( ( Opcode & 0x3f ) << 26 )
+ | ( ( Ra & 0x1f ) << 21 )
+ | ( ( Rb & 0x1f ) << 16 )
+ | ( Disp & 0xffff) ;
+
+ tcg_out32(s, v);
+}
+
+/*
+ * construct insn with following format.
+ * (used for jmp insn)
+ *
+ * 31 26 25 21 20 16 15 0
+ * ------------------------------------------------------
+ * | OpCode | Ra | Rb | Func | Rsvd |
+ * ------------------------------------------------------
+*/
+static inline void tcg_out_inst3_func(TCGContext *s, int Opcode, int Ra, int Rb, int Func, int Disp)
+{
+ uint32_t v;
+
+ v = ( ( Opcode & 0x3f ) << 26 )
+ | ( ( Ra & 0x1f ) << 21 )
+ | ( ( Rb & 0x1f ) << 16 )
+ | ( ( Func & 0x3 ) << 14 )
+ | ( Disp & 0x3fff) ;
+
+ tcg_out32(s, v);
+}
+
+/*
+ * construct insn with following format.
+ * (used for operate insn)
+ *
+ * 1
+ * 31 26 25 21 20 16 15 13 2 11 5 4 0
+ * ------------------------------------------------------
+ * | OpCode | Ra | Rb | SBZ |0| Func | Rc |
+ * ------------------------------------------------------
+*/
+static inline void tcg_out_inst4(TCGContext *s, int Opcode, int Ra, int Rb, int Func, int Rc)
+{
+ uint32_t v;
+
+ v = ( (Opcode & 0x3f) << 26 )
+ | ( ( Ra & 0x1f ) << 21 )
+ | ( ( Rb & 0x1f ) << 16 )
+ | ( ( Func & 0x7f ) << 5 )
+ | ( Rc & 0x1f ) ;
+
+ tcg_out32(s, v);
+}
+
+/*
+ * construct insn with following format.
+ * (used for operate insn with immediate)
+ *
+ * 1
+ * 31 26 25 21 20 13 2 11 5 4 0
+ * ------------------------------------------------------
+ * | OpCode | Ra | LIT |1| Func | Rc |
+ * ------------------------------------------------------
+*/
+static inline void tcg_out_inst4i(TCGContext *s, int Opcode, int Ra, int Lit, int Func, int Rc)
+{
+ uint32_t v;
+
+ v = ( (Opcode & 0x3f) << 26 )
+ | ( ( Ra & 0x1f ) << 21 )
+ | ( ( Lit & 0xff ) << 13 )
+ | ( ( Func & 0x7f ) << 5 )
+ | ( 1 << 12 )
+ | ( Rc & 0x1f ) ;
+
+ tcg_out32(s, v);
+}
+
+/*
+ * mov from a reg to another
+*/
+static inline void tcg_out_mov(TCGContext *s, int Rc, int Rb)
+{
+ if ( Rb != Rc ) {
+ tcg_out_inst4(s, ALPHA_LOGIC, TCG_REG_31, Rb, ARITH_BIS, Rc); // bis $31, Rb, Rc
+ }
+}
+
+/*
+ * mov a 64-bit immediate 'arg' to regsiter 'Ra', this function will
+ * generate fixed length (5 insns, 20 bytes) of target insn sequence.
+*/
+static inline void tcg_out_movi_fixl( \
+ TCGContext *s, TCGType type, int Ra, tcg_target_long arg)
+{
+ if( arg & ((tcg_target_ulong)0x800000000000) )
+ tcg_out_inst3_disp(s, ALPHA_LDAH, Ra, TCG_REG_31, (arg>>48)+1 );
+ else
+ tcg_out_inst3_disp(s, ALPHA_LDAH, Ra, TCG_REG_31, arg>>48 ); // ldah Ra, arg<63:48>($31)
+
+ if( arg & ((tcg_target_ulong)0x80000000) )
{
+ tcg_out_inst3_disp(s, ALPHA_LDA, Ra, Ra, (arg>>32)+1 );
+ }
+ else
+ tcg_out_inst3_disp(s, ALPHA_LDA, Ra, Ra, arg>>32 ); // lda Ra, arg<47:32>(Ra)
+
+ tcg_out_inst4i(s, ALPHA_SHIFT, Ra, 32, ARITH_SLL, Ra); // sll Ra, 32, Ra
+
+ if( arg & ((tcg_target_ulong)0x8000) )
+ tcg_out_inst3_disp(s, ALPHA_LDAH, Ra, Ra, (arg>>16)+1 );
+ else
+ tcg_out_inst3_disp(s, ALPHA_LDAH, Ra, Ra, arg>>16 ); // ldah Ra, arg<31:16>(Ra)
+
+ tcg_out_inst3_disp(s, ALPHA_LDA, Ra, Ra, arg ); // lda Ra, arg<15:0>(Ra)
+}
+
+/*
+ * mov 64-bit immediate 'arg' to regsiter 'Ra'. this function will
+ * generate variable length of target insn sequence.
+*/
+static inline void tcg_out_movi( \
+ TCGContext *s, TCGType type, int Ra, tcg_target_long arg)
+{
+ if (arg == 0) {
+ tcg_out_inst4(s, ALPHA_LOGIC, Ra, Ra, ARITH_XOR, Ra); // xor Ra, Ra, Ra
+ }
+ else if( arg == (int16_t)arg ) {
+ tcg_out_inst3_disp(s, ALPHA_LDA, Ra, TCG_REG_31, arg ); // lda Ra, arg<15:0>($31)
+ }
+ else if( arg == (int32_t)arg ) {
+ if( arg & (1<<15) ) {
+ tcg_out_inst3_disp(s, ALPHA_LDAH, Ra, TCG_REG_31, (arg>>16)+1);
+ } else {
+ tcg_out_inst3_disp(s, ALPHA_LDAH, Ra, TCG_REG_31, arg>>16); // ldah Ra, arg<31:16>($31)
+ }
+ tcg_out_inst3_disp(s, ALPHA_LDA, Ra, Ra, arg ); // lda Ra, arg<15:0>(Ra)
+ } else {
+ /* use the most complex style of movement */
+ tcg_out_movi_fixl(s, type, Ra, arg);
+ }
+}
+
+/*
+ * load value in disp(Rb) to Ra.
+*/
+static inline void tcg_out_ld( \
+ TCGContext *s, TCGType type, int Ra, int Rb, tcg_target_long disp)
+{
+ int Opcode;
+
+ if( type == TCG_TYPE_I32) {
+ Opcode = ALPHA_LDL;
+ } else {
+ Opcode = ALPHA_LDQ;
+ }
+
+ if( disp != (int16_t)disp ) {
+ /* disp cannot be stored in insn directly */
+ tcg_out_movi(s, type, TMP_REG, disp);
+ tcg_out_inst4(s, ALPHA_ARITH, Rb, TMP_REG, ARITH_ADDQ, TMP_REG); // addq Rb, TMP_REG, TMP_REG
+ tcg_out_inst3_disp(s, Opcode, Ra, TMP_REG, 0); // ldx Ra, 0(TMP_REG)
+ }
+ else
+ tcg_out_inst3_disp(s, Opcode, Ra, Rb, disp); // ldx Ra, disp(Rb)
+}
+
+/*
+ * store value in Ra to disp(Rb).
+*/
+static inline void tcg_out_st( \
+ TCGContext *s, TCGType type, int Ra, int Rb, tcg_target_long disp)
+{
+ int Opcode;
+
+ if( type == TCG_TYPE_I32) {
+ Opcode = ALPHA_STL;
+ } else {
+ Opcode = ALPHA_STQ;
+ }
+
+ if( disp != (int16_t)disp ) {
+ /* disp cannot be stored in insn directly */
+ tcg_out_movi(s, type, TMP_REG, disp);
+ tcg_out_inst4(s, ALPHA_ARITH, Rb, TMP_REG, ARITH_ADDQ, TMP_REG); // addq Rb, TMP_REG, TMP_REG
+ tcg_out_inst3_disp(s, Opcode, Ra, TMP_REG, 0); // stx Ra, 0(TMP_REG)
+ }
+ else
+ tcg_out_inst3_disp(s, Opcode, Ra, Rb, disp); // stx Ra, disp(Rb)
+}
+
+/*
+ * generate arithmatic instruction with immediate. Ra is used as both
+ * input and output, and val is used as another input.
+*/
+static inline void tgen_arithi( \
+ TCGContext *s, int Opcode, int Func, int Ra, tcg_target_long val)
+{
+ if (val == (uint8_t)val) {
+ tcg_out_inst4i(s, Opcode, Ra, val, Func, Ra); // arithi Ra, #b, Ra
+ } else {
+ tcg_out_movi(s, TCG_TYPE_I64, TMP_REG, val);
+ tcg_out_inst4(s, Opcode, Ra, TMP_REG, Func, Ra); // arithi Ra, TMP_REG, Ra
+ }
+}
+
+/*
+ * generate addq instruction with immediate.
+*/
+static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+{
+ if (val != 0)
+ tgen_arithi(s, ALPHA_ARITH, ARITH_ADDQ, reg, val);
+}
+
+/*
+ * generate insn to push reg onto stack.
+*/
+static inline void tcg_out_push(TCGContext *s, int reg)
+{
+ tcg_out_inst4i(s, ALPHA_ARITH, TCG_REG_30, 8, ARITH_SUBQ, TCG_REG_30);
+ tcg_out_inst3_disp(s, ALPHA_STQ, reg, TCG_REG_30, 0);
+}
+
+/*
+ * generate insn to pop value from stack to reg.
+*/
+static inline void tcg_out_pop(TCGContext *s, int reg)
+{
+ tcg_out_inst3_disp(s, ALPHA_LDQ, reg, TCG_REG_30, 0);
+ tcg_out_inst4i(s, ALPHA_ARITH, TCG_REG_30, 8, ARITH_ADDQ, TCG_REG_30);
+}
+
+static const uint8_t tcg_cond_to_jcc[10] = {
+ [TCG_COND_EQ] = ARITH_CMPEQ,
+ [TCG_COND_NE] = ARITH_CMPEQ,
+ [TCG_COND_LT] = ARITH_CMPLT,
+ [TCG_COND_GE] = ARITH_CMPLT,
+ [TCG_COND_LE] = ARITH_CMPLE,
+ [TCG_COND_GT] = ARITH_CMPLE,
+ [TCG_COND_LTU] = ARITH_CMPULT,
+ [TCG_COND_GEU] = ARITH_CMPULT,
+ [TCG_COND_LEU] = ARITH_CMPULE,
+ [TCG_COND_GTU] = ARITH_CMPULE
+};
+
+/*
+ * called by tcg_out_reloc() when the label address is determined,
+ * i.e., label->has_value is true. what should be done is to patch
+ * the jmp insn that reference this label.
+ *
+ * code_ptr - position need to patch
+ * type - relocation type
+ * value - label address
+ * addend - not used
+*/
+static void patch_reloc(uint8_t *code_ptr, \
+ int type, tcg_target_long value, tcg_target_long addend)
+{
+ TCGContext s;
+
+ if ( type != R_ALPHA_REFQUAD)
+ tcg_abort();
+
+ s.code_ptr = code_ptr;
+ tcg_out_movi_fixl(&s, TCG_TYPE_I64, TMP_REG, value);
+ tcg_out_inst3_func(&s, CONTROL_JMP, TCG_REG_31, TMP_REG, FUNC_JMP, 0);
+}
+
+/*
+ * generate insns for BR or BRCOND
+ * opc must be CONTROL_BR or CONTROL_BLBC or CONTROL_BLBS
+ * Ra fixed to TMP_REG
+*/
+static void tcg_out_jxx(TCGContext *s, int opc, int Ra, int label_index)
+{
+ tcg_target_long val;
+ TCGLabel *l = &s->labels[label_index];
+
+ if ((Ra != TMP_REG) ||
+ (opc != CONTROL_BR && opc != CONTROL_BLBC && opc != CONTROL_BLBS) )
+ tcg_abort();
+
+ if (l->has_value) {
+ /* the label address has been resolved. */
+ val = (l->u.value - (tcg_target_long)s->code_ptr - 4) >> 2;
+ if ( val >= -0x100000 && val < 0x100000) {
+ /* if distance can be put into 21-bit field */
+ tcg_out_inst2(s, opc, Ra, val);
+ } else {
+ /* distance can't be put into 21-bit field */
+ if ( opc != CONTROL_BR) {
+ tcg_out_inst2(s, opc^4, Ra, 6);
+ }
+
+ tcg_out_movi_fixl(s, TCG_TYPE_I64, Ra, l->u.value);
+ tcg_out_inst3_func(s, CONTROL_JMP, TCG_REG_31, Ra, FUNC_JMP, 0); // jmp $31, TMP_REG, 0
+ }
+ } else {
+ /*
+ * if the label addr has not been determined, we first insert a short jmp,
+ * and then resv space (6 insns, 24 bytes) for long jmp
+ */
+ if ( opc != CONTROL_BR) {
+ tcg_out_inst2(s, opc^4, Ra, 6);
+ }
+
+ /* record relocation infor */
+ tcg_out_reloc(s, s->code_ptr, R_ALPHA_REFQUAD, label_index, 0);
+ s->code_ptr += 24;
+ }
+}
+
+/*
+ * generate insn for INDEX_op_brcond
+*/
+static void tcg_out_brcond( TCGContext *s, int cond, \
+ TCGArg arg1, TCGArg arg2, int const_arg2, int label_index)
+{
+ int Func, jcc_opc;
+
+ if ( cond < TCG_COND_EQ || cond > TCG_COND_GTU)
+ tcg_abort();
+
+ /* get function code according to condition */
+ Func = tcg_cond_to_jcc[cond];
+
+ if ( const_arg2) {
+ tcg_out_movi(s, TCG_TYPE_I64, TMP_REG, arg2);
+ tcg_out_inst4(s, ALPHA_ARITH, arg1, TMP_REG, Func, TMP_REG); // CMPxx arg1, TMP_REG, TMP_REG
+ } else {
+ tcg_out_inst4(s, ALPHA_ARITH, arg1, arg2, Func, TMP_REG); // CMPxx arg1, arg2, TMP_REG
+ }
+
+ //
+ // ---------------------------------
+ // cond & 1 | TMP_REG | take?
+ // ---------------------------------
+ // 0 | 0 | not
+ // 0 | 1 | yes
+ // 1 | 0 | yes
+ // 1 | 1 | not
+ // ---------------------------------
+ //
+ jcc_opc = (cond & 1) ? CONTROL_BLBC : CONTROL_BLBS;
+ tcg_out_jxx(s, jcc_opc, TMP_REG, label_index);
+}
+
+
+#if defined(CONFIG_SOFTMMU)
+
+#include "../../softmmu_defs.h"
+
+static void *qemu_ld_helpers[4] = {
+ __ldb_mmu,
+ __ldw_mmu,
+ __ldl_mmu,
+ __ldq_mmu,
+};
+
+static void *qemu_st_helpers[4] = {
+ __stb_mmu,
+ __stw_mmu,
+ __stl_mmu,
+ __stq_mmu,
+};
+
+#endif
+
+/*
+ * XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
+ * EAX. It will be useful once fixed registers globals are less common.
+ *
+ * output host insn for op 'qemu_ldxx t0, t1, flags', which means fetching value from t1 to t0.
+ * flags gives the current CPU mode, kernel or user.
+ *
+ * opc argument determines the data width and extension type (zero or signed), and has the
+ * following layout:
+ * 2 1 0
+ * ------------------------------------
+ * | | E | W |
+ * ------------------------------------
+ *
+ * E = 0 means zero extention, 1 means signed extension
+ * W = 0 means byte, 1 means word, 2 means dword.
+ *
+ * Note that VM addr space may be 32-bit or 64-bit, below, we take 32-bit addr space as example
+ * when doing the comment.
+*/
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap;
+
+#if defined(CONFIG_SOFTMMU)
+ uint8_t *label1_ptr, *label2_ptr;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ mem_index = *args;
+ s_bits = opc & 3;
+
+ r0 = TCG_REG_16;
+ r1 = TCG_REG_17;
+
+#if defined(CONFIG_SOFTMMU)
+
+ tcg_out_mov(s, r1, addr_reg);
+ tcg_out_mov(s, r0, addr_reg);
+
+#if TARGET_LONG_BITS == 32
+ /* if VM is of 32-bit arch, clear higher 32-bit of addr */
+ tcg_out_inst4i(s, ALPHA_SHIFT, r0, 32, ARITH_SLL, r0); // sll r0, 32, r0
+ tcg_out_inst4i(s, ALPHA_SHIFT, r0, 32, ARITH_SRL, r0); // srl r0, 32, r0
+ tcg_out_inst4i(s, ALPHA_SHIFT, r1, 32, ARITH_SLL, r1); // sll r0, 32, r0
+ tcg_out_inst4i(s, ALPHA_SHIFT, r1, 32, ARITH_SRL, r1); // srl r0, 32, r0
+#endif
+
+ tgen_arithi(s, ALPHA_LOGIC, ARITH_AND, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); // and r0, #b, r0
+
+ //
+ // after above insn, we got the page # stored in r0. note that if VM addr space is 32 bits,
+ // then the higher 32 bits of r0 should be 0
+ //
+ // 32 31 12 11 1 0
+ // -------------------------------------------------------------
+ // ...00 | page# | ...0000... |xx|
+ // -------------------------------------------------------------
+ //
+
+ //
+ // the following 2 host insns are tricky. note that TLB has 256 entries,
+ // and entry is (1<<CPU_TLB_ENTRY_BITS) bytes aligned. to check
+ // whether an address is cached in TLB, we may (1) get the page#
+ // from the address; (2) mask page# by 0xff, i.e., the simplest hash
+ // algorithm, to get TLB entry index; (3) shift the result CPU_TLB_ENTRY_BITS
+ // bits left to get the entry offset in TLB; (4) compare page# calculated
+ // in step (1) with the page# stored in TLB entry, if match, we can tell
+ // that the address is cached. take i386 as example, the CPU_TLB_ENTRY_BITS
+ // is 4, TARGET_PAGE_BITS is 12, so the original address has the folloing
+ // layout.
+ //
+ // 32 31 12 11 4 3 0
+ // -------------------------------------------------------------
+ // ...00 | page# | | |
+ // -------------------------------------------------------------
+ //
+
+ tgen_arithi(s, ALPHA_SHIFT, ARITH_SRL, r1, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); // srl r1, #b, r1
+
+ //
+ // after above insn, the addres has following layout:
+ //
+ // 32 31 12 11 4 3 0
+ // -------------------------------------------------------------
+ // ...00 | 0000... | page# | |
+ // -------------------------------------------------------------
+ //
+
+ tgen_arithi(s, ALPHA_LOGIC, ARITH_AND, r1, (CPU_TLB_SIZE-1) << CPU_TLB_ENTRY_BITS); // and r1, #b, r1
+
+ // after above insn, the addres has following layout:
+ //
+ // 32 31 12 11 4 3 0
+ // --------------------------------------------------------------
+ // ...00 | 00000 | page# & 0xff | 0000 |
+ // --------------------------------------------------------------
+ // |<- TLB entry offset ->|
+ //
+
+ tcg_out_addi(s, r1, offsetof(CPUState, tlb_table[mem_index][0].addr_read)); // addq r1, offset, r1
+ tcg_out_inst4(s, ALPHA_ARITH, r1, TCG_REG_15, ARITH_ADDQ, r1); // addq r1, $15, r1
+#if TARGET_LONG_BITS == 32
+ tcg_out_inst3_disp(s, ALPHA_LDL, TMP_REG, r1, 0); // ldl TMP_REG, 0(r1)
+ tcg_out_inst4i(s, ALPHA_SHIFT, TMP_REG, 32, ARITH_SLL, TMP_REG); // sll TMP_REG, 32, TMP_REG
+ tcg_out_inst4i(s, ALPHA_SHIFT, TMP_REG, 32, ARITH_SRL, TMP_REG); // srl TMP_REG, 32, TMP_REG
+#else
+ tcg_out_inst3_disp(s, ALPHA_LDQ, TMP_REG, r1, 0); // ldq TMP_REG, 0(r1)
+#endif
+
+ //
+ // now, r0 contains the page# and TMP_REG contains the addr to tlb_entry.addr_read
+ // we below will compare them
+ //
+ tcg_out_inst4(s, ALPHA_ARITH, TMP_REG, r0, ARITH_CMPEQ, TMP_REG); // cmpeq TMP_REG, r0, TMP_REG
+
+ tcg_out_mov(s, r0, addr_reg);
+#if TARGET_LONG_BITS == 32
+ tcg_out_inst4i(s, ALPHA_SHIFT, r0, 32, ARITH_SLL, r0); // sll r0, 32, r0
+ tcg_out_inst4i(s, ALPHA_SHIFT, r0, 32, ARITH_SRL, r0); // srl r0, 32, r0
+#endif
+
+ //
+ // if equal, we jump to label1. since label1 is not resolved yet,
+ // we just record a relocation.
+ //
+ label1_ptr = s->code_ptr;
+ s->code_ptr += 4;
+
+ //
+ // here, unequal, TLB-miss.
+ //
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_17, mem_index); // pass argument 2
+ tcg_out_movi(s, TCG_TYPE_I64, \
+ TMP_REG, (tcg_target_long)qemu_ld_helpers[s_bits]); // get helper func entry
+ tcg_out_push(s, TCG_REG_26);
+tcg_out_mov(s, TCG_REG_27, TMP_REG);
+ tcg_out_inst3_func(s, CONTROL_CALL, TCG_REG_26, TMP_REG, FUNC_CALL, 0); // call helper func
+ tcg_out_pop(s, TCG_REG_26);
+
+ //
+ // after helper function call, the result of ld is saved in $0
+ //
+ switch(opc) {
+ case 0 | 4:
+ tcg_out_inst4(s, ALPHA_SEXT, TCG_REG_31, TCG_REG_0, ARITH_SEXTB, data_reg); // sextb $31, $0, data_reg
+ break;
+ case 1 | 4:
+ tcg_out_inst4(s, ALPHA_SEXT, TCG_REG_31, TCG_REG_0, ARITH_SEXTW, data_reg); // sextw $31, $0, data_reg
+ break;
+ case 2 | 4:
+ tcg_out_inst4i(s, ALPHA_SHIFT, TCG_REG_0, 32, ARITH_SLL, TCG_REG_0); // sll $0, 32, $0
+ tcg_out_inst4i(s, ALPHA_SHIFT, TCG_REG_0, 32, ARITH_SRA, data_reg); // sra $0, 32, data_reg
+ break;
+ case 0:
+ tcg_out_inst4i(s, ALPHA_SHIFT, TCG_REG_0, 56, ARITH_SLL, TCG_REG_0); // sll $0, 56, $0
+ tcg_out_inst4i(s, ALPHA_SHIFT, TCG_REG_0, 56, ARITH_SRL, data_reg); // srl $0, 56, data_reg
+ break;
+ case 1:
+ tcg_out_inst4i(s, ALPHA_SHIFT, TCG_REG_0, 48, ARITH_SLL, TCG_REG_0); // sll $0, 48, $0
+ tcg_out_inst4i(s, ALPHA_SHIFT, TCG_REG_0, 48, ARITH_SRL, data_reg); // srl $0, 48, data_reg
+ break;
+ case 2:
+ default:
+ tcg_out_inst4i(s, ALPHA_SHIFT, TCG_REG_0, 32, ARITH_SLL, TCG_REG_0); // sll $0, 32, $0
+ tcg_out_inst4i(s, ALPHA_SHIFT, TCG_REG_0, 32, ARITH_SRL, data_reg); // srl $0, 32, data_reg
+ break;
+ case 3:
+ tcg_out_mov(s, data_reg, TCG_REG_0);
+ break;
+ }
+
+ //
+ // we have done, jmp to label2. label2 is not resolved yet,
+ // we record a relocation.
+ //
+ label2_ptr = s->code_ptr;
+ s->code_ptr += 4;
+
+ // patch jmp to label1
+ *(uint32_t *)label1_ptr = (uint32_t) \
+ ( ( CONTROL_BNE << 26 ) | ( TMP_REG << 21 ) \
+ | ( ((s->code_ptr-label1_ptr-4)>>2) & 0x1fffff) ); // beq TMP_REG, disp
+
+ //
+ // if we get here, a TLB entry is hit, r0 contains the guest addr and
+ // r1 contains the ptr that point to tlb_entry.addr_read. what we should
+ // do is to load the tlb_entry.addend (64-bit on alpha) and add it to
+ // r0 to get the host VA
+ //
+ tcg_out_movi(s, TCG_TYPE_I64, TMP_REG, \
+ offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_read)); // TMP_REG <- distance btw addent and addr_read
+ tcg_out_inst4(s, ALPHA_ARITH, r1, TMP_REG, ARITH_ADDQ, r1); // addq r1, TMP_REG, r1
+ tcg_out_inst3_disp(s, ALPHA_LDQ, TMP_REG, r1, 0); // ldq TMP_REG, r1, 0
+ tcg_out_inst4(s, ALPHA_ARITH, r0, TMP_REG, ARITH_ADDQ, r0); // addq r0, TMP_REG, r0
+
+#else
+ r0 = addr_reg;
+#endif // endif defined(CONFIG_SOFTMMU)
+
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 1;
+#else
+ bswap = 0;
+#endif
+
+ if ( bswap) {
+ tcg_abort();
+ }
+
+ //
+ // when we get here, r0 contains the host VA that can be used to access guest PA
+ //
+ switch(opc) {
+ case 0:
+ tcg_out_inst3_disp(s, ALPHA_LDBU, data_reg, r0, 0); // ldbu data_reg, 0(r0)
+ break;
+ case 0 | 4:
+ tcg_out_inst3_disp(s, ALPHA_LDBU, data_reg, r0, 0); // ldbu data_reg, 0(r0)
+ tcg_out_inst4(s, ALPHA_SEXT, TCG_REG_31, data_reg, ARITH_SEXTB, data_reg); // sextb $31, data_reg, data_reg
+ break;
+ case 1:
+ tcg_out_inst3_disp(s, ALPHA_LDWU, data_reg, r0, 0); // ldwu data_reg, 0(r0)
+ break;
+ case 1 | 4:
+ tcg_out_inst3_disp(s, ALPHA_LDWU, data_reg, r0, 0); // ldwu data_reg, 0(r0)
+ tcg_out_inst4(s, ALPHA_SEXT, TCG_REG_31, data_reg, ARITH_SEXTW, data_reg); // sextw $31, data_reg, data_reg
+ break;
+ case 2:
+ tcg_out_inst3_disp(s, ALPHA_LDL, data_reg, r0, 0); // ldl data_reg, 0(r0)
+ tcg_out_inst4i(s, ALPHA_SHIFT, data_reg, 32, ARITH_SLL, data_reg); // sll data_reg, 32, data_reg
+ tcg_out_inst4i(s, ALPHA_SHIFT, data_reg, 32, ARITH_SRL, data_reg); // srl data_reg, 32, data_reg
+ break;
+ case 2 | 4:
+ tcg_out_inst3_disp(s, ALPHA_LDL, data_reg, r0, 0); // ldl data_reg, 0(r0)
+ break;
+ case 3:
+ tcg_out_inst3_disp(s, ALPHA_LDQ, data_reg, r0, 0); // ldq data_reg, 0(r0)
+ break;
+ default:
+ tcg_abort();
+ }
+
+#if defined(CONFIG_SOFTMMU)
+ /* label2: */
+ *(uint32_t *)label2_ptr = (uint32_t)( ( CONTROL_BR << 26 ) \
+ | ( TCG_REG_31 << 21 ) |
+ ( ((s->code_ptr-label2_ptr-4)>>2) & 0x1fffff) );
+#endif
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
+{
+ int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap;
+#if defined(CONFIG_SOFTMMU)
+ uint8_t *label1_ptr, *label2_ptr;
+#endif
+
+ data_reg = *args++;
+ addr_reg = *args++;
+ mem_index = *args;
+ s_bits = opc&3;
+
+ r0 = TCG_REG_16;
+ r1 = TCG_REG_17;
+
+#if defined(CONFIG_SOFTMMU)
+
+ tcg_out_mov(s, r1, addr_reg);
+ tcg_out_mov(s, r0, addr_reg);
+
+#if TARGET_LONG_BITS == 32
+ /* if VM is of 32-bit arch, clear higher 32-bit of addr */
+ tcg_out_inst4i(s, ALPHA_SHIFT, r0, 32, ARITH_SLL, r0); // sll r0, 32, r0
+ tcg_out_inst4i(s, ALPHA_SHIFT, r0, 32, ARITH_SRL, r0); // srl r0, 32, r0
+ tcg_out_inst4i(s, ALPHA_SHIFT, r1, 32, ARITH_SLL, r1); // sll r0, 32, r0
+ tcg_out_inst4i(s, ALPHA_SHIFT, r1, 32, ARITH_SRL, r1); // srl r0, 32, r0
+#endif
+
+ tgen_arithi(s, ALPHA_LOGIC, ARITH_AND, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); // and r0, #b, r0
+
+ tgen_arithi(s, ALPHA_SHIFT, ARITH_SRL, r1, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); // srl r1, #b, r1
+ tgen_arithi(s, ALPHA_LOGIC, ARITH_AND, r1, (CPU_TLB_SIZE-1) << CPU_TLB_ENTRY_BITS); // and r1, #b, r1
+
+ tcg_out_addi(s, r1, offsetof(CPUState, tlb_table[mem_index][0].addr_write)); // addq r1, offset, r1
+ tcg_out_inst4(s, ALPHA_ARITH, r1, TCG_REG_15, ARITH_ADDQ, r1); // addq r1, $15, r1
+
+#if TARGET_LONG_BITS == 32
+ tcg_out_inst3_disp(s, ALPHA_LDL, TMP_REG, r1, 0); // ldl TMP_REG, 0(r1)
+ tcg_out_inst4i(s, ALPHA_SHIFT, TMP_REG, 32, ARITH_SLL, TMP_REG); // sll TMP_REG, 32, TMP_REG
+ tcg_out_inst4i(s, ALPHA_SHIFT, TMP_REG, 32, ARITH_SRL, TMP_REG); // srl TMP_REG, 32, TMP_REG
+#else
+ tcg_out_inst3_disp(s, ALPHA_LDQ, TMP_REG, r1, 0); // ldq TMP_REG, 0(r1)
+#endif
+
+ //
+ // now, r0 contains the page# and TMP_REG contains the addr to tlb_entry.addr_read
+ // we below will compare them
+ //
+ tcg_out_inst4(s, ALPHA_ARITH, TMP_REG, r0, ARITH_CMPEQ, TMP_REG); // cmpeq TMP_REG, r0, TMP_REG
+
+ tcg_out_mov(s, r0, addr_reg);
+#if TARGET_LONG_BITS == 32
+ tcg_out_inst4i(s, ALPHA_SHIFT, r0, 32, ARITH_SLL, r0); // sll r0, 32, r0
+ tcg_out_inst4i(s, ALPHA_SHIFT, r0, 32, ARITH_SRL, r0); // srl r0, 32, r0
+#endif
+
+ //
+ // if equal, we jump to label1. since label1 is not resolved yet,
+ // we just record a relocation.
+ //
+ label1_ptr = s->code_ptr;
+ s->code_ptr += 4;
+
+ // here, unequal, TLB-miss, ...
+ tcg_out_mov(s, TCG_REG_17, data_reg); // pass argument 2
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_18, mem_index); // pass argument 3
+ tcg_out_movi(s, TCG_TYPE_I64, \
+ TMP_REG, (tcg_target_long)qemu_st_helpers[s_bits]); // get helper func entry
+ tcg_out_push(s, TCG_REG_26);
+tcg_out_mov(s, TCG_REG_27,TMP_REG);
+ tcg_out_inst3_func(s, CONTROL_CALL, TCG_REG_26, TMP_REG, FUNC_CALL, 0); // call helper func
+ tcg_out_pop(s, TCG_REG_26);
+
+ //
+ // we have done, jmp to label2. label2 is not resolved yet,
+ // we record a relocation.
+ //
+ label2_ptr = s->code_ptr;
+ s->code_ptr += 4;
+
+ // patch jmp to label1
+ *(uint32_t *)label1_ptr = (uint32_t) \
+ ( ( CONTROL_BNE << 26) | ( TMP_REG << 21 )
+ | ( ((s->code_ptr-label1_ptr-4)>>2) & 0x1fffff) ); // bne TMP_REG, disp
+
+ //
+ // if we get here, a TLB entry is hit, r0 contains the guest addr and
+ // r1 contains the ptr that point to tlb_entry.addr_read. what we should
+ // do is to load the tlb_entry.addend (64-bit on alpha) and add it to
+ // r0 to get the host VA
+ //
+ tcg_out_movi(s, TCG_TYPE_I64, TMP_REG, \
+ offsetof(CPUTLBEntry, addend) - offsetof(CPUTLBEntry, addr_write)); // TMP_REG <- distance btw addent and addr_write
+ tcg_out_inst4(s, ALPHA_ARITH, r1, TMP_REG, ARITH_ADDQ, r1); // addq r1, TMP_REG, r1
+ tcg_out_inst3_disp(s, ALPHA_LDQ, TMP_REG, r1, 0); // ldq TMP_REG, r1, 0
+ tcg_out_inst4(s, ALPHA_ARITH, r0, TMP_REG, ARITH_ADDQ, r0); // addq r0, TMP_REG, r0
+
+#else
+ r0 = addr_reg;
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ bswap = 1;
+#else
+ bswap = 0;
+#endif
+
+ if ( bswap) {
+ tcg_abort();
+ }
+
+ //
+ // when we get here, r0 contains the host VA that can be used to access guest PA
+ //
+ switch(opc) {
+ case 0:
+ tcg_out_inst3_disp(s, ALPHA_STB, data_reg, r0, 0); // stb data_reg, 0(r0)
+ break;
+ case 1:
+ tcg_out_inst3_disp(s, ALPHA_STW, data_reg, r0, 0); // stw data_reg, 0(r0)
+ break;
+ case 2:
+ tcg_out_inst3_disp(s, ALPHA_STL, data_reg, r0, 0); // stl data_reg, 0(r0)
+ break;
+ case 3:
+ tcg_out_inst3_disp(s, ALPHA_STQ, data_reg, r0, 0); // stq data_reg, 0(r0)
+ break;
+ default:
+ tcg_abort();
+ }
+
+#if defined(CONFIG_SOFTMMU)
+ /* label2: */
+ *(uint32_t *)label2_ptr = (uint32_t)( ( CONTROL_BR << 26 ) \
+ | ( TCG_REG_31 << 21 ) | ( ((s->code_ptr-label2_ptr-4)>>2) & 0x1fffff));
+#endif
+}
+
+static inline void tgen_ldxx( TCGContext *s, int Ra, int Rb, tcg_target_long disp, int flags)
+{
+ int opc_array[4] = { ALPHA_LDBU, ALPHA_LDWU, ALPHA_LDL, ALPHA_LDQ};
+ int opc = opc_array[flags & 3];
+
+ if( disp != (int16_t)disp ) {
+ /* disp cannot be stored in insn directly */
+ tcg_out_movi(s, TCG_TYPE_I64, TMP_REG, disp);
+ tcg_out_inst4(s, ALPHA_ARITH, Rb, TMP_REG, ARITH_ADDQ, TMP_REG); // addq r, TMP_REG, TMP_REG
+ tcg_out_inst3_disp(s, opc, Ra, TMP_REG, 0); // ldx ret, 0(TMP_REG)
+ } else {
+ tcg_out_inst3_disp(s, opc, Ra, Rb, disp); // ldx ret, disp(r)
+ }
+
+ switch ( flags & 7) {
+ case 0:
+ case 1:
+ case 2|4:
+ case 3:
+ break;
+ case 0|4:
+ tcg_out_inst4(s, ALPHA_SEXT, TCG_REG_31, Ra, ARITH_SEXTB, Ra); // sextb $31, ra, ra
+ break;
+ case 1|4:
+ tcg_out_inst4(s, ALPHA_SEXT, TCG_REG_31, Ra, ARITH_SEXTW, Ra); // sextw $31, ra, ra
+ break;
+ case 2:
+ tcg_out_inst4i(s, ALPHA_SHIFT, Ra, 32, ARITH_SLL, Ra); // sll ret, 32, ret
+ tcg_out_inst4i(s, ALPHA_SHIFT, Ra, 32, ARITH_SRL, Ra); // srl ret, 32, ret
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+static inline void tgen_stxx( TCGContext *s, int Ra, int Rb, tcg_target_long disp, int flags)
+{
+ int opc_array[4] = { ALPHA_STB, ALPHA_STW, ALPHA_STL, ALPHA_STQ};
+ int opc = opc_array[flags & 3];
+
+ if( disp != (int16_t)disp ) {
+ /* disp cannot be stored in insn directly */
+ tcg_out_movi(s, TCG_TYPE_I64, TMP_REG, disp);
+ tcg_out_inst4(s, ALPHA_ARITH, Rb, TMP_REG, ARITH_ADDQ, TMP_REG); // addq Rb, TMP_REG, TMP_REG
+ tcg_out_inst3_disp(s, opc, Ra, TMP_REG, 0); // stx Ra, 0(TMP_REG)
+ } else {
+ tcg_out_inst3_disp(s, opc, Ra, Rb, disp); // stx Ra, disp(Rb)
+ }
+}
+
+static inline void tcg_out_op(TCGContext *s, \
+ int opc, const TCGArg *args, const int *const_args)
+{
+ int oc, c;
+ switch(opc)
+ {
+ case INDEX_op_exit_tb:
+ /*
+ * exit_tb t0, where t0 is always constant and should be returned to engine
+ * since we'll back to engine soon, $0 and $1 will never be used
+ */
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_0, args[0]);
+ tcg_out_movi(s, TCG_TYPE_I64, TMP_REG, (tcg_target_long)tb_ret_addr);
+ tcg_out_inst3_func(s, CONTROL_JMP, TCG_REG_31, TMP_REG, FUNC_JMP, 0); // jmp $31, TMP_REG, hint
+ break;
+
+ case INDEX_op_goto_tb:
+ /* goto_tb idx, where idx is constant 0 or 1, indicating the branch # */
+ if (s->tb_jmp_offset) {
+ /* we don't support direct jmp */
+ tcg_abort();
+ } else {
+ /* indirect jump method */
+ tcg_out_movi( s, TCG_TYPE_I64, TMP_REG, (tcg_target_long)(s->tb_next + args[0]));
+ tcg_out_ld( s, TCG_TYPE_I64, TMP_REG, TMP_REG, 0);
+ tcg_out_inst3_func(s, CONTROL_JMP, TCG_REG_31, TMP_REG, FUNC_JMP, 0); // jmp $31, TMP_REG, hint
+ }
+ s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
+ break;
+
+ case INDEX_op_call:
+ /* call <ret> <params> ptr, where ptr has be stored in args[0] */
+ if (const_args[0]) {
+ tcg_abort();
+ } else {
+ tcg_out_push( s, TCG_REG_26);
+ tcg_out_mov( s, TCG_REG_27, args[0]);
+ tcg_out_inst3_func(s, CONTROL_CALL, TCG_REG_26, args[0], FUNC_CALL, 0);
+ tcg_out_pop( s, TCG_REG_26);
+ }
+ break;
+
+ case INDEX_op_jmp:
+ /* jmp t0, where t0 gives the target address */
+ if (const_args[0]) {
+ tcg_abort();
+ } else {
+ tcg_out_inst3_func(s, CONTROL_JMP, TCG_REG_31, args[0], FUNC_JMP, 0);
+ }
+ break;
+
+ case INDEX_op_br:
+ /* br idx, where idx gives the label index */
+ tcg_out_jxx(s, CONTROL_BR, TMP_REG, args[0]);
+ break;
+
+ case INDEX_op_mov_i32:
+ case INDEX_op_mov_i64:
+ /* mov_i32/i64 t0, t1, implemented in tcg.c:tcg_reg_alloc_mov() */
+ tcg_abort();
+ break;
+
+ case INDEX_op_movi_i32:
+ case INDEX_op_movi_i64:
+ /* movi_i32/i64 t0, t1, implemented in tcg.c:tcg_reg_alloc_movi() */
+ tcg_abort();
+ break;
+
+ case INDEX_op_ld8u_i32:
+ case INDEX_op_ld8u_i64:
+ /* ld8u_i32/i64 t0, t1, offset */
+ tgen_ldxx( s, args[0], args[1], args[2], 0);
+ break;
+
+ case INDEX_op_ld8s_i32:
+ case INDEX_op_ld8s_i64:
+ /* ld8s_i32/i64 t0, t1, offset */
+ tgen_ldxx( s, args[0], args[1], args[2], 0|4);
+ break;
+
+ case INDEX_op_ld16u_i32:
+ case INDEX_op_ld16u_i64:
+ /* ld16u_i32/i64 t0, t1, offset */
+ tgen_ldxx( s, args[0], args[1], args[2], 1);
+ break;
+
+ case INDEX_op_ld16s_i32:
+ case INDEX_op_ld16s_i64:
+ /* ld16s_i32/i64 t0, t1, offset */
+ tgen_ldxx( s, args[0], args[1], args[2], 1|4);
+ break;
+
+ case INDEX_op_ld32u_i64:
+ /* ld32u_i64 t0, t1, offset */
+ tgen_ldxx( s, args[0], args[1], args[2], 2);
+ break;
+
+ case INDEX_op_ld_i32:
+ case INDEX_op_ld32s_i64:
+ /* ld_i32 t0, t1, offset or ld32s_i64 t0, t1, offset */
+ tgen_ldxx( s, args[0], args[1], args[2], 2|4);
+ break;
+
+ case INDEX_op_ld_i64:
+ /* ld_i32 t0, t1, offset */
+ tgen_ldxx( s, args[0], args[1], args[2], 3);
+ break;
+
+ case INDEX_op_st8_i32:
+ case INDEX_op_st8_i64:
+ /* st8_i32/i64 t0, t1, offset */
+ tgen_stxx( s, args[0], args[1], args[2], 0);
+ break;
+
+ case INDEX_op_st16_i32:
+ case INDEX_op_st16_i64:
+ /* st16_i32/i64 t0, t1, offset */
+ tgen_stxx( s, args[0], args[1], args[2], 1);
+ break;
+
+ case INDEX_op_st_i32:
+ case INDEX_op_st32_i64:
+ /* st_i32/st32_i64 t0, t1, offset */
+ tgen_stxx( s, args[0], args[1], args[2], 2);
+ break;
+
+ case INDEX_op_st_i64:
+ /* st_i64 t0, t1, offset */
+ tgen_stxx( s, args[0], args[1], args[2], 3);
+ break;
+
+ case INDEX_op_add_i32:
+ /* add_i32 t0, t1, t2 */
+ oc = ALPHA_ARITH;
+ c = ARITH_ADDL;
+ goto gen_arith;
+ case INDEX_op_add_i64:
+ /* add_i64 t0, t1, t2 */
+ oc = ALPHA_ARITH;
+ c = ARITH_ADDQ;
+ goto gen_arith;
+ case INDEX_op_sub_i32:
+ /* sub_i32 t0, t1, t2 */
+ oc = ALPHA_ARITH;
+ c = ARITH_SUBL;
+ goto gen_arith;
+ case INDEX_op_sub_i64:
+ /* sub_i84 t0, t1, t2 */
+ oc = ALPHA_ARITH;
+ c = ARITH_SUBQ;
+ goto gen_arith;
+ case INDEX_op_mul_i32:
+ /* mul_i32 t0, t1, t2 */
+ oc = ALPHA_MUL;
+ c = ARITH_MULL;
+ goto gen_arith;
+ case INDEX_op_mul_i64:
+ /* mul_i64 t0, t1, t2 */
+ oc = ALPHA_MUL;
+ c = ARITH_MULQ;
+ goto gen_arith;
+ case INDEX_op_and_i32:
+ case INDEX_op_and_i64:
+ /* and_i32/i64 t0, t1, t2 */
+ oc = ALPHA_LOGIC;
+ c = ARITH_AND;
+ goto gen_arith;
+ case INDEX_op_or_i32:
+ case INDEX_op_or_i64:
+ /* or_i32/i64 t0, t1, t2 */
+ oc = ALPHA_LOGIC;
+ c = ARITH_BIS;
+ goto gen_arith;
+ case INDEX_op_xor_i32:
+ case INDEX_op_xor_i64:
+ /* xor_i32/i64 t0, t1, t2 */
+ oc = ALPHA_LOGIC;
+ c = ARITH_XOR;
+ goto gen_arith;
+ case INDEX_op_shl_i32:
+ case INDEX_op_shl_i64:
+ /* shl_i32/i64 t0, t1, t2 */
+ oc = ALPHA_SHIFT;
+ c = ARITH_SLL;
+ goto gen_arith;
+ case INDEX_op_shr_i32:
+ tcg_out_inst4i(s, ALPHA_SHIFT, args[0], 32, ARITH_SLL, args[0]);
+ tcg_out_inst4i(s, ALPHA_SHIFT, args[0], 32, ARITH_SRL, args[0]);
+ case INDEX_op_shr_i64:
+ /* shr_i32/i64 t0, t1, t2 */
+ oc = ALPHA_SHIFT;
+ c = ARITH_SRL;
+ goto gen_arith;
+ case INDEX_op_sar_i32:
+ tcg_out_inst4i(s, ALPHA_SHIFT, args[0], 32, ARITH_SLL, args[0]);
+ tcg_out_inst4i(s, ALPHA_SHIFT, args[0], 32, ARITH_SRA, args[0]);
+ case INDEX_op_sar_i64:
+ /* sar_i32/i64 t0, t1, t2 */
+ oc = ALPHA_SHIFT;
+ c = ARITH_SRA;
+ gen_arith:
+ if (const_args[2]) {
+ tgen_arithi(s, oc, c, args[0], args[2]);
+ } else {
+ tcg_out_inst4(s, oc, args[0], args[2], c, args[0]);
+ }
+ break;
+
+ case INDEX_op_brcond_i32:
+ case INDEX_op_brcond_i64:
+ /* brcond_i32/i64 t0, t1, cond, label */
+ tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]);
+ break;
+
+ case INDEX_op_qemu_ld8u:
+ tcg_out_qemu_ld(s, args, 0);
+ break;
+ case INDEX_op_qemu_ld8s:
+ tcg_out_qemu_ld(s, args, 0 | 4);
+ break;
+ case INDEX_op_qemu_ld16u:
+ tcg_out_qemu_ld(s, args, 1);
+ break;
+ case INDEX_op_qemu_ld16s:
+ tcg_out_qemu_ld(s, args, 1 | 4);
+ break;
+ case INDEX_op_qemu_ld32u:
+ tcg_out_qemu_ld(s, args, 2);
+ break;
+ case INDEX_op_qemu_ld32s:
+ tcg_out_qemu_ld(s, args, 2 | 4);
+ break;
+ case INDEX_op_qemu_ld64:
+ tcg_out_qemu_ld(s, args, 3);
+ break;
+
+ case INDEX_op_qemu_st8:
+ tcg_out_qemu_st(s, args, 0);
+ break;
+ case INDEX_op_qemu_st16:
+ tcg_out_qemu_st(s, args, 1);
+ break;
+ case INDEX_op_qemu_st32:
+ tcg_out_qemu_st(s, args, 2);
+ break;
+ case INDEX_op_qemu_st64:
+ tcg_out_qemu_st(s, args, 3);
+ break;
+
+ case INDEX_op_div2_i32:
+ case INDEX_op_divu2_i32:
+ default:
+ tcg_abort();
+ }
+
+ tcg_out_inst4(s, ALPHA_LOGIC, 31, 31, ARITH_AND, 31);
+}
+
+static const TCGTargetOpDef alpha_op_defs[] = {
+ { INDEX_op_exit_tb, { } },
+ { INDEX_op_goto_tb, { } },
+ { INDEX_op_call, { "r" } },
+ { INDEX_op_jmp, { "r" } },
+ { INDEX_op_br, { } },
+
+ { INDEX_op_mov_i32, { "r", "r" } },
+ { INDEX_op_movi_i32, { "r" } },
+ { INDEX_op_ld8u_i32, { "r", "r" } },
+ { INDEX_op_ld8s_i32, { "r", "r" } },
+ { INDEX_op_ld16u_i32, { "r", "r" } },
+ { INDEX_op_ld16s_i32, { "r", "r" } },
+ { INDEX_op_ld_i32, { "r", "r" } },
+ { INDEX_op_st8_i32, { "r", "r" } },
+ { INDEX_op_st16_i32, { "r", "r" } },
+ { INDEX_op_st_i32, { "r", "r" } },
+
+ { INDEX_op_add_i32, { "r", "0", "ri" } },
+ { INDEX_op_mul_i32, { "r", "0", "ri" } },
+ //{ INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } },
+ //{ INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } },
+ { INDEX_op_sub_i32, { "r", "0", "ri" } },
+ { INDEX_op_and_i32, { "r", "0", "ri" } },
+ { INDEX_op_or_i32, { "r", "0", "ri" } },
+ { INDEX_op_xor_i32, { "r", "0", "ri" } },
+
+ { INDEX_op_shl_i32, { "r", "0", "ri" } },
+ { INDEX_op_shr_i32, { "r", "0", "ri" } },
+ { INDEX_op_sar_i32, { "r", "0", "ri" } },
+
+ { INDEX_op_brcond_i32, { "r", "ri" } },
+
+ { INDEX_op_mov_i64, { "r", "r" } },
+ { INDEX_op_movi_i64, { "r" } },
+ { INDEX_op_ld8u_i64, { "r", "r" } },
+ { INDEX_op_ld8s_i64, { "r", "r" } },
+ { INDEX_op_ld16u_i64, { "r", "r" } },
+ { INDEX_op_ld16s_i64, { "r", "r" } },
+ { INDEX_op_ld32u_i64, { "r", "r" } },
+ { INDEX_op_ld32s_i64, { "r", "r" } },
+ { INDEX_op_ld_i64, { "r", "r" } },
+ { INDEX_op_st8_i64, { "r", "r" } },
+ { INDEX_op_st16_i64, { "r", "r" } },
+ { INDEX_op_st32_i64, { "r", "r" } },
+ { INDEX_op_st_i64, { "r", "r" } },
+
+ { INDEX_op_add_i64, { "r", "0", "ri" } },
+ { INDEX_op_mul_i64, { "r", "0", "ri" } },
+ //{ INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } },
+ //{ INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } },
+ { INDEX_op_sub_i64, { "r", "0", "ri" } },
+ { INDEX_op_and_i64, { "r", "0", "ri" } },
+ { INDEX_op_or_i64, { "r", "0", "ri" } },
+ { INDEX_op_xor_i64, { "r", "0", "ri" } },
+
+ { INDEX_op_shl_i64, { "r", "0", "ri" } },
+ { INDEX_op_shr_i64, { "r", "0", "ri" } },
+ { INDEX_op_sar_i64, { "r", "0", "ri" } },
+
+ { INDEX_op_brcond_i64, { "r", "ri" } },
+
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32u, { "r", "L" } },
+ { INDEX_op_qemu_ld32s, { "r", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "L" } },
+
+ { INDEX_op_qemu_st8, { "L", "L" } },
+ { INDEX_op_qemu_st16, { "L", "L" } },
+ { INDEX_op_qemu_st32, { "L", "L" } },
+ { INDEX_op_qemu_st64, { "L", "L", "L" } },
+
+ { -1 },
+};
+
+
+static int tcg_target_callee_save_regs[] = {
+ /* TCG_REG_15, */ // used for the global env, so no need to save
+ TCG_REG_9,
+ TCG_REG_10,
+ TCG_REG_11,
+ TCG_REG_12,
+ TCG_REG_13,
+ TCG_REG_14
+};
+
+/*
+ * Generate global QEMU prologue and epilogue code
+*/
+void tcg_target_qemu_prologue(TCGContext *s)
+{
+ int i, frame_size, push_size, stack_addend;
+
+ /* TB prologue */
+/*printf("TB prologue @ %lx\n", s->code_ptr);*/
+
+ /* save TCG_REG_26 */
+ tcg_out_push(s, TCG_REG_26);
+
+ /* save all callee saved registers */
+ for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+ tcg_out_push(s, tcg_target_callee_save_regs[i]);
+ }
+
+ /* reserve some stack space */
+ push_size = 8 + (1 + ARRAY_SIZE(tcg_target_callee_save_regs)) * 8;
+ frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
+ frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & ~(TCG_TARGET_STACK_ALIGN - 1);
+ stack_addend = frame_size - push_size;
+ tcg_out_addi(s, TCG_REG_30, -stack_addend);
+
+ tcg_out_inst3_func(s, CONTROL_JMP, TCG_REG_31, TCG_REG_16, FUNC_JMP, 0); /* jmp $16 */
+
+ /* TB epilogue */
+ tb_ret_addr = s->code_ptr;
+ tcg_out_addi(s, TCG_REG_30, stack_addend);
+ for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
+ tcg_out_pop(s, tcg_target_callee_save_regs[i]);
+ }
+
+ tcg_out_pop(s, TCG_REG_26);
+ tcg_out_inst3_func(s, CONTROL_RET, TCG_REG_31, TCG_REG_26, FUNC_RET, 0); /* ret */
+}
+
+
+void tcg_target_init(TCGContext *s)
+{
+ /* fail safe */
+ if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
+ tcg_abort();
+
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
+ tcg_regset_set32(tcg_target_call_clobber_regs, 0,
+ (1 << TCG_REG_1 ) | (1 << TCG_REG_2 ) | (1 << TCG_REG_3 ) | (1 << TCG_REG_4 ) |
+ (1 << TCG_REG_5 ) | (1 << TCG_REG_6 ) | (1 << TCG_REG_7 ) | (1 << TCG_REG_8 ) |
+ (1 << TCG_REG_22) | (1 << TCG_REG_23) | (1 << TCG_REG_24) | (1 << TCG_REG_25) |
+ (1 << TCG_REG_16) | (1 << TCG_REG_17) | (1 << TCG_REG_18) | (1 << TCG_REG_19) |
+ (1 << TCG_REG_20) | (1 << TCG_REG_21) | (1 << TCG_REG_0 ));
+
+ tcg_regset_clear(s->reserved_regs);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_26);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_27);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_28);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_29);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_30);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_31); // $15, $26~$31 not alloced by tcg.c
+ tcg_regset_set_reg(s->reserved_regs, TMP_REG); // reserved register for used in this file
+
+ tcg_add_target_add_op_defs(alpha_op_defs);
+ printf("tcg_init called.\n");
+}
+
@@ -0,0 +1,60 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define TCG_TARGET_ALPHA 1
+
+#define TCG_TARGET_REG_BITS 64
+
+#define TCG_TARGET_NB_REGS 32
+
+enum {
+ TCG_REG_0 = 0, TCG_REG_1, TCG_REG_2, TCG_REG_3,
+ TCG_REG_4, TCG_REG_5, TCG_REG_6, TCG_REG_7,
+ TCG_REG_8, TCG_REG_9, TCG_REG_10, TCG_REG_11,
+ TCG_REG_12, TCG_REG_13, TCG_REG_14, TCG_REG_15,
+ TCG_REG_16, TCG_REG_17, TCG_REG_18, TCG_REG_19,
+ TCG_REG_20, TCG_REG_21, TCG_REG_22, TCG_REG_23,
+ TCG_REG_24, TCG_REG_25, TCG_REG_26, TCG_REG_27,
+ TCG_REG_28, TCG_REG_29, TCG_REG_30, TCG_REG_31
+};
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_30
+#define TCG_TARGET_STACK_ALIGN 16
+#define TCG_TARGET_CALL_STACK_OFFSET 0
+
+/* Note: must be synced with dyngen-exec.h */
+#define TCG_AREG0 TCG_REG_15
+#define TCG_AREG1 TCG_REG_9
+#define TCG_AREG2 TCG_REG_10
+#define TCG_AREG3 TCG_REG_11
+#define TCG_AREG4 TCG_REG_12
+#define TCG_AREG5 TCG_REG_13
+#define TCG_AREG6 TCG_REG_14
+
+#define TMP_REG TCG_REG_25
+
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+ asm("call_pal 0x86");
+}