xref: /qemu/target/microblaze/translate.c (revision 2c9e8ddd769959e899206b4cdea466ba5845e0bc)
14acb54baSEdgar E. Iglesias /*
24acb54baSEdgar E. Iglesias  *  Xilinx MicroBlaze emulation for qemu: main translation routines.
34acb54baSEdgar E. Iglesias  *
44acb54baSEdgar E. Iglesias  *  Copyright (c) 2009 Edgar E. Iglesias.
5dadc1064SPeter A. G. Crosthwaite  *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
64acb54baSEdgar E. Iglesias  *
74acb54baSEdgar E. Iglesias  * This library is free software; you can redistribute it and/or
84acb54baSEdgar E. Iglesias  * modify it under the terms of the GNU Lesser General Public
94acb54baSEdgar E. Iglesias  * License as published by the Free Software Foundation; either
10ee452036SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
114acb54baSEdgar E. Iglesias  *
124acb54baSEdgar E. Iglesias  * This library is distributed in the hope that it will be useful,
134acb54baSEdgar E. Iglesias  * but WITHOUT ANY WARRANTY; without even the implied warranty of
144acb54baSEdgar E. Iglesias  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
154acb54baSEdgar E. Iglesias  * Lesser General Public License for more details.
164acb54baSEdgar E. Iglesias  *
174acb54baSEdgar E. Iglesias  * You should have received a copy of the GNU Lesser General Public
188167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
194acb54baSEdgar E. Iglesias  */
204acb54baSEdgar E. Iglesias 
218fd9deceSPeter Maydell #include "qemu/osdep.h"
224acb54baSEdgar E. Iglesias #include "cpu.h"
2363c91552SPaolo Bonzini #include "exec/exec-all.h"
244597463bSPhilippe Mathieu-Daudé #include "exec/cpu_ldst.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
262ef6175aSRichard Henderson #include "exec/helper-proto.h"
272ef6175aSRichard Henderson #include "exec/helper-gen.h"
2877fc6f5eSLluís Vilanova #include "exec/translator.h"
2968df8c8dSPhilippe Mathieu-Daudé #include "exec/translation-block.h"
3090c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
314acb54baSEdgar E. Iglesias 
32508127e2SPaolo Bonzini #include "exec/log.h"
33a7e30d84SLluís Vilanova 
34d53106c9SRichard Henderson #define HELPER_H "helper.h"
35d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
36d53106c9SRichard Henderson #undef  HELPER_H
37d53106c9SRichard Henderson 
384acb54baSEdgar E. Iglesias #define EXTRACT_FIELD(src, start, end) \
394acb54baSEdgar E. Iglesias             (((src) >> start) & ((1 << (end - start + 1)) - 1))
404acb54baSEdgar E. Iglesias 
4177fc6f5eSLluís Vilanova /* is_jmp field values */
4277fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
4317e77796SRichard Henderson #define DISAS_EXIT    DISAS_TARGET_1 /* all cpu state modified dynamically */
4477fc6f5eSLluís Vilanova 
45f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */
46f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2
47f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */
48f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3
49f6278ca9SRichard Henderson 
50cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
510f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
523e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
531074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
549b158558SRichard Henderson static TCGv_i32 cpu_imm;
55b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
560f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
579b158558SRichard Henderson static TCGv_i32 cpu_iflags;
589b158558SRichard Henderson static TCGv cpu_res_addr;
599b158558SRichard Henderson static TCGv_i32 cpu_res_val;
604acb54baSEdgar E. Iglesias 
614acb54baSEdgar E. Iglesias /* This is the state at translation time.  */
624acb54baSEdgar E. Iglesias typedef struct DisasContext {
63d4705ae0SRichard Henderson     DisasContextBase base;
644b893631SRichard Henderson     const MicroBlazeCPUConfig *cfg;
654acb54baSEdgar E. Iglesias 
6620800179SRichard Henderson     TCGv_i32 r0;
6720800179SRichard Henderson     bool r0_set;
6820800179SRichard Henderson 
694acb54baSEdgar E. Iglesias     /* Decoder.  */
70d7ecb757SRichard Henderson     uint32_t ext_imm;
71683a247eSRichard Henderson     unsigned int tb_flags;
726f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
73287b1defSRichard Henderson     int mem_index;
744acb54baSEdgar E. Iglesias 
75b9c58aabSRichard Henderson     /* Condition under which to jump, including NEVER and ALWAYS. */
76b9c58aabSRichard Henderson     TCGCond jmp_cond;
77b9c58aabSRichard Henderson 
78b9c58aabSRichard Henderson     /* Immediate branch-taken destination, or -1 for indirect. */
79b9c58aabSRichard Henderson     uint32_t jmp_dest;
804acb54baSEdgar E. Iglesias } DisasContext;
814acb54baSEdgar E. Iglesias 
8220800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8320800179SRichard Henderson {
8420800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
8520800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
8620800179SRichard Henderson     }
8720800179SRichard Henderson     return x;
8820800179SRichard Henderson }
8920800179SRichard Henderson 
9044d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9144d1432bSRichard Henderson #include "decode-insns.c.inc"
9244d1432bSRichard Henderson 
93683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
944acb54baSEdgar E. Iglesias {
954abf79a4SDong Xu Wang     /* Synch the tb dependent flags between translator and runtime.  */
9688e74b61SRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
9788e74b61SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
984acb54baSEdgar E. Iglesias     }
994acb54baSEdgar E. Iglesias }
1004acb54baSEdgar E. Iglesias 
10141ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
1024acb54baSEdgar E. Iglesias {
103ad75a51eSRichard Henderson     gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
104d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
1054acb54baSEdgar E. Iglesias }
1064acb54baSEdgar E. Iglesias 
10741ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
10841ba37c4SRichard Henderson {
10941ba37c4SRichard Henderson     t_sync_flags(dc);
110d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
11141ba37c4SRichard Henderson     gen_raise_exception(dc, index);
11241ba37c4SRichard Henderson }
11341ba37c4SRichard Henderson 
11441ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
11541ba37c4SRichard Henderson {
116a5ea3dd7SRichard Henderson     TCGv_i32 tmp = tcg_constant_i32(esr_ec);
117ad75a51eSRichard Henderson     tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUMBState, esr));
11841ba37c4SRichard Henderson 
11941ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
12041ba37c4SRichard Henderson }
12141ba37c4SRichard Henderson 
1224acb54baSEdgar E. Iglesias static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
1234acb54baSEdgar E. Iglesias {
12466345580SRichard Henderson     if (translator_use_goto_tb(&dc->base, dest)) {
1254acb54baSEdgar E. Iglesias         tcg_gen_goto_tb(n);
1260f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
127d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
1284acb54baSEdgar E. Iglesias     } else {
1290f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1304059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
1314acb54baSEdgar E. Iglesias     }
132d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
1334acb54baSEdgar E. Iglesias }
1344acb54baSEdgar E. Iglesias 
135bdfc1e88SEdgar E. Iglesias /*
1369ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1379ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1389ba8cd45SEdgar E. Iglesias  */
1399ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1409ba8cd45SEdgar E. Iglesias {
1412c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1424b893631SRichard Henderson         && dc->cfg->illegal_opcode_exception) {
14341ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1449ba8cd45SEdgar E. Iglesias     }
1459ba8cd45SEdgar E. Iglesias     return cond;
1469ba8cd45SEdgar E. Iglesias }
1479ba8cd45SEdgar E. Iglesias 
1489ba8cd45SEdgar E. Iglesias /*
149bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
150bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
151bdfc1e88SEdgar E. Iglesias  */
152bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
153bdfc1e88SEdgar E. Iglesias {
154287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
155bdfc1e88SEdgar E. Iglesias 
1562c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
15741ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
158bdfc1e88SEdgar E. Iglesias     }
159bdfc1e88SEdgar E. Iglesias     return cond_user;
160bdfc1e88SEdgar E. Iglesias }
161bdfc1e88SEdgar E. Iglesias 
1622a7567a2SRichard Henderson /*
1632a7567a2SRichard Henderson  * Return true, and log an error, if the current insn is
1642a7567a2SRichard Henderson  * within a delay slot.
1652a7567a2SRichard Henderson  */
1662a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
1672a7567a2SRichard Henderson {
1682a7567a2SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1692a7567a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
1702a7567a2SRichard Henderson                       "Invalid insn in delay slot: %s at %08x\n",
1712a7567a2SRichard Henderson                       insn_type, (uint32_t)dc->base.pc_next);
1722a7567a2SRichard Henderson         return true;
1732a7567a2SRichard Henderson     }
1742a7567a2SRichard Henderson     return false;
1752a7567a2SRichard Henderson }
1762a7567a2SRichard Henderson 
17720800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
1784acb54baSEdgar E. Iglesias {
17920800179SRichard Henderson     if (likely(reg != 0)) {
18020800179SRichard Henderson         return cpu_R[reg];
1814acb54baSEdgar E. Iglesias     }
18220800179SRichard Henderson     if (!dc->r0_set) {
18320800179SRichard Henderson         if (dc->r0 == NULL) {
18420800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
1854acb54baSEdgar E. Iglesias         }
18620800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
18720800179SRichard Henderson         dc->r0_set = true;
18820800179SRichard Henderson     }
18920800179SRichard Henderson     return dc->r0;
19040cbf5b7SEdgar E. Iglesias }
19140cbf5b7SEdgar E. Iglesias 
19220800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
19320800179SRichard Henderson {
19420800179SRichard Henderson     if (likely(reg != 0)) {
19520800179SRichard Henderson         return cpu_R[reg];
19620800179SRichard Henderson     }
19720800179SRichard Henderson     if (dc->r0 == NULL) {
19820800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
19920800179SRichard Henderson     }
20020800179SRichard Henderson     return dc->r0;
20140cbf5b7SEdgar E. Iglesias }
20240cbf5b7SEdgar E. Iglesias 
20320800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
20420800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
20520800179SRichard Henderson {
20620800179SRichard Henderson     TCGv_i32 rd, ra, rb;
20720800179SRichard Henderson 
20820800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
20920800179SRichard Henderson         return true;
21040cbf5b7SEdgar E. Iglesias     }
21120800179SRichard Henderson 
21220800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
21320800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
21420800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
21520800179SRichard Henderson     fn(rd, ra, rb);
21620800179SRichard Henderson     return true;
21720800179SRichard Henderson }
21820800179SRichard Henderson 
21939cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
22039cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
22139cf3864SRichard Henderson {
22239cf3864SRichard Henderson     TCGv_i32 rd, ra;
22339cf3864SRichard Henderson 
22439cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
22539cf3864SRichard Henderson         return true;
22639cf3864SRichard Henderson     }
22739cf3864SRichard Henderson 
22839cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
22939cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
23039cf3864SRichard Henderson     fn(rd, ra);
23139cf3864SRichard Henderson     return true;
23239cf3864SRichard Henderson }
23339cf3864SRichard Henderson 
23420800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
23520800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
23620800179SRichard Henderson {
23720800179SRichard Henderson     TCGv_i32 rd, ra;
23820800179SRichard Henderson 
23920800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24020800179SRichard Henderson         return true;
24120800179SRichard Henderson     }
24220800179SRichard Henderson 
24320800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
24420800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
24520800179SRichard Henderson     fni(rd, ra, arg->imm);
24620800179SRichard Henderson     return true;
24720800179SRichard Henderson }
24820800179SRichard Henderson 
24920800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
25020800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
25120800179SRichard Henderson {
25220800179SRichard Henderson     TCGv_i32 rd, ra, imm;
25320800179SRichard Henderson 
25420800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
25520800179SRichard Henderson         return true;
25620800179SRichard Henderson     }
25720800179SRichard Henderson 
25820800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
25920800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
260a5ea3dd7SRichard Henderson     imm = tcg_constant_i32(arg->imm);
26120800179SRichard Henderson 
26220800179SRichard Henderson     fn(rd, ra, imm);
26320800179SRichard Henderson     return true;
26420800179SRichard Henderson }
26520800179SRichard Henderson 
26620800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
26720800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
26820800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
26920800179SRichard Henderson 
270607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
271607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
2724b893631SRichard Henderson     { return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
273607f5767SRichard Henderson 
27439cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
27539cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
27639cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
27739cf3864SRichard Henderson 
27839cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
27939cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
2804b893631SRichard Henderson     { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
28139cf3864SRichard Henderson 
28220800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
28320800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
28420800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
28520800179SRichard Henderson 
28697955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
28797955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
2884b893631SRichard Henderson     { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
28997955cebSRichard Henderson 
29020800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
29120800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29220800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
29320800179SRichard Henderson 
294d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
295d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
296ad75a51eSRichard Henderson     { HELPER(out, tcg_env, ina); }
297d5aead3dSRichard Henderson 
298d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
299d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
300ad75a51eSRichard Henderson     { HELPER(out, tcg_env, ina, inb); }
301d5aead3dSRichard Henderson 
30220800179SRichard Henderson /* No input carry, but output carry. */
30320800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
30420800179SRichard Henderson {
305a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
30620800179SRichard Henderson 
30720800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
30820800179SRichard Henderson }
30920800179SRichard Henderson 
31020800179SRichard Henderson /* Input and output carry. */
31120800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
31220800179SRichard Henderson {
313a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
31420800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
31520800179SRichard Henderson 
31620800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
31720800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
31820800179SRichard Henderson }
31920800179SRichard Henderson 
32020800179SRichard Henderson /* Input carry, but no output carry. */
32120800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
32220800179SRichard Henderson {
32320800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
32420800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
32520800179SRichard Henderson }
32620800179SRichard Henderson 
32720800179SRichard Henderson DO_TYPEA(add, true, gen_add)
32820800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
32920800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
33020800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
33120800179SRichard Henderson 
33220800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
33320800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
33420800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
33520800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
33620800179SRichard Henderson 
337cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
338cb0a0a4cSRichard Henderson {
339cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
340cb0a0a4cSRichard Henderson }
341cb0a0a4cSRichard Henderson 
342cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
343cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
344cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
345cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
346cb0a0a4cSRichard Henderson 
347081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
348081d8e02SRichard Henderson {
349081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
350081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
351081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
352081d8e02SRichard Henderson }
353081d8e02SRichard Henderson 
354081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
355081d8e02SRichard Henderson {
356081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
357081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
358081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
359081d8e02SRichard Henderson }
360081d8e02SRichard Henderson 
361081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
362081d8e02SRichard Henderson {
363081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
364081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
365081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
366081d8e02SRichard Henderson }
367081d8e02SRichard Henderson 
368081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
369081d8e02SRichard Henderson {
370081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
371081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
372081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
373081d8e02SRichard Henderson 
374081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
375081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
376081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
377081d8e02SRichard Henderson                       imm_w, imm_s);
378081d8e02SRichard Henderson     } else {
379081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
380081d8e02SRichard Henderson     }
381081d8e02SRichard Henderson }
382081d8e02SRichard Henderson 
383081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
384081d8e02SRichard Henderson {
385081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
386081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
387081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
388081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
389081d8e02SRichard Henderson 
390081d8e02SRichard Henderson     if (imm_w < imm_s) {
391081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
392081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
393081d8e02SRichard Henderson                       imm_w, imm_s);
394081d8e02SRichard Henderson     } else {
395081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
396081d8e02SRichard Henderson     }
397081d8e02SRichard Henderson }
398081d8e02SRichard Henderson 
399081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
400081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
401081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
402081d8e02SRichard Henderson 
403081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
404081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
405081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
406081d8e02SRichard Henderson 
407081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
408081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
409081d8e02SRichard Henderson 
41039cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
41139cf3864SRichard Henderson {
41239cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
41339cf3864SRichard Henderson }
41439cf3864SRichard Henderson 
41539cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
41639cf3864SRichard Henderson 
41758b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
41858b48b63SRichard Henderson {
41958b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
42058b48b63SRichard Henderson 
42158b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
42258b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
42358b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
42458b48b63SRichard Henderson }
42558b48b63SRichard Henderson 
42658b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
42758b48b63SRichard Henderson {
42858b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
42958b48b63SRichard Henderson 
43058b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
43158b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
43258b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
43358b48b63SRichard Henderson }
43458b48b63SRichard Henderson 
43558b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
43658b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
437a2b0b90eSRichard Henderson 
438d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
439d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
440d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
441d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
442d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
443d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
444d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
445d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
446d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
447d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
448d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
449d5aead3dSRichard Henderson 
450d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
451d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
452d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
453d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
454d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
455d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
456d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
457d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
458d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
459d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
460d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
461d5aead3dSRichard Henderson 
462d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
463d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
464d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
465d5aead3dSRichard Henderson 
466d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
467d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
468d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
469d5aead3dSRichard Henderson 
470d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
471b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
472b1354342SRichard Henderson {
473ad75a51eSRichard Henderson     gen_helper_divs(out, tcg_env, inb, ina);
474b1354342SRichard Henderson }
475b1354342SRichard Henderson 
476b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
477b1354342SRichard Henderson {
478ad75a51eSRichard Henderson     gen_helper_divu(out, tcg_env, inb, ina);
479b1354342SRichard Henderson }
480b1354342SRichard Henderson 
481b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
482b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
483b1354342SRichard Henderson 
484e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
485e64b2e5cSRichard Henderson {
4862a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "imm")) {
4872a7567a2SRichard Henderson         return true;
4882a7567a2SRichard Henderson     }
489e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
490e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
4916f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
492e64b2e5cSRichard Henderson     return true;
493e64b2e5cSRichard Henderson }
494e64b2e5cSRichard Henderson 
49597955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
49697955cebSRichard Henderson {
49797955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
49897955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
49997955cebSRichard Henderson }
50097955cebSRichard Henderson 
50197955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
50297955cebSRichard Henderson {
50397955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
50497955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
50597955cebSRichard Henderson }
50697955cebSRichard Henderson 
50797955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
50897955cebSRichard Henderson {
50997955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
51097955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
51197955cebSRichard Henderson }
51297955cebSRichard Henderson 
51397955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
51497955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
51597955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
51697955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
51797955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
51897955cebSRichard Henderson 
519cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
520cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
521cb0a0a4cSRichard Henderson 
522607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
523607f5767SRichard Henderson {
524607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
525607f5767SRichard Henderson }
526607f5767SRichard Henderson 
527607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
528607f5767SRichard Henderson {
529607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
530607f5767SRichard Henderson }
531607f5767SRichard Henderson 
532607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
533607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
534607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
535607f5767SRichard Henderson 
536a2b0b90eSRichard Henderson /* No input carry, but output carry. */
537a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
538a2b0b90eSRichard Henderson {
539a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
540a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
541a2b0b90eSRichard Henderson }
542a2b0b90eSRichard Henderson 
543a2b0b90eSRichard Henderson /* Input and output carry. */
544a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
545a2b0b90eSRichard Henderson {
546a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
547a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
548a2b0b90eSRichard Henderson 
549a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
550a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
551a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
552a2b0b90eSRichard Henderson }
553a2b0b90eSRichard Henderson 
554a2b0b90eSRichard Henderson /* No input or output carry. */
555a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
556a2b0b90eSRichard Henderson {
557a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
558a2b0b90eSRichard Henderson }
559a2b0b90eSRichard Henderson 
560a2b0b90eSRichard Henderson /* Input carry, no output carry. */
561a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
562a2b0b90eSRichard Henderson {
563a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
564a2b0b90eSRichard Henderson 
565a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
566a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
567a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
568a2b0b90eSRichard Henderson }
569a2b0b90eSRichard Henderson 
570a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
571a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
572a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
573a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
574a2b0b90eSRichard Henderson 
575a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
576a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
577a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
578a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
579a2b0b90eSRichard Henderson 
58039cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
58139cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
58239cf3864SRichard Henderson 
58339cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
58439cf3864SRichard Henderson {
58539cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
58639cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
58739cf3864SRichard Henderson }
58839cf3864SRichard Henderson 
58939cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
59039cf3864SRichard Henderson {
59139cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
59239cf3864SRichard Henderson 
59339cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
59439cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
59539cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
59639cf3864SRichard Henderson }
59739cf3864SRichard Henderson 
59839cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
59939cf3864SRichard Henderson {
60039cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
60139cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
60239cf3864SRichard Henderson }
60339cf3864SRichard Henderson 
60439cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
60539cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
60639cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
60739cf3864SRichard Henderson 
60839cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
60939cf3864SRichard Henderson {
61039cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
61139cf3864SRichard Henderson }
61239cf3864SRichard Henderson 
61339cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
61439cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
61539cf3864SRichard Henderson 
61639cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
61739cf3864SRichard Henderson {
61839cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
61939cf3864SRichard Henderson     trap_userspace(dc, true);
62039cf3864SRichard Henderson     return true;
62139cf3864SRichard Henderson }
62239cf3864SRichard Henderson 
623cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
624cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
625cb0a0a4cSRichard Henderson 
626d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
627d8e59c4aSRichard Henderson {
628d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
629d8e59c4aSRichard Henderson 
630d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
631d8e59c4aSRichard Henderson     if (ra && rb) {
632d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
633d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
634d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
635d8e59c4aSRichard Henderson     } else if (ra) {
636d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
637d8e59c4aSRichard Henderson     } else if (rb) {
638d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
639d8e59c4aSRichard Henderson     } else {
640d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
641d8e59c4aSRichard Henderson     }
642d8e59c4aSRichard Henderson 
6434b893631SRichard Henderson     if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
644ad75a51eSRichard Henderson         gen_helper_stackprot(tcg_env, ret);
645d8e59c4aSRichard Henderson     }
646d8e59c4aSRichard Henderson     return ret;
647d8e59c4aSRichard Henderson }
648d8e59c4aSRichard Henderson 
649d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
650d8e59c4aSRichard Henderson {
651d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
652d8e59c4aSRichard Henderson 
653d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
654d8e59c4aSRichard Henderson     if (ra) {
655d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
656d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
657d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
658d8e59c4aSRichard Henderson     } else {
659d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
660d8e59c4aSRichard Henderson     }
661d8e59c4aSRichard Henderson 
6624b893631SRichard Henderson     if (ra == 1 && dc->cfg->stackprot) {
663ad75a51eSRichard Henderson         gen_helper_stackprot(tcg_env, ret);
664d8e59c4aSRichard Henderson     }
665d8e59c4aSRichard Henderson     return ret;
666d8e59c4aSRichard Henderson }
667d8e59c4aSRichard Henderson 
66819f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
669d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
670d8e59c4aSRichard Henderson {
6714b893631SRichard Henderson     int addr_size = dc->cfg->addr_size;
672d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
673d8e59c4aSRichard Henderson 
674d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
675d8e59c4aSRichard Henderson         if (rb) {
676d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
677d8e59c4aSRichard Henderson         } else {
678d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
679d8e59c4aSRichard Henderson         }
680d8e59c4aSRichard Henderson     } else {
681d8e59c4aSRichard Henderson         if (rb) {
682d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
683d8e59c4aSRichard Henderson         } else {
684d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
685d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
686d8e59c4aSRichard Henderson         }
687d8e59c4aSRichard Henderson         if (addr_size < 64) {
688d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
689d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
690d8e59c4aSRichard Henderson         }
691d8e59c4aSRichard Henderson     }
692d8e59c4aSRichard Henderson     return ret;
693d8e59c4aSRichard Henderson }
69419f27b6cSRichard Henderson #endif
695d8e59c4aSRichard Henderson 
696b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
697ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
698ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
699ab0c8d0fSRichard Henderson {
700e2313450SRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->base.insn_start, 1);
701ab0c8d0fSRichard Henderson 
702ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
703ab0c8d0fSRichard Henderson     iflags |= rd << 5;
704ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
705ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
706ab0c8d0fSRichard Henderson 
707e2313450SRichard Henderson     tcg_set_insn_start_param(dc->base.insn_start, 1, iflags);
708ab0c8d0fSRichard Henderson }
709b414df75SRichard Henderson #endif
710ab0c8d0fSRichard Henderson 
711*2c9e8dddSPhilippe Mathieu-Daudé static inline MemOp mo_endian(DisasContext *dc)
712*2c9e8dddSPhilippe Mathieu-Daudé {
713*2c9e8dddSPhilippe Mathieu-Daudé     return MO_TE;
714*2c9e8dddSPhilippe Mathieu-Daudé }
715*2c9e8dddSPhilippe Mathieu-Daudé 
716d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
717d8e59c4aSRichard Henderson                     int mem_index, bool rev)
718d8e59c4aSRichard Henderson {
719d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
720d8e59c4aSRichard Henderson 
721*2c9e8dddSPhilippe Mathieu-Daudé     mop |= mo_endian(dc);
722401bd7d3SPhilippe Mathieu-Daudé 
723d8e59c4aSRichard Henderson     /*
724d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
725d8e59c4aSRichard Henderson      *
726d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
727d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
728d8e59c4aSRichard Henderson      */
729d8e59c4aSRichard Henderson     if (rev) {
730d8e59c4aSRichard Henderson         if (size > MO_8) {
731d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
732d8e59c4aSRichard Henderson         }
733d8e59c4aSRichard Henderson         if (size < MO_32) {
734d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
735d8e59c4aSRichard Henderson         }
736d8e59c4aSRichard Henderson     }
737d8e59c4aSRichard Henderson 
738b414df75SRichard Henderson     /*
739b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
740b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
741b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
742b414df75SRichard Henderson      */
743b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
744ab0c8d0fSRichard Henderson     if (size > MO_8 &&
745ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
7464b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
747ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
748ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
749d8e59c4aSRichard Henderson     }
750b414df75SRichard Henderson #endif
751d8e59c4aSRichard Henderson 
752ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
753d8e59c4aSRichard Henderson     return true;
754d8e59c4aSRichard Henderson }
755d8e59c4aSRichard Henderson 
756d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
757d8e59c4aSRichard Henderson {
758d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
759d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
760d8e59c4aSRichard Henderson }
761d8e59c4aSRichard Henderson 
762d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
763d8e59c4aSRichard Henderson {
764d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
765d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
766d8e59c4aSRichard Henderson }
767d8e59c4aSRichard Henderson 
768d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
769d8e59c4aSRichard Henderson {
770d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
771d8e59c4aSRichard Henderson         return true;
772d8e59c4aSRichard Henderson     }
77319f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
77419f27b6cSRichard Henderson     return true;
77519f27b6cSRichard Henderson #else
776d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
777d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
77819f27b6cSRichard Henderson #endif
779d8e59c4aSRichard Henderson }
780d8e59c4aSRichard Henderson 
781d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
782d8e59c4aSRichard Henderson {
783d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
784d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
785d8e59c4aSRichard Henderson }
786d8e59c4aSRichard Henderson 
787d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
788d8e59c4aSRichard Henderson {
789d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
790401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UW, dc->mem_index, false);
791d8e59c4aSRichard Henderson }
792d8e59c4aSRichard Henderson 
793d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
794d8e59c4aSRichard Henderson {
795d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
796401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UW, dc->mem_index, true);
797d8e59c4aSRichard Henderson }
798d8e59c4aSRichard Henderson 
799d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
800d8e59c4aSRichard Henderson {
801d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
802d8e59c4aSRichard Henderson         return true;
803d8e59c4aSRichard Henderson     }
80419f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
80519f27b6cSRichard Henderson     return true;
80619f27b6cSRichard Henderson #else
807d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
808401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UW, MMU_NOMMU_IDX, false);
80919f27b6cSRichard Henderson #endif
810d8e59c4aSRichard Henderson }
811d8e59c4aSRichard Henderson 
812d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
813d8e59c4aSRichard Henderson {
814d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
815401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UW, dc->mem_index, false);
816d8e59c4aSRichard Henderson }
817d8e59c4aSRichard Henderson 
818d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
819d8e59c4aSRichard Henderson {
820d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
821401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UL, dc->mem_index, false);
822d8e59c4aSRichard Henderson }
823d8e59c4aSRichard Henderson 
824d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
825d8e59c4aSRichard Henderson {
826d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
827401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UL, dc->mem_index, true);
828d8e59c4aSRichard Henderson }
829d8e59c4aSRichard Henderson 
830d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
831d8e59c4aSRichard Henderson {
832d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
833d8e59c4aSRichard Henderson         return true;
834d8e59c4aSRichard Henderson     }
83519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
83619f27b6cSRichard Henderson     return true;
83719f27b6cSRichard Henderson #else
838d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
839401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UL, MMU_NOMMU_IDX, false);
84019f27b6cSRichard Henderson #endif
841d8e59c4aSRichard Henderson }
842d8e59c4aSRichard Henderson 
843d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
844d8e59c4aSRichard Henderson {
845d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
846401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UL, dc->mem_index, false);
847d8e59c4aSRichard Henderson }
848d8e59c4aSRichard Henderson 
849d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
850d8e59c4aSRichard Henderson {
851d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
852d8e59c4aSRichard Henderson 
853d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
854d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
855d8e59c4aSRichard Henderson 
856*2c9e8dddSPhilippe Mathieu-Daudé     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index,
857*2c9e8dddSPhilippe Mathieu-Daudé                         mo_endian(dc) | MO_UL);
858d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
859d8e59c4aSRichard Henderson 
860d8e59c4aSRichard Henderson     if (arg->rd) {
861d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
862d8e59c4aSRichard Henderson     }
863d8e59c4aSRichard Henderson 
864d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
865d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
866d8e59c4aSRichard Henderson     return true;
867d8e59c4aSRichard Henderson }
868d8e59c4aSRichard Henderson 
869d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
870d8e59c4aSRichard Henderson                      int mem_index, bool rev)
871d8e59c4aSRichard Henderson {
872d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
873d8e59c4aSRichard Henderson 
874*2c9e8dddSPhilippe Mathieu-Daudé     mop |= mo_endian(dc);
875401bd7d3SPhilippe Mathieu-Daudé 
876d8e59c4aSRichard Henderson     /*
877d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
878d8e59c4aSRichard Henderson      *
879d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
880d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
881d8e59c4aSRichard Henderson      */
882d8e59c4aSRichard Henderson     if (rev) {
883d8e59c4aSRichard Henderson         if (size > MO_8) {
884d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
885d8e59c4aSRichard Henderson         }
886d8e59c4aSRichard Henderson         if (size < MO_32) {
887d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
888d8e59c4aSRichard Henderson         }
889d8e59c4aSRichard Henderson     }
890d8e59c4aSRichard Henderson 
891b414df75SRichard Henderson     /*
892b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
893b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
894b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
895b414df75SRichard Henderson      */
896b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
897ab0c8d0fSRichard Henderson     if (size > MO_8 &&
898ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
8994b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
900ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
901ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
902d8e59c4aSRichard Henderson     }
903b414df75SRichard Henderson #endif
904d8e59c4aSRichard Henderson 
905ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
906d8e59c4aSRichard Henderson     return true;
907d8e59c4aSRichard Henderson }
908d8e59c4aSRichard Henderson 
909d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
910d8e59c4aSRichard Henderson {
911d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
912d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
913d8e59c4aSRichard Henderson }
914d8e59c4aSRichard Henderson 
915d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
916d8e59c4aSRichard Henderson {
917d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
918d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
919d8e59c4aSRichard Henderson }
920d8e59c4aSRichard Henderson 
921d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
922d8e59c4aSRichard Henderson {
923d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
924d8e59c4aSRichard Henderson         return true;
925d8e59c4aSRichard Henderson     }
92619f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
92719f27b6cSRichard Henderson     return true;
92819f27b6cSRichard Henderson #else
929d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
930d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
93119f27b6cSRichard Henderson #endif
932d8e59c4aSRichard Henderson }
933d8e59c4aSRichard Henderson 
934d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
935d8e59c4aSRichard Henderson {
936d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
937d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
938d8e59c4aSRichard Henderson }
939d8e59c4aSRichard Henderson 
940d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
941d8e59c4aSRichard Henderson {
942d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
943401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UW, dc->mem_index, false);
944d8e59c4aSRichard Henderson }
945d8e59c4aSRichard Henderson 
946d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
947d8e59c4aSRichard Henderson {
948d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
949401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UW, dc->mem_index, true);
950d8e59c4aSRichard Henderson }
951d8e59c4aSRichard Henderson 
952d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
953d8e59c4aSRichard Henderson {
954d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
955d8e59c4aSRichard Henderson         return true;
956d8e59c4aSRichard Henderson     }
95719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
95819f27b6cSRichard Henderson     return true;
95919f27b6cSRichard Henderson #else
960d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
961401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UW, MMU_NOMMU_IDX, false);
96219f27b6cSRichard Henderson #endif
963d8e59c4aSRichard Henderson }
964d8e59c4aSRichard Henderson 
965d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
966d8e59c4aSRichard Henderson {
967d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
968401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UW, dc->mem_index, false);
969d8e59c4aSRichard Henderson }
970d8e59c4aSRichard Henderson 
971d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
972d8e59c4aSRichard Henderson {
973d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
974401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UL, dc->mem_index, false);
975d8e59c4aSRichard Henderson }
976d8e59c4aSRichard Henderson 
977d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
978d8e59c4aSRichard Henderson {
979d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
980401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UL, dc->mem_index, true);
981d8e59c4aSRichard Henderson }
982d8e59c4aSRichard Henderson 
983d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
984d8e59c4aSRichard Henderson {
985d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
986d8e59c4aSRichard Henderson         return true;
987d8e59c4aSRichard Henderson     }
98819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
98919f27b6cSRichard Henderson     return true;
99019f27b6cSRichard Henderson #else
991d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
992401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UL, MMU_NOMMU_IDX, false);
99319f27b6cSRichard Henderson #endif
994d8e59c4aSRichard Henderson }
995d8e59c4aSRichard Henderson 
996d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
997d8e59c4aSRichard Henderson {
998d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
999401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UL, dc->mem_index, false);
1000d8e59c4aSRichard Henderson }
1001d8e59c4aSRichard Henderson 
1002d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1003d8e59c4aSRichard Henderson {
1004d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1005d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1006d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1007d8e59c4aSRichard Henderson     TCGv_i32 tval;
1008d8e59c4aSRichard Henderson 
1009d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1010d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1011d8e59c4aSRichard Henderson 
1012d8e59c4aSRichard Henderson     /*
1013d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1014d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1015d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1016d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1017d8e59c4aSRichard Henderson      */
1018d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1019d8e59c4aSRichard Henderson 
1020d8e59c4aSRichard Henderson     /*
1021d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1022d8e59c4aSRichard Henderson      * the reserved location.
1023d8e59c4aSRichard Henderson      */
1024d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1025d8e59c4aSRichard Henderson 
1026d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1027d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1028*2c9e8dddSPhilippe Mathieu-Daudé                                dc->mem_index, mo_endian(dc) | MO_UL);
1029d8e59c4aSRichard Henderson 
1030d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1031d8e59c4aSRichard Henderson 
1032d8e59c4aSRichard Henderson     /* Success */
1033d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1034d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1035d8e59c4aSRichard Henderson 
1036d8e59c4aSRichard Henderson     /* Failure */
1037d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1038d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1039d8e59c4aSRichard Henderson 
1040d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1041d8e59c4aSRichard Henderson 
1042d8e59c4aSRichard Henderson     /*
1043d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1044d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1045d8e59c4aSRichard Henderson      */
1046d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1047d8e59c4aSRichard Henderson     return true;
1048d8e59c4aSRichard Henderson }
1049d8e59c4aSRichard Henderson 
105016bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
105116bbbbc9SRichard Henderson {
105216bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
105316bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
105416bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
105516bbbbc9SRichard Henderson     }
105616bbbbc9SRichard Henderson }
105716bbbbc9SRichard Henderson 
105816bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
105916bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
106016bbbbc9SRichard Henderson {
106116bbbbc9SRichard Henderson     uint32_t add_pc;
106216bbbbc9SRichard Henderson 
10632a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "branch")) {
10642a7567a2SRichard Henderson         return true;
10652a7567a2SRichard Henderson     }
106616bbbbc9SRichard Henderson     if (delay) {
106716bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
106816bbbbc9SRichard Henderson     }
106916bbbbc9SRichard Henderson 
107016bbbbc9SRichard Henderson     if (link) {
107116bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
107216bbbbc9SRichard Henderson     }
107316bbbbc9SRichard Henderson 
107416bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
107516bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
107616bbbbc9SRichard Henderson     if (dest_rb > 0) {
107716bbbbc9SRichard Henderson         dc->jmp_dest = -1;
107816bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
107916bbbbc9SRichard Henderson     } else {
108016bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
108116bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
108216bbbbc9SRichard Henderson     }
108316bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
108416bbbbc9SRichard Henderson     return true;
108516bbbbc9SRichard Henderson }
108616bbbbc9SRichard Henderson 
108716bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
108816bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
108916bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
109016bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
109116bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
109216bbbbc9SRichard Henderson 
109316bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
109416bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
109516bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
109616bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
109716bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
109816bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
109916bbbbc9SRichard Henderson 
1100fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1101fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1102fd779113SRichard Henderson {
1103fd779113SRichard Henderson     TCGv_i32 zero, next;
1104fd779113SRichard Henderson 
11052a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "bcc")) {
11062a7567a2SRichard Henderson         return true;
11072a7567a2SRichard Henderson     }
1108fd779113SRichard Henderson     if (delay) {
1109fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1110fd779113SRichard Henderson     }
1111fd779113SRichard Henderson 
1112fd779113SRichard Henderson     dc->jmp_cond = cond;
1113fd779113SRichard Henderson 
1114fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1115fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1116fd779113SRichard Henderson 
1117fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1118fd779113SRichard Henderson     if (dest_rb > 0) {
1119fd779113SRichard Henderson         dc->jmp_dest = -1;
1120fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1121fd779113SRichard Henderson     } else {
1122fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1123fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1124fd779113SRichard Henderson     }
1125fd779113SRichard Henderson 
1126fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1127a5ea3dd7SRichard Henderson     zero = tcg_constant_i32(0);
1128a5ea3dd7SRichard Henderson     next = tcg_constant_i32(dc->base.pc_next + (delay + 1) * 4);
1129fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1130fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1131fd779113SRichard Henderson                         cpu_btarget, next);
1132fd779113SRichard Henderson 
1133fd779113SRichard Henderson     return true;
1134fd779113SRichard Henderson }
1135fd779113SRichard Henderson 
1136fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1137fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1138fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1139fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1140fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1141fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1142fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1143fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1144fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1145fd779113SRichard Henderson 
1146fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1147fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1148fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1149fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1150fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1151fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1152fd779113SRichard Henderson 
1153f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1154f5235314SRichard Henderson {
1155f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1156f5235314SRichard Henderson         return true;
1157f5235314SRichard Henderson     }
11582a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brk")) {
11592a7567a2SRichard Henderson         return true;
11602a7567a2SRichard Henderson     }
11612a7567a2SRichard Henderson 
1162f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1163f5235314SRichard Henderson     if (arg->rd) {
1164f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1165f5235314SRichard Henderson     }
1166f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1167f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1168f5235314SRichard Henderson 
116917e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1170f5235314SRichard Henderson     return true;
1171f5235314SRichard Henderson }
1172f5235314SRichard Henderson 
1173f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1174f5235314SRichard Henderson {
1175f5235314SRichard Henderson     uint32_t imm = arg->imm;
1176f5235314SRichard Henderson 
1177f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1178f5235314SRichard Henderson         return true;
1179f5235314SRichard Henderson     }
11802a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brki")) {
11812a7567a2SRichard Henderson         return true;
11822a7567a2SRichard Henderson     }
11832a7567a2SRichard Henderson 
1184f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1185f5235314SRichard Henderson     if (arg->rd) {
1186f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1187f5235314SRichard Henderson     }
1188f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1189f5235314SRichard Henderson 
1190f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1191f5235314SRichard Henderson     switch (imm) {
1192f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1193f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1194f5235314SRichard Henderson         break;
1195f5235314SRichard Henderson     case 0x18: /* debug trap */
1196f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1197f5235314SRichard Henderson         break;
1198f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1199f5235314SRichard Henderson         g_assert_not_reached();
1200f5235314SRichard Henderson     }
1201f5235314SRichard Henderson #else
1202f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1203f5235314SRichard Henderson 
1204f5235314SRichard Henderson     if (imm != 0x18) {
1205f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1206f5235314SRichard Henderson     }
1207f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1208f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1209f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1210f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1211f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1212f5235314SRichard Henderson     }
1213f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
121417e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1215f5235314SRichard Henderson #endif
1216f5235314SRichard Henderson 
1217f5235314SRichard Henderson     return true;
1218f5235314SRichard Henderson }
1219f5235314SRichard Henderson 
1220ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1221ee8c7f9fSRichard Henderson {
1222ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1223ee8c7f9fSRichard Henderson 
12242a7567a2SRichard Henderson     /* Note that mbar is a specialized branch instruction. */
12252a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "mbar")) {
12262a7567a2SRichard Henderson         return true;
12272a7567a2SRichard Henderson     }
12282a7567a2SRichard Henderson 
1229ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1230ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1231ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1232ee8c7f9fSRichard Henderson     }
1233ee8c7f9fSRichard Henderson 
1234ee8c7f9fSRichard Henderson     /* Sleep. */
1235ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1236ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1237ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1238ee8c7f9fSRichard Henderson             return true;
1239ee8c7f9fSRichard Henderson         }
1240ee8c7f9fSRichard Henderson 
1241ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1242ee8c7f9fSRichard Henderson 
1243ad75a51eSRichard Henderson         tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
1244ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1245ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1246ee8c7f9fSRichard Henderson 
1247ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1248ee8c7f9fSRichard Henderson 
1249ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1250ee8c7f9fSRichard Henderson     }
1251ee8c7f9fSRichard Henderson 
1252ee8c7f9fSRichard Henderson     /*
1253ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1254ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1255ee8c7f9fSRichard Henderson      * code immediately.
1256ee8c7f9fSRichard Henderson      *
1257ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1258ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1259ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1260ee8c7f9fSRichard Henderson      *
1261ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1262ee8c7f9fSRichard Henderson      */
126343b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
1264ee8c7f9fSRichard Henderson     return true;
1265ee8c7f9fSRichard Henderson }
1266ee8c7f9fSRichard Henderson 
1267e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1268e6cb0354SRichard Henderson {
1269e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1270e6cb0354SRichard Henderson         return true;
1271e6cb0354SRichard Henderson     }
12722a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "rts")) {
12732a7567a2SRichard Henderson         return true;
12742a7567a2SRichard Henderson     }
12752a7567a2SRichard Henderson 
1276e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1277e6cb0354SRichard Henderson     setup_dslot(dc, true);
1278e6cb0354SRichard Henderson 
1279e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1280e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1281e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1282e6cb0354SRichard Henderson     return true;
1283e6cb0354SRichard Henderson }
1284e6cb0354SRichard Henderson 
1285e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1286e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1287e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1288e6cb0354SRichard Henderson 
1289e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1290e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1291e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1292e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1293e6cb0354SRichard Henderson 
129420800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
129520800179SRichard Henderson {
129620800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
12974b893631SRichard Henderson     if (dc->cfg->opcode_0_illegal) {
129820800179SRichard Henderson         trap_illegal(dc, true);
129920800179SRichard Henderson         return true;
130020800179SRichard Henderson     }
130120800179SRichard Henderson     /*
130220800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
130320800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
130420800179SRichard Henderson      */
130520800179SRichard Henderson     return false;
130640cbf5b7SEdgar E. Iglesias }
13074acb54baSEdgar E. Iglesias 
13081074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
13094acb54baSEdgar E. Iglesias {
13101074c0fbSRichard Henderson     TCGv_i32 t;
13111074c0fbSRichard Henderson 
13121074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
13131074c0fbSRichard Henderson     t = tcg_temp_new_i32();
13141074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13151074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
13164acb54baSEdgar E. Iglesias }
13174acb54baSEdgar E. Iglesias 
1318536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1319536e340fSRichard Henderson {
1320536e340fSRichard Henderson     uint32_t imm = arg->imm;
1321536e340fSRichard Henderson 
1322536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1323536e340fSRichard Henderson         return true;
1324536e340fSRichard Henderson     }
1325536e340fSRichard Henderson 
1326536e340fSRichard Henderson     if (arg->rd) {
1327536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1328536e340fSRichard Henderson     }
1329536e340fSRichard Henderson 
1330536e340fSRichard Henderson     /*
1331536e340fSRichard Henderson      * Handle the carry bit separately.
1332536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1333536e340fSRichard Henderson      */
1334536e340fSRichard Henderson     if (imm & MSR_C) {
1335536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1336536e340fSRichard Henderson     }
1337536e340fSRichard Henderson 
1338536e340fSRichard Henderson     /*
1339536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1340536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1341536e340fSRichard Henderson      */
1342536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1343536e340fSRichard Henderson 
1344536e340fSRichard Henderson     if (imm != 0) {
1345536e340fSRichard Henderson         if (set) {
1346536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1347536e340fSRichard Henderson         } else {
1348536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1349536e340fSRichard Henderson         }
135043b34134SRichard Henderson         dc->base.is_jmp = DISAS_EXIT_NEXT;
1351536e340fSRichard Henderson     }
1352536e340fSRichard Henderson     return true;
1353536e340fSRichard Henderson }
1354536e340fSRichard Henderson 
1355536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1356536e340fSRichard Henderson {
1357536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1358536e340fSRichard Henderson }
1359536e340fSRichard Henderson 
1360536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1361536e340fSRichard Henderson {
1362536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1363536e340fSRichard Henderson }
1364536e340fSRichard Henderson 
13659df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
13664acb54baSEdgar E. Iglesias {
13679df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
13689df297a2SRichard Henderson         return true;
1369f0f7e7f7SEdgar E. Iglesias     }
1370f0f7e7f7SEdgar E. Iglesias 
13719df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
13729df297a2SRichard Henderson     g_assert_not_reached();
13739df297a2SRichard Henderson #else
13749df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
13759df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
13769df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
13779df297a2SRichard Henderson         return true;
13782023e9a3SEdgar E. Iglesias     }
13794acb54baSEdgar E. Iglesias 
13809df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
13819df297a2SRichard Henderson     switch (arg->rs) {
1382aa28e6d4SRichard Henderson     case SR_MSR:
138343b34134SRichard Henderson         /* Install MSR_C.  */
138443b34134SRichard Henderson         tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
138543b34134SRichard Henderson         /*
138643b34134SRichard Henderson          * Clear MSR_C and MSR_CC;
138743b34134SRichard Henderson          * MSR_PVR is not writable, and is always clear.
138843b34134SRichard Henderson          */
138943b34134SRichard Henderson         tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
13904acb54baSEdgar E. Iglesias         break;
13919df297a2SRichard Henderson     case SR_FSR:
1392ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, fsr));
13939df297a2SRichard Henderson         break;
13949df297a2SRichard Henderson     case 0x800:
1395ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, slr));
13969df297a2SRichard Henderson         break;
13979df297a2SRichard Henderson     case 0x802:
1398ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, shr));
13999df297a2SRichard Henderson         break;
14009df297a2SRichard Henderson 
14019df297a2SRichard Henderson     case 0x1000: /* PID */
14029df297a2SRichard Henderson     case 0x1001: /* ZPR */
14039df297a2SRichard Henderson     case 0x1002: /* TLBX */
14049df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14059df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14069df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14079df297a2SRichard Henderson         {
1408a5ea3dd7SRichard Henderson             TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1409a5ea3dd7SRichard Henderson             TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
14109df297a2SRichard Henderson 
1411ad75a51eSRichard Henderson             gen_helper_mmu_write(tcg_env, tmp_ext, tmp_reg, src);
14129df297a2SRichard Henderson         }
14139df297a2SRichard Henderson         break;
14149df297a2SRichard Henderson 
14159df297a2SRichard Henderson     default:
14169df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14179df297a2SRichard Henderson         return true;
14189df297a2SRichard Henderson     }
141943b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
14209df297a2SRichard Henderson     return true;
14219df297a2SRichard Henderson #endif
14229df297a2SRichard Henderson }
14239df297a2SRichard Henderson 
14249df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14259df297a2SRichard Henderson {
14269df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
14279df297a2SRichard Henderson 
14289df297a2SRichard Henderson     if (arg->e) {
14299df297a2SRichard Henderson         switch (arg->rs) {
1430351527b7SEdgar E. Iglesias         case SR_EAR:
1431dbdb77c4SRichard Henderson             {
1432dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
1433ad75a51eSRichard Henderson                 tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14349df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1435dbdb77c4SRichard Henderson             }
14369df297a2SRichard Henderson             return true;
14379df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14389df297a2SRichard Henderson         case 0x1003: /* TLBLO */
14399df297a2SRichard Henderson             /* Handled below. */
1440aa28e6d4SRichard Henderson             break;
14419df297a2SRichard Henderson #endif
14429df297a2SRichard Henderson         case 0x2006 ... 0x2009:
14439df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
14449df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
14459df297a2SRichard Henderson             return true;
14464acb54baSEdgar E. Iglesias         default:
14479df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
14489df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
14499df297a2SRichard Henderson             return true;
14504acb54baSEdgar E. Iglesias         }
14519df297a2SRichard Henderson     }
14529df297a2SRichard Henderson 
14539df297a2SRichard Henderson     switch (arg->rs) {
1454aa28e6d4SRichard Henderson     case SR_PC:
14559df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
14564acb54baSEdgar E. Iglesias         break;
1457aa28e6d4SRichard Henderson     case SR_MSR:
14589df297a2SRichard Henderson         msr_read(dc, dest);
14594acb54baSEdgar E. Iglesias         break;
1460351527b7SEdgar E. Iglesias     case SR_EAR:
1461dbdb77c4SRichard Henderson         {
1462dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1463ad75a51eSRichard Henderson             tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14649df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1465a1b48e3aSEdgar E. Iglesias         }
1466aa28e6d4SRichard Henderson         break;
1467351527b7SEdgar E. Iglesias     case SR_ESR:
1468ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, esr));
1469aa28e6d4SRichard Henderson         break;
1470351527b7SEdgar E. Iglesias     case SR_FSR:
1471ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, fsr));
1472aa28e6d4SRichard Henderson         break;
1473351527b7SEdgar E. Iglesias     case SR_BTR:
1474ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, btr));
1475aa28e6d4SRichard Henderson         break;
14767cdae31dSTong Ho     case SR_EDR:
1477ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, edr));
14784acb54baSEdgar E. Iglesias         break;
14795818dee5SEdgar E. Iglesias     case 0x800:
1480ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, slr));
14815818dee5SEdgar E. Iglesias         break;
14825818dee5SEdgar E. Iglesias     case 0x802:
1483ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, shr));
14845818dee5SEdgar E. Iglesias         break;
14859df297a2SRichard Henderson 
14869df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14879df297a2SRichard Henderson     case 0x1000: /* PID */
14889df297a2SRichard Henderson     case 0x1001: /* ZPR */
14899df297a2SRichard Henderson     case 0x1002: /* TLBX */
14909df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14919df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14929df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14939df297a2SRichard Henderson         {
1494a5ea3dd7SRichard Henderson             TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1495a5ea3dd7SRichard Henderson             TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
14969df297a2SRichard Henderson 
1497ad75a51eSRichard Henderson             gen_helper_mmu_read(dest, tcg_env, tmp_ext, tmp_reg);
14989df297a2SRichard Henderson         }
14999df297a2SRichard Henderson         break;
15009df297a2SRichard Henderson #endif
15019df297a2SRichard Henderson 
1502351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
1503ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env,
1504a4bcfc33SRichard Henderson                        offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1505a4bcfc33SRichard Henderson                        - offsetof(MicroBlazeCPU, env));
15064acb54baSEdgar E. Iglesias         break;
15074acb54baSEdgar E. Iglesias     default:
15089df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
15094acb54baSEdgar E. Iglesias         break;
15104acb54baSEdgar E. Iglesias     }
15119df297a2SRichard Henderson     return true;
15124acb54baSEdgar E. Iglesias }
15134acb54baSEdgar E. Iglesias 
15143fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
15154acb54baSEdgar E. Iglesias {
15163fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
15174acb54baSEdgar E. Iglesias 
15183fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15193fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15203fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15213fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15223fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15234acb54baSEdgar E. Iglesias }
15244acb54baSEdgar E. Iglesias 
15253fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
15264acb54baSEdgar E. Iglesias {
15273fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
15284acb54baSEdgar E. Iglesias 
15293fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15303fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15313fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15323fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15334acb54baSEdgar E. Iglesias }
15344acb54baSEdgar E. Iglesias 
15353fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
15364acb54baSEdgar E. Iglesias {
15373fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
15384acb54baSEdgar E. Iglesias 
15393fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15403fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15413fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15423fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15433fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15444acb54baSEdgar E. Iglesias }
15454acb54baSEdgar E. Iglesias 
15466d76d23eSEdgar E. Iglesias /* Insns connected to FSL or AXI stream attached devices.  */
154752065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
15486d76d23eSEdgar E. Iglesias {
15496d76d23eSEdgar E. Iglesias     TCGv_i32 t_id, t_ctrl;
15506d76d23eSEdgar E. Iglesias 
1551bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
155252065d8fSRichard Henderson         return true;
15536d76d23eSEdgar E. Iglesias     }
15546d76d23eSEdgar E. Iglesias 
1555cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
155652065d8fSRichard Henderson     if (rb) {
155752065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
15586d76d23eSEdgar E. Iglesias     } else {
155952065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
15606d76d23eSEdgar E. Iglesias     }
15616d76d23eSEdgar E. Iglesias 
1562a5ea3dd7SRichard Henderson     t_ctrl = tcg_constant_i32(ctrl);
156352065d8fSRichard Henderson     gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
156452065d8fSRichard Henderson     return true;
156552065d8fSRichard Henderson }
156652065d8fSRichard Henderson 
156752065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
156852065d8fSRichard Henderson {
156952065d8fSRichard Henderson     return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
157052065d8fSRichard Henderson }
157152065d8fSRichard Henderson 
157252065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
157352065d8fSRichard Henderson {
157452065d8fSRichard Henderson     return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
157552065d8fSRichard Henderson }
157652065d8fSRichard Henderson 
157752065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
157852065d8fSRichard Henderson {
157952065d8fSRichard Henderson     TCGv_i32 t_id, t_ctrl;
158052065d8fSRichard Henderson 
158152065d8fSRichard Henderson     if (trap_userspace(dc, true)) {
158252065d8fSRichard Henderson         return true;
158352065d8fSRichard Henderson     }
158452065d8fSRichard Henderson 
158552065d8fSRichard Henderson     t_id = tcg_temp_new_i32();
158652065d8fSRichard Henderson     if (rb) {
158752065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
158852065d8fSRichard Henderson     } else {
158952065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
159052065d8fSRichard Henderson     }
159152065d8fSRichard Henderson 
1592a5ea3dd7SRichard Henderson     t_ctrl = tcg_constant_i32(ctrl);
159352065d8fSRichard Henderson     gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
159452065d8fSRichard Henderson     return true;
159552065d8fSRichard Henderson }
159652065d8fSRichard Henderson 
159752065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
159852065d8fSRichard Henderson {
159952065d8fSRichard Henderson     return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
160052065d8fSRichard Henderson }
160152065d8fSRichard Henderson 
160252065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
160352065d8fSRichard Henderson {
160452065d8fSRichard Henderson     return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
16056d76d23eSEdgar E. Iglesias }
16066d76d23eSEdgar E. Iglesias 
1607372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
16084acb54baSEdgar E. Iglesias {
1609372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1610372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1611372122e3SRichard Henderson     int bound;
16124acb54baSEdgar E. Iglesias 
16134b893631SRichard Henderson     dc->cfg = &cpu->cfg;
1614683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1615d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
161620800179SRichard Henderson     dc->r0 = NULL;
161720800179SRichard Henderson     dc->r0_set = false;
16183b916140SRichard Henderson     dc->mem_index = cpu_mmu_index(cs, false);
1619b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1620b9c58aabSRichard Henderson     dc->jmp_dest = -1;
16214acb54baSEdgar E. Iglesias 
1622372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1623372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1624a47dddd7SAndreas Färber }
16254acb54baSEdgar E. Iglesias 
1626372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
16274acb54baSEdgar E. Iglesias {
1628b933066aSRichard Henderson }
1629b933066aSRichard Henderson 
1630372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1631372122e3SRichard Henderson {
1632683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1633683a247eSRichard Henderson 
1634683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1635372122e3SRichard Henderson }
16364acb54baSEdgar E. Iglesias 
1637372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1638372122e3SRichard Henderson {
1639372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
164044d1432bSRichard Henderson     uint32_t ir;
1641372122e3SRichard Henderson 
1642372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1643372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1644372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1645372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1646959082fcSRichard Henderson     }
16474acb54baSEdgar E. Iglesias 
16486f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
16496f9642d7SRichard Henderson 
16501561fee6SRichard Henderson     ir = translator_ldl(cpu_env(cs), &dc->base, dc->base.pc_next);
165144d1432bSRichard Henderson     if (!decode(dc, ir)) {
1652921afa9dSRichard Henderson         trap_illegal(dc, true);
165344d1432bSRichard Henderson     }
165420800179SRichard Henderson 
165520800179SRichard Henderson     if (dc->r0) {
165620800179SRichard Henderson         dc->r0 = NULL;
165720800179SRichard Henderson         dc->r0_set = false;
165820800179SRichard Henderson     }
165920800179SRichard Henderson 
16606f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
16616f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1662d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1663372122e3SRichard Henderson     }
16646f9642d7SRichard Henderson 
16651e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
16666f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1667d4705ae0SRichard Henderson     dc->base.pc_next += 4;
16684acb54baSEdgar E. Iglesias 
1669b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
16703d35bcc2SRichard Henderson         /*
16713d35bcc2SRichard Henderson          * Finish any return-from branch.
16723d35bcc2SRichard Henderson          */
16733c745866SRichard Henderson         uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16743c745866SRichard Henderson         if (unlikely(rt_ibe != 0)) {
16753c745866SRichard Henderson             dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16763c745866SRichard Henderson             if (rt_ibe & DRTI_FLAG) {
16774acb54baSEdgar E. Iglesias                 do_rti(dc);
16783c745866SRichard Henderson             } else if (rt_ibe & DRTB_FLAG) {
16794acb54baSEdgar E. Iglesias                 do_rtb(dc);
16803c745866SRichard Henderson             } else {
16814acb54baSEdgar E. Iglesias                 do_rte(dc);
1682372122e3SRichard Henderson             }
16833c745866SRichard Henderson         }
16843d35bcc2SRichard Henderson 
16853d35bcc2SRichard Henderson         /* Complete the branch, ending the TB. */
16863d35bcc2SRichard Henderson         switch (dc->base.is_jmp) {
16873d35bcc2SRichard Henderson         case DISAS_NORETURN:
16883d35bcc2SRichard Henderson             /*
16893d35bcc2SRichard Henderson              * E.g. illegal insn in a delay slot.  We've already exited
16903d35bcc2SRichard Henderson              * and will handle D_FLAG in mb_cpu_do_interrupt.
16913d35bcc2SRichard Henderson              */
16923d35bcc2SRichard Henderson             break;
16933d35bcc2SRichard Henderson         case DISAS_NEXT:
16943c745866SRichard Henderson             /*
16953c745866SRichard Henderson              * Normal insn a delay slot.
16963c745866SRichard Henderson              * However, the return-from-exception type insns should
16973c745866SRichard Henderson              * return to the main loop, as they have adjusted MSR.
16983c745866SRichard Henderson              */
16993c745866SRichard Henderson             dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
17003d35bcc2SRichard Henderson             break;
17013d35bcc2SRichard Henderson         case DISAS_EXIT_NEXT:
17023d35bcc2SRichard Henderson             /*
17033d35bcc2SRichard Henderson              * E.g. mts insn in a delay slot.  Continue with btarget,
17043d35bcc2SRichard Henderson              * but still return to the main loop.
17053d35bcc2SRichard Henderson              */
17063d35bcc2SRichard Henderson             dc->base.is_jmp = DISAS_EXIT_JUMP;
17073d35bcc2SRichard Henderson             break;
17083d35bcc2SRichard Henderson         default:
17093d35bcc2SRichard Henderson             g_assert_not_reached();
17103d35bcc2SRichard Henderson         }
1711372122e3SRichard Henderson     }
1712372122e3SRichard Henderson }
1713372122e3SRichard Henderson 
1714372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1715372122e3SRichard Henderson {
1716372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1717372122e3SRichard Henderson 
1718372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1719372122e3SRichard Henderson         /* We have already exited the TB. */
1720372122e3SRichard Henderson         return;
1721372122e3SRichard Henderson     }
1722372122e3SRichard Henderson 
1723372122e3SRichard Henderson     t_sync_flags(dc);
1724372122e3SRichard Henderson 
1725372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1726372122e3SRichard Henderson     case DISAS_TOO_MANY:
1727372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1728372122e3SRichard Henderson         return;
1729372122e3SRichard Henderson 
173017e77796SRichard Henderson     case DISAS_EXIT:
1731f6278ca9SRichard Henderson         break;
1732f6278ca9SRichard Henderson     case DISAS_EXIT_NEXT:
1733f6278ca9SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1734f6278ca9SRichard Henderson         break;
1735f6278ca9SRichard Henderson     case DISAS_EXIT_JUMP:
1736f6278ca9SRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1737f6278ca9SRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1738f6278ca9SRichard Henderson         break;
1739372122e3SRichard Henderson 
1740372122e3SRichard Henderson     case DISAS_JUMP:
1741fbafb3a4SRichard Henderson         if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
1742b9c58aabSRichard Henderson             /* Direct jump. */
1743b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1744b9c58aabSRichard Henderson 
1745b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1746b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1747b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1748b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1749b9c58aabSRichard Henderson 
1750b9c58aabSRichard Henderson                 /*
1751b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1752b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1753b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1754b9c58aabSRichard Henderson                  */
1755b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1756b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1757b9c58aabSRichard Henderson 
1758b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1759b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1760b9c58aabSRichard Henderson                 gen_set_label(taken);
1761b9c58aabSRichard Henderson             }
1762b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1763b9c58aabSRichard Henderson             return;
1764b9c58aabSRichard Henderson         }
1765b9c58aabSRichard Henderson 
1766fbafb3a4SRichard Henderson         /* Indirect jump (or direct jump w/ goto_tb disabled) */
1767b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1768b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
17694059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
1770372122e3SRichard Henderson         return;
1771372122e3SRichard Henderson 
1772a2b80dbdSRichard Henderson     default:
1773a2b80dbdSRichard Henderson         g_assert_not_reached();
17744acb54baSEdgar E. Iglesias     }
1775f6278ca9SRichard Henderson 
1776f6278ca9SRichard Henderson     /* Finish DISAS_EXIT_* */
1777f6278ca9SRichard Henderson     if (unlikely(cs->singlestep_enabled)) {
1778f6278ca9SRichard Henderson         gen_raise_exception(dc, EXCP_DEBUG);
1779f6278ca9SRichard Henderson     } else {
1780f6278ca9SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1781f6278ca9SRichard Henderson     }
17824acb54baSEdgar E. Iglesias }
17830a7df5daSRichard Henderson 
1784372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1785372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1786372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1787372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1788372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1789372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1790372122e3SRichard Henderson };
1791372122e3SRichard Henderson 
1792e4a8e093SRichard Henderson void mb_translate_code(CPUState *cpu, TranslationBlock *tb,
1793e4a8e093SRichard Henderson                        int *max_insns, vaddr pc, void *host_pc)
1794372122e3SRichard Henderson {
1795372122e3SRichard Henderson     DisasContext dc;
1796306c8721SRichard Henderson     translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base);
17974acb54baSEdgar E. Iglesias }
17984acb54baSEdgar E. Iglesias 
179990c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
18004acb54baSEdgar E. Iglesias {
1801da953643SPhilippe Mathieu-Daudé     CPUMBState *env = cpu_env(cs);
18020c3da918SRichard Henderson     uint32_t iflags;
18034acb54baSEdgar E. Iglesias     int i;
18044acb54baSEdgar E. Iglesias 
18050c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18060c3da918SRichard Henderson                  env->pc, env->msr,
18072e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18082e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18092e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18102e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18110c3da918SRichard Henderson 
18120c3da918SRichard Henderson     iflags = env->iflags;
18130c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18140c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18150c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18162ead1b18SJoe Komlodi     }
18170c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18180c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18190c3da918SRichard Henderson     }
18200c3da918SRichard Henderson     if (iflags & D_FLAG) {
1821b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18220c3da918SRichard Henderson     }
18230c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18240c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18250c3da918SRichard Henderson     }
18260c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18270c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18280c3da918SRichard Henderson     }
18290c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18300c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18310c3da918SRichard Henderson     }
18320c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18330c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18342ead1b18SJoe Komlodi     }
183517c52a43SEdgar E. Iglesias 
18360c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
183719f27b6cSRichard Henderson                  "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
18380c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18390c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18400c3da918SRichard Henderson 
18410c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18420c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18430c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18440c3da918SRichard Henderson     }
18450c3da918SRichard Henderson     qemu_fprintf(f, "\n");
18464acb54baSEdgar E. Iglesias }
18474acb54baSEdgar E. Iglesias 
1848cd0c24f9SAndreas Färber void mb_tcg_init(void)
1849cd0c24f9SAndreas Färber {
1850480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1851480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
18524acb54baSEdgar E. Iglesias 
1853480d29a8SRichard Henderson     static const struct {
1854480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1855480d29a8SRichard Henderson     } i32s[] = {
1856e47c2231SRichard Henderson         /*
1857e47c2231SRichard Henderson          * Note that r0 is handled specially in reg_for_read
1858e47c2231SRichard Henderson          * and reg_for_write.  Nothing should touch cpu_R[0].
1859e47c2231SRichard Henderson          * Leave that element NULL, which will assert quickly
1860e47c2231SRichard Henderson          * inside the tcg generator functions.
1861e47c2231SRichard Henderson          */
1862e47c2231SRichard Henderson                R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1863480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1864480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1865480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1866480d29a8SRichard Henderson 
1867480d29a8SRichard Henderson         SP(pc),
1868480d29a8SRichard Henderson         SP(msr),
18691074c0fbSRichard Henderson         SP(msr_c),
1870480d29a8SRichard Henderson         SP(imm),
1871480d29a8SRichard Henderson         SP(iflags),
1872b9c58aabSRichard Henderson         SP(bvalue),
1873480d29a8SRichard Henderson         SP(btarget),
1874480d29a8SRichard Henderson         SP(res_val),
1875480d29a8SRichard Henderson     };
1876480d29a8SRichard Henderson 
1877480d29a8SRichard Henderson #undef R
1878480d29a8SRichard Henderson #undef SP
1879480d29a8SRichard Henderson 
1880480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1881480d29a8SRichard Henderson         *i32s[i].var =
1882ad75a51eSRichard Henderson           tcg_global_mem_new_i32(tcg_env, i32s[i].ofs, i32s[i].name);
18834acb54baSEdgar E. Iglesias     }
188476e8187dSRichard Henderson 
1885480d29a8SRichard Henderson     cpu_res_addr =
1886ad75a51eSRichard Henderson         tcg_global_mem_new(tcg_env, offsetof(CPUMBState, res_addr), "res_addr");
18874acb54baSEdgar E. Iglesias }
1888