xref: /openbmc/qemu/target/microblaze/translate.c (revision 2b01688380103acc2a9cd197b964d643fceba2a9)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  Xilinx MicroBlaze emulation for qemu: main translation routines.
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2009 Edgar E. Iglesias.
5fcf5ef2aSThomas Huth  *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
10ee452036SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth  */
20fcf5ef2aSThomas Huth 
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "exec/exec-all.h"
244597463bSPhilippe Mathieu-Daudé #include "exec/cpu_ldst.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
26fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
27fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
2877fc6f5eSLluís Vilanova #include "exec/translator.h"
2990c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
30fcf5ef2aSThomas Huth 
31fcf5ef2aSThomas Huth #include "exec/log.h"
32fcf5ef2aSThomas Huth 
33d53106c9SRichard Henderson #define HELPER_H "helper.h"
34d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
35d53106c9SRichard Henderson #undef  HELPER_H
36d53106c9SRichard Henderson 
37fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
38fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
39fcf5ef2aSThomas Huth 
4077fc6f5eSLluís Vilanova /* is_jmp field values */
4177fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
4217e77796SRichard Henderson #define DISAS_EXIT    DISAS_TARGET_1 /* all cpu state modified dynamically */
4377fc6f5eSLluís Vilanova 
44f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */
45f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2
46f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */
47f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3
48f6278ca9SRichard Henderson 
49cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
500f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
513e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
521074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
539b158558SRichard Henderson static TCGv_i32 cpu_imm;
54b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
550f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
569b158558SRichard Henderson static TCGv_i32 cpu_iflags;
579b158558SRichard Henderson static TCGv cpu_res_addr;
589b158558SRichard Henderson static TCGv_i32 cpu_res_val;
59fcf5ef2aSThomas Huth 
60fcf5ef2aSThomas Huth /* This is the state at translation time.  */
61fcf5ef2aSThomas Huth typedef struct DisasContext {
62d4705ae0SRichard Henderson     DisasContextBase base;
634b893631SRichard Henderson     const MicroBlazeCPUConfig *cfg;
64fcf5ef2aSThomas Huth 
6520800179SRichard Henderson     TCGv_i32 r0;
6620800179SRichard Henderson     bool r0_set;
6720800179SRichard Henderson 
68fcf5ef2aSThomas Huth     /* Decoder.  */
69d7ecb757SRichard Henderson     uint32_t ext_imm;
70683a247eSRichard Henderson     unsigned int tb_flags;
716f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
72287b1defSRichard Henderson     int mem_index;
73fcf5ef2aSThomas Huth 
74b9c58aabSRichard Henderson     /* Condition under which to jump, including NEVER and ALWAYS. */
75b9c58aabSRichard Henderson     TCGCond jmp_cond;
76b9c58aabSRichard Henderson 
77b9c58aabSRichard Henderson     /* Immediate branch-taken destination, or -1 for indirect. */
78b9c58aabSRichard Henderson     uint32_t jmp_dest;
79fcf5ef2aSThomas Huth } DisasContext;
80fcf5ef2aSThomas Huth 
typeb_imm(DisasContext * dc,int x)8120800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8220800179SRichard Henderson {
8320800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
8420800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
8520800179SRichard Henderson     }
8620800179SRichard Henderson     return x;
8720800179SRichard Henderson }
8820800179SRichard Henderson 
8944d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9044d1432bSRichard Henderson #include "decode-insns.c.inc"
9144d1432bSRichard Henderson 
t_sync_flags(DisasContext * dc)92683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
93fcf5ef2aSThomas Huth {
94fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
9588e74b61SRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
9688e74b61SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
97fcf5ef2aSThomas Huth     }
98fcf5ef2aSThomas Huth }
99fcf5ef2aSThomas Huth 
gen_raise_exception(DisasContext * dc,uint32_t index)10041ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
101fcf5ef2aSThomas Huth {
102ad75a51eSRichard Henderson     gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
103d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
104fcf5ef2aSThomas Huth }
105fcf5ef2aSThomas Huth 
gen_raise_exception_sync(DisasContext * dc,uint32_t index)10641ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
10741ba37c4SRichard Henderson {
10841ba37c4SRichard Henderson     t_sync_flags(dc);
109d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
11041ba37c4SRichard Henderson     gen_raise_exception(dc, index);
11141ba37c4SRichard Henderson }
11241ba37c4SRichard Henderson 
gen_raise_hw_excp(DisasContext * dc,uint32_t esr_ec)11341ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
11441ba37c4SRichard Henderson {
115a5ea3dd7SRichard Henderson     TCGv_i32 tmp = tcg_constant_i32(esr_ec);
116ad75a51eSRichard Henderson     tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUMBState, esr));
11741ba37c4SRichard Henderson 
11841ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
11941ba37c4SRichard Henderson }
12041ba37c4SRichard Henderson 
gen_goto_tb(DisasContext * dc,int n,target_ulong dest)121fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
122fcf5ef2aSThomas Huth {
12366345580SRichard Henderson     if (translator_use_goto_tb(&dc->base, dest)) {
124fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1250f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
126d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
127fcf5ef2aSThomas Huth     } else {
1280f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1294059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
130fcf5ef2aSThomas Huth     }
131d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
132fcf5ef2aSThomas Huth }
133fcf5ef2aSThomas Huth 
134bdfc1e88SEdgar E. Iglesias /*
1359ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1369ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1379ba8cd45SEdgar E. Iglesias  */
trap_illegal(DisasContext * dc,bool cond)1389ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1399ba8cd45SEdgar E. Iglesias {
1402c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1414b893631SRichard Henderson         && dc->cfg->illegal_opcode_exception) {
14241ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1439ba8cd45SEdgar E. Iglesias     }
1449ba8cd45SEdgar E. Iglesias     return cond;
1459ba8cd45SEdgar E. Iglesias }
1469ba8cd45SEdgar E. Iglesias 
1479ba8cd45SEdgar E. Iglesias /*
148bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
149bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
150bdfc1e88SEdgar E. Iglesias  */
trap_userspace(DisasContext * dc,bool cond)151bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
152bdfc1e88SEdgar E. Iglesias {
153287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
154bdfc1e88SEdgar E. Iglesias 
1552c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
15641ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
157bdfc1e88SEdgar E. Iglesias     }
158bdfc1e88SEdgar E. Iglesias     return cond_user;
159bdfc1e88SEdgar E. Iglesias }
160bdfc1e88SEdgar E. Iglesias 
1612a7567a2SRichard Henderson /*
1622a7567a2SRichard Henderson  * Return true, and log an error, if the current insn is
1632a7567a2SRichard Henderson  * within a delay slot.
1642a7567a2SRichard Henderson  */
invalid_delay_slot(DisasContext * dc,const char * insn_type)1652a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
1662a7567a2SRichard Henderson {
1672a7567a2SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1682a7567a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
1692a7567a2SRichard Henderson                       "Invalid insn in delay slot: %s at %08x\n",
1702a7567a2SRichard Henderson                       insn_type, (uint32_t)dc->base.pc_next);
1712a7567a2SRichard Henderson         return true;
1722a7567a2SRichard Henderson     }
1732a7567a2SRichard Henderson     return false;
1742a7567a2SRichard Henderson }
1752a7567a2SRichard Henderson 
reg_for_read(DisasContext * dc,int reg)17620800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
177fcf5ef2aSThomas Huth {
17820800179SRichard Henderson     if (likely(reg != 0)) {
17920800179SRichard Henderson         return cpu_R[reg];
180fcf5ef2aSThomas Huth     }
18120800179SRichard Henderson     if (!dc->r0_set) {
18220800179SRichard Henderson         if (dc->r0 == NULL) {
18320800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
184fcf5ef2aSThomas Huth         }
18520800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
18620800179SRichard Henderson         dc->r0_set = true;
18720800179SRichard Henderson     }
18820800179SRichard Henderson     return dc->r0;
189fcf5ef2aSThomas Huth }
190fcf5ef2aSThomas Huth 
reg_for_write(DisasContext * dc,int reg)19120800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
19220800179SRichard Henderson {
19320800179SRichard Henderson     if (likely(reg != 0)) {
19420800179SRichard Henderson         return cpu_R[reg];
19520800179SRichard Henderson     }
19620800179SRichard Henderson     if (dc->r0 == NULL) {
19720800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
19820800179SRichard Henderson     }
19920800179SRichard Henderson     return dc->r0;
200fcf5ef2aSThomas Huth }
201fcf5ef2aSThomas Huth 
do_typea(DisasContext * dc,arg_typea * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32,TCGv_i32))20220800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
20320800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
20420800179SRichard Henderson {
20520800179SRichard Henderson     TCGv_i32 rd, ra, rb;
20620800179SRichard Henderson 
20720800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
20820800179SRichard Henderson         return true;
209fcf5ef2aSThomas Huth     }
21020800179SRichard Henderson 
21120800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
21220800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
21320800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
21420800179SRichard Henderson     fn(rd, ra, rb);
21520800179SRichard Henderson     return true;
21620800179SRichard Henderson }
21720800179SRichard Henderson 
do_typea0(DisasContext * dc,arg_typea0 * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32))21839cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
21939cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
22039cf3864SRichard Henderson {
22139cf3864SRichard Henderson     TCGv_i32 rd, ra;
22239cf3864SRichard Henderson 
22339cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
22439cf3864SRichard Henderson         return true;
22539cf3864SRichard Henderson     }
22639cf3864SRichard Henderson 
22739cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
22839cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
22939cf3864SRichard Henderson     fn(rd, ra);
23039cf3864SRichard Henderson     return true;
23139cf3864SRichard Henderson }
23239cf3864SRichard Henderson 
do_typeb_imm(DisasContext * dc,arg_typeb * arg,bool side_effects,void (* fni)(TCGv_i32,TCGv_i32,int32_t))23320800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
23420800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
23520800179SRichard Henderson {
23620800179SRichard Henderson     TCGv_i32 rd, ra;
23720800179SRichard Henderson 
23820800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
23920800179SRichard Henderson         return true;
24020800179SRichard Henderson     }
24120800179SRichard Henderson 
24220800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
24320800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
24420800179SRichard Henderson     fni(rd, ra, arg->imm);
24520800179SRichard Henderson     return true;
24620800179SRichard Henderson }
24720800179SRichard Henderson 
do_typeb_val(DisasContext * dc,arg_typeb * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32,TCGv_i32))24820800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
24920800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
25020800179SRichard Henderson {
25120800179SRichard Henderson     TCGv_i32 rd, ra, imm;
25220800179SRichard Henderson 
25320800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
25420800179SRichard Henderson         return true;
25520800179SRichard Henderson     }
25620800179SRichard Henderson 
25720800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
25820800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
259a5ea3dd7SRichard Henderson     imm = tcg_constant_i32(arg->imm);
26020800179SRichard Henderson 
26120800179SRichard Henderson     fn(rd, ra, imm);
26220800179SRichard Henderson     return true;
26320800179SRichard Henderson }
26420800179SRichard Henderson 
26520800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
26620800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
26720800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
26820800179SRichard Henderson 
269607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
270607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
2714b893631SRichard Henderson     { return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
272607f5767SRichard Henderson 
27339cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
27439cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
27539cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
27639cf3864SRichard Henderson 
27739cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
27839cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
2794b893631SRichard Henderson     { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
28039cf3864SRichard Henderson 
28120800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
28220800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
28320800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
28420800179SRichard Henderson 
28597955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
28697955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
2874b893631SRichard Henderson     { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
28897955cebSRichard Henderson 
28920800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
29020800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29120800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
29220800179SRichard Henderson 
293d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
294d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
295ad75a51eSRichard Henderson     { HELPER(out, tcg_env, ina); }
296d5aead3dSRichard Henderson 
297d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
298d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
299ad75a51eSRichard Henderson     { HELPER(out, tcg_env, ina, inb); }
300d5aead3dSRichard Henderson 
30120800179SRichard Henderson /* No input carry, but output carry. */
gen_add(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)30220800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
30320800179SRichard Henderson {
304a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
30520800179SRichard Henderson 
30620800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
30720800179SRichard Henderson }
30820800179SRichard Henderson 
30920800179SRichard Henderson /* Input and output carry. */
gen_addc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)31020800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
31120800179SRichard Henderson {
312a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
31320800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
31420800179SRichard Henderson 
31520800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
31620800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
31720800179SRichard Henderson }
31820800179SRichard Henderson 
31920800179SRichard Henderson /* Input carry, but no output carry. */
gen_addkc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)32020800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
32120800179SRichard Henderson {
32220800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
32320800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
32420800179SRichard Henderson }
32520800179SRichard Henderson 
DO_TYPEA(add,true,gen_add)32620800179SRichard Henderson DO_TYPEA(add, true, gen_add)
32720800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
32820800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
32920800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
33020800179SRichard Henderson 
33120800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
33220800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
33320800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
33420800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
33520800179SRichard Henderson 
336cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
337cb0a0a4cSRichard Henderson {
338cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
339cb0a0a4cSRichard Henderson }
340cb0a0a4cSRichard Henderson 
DO_TYPEA(and,false,tcg_gen_and_i32)341cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
342cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
343cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
344cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
345cb0a0a4cSRichard Henderson 
346081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
347081d8e02SRichard Henderson {
348081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
349081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
350081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
351081d8e02SRichard Henderson }
352081d8e02SRichard Henderson 
gen_bsrl(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)353081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
354081d8e02SRichard Henderson {
355081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
356081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
357081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
358081d8e02SRichard Henderson }
359081d8e02SRichard Henderson 
gen_bsll(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)360081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
361081d8e02SRichard Henderson {
362081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
363081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
364081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
365081d8e02SRichard Henderson }
366081d8e02SRichard Henderson 
gen_bsefi(TCGv_i32 out,TCGv_i32 ina,int32_t imm)367081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
368081d8e02SRichard Henderson {
369081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
370081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
371081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
372081d8e02SRichard Henderson 
373081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
374081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
375081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
376081d8e02SRichard Henderson                       imm_w, imm_s);
377081d8e02SRichard Henderson     } else {
378081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
379081d8e02SRichard Henderson     }
380081d8e02SRichard Henderson }
381081d8e02SRichard Henderson 
gen_bsifi(TCGv_i32 out,TCGv_i32 ina,int32_t imm)382081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
383081d8e02SRichard Henderson {
384081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
385081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
386081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
387081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
388081d8e02SRichard Henderson 
389081d8e02SRichard Henderson     if (imm_w < imm_s) {
390081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
391081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
392081d8e02SRichard Henderson                       imm_w, imm_s);
393081d8e02SRichard Henderson     } else {
394081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
395081d8e02SRichard Henderson     }
396081d8e02SRichard Henderson }
397081d8e02SRichard Henderson 
DO_TYPEA_CFG(bsra,use_barrel,false,gen_bsra)398081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
399081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
400081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
401081d8e02SRichard Henderson 
402081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
403081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
404081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
405081d8e02SRichard Henderson 
406081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
407081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
408081d8e02SRichard Henderson 
40939cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
41039cf3864SRichard Henderson {
41139cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
41239cf3864SRichard Henderson }
41339cf3864SRichard Henderson 
DO_TYPEA0_CFG(clz,use_pcmp_instr,false,gen_clz)41439cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
41539cf3864SRichard Henderson 
41658b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
41758b48b63SRichard Henderson {
41858b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
41958b48b63SRichard Henderson 
42058b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
42158b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
42258b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
42358b48b63SRichard Henderson }
42458b48b63SRichard Henderson 
gen_cmpu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)42558b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
42658b48b63SRichard Henderson {
42758b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
42858b48b63SRichard Henderson 
42958b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
43058b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
43158b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
43258b48b63SRichard Henderson }
43358b48b63SRichard Henderson 
DO_TYPEA(cmp,false,gen_cmp)43458b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
43558b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
436a2b0b90eSRichard Henderson 
437d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
438d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
439d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
440d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
441d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
442d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
443d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
444d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
445d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
446d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
447d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
448d5aead3dSRichard Henderson 
449d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
450d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
451d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
452d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
453d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
454d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
455d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
456d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
457d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
458d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
459d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
460d5aead3dSRichard Henderson 
461d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
462d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
463d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
464d5aead3dSRichard Henderson 
465d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
466d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
467d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
468d5aead3dSRichard Henderson 
469d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
470b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
471b1354342SRichard Henderson {
472ad75a51eSRichard Henderson     gen_helper_divs(out, tcg_env, inb, ina);
473b1354342SRichard Henderson }
474b1354342SRichard Henderson 
gen_idivu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)475b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
476b1354342SRichard Henderson {
477ad75a51eSRichard Henderson     gen_helper_divu(out, tcg_env, inb, ina);
478b1354342SRichard Henderson }
479b1354342SRichard Henderson 
DO_TYPEA_CFG(idiv,use_div,true,gen_idiv)480b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
481b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
482b1354342SRichard Henderson 
483e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
484e64b2e5cSRichard Henderson {
4852a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "imm")) {
4862a7567a2SRichard Henderson         return true;
4872a7567a2SRichard Henderson     }
488e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
489e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
4906f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
491e64b2e5cSRichard Henderson     return true;
492e64b2e5cSRichard Henderson }
493e64b2e5cSRichard Henderson 
gen_mulh(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)49497955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
49597955cebSRichard Henderson {
49697955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
49797955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
49897955cebSRichard Henderson }
49997955cebSRichard Henderson 
gen_mulhu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)50097955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
50197955cebSRichard Henderson {
50297955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
50397955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
50497955cebSRichard Henderson }
50597955cebSRichard Henderson 
gen_mulhsu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)50697955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
50797955cebSRichard Henderson {
50897955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
50997955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
51097955cebSRichard Henderson }
51197955cebSRichard Henderson 
DO_TYPEA_CFG(mul,use_hw_mul,false,tcg_gen_mul_i32)51297955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
51397955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
51497955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
51597955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
51697955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
51797955cebSRichard Henderson 
518cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
519cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
520cb0a0a4cSRichard Henderson 
521607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
522607f5767SRichard Henderson {
523607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
524607f5767SRichard Henderson }
525607f5767SRichard Henderson 
gen_pcmpne(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)526607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
527607f5767SRichard Henderson {
528607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
529607f5767SRichard Henderson }
530607f5767SRichard Henderson 
DO_TYPEA_CFG(pcmpbf,use_pcmp_instr,false,gen_helper_pcmpbf)531607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
532607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
533607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
534607f5767SRichard Henderson 
535a2b0b90eSRichard Henderson /* No input carry, but output carry. */
536a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
537a2b0b90eSRichard Henderson {
538a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
539a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
540a2b0b90eSRichard Henderson }
541a2b0b90eSRichard Henderson 
542a2b0b90eSRichard Henderson /* Input and output carry. */
gen_rsubc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)543a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
544a2b0b90eSRichard Henderson {
545a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
546a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
547a2b0b90eSRichard Henderson 
548a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
549a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
550a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
551a2b0b90eSRichard Henderson }
552a2b0b90eSRichard Henderson 
553a2b0b90eSRichard Henderson /* No input or output carry. */
gen_rsubk(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)554a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
555a2b0b90eSRichard Henderson {
556a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
557a2b0b90eSRichard Henderson }
558a2b0b90eSRichard Henderson 
559a2b0b90eSRichard Henderson /* Input carry, no output carry. */
gen_rsubkc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)560a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
561a2b0b90eSRichard Henderson {
562a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
563a2b0b90eSRichard Henderson 
564a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
565a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
566a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
567a2b0b90eSRichard Henderson }
568a2b0b90eSRichard Henderson 
DO_TYPEA(rsub,true,gen_rsub)569a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
570a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
571a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
572a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
573a2b0b90eSRichard Henderson 
574a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
575a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
576a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
577a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
578a2b0b90eSRichard Henderson 
57939cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
58039cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
58139cf3864SRichard Henderson 
58239cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
58339cf3864SRichard Henderson {
58439cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
58539cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
58639cf3864SRichard Henderson }
58739cf3864SRichard Henderson 
gen_src(TCGv_i32 out,TCGv_i32 ina)58839cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
58939cf3864SRichard Henderson {
59039cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
59139cf3864SRichard Henderson 
59239cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
59339cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
59439cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
59539cf3864SRichard Henderson }
59639cf3864SRichard Henderson 
gen_srl(TCGv_i32 out,TCGv_i32 ina)59739cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
59839cf3864SRichard Henderson {
59939cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
60039cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
60139cf3864SRichard Henderson }
60239cf3864SRichard Henderson 
DO_TYPEA0(sra,false,gen_sra)60339cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
60439cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
60539cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
60639cf3864SRichard Henderson 
60739cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
60839cf3864SRichard Henderson {
60939cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
61039cf3864SRichard Henderson }
61139cf3864SRichard Henderson 
DO_TYPEA0(swapb,false,tcg_gen_bswap32_i32)61239cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
61339cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
61439cf3864SRichard Henderson 
61539cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
61639cf3864SRichard Henderson {
61739cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
61839cf3864SRichard Henderson     trap_userspace(dc, true);
61939cf3864SRichard Henderson     return true;
62039cf3864SRichard Henderson }
62139cf3864SRichard Henderson 
DO_TYPEA(xor,false,tcg_gen_xor_i32)622cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
623cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
624cb0a0a4cSRichard Henderson 
625d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
626d8e59c4aSRichard Henderson {
627d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
628d8e59c4aSRichard Henderson 
629d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
630d8e59c4aSRichard Henderson     if (ra && rb) {
631d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
632d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
633d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
634d8e59c4aSRichard Henderson     } else if (ra) {
635d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
636d8e59c4aSRichard Henderson     } else if (rb) {
637d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
638d8e59c4aSRichard Henderson     } else {
639d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
640d8e59c4aSRichard Henderson     }
641d8e59c4aSRichard Henderson 
6424b893631SRichard Henderson     if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
643ad75a51eSRichard Henderson         gen_helper_stackprot(tcg_env, ret);
644d8e59c4aSRichard Henderson     }
645d8e59c4aSRichard Henderson     return ret;
646d8e59c4aSRichard Henderson }
647d8e59c4aSRichard Henderson 
compute_ldst_addr_typeb(DisasContext * dc,int ra,int imm)648d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
649d8e59c4aSRichard Henderson {
650d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
651d8e59c4aSRichard Henderson 
652d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
653d8e59c4aSRichard Henderson     if (ra) {
654d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
655d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
656d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
657d8e59c4aSRichard Henderson     } else {
658d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
659d8e59c4aSRichard Henderson     }
660d8e59c4aSRichard Henderson 
6614b893631SRichard Henderson     if (ra == 1 && dc->cfg->stackprot) {
662ad75a51eSRichard Henderson         gen_helper_stackprot(tcg_env, ret);
663d8e59c4aSRichard Henderson     }
664d8e59c4aSRichard Henderson     return ret;
665d8e59c4aSRichard Henderson }
666d8e59c4aSRichard Henderson 
66719f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
compute_ldst_addr_ea(DisasContext * dc,int ra,int rb)668d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
669d8e59c4aSRichard Henderson {
6704b893631SRichard Henderson     int addr_size = dc->cfg->addr_size;
671d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
672d8e59c4aSRichard Henderson 
673d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
674d8e59c4aSRichard Henderson         if (rb) {
675d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
676d8e59c4aSRichard Henderson         } else {
677d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
678d8e59c4aSRichard Henderson         }
679d8e59c4aSRichard Henderson     } else {
680d8e59c4aSRichard Henderson         if (rb) {
681d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
682d8e59c4aSRichard Henderson         } else {
683d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
684d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
685d8e59c4aSRichard Henderson         }
686d8e59c4aSRichard Henderson         if (addr_size < 64) {
687d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
688d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
689d8e59c4aSRichard Henderson         }
690d8e59c4aSRichard Henderson     }
691d8e59c4aSRichard Henderson     return ret;
692d8e59c4aSRichard Henderson }
69319f27b6cSRichard Henderson #endif
694d8e59c4aSRichard Henderson 
695b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
record_unaligned_ess(DisasContext * dc,int rd,MemOp size,bool store)696ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
697ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
698ab0c8d0fSRichard Henderson {
699e2313450SRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->base.insn_start, 1);
700ab0c8d0fSRichard Henderson 
701ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
702ab0c8d0fSRichard Henderson     iflags |= rd << 5;
703ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
704ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
705ab0c8d0fSRichard Henderson 
706e2313450SRichard Henderson     tcg_set_insn_start_param(dc->base.insn_start, 1, iflags);
707ab0c8d0fSRichard Henderson }
708b414df75SRichard Henderson #endif
709ab0c8d0fSRichard Henderson 
do_load(DisasContext * dc,int rd,TCGv addr,MemOp mop,int mem_index,bool rev)710d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
711d8e59c4aSRichard Henderson                     int mem_index, bool rev)
712d8e59c4aSRichard Henderson {
713d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
714d8e59c4aSRichard Henderson 
715d8e59c4aSRichard Henderson     /*
716d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
717d8e59c4aSRichard Henderson      *
718d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
719d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
720d8e59c4aSRichard Henderson      */
721d8e59c4aSRichard Henderson     if (rev) {
722d8e59c4aSRichard Henderson         if (size > MO_8) {
723d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
724d8e59c4aSRichard Henderson         }
725d8e59c4aSRichard Henderson         if (size < MO_32) {
726d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
727d8e59c4aSRichard Henderson         }
728d8e59c4aSRichard Henderson     }
729d8e59c4aSRichard Henderson 
730b414df75SRichard Henderson     /*
731b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
732b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
733b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
734b414df75SRichard Henderson      */
735b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
736ab0c8d0fSRichard Henderson     if (size > MO_8 &&
737ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
7384b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
739ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
740ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
741d8e59c4aSRichard Henderson     }
742b414df75SRichard Henderson #endif
743d8e59c4aSRichard Henderson 
744ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
745d8e59c4aSRichard Henderson     return true;
746d8e59c4aSRichard Henderson }
747d8e59c4aSRichard Henderson 
trans_lbu(DisasContext * dc,arg_typea * arg)748d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
749d8e59c4aSRichard Henderson {
750d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
751d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
752d8e59c4aSRichard Henderson }
753d8e59c4aSRichard Henderson 
trans_lbur(DisasContext * dc,arg_typea * arg)754d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
755d8e59c4aSRichard Henderson {
756d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
757d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
758d8e59c4aSRichard Henderson }
759d8e59c4aSRichard Henderson 
trans_lbuea(DisasContext * dc,arg_typea * arg)760d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
761d8e59c4aSRichard Henderson {
762d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
763d8e59c4aSRichard Henderson         return true;
764d8e59c4aSRichard Henderson     }
76519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
76619f27b6cSRichard Henderson     return true;
76719f27b6cSRichard Henderson #else
768d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
769d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
77019f27b6cSRichard Henderson #endif
771d8e59c4aSRichard Henderson }
772d8e59c4aSRichard Henderson 
trans_lbui(DisasContext * dc,arg_typeb * arg)773d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
774d8e59c4aSRichard Henderson {
775d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
776d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
777d8e59c4aSRichard Henderson }
778d8e59c4aSRichard Henderson 
trans_lhu(DisasContext * dc,arg_typea * arg)779d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
780d8e59c4aSRichard Henderson {
781d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
782d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
783d8e59c4aSRichard Henderson }
784d8e59c4aSRichard Henderson 
trans_lhur(DisasContext * dc,arg_typea * arg)785d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
786d8e59c4aSRichard Henderson {
787d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
788d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
789d8e59c4aSRichard Henderson }
790d8e59c4aSRichard Henderson 
trans_lhuea(DisasContext * dc,arg_typea * arg)791d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
792d8e59c4aSRichard Henderson {
793d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
794d8e59c4aSRichard Henderson         return true;
795d8e59c4aSRichard Henderson     }
79619f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
79719f27b6cSRichard Henderson     return true;
79819f27b6cSRichard Henderson #else
799d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
800d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
80119f27b6cSRichard Henderson #endif
802d8e59c4aSRichard Henderson }
803d8e59c4aSRichard Henderson 
trans_lhui(DisasContext * dc,arg_typeb * arg)804d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
805d8e59c4aSRichard Henderson {
806d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
807d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
808d8e59c4aSRichard Henderson }
809d8e59c4aSRichard Henderson 
trans_lw(DisasContext * dc,arg_typea * arg)810d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
811d8e59c4aSRichard Henderson {
812d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
813d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
814d8e59c4aSRichard Henderson }
815d8e59c4aSRichard Henderson 
trans_lwr(DisasContext * dc,arg_typea * arg)816d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
817d8e59c4aSRichard Henderson {
818d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
819d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
820d8e59c4aSRichard Henderson }
821d8e59c4aSRichard Henderson 
trans_lwea(DisasContext * dc,arg_typea * arg)822d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
823d8e59c4aSRichard Henderson {
824d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
825d8e59c4aSRichard Henderson         return true;
826d8e59c4aSRichard Henderson     }
82719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
82819f27b6cSRichard Henderson     return true;
82919f27b6cSRichard Henderson #else
830d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
831d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
83219f27b6cSRichard Henderson #endif
833d8e59c4aSRichard Henderson }
834d8e59c4aSRichard Henderson 
trans_lwi(DisasContext * dc,arg_typeb * arg)835d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
836d8e59c4aSRichard Henderson {
837d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
838d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
839d8e59c4aSRichard Henderson }
840d8e59c4aSRichard Henderson 
trans_lwx(DisasContext * dc,arg_typea * arg)841d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
842d8e59c4aSRichard Henderson {
843d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
844d8e59c4aSRichard Henderson 
845d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
846d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
847d8e59c4aSRichard Henderson 
848d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
849d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
850d8e59c4aSRichard Henderson 
851d8e59c4aSRichard Henderson     if (arg->rd) {
852d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
853d8e59c4aSRichard Henderson     }
854d8e59c4aSRichard Henderson 
855d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
856d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
857d8e59c4aSRichard Henderson     return true;
858d8e59c4aSRichard Henderson }
859d8e59c4aSRichard Henderson 
do_store(DisasContext * dc,int rd,TCGv addr,MemOp mop,int mem_index,bool rev)860d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
861d8e59c4aSRichard Henderson                      int mem_index, bool rev)
862d8e59c4aSRichard Henderson {
863d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
864d8e59c4aSRichard Henderson 
865d8e59c4aSRichard Henderson     /*
866d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
867d8e59c4aSRichard Henderson      *
868d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
869d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
870d8e59c4aSRichard Henderson      */
871d8e59c4aSRichard Henderson     if (rev) {
872d8e59c4aSRichard Henderson         if (size > MO_8) {
873d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
874d8e59c4aSRichard Henderson         }
875d8e59c4aSRichard Henderson         if (size < MO_32) {
876d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
877d8e59c4aSRichard Henderson         }
878d8e59c4aSRichard Henderson     }
879d8e59c4aSRichard Henderson 
880b414df75SRichard Henderson     /*
881b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
882b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
883b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
884b414df75SRichard Henderson      */
885b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
886ab0c8d0fSRichard Henderson     if (size > MO_8 &&
887ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
8884b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
889ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
890ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
891d8e59c4aSRichard Henderson     }
892b414df75SRichard Henderson #endif
893d8e59c4aSRichard Henderson 
894ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
895d8e59c4aSRichard Henderson     return true;
896d8e59c4aSRichard Henderson }
897d8e59c4aSRichard Henderson 
trans_sb(DisasContext * dc,arg_typea * arg)898d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
899d8e59c4aSRichard Henderson {
900d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
901d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
902d8e59c4aSRichard Henderson }
903d8e59c4aSRichard Henderson 
trans_sbr(DisasContext * dc,arg_typea * arg)904d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
905d8e59c4aSRichard Henderson {
906d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
907d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
908d8e59c4aSRichard Henderson }
909d8e59c4aSRichard Henderson 
trans_sbea(DisasContext * dc,arg_typea * arg)910d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
911d8e59c4aSRichard Henderson {
912d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
913d8e59c4aSRichard Henderson         return true;
914d8e59c4aSRichard Henderson     }
91519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
91619f27b6cSRichard Henderson     return true;
91719f27b6cSRichard Henderson #else
918d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
919d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
92019f27b6cSRichard Henderson #endif
921d8e59c4aSRichard Henderson }
922d8e59c4aSRichard Henderson 
trans_sbi(DisasContext * dc,arg_typeb * arg)923d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
924d8e59c4aSRichard Henderson {
925d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
926d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
927d8e59c4aSRichard Henderson }
928d8e59c4aSRichard Henderson 
trans_sh(DisasContext * dc,arg_typea * arg)929d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
930d8e59c4aSRichard Henderson {
931d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
932d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
933d8e59c4aSRichard Henderson }
934d8e59c4aSRichard Henderson 
trans_shr(DisasContext * dc,arg_typea * arg)935d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
936d8e59c4aSRichard Henderson {
937d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
938d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
939d8e59c4aSRichard Henderson }
940d8e59c4aSRichard Henderson 
trans_shea(DisasContext * dc,arg_typea * arg)941d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
942d8e59c4aSRichard Henderson {
943d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
944d8e59c4aSRichard Henderson         return true;
945d8e59c4aSRichard Henderson     }
94619f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
94719f27b6cSRichard Henderson     return true;
94819f27b6cSRichard Henderson #else
949d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
950d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
95119f27b6cSRichard Henderson #endif
952d8e59c4aSRichard Henderson }
953d8e59c4aSRichard Henderson 
trans_shi(DisasContext * dc,arg_typeb * arg)954d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
955d8e59c4aSRichard Henderson {
956d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
957d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
958d8e59c4aSRichard Henderson }
959d8e59c4aSRichard Henderson 
trans_sw(DisasContext * dc,arg_typea * arg)960d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
961d8e59c4aSRichard Henderson {
962d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
963d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
964d8e59c4aSRichard Henderson }
965d8e59c4aSRichard Henderson 
trans_swr(DisasContext * dc,arg_typea * arg)966d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
967d8e59c4aSRichard Henderson {
968d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
969d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
970d8e59c4aSRichard Henderson }
971d8e59c4aSRichard Henderson 
trans_swea(DisasContext * dc,arg_typea * arg)972d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
973d8e59c4aSRichard Henderson {
974d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
975d8e59c4aSRichard Henderson         return true;
976d8e59c4aSRichard Henderson     }
97719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
97819f27b6cSRichard Henderson     return true;
97919f27b6cSRichard Henderson #else
980d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
981d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
98219f27b6cSRichard Henderson #endif
983d8e59c4aSRichard Henderson }
984d8e59c4aSRichard Henderson 
trans_swi(DisasContext * dc,arg_typeb * arg)985d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
986d8e59c4aSRichard Henderson {
987d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
988d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
989d8e59c4aSRichard Henderson }
990d8e59c4aSRichard Henderson 
trans_swx(DisasContext * dc,arg_typea * arg)991d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
992d8e59c4aSRichard Henderson {
993d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
994d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
995d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
996d8e59c4aSRichard Henderson     TCGv_i32 tval;
997d8e59c4aSRichard Henderson 
998d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
999d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1000d8e59c4aSRichard Henderson 
1001d8e59c4aSRichard Henderson     /*
1002d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1003d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1004d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1005d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1006d8e59c4aSRichard Henderson      */
1007d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1008d8e59c4aSRichard Henderson 
1009d8e59c4aSRichard Henderson     /*
1010d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1011d8e59c4aSRichard Henderson      * the reserved location.
1012d8e59c4aSRichard Henderson      */
1013d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1014d8e59c4aSRichard Henderson 
1015d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1016d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1017d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1018d8e59c4aSRichard Henderson 
1019d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1020d8e59c4aSRichard Henderson 
1021d8e59c4aSRichard Henderson     /* Success */
1022d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1023d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1024d8e59c4aSRichard Henderson 
1025d8e59c4aSRichard Henderson     /* Failure */
1026d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1027d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1028d8e59c4aSRichard Henderson 
1029d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1030d8e59c4aSRichard Henderson 
1031d8e59c4aSRichard Henderson     /*
1032d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1033d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1034d8e59c4aSRichard Henderson      */
1035d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1036d8e59c4aSRichard Henderson     return true;
1037d8e59c4aSRichard Henderson }
1038d8e59c4aSRichard Henderson 
setup_dslot(DisasContext * dc,bool type_b)103916bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
104016bbbbc9SRichard Henderson {
104116bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
104216bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
104316bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
104416bbbbc9SRichard Henderson     }
104516bbbbc9SRichard Henderson }
104616bbbbc9SRichard Henderson 
do_branch(DisasContext * dc,int dest_rb,int dest_imm,bool delay,bool abs,int link)104716bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
104816bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
104916bbbbc9SRichard Henderson {
105016bbbbc9SRichard Henderson     uint32_t add_pc;
105116bbbbc9SRichard Henderson 
10522a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "branch")) {
10532a7567a2SRichard Henderson         return true;
10542a7567a2SRichard Henderson     }
105516bbbbc9SRichard Henderson     if (delay) {
105616bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
105716bbbbc9SRichard Henderson     }
105816bbbbc9SRichard Henderson 
105916bbbbc9SRichard Henderson     if (link) {
106016bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
106116bbbbc9SRichard Henderson     }
106216bbbbc9SRichard Henderson 
106316bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
106416bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
106516bbbbc9SRichard Henderson     if (dest_rb > 0) {
106616bbbbc9SRichard Henderson         dc->jmp_dest = -1;
106716bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
106816bbbbc9SRichard Henderson     } else {
106916bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
107016bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
107116bbbbc9SRichard Henderson     }
107216bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
107316bbbbc9SRichard Henderson     return true;
107416bbbbc9SRichard Henderson }
107516bbbbc9SRichard Henderson 
107616bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
107716bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
107816bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
107916bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
108016bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
108116bbbbc9SRichard Henderson 
DO_BR(br,bri,false,false,false)108216bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
108316bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
108416bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
108516bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
108616bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
108716bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
108816bbbbc9SRichard Henderson 
1089fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1090fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1091fd779113SRichard Henderson {
1092fd779113SRichard Henderson     TCGv_i32 zero, next;
1093fd779113SRichard Henderson 
10942a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "bcc")) {
10952a7567a2SRichard Henderson         return true;
10962a7567a2SRichard Henderson     }
1097fd779113SRichard Henderson     if (delay) {
1098fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1099fd779113SRichard Henderson     }
1100fd779113SRichard Henderson 
1101fd779113SRichard Henderson     dc->jmp_cond = cond;
1102fd779113SRichard Henderson 
1103fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1104fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1105fd779113SRichard Henderson 
1106fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1107fd779113SRichard Henderson     if (dest_rb > 0) {
1108fd779113SRichard Henderson         dc->jmp_dest = -1;
1109fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1110fd779113SRichard Henderson     } else {
1111fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1112fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1113fd779113SRichard Henderson     }
1114fd779113SRichard Henderson 
1115fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1116a5ea3dd7SRichard Henderson     zero = tcg_constant_i32(0);
1117a5ea3dd7SRichard Henderson     next = tcg_constant_i32(dc->base.pc_next + (delay + 1) * 4);
1118fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1119fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1120fd779113SRichard Henderson                         cpu_btarget, next);
1121fd779113SRichard Henderson 
1122fd779113SRichard Henderson     return true;
1123fd779113SRichard Henderson }
1124fd779113SRichard Henderson 
1125fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1126fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1127fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1128fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1129fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1130fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1131fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1132fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1133fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1134fd779113SRichard Henderson 
DO_BCC(beq,TCG_COND_EQ)1135fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1136fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1137fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1138fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1139fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1140fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1141fd779113SRichard Henderson 
1142f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1143f5235314SRichard Henderson {
1144f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1145f5235314SRichard Henderson         return true;
1146f5235314SRichard Henderson     }
11472a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brk")) {
11482a7567a2SRichard Henderson         return true;
11492a7567a2SRichard Henderson     }
11502a7567a2SRichard Henderson 
1151f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1152f5235314SRichard Henderson     if (arg->rd) {
1153f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1154f5235314SRichard Henderson     }
1155f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1156f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1157f5235314SRichard Henderson 
115817e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1159f5235314SRichard Henderson     return true;
1160f5235314SRichard Henderson }
1161f5235314SRichard Henderson 
trans_brki(DisasContext * dc,arg_typeb_br * arg)1162f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1163f5235314SRichard Henderson {
1164f5235314SRichard Henderson     uint32_t imm = arg->imm;
1165f5235314SRichard Henderson 
1166f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1167f5235314SRichard Henderson         return true;
1168f5235314SRichard Henderson     }
11692a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brki")) {
11702a7567a2SRichard Henderson         return true;
11712a7567a2SRichard Henderson     }
11722a7567a2SRichard Henderson 
1173f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1174f5235314SRichard Henderson     if (arg->rd) {
1175f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1176f5235314SRichard Henderson     }
1177f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1178f5235314SRichard Henderson 
1179f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1180f5235314SRichard Henderson     switch (imm) {
1181f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1182f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1183f5235314SRichard Henderson         break;
1184f5235314SRichard Henderson     case 0x18: /* debug trap */
1185f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1186f5235314SRichard Henderson         break;
1187f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1188f5235314SRichard Henderson         g_assert_not_reached();
1189f5235314SRichard Henderson     }
1190f5235314SRichard Henderson #else
1191f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1192f5235314SRichard Henderson 
1193f5235314SRichard Henderson     if (imm != 0x18) {
1194f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1195f5235314SRichard Henderson     }
1196f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1197f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1198f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1199f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1200f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1201f5235314SRichard Henderson     }
1202f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
120317e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1204f5235314SRichard Henderson #endif
1205f5235314SRichard Henderson 
1206f5235314SRichard Henderson     return true;
1207f5235314SRichard Henderson }
1208f5235314SRichard Henderson 
trans_mbar(DisasContext * dc,arg_mbar * arg)1209ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1210ee8c7f9fSRichard Henderson {
1211ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1212ee8c7f9fSRichard Henderson 
12132a7567a2SRichard Henderson     /* Note that mbar is a specialized branch instruction. */
12142a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "mbar")) {
12152a7567a2SRichard Henderson         return true;
12162a7567a2SRichard Henderson     }
12172a7567a2SRichard Henderson 
1218ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1219ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1220ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1221ee8c7f9fSRichard Henderson     }
1222ee8c7f9fSRichard Henderson 
1223ee8c7f9fSRichard Henderson     /* Sleep. */
1224ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1225ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1226ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1227ee8c7f9fSRichard Henderson             return true;
1228ee8c7f9fSRichard Henderson         }
1229ee8c7f9fSRichard Henderson 
1230ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1231ee8c7f9fSRichard Henderson 
1232ad75a51eSRichard Henderson         tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
1233ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1234ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1235ee8c7f9fSRichard Henderson 
1236ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1237ee8c7f9fSRichard Henderson 
1238ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1239ee8c7f9fSRichard Henderson     }
1240ee8c7f9fSRichard Henderson 
1241ee8c7f9fSRichard Henderson     /*
1242ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1243ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1244ee8c7f9fSRichard Henderson      * code immediately.
1245ee8c7f9fSRichard Henderson      *
1246ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1247ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1248ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1249ee8c7f9fSRichard Henderson      *
1250ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1251ee8c7f9fSRichard Henderson      */
125243b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
1253ee8c7f9fSRichard Henderson     return true;
1254ee8c7f9fSRichard Henderson }
1255ee8c7f9fSRichard Henderson 
do_rts(DisasContext * dc,arg_typeb_bc * arg,int to_set)1256e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1257e6cb0354SRichard Henderson {
1258e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1259e6cb0354SRichard Henderson         return true;
1260e6cb0354SRichard Henderson     }
12612a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "rts")) {
12622a7567a2SRichard Henderson         return true;
12632a7567a2SRichard Henderson     }
12642a7567a2SRichard Henderson 
1265e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1266e6cb0354SRichard Henderson     setup_dslot(dc, true);
1267e6cb0354SRichard Henderson 
1268e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1269e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1270e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1271e6cb0354SRichard Henderson     return true;
1272e6cb0354SRichard Henderson }
1273e6cb0354SRichard Henderson 
1274e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1275e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1276e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1277e6cb0354SRichard Henderson 
DO_RTS(rtbd,DRTB_FLAG)1278e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1279e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1280e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1281e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1282e6cb0354SRichard Henderson 
128320800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
128420800179SRichard Henderson {
128520800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
12864b893631SRichard Henderson     if (dc->cfg->opcode_0_illegal) {
128720800179SRichard Henderson         trap_illegal(dc, true);
128820800179SRichard Henderson         return true;
128920800179SRichard Henderson     }
129020800179SRichard Henderson     /*
129120800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
129220800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
129320800179SRichard Henderson      */
129420800179SRichard Henderson     return false;
1295fcf5ef2aSThomas Huth }
1296fcf5ef2aSThomas Huth 
msr_read(DisasContext * dc,TCGv_i32 d)12971074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1298fcf5ef2aSThomas Huth {
12991074c0fbSRichard Henderson     TCGv_i32 t;
13001074c0fbSRichard Henderson 
13011074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
13021074c0fbSRichard Henderson     t = tcg_temp_new_i32();
13031074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13041074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
1305fcf5ef2aSThomas Huth }
1306fcf5ef2aSThomas Huth 
do_msrclrset(DisasContext * dc,arg_type_msr * arg,bool set)1307536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1308536e340fSRichard Henderson {
1309536e340fSRichard Henderson     uint32_t imm = arg->imm;
1310536e340fSRichard Henderson 
1311536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1312536e340fSRichard Henderson         return true;
1313536e340fSRichard Henderson     }
1314536e340fSRichard Henderson 
1315536e340fSRichard Henderson     if (arg->rd) {
1316536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1317536e340fSRichard Henderson     }
1318536e340fSRichard Henderson 
1319536e340fSRichard Henderson     /*
1320536e340fSRichard Henderson      * Handle the carry bit separately.
1321536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1322536e340fSRichard Henderson      */
1323536e340fSRichard Henderson     if (imm & MSR_C) {
1324536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1325536e340fSRichard Henderson     }
1326536e340fSRichard Henderson 
1327536e340fSRichard Henderson     /*
1328536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1329536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1330536e340fSRichard Henderson      */
1331536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1332536e340fSRichard Henderson 
1333536e340fSRichard Henderson     if (imm != 0) {
1334536e340fSRichard Henderson         if (set) {
1335536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1336536e340fSRichard Henderson         } else {
1337536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1338536e340fSRichard Henderson         }
133943b34134SRichard Henderson         dc->base.is_jmp = DISAS_EXIT_NEXT;
1340536e340fSRichard Henderson     }
1341536e340fSRichard Henderson     return true;
1342536e340fSRichard Henderson }
1343536e340fSRichard Henderson 
trans_msrclr(DisasContext * dc,arg_type_msr * arg)1344536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1345536e340fSRichard Henderson {
1346536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1347536e340fSRichard Henderson }
1348536e340fSRichard Henderson 
trans_msrset(DisasContext * dc,arg_type_msr * arg)1349536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1350536e340fSRichard Henderson {
1351536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1352536e340fSRichard Henderson }
1353536e340fSRichard Henderson 
trans_mts(DisasContext * dc,arg_mts * arg)13549df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
1355fcf5ef2aSThomas Huth {
13569df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
13579df297a2SRichard Henderson         return true;
1358f0f7e7f7SEdgar E. Iglesias     }
1359f0f7e7f7SEdgar E. Iglesias 
13609df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
13619df297a2SRichard Henderson     g_assert_not_reached();
13629df297a2SRichard Henderson #else
13639df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
13649df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
13659df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
13669df297a2SRichard Henderson         return true;
13672023e9a3SEdgar E. Iglesias     }
1368fcf5ef2aSThomas Huth 
13699df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
13709df297a2SRichard Henderson     switch (arg->rs) {
1371aa28e6d4SRichard Henderson     case SR_MSR:
137243b34134SRichard Henderson         /* Install MSR_C.  */
137343b34134SRichard Henderson         tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
137443b34134SRichard Henderson         /*
137543b34134SRichard Henderson          * Clear MSR_C and MSR_CC;
137643b34134SRichard Henderson          * MSR_PVR is not writable, and is always clear.
137743b34134SRichard Henderson          */
137843b34134SRichard Henderson         tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
1379fcf5ef2aSThomas Huth         break;
13809df297a2SRichard Henderson     case SR_FSR:
1381ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, fsr));
13829df297a2SRichard Henderson         break;
13839df297a2SRichard Henderson     case 0x800:
1384ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, slr));
13859df297a2SRichard Henderson         break;
13869df297a2SRichard Henderson     case 0x802:
1387ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, shr));
13889df297a2SRichard Henderson         break;
13899df297a2SRichard Henderson 
13909df297a2SRichard Henderson     case 0x1000: /* PID */
13919df297a2SRichard Henderson     case 0x1001: /* ZPR */
13929df297a2SRichard Henderson     case 0x1002: /* TLBX */
13939df297a2SRichard Henderson     case 0x1003: /* TLBLO */
13949df297a2SRichard Henderson     case 0x1004: /* TLBHI */
13959df297a2SRichard Henderson     case 0x1005: /* TLBSX */
13969df297a2SRichard Henderson         {
1397a5ea3dd7SRichard Henderson             TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1398a5ea3dd7SRichard Henderson             TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
13999df297a2SRichard Henderson 
1400ad75a51eSRichard Henderson             gen_helper_mmu_write(tcg_env, tmp_ext, tmp_reg, src);
14019df297a2SRichard Henderson         }
14029df297a2SRichard Henderson         break;
14039df297a2SRichard Henderson 
14049df297a2SRichard Henderson     default:
14059df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14069df297a2SRichard Henderson         return true;
14079df297a2SRichard Henderson     }
140843b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
14099df297a2SRichard Henderson     return true;
14109df297a2SRichard Henderson #endif
14119df297a2SRichard Henderson }
14129df297a2SRichard Henderson 
trans_mfs(DisasContext * dc,arg_mfs * arg)14139df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14149df297a2SRichard Henderson {
14159df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
14169df297a2SRichard Henderson 
14179df297a2SRichard Henderson     if (arg->e) {
14189df297a2SRichard Henderson         switch (arg->rs) {
1419351527b7SEdgar E. Iglesias         case SR_EAR:
1420dbdb77c4SRichard Henderson             {
1421dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
1422ad75a51eSRichard Henderson                 tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14239df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1424dbdb77c4SRichard Henderson             }
14259df297a2SRichard Henderson             return true;
14269df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14279df297a2SRichard Henderson         case 0x1003: /* TLBLO */
14289df297a2SRichard Henderson             /* Handled below. */
1429aa28e6d4SRichard Henderson             break;
14309df297a2SRichard Henderson #endif
14319df297a2SRichard Henderson         case 0x2006 ... 0x2009:
14329df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
14339df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
14349df297a2SRichard Henderson             return true;
1435fcf5ef2aSThomas Huth         default:
14369df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
14379df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
14389df297a2SRichard Henderson             return true;
1439fcf5ef2aSThomas Huth         }
14409df297a2SRichard Henderson     }
14419df297a2SRichard Henderson 
14429df297a2SRichard Henderson     switch (arg->rs) {
1443aa28e6d4SRichard Henderson     case SR_PC:
14449df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
1445fcf5ef2aSThomas Huth         break;
1446aa28e6d4SRichard Henderson     case SR_MSR:
14479df297a2SRichard Henderson         msr_read(dc, dest);
1448fcf5ef2aSThomas Huth         break;
1449351527b7SEdgar E. Iglesias     case SR_EAR:
1450dbdb77c4SRichard Henderson         {
1451dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1452ad75a51eSRichard Henderson             tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14539df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1454a1b48e3aSEdgar E. Iglesias         }
1455aa28e6d4SRichard Henderson         break;
1456351527b7SEdgar E. Iglesias     case SR_ESR:
1457ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, esr));
1458aa28e6d4SRichard Henderson         break;
1459351527b7SEdgar E. Iglesias     case SR_FSR:
1460ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, fsr));
1461aa28e6d4SRichard Henderson         break;
1462351527b7SEdgar E. Iglesias     case SR_BTR:
1463ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, btr));
1464aa28e6d4SRichard Henderson         break;
14657cdae31dSTong Ho     case SR_EDR:
1466ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, edr));
1467fcf5ef2aSThomas Huth         break;
1468fcf5ef2aSThomas Huth     case 0x800:
1469ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, slr));
1470fcf5ef2aSThomas Huth         break;
1471fcf5ef2aSThomas Huth     case 0x802:
1472ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, shr));
1473fcf5ef2aSThomas Huth         break;
14749df297a2SRichard Henderson 
14759df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14769df297a2SRichard Henderson     case 0x1000: /* PID */
14779df297a2SRichard Henderson     case 0x1001: /* ZPR */
14789df297a2SRichard Henderson     case 0x1002: /* TLBX */
14799df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14809df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14819df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14829df297a2SRichard Henderson         {
1483a5ea3dd7SRichard Henderson             TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1484a5ea3dd7SRichard Henderson             TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
14859df297a2SRichard Henderson 
1486ad75a51eSRichard Henderson             gen_helper_mmu_read(dest, tcg_env, tmp_ext, tmp_reg);
14879df297a2SRichard Henderson         }
14889df297a2SRichard Henderson         break;
14899df297a2SRichard Henderson #endif
14909df297a2SRichard Henderson 
1491351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
1492ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env,
1493a4bcfc33SRichard Henderson                        offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1494a4bcfc33SRichard Henderson                        - offsetof(MicroBlazeCPU, env));
1495fcf5ef2aSThomas Huth         break;
1496fcf5ef2aSThomas Huth     default:
14979df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1498fcf5ef2aSThomas Huth         break;
1499fcf5ef2aSThomas Huth     }
15009df297a2SRichard Henderson     return true;
1501fcf5ef2aSThomas Huth }
1502fcf5ef2aSThomas Huth 
do_rti(DisasContext * dc)15033fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
1504fcf5ef2aSThomas Huth {
15053fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1506fcf5ef2aSThomas Huth 
15073fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15083fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15093fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15103fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15113fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1512fcf5ef2aSThomas Huth }
1513fcf5ef2aSThomas Huth 
do_rtb(DisasContext * dc)15143fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
1515fcf5ef2aSThomas Huth {
15163fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1517fcf5ef2aSThomas Huth 
15183fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15193fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15203fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15213fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1522fcf5ef2aSThomas Huth }
1523fcf5ef2aSThomas Huth 
do_rte(DisasContext * dc)15243fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
1525fcf5ef2aSThomas Huth {
15263fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1527fcf5ef2aSThomas Huth 
15283fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15293fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15303fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15313fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15323fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1533fcf5ef2aSThomas Huth }
1534fcf5ef2aSThomas Huth 
1535fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
do_get(DisasContext * dc,int rd,int rb,int imm,int ctrl)153652065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1537fcf5ef2aSThomas Huth {
1538fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1539fcf5ef2aSThomas Huth 
1540bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
154152065d8fSRichard Henderson         return true;
1542fcf5ef2aSThomas Huth     }
1543fcf5ef2aSThomas Huth 
1544cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
154552065d8fSRichard Henderson     if (rb) {
154652065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1547fcf5ef2aSThomas Huth     } else {
154852065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
1549fcf5ef2aSThomas Huth     }
1550fcf5ef2aSThomas Huth 
1551a5ea3dd7SRichard Henderson     t_ctrl = tcg_constant_i32(ctrl);
155252065d8fSRichard Henderson     gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
155352065d8fSRichard Henderson     return true;
155452065d8fSRichard Henderson }
155552065d8fSRichard Henderson 
trans_get(DisasContext * dc,arg_get * arg)155652065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
155752065d8fSRichard Henderson {
155852065d8fSRichard Henderson     return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
155952065d8fSRichard Henderson }
156052065d8fSRichard Henderson 
trans_getd(DisasContext * dc,arg_getd * arg)156152065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
156252065d8fSRichard Henderson {
156352065d8fSRichard Henderson     return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
156452065d8fSRichard Henderson }
156552065d8fSRichard Henderson 
do_put(DisasContext * dc,int ra,int rb,int imm,int ctrl)156652065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
156752065d8fSRichard Henderson {
156852065d8fSRichard Henderson     TCGv_i32 t_id, t_ctrl;
156952065d8fSRichard Henderson 
157052065d8fSRichard Henderson     if (trap_userspace(dc, true)) {
157152065d8fSRichard Henderson         return true;
157252065d8fSRichard Henderson     }
157352065d8fSRichard Henderson 
157452065d8fSRichard Henderson     t_id = tcg_temp_new_i32();
157552065d8fSRichard Henderson     if (rb) {
157652065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
157752065d8fSRichard Henderson     } else {
157852065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
157952065d8fSRichard Henderson     }
158052065d8fSRichard Henderson 
1581a5ea3dd7SRichard Henderson     t_ctrl = tcg_constant_i32(ctrl);
158252065d8fSRichard Henderson     gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
158352065d8fSRichard Henderson     return true;
158452065d8fSRichard Henderson }
158552065d8fSRichard Henderson 
trans_put(DisasContext * dc,arg_put * arg)158652065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
158752065d8fSRichard Henderson {
158852065d8fSRichard Henderson     return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
158952065d8fSRichard Henderson }
159052065d8fSRichard Henderson 
trans_putd(DisasContext * dc,arg_putd * arg)159152065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
159252065d8fSRichard Henderson {
159352065d8fSRichard Henderson     return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1594fcf5ef2aSThomas Huth }
1595fcf5ef2aSThomas Huth 
mb_tr_init_disas_context(DisasContextBase * dcb,CPUState * cs)1596372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1597fcf5ef2aSThomas Huth {
1598372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1599372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1600372122e3SRichard Henderson     int bound;
1601fcf5ef2aSThomas Huth 
16024b893631SRichard Henderson     dc->cfg = &cpu->cfg;
1603683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1604d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
160520800179SRichard Henderson     dc->r0 = NULL;
160620800179SRichard Henderson     dc->r0_set = false;
16073b916140SRichard Henderson     dc->mem_index = cpu_mmu_index(cs, false);
1608b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1609b9c58aabSRichard Henderson     dc->jmp_dest = -1;
1610fcf5ef2aSThomas Huth 
1611372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1612372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1613fcf5ef2aSThomas Huth }
1614fcf5ef2aSThomas Huth 
mb_tr_tb_start(DisasContextBase * dcb,CPUState * cs)1615372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1616fcf5ef2aSThomas Huth {
1617fcf5ef2aSThomas Huth }
1618fcf5ef2aSThomas Huth 
mb_tr_insn_start(DisasContextBase * dcb,CPUState * cs)1619372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1620372122e3SRichard Henderson {
1621683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1622683a247eSRichard Henderson 
1623683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1624372122e3SRichard Henderson }
1625fcf5ef2aSThomas Huth 
mb_tr_translate_insn(DisasContextBase * dcb,CPUState * cs)1626372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1627372122e3SRichard Henderson {
1628372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
162944d1432bSRichard Henderson     uint32_t ir;
1630372122e3SRichard Henderson 
1631372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1632372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1633372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1634372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1635fcf5ef2aSThomas Huth     }
1636fcf5ef2aSThomas Huth 
16376f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
16386f9642d7SRichard Henderson 
1639*1561fee6SRichard Henderson     ir = translator_ldl(cpu_env(cs), &dc->base, dc->base.pc_next);
164044d1432bSRichard Henderson     if (!decode(dc, ir)) {
1641921afa9dSRichard Henderson         trap_illegal(dc, true);
164244d1432bSRichard Henderson     }
164320800179SRichard Henderson 
164420800179SRichard Henderson     if (dc->r0) {
164520800179SRichard Henderson         dc->r0 = NULL;
164620800179SRichard Henderson         dc->r0_set = false;
164720800179SRichard Henderson     }
164820800179SRichard Henderson 
16496f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
16506f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1651d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1652372122e3SRichard Henderson     }
16536f9642d7SRichard Henderson 
16541e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
16556f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1656d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1657fcf5ef2aSThomas Huth 
1658b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
16593d35bcc2SRichard Henderson         /*
16603d35bcc2SRichard Henderson          * Finish any return-from branch.
16613d35bcc2SRichard Henderson          */
16623c745866SRichard Henderson         uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16633c745866SRichard Henderson         if (unlikely(rt_ibe != 0)) {
16643c745866SRichard Henderson             dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16653c745866SRichard Henderson             if (rt_ibe & DRTI_FLAG) {
1666fcf5ef2aSThomas Huth                 do_rti(dc);
16673c745866SRichard Henderson             } else if (rt_ibe & DRTB_FLAG) {
1668fcf5ef2aSThomas Huth                 do_rtb(dc);
16693c745866SRichard Henderson             } else {
1670fcf5ef2aSThomas Huth                 do_rte(dc);
1671372122e3SRichard Henderson             }
16723c745866SRichard Henderson         }
16733d35bcc2SRichard Henderson 
16743d35bcc2SRichard Henderson         /* Complete the branch, ending the TB. */
16753d35bcc2SRichard Henderson         switch (dc->base.is_jmp) {
16763d35bcc2SRichard Henderson         case DISAS_NORETURN:
16773d35bcc2SRichard Henderson             /*
16783d35bcc2SRichard Henderson              * E.g. illegal insn in a delay slot.  We've already exited
16793d35bcc2SRichard Henderson              * and will handle D_FLAG in mb_cpu_do_interrupt.
16803d35bcc2SRichard Henderson              */
16813d35bcc2SRichard Henderson             break;
16823d35bcc2SRichard Henderson         case DISAS_NEXT:
16833c745866SRichard Henderson             /*
16843c745866SRichard Henderson              * Normal insn a delay slot.
16853c745866SRichard Henderson              * However, the return-from-exception type insns should
16863c745866SRichard Henderson              * return to the main loop, as they have adjusted MSR.
16873c745866SRichard Henderson              */
16883c745866SRichard Henderson             dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
16893d35bcc2SRichard Henderson             break;
16903d35bcc2SRichard Henderson         case DISAS_EXIT_NEXT:
16913d35bcc2SRichard Henderson             /*
16923d35bcc2SRichard Henderson              * E.g. mts insn in a delay slot.  Continue with btarget,
16933d35bcc2SRichard Henderson              * but still return to the main loop.
16943d35bcc2SRichard Henderson              */
16953d35bcc2SRichard Henderson             dc->base.is_jmp = DISAS_EXIT_JUMP;
16963d35bcc2SRichard Henderson             break;
16973d35bcc2SRichard Henderson         default:
16983d35bcc2SRichard Henderson             g_assert_not_reached();
16993d35bcc2SRichard Henderson         }
1700372122e3SRichard Henderson     }
1701372122e3SRichard Henderson }
1702372122e3SRichard Henderson 
mb_tr_tb_stop(DisasContextBase * dcb,CPUState * cs)1703372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1704372122e3SRichard Henderson {
1705372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1706372122e3SRichard Henderson 
1707372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1708372122e3SRichard Henderson         /* We have already exited the TB. */
1709372122e3SRichard Henderson         return;
1710372122e3SRichard Henderson     }
1711372122e3SRichard Henderson 
1712372122e3SRichard Henderson     t_sync_flags(dc);
1713372122e3SRichard Henderson 
1714372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1715372122e3SRichard Henderson     case DISAS_TOO_MANY:
1716372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1717372122e3SRichard Henderson         return;
1718372122e3SRichard Henderson 
171917e77796SRichard Henderson     case DISAS_EXIT:
1720f6278ca9SRichard Henderson         break;
1721f6278ca9SRichard Henderson     case DISAS_EXIT_NEXT:
1722f6278ca9SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1723f6278ca9SRichard Henderson         break;
1724f6278ca9SRichard Henderson     case DISAS_EXIT_JUMP:
1725f6278ca9SRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1726f6278ca9SRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1727f6278ca9SRichard Henderson         break;
1728372122e3SRichard Henderson 
1729372122e3SRichard Henderson     case DISAS_JUMP:
1730fbafb3a4SRichard Henderson         if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
1731b9c58aabSRichard Henderson             /* Direct jump. */
1732b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1733b9c58aabSRichard Henderson 
1734b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1735b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1736b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1737b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1738b9c58aabSRichard Henderson 
1739b9c58aabSRichard Henderson                 /*
1740b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1741b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1742b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1743b9c58aabSRichard Henderson                  */
1744b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1745b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1746b9c58aabSRichard Henderson 
1747b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1748b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1749b9c58aabSRichard Henderson                 gen_set_label(taken);
1750b9c58aabSRichard Henderson             }
1751b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1752b9c58aabSRichard Henderson             return;
1753b9c58aabSRichard Henderson         }
1754b9c58aabSRichard Henderson 
1755fbafb3a4SRichard Henderson         /* Indirect jump (or direct jump w/ goto_tb disabled) */
1756b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1757b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
17584059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
1759372122e3SRichard Henderson         return;
1760372122e3SRichard Henderson 
1761a2b80dbdSRichard Henderson     default:
1762a2b80dbdSRichard Henderson         g_assert_not_reached();
1763fcf5ef2aSThomas Huth     }
1764f6278ca9SRichard Henderson 
1765f6278ca9SRichard Henderson     /* Finish DISAS_EXIT_* */
1766f6278ca9SRichard Henderson     if (unlikely(cs->singlestep_enabled)) {
1767f6278ca9SRichard Henderson         gen_raise_exception(dc, EXCP_DEBUG);
1768f6278ca9SRichard Henderson     } else {
1769f6278ca9SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1770f6278ca9SRichard Henderson     }
1771fcf5ef2aSThomas Huth }
1772fcf5ef2aSThomas Huth 
1773372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1774372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1775372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1776372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1777372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1778372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1779372122e3SRichard Henderson };
1780372122e3SRichard Henderson 
gen_intermediate_code(CPUState * cpu,TranslationBlock * tb,int * max_insns,vaddr pc,void * host_pc)1781597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
178232f0c394SAnton Johansson                            vaddr pc, void *host_pc)
1783372122e3SRichard Henderson {
1784372122e3SRichard Henderson     DisasContext dc;
1785306c8721SRichard Henderson     translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base);
1786fcf5ef2aSThomas Huth }
1787fcf5ef2aSThomas Huth 
mb_cpu_dump_state(CPUState * cs,FILE * f,int flags)178890c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1789fcf5ef2aSThomas Huth {
1790da953643SPhilippe Mathieu-Daudé     CPUMBState *env = cpu_env(cs);
17910c3da918SRichard Henderson     uint32_t iflags;
1792fcf5ef2aSThomas Huth     int i;
1793fcf5ef2aSThomas Huth 
17940c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
17950c3da918SRichard Henderson                  env->pc, env->msr,
17962e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
17972e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
17982e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
17992e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18000c3da918SRichard Henderson 
18010c3da918SRichard Henderson     iflags = env->iflags;
18020c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18030c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18040c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18052ead1b18SJoe Komlodi     }
18060c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18070c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18080c3da918SRichard Henderson     }
18090c3da918SRichard Henderson     if (iflags & D_FLAG) {
1810b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18110c3da918SRichard Henderson     }
18120c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18130c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18140c3da918SRichard Henderson     }
18150c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18160c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18170c3da918SRichard Henderson     }
18180c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18190c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18200c3da918SRichard Henderson     }
18210c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18220c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18232ead1b18SJoe Komlodi     }
1824fcf5ef2aSThomas Huth 
18250c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
182619f27b6cSRichard Henderson                  "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
18270c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18280c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18290c3da918SRichard Henderson 
18300c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18310c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18320c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18330c3da918SRichard Henderson     }
18340c3da918SRichard Henderson     qemu_fprintf(f, "\n");
1835fcf5ef2aSThomas Huth }
1836fcf5ef2aSThomas Huth 
mb_tcg_init(void)1837fcf5ef2aSThomas Huth void mb_tcg_init(void)
1838fcf5ef2aSThomas Huth {
1839480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1840480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1841fcf5ef2aSThomas Huth 
1842480d29a8SRichard Henderson     static const struct {
1843480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1844480d29a8SRichard Henderson     } i32s[] = {
1845e47c2231SRichard Henderson         /*
1846e47c2231SRichard Henderson          * Note that r0 is handled specially in reg_for_read
1847e47c2231SRichard Henderson          * and reg_for_write.  Nothing should touch cpu_R[0].
1848e47c2231SRichard Henderson          * Leave that element NULL, which will assert quickly
1849e47c2231SRichard Henderson          * inside the tcg generator functions.
1850e47c2231SRichard Henderson          */
1851e47c2231SRichard Henderson                R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1852480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1853480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1854480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1855480d29a8SRichard Henderson 
1856480d29a8SRichard Henderson         SP(pc),
1857480d29a8SRichard Henderson         SP(msr),
18581074c0fbSRichard Henderson         SP(msr_c),
1859480d29a8SRichard Henderson         SP(imm),
1860480d29a8SRichard Henderson         SP(iflags),
1861b9c58aabSRichard Henderson         SP(bvalue),
1862480d29a8SRichard Henderson         SP(btarget),
1863480d29a8SRichard Henderson         SP(res_val),
1864480d29a8SRichard Henderson     };
1865480d29a8SRichard Henderson 
1866480d29a8SRichard Henderson #undef R
1867480d29a8SRichard Henderson #undef SP
1868480d29a8SRichard Henderson 
1869480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1870480d29a8SRichard Henderson         *i32s[i].var =
1871ad75a51eSRichard Henderson           tcg_global_mem_new_i32(tcg_env, i32s[i].ofs, i32s[i].name);
1872fcf5ef2aSThomas Huth     }
187376e8187dSRichard Henderson 
1874480d29a8SRichard Henderson     cpu_res_addr =
1875ad75a51eSRichard Henderson         tcg_global_mem_new(tcg_env, offsetof(CPUMBState, res_addr), "res_addr");
1876fcf5ef2aSThomas Huth }
1877