xref: /openbmc/qemu/target/microblaze/translate.c (revision 17e777965257e19b17dfbf7c08c495f05303a860)
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
10fcf5ef2aSThomas Huth  * version 2 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 "disas/disas.h"
24fcf5ef2aSThomas Huth #include "exec/exec-all.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
26fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
27fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h"
28fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
2977fc6f5eSLluís Vilanova #include "exec/translator.h"
3090c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
31fcf5ef2aSThomas Huth 
32fcf5ef2aSThomas Huth #include "trace-tcg.h"
33fcf5ef2aSThomas Huth #include "exec/log.h"
34fcf5ef2aSThomas Huth 
35fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
36fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
37fcf5ef2aSThomas Huth 
3877fc6f5eSLluís Vilanova /* is_jmp field values */
3977fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
40*17e77796SRichard Henderson #define DISAS_EXIT    DISAS_TARGET_1 /* all cpu state modified dynamically */
4177fc6f5eSLluís Vilanova 
42cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
430f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
443e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
451074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
469b158558SRichard Henderson static TCGv_i32 cpu_imm;
47b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
480f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
499b158558SRichard Henderson static TCGv_i32 cpu_iflags;
509b158558SRichard Henderson static TCGv cpu_res_addr;
519b158558SRichard Henderson static TCGv_i32 cpu_res_val;
52fcf5ef2aSThomas Huth 
53fcf5ef2aSThomas Huth #include "exec/gen-icount.h"
54fcf5ef2aSThomas Huth 
55fcf5ef2aSThomas Huth /* This is the state at translation time.  */
56fcf5ef2aSThomas Huth typedef struct DisasContext {
57d4705ae0SRichard Henderson     DisasContextBase base;
58fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu;
59fcf5ef2aSThomas Huth 
60683a247eSRichard Henderson     /* TCG op of the current insn_start.  */
61683a247eSRichard Henderson     TCGOp *insn_start;
62683a247eSRichard Henderson 
6320800179SRichard Henderson     TCGv_i32 r0;
6420800179SRichard Henderson     bool r0_set;
6520800179SRichard Henderson 
66fcf5ef2aSThomas Huth     /* Decoder.  */
67d7ecb757SRichard Henderson     uint32_t ext_imm;
68fcf5ef2aSThomas Huth     unsigned int cpustate_changed;
69683a247eSRichard Henderson     unsigned int tb_flags;
706f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
71287b1defSRichard Henderson     int mem_index;
72fcf5ef2aSThomas Huth 
73b9c58aabSRichard Henderson     /* Condition under which to jump, including NEVER and ALWAYS. */
74b9c58aabSRichard Henderson     TCGCond jmp_cond;
75b9c58aabSRichard Henderson 
76b9c58aabSRichard Henderson     /* Immediate branch-taken destination, or -1 for indirect. */
77b9c58aabSRichard Henderson     uint32_t jmp_dest;
78fcf5ef2aSThomas Huth } DisasContext;
79fcf5ef2aSThomas Huth 
8020800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8120800179SRichard Henderson {
8220800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
8320800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
8420800179SRichard Henderson     }
8520800179SRichard Henderson     return x;
8620800179SRichard Henderson }
8720800179SRichard Henderson 
8844d1432bSRichard Henderson /* Include the auto-generated decoder.  */
8944d1432bSRichard Henderson #include "decode-insns.c.inc"
9044d1432bSRichard Henderson 
91683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
92fcf5ef2aSThomas Huth {
93fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
9488e74b61SRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
9588e74b61SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
96fcf5ef2aSThomas Huth     }
97fcf5ef2aSThomas Huth }
98fcf5ef2aSThomas Huth 
9941ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
100fcf5ef2aSThomas Huth {
101fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
102fcf5ef2aSThomas Huth 
103fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
104fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
105d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
106fcf5ef2aSThomas Huth }
107fcf5ef2aSThomas Huth 
10841ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
10941ba37c4SRichard Henderson {
11041ba37c4SRichard Henderson     t_sync_flags(dc);
111d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
11241ba37c4SRichard Henderson     gen_raise_exception(dc, index);
11341ba37c4SRichard Henderson }
11441ba37c4SRichard Henderson 
11541ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
11641ba37c4SRichard Henderson {
11741ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
11841ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
11941ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
12041ba37c4SRichard Henderson 
12141ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
12241ba37c4SRichard Henderson }
12341ba37c4SRichard Henderson 
124fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
125fcf5ef2aSThomas Huth {
126fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
127d4705ae0SRichard Henderson     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
128fcf5ef2aSThomas Huth #else
129fcf5ef2aSThomas Huth     return true;
130fcf5ef2aSThomas Huth #endif
131fcf5ef2aSThomas Huth }
132fcf5ef2aSThomas Huth 
133fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
134fcf5ef2aSThomas Huth {
135d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1360b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1370b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1380b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1390b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
1400b46fa08SRichard Henderson     } else if (use_goto_tb(dc, dest)) {
141fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1420f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
143d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
144fcf5ef2aSThomas Huth     } else {
1450f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
14607ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
147fcf5ef2aSThomas Huth     }
148d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
149fcf5ef2aSThomas Huth }
150fcf5ef2aSThomas Huth 
151bdfc1e88SEdgar E. Iglesias /*
1529ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1539ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1549ba8cd45SEdgar E. Iglesias  */
1559ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1569ba8cd45SEdgar E. Iglesias {
1572c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1585143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
15941ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1609ba8cd45SEdgar E. Iglesias     }
1619ba8cd45SEdgar E. Iglesias     return cond;
1629ba8cd45SEdgar E. Iglesias }
1639ba8cd45SEdgar E. Iglesias 
1649ba8cd45SEdgar E. Iglesias /*
165bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
166bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
167bdfc1e88SEdgar E. Iglesias  */
168bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
169bdfc1e88SEdgar E. Iglesias {
170287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
171bdfc1e88SEdgar E. Iglesias 
1722c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
17341ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
174bdfc1e88SEdgar E. Iglesias     }
175bdfc1e88SEdgar E. Iglesias     return cond_user;
176bdfc1e88SEdgar E. Iglesias }
177bdfc1e88SEdgar E. Iglesias 
17820800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
179fcf5ef2aSThomas Huth {
18020800179SRichard Henderson     if (likely(reg != 0)) {
18120800179SRichard Henderson         return cpu_R[reg];
182fcf5ef2aSThomas Huth     }
18320800179SRichard Henderson     if (!dc->r0_set) {
18420800179SRichard Henderson         if (dc->r0 == NULL) {
18520800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
186fcf5ef2aSThomas Huth         }
18720800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
18820800179SRichard Henderson         dc->r0_set = true;
18920800179SRichard Henderson     }
19020800179SRichard Henderson     return dc->r0;
191fcf5ef2aSThomas Huth }
192fcf5ef2aSThomas Huth 
19320800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
19420800179SRichard Henderson {
19520800179SRichard Henderson     if (likely(reg != 0)) {
19620800179SRichard Henderson         return cpu_R[reg];
19720800179SRichard Henderson     }
19820800179SRichard Henderson     if (dc->r0 == NULL) {
19920800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
20020800179SRichard Henderson     }
20120800179SRichard Henderson     return dc->r0;
202fcf5ef2aSThomas Huth }
203fcf5ef2aSThomas Huth 
20420800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
20520800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
20620800179SRichard Henderson {
20720800179SRichard Henderson     TCGv_i32 rd, ra, rb;
20820800179SRichard Henderson 
20920800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
21020800179SRichard Henderson         return true;
211fcf5ef2aSThomas Huth     }
21220800179SRichard Henderson 
21320800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
21420800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
21520800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
21620800179SRichard Henderson     fn(rd, ra, rb);
21720800179SRichard Henderson     return true;
21820800179SRichard Henderson }
21920800179SRichard Henderson 
22039cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
22139cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
22239cf3864SRichard Henderson {
22339cf3864SRichard Henderson     TCGv_i32 rd, ra;
22439cf3864SRichard Henderson 
22539cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
22639cf3864SRichard Henderson         return true;
22739cf3864SRichard Henderson     }
22839cf3864SRichard Henderson 
22939cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
23039cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
23139cf3864SRichard Henderson     fn(rd, ra);
23239cf3864SRichard Henderson     return true;
23339cf3864SRichard Henderson }
23439cf3864SRichard Henderson 
23520800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
23620800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
23720800179SRichard Henderson {
23820800179SRichard Henderson     TCGv_i32 rd, ra;
23920800179SRichard Henderson 
24020800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24120800179SRichard Henderson         return true;
24220800179SRichard Henderson     }
24320800179SRichard Henderson 
24420800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
24520800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
24620800179SRichard Henderson     fni(rd, ra, arg->imm);
24720800179SRichard Henderson     return true;
24820800179SRichard Henderson }
24920800179SRichard Henderson 
25020800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
25120800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
25220800179SRichard Henderson {
25320800179SRichard Henderson     TCGv_i32 rd, ra, imm;
25420800179SRichard Henderson 
25520800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
25620800179SRichard Henderson         return true;
25720800179SRichard Henderson     }
25820800179SRichard Henderson 
25920800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26020800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
26120800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
26220800179SRichard Henderson 
26320800179SRichard Henderson     fn(rd, ra, imm);
26420800179SRichard Henderson 
26520800179SRichard Henderson     tcg_temp_free_i32(imm);
26620800179SRichard Henderson     return true;
26720800179SRichard Henderson }
26820800179SRichard Henderson 
26920800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
27020800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
27120800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
27220800179SRichard Henderson 
273607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
274607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
275607f5767SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); }
276607f5767SRichard Henderson 
27739cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
27839cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
27939cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
28039cf3864SRichard Henderson 
28139cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
28239cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
28339cf3864SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); }
28439cf3864SRichard Henderson 
28520800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
28620800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
28720800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
28820800179SRichard Henderson 
28997955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
29097955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29197955cebSRichard Henderson     { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); }
29297955cebSRichard Henderson 
29320800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
29420800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29520800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
29620800179SRichard Henderson 
297d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
298d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
299d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
300d5aead3dSRichard Henderson 
301d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
302d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
303d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
304d5aead3dSRichard Henderson 
30520800179SRichard Henderson /* No input carry, but output carry. */
30620800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
30720800179SRichard Henderson {
30820800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
30920800179SRichard Henderson 
31020800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
31120800179SRichard Henderson 
31220800179SRichard Henderson     tcg_temp_free_i32(zero);
31320800179SRichard Henderson }
31420800179SRichard Henderson 
31520800179SRichard Henderson /* Input and output carry. */
31620800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
31720800179SRichard Henderson {
31820800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
31920800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
32020800179SRichard Henderson 
32120800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
32220800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
32320800179SRichard Henderson 
32420800179SRichard Henderson     tcg_temp_free_i32(tmp);
32520800179SRichard Henderson     tcg_temp_free_i32(zero);
32620800179SRichard Henderson }
32720800179SRichard Henderson 
32820800179SRichard Henderson /* Input carry, but no output carry. */
32920800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
33020800179SRichard Henderson {
33120800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
33220800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
33320800179SRichard Henderson }
33420800179SRichard Henderson 
33520800179SRichard Henderson DO_TYPEA(add, true, gen_add)
33620800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
33720800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
33820800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
33920800179SRichard Henderson 
34020800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
34120800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
34220800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
34320800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
34420800179SRichard Henderson 
345cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
346cb0a0a4cSRichard Henderson {
347cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
348cb0a0a4cSRichard Henderson }
349cb0a0a4cSRichard Henderson 
350cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
351cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
352cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
353cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
354cb0a0a4cSRichard Henderson 
355081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
356081d8e02SRichard Henderson {
357081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
358081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
359081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
360081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
361081d8e02SRichard Henderson }
362081d8e02SRichard Henderson 
363081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
364081d8e02SRichard Henderson {
365081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
366081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
367081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
368081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
369081d8e02SRichard Henderson }
370081d8e02SRichard Henderson 
371081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
372081d8e02SRichard Henderson {
373081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
374081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
375081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
376081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
377081d8e02SRichard Henderson }
378081d8e02SRichard Henderson 
379081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
380081d8e02SRichard Henderson {
381081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
382081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
383081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
384081d8e02SRichard Henderson 
385081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
386081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
387081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
388081d8e02SRichard Henderson                       imm_w, imm_s);
389081d8e02SRichard Henderson     } else {
390081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
391081d8e02SRichard Henderson     }
392081d8e02SRichard Henderson }
393081d8e02SRichard Henderson 
394081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
395081d8e02SRichard Henderson {
396081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
397081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
398081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
399081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
400081d8e02SRichard Henderson 
401081d8e02SRichard Henderson     if (imm_w < imm_s) {
402081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
403081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
404081d8e02SRichard Henderson                       imm_w, imm_s);
405081d8e02SRichard Henderson     } else {
406081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
407081d8e02SRichard Henderson     }
408081d8e02SRichard Henderson }
409081d8e02SRichard Henderson 
410081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
411081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
412081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
413081d8e02SRichard Henderson 
414081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
415081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
416081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
417081d8e02SRichard Henderson 
418081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
419081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
420081d8e02SRichard Henderson 
42139cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
42239cf3864SRichard Henderson {
42339cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
42439cf3864SRichard Henderson }
42539cf3864SRichard Henderson 
42639cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
42739cf3864SRichard Henderson 
42858b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
42958b48b63SRichard Henderson {
43058b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
43158b48b63SRichard Henderson 
43258b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
43358b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
43458b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
43558b48b63SRichard Henderson     tcg_temp_free_i32(lt);
43658b48b63SRichard Henderson }
43758b48b63SRichard Henderson 
43858b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
43958b48b63SRichard Henderson {
44058b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
44158b48b63SRichard Henderson 
44258b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
44358b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
44458b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
44558b48b63SRichard Henderson     tcg_temp_free_i32(lt);
44658b48b63SRichard Henderson }
44758b48b63SRichard Henderson 
44858b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
44958b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
450a2b0b90eSRichard Henderson 
451d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
452d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
453d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
454d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
455d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
456d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
457d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
458d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
459d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
460d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
461d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
462d5aead3dSRichard Henderson 
463d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
464d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
465d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
466d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
467d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
468d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
469d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
470d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
471d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
472d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
473d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
474d5aead3dSRichard Henderson 
475d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
476d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
477d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
478d5aead3dSRichard Henderson 
479d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
480d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
481d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
482d5aead3dSRichard Henderson 
483d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
484b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
485b1354342SRichard Henderson {
486b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
487b1354342SRichard Henderson }
488b1354342SRichard Henderson 
489b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
490b1354342SRichard Henderson {
491b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
492b1354342SRichard Henderson }
493b1354342SRichard Henderson 
494b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
495b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
496b1354342SRichard Henderson 
497e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
498e64b2e5cSRichard Henderson {
499e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
500e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
5016f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
502e64b2e5cSRichard Henderson     return true;
503e64b2e5cSRichard Henderson }
504e64b2e5cSRichard Henderson 
50597955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
50697955cebSRichard Henderson {
50797955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
50897955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
50997955cebSRichard Henderson     tcg_temp_free_i32(tmp);
51097955cebSRichard Henderson }
51197955cebSRichard Henderson 
51297955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
51397955cebSRichard Henderson {
51497955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
51597955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
51697955cebSRichard Henderson     tcg_temp_free_i32(tmp);
51797955cebSRichard Henderson }
51897955cebSRichard Henderson 
51997955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
52097955cebSRichard Henderson {
52197955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
52297955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
52397955cebSRichard Henderson     tcg_temp_free_i32(tmp);
52497955cebSRichard Henderson }
52597955cebSRichard Henderson 
52697955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
52797955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
52897955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
52997955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
53097955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
53197955cebSRichard Henderson 
532cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
533cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
534cb0a0a4cSRichard Henderson 
535607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
536607f5767SRichard Henderson {
537607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
538607f5767SRichard Henderson }
539607f5767SRichard Henderson 
540607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
541607f5767SRichard Henderson {
542607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
543607f5767SRichard Henderson }
544607f5767SRichard Henderson 
545607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
546607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
547607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
548607f5767SRichard Henderson 
549a2b0b90eSRichard Henderson /* No input carry, but output carry. */
550a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
551a2b0b90eSRichard Henderson {
552a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
553a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
554a2b0b90eSRichard Henderson }
555a2b0b90eSRichard Henderson 
556a2b0b90eSRichard Henderson /* Input and output carry. */
557a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
558a2b0b90eSRichard Henderson {
559a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
560a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
561a2b0b90eSRichard Henderson 
562a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
563a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
564a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
565a2b0b90eSRichard Henderson 
566a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
567a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
568a2b0b90eSRichard Henderson }
569a2b0b90eSRichard Henderson 
570a2b0b90eSRichard Henderson /* No input or output carry. */
571a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
572a2b0b90eSRichard Henderson {
573a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
574a2b0b90eSRichard Henderson }
575a2b0b90eSRichard Henderson 
576a2b0b90eSRichard Henderson /* Input carry, no output carry. */
577a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
578a2b0b90eSRichard Henderson {
579a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
580a2b0b90eSRichard Henderson 
581a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
582a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
583a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
584a2b0b90eSRichard Henderson 
585a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
586a2b0b90eSRichard Henderson }
587a2b0b90eSRichard Henderson 
588a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
589a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
590a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
591a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
592a2b0b90eSRichard Henderson 
593a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
594a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
595a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
596a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
597a2b0b90eSRichard Henderson 
59839cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
59939cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
60039cf3864SRichard Henderson 
60139cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
60239cf3864SRichard Henderson {
60339cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
60439cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
60539cf3864SRichard Henderson }
60639cf3864SRichard Henderson 
60739cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
60839cf3864SRichard Henderson {
60939cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
61039cf3864SRichard Henderson 
61139cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
61239cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
61339cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
61439cf3864SRichard Henderson 
61539cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
61639cf3864SRichard Henderson }
61739cf3864SRichard Henderson 
61839cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
61939cf3864SRichard Henderson {
62039cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
62139cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
62239cf3864SRichard Henderson }
62339cf3864SRichard Henderson 
62439cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
62539cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
62639cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
62739cf3864SRichard Henderson 
62839cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
62939cf3864SRichard Henderson {
63039cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
63139cf3864SRichard Henderson }
63239cf3864SRichard Henderson 
63339cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
63439cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
63539cf3864SRichard Henderson 
63639cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
63739cf3864SRichard Henderson {
63839cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
63939cf3864SRichard Henderson     trap_userspace(dc, true);
64039cf3864SRichard Henderson     return true;
64139cf3864SRichard Henderson }
64239cf3864SRichard Henderson 
643cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
644cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
645cb0a0a4cSRichard Henderson 
646d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
647d8e59c4aSRichard Henderson {
648d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
649d8e59c4aSRichard Henderson 
650d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
651d8e59c4aSRichard Henderson     if (ra && rb) {
652d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
653d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
654d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
655d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
656d8e59c4aSRichard Henderson     } else if (ra) {
657d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
658d8e59c4aSRichard Henderson     } else if (rb) {
659d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
660d8e59c4aSRichard Henderson     } else {
661d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
662d8e59c4aSRichard Henderson     }
663d8e59c4aSRichard Henderson 
664d8e59c4aSRichard Henderson     if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) {
665d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
666d8e59c4aSRichard Henderson     }
667d8e59c4aSRichard Henderson     return ret;
668d8e59c4aSRichard Henderson }
669d8e59c4aSRichard Henderson 
670d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
671d8e59c4aSRichard Henderson {
672d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
673d8e59c4aSRichard Henderson 
674d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
675d8e59c4aSRichard Henderson     if (ra) {
676d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
677d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
678d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
679d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
680d8e59c4aSRichard Henderson     } else {
681d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
682d8e59c4aSRichard Henderson     }
683d8e59c4aSRichard Henderson 
684d8e59c4aSRichard Henderson     if (ra == 1 && dc->cpu->cfg.stackprot) {
685d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
686d8e59c4aSRichard Henderson     }
687d8e59c4aSRichard Henderson     return ret;
688d8e59c4aSRichard Henderson }
689d8e59c4aSRichard Henderson 
69019f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
691d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
692d8e59c4aSRichard Henderson {
693d8e59c4aSRichard Henderson     int addr_size = dc->cpu->cfg.addr_size;
694d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
695d8e59c4aSRichard Henderson 
696d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
697d8e59c4aSRichard Henderson         if (rb) {
698d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
699d8e59c4aSRichard Henderson         } else {
700d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
701d8e59c4aSRichard Henderson         }
702d8e59c4aSRichard Henderson     } else {
703d8e59c4aSRichard Henderson         if (rb) {
704d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
705d8e59c4aSRichard Henderson         } else {
706d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
707d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
708d8e59c4aSRichard Henderson         }
709d8e59c4aSRichard Henderson         if (addr_size < 64) {
710d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
711d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
712d8e59c4aSRichard Henderson         }
713d8e59c4aSRichard Henderson     }
714d8e59c4aSRichard Henderson     return ret;
715d8e59c4aSRichard Henderson }
71619f27b6cSRichard Henderson #endif
717d8e59c4aSRichard Henderson 
718ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
719ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
720ab0c8d0fSRichard Henderson {
721ab0c8d0fSRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
722ab0c8d0fSRichard Henderson 
723ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
724ab0c8d0fSRichard Henderson     iflags |= rd << 5;
725ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
726ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
727ab0c8d0fSRichard Henderson 
728ab0c8d0fSRichard Henderson     tcg_set_insn_start_param(dc->insn_start, 1, iflags);
729ab0c8d0fSRichard Henderson }
730ab0c8d0fSRichard Henderson 
731d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
732d8e59c4aSRichard Henderson                     int mem_index, bool rev)
733d8e59c4aSRichard Henderson {
734d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
735d8e59c4aSRichard Henderson 
736d8e59c4aSRichard Henderson     /*
737d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
738d8e59c4aSRichard Henderson      *
739d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
740d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
741d8e59c4aSRichard Henderson      */
742d8e59c4aSRichard Henderson     if (rev) {
743d8e59c4aSRichard Henderson         if (size > MO_8) {
744d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
745d8e59c4aSRichard Henderson         }
746d8e59c4aSRichard Henderson         if (size < MO_32) {
747d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
748d8e59c4aSRichard Henderson         }
749d8e59c4aSRichard Henderson     }
750d8e59c4aSRichard Henderson 
751ab0c8d0fSRichard Henderson     if (size > MO_8 &&
752ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
753ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
754ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
755ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
756d8e59c4aSRichard Henderson     }
757d8e59c4aSRichard Henderson 
758ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
759d8e59c4aSRichard Henderson 
760d8e59c4aSRichard Henderson     tcg_temp_free(addr);
761d8e59c4aSRichard Henderson     return true;
762d8e59c4aSRichard Henderson }
763d8e59c4aSRichard Henderson 
764d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
765d8e59c4aSRichard Henderson {
766d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
767d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
768d8e59c4aSRichard Henderson }
769d8e59c4aSRichard Henderson 
770d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
771d8e59c4aSRichard Henderson {
772d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
773d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
774d8e59c4aSRichard Henderson }
775d8e59c4aSRichard Henderson 
776d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
777d8e59c4aSRichard Henderson {
778d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
779d8e59c4aSRichard Henderson         return true;
780d8e59c4aSRichard Henderson     }
78119f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
78219f27b6cSRichard Henderson     return true;
78319f27b6cSRichard Henderson #else
784d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
785d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
78619f27b6cSRichard Henderson #endif
787d8e59c4aSRichard Henderson }
788d8e59c4aSRichard Henderson 
789d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
790d8e59c4aSRichard Henderson {
791d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
792d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
793d8e59c4aSRichard Henderson }
794d8e59c4aSRichard Henderson 
795d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
796d8e59c4aSRichard Henderson {
797d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
798d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
799d8e59c4aSRichard Henderson }
800d8e59c4aSRichard Henderson 
801d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
802d8e59c4aSRichard Henderson {
803d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
804d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
805d8e59c4aSRichard Henderson }
806d8e59c4aSRichard Henderson 
807d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
808d8e59c4aSRichard Henderson {
809d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
810d8e59c4aSRichard Henderson         return true;
811d8e59c4aSRichard Henderson     }
81219f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
81319f27b6cSRichard Henderson     return true;
81419f27b6cSRichard Henderson #else
815d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
816d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
81719f27b6cSRichard Henderson #endif
818d8e59c4aSRichard Henderson }
819d8e59c4aSRichard Henderson 
820d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
821d8e59c4aSRichard Henderson {
822d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
823d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
824d8e59c4aSRichard Henderson }
825d8e59c4aSRichard Henderson 
826d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
827d8e59c4aSRichard Henderson {
828d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
829d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
830d8e59c4aSRichard Henderson }
831d8e59c4aSRichard Henderson 
832d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
833d8e59c4aSRichard Henderson {
834d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
835d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
836d8e59c4aSRichard Henderson }
837d8e59c4aSRichard Henderson 
838d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
839d8e59c4aSRichard Henderson {
840d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
841d8e59c4aSRichard Henderson         return true;
842d8e59c4aSRichard Henderson     }
84319f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
84419f27b6cSRichard Henderson     return true;
84519f27b6cSRichard Henderson #else
846d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
847d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
84819f27b6cSRichard Henderson #endif
849d8e59c4aSRichard Henderson }
850d8e59c4aSRichard Henderson 
851d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
852d8e59c4aSRichard Henderson {
853d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
854d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
855d8e59c4aSRichard Henderson }
856d8e59c4aSRichard Henderson 
857d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
858d8e59c4aSRichard Henderson {
859d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
860d8e59c4aSRichard Henderson 
861d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
862d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
863d8e59c4aSRichard Henderson 
864d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
865d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
866d8e59c4aSRichard Henderson     tcg_temp_free(addr);
867d8e59c4aSRichard Henderson 
868d8e59c4aSRichard Henderson     if (arg->rd) {
869d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
870d8e59c4aSRichard Henderson     }
871d8e59c4aSRichard Henderson 
872d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
873d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
874d8e59c4aSRichard Henderson     return true;
875d8e59c4aSRichard Henderson }
876d8e59c4aSRichard Henderson 
877d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
878d8e59c4aSRichard Henderson                      int mem_index, bool rev)
879d8e59c4aSRichard Henderson {
880d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
881d8e59c4aSRichard Henderson 
882d8e59c4aSRichard Henderson     /*
883d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
884d8e59c4aSRichard Henderson      *
885d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
886d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
887d8e59c4aSRichard Henderson      */
888d8e59c4aSRichard Henderson     if (rev) {
889d8e59c4aSRichard Henderson         if (size > MO_8) {
890d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
891d8e59c4aSRichard Henderson         }
892d8e59c4aSRichard Henderson         if (size < MO_32) {
893d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
894d8e59c4aSRichard Henderson         }
895d8e59c4aSRichard Henderson     }
896d8e59c4aSRichard Henderson 
897ab0c8d0fSRichard Henderson     if (size > MO_8 &&
898ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
899ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
900ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
901ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
902d8e59c4aSRichard Henderson     }
903d8e59c4aSRichard Henderson 
904ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
905ab0c8d0fSRichard Henderson 
906d8e59c4aSRichard Henderson     tcg_temp_free(addr);
907d8e59c4aSRichard Henderson     return true;
908d8e59c4aSRichard Henderson }
909d8e59c4aSRichard Henderson 
910d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
911d8e59c4aSRichard Henderson {
912d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
913d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
914d8e59c4aSRichard Henderson }
915d8e59c4aSRichard Henderson 
916d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
917d8e59c4aSRichard Henderson {
918d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
919d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
920d8e59c4aSRichard Henderson }
921d8e59c4aSRichard Henderson 
922d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
923d8e59c4aSRichard Henderson {
924d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
925d8e59c4aSRichard Henderson         return true;
926d8e59c4aSRichard Henderson     }
92719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
92819f27b6cSRichard Henderson     return true;
92919f27b6cSRichard Henderson #else
930d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
931d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
93219f27b6cSRichard Henderson #endif
933d8e59c4aSRichard Henderson }
934d8e59c4aSRichard Henderson 
935d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
936d8e59c4aSRichard Henderson {
937d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
938d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
939d8e59c4aSRichard Henderson }
940d8e59c4aSRichard Henderson 
941d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
942d8e59c4aSRichard Henderson {
943d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
944d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
945d8e59c4aSRichard Henderson }
946d8e59c4aSRichard Henderson 
947d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
948d8e59c4aSRichard Henderson {
949d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
950d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
951d8e59c4aSRichard Henderson }
952d8e59c4aSRichard Henderson 
953d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
954d8e59c4aSRichard Henderson {
955d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
956d8e59c4aSRichard Henderson         return true;
957d8e59c4aSRichard Henderson     }
95819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
95919f27b6cSRichard Henderson     return true;
96019f27b6cSRichard Henderson #else
961d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
962d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
96319f27b6cSRichard Henderson #endif
964d8e59c4aSRichard Henderson }
965d8e59c4aSRichard Henderson 
966d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
967d8e59c4aSRichard Henderson {
968d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
969d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
970d8e59c4aSRichard Henderson }
971d8e59c4aSRichard Henderson 
972d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
973d8e59c4aSRichard Henderson {
974d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
975d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
976d8e59c4aSRichard Henderson }
977d8e59c4aSRichard Henderson 
978d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
979d8e59c4aSRichard Henderson {
980d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
981d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
982d8e59c4aSRichard Henderson }
983d8e59c4aSRichard Henderson 
984d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
985d8e59c4aSRichard Henderson {
986d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
987d8e59c4aSRichard Henderson         return true;
988d8e59c4aSRichard Henderson     }
98919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
99019f27b6cSRichard Henderson     return true;
99119f27b6cSRichard Henderson #else
992d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
993d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
99419f27b6cSRichard Henderson #endif
995d8e59c4aSRichard Henderson }
996d8e59c4aSRichard Henderson 
997d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
998d8e59c4aSRichard Henderson {
999d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1000d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1001d8e59c4aSRichard Henderson }
1002d8e59c4aSRichard Henderson 
1003d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1004d8e59c4aSRichard Henderson {
1005d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1006d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1007d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1008d8e59c4aSRichard Henderson     TCGv_i32 tval;
1009d8e59c4aSRichard Henderson 
1010d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1011d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1012d8e59c4aSRichard Henderson 
1013d8e59c4aSRichard Henderson     /*
1014d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1015d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1016d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1017d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1018d8e59c4aSRichard Henderson      */
1019d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1020d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1021d8e59c4aSRichard Henderson 
1022d8e59c4aSRichard Henderson     /*
1023d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1024d8e59c4aSRichard Henderson      * the reserved location.
1025d8e59c4aSRichard Henderson      */
1026d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1027d8e59c4aSRichard Henderson 
1028d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1029d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1030d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1031d8e59c4aSRichard Henderson 
1032d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1033d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1034d8e59c4aSRichard Henderson 
1035d8e59c4aSRichard Henderson     /* Success */
1036d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1037d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1038d8e59c4aSRichard Henderson 
1039d8e59c4aSRichard Henderson     /* Failure */
1040d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1041d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1042d8e59c4aSRichard Henderson 
1043d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1044d8e59c4aSRichard Henderson 
1045d8e59c4aSRichard Henderson     /*
1046d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1047d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1048d8e59c4aSRichard Henderson      */
1049d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1050d8e59c4aSRichard Henderson     return true;
1051d8e59c4aSRichard Henderson }
1052d8e59c4aSRichard Henderson 
105316bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
105416bbbbc9SRichard Henderson {
105516bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
105616bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
105716bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
105816bbbbc9SRichard Henderson     }
105916bbbbc9SRichard Henderson }
106016bbbbc9SRichard Henderson 
106116bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
106216bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
106316bbbbc9SRichard Henderson {
106416bbbbc9SRichard Henderson     uint32_t add_pc;
106516bbbbc9SRichard Henderson 
106616bbbbc9SRichard Henderson     if (delay) {
106716bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
106816bbbbc9SRichard Henderson     }
106916bbbbc9SRichard Henderson 
107016bbbbc9SRichard Henderson     if (link) {
107116bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
107216bbbbc9SRichard Henderson     }
107316bbbbc9SRichard Henderson 
107416bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
107516bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
107616bbbbc9SRichard Henderson     if (dest_rb > 0) {
107716bbbbc9SRichard Henderson         dc->jmp_dest = -1;
107816bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
107916bbbbc9SRichard Henderson     } else {
108016bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
108116bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
108216bbbbc9SRichard Henderson     }
108316bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
108416bbbbc9SRichard Henderson     return true;
108516bbbbc9SRichard Henderson }
108616bbbbc9SRichard Henderson 
108716bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
108816bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
108916bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
109016bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
109116bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
109216bbbbc9SRichard Henderson 
109316bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
109416bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
109516bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
109616bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
109716bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
109816bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
109916bbbbc9SRichard Henderson 
1100fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1101fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1102fd779113SRichard Henderson {
1103fd779113SRichard Henderson     TCGv_i32 zero, next;
1104fd779113SRichard Henderson 
1105fd779113SRichard Henderson     if (delay) {
1106fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1107fd779113SRichard Henderson     }
1108fd779113SRichard Henderson 
1109fd779113SRichard Henderson     dc->jmp_cond = cond;
1110fd779113SRichard Henderson 
1111fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1112fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1113fd779113SRichard Henderson 
1114fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1115fd779113SRichard Henderson     if (dest_rb > 0) {
1116fd779113SRichard Henderson         dc->jmp_dest = -1;
1117fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1118fd779113SRichard Henderson     } else {
1119fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1120fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1121fd779113SRichard Henderson     }
1122fd779113SRichard Henderson 
1123fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1124fd779113SRichard Henderson     zero = tcg_const_i32(0);
1125fd779113SRichard Henderson     next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4);
1126fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1127fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1128fd779113SRichard Henderson                         cpu_btarget, next);
1129fd779113SRichard Henderson     tcg_temp_free_i32(zero);
1130fd779113SRichard Henderson     tcg_temp_free_i32(next);
1131fd779113SRichard Henderson 
1132fd779113SRichard Henderson     return true;
1133fd779113SRichard Henderson }
1134fd779113SRichard Henderson 
1135fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1136fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1137fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1138fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1139fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1140fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1141fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1142fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1143fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1144fd779113SRichard Henderson 
1145fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1146fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1147fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1148fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1149fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1150fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1151fd779113SRichard Henderson 
1152f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1153f5235314SRichard Henderson {
1154f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1155f5235314SRichard Henderson         return true;
1156f5235314SRichard Henderson     }
1157f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1158f5235314SRichard Henderson     if (arg->rd) {
1159f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1160f5235314SRichard Henderson     }
1161f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1162f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1163f5235314SRichard Henderson 
1164*17e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1165f5235314SRichard Henderson     return true;
1166f5235314SRichard Henderson }
1167f5235314SRichard Henderson 
1168f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1169f5235314SRichard Henderson {
1170f5235314SRichard Henderson     uint32_t imm = arg->imm;
1171f5235314SRichard Henderson 
1172f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1173f5235314SRichard Henderson         return true;
1174f5235314SRichard Henderson     }
1175f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1176f5235314SRichard Henderson     if (arg->rd) {
1177f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1178f5235314SRichard Henderson     }
1179f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1180f5235314SRichard Henderson 
1181f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1182f5235314SRichard Henderson     switch (imm) {
1183f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1184f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1185f5235314SRichard Henderson         break;
1186f5235314SRichard Henderson     case 0x18: /* debug trap */
1187f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1188f5235314SRichard Henderson         break;
1189f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1190f5235314SRichard Henderson         g_assert_not_reached();
1191f5235314SRichard Henderson     }
1192f5235314SRichard Henderson #else
1193f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1194f5235314SRichard Henderson 
1195f5235314SRichard Henderson     if (imm != 0x18) {
1196f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1197f5235314SRichard Henderson     }
1198f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1199f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1200f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1201f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1202f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1203f5235314SRichard Henderson     }
1204f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
1205*17e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1206f5235314SRichard Henderson #endif
1207f5235314SRichard Henderson 
1208f5235314SRichard Henderson     return true;
1209f5235314SRichard Henderson }
1210f5235314SRichard Henderson 
1211ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1212ee8c7f9fSRichard Henderson {
1213ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1214ee8c7f9fSRichard Henderson 
1215ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1216ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1217ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1218ee8c7f9fSRichard Henderson     }
1219ee8c7f9fSRichard Henderson 
1220ee8c7f9fSRichard Henderson     /* Sleep. */
1221ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1222ee8c7f9fSRichard Henderson         TCGv_i32 tmp_1;
1223ee8c7f9fSRichard Henderson 
1224ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1225ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1226ee8c7f9fSRichard Henderson             return true;
1227ee8c7f9fSRichard Henderson         }
1228ee8c7f9fSRichard Henderson 
1229ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1230ee8c7f9fSRichard Henderson 
1231ee8c7f9fSRichard Henderson         tmp_1 = tcg_const_i32(1);
1232ee8c7f9fSRichard Henderson         tcg_gen_st_i32(tmp_1, cpu_env,
1233ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1234ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1235ee8c7f9fSRichard Henderson         tcg_temp_free_i32(tmp_1);
1236ee8c7f9fSRichard Henderson 
1237ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1238ee8c7f9fSRichard Henderson 
1239ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1240ee8c7f9fSRichard Henderson     }
1241ee8c7f9fSRichard Henderson 
1242ee8c7f9fSRichard Henderson     /*
1243ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1244ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1245ee8c7f9fSRichard Henderson      * code immediately.
1246ee8c7f9fSRichard Henderson      *
1247ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1248ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1249ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1250ee8c7f9fSRichard Henderson      *
1251ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1252ee8c7f9fSRichard Henderson      */
1253ee8c7f9fSRichard Henderson     dc->cpustate_changed = 1;
1254ee8c7f9fSRichard Henderson     return true;
1255ee8c7f9fSRichard Henderson }
1256ee8c7f9fSRichard Henderson 
1257e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1258e6cb0354SRichard Henderson {
1259e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1260e6cb0354SRichard Henderson         return true;
1261e6cb0354SRichard Henderson     }
1262e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1263e6cb0354SRichard Henderson     setup_dslot(dc, true);
1264e6cb0354SRichard Henderson 
1265e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1266e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1267e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1268e6cb0354SRichard Henderson     return true;
1269e6cb0354SRichard Henderson }
1270e6cb0354SRichard Henderson 
1271e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1272e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1273e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1274e6cb0354SRichard Henderson 
1275e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1276e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1277e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1278e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1279e6cb0354SRichard Henderson 
128020800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
128120800179SRichard Henderson {
128220800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
128320800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
128420800179SRichard Henderson         trap_illegal(dc, true);
128520800179SRichard Henderson         return true;
128620800179SRichard Henderson     }
128720800179SRichard Henderson     /*
128820800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
128920800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
129020800179SRichard Henderson      */
129120800179SRichard Henderson     return false;
1292fcf5ef2aSThomas Huth }
1293fcf5ef2aSThomas Huth 
12941074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1295fcf5ef2aSThomas Huth {
12961074c0fbSRichard Henderson     TCGv_i32 t;
12971074c0fbSRichard Henderson 
12981074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
12991074c0fbSRichard Henderson     t = tcg_temp_new_i32();
13001074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13011074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
13021074c0fbSRichard Henderson     tcg_temp_free_i32(t);
1303fcf5ef2aSThomas Huth }
1304fcf5ef2aSThomas Huth 
13059df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
13061074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v)
1307fcf5ef2aSThomas Huth {
1308fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
13091074c0fbSRichard Henderson 
13101074c0fbSRichard Henderson     /* Install MSR_C.  */
13111074c0fbSRichard Henderson     tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
13121074c0fbSRichard Henderson 
13131074c0fbSRichard Henderson     /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
13141074c0fbSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
1315fcf5ef2aSThomas Huth }
13169df297a2SRichard Henderson #endif
1317fcf5ef2aSThomas Huth 
1318536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1319536e340fSRichard Henderson {
1320536e340fSRichard Henderson     uint32_t imm = arg->imm;
1321536e340fSRichard Henderson 
1322536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1323536e340fSRichard Henderson         return true;
1324536e340fSRichard Henderson     }
1325536e340fSRichard Henderson 
1326536e340fSRichard Henderson     if (arg->rd) {
1327536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1328536e340fSRichard Henderson     }
1329536e340fSRichard Henderson 
1330536e340fSRichard Henderson     /*
1331536e340fSRichard Henderson      * Handle the carry bit separately.
1332536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1333536e340fSRichard Henderson      */
1334536e340fSRichard Henderson     if (imm & MSR_C) {
1335536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1336536e340fSRichard Henderson     }
1337536e340fSRichard Henderson 
1338536e340fSRichard Henderson     /*
1339536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1340536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1341536e340fSRichard Henderson      */
1342536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1343536e340fSRichard Henderson 
1344536e340fSRichard Henderson     if (imm != 0) {
1345536e340fSRichard Henderson         if (set) {
1346536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1347536e340fSRichard Henderson         } else {
1348536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1349536e340fSRichard Henderson         }
1350536e340fSRichard Henderson         dc->cpustate_changed = 1;
1351536e340fSRichard Henderson     }
1352536e340fSRichard Henderson     return true;
1353536e340fSRichard Henderson }
1354536e340fSRichard Henderson 
1355536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1356536e340fSRichard Henderson {
1357536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1358536e340fSRichard Henderson }
1359536e340fSRichard Henderson 
1360536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1361536e340fSRichard Henderson {
1362536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1363536e340fSRichard Henderson }
1364536e340fSRichard Henderson 
13659df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
1366fcf5ef2aSThomas Huth {
13679df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
13689df297a2SRichard Henderson         return true;
1369f0f7e7f7SEdgar E. Iglesias     }
1370f0f7e7f7SEdgar E. Iglesias 
13719df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
13729df297a2SRichard Henderson     g_assert_not_reached();
13739df297a2SRichard Henderson #else
13749df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
13759df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
13769df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
13779df297a2SRichard Henderson         return true;
13782023e9a3SEdgar E. Iglesias     }
1379fcf5ef2aSThomas Huth 
13809df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
13819df297a2SRichard Henderson     switch (arg->rs) {
1382aa28e6d4SRichard Henderson     case SR_MSR:
13839df297a2SRichard Henderson         msr_write(dc, src);
1384fcf5ef2aSThomas Huth         break;
13859df297a2SRichard Henderson     case SR_FSR:
13869df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr));
13879df297a2SRichard Henderson         break;
13889df297a2SRichard Henderson     case 0x800:
13899df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr));
13909df297a2SRichard Henderson         break;
13919df297a2SRichard Henderson     case 0x802:
13929df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr));
13939df297a2SRichard Henderson         break;
13949df297a2SRichard Henderson 
13959df297a2SRichard Henderson     case 0x1000: /* PID */
13969df297a2SRichard Henderson     case 0x1001: /* ZPR */
13979df297a2SRichard Henderson     case 0x1002: /* TLBX */
13989df297a2SRichard Henderson     case 0x1003: /* TLBLO */
13999df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14009df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14019df297a2SRichard Henderson         {
14029df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
14039df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
14049df297a2SRichard Henderson 
14059df297a2SRichard Henderson             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src);
14069df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
14079df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
14089df297a2SRichard Henderson         }
14099df297a2SRichard Henderson         break;
14109df297a2SRichard Henderson 
14119df297a2SRichard Henderson     default:
14129df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14139df297a2SRichard Henderson         return true;
14149df297a2SRichard Henderson     }
14159df297a2SRichard Henderson     dc->cpustate_changed = 1;
14169df297a2SRichard Henderson     return true;
14179df297a2SRichard Henderson #endif
14189df297a2SRichard Henderson }
14199df297a2SRichard Henderson 
14209df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14219df297a2SRichard Henderson {
14229df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
14239df297a2SRichard Henderson 
14249df297a2SRichard Henderson     if (arg->e) {
14259df297a2SRichard Henderson         switch (arg->rs) {
1426351527b7SEdgar E. Iglesias         case SR_EAR:
1427dbdb77c4SRichard Henderson             {
1428dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
14299df297a2SRichard Henderson                 tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
14309df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1431dbdb77c4SRichard Henderson                 tcg_temp_free_i64(t64);
1432dbdb77c4SRichard Henderson             }
14339df297a2SRichard Henderson             return true;
14349df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14359df297a2SRichard Henderson         case 0x1003: /* TLBLO */
14369df297a2SRichard Henderson             /* Handled below. */
1437aa28e6d4SRichard Henderson             break;
14389df297a2SRichard Henderson #endif
14399df297a2SRichard Henderson         case 0x2006 ... 0x2009:
14409df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
14419df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
14429df297a2SRichard Henderson             return true;
1443fcf5ef2aSThomas Huth         default:
14449df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
14459df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
14469df297a2SRichard Henderson             return true;
1447fcf5ef2aSThomas Huth         }
14489df297a2SRichard Henderson     }
14499df297a2SRichard Henderson 
14509df297a2SRichard Henderson     switch (arg->rs) {
1451aa28e6d4SRichard Henderson     case SR_PC:
14529df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
1453fcf5ef2aSThomas Huth         break;
1454aa28e6d4SRichard Henderson     case SR_MSR:
14559df297a2SRichard Henderson         msr_read(dc, dest);
1456fcf5ef2aSThomas Huth         break;
1457351527b7SEdgar E. Iglesias     case SR_EAR:
1458dbdb77c4SRichard Henderson         {
1459dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1460dbdb77c4SRichard Henderson             tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
14619df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1462dbdb77c4SRichard Henderson             tcg_temp_free_i64(t64);
1463a1b48e3aSEdgar E. Iglesias         }
1464aa28e6d4SRichard Henderson         break;
1465351527b7SEdgar E. Iglesias     case SR_ESR:
14669df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr));
1467aa28e6d4SRichard Henderson         break;
1468351527b7SEdgar E. Iglesias     case SR_FSR:
14699df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr));
1470aa28e6d4SRichard Henderson         break;
1471351527b7SEdgar E. Iglesias     case SR_BTR:
14729df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr));
1473aa28e6d4SRichard Henderson         break;
14747cdae31dSTong Ho     case SR_EDR:
14759df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr));
1476fcf5ef2aSThomas Huth         break;
1477fcf5ef2aSThomas Huth     case 0x800:
14789df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr));
1479fcf5ef2aSThomas Huth         break;
1480fcf5ef2aSThomas Huth     case 0x802:
14819df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr));
1482fcf5ef2aSThomas Huth         break;
14839df297a2SRichard Henderson 
14849df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14859df297a2SRichard Henderson     case 0x1000: /* PID */
14869df297a2SRichard Henderson     case 0x1001: /* ZPR */
14879df297a2SRichard Henderson     case 0x1002: /* TLBX */
14889df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14899df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14909df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14919df297a2SRichard Henderson         {
14929df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
14939df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
14949df297a2SRichard Henderson 
14959df297a2SRichard Henderson             gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg);
14969df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
14979df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
14989df297a2SRichard Henderson         }
14999df297a2SRichard Henderson         break;
15009df297a2SRichard Henderson #endif
15019df297a2SRichard Henderson 
1502351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
15039df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env,
15049df297a2SRichard Henderson                        offsetof(CPUMBState, pvr.regs[arg->rs - 0x2000]));
1505fcf5ef2aSThomas Huth         break;
1506fcf5ef2aSThomas Huth     default:
15079df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1508fcf5ef2aSThomas Huth         break;
1509fcf5ef2aSThomas Huth     }
15109df297a2SRichard Henderson     return true;
1511fcf5ef2aSThomas Huth }
1512fcf5ef2aSThomas Huth 
15133fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
1514fcf5ef2aSThomas Huth {
15153fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1516fcf5ef2aSThomas Huth 
15173fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15183fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15193fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15203fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15213fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15223fb394fdSRichard Henderson 
15233fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1524fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1525fcf5ef2aSThomas Huth }
1526fcf5ef2aSThomas Huth 
15273fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
1528fcf5ef2aSThomas Huth {
15293fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1530fcf5ef2aSThomas Huth 
15313fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15323fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15333fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15343fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15353fb394fdSRichard Henderson 
15363fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1537fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1538fcf5ef2aSThomas Huth }
1539fcf5ef2aSThomas Huth 
15403fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
1541fcf5ef2aSThomas Huth {
15423fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1543fcf5ef2aSThomas Huth 
15443fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15453fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15463fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15473fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15483fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1549fcf5ef2aSThomas Huth 
15503fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1551fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1552fcf5ef2aSThomas Huth }
1553fcf5ef2aSThomas Huth 
1554fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
155552065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1556fcf5ef2aSThomas Huth {
1557fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1558fcf5ef2aSThomas Huth 
1559bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
156052065d8fSRichard Henderson         return true;
1561fcf5ef2aSThomas Huth     }
1562fcf5ef2aSThomas Huth 
1563cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
156452065d8fSRichard Henderson     if (rb) {
156552065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1566fcf5ef2aSThomas Huth     } else {
156752065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
1568fcf5ef2aSThomas Huth     }
1569fcf5ef2aSThomas Huth 
1570cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
157152065d8fSRichard Henderson     gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
1572cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1573cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
157452065d8fSRichard Henderson     return true;
157552065d8fSRichard Henderson }
157652065d8fSRichard Henderson 
157752065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
157852065d8fSRichard Henderson {
157952065d8fSRichard Henderson     return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
158052065d8fSRichard Henderson }
158152065d8fSRichard Henderson 
158252065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
158352065d8fSRichard Henderson {
158452065d8fSRichard Henderson     return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
158552065d8fSRichard Henderson }
158652065d8fSRichard Henderson 
158752065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
158852065d8fSRichard Henderson {
158952065d8fSRichard Henderson     TCGv_i32 t_id, t_ctrl;
159052065d8fSRichard Henderson 
159152065d8fSRichard Henderson     if (trap_userspace(dc, true)) {
159252065d8fSRichard Henderson         return true;
159352065d8fSRichard Henderson     }
159452065d8fSRichard Henderson 
159552065d8fSRichard Henderson     t_id = tcg_temp_new_i32();
159652065d8fSRichard Henderson     if (rb) {
159752065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
159852065d8fSRichard Henderson     } else {
159952065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
160052065d8fSRichard Henderson     }
160152065d8fSRichard Henderson 
160252065d8fSRichard Henderson     t_ctrl = tcg_const_i32(ctrl);
160352065d8fSRichard Henderson     gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
160452065d8fSRichard Henderson     tcg_temp_free_i32(t_id);
160552065d8fSRichard Henderson     tcg_temp_free_i32(t_ctrl);
160652065d8fSRichard Henderson     return true;
160752065d8fSRichard Henderson }
160852065d8fSRichard Henderson 
160952065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
161052065d8fSRichard Henderson {
161152065d8fSRichard Henderson     return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
161252065d8fSRichard Henderson }
161352065d8fSRichard Henderson 
161452065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
161552065d8fSRichard Henderson {
161652065d8fSRichard Henderson     return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1617fcf5ef2aSThomas Huth }
1618fcf5ef2aSThomas Huth 
1619372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1620fcf5ef2aSThomas Huth {
1621372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1622372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1623372122e3SRichard Henderson     int bound;
1624fcf5ef2aSThomas Huth 
1625fcf5ef2aSThomas Huth     dc->cpu = cpu;
1626683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1627fcf5ef2aSThomas Huth     dc->cpustate_changed = 0;
1628d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
162920800179SRichard Henderson     dc->r0 = NULL;
163020800179SRichard Henderson     dc->r0_set = false;
1631287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
1632b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1633b9c58aabSRichard Henderson     dc->jmp_dest = -1;
1634fcf5ef2aSThomas Huth 
1635372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1636372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1637fcf5ef2aSThomas Huth }
1638fcf5ef2aSThomas Huth 
1639372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1640fcf5ef2aSThomas Huth {
1641fcf5ef2aSThomas Huth }
1642fcf5ef2aSThomas Huth 
1643372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1644372122e3SRichard Henderson {
1645683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1646683a247eSRichard Henderson 
1647683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1648683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1649372122e3SRichard Henderson }
1650fcf5ef2aSThomas Huth 
1651372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1652372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1653372122e3SRichard Henderson {
1654372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1655372122e3SRichard Henderson 
1656372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1657372122e3SRichard Henderson 
1658372122e3SRichard Henderson     /*
1659372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1660372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1661372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1662372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1663372122e3SRichard Henderson      */
1664372122e3SRichard Henderson     dc->base.pc_next += 4;
1665372122e3SRichard Henderson     return true;
1666372122e3SRichard Henderson }
1667372122e3SRichard Henderson 
1668372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1669372122e3SRichard Henderson {
1670372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1671372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
167244d1432bSRichard Henderson     uint32_t ir;
1673372122e3SRichard Henderson 
1674372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1675372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1676372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1677372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1678fcf5ef2aSThomas Huth     }
1679fcf5ef2aSThomas Huth 
16806f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
16816f9642d7SRichard Henderson 
168244d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
168344d1432bSRichard Henderson     if (!decode(dc, ir)) {
1684921afa9dSRichard Henderson         trap_illegal(dc, true);
168544d1432bSRichard Henderson     }
168620800179SRichard Henderson 
168720800179SRichard Henderson     if (dc->r0) {
168820800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
168920800179SRichard Henderson         dc->r0 = NULL;
169020800179SRichard Henderson         dc->r0_set = false;
169120800179SRichard Henderson     }
169220800179SRichard Henderson 
16936f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
16946f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1695d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1696372122e3SRichard Henderson     }
16976f9642d7SRichard Henderson 
16981e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
16996f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1700d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1701fcf5ef2aSThomas Huth 
1702b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
1703372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
1704fcf5ef2aSThomas Huth             do_rti(dc);
1705b9c58aabSRichard Henderson         } else if (dc->tb_flags & DRTB_FLAG) {
1706fcf5ef2aSThomas Huth             do_rtb(dc);
1707b9c58aabSRichard Henderson         } else if (dc->tb_flags & DRTE_FLAG) {
1708fcf5ef2aSThomas Huth             do_rte(dc);
1709372122e3SRichard Henderson         }
1710372122e3SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1711372122e3SRichard Henderson     }
1712372122e3SRichard Henderson 
1713372122e3SRichard Henderson     /* Force an exit if the per-tb cpu state has changed.  */
1714372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
1715*17e77796SRichard Henderson         dc->base.is_jmp = DISAS_EXIT;
1716372122e3SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1717372122e3SRichard Henderson     }
1718372122e3SRichard Henderson }
1719372122e3SRichard Henderson 
1720372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1721372122e3SRichard Henderson {
1722372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1723372122e3SRichard Henderson 
1724372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1725372122e3SRichard Henderson         /* We have already exited the TB. */
1726372122e3SRichard Henderson         return;
1727372122e3SRichard Henderson     }
1728372122e3SRichard Henderson 
1729372122e3SRichard Henderson     t_sync_flags(dc);
1730372122e3SRichard Henderson 
1731372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1732372122e3SRichard Henderson     case DISAS_TOO_MANY:
1733372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1734372122e3SRichard Henderson         return;
1735372122e3SRichard Henderson 
1736*17e77796SRichard Henderson     case DISAS_EXIT:
1737372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1738372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1739372122e3SRichard Henderson         } else {
1740372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1741372122e3SRichard Henderson         }
1742372122e3SRichard Henderson         return;
1743372122e3SRichard Henderson 
1744372122e3SRichard Henderson     case DISAS_JUMP:
1745b9c58aabSRichard Henderson         if (dc->jmp_dest != -1 && !cs->singlestep_enabled) {
1746b9c58aabSRichard Henderson             /* Direct jump. */
1747b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1748b9c58aabSRichard Henderson 
1749b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1750b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1751b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1752b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1753b9c58aabSRichard Henderson 
1754b9c58aabSRichard Henderson                 /*
1755b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1756b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1757b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1758b9c58aabSRichard Henderson                  */
1759b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1760b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1761b9c58aabSRichard Henderson 
1762b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1763b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1764b9c58aabSRichard Henderson                 gen_set_label(taken);
1765b9c58aabSRichard Henderson             }
1766b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1767b9c58aabSRichard Henderson             return;
1768b9c58aabSRichard Henderson         }
1769b9c58aabSRichard Henderson 
1770b9c58aabSRichard Henderson         /* Indirect jump (or direct jump w/ singlestep) */
1771b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1772b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1773372122e3SRichard Henderson 
1774372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1775372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1776372122e3SRichard Henderson         } else {
1777372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1778372122e3SRichard Henderson         }
1779372122e3SRichard Henderson         return;
1780372122e3SRichard Henderson 
1781a2b80dbdSRichard Henderson     default:
1782a2b80dbdSRichard Henderson         g_assert_not_reached();
1783fcf5ef2aSThomas Huth     }
1784fcf5ef2aSThomas Huth }
1785fcf5ef2aSThomas Huth 
1786372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1787372122e3SRichard Henderson {
1788372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1789372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1790fcf5ef2aSThomas Huth }
1791372122e3SRichard Henderson 
1792372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1793372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1794372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1795372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1796372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1797372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1798372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1799372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1800372122e3SRichard Henderson };
1801372122e3SRichard Henderson 
1802372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1803372122e3SRichard Henderson {
1804372122e3SRichard Henderson     DisasContext dc;
1805372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1806fcf5ef2aSThomas Huth }
1807fcf5ef2aSThomas Huth 
180890c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1809fcf5ef2aSThomas Huth {
1810fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1811fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
18120c3da918SRichard Henderson     uint32_t iflags;
1813fcf5ef2aSThomas Huth     int i;
1814fcf5ef2aSThomas Huth 
18150c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18160c3da918SRichard Henderson                  env->pc, env->msr,
18172e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18182e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18192e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18202e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18210c3da918SRichard Henderson 
18220c3da918SRichard Henderson     iflags = env->iflags;
18230c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18240c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18250c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18262ead1b18SJoe Komlodi     }
18270c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18280c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18290c3da918SRichard Henderson     }
18300c3da918SRichard Henderson     if (iflags & D_FLAG) {
1831b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18320c3da918SRichard Henderson     }
18330c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18340c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18350c3da918SRichard Henderson     }
18360c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18370c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18380c3da918SRichard Henderson     }
18390c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18400c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18410c3da918SRichard Henderson     }
18420c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18430c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18442ead1b18SJoe Komlodi     }
1845fcf5ef2aSThomas Huth 
18460c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
184719f27b6cSRichard Henderson                  "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
18480c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18490c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18500c3da918SRichard Henderson 
18510c3da918SRichard Henderson     for (i = 0; i < 12; i++) {
18520c3da918SRichard Henderson         qemu_fprintf(f, "rpvr%-2d=%08x%c",
18530c3da918SRichard Henderson                      i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' ');
1854fcf5ef2aSThomas Huth     }
18550c3da918SRichard Henderson 
18560c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18570c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18580c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18590c3da918SRichard Henderson     }
18600c3da918SRichard Henderson     qemu_fprintf(f, "\n");
1861fcf5ef2aSThomas Huth }
1862fcf5ef2aSThomas Huth 
1863fcf5ef2aSThomas Huth void mb_tcg_init(void)
1864fcf5ef2aSThomas Huth {
1865480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1866480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1867fcf5ef2aSThomas Huth 
1868480d29a8SRichard Henderson     static const struct {
1869480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1870480d29a8SRichard Henderson     } i32s[] = {
1871e47c2231SRichard Henderson         /*
1872e47c2231SRichard Henderson          * Note that r0 is handled specially in reg_for_read
1873e47c2231SRichard Henderson          * and reg_for_write.  Nothing should touch cpu_R[0].
1874e47c2231SRichard Henderson          * Leave that element NULL, which will assert quickly
1875e47c2231SRichard Henderson          * inside the tcg generator functions.
1876e47c2231SRichard Henderson          */
1877e47c2231SRichard Henderson                R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1878480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1879480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1880480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1881480d29a8SRichard Henderson 
1882480d29a8SRichard Henderson         SP(pc),
1883480d29a8SRichard Henderson         SP(msr),
18841074c0fbSRichard Henderson         SP(msr_c),
1885480d29a8SRichard Henderson         SP(imm),
1886480d29a8SRichard Henderson         SP(iflags),
1887b9c58aabSRichard Henderson         SP(bvalue),
1888480d29a8SRichard Henderson         SP(btarget),
1889480d29a8SRichard Henderson         SP(res_val),
1890480d29a8SRichard Henderson     };
1891480d29a8SRichard Henderson 
1892480d29a8SRichard Henderson #undef R
1893480d29a8SRichard Henderson #undef SP
1894480d29a8SRichard Henderson 
1895480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1896480d29a8SRichard Henderson         *i32s[i].var =
1897480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1898fcf5ef2aSThomas Huth     }
189976e8187dSRichard Henderson 
1900480d29a8SRichard Henderson     cpu_res_addr =
1901480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1902fcf5ef2aSThomas Huth }
1903fcf5ef2aSThomas Huth 
1904fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1905fcf5ef2aSThomas Huth                           target_ulong *data)
1906fcf5ef2aSThomas Huth {
190776e8187dSRichard Henderson     env->pc = data[0];
1908683a247eSRichard Henderson     env->iflags = data[1];
1909fcf5ef2aSThomas Huth }
1910