xref: /openbmc/qemu/target/microblaze/translate.c (revision 32f0c394bbf7fb2be635658cbf84c72a124720a0)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  Xilinx MicroBlaze emulation for qemu: main translation routines.
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2009 Edgar E. Iglesias.
5fcf5ef2aSThomas Huth  *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
10ee452036SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth  */
20fcf5ef2aSThomas Huth 
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "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/helper-gen.h"
2877fc6f5eSLluís Vilanova #include "exec/translator.h"
2990c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
30fcf5ef2aSThomas Huth 
31fcf5ef2aSThomas Huth #include "exec/log.h"
32fcf5ef2aSThomas Huth 
33d53106c9SRichard Henderson #define HELPER_H "helper.h"
34d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
35d53106c9SRichard Henderson #undef  HELPER_H
36d53106c9SRichard Henderson 
37fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
38fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
39fcf5ef2aSThomas Huth 
4077fc6f5eSLluís Vilanova /* is_jmp field values */
4177fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
4217e77796SRichard Henderson #define DISAS_EXIT    DISAS_TARGET_1 /* all cpu state modified dynamically */
4377fc6f5eSLluís Vilanova 
44f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */
45f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2
46f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */
47f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3
48f6278ca9SRichard Henderson 
49cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
500f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
513e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
521074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
539b158558SRichard Henderson static TCGv_i32 cpu_imm;
54b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
550f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
569b158558SRichard Henderson static TCGv_i32 cpu_iflags;
579b158558SRichard Henderson static TCGv cpu_res_addr;
589b158558SRichard Henderson static TCGv_i32 cpu_res_val;
59fcf5ef2aSThomas Huth 
60fcf5ef2aSThomas Huth /* This is the state at translation time.  */
61fcf5ef2aSThomas Huth typedef struct DisasContext {
62d4705ae0SRichard Henderson     DisasContextBase base;
634b893631SRichard Henderson     const MicroBlazeCPUConfig *cfg;
64fcf5ef2aSThomas Huth 
65683a247eSRichard Henderson     /* TCG op of the current insn_start.  */
66683a247eSRichard Henderson     TCGOp *insn_start;
67683a247eSRichard Henderson 
6820800179SRichard Henderson     TCGv_i32 r0;
6920800179SRichard Henderson     bool r0_set;
7020800179SRichard Henderson 
71fcf5ef2aSThomas Huth     /* Decoder.  */
72d7ecb757SRichard Henderson     uint32_t ext_imm;
73683a247eSRichard Henderson     unsigned int tb_flags;
746f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
75287b1defSRichard Henderson     int mem_index;
76fcf5ef2aSThomas Huth 
77b9c58aabSRichard Henderson     /* Condition under which to jump, including NEVER and ALWAYS. */
78b9c58aabSRichard Henderson     TCGCond jmp_cond;
79b9c58aabSRichard Henderson 
80b9c58aabSRichard Henderson     /* Immediate branch-taken destination, or -1 for indirect. */
81b9c58aabSRichard Henderson     uint32_t jmp_dest;
82fcf5ef2aSThomas Huth } DisasContext;
83fcf5ef2aSThomas Huth 
8420800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8520800179SRichard Henderson {
8620800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
8720800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
8820800179SRichard Henderson     }
8920800179SRichard Henderson     return x;
9020800179SRichard Henderson }
9120800179SRichard Henderson 
9244d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9344d1432bSRichard Henderson #include "decode-insns.c.inc"
9444d1432bSRichard Henderson 
95683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
96fcf5ef2aSThomas Huth {
97fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
9888e74b61SRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
9988e74b61SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
100fcf5ef2aSThomas Huth     }
101fcf5ef2aSThomas Huth }
102fcf5ef2aSThomas Huth 
10341ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
104fcf5ef2aSThomas Huth {
105ad75a51eSRichard Henderson     gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
106d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
107fcf5ef2aSThomas Huth }
108fcf5ef2aSThomas Huth 
10941ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
11041ba37c4SRichard Henderson {
11141ba37c4SRichard Henderson     t_sync_flags(dc);
112d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
11341ba37c4SRichard Henderson     gen_raise_exception(dc, index);
11441ba37c4SRichard Henderson }
11541ba37c4SRichard Henderson 
11641ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
11741ba37c4SRichard Henderson {
118a5ea3dd7SRichard Henderson     TCGv_i32 tmp = tcg_constant_i32(esr_ec);
119ad75a51eSRichard Henderson     tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUMBState, esr));
12041ba37c4SRichard Henderson 
12141ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
12241ba37c4SRichard Henderson }
12341ba37c4SRichard Henderson 
124fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
125fcf5ef2aSThomas Huth {
12666345580SRichard Henderson     if (translator_use_goto_tb(&dc->base, dest)) {
127fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1280f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
129d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
130fcf5ef2aSThomas Huth     } else {
1310f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1324059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
133fcf5ef2aSThomas Huth     }
134d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
135fcf5ef2aSThomas Huth }
136fcf5ef2aSThomas Huth 
137bdfc1e88SEdgar E. Iglesias /*
1389ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1399ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1409ba8cd45SEdgar E. Iglesias  */
1419ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1429ba8cd45SEdgar E. Iglesias {
1432c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1444b893631SRichard Henderson         && dc->cfg->illegal_opcode_exception) {
14541ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1469ba8cd45SEdgar E. Iglesias     }
1479ba8cd45SEdgar E. Iglesias     return cond;
1489ba8cd45SEdgar E. Iglesias }
1499ba8cd45SEdgar E. Iglesias 
1509ba8cd45SEdgar E. Iglesias /*
151bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
152bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
153bdfc1e88SEdgar E. Iglesias  */
154bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
155bdfc1e88SEdgar E. Iglesias {
156287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
157bdfc1e88SEdgar E. Iglesias 
1582c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
15941ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
160bdfc1e88SEdgar E. Iglesias     }
161bdfc1e88SEdgar E. Iglesias     return cond_user;
162bdfc1e88SEdgar E. Iglesias }
163bdfc1e88SEdgar E. Iglesias 
1642a7567a2SRichard Henderson /*
1652a7567a2SRichard Henderson  * Return true, and log an error, if the current insn is
1662a7567a2SRichard Henderson  * within a delay slot.
1672a7567a2SRichard Henderson  */
1682a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
1692a7567a2SRichard Henderson {
1702a7567a2SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1712a7567a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
1722a7567a2SRichard Henderson                       "Invalid insn in delay slot: %s at %08x\n",
1732a7567a2SRichard Henderson                       insn_type, (uint32_t)dc->base.pc_next);
1742a7567a2SRichard Henderson         return true;
1752a7567a2SRichard Henderson     }
1762a7567a2SRichard Henderson     return false;
1772a7567a2SRichard Henderson }
1782a7567a2SRichard Henderson 
17920800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
180fcf5ef2aSThomas Huth {
18120800179SRichard Henderson     if (likely(reg != 0)) {
18220800179SRichard Henderson         return cpu_R[reg];
183fcf5ef2aSThomas Huth     }
18420800179SRichard Henderson     if (!dc->r0_set) {
18520800179SRichard Henderson         if (dc->r0 == NULL) {
18620800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
187fcf5ef2aSThomas Huth         }
18820800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
18920800179SRichard Henderson         dc->r0_set = true;
19020800179SRichard Henderson     }
19120800179SRichard Henderson     return dc->r0;
192fcf5ef2aSThomas Huth }
193fcf5ef2aSThomas Huth 
19420800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
19520800179SRichard Henderson {
19620800179SRichard Henderson     if (likely(reg != 0)) {
19720800179SRichard Henderson         return cpu_R[reg];
19820800179SRichard Henderson     }
19920800179SRichard Henderson     if (dc->r0 == NULL) {
20020800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
20120800179SRichard Henderson     }
20220800179SRichard Henderson     return dc->r0;
203fcf5ef2aSThomas Huth }
204fcf5ef2aSThomas Huth 
20520800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
20620800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
20720800179SRichard Henderson {
20820800179SRichard Henderson     TCGv_i32 rd, ra, rb;
20920800179SRichard Henderson 
21020800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
21120800179SRichard Henderson         return true;
212fcf5ef2aSThomas Huth     }
21320800179SRichard Henderson 
21420800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
21520800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
21620800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
21720800179SRichard Henderson     fn(rd, ra, rb);
21820800179SRichard Henderson     return true;
21920800179SRichard Henderson }
22020800179SRichard Henderson 
22139cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
22239cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
22339cf3864SRichard Henderson {
22439cf3864SRichard Henderson     TCGv_i32 rd, ra;
22539cf3864SRichard Henderson 
22639cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
22739cf3864SRichard Henderson         return true;
22839cf3864SRichard Henderson     }
22939cf3864SRichard Henderson 
23039cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
23139cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
23239cf3864SRichard Henderson     fn(rd, ra);
23339cf3864SRichard Henderson     return true;
23439cf3864SRichard Henderson }
23539cf3864SRichard Henderson 
23620800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
23720800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
23820800179SRichard Henderson {
23920800179SRichard Henderson     TCGv_i32 rd, ra;
24020800179SRichard Henderson 
24120800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24220800179SRichard Henderson         return true;
24320800179SRichard Henderson     }
24420800179SRichard Henderson 
24520800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
24620800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
24720800179SRichard Henderson     fni(rd, ra, arg->imm);
24820800179SRichard Henderson     return true;
24920800179SRichard Henderson }
25020800179SRichard Henderson 
25120800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
25220800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
25320800179SRichard Henderson {
25420800179SRichard Henderson     TCGv_i32 rd, ra, imm;
25520800179SRichard Henderson 
25620800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
25720800179SRichard Henderson         return true;
25820800179SRichard Henderson     }
25920800179SRichard Henderson 
26020800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26120800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
262a5ea3dd7SRichard Henderson     imm = tcg_constant_i32(arg->imm);
26320800179SRichard Henderson 
26420800179SRichard Henderson     fn(rd, ra, imm);
26520800179SRichard Henderson     return true;
26620800179SRichard Henderson }
26720800179SRichard Henderson 
26820800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
26920800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
27020800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
27120800179SRichard Henderson 
272607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
273607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
2744b893631SRichard Henderson     { return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
275607f5767SRichard Henderson 
27639cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
27739cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
27839cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
27939cf3864SRichard Henderson 
28039cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
28139cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
2824b893631SRichard Henderson     { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
28339cf3864SRichard Henderson 
28420800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
28520800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
28620800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
28720800179SRichard Henderson 
28897955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
28997955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
2904b893631SRichard Henderson     { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
29197955cebSRichard Henderson 
29220800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
29320800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29420800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
29520800179SRichard Henderson 
296d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
297d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
298ad75a51eSRichard Henderson     { HELPER(out, tcg_env, ina); }
299d5aead3dSRichard Henderson 
300d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
301d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
302ad75a51eSRichard Henderson     { HELPER(out, tcg_env, ina, inb); }
303d5aead3dSRichard Henderson 
30420800179SRichard Henderson /* No input carry, but output carry. */
30520800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
30620800179SRichard Henderson {
307a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
30820800179SRichard Henderson 
30920800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
31020800179SRichard Henderson }
31120800179SRichard Henderson 
31220800179SRichard Henderson /* Input and output carry. */
31320800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
31420800179SRichard Henderson {
315a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
31620800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
31720800179SRichard Henderson 
31820800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
31920800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
32020800179SRichard Henderson }
32120800179SRichard Henderson 
32220800179SRichard Henderson /* Input carry, but no output carry. */
32320800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
32420800179SRichard Henderson {
32520800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
32620800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
32720800179SRichard Henderson }
32820800179SRichard Henderson 
32920800179SRichard Henderson DO_TYPEA(add, true, gen_add)
33020800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
33120800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
33220800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
33320800179SRichard Henderson 
33420800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
33520800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
33620800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
33720800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
33820800179SRichard Henderson 
339cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
340cb0a0a4cSRichard Henderson {
341cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
342cb0a0a4cSRichard Henderson }
343cb0a0a4cSRichard Henderson 
344cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
345cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
346cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
347cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
348cb0a0a4cSRichard Henderson 
349081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
350081d8e02SRichard Henderson {
351081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
352081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
353081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
354081d8e02SRichard Henderson }
355081d8e02SRichard Henderson 
356081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
357081d8e02SRichard Henderson {
358081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
359081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
360081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
361081d8e02SRichard Henderson }
362081d8e02SRichard Henderson 
363081d8e02SRichard Henderson static void gen_bsll(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_shl_i32(out, ina, tmp);
368081d8e02SRichard Henderson }
369081d8e02SRichard Henderson 
370081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
371081d8e02SRichard Henderson {
372081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
373081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
374081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
375081d8e02SRichard Henderson 
376081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
377081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
378081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
379081d8e02SRichard Henderson                       imm_w, imm_s);
380081d8e02SRichard Henderson     } else {
381081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
382081d8e02SRichard Henderson     }
383081d8e02SRichard Henderson }
384081d8e02SRichard Henderson 
385081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
386081d8e02SRichard Henderson {
387081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
388081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
389081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
390081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
391081d8e02SRichard Henderson 
392081d8e02SRichard Henderson     if (imm_w < imm_s) {
393081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
394081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
395081d8e02SRichard Henderson                       imm_w, imm_s);
396081d8e02SRichard Henderson     } else {
397081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
398081d8e02SRichard Henderson     }
399081d8e02SRichard Henderson }
400081d8e02SRichard Henderson 
401081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
402081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
403081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
404081d8e02SRichard Henderson 
405081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
406081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
407081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
408081d8e02SRichard Henderson 
409081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
410081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
411081d8e02SRichard Henderson 
41239cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
41339cf3864SRichard Henderson {
41439cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
41539cf3864SRichard Henderson }
41639cf3864SRichard Henderson 
41739cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
41839cf3864SRichard Henderson 
41958b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
42058b48b63SRichard Henderson {
42158b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
42258b48b63SRichard Henderson 
42358b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
42458b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
42558b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
42658b48b63SRichard Henderson }
42758b48b63SRichard Henderson 
42858b48b63SRichard Henderson static void gen_cmpu(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_LTU, 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 }
43658b48b63SRichard Henderson 
43758b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
43858b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
439a2b0b90eSRichard Henderson 
440d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
441d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
442d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
443d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
444d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
445d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
446d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
447d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
448d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
449d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
450d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
451d5aead3dSRichard Henderson 
452d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
453d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
454d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
455d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
456d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
457d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
458d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
459d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
460d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
461d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
462d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
463d5aead3dSRichard Henderson 
464d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
465d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
466d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
467d5aead3dSRichard Henderson 
468d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
469d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
470d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
471d5aead3dSRichard Henderson 
472d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
473b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
474b1354342SRichard Henderson {
475ad75a51eSRichard Henderson     gen_helper_divs(out, tcg_env, inb, ina);
476b1354342SRichard Henderson }
477b1354342SRichard Henderson 
478b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
479b1354342SRichard Henderson {
480ad75a51eSRichard Henderson     gen_helper_divu(out, tcg_env, inb, ina);
481b1354342SRichard Henderson }
482b1354342SRichard Henderson 
483b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
484b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
485b1354342SRichard Henderson 
486e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
487e64b2e5cSRichard Henderson {
4882a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "imm")) {
4892a7567a2SRichard Henderson         return true;
4902a7567a2SRichard Henderson     }
491e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
492e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
4936f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
494e64b2e5cSRichard Henderson     return true;
495e64b2e5cSRichard Henderson }
496e64b2e5cSRichard Henderson 
49797955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
49897955cebSRichard Henderson {
49997955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
50097955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
50197955cebSRichard Henderson }
50297955cebSRichard Henderson 
50397955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
50497955cebSRichard Henderson {
50597955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
50697955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
50797955cebSRichard Henderson }
50897955cebSRichard Henderson 
50997955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
51097955cebSRichard Henderson {
51197955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
51297955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
51397955cebSRichard Henderson }
51497955cebSRichard Henderson 
51597955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
51697955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
51797955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
51897955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
51997955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
52097955cebSRichard Henderson 
521cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
522cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
523cb0a0a4cSRichard Henderson 
524607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
525607f5767SRichard Henderson {
526607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
527607f5767SRichard Henderson }
528607f5767SRichard Henderson 
529607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
530607f5767SRichard Henderson {
531607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
532607f5767SRichard Henderson }
533607f5767SRichard Henderson 
534607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
535607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
536607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
537607f5767SRichard Henderson 
538a2b0b90eSRichard Henderson /* No input carry, but output carry. */
539a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
540a2b0b90eSRichard Henderson {
541a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
542a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
543a2b0b90eSRichard Henderson }
544a2b0b90eSRichard Henderson 
545a2b0b90eSRichard Henderson /* Input and output carry. */
546a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
547a2b0b90eSRichard Henderson {
548a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
549a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
550a2b0b90eSRichard Henderson 
551a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
552a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
553a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
554a2b0b90eSRichard Henderson }
555a2b0b90eSRichard Henderson 
556a2b0b90eSRichard Henderson /* No input or output carry. */
557a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
558a2b0b90eSRichard Henderson {
559a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
560a2b0b90eSRichard Henderson }
561a2b0b90eSRichard Henderson 
562a2b0b90eSRichard Henderson /* Input carry, no output carry. */
563a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
564a2b0b90eSRichard Henderson {
565a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
566a2b0b90eSRichard Henderson 
567a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
568a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
569a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
570a2b0b90eSRichard Henderson }
571a2b0b90eSRichard Henderson 
572a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
573a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
574a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
575a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
576a2b0b90eSRichard Henderson 
577a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
578a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
579a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
580a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
581a2b0b90eSRichard Henderson 
58239cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
58339cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
58439cf3864SRichard Henderson 
58539cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
58639cf3864SRichard Henderson {
58739cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
58839cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
58939cf3864SRichard Henderson }
59039cf3864SRichard Henderson 
59139cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
59239cf3864SRichard Henderson {
59339cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
59439cf3864SRichard Henderson 
59539cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
59639cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
59739cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
59839cf3864SRichard Henderson }
59939cf3864SRichard Henderson 
60039cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
60139cf3864SRichard Henderson {
60239cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
60339cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
60439cf3864SRichard Henderson }
60539cf3864SRichard Henderson 
60639cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
60739cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
60839cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
60939cf3864SRichard Henderson 
61039cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
61139cf3864SRichard Henderson {
61239cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
61339cf3864SRichard Henderson }
61439cf3864SRichard Henderson 
61539cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
61639cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
61739cf3864SRichard Henderson 
61839cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
61939cf3864SRichard Henderson {
62039cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
62139cf3864SRichard Henderson     trap_userspace(dc, true);
62239cf3864SRichard Henderson     return true;
62339cf3864SRichard Henderson }
62439cf3864SRichard Henderson 
625cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
626cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
627cb0a0a4cSRichard Henderson 
628d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
629d8e59c4aSRichard Henderson {
630d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
631d8e59c4aSRichard Henderson 
632d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
633d8e59c4aSRichard Henderson     if (ra && rb) {
634d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
635d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
636d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
637d8e59c4aSRichard Henderson     } else if (ra) {
638d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
639d8e59c4aSRichard Henderson     } else if (rb) {
640d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
641d8e59c4aSRichard Henderson     } else {
642d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
643d8e59c4aSRichard Henderson     }
644d8e59c4aSRichard Henderson 
6454b893631SRichard Henderson     if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
646ad75a51eSRichard Henderson         gen_helper_stackprot(tcg_env, ret);
647d8e59c4aSRichard Henderson     }
648d8e59c4aSRichard Henderson     return ret;
649d8e59c4aSRichard Henderson }
650d8e59c4aSRichard Henderson 
651d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
652d8e59c4aSRichard Henderson {
653d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
654d8e59c4aSRichard Henderson 
655d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
656d8e59c4aSRichard Henderson     if (ra) {
657d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
658d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
659d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
660d8e59c4aSRichard Henderson     } else {
661d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
662d8e59c4aSRichard Henderson     }
663d8e59c4aSRichard Henderson 
6644b893631SRichard Henderson     if (ra == 1 && dc->cfg->stackprot) {
665ad75a51eSRichard Henderson         gen_helper_stackprot(tcg_env, ret);
666d8e59c4aSRichard Henderson     }
667d8e59c4aSRichard Henderson     return ret;
668d8e59c4aSRichard Henderson }
669d8e59c4aSRichard Henderson 
67019f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
671d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
672d8e59c4aSRichard Henderson {
6734b893631SRichard Henderson     int addr_size = dc->cfg->addr_size;
674d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
675d8e59c4aSRichard Henderson 
676d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
677d8e59c4aSRichard Henderson         if (rb) {
678d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
679d8e59c4aSRichard Henderson         } else {
680d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
681d8e59c4aSRichard Henderson         }
682d8e59c4aSRichard Henderson     } else {
683d8e59c4aSRichard Henderson         if (rb) {
684d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
685d8e59c4aSRichard Henderson         } else {
686d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
687d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
688d8e59c4aSRichard Henderson         }
689d8e59c4aSRichard Henderson         if (addr_size < 64) {
690d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
691d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
692d8e59c4aSRichard Henderson         }
693d8e59c4aSRichard Henderson     }
694d8e59c4aSRichard Henderson     return ret;
695d8e59c4aSRichard Henderson }
69619f27b6cSRichard Henderson #endif
697d8e59c4aSRichard Henderson 
698b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
699ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
700ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
701ab0c8d0fSRichard Henderson {
702ab0c8d0fSRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
703ab0c8d0fSRichard Henderson 
704ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
705ab0c8d0fSRichard Henderson     iflags |= rd << 5;
706ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
707ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
708ab0c8d0fSRichard Henderson 
709ab0c8d0fSRichard Henderson     tcg_set_insn_start_param(dc->insn_start, 1, iflags);
710ab0c8d0fSRichard Henderson }
711b414df75SRichard Henderson #endif
712ab0c8d0fSRichard Henderson 
713d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
714d8e59c4aSRichard Henderson                     int mem_index, bool rev)
715d8e59c4aSRichard Henderson {
716d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
717d8e59c4aSRichard Henderson 
718d8e59c4aSRichard Henderson     /*
719d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
720d8e59c4aSRichard Henderson      *
721d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
722d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
723d8e59c4aSRichard Henderson      */
724d8e59c4aSRichard Henderson     if (rev) {
725d8e59c4aSRichard Henderson         if (size > MO_8) {
726d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
727d8e59c4aSRichard Henderson         }
728d8e59c4aSRichard Henderson         if (size < MO_32) {
729d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
730d8e59c4aSRichard Henderson         }
731d8e59c4aSRichard Henderson     }
732d8e59c4aSRichard Henderson 
733b414df75SRichard Henderson     /*
734b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
735b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
736b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
737b414df75SRichard Henderson      */
738b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
739ab0c8d0fSRichard Henderson     if (size > MO_8 &&
740ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
7414b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
742ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
743ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
744d8e59c4aSRichard Henderson     }
745b414df75SRichard Henderson #endif
746d8e59c4aSRichard Henderson 
747ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
748d8e59c4aSRichard Henderson     return true;
749d8e59c4aSRichard Henderson }
750d8e59c4aSRichard Henderson 
751d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
752d8e59c4aSRichard Henderson {
753d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
754d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
755d8e59c4aSRichard Henderson }
756d8e59c4aSRichard Henderson 
757d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
758d8e59c4aSRichard Henderson {
759d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
760d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
761d8e59c4aSRichard Henderson }
762d8e59c4aSRichard Henderson 
763d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
764d8e59c4aSRichard Henderson {
765d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
766d8e59c4aSRichard Henderson         return true;
767d8e59c4aSRichard Henderson     }
76819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
76919f27b6cSRichard Henderson     return true;
77019f27b6cSRichard Henderson #else
771d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
772d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
77319f27b6cSRichard Henderson #endif
774d8e59c4aSRichard Henderson }
775d8e59c4aSRichard Henderson 
776d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
777d8e59c4aSRichard Henderson {
778d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
779d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
780d8e59c4aSRichard Henderson }
781d8e59c4aSRichard Henderson 
782d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
783d8e59c4aSRichard Henderson {
784d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
785d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
786d8e59c4aSRichard Henderson }
787d8e59c4aSRichard Henderson 
788d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
789d8e59c4aSRichard Henderson {
790d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
791d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
792d8e59c4aSRichard Henderson }
793d8e59c4aSRichard Henderson 
794d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
795d8e59c4aSRichard Henderson {
796d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
797d8e59c4aSRichard Henderson         return true;
798d8e59c4aSRichard Henderson     }
79919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
80019f27b6cSRichard Henderson     return true;
80119f27b6cSRichard Henderson #else
802d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
803d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
80419f27b6cSRichard Henderson #endif
805d8e59c4aSRichard Henderson }
806d8e59c4aSRichard Henderson 
807d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
808d8e59c4aSRichard Henderson {
809d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
810d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
811d8e59c4aSRichard Henderson }
812d8e59c4aSRichard Henderson 
813d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
814d8e59c4aSRichard Henderson {
815d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
816d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
817d8e59c4aSRichard Henderson }
818d8e59c4aSRichard Henderson 
819d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
820d8e59c4aSRichard Henderson {
821d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
822d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
823d8e59c4aSRichard Henderson }
824d8e59c4aSRichard Henderson 
825d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
826d8e59c4aSRichard Henderson {
827d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
828d8e59c4aSRichard Henderson         return true;
829d8e59c4aSRichard Henderson     }
83019f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
83119f27b6cSRichard Henderson     return true;
83219f27b6cSRichard Henderson #else
833d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
834d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
83519f27b6cSRichard Henderson #endif
836d8e59c4aSRichard Henderson }
837d8e59c4aSRichard Henderson 
838d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
839d8e59c4aSRichard Henderson {
840d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
841d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
842d8e59c4aSRichard Henderson }
843d8e59c4aSRichard Henderson 
844d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
845d8e59c4aSRichard Henderson {
846d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
847d8e59c4aSRichard Henderson 
848d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
849d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
850d8e59c4aSRichard Henderson 
851d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
852d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
853d8e59c4aSRichard Henderson 
854d8e59c4aSRichard Henderson     if (arg->rd) {
855d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
856d8e59c4aSRichard Henderson     }
857d8e59c4aSRichard Henderson 
858d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
859d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
860d8e59c4aSRichard Henderson     return true;
861d8e59c4aSRichard Henderson }
862d8e59c4aSRichard Henderson 
863d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
864d8e59c4aSRichard Henderson                      int mem_index, bool rev)
865d8e59c4aSRichard Henderson {
866d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
867d8e59c4aSRichard Henderson 
868d8e59c4aSRichard Henderson     /*
869d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
870d8e59c4aSRichard Henderson      *
871d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
872d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
873d8e59c4aSRichard Henderson      */
874d8e59c4aSRichard Henderson     if (rev) {
875d8e59c4aSRichard Henderson         if (size > MO_8) {
876d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
877d8e59c4aSRichard Henderson         }
878d8e59c4aSRichard Henderson         if (size < MO_32) {
879d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
880d8e59c4aSRichard Henderson         }
881d8e59c4aSRichard Henderson     }
882d8e59c4aSRichard Henderson 
883b414df75SRichard Henderson     /*
884b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
885b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
886b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
887b414df75SRichard Henderson      */
888b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
889ab0c8d0fSRichard Henderson     if (size > MO_8 &&
890ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
8914b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
892ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
893ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
894d8e59c4aSRichard Henderson     }
895b414df75SRichard Henderson #endif
896d8e59c4aSRichard Henderson 
897ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
898d8e59c4aSRichard Henderson     return true;
899d8e59c4aSRichard Henderson }
900d8e59c4aSRichard Henderson 
901d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
902d8e59c4aSRichard Henderson {
903d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
904d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
905d8e59c4aSRichard Henderson }
906d8e59c4aSRichard Henderson 
907d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
908d8e59c4aSRichard Henderson {
909d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
910d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
911d8e59c4aSRichard Henderson }
912d8e59c4aSRichard Henderson 
913d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
914d8e59c4aSRichard Henderson {
915d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
916d8e59c4aSRichard Henderson         return true;
917d8e59c4aSRichard Henderson     }
91819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
91919f27b6cSRichard Henderson     return true;
92019f27b6cSRichard Henderson #else
921d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
922d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
92319f27b6cSRichard Henderson #endif
924d8e59c4aSRichard Henderson }
925d8e59c4aSRichard Henderson 
926d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
927d8e59c4aSRichard Henderson {
928d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
929d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
930d8e59c4aSRichard Henderson }
931d8e59c4aSRichard Henderson 
932d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
933d8e59c4aSRichard Henderson {
934d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
935d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
936d8e59c4aSRichard Henderson }
937d8e59c4aSRichard Henderson 
938d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
939d8e59c4aSRichard Henderson {
940d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
941d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
942d8e59c4aSRichard Henderson }
943d8e59c4aSRichard Henderson 
944d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
945d8e59c4aSRichard Henderson {
946d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
947d8e59c4aSRichard Henderson         return true;
948d8e59c4aSRichard Henderson     }
94919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
95019f27b6cSRichard Henderson     return true;
95119f27b6cSRichard Henderson #else
952d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
953d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
95419f27b6cSRichard Henderson #endif
955d8e59c4aSRichard Henderson }
956d8e59c4aSRichard Henderson 
957d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
958d8e59c4aSRichard Henderson {
959d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
960d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
961d8e59c4aSRichard Henderson }
962d8e59c4aSRichard Henderson 
963d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
964d8e59c4aSRichard Henderson {
965d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
966d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
967d8e59c4aSRichard Henderson }
968d8e59c4aSRichard Henderson 
969d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
970d8e59c4aSRichard Henderson {
971d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
972d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
973d8e59c4aSRichard Henderson }
974d8e59c4aSRichard Henderson 
975d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
976d8e59c4aSRichard Henderson {
977d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
978d8e59c4aSRichard Henderson         return true;
979d8e59c4aSRichard Henderson     }
98019f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
98119f27b6cSRichard Henderson     return true;
98219f27b6cSRichard Henderson #else
983d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
984d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
98519f27b6cSRichard Henderson #endif
986d8e59c4aSRichard Henderson }
987d8e59c4aSRichard Henderson 
988d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
989d8e59c4aSRichard Henderson {
990d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
991d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
992d8e59c4aSRichard Henderson }
993d8e59c4aSRichard Henderson 
994d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
995d8e59c4aSRichard Henderson {
996d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
997d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
998d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
999d8e59c4aSRichard Henderson     TCGv_i32 tval;
1000d8e59c4aSRichard Henderson 
1001d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1002d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1003d8e59c4aSRichard Henderson 
1004d8e59c4aSRichard Henderson     /*
1005d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1006d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1007d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1008d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1009d8e59c4aSRichard Henderson      */
1010d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1011d8e59c4aSRichard Henderson 
1012d8e59c4aSRichard Henderson     /*
1013d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1014d8e59c4aSRichard Henderson      * the reserved location.
1015d8e59c4aSRichard Henderson      */
1016d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1017d8e59c4aSRichard Henderson 
1018d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1019d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1020d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1021d8e59c4aSRichard Henderson 
1022d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1023d8e59c4aSRichard Henderson 
1024d8e59c4aSRichard Henderson     /* Success */
1025d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1026d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1027d8e59c4aSRichard Henderson 
1028d8e59c4aSRichard Henderson     /* Failure */
1029d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1030d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1031d8e59c4aSRichard Henderson 
1032d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1033d8e59c4aSRichard Henderson 
1034d8e59c4aSRichard Henderson     /*
1035d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1036d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1037d8e59c4aSRichard Henderson      */
1038d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1039d8e59c4aSRichard Henderson     return true;
1040d8e59c4aSRichard Henderson }
1041d8e59c4aSRichard Henderson 
104216bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
104316bbbbc9SRichard Henderson {
104416bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
104516bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
104616bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
104716bbbbc9SRichard Henderson     }
104816bbbbc9SRichard Henderson }
104916bbbbc9SRichard Henderson 
105016bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
105116bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
105216bbbbc9SRichard Henderson {
105316bbbbc9SRichard Henderson     uint32_t add_pc;
105416bbbbc9SRichard Henderson 
10552a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "branch")) {
10562a7567a2SRichard Henderson         return true;
10572a7567a2SRichard Henderson     }
105816bbbbc9SRichard Henderson     if (delay) {
105916bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
106016bbbbc9SRichard Henderson     }
106116bbbbc9SRichard Henderson 
106216bbbbc9SRichard Henderson     if (link) {
106316bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
106416bbbbc9SRichard Henderson     }
106516bbbbc9SRichard Henderson 
106616bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
106716bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
106816bbbbc9SRichard Henderson     if (dest_rb > 0) {
106916bbbbc9SRichard Henderson         dc->jmp_dest = -1;
107016bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
107116bbbbc9SRichard Henderson     } else {
107216bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
107316bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
107416bbbbc9SRichard Henderson     }
107516bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
107616bbbbc9SRichard Henderson     return true;
107716bbbbc9SRichard Henderson }
107816bbbbc9SRichard Henderson 
107916bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
108016bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
108116bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
108216bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
108316bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
108416bbbbc9SRichard Henderson 
108516bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
108616bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
108716bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
108816bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
108916bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
109016bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
109116bbbbc9SRichard Henderson 
1092fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1093fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1094fd779113SRichard Henderson {
1095fd779113SRichard Henderson     TCGv_i32 zero, next;
1096fd779113SRichard Henderson 
10972a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "bcc")) {
10982a7567a2SRichard Henderson         return true;
10992a7567a2SRichard Henderson     }
1100fd779113SRichard Henderson     if (delay) {
1101fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1102fd779113SRichard Henderson     }
1103fd779113SRichard Henderson 
1104fd779113SRichard Henderson     dc->jmp_cond = cond;
1105fd779113SRichard Henderson 
1106fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1107fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1108fd779113SRichard Henderson 
1109fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1110fd779113SRichard Henderson     if (dest_rb > 0) {
1111fd779113SRichard Henderson         dc->jmp_dest = -1;
1112fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1113fd779113SRichard Henderson     } else {
1114fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1115fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1116fd779113SRichard Henderson     }
1117fd779113SRichard Henderson 
1118fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1119a5ea3dd7SRichard Henderson     zero = tcg_constant_i32(0);
1120a5ea3dd7SRichard Henderson     next = tcg_constant_i32(dc->base.pc_next + (delay + 1) * 4);
1121fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1122fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1123fd779113SRichard Henderson                         cpu_btarget, next);
1124fd779113SRichard Henderson 
1125fd779113SRichard Henderson     return true;
1126fd779113SRichard Henderson }
1127fd779113SRichard Henderson 
1128fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1129fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1130fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1131fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1132fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1133fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1134fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1135fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1136fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1137fd779113SRichard Henderson 
1138fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1139fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1140fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1141fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1142fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1143fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1144fd779113SRichard Henderson 
1145f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1146f5235314SRichard Henderson {
1147f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1148f5235314SRichard Henderson         return true;
1149f5235314SRichard Henderson     }
11502a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brk")) {
11512a7567a2SRichard Henderson         return true;
11522a7567a2SRichard Henderson     }
11532a7567a2SRichard Henderson 
1154f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1155f5235314SRichard Henderson     if (arg->rd) {
1156f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1157f5235314SRichard Henderson     }
1158f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1159f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1160f5235314SRichard Henderson 
116117e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1162f5235314SRichard Henderson     return true;
1163f5235314SRichard Henderson }
1164f5235314SRichard Henderson 
1165f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1166f5235314SRichard Henderson {
1167f5235314SRichard Henderson     uint32_t imm = arg->imm;
1168f5235314SRichard Henderson 
1169f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1170f5235314SRichard Henderson         return true;
1171f5235314SRichard Henderson     }
11722a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brki")) {
11732a7567a2SRichard Henderson         return true;
11742a7567a2SRichard Henderson     }
11752a7567a2SRichard Henderson 
1176f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1177f5235314SRichard Henderson     if (arg->rd) {
1178f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1179f5235314SRichard Henderson     }
1180f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1181f5235314SRichard Henderson 
1182f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1183f5235314SRichard Henderson     switch (imm) {
1184f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1185f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1186f5235314SRichard Henderson         break;
1187f5235314SRichard Henderson     case 0x18: /* debug trap */
1188f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1189f5235314SRichard Henderson         break;
1190f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1191f5235314SRichard Henderson         g_assert_not_reached();
1192f5235314SRichard Henderson     }
1193f5235314SRichard Henderson #else
1194f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1195f5235314SRichard Henderson 
1196f5235314SRichard Henderson     if (imm != 0x18) {
1197f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1198f5235314SRichard Henderson     }
1199f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1200f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1201f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1202f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1203f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1204f5235314SRichard Henderson     }
1205f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
120617e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1207f5235314SRichard Henderson #endif
1208f5235314SRichard Henderson 
1209f5235314SRichard Henderson     return true;
1210f5235314SRichard Henderson }
1211f5235314SRichard Henderson 
1212ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1213ee8c7f9fSRichard Henderson {
1214ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1215ee8c7f9fSRichard Henderson 
12162a7567a2SRichard Henderson     /* Note that mbar is a specialized branch instruction. */
12172a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "mbar")) {
12182a7567a2SRichard Henderson         return true;
12192a7567a2SRichard Henderson     }
12202a7567a2SRichard Henderson 
1221ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1222ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1223ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1224ee8c7f9fSRichard Henderson     }
1225ee8c7f9fSRichard Henderson 
1226ee8c7f9fSRichard Henderson     /* Sleep. */
1227ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1228ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1229ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1230ee8c7f9fSRichard Henderson             return true;
1231ee8c7f9fSRichard Henderson         }
1232ee8c7f9fSRichard Henderson 
1233ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1234ee8c7f9fSRichard Henderson 
1235ad75a51eSRichard Henderson         tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
1236ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1237ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1238ee8c7f9fSRichard Henderson 
1239ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1240ee8c7f9fSRichard Henderson 
1241ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1242ee8c7f9fSRichard Henderson     }
1243ee8c7f9fSRichard Henderson 
1244ee8c7f9fSRichard Henderson     /*
1245ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1246ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1247ee8c7f9fSRichard Henderson      * code immediately.
1248ee8c7f9fSRichard Henderson      *
1249ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1250ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1251ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1252ee8c7f9fSRichard Henderson      *
1253ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1254ee8c7f9fSRichard Henderson      */
125543b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
1256ee8c7f9fSRichard Henderson     return true;
1257ee8c7f9fSRichard Henderson }
1258ee8c7f9fSRichard Henderson 
1259e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1260e6cb0354SRichard Henderson {
1261e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1262e6cb0354SRichard Henderson         return true;
1263e6cb0354SRichard Henderson     }
12642a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "rts")) {
12652a7567a2SRichard Henderson         return true;
12662a7567a2SRichard Henderson     }
12672a7567a2SRichard Henderson 
1268e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1269e6cb0354SRichard Henderson     setup_dslot(dc, true);
1270e6cb0354SRichard Henderson 
1271e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1272e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1273e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1274e6cb0354SRichard Henderson     return true;
1275e6cb0354SRichard Henderson }
1276e6cb0354SRichard Henderson 
1277e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1278e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1279e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1280e6cb0354SRichard Henderson 
1281e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1282e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1283e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1284e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1285e6cb0354SRichard Henderson 
128620800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
128720800179SRichard Henderson {
128820800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
12894b893631SRichard Henderson     if (dc->cfg->opcode_0_illegal) {
129020800179SRichard Henderson         trap_illegal(dc, true);
129120800179SRichard Henderson         return true;
129220800179SRichard Henderson     }
129320800179SRichard Henderson     /*
129420800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
129520800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
129620800179SRichard Henderson      */
129720800179SRichard Henderson     return false;
1298fcf5ef2aSThomas Huth }
1299fcf5ef2aSThomas Huth 
13001074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1301fcf5ef2aSThomas Huth {
13021074c0fbSRichard Henderson     TCGv_i32 t;
13031074c0fbSRichard Henderson 
13041074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
13051074c0fbSRichard Henderson     t = tcg_temp_new_i32();
13061074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13071074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
1308fcf5ef2aSThomas Huth }
1309fcf5ef2aSThomas Huth 
1310536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1311536e340fSRichard Henderson {
1312536e340fSRichard Henderson     uint32_t imm = arg->imm;
1313536e340fSRichard Henderson 
1314536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1315536e340fSRichard Henderson         return true;
1316536e340fSRichard Henderson     }
1317536e340fSRichard Henderson 
1318536e340fSRichard Henderson     if (arg->rd) {
1319536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1320536e340fSRichard Henderson     }
1321536e340fSRichard Henderson 
1322536e340fSRichard Henderson     /*
1323536e340fSRichard Henderson      * Handle the carry bit separately.
1324536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1325536e340fSRichard Henderson      */
1326536e340fSRichard Henderson     if (imm & MSR_C) {
1327536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1328536e340fSRichard Henderson     }
1329536e340fSRichard Henderson 
1330536e340fSRichard Henderson     /*
1331536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1332536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1333536e340fSRichard Henderson      */
1334536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1335536e340fSRichard Henderson 
1336536e340fSRichard Henderson     if (imm != 0) {
1337536e340fSRichard Henderson         if (set) {
1338536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1339536e340fSRichard Henderson         } else {
1340536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1341536e340fSRichard Henderson         }
134243b34134SRichard Henderson         dc->base.is_jmp = DISAS_EXIT_NEXT;
1343536e340fSRichard Henderson     }
1344536e340fSRichard Henderson     return true;
1345536e340fSRichard Henderson }
1346536e340fSRichard Henderson 
1347536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1348536e340fSRichard Henderson {
1349536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1350536e340fSRichard Henderson }
1351536e340fSRichard Henderson 
1352536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1353536e340fSRichard Henderson {
1354536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1355536e340fSRichard Henderson }
1356536e340fSRichard Henderson 
13579df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
1358fcf5ef2aSThomas Huth {
13599df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
13609df297a2SRichard Henderson         return true;
1361f0f7e7f7SEdgar E. Iglesias     }
1362f0f7e7f7SEdgar E. Iglesias 
13639df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
13649df297a2SRichard Henderson     g_assert_not_reached();
13659df297a2SRichard Henderson #else
13669df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
13679df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
13689df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
13699df297a2SRichard Henderson         return true;
13702023e9a3SEdgar E. Iglesias     }
1371fcf5ef2aSThomas Huth 
13729df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
13739df297a2SRichard Henderson     switch (arg->rs) {
1374aa28e6d4SRichard Henderson     case SR_MSR:
137543b34134SRichard Henderson         /* Install MSR_C.  */
137643b34134SRichard Henderson         tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
137743b34134SRichard Henderson         /*
137843b34134SRichard Henderson          * Clear MSR_C and MSR_CC;
137943b34134SRichard Henderson          * MSR_PVR is not writable, and is always clear.
138043b34134SRichard Henderson          */
138143b34134SRichard Henderson         tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
1382fcf5ef2aSThomas Huth         break;
13839df297a2SRichard Henderson     case SR_FSR:
1384ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, fsr));
13859df297a2SRichard Henderson         break;
13869df297a2SRichard Henderson     case 0x800:
1387ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, slr));
13889df297a2SRichard Henderson         break;
13899df297a2SRichard Henderson     case 0x802:
1390ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, shr));
13919df297a2SRichard Henderson         break;
13929df297a2SRichard Henderson 
13939df297a2SRichard Henderson     case 0x1000: /* PID */
13949df297a2SRichard Henderson     case 0x1001: /* ZPR */
13959df297a2SRichard Henderson     case 0x1002: /* TLBX */
13969df297a2SRichard Henderson     case 0x1003: /* TLBLO */
13979df297a2SRichard Henderson     case 0x1004: /* TLBHI */
13989df297a2SRichard Henderson     case 0x1005: /* TLBSX */
13999df297a2SRichard Henderson         {
1400a5ea3dd7SRichard Henderson             TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1401a5ea3dd7SRichard Henderson             TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
14029df297a2SRichard Henderson 
1403ad75a51eSRichard Henderson             gen_helper_mmu_write(tcg_env, tmp_ext, tmp_reg, src);
14049df297a2SRichard Henderson         }
14059df297a2SRichard Henderson         break;
14069df297a2SRichard Henderson 
14079df297a2SRichard Henderson     default:
14089df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14099df297a2SRichard Henderson         return true;
14109df297a2SRichard Henderson     }
141143b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
14129df297a2SRichard Henderson     return true;
14139df297a2SRichard Henderson #endif
14149df297a2SRichard Henderson }
14159df297a2SRichard Henderson 
14169df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14179df297a2SRichard Henderson {
14189df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
14199df297a2SRichard Henderson 
14209df297a2SRichard Henderson     if (arg->e) {
14219df297a2SRichard Henderson         switch (arg->rs) {
1422351527b7SEdgar E. Iglesias         case SR_EAR:
1423dbdb77c4SRichard Henderson             {
1424dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
1425ad75a51eSRichard Henderson                 tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14269df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1427dbdb77c4SRichard Henderson             }
14289df297a2SRichard Henderson             return true;
14299df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14309df297a2SRichard Henderson         case 0x1003: /* TLBLO */
14319df297a2SRichard Henderson             /* Handled below. */
1432aa28e6d4SRichard Henderson             break;
14339df297a2SRichard Henderson #endif
14349df297a2SRichard Henderson         case 0x2006 ... 0x2009:
14359df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
14369df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
14379df297a2SRichard Henderson             return true;
1438fcf5ef2aSThomas Huth         default:
14399df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
14409df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
14419df297a2SRichard Henderson             return true;
1442fcf5ef2aSThomas Huth         }
14439df297a2SRichard Henderson     }
14449df297a2SRichard Henderson 
14459df297a2SRichard Henderson     switch (arg->rs) {
1446aa28e6d4SRichard Henderson     case SR_PC:
14479df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
1448fcf5ef2aSThomas Huth         break;
1449aa28e6d4SRichard Henderson     case SR_MSR:
14509df297a2SRichard Henderson         msr_read(dc, dest);
1451fcf5ef2aSThomas Huth         break;
1452351527b7SEdgar E. Iglesias     case SR_EAR:
1453dbdb77c4SRichard Henderson         {
1454dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1455ad75a51eSRichard Henderson             tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14569df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1457a1b48e3aSEdgar E. Iglesias         }
1458aa28e6d4SRichard Henderson         break;
1459351527b7SEdgar E. Iglesias     case SR_ESR:
1460ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, esr));
1461aa28e6d4SRichard Henderson         break;
1462351527b7SEdgar E. Iglesias     case SR_FSR:
1463ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, fsr));
1464aa28e6d4SRichard Henderson         break;
1465351527b7SEdgar E. Iglesias     case SR_BTR:
1466ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, btr));
1467aa28e6d4SRichard Henderson         break;
14687cdae31dSTong Ho     case SR_EDR:
1469ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, edr));
1470fcf5ef2aSThomas Huth         break;
1471fcf5ef2aSThomas Huth     case 0x800:
1472ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, slr));
1473fcf5ef2aSThomas Huth         break;
1474fcf5ef2aSThomas Huth     case 0x802:
1475ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, shr));
1476fcf5ef2aSThomas Huth         break;
14779df297a2SRichard Henderson 
14789df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14799df297a2SRichard Henderson     case 0x1000: /* PID */
14809df297a2SRichard Henderson     case 0x1001: /* ZPR */
14819df297a2SRichard Henderson     case 0x1002: /* TLBX */
14829df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14839df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14849df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14859df297a2SRichard Henderson         {
1486a5ea3dd7SRichard Henderson             TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1487a5ea3dd7SRichard Henderson             TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
14889df297a2SRichard Henderson 
1489ad75a51eSRichard Henderson             gen_helper_mmu_read(dest, tcg_env, tmp_ext, tmp_reg);
14909df297a2SRichard Henderson         }
14919df297a2SRichard Henderson         break;
14929df297a2SRichard Henderson #endif
14939df297a2SRichard Henderson 
1494351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
1495ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env,
1496a4bcfc33SRichard Henderson                        offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1497a4bcfc33SRichard Henderson                        - offsetof(MicroBlazeCPU, env));
1498fcf5ef2aSThomas Huth         break;
1499fcf5ef2aSThomas Huth     default:
15009df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1501fcf5ef2aSThomas Huth         break;
1502fcf5ef2aSThomas Huth     }
15039df297a2SRichard Henderson     return true;
1504fcf5ef2aSThomas Huth }
1505fcf5ef2aSThomas Huth 
15063fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
1507fcf5ef2aSThomas Huth {
15083fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1509fcf5ef2aSThomas Huth 
15103fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15113fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15123fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15133fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15143fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1515fcf5ef2aSThomas Huth }
1516fcf5ef2aSThomas Huth 
15173fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
1518fcf5ef2aSThomas Huth {
15193fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1520fcf5ef2aSThomas Huth 
15213fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15223fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15233fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15243fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1525fcf5ef2aSThomas Huth }
1526fcf5ef2aSThomas Huth 
15273fb394fdSRichard Henderson static void do_rte(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_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15333fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15343fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15353fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1536fcf5ef2aSThomas Huth }
1537fcf5ef2aSThomas Huth 
1538fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
153952065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1540fcf5ef2aSThomas Huth {
1541fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1542fcf5ef2aSThomas Huth 
1543bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
154452065d8fSRichard Henderson         return true;
1545fcf5ef2aSThomas Huth     }
1546fcf5ef2aSThomas Huth 
1547cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
154852065d8fSRichard Henderson     if (rb) {
154952065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1550fcf5ef2aSThomas Huth     } else {
155152065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
1552fcf5ef2aSThomas Huth     }
1553fcf5ef2aSThomas Huth 
1554a5ea3dd7SRichard Henderson     t_ctrl = tcg_constant_i32(ctrl);
155552065d8fSRichard Henderson     gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
155652065d8fSRichard Henderson     return true;
155752065d8fSRichard Henderson }
155852065d8fSRichard Henderson 
155952065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
156052065d8fSRichard Henderson {
156152065d8fSRichard Henderson     return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
156252065d8fSRichard Henderson }
156352065d8fSRichard Henderson 
156452065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
156552065d8fSRichard Henderson {
156652065d8fSRichard Henderson     return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
156752065d8fSRichard Henderson }
156852065d8fSRichard Henderson 
156952065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
157052065d8fSRichard Henderson {
157152065d8fSRichard Henderson     TCGv_i32 t_id, t_ctrl;
157252065d8fSRichard Henderson 
157352065d8fSRichard Henderson     if (trap_userspace(dc, true)) {
157452065d8fSRichard Henderson         return true;
157552065d8fSRichard Henderson     }
157652065d8fSRichard Henderson 
157752065d8fSRichard Henderson     t_id = tcg_temp_new_i32();
157852065d8fSRichard Henderson     if (rb) {
157952065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
158052065d8fSRichard Henderson     } else {
158152065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
158252065d8fSRichard Henderson     }
158352065d8fSRichard Henderson 
1584a5ea3dd7SRichard Henderson     t_ctrl = tcg_constant_i32(ctrl);
158552065d8fSRichard Henderson     gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
158652065d8fSRichard Henderson     return true;
158752065d8fSRichard Henderson }
158852065d8fSRichard Henderson 
158952065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
159052065d8fSRichard Henderson {
159152065d8fSRichard Henderson     return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
159252065d8fSRichard Henderson }
159352065d8fSRichard Henderson 
159452065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
159552065d8fSRichard Henderson {
159652065d8fSRichard Henderson     return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1597fcf5ef2aSThomas Huth }
1598fcf5ef2aSThomas Huth 
1599372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1600fcf5ef2aSThomas Huth {
1601372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1602372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1603372122e3SRichard Henderson     int bound;
1604fcf5ef2aSThomas Huth 
16054b893631SRichard Henderson     dc->cfg = &cpu->cfg;
1606683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1607d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
160820800179SRichard Henderson     dc->r0 = NULL;
160920800179SRichard Henderson     dc->r0_set = false;
1610287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
1611b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1612b9c58aabSRichard Henderson     dc->jmp_dest = -1;
1613fcf5ef2aSThomas Huth 
1614372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1615372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1616fcf5ef2aSThomas Huth }
1617fcf5ef2aSThomas Huth 
1618372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1619fcf5ef2aSThomas Huth {
1620fcf5ef2aSThomas Huth }
1621fcf5ef2aSThomas Huth 
1622372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1623372122e3SRichard Henderson {
1624683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1625683a247eSRichard Henderson 
1626683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1627683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1628372122e3SRichard Henderson }
1629fcf5ef2aSThomas Huth 
1630372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1631372122e3SRichard Henderson {
1632372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1633b77af26eSRichard Henderson     CPUMBState *env = cpu_env(cs);
163444d1432bSRichard Henderson     uint32_t ir;
1635372122e3SRichard Henderson 
1636372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1637372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1638372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1639372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1640fcf5ef2aSThomas Huth     }
1641fcf5ef2aSThomas Huth 
16426f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
16436f9642d7SRichard Henderson 
164444d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
164544d1432bSRichard Henderson     if (!decode(dc, ir)) {
1646921afa9dSRichard Henderson         trap_illegal(dc, true);
164744d1432bSRichard Henderson     }
164820800179SRichard Henderson 
164920800179SRichard Henderson     if (dc->r0) {
165020800179SRichard Henderson         dc->r0 = NULL;
165120800179SRichard Henderson         dc->r0_set = false;
165220800179SRichard Henderson     }
165320800179SRichard Henderson 
16546f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
16556f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1656d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1657372122e3SRichard Henderson     }
16586f9642d7SRichard Henderson 
16591e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
16606f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1661d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1662fcf5ef2aSThomas Huth 
1663b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
16643d35bcc2SRichard Henderson         /*
16653d35bcc2SRichard Henderson          * Finish any return-from branch.
16663d35bcc2SRichard Henderson          */
16673c745866SRichard Henderson         uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16683c745866SRichard Henderson         if (unlikely(rt_ibe != 0)) {
16693c745866SRichard Henderson             dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16703c745866SRichard Henderson             if (rt_ibe & DRTI_FLAG) {
1671fcf5ef2aSThomas Huth                 do_rti(dc);
16723c745866SRichard Henderson             } else if (rt_ibe & DRTB_FLAG) {
1673fcf5ef2aSThomas Huth                 do_rtb(dc);
16743c745866SRichard Henderson             } else {
1675fcf5ef2aSThomas Huth                 do_rte(dc);
1676372122e3SRichard Henderson             }
16773c745866SRichard Henderson         }
16783d35bcc2SRichard Henderson 
16793d35bcc2SRichard Henderson         /* Complete the branch, ending the TB. */
16803d35bcc2SRichard Henderson         switch (dc->base.is_jmp) {
16813d35bcc2SRichard Henderson         case DISAS_NORETURN:
16823d35bcc2SRichard Henderson             /*
16833d35bcc2SRichard Henderson              * E.g. illegal insn in a delay slot.  We've already exited
16843d35bcc2SRichard Henderson              * and will handle D_FLAG in mb_cpu_do_interrupt.
16853d35bcc2SRichard Henderson              */
16863d35bcc2SRichard Henderson             break;
16873d35bcc2SRichard Henderson         case DISAS_NEXT:
16883c745866SRichard Henderson             /*
16893c745866SRichard Henderson              * Normal insn a delay slot.
16903c745866SRichard Henderson              * However, the return-from-exception type insns should
16913c745866SRichard Henderson              * return to the main loop, as they have adjusted MSR.
16923c745866SRichard Henderson              */
16933c745866SRichard Henderson             dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
16943d35bcc2SRichard Henderson             break;
16953d35bcc2SRichard Henderson         case DISAS_EXIT_NEXT:
16963d35bcc2SRichard Henderson             /*
16973d35bcc2SRichard Henderson              * E.g. mts insn in a delay slot.  Continue with btarget,
16983d35bcc2SRichard Henderson              * but still return to the main loop.
16993d35bcc2SRichard Henderson              */
17003d35bcc2SRichard Henderson             dc->base.is_jmp = DISAS_EXIT_JUMP;
17013d35bcc2SRichard Henderson             break;
17023d35bcc2SRichard Henderson         default:
17033d35bcc2SRichard Henderson             g_assert_not_reached();
17043d35bcc2SRichard Henderson         }
1705372122e3SRichard Henderson     }
1706372122e3SRichard Henderson }
1707372122e3SRichard Henderson 
1708372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1709372122e3SRichard Henderson {
1710372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1711372122e3SRichard Henderson 
1712372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1713372122e3SRichard Henderson         /* We have already exited the TB. */
1714372122e3SRichard Henderson         return;
1715372122e3SRichard Henderson     }
1716372122e3SRichard Henderson 
1717372122e3SRichard Henderson     t_sync_flags(dc);
1718372122e3SRichard Henderson 
1719372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1720372122e3SRichard Henderson     case DISAS_TOO_MANY:
1721372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1722372122e3SRichard Henderson         return;
1723372122e3SRichard Henderson 
172417e77796SRichard Henderson     case DISAS_EXIT:
1725f6278ca9SRichard Henderson         break;
1726f6278ca9SRichard Henderson     case DISAS_EXIT_NEXT:
1727f6278ca9SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1728f6278ca9SRichard Henderson         break;
1729f6278ca9SRichard Henderson     case DISAS_EXIT_JUMP:
1730f6278ca9SRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1731f6278ca9SRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1732f6278ca9SRichard Henderson         break;
1733372122e3SRichard Henderson 
1734372122e3SRichard Henderson     case DISAS_JUMP:
1735fbafb3a4SRichard Henderson         if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
1736b9c58aabSRichard Henderson             /* Direct jump. */
1737b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1738b9c58aabSRichard Henderson 
1739b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1740b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1741b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1742b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1743b9c58aabSRichard Henderson 
1744b9c58aabSRichard Henderson                 /*
1745b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1746b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1747b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1748b9c58aabSRichard Henderson                  */
1749b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1750b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1751b9c58aabSRichard Henderson 
1752b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1753b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1754b9c58aabSRichard Henderson                 gen_set_label(taken);
1755b9c58aabSRichard Henderson             }
1756b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1757b9c58aabSRichard Henderson             return;
1758b9c58aabSRichard Henderson         }
1759b9c58aabSRichard Henderson 
1760fbafb3a4SRichard Henderson         /* Indirect jump (or direct jump w/ goto_tb disabled) */
1761b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1762b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
17634059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
1764372122e3SRichard Henderson         return;
1765372122e3SRichard Henderson 
1766a2b80dbdSRichard Henderson     default:
1767a2b80dbdSRichard Henderson         g_assert_not_reached();
1768fcf5ef2aSThomas Huth     }
1769f6278ca9SRichard Henderson 
1770f6278ca9SRichard Henderson     /* Finish DISAS_EXIT_* */
1771f6278ca9SRichard Henderson     if (unlikely(cs->singlestep_enabled)) {
1772f6278ca9SRichard Henderson         gen_raise_exception(dc, EXCP_DEBUG);
1773f6278ca9SRichard Henderson     } else {
1774f6278ca9SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1775f6278ca9SRichard Henderson     }
1776fcf5ef2aSThomas Huth }
1777fcf5ef2aSThomas Huth 
17788eb806a7SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb,
17798eb806a7SRichard Henderson                             CPUState *cs, FILE *logfile)
1780372122e3SRichard Henderson {
17818eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(dcb->pc_first));
17828eb806a7SRichard Henderson     target_disas(logfile, cs, dcb->pc_first, dcb->tb->size);
1783fcf5ef2aSThomas Huth }
1784372122e3SRichard Henderson 
1785372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1786372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1787372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1788372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1789372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1790372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1791372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1792372122e3SRichard Henderson };
1793372122e3SRichard Henderson 
1794597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
1795*32f0c394SAnton Johansson                            vaddr pc, void *host_pc)
1796372122e3SRichard Henderson {
1797372122e3SRichard Henderson     DisasContext dc;
1798306c8721SRichard Henderson     translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base);
1799fcf5ef2aSThomas Huth }
1800fcf5ef2aSThomas Huth 
180190c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1802fcf5ef2aSThomas Huth {
1803fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1804fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
18050c3da918SRichard Henderson     uint32_t iflags;
1806fcf5ef2aSThomas Huth     int i;
1807fcf5ef2aSThomas Huth 
18080c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18090c3da918SRichard Henderson                  env->pc, env->msr,
18102e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18112e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18122e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18132e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18140c3da918SRichard Henderson 
18150c3da918SRichard Henderson     iflags = env->iflags;
18160c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18170c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18180c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18192ead1b18SJoe Komlodi     }
18200c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18210c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18220c3da918SRichard Henderson     }
18230c3da918SRichard Henderson     if (iflags & D_FLAG) {
1824b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18250c3da918SRichard Henderson     }
18260c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18270c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18280c3da918SRichard Henderson     }
18290c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18300c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18310c3da918SRichard Henderson     }
18320c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18330c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18340c3da918SRichard Henderson     }
18350c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18360c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18372ead1b18SJoe Komlodi     }
1838fcf5ef2aSThomas Huth 
18390c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
184019f27b6cSRichard Henderson                  "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
18410c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18420c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18430c3da918SRichard Henderson 
18440c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18450c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18460c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18470c3da918SRichard Henderson     }
18480c3da918SRichard Henderson     qemu_fprintf(f, "\n");
1849fcf5ef2aSThomas Huth }
1850fcf5ef2aSThomas Huth 
1851fcf5ef2aSThomas Huth void mb_tcg_init(void)
1852fcf5ef2aSThomas Huth {
1853480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1854480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1855fcf5ef2aSThomas Huth 
1856480d29a8SRichard Henderson     static const struct {
1857480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1858480d29a8SRichard Henderson     } i32s[] = {
1859e47c2231SRichard Henderson         /*
1860e47c2231SRichard Henderson          * Note that r0 is handled specially in reg_for_read
1861e47c2231SRichard Henderson          * and reg_for_write.  Nothing should touch cpu_R[0].
1862e47c2231SRichard Henderson          * Leave that element NULL, which will assert quickly
1863e47c2231SRichard Henderson          * inside the tcg generator functions.
1864e47c2231SRichard Henderson          */
1865e47c2231SRichard Henderson                R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1866480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1867480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1868480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1869480d29a8SRichard Henderson 
1870480d29a8SRichard Henderson         SP(pc),
1871480d29a8SRichard Henderson         SP(msr),
18721074c0fbSRichard Henderson         SP(msr_c),
1873480d29a8SRichard Henderson         SP(imm),
1874480d29a8SRichard Henderson         SP(iflags),
1875b9c58aabSRichard Henderson         SP(bvalue),
1876480d29a8SRichard Henderson         SP(btarget),
1877480d29a8SRichard Henderson         SP(res_val),
1878480d29a8SRichard Henderson     };
1879480d29a8SRichard Henderson 
1880480d29a8SRichard Henderson #undef R
1881480d29a8SRichard Henderson #undef SP
1882480d29a8SRichard Henderson 
1883480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1884480d29a8SRichard Henderson         *i32s[i].var =
1885ad75a51eSRichard Henderson           tcg_global_mem_new_i32(tcg_env, i32s[i].ofs, i32s[i].name);
1886fcf5ef2aSThomas Huth     }
188776e8187dSRichard Henderson 
1888480d29a8SRichard Henderson     cpu_res_addr =
1889ad75a51eSRichard Henderson         tcg_global_mem_new(tcg_env, offsetof(CPUMBState, res_addr), "res_addr");
1890fcf5ef2aSThomas Huth }
1891