xref: /qemu/target/microblaze/translate.c (revision 683a247ed7a4993464e995106c20acbe237bdbfc)
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
104acb54baSEdgar E. Iglesias  * version 2 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"
2376cad711SPaolo Bonzini #include "disas/disas.h"
2463c91552SPaolo Bonzini #include "exec/exec-all.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
262ef6175aSRichard Henderson #include "exec/helper-proto.h"
274acb54baSEdgar E. Iglesias #include "microblaze-decode.h"
28f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
292ef6175aSRichard Henderson #include "exec/helper-gen.h"
3077fc6f5eSLluís Vilanova #include "exec/translator.h"
3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
324acb54baSEdgar E. Iglesias 
33a7e30d84SLluís Vilanova #include "trace-tcg.h"
34508127e2SPaolo Bonzini #include "exec/log.h"
35a7e30d84SLluís Vilanova 
364acb54baSEdgar E. Iglesias #define EXTRACT_FIELD(src, start, end) \
374acb54baSEdgar E. Iglesias             (((src) >> start) & ((1 << (end - start + 1)) - 1))
384acb54baSEdgar E. Iglesias 
3977fc6f5eSLluís Vilanova /* is_jmp field values */
4077fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
4177fc6f5eSLluís Vilanova #define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
4277fc6f5eSLluís Vilanova 
43cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
440f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
453e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
461074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
479b158558SRichard Henderson static TCGv_i32 cpu_imm;
489b158558SRichard Henderson static TCGv_i32 cpu_btaken;
490f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
509b158558SRichard Henderson static TCGv_i32 cpu_iflags;
519b158558SRichard Henderson static TCGv cpu_res_addr;
529b158558SRichard Henderson static TCGv_i32 cpu_res_val;
534acb54baSEdgar E. Iglesias 
54022c62cbSPaolo Bonzini #include "exec/gen-icount.h"
554acb54baSEdgar E. Iglesias 
564acb54baSEdgar E. Iglesias /* This is the state at translation time.  */
574acb54baSEdgar E. Iglesias typedef struct DisasContext {
58d4705ae0SRichard Henderson     DisasContextBase base;
590063ebd6SAndreas Färber     MicroBlazeCPU *cpu;
604acb54baSEdgar E. Iglesias 
61*683a247eSRichard Henderson     /* TCG op of the current insn_start.  */
62*683a247eSRichard Henderson     TCGOp *insn_start;
63*683a247eSRichard Henderson 
6420800179SRichard Henderson     TCGv_i32 r0;
6520800179SRichard Henderson     bool r0_set;
6620800179SRichard Henderson 
674acb54baSEdgar E. Iglesias     /* Decoder.  */
684acb54baSEdgar E. Iglesias     int type_b;
694acb54baSEdgar E. Iglesias     uint32_t ir;
70d7ecb757SRichard Henderson     uint32_t ext_imm;
714acb54baSEdgar E. Iglesias     uint8_t opcode;
724acb54baSEdgar E. Iglesias     uint8_t rd, ra, rb;
734acb54baSEdgar E. Iglesias     uint16_t imm;
744acb54baSEdgar E. Iglesias 
754acb54baSEdgar E. Iglesias     unsigned int cpustate_changed;
764acb54baSEdgar E. Iglesias     unsigned int delayed_branch;
77*683a247eSRichard Henderson     unsigned int tb_flags;
784acb54baSEdgar E. Iglesias     unsigned int clear_imm;
79287b1defSRichard Henderson     int mem_index;
804acb54baSEdgar E. Iglesias 
814acb54baSEdgar E. Iglesias #define JMP_NOJMP     0
824acb54baSEdgar E. Iglesias #define JMP_DIRECT    1
83844bab60SEdgar E. Iglesias #define JMP_DIRECT_CC 2
84844bab60SEdgar E. Iglesias #define JMP_INDIRECT  3
854acb54baSEdgar E. Iglesias     unsigned int jmp;
864acb54baSEdgar E. Iglesias     uint32_t jmp_pc;
874acb54baSEdgar E. Iglesias 
884acb54baSEdgar E. Iglesias     int abort_at_next_insn;
894acb54baSEdgar E. Iglesias } DisasContext;
904acb54baSEdgar E. Iglesias 
9120800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
9220800179SRichard Henderson {
9320800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
9420800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
9520800179SRichard Henderson     }
9620800179SRichard Henderson     return x;
9720800179SRichard Henderson }
9820800179SRichard Henderson 
9944d1432bSRichard Henderson /* Include the auto-generated decoder.  */
10044d1432bSRichard Henderson #include "decode-insns.c.inc"
10144d1432bSRichard Henderson 
102*683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
1034acb54baSEdgar E. Iglesias {
1044abf79a4SDong Xu Wang     /* Synch the tb dependent flags between translator and runtime.  */
105*683a247eSRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) {
106*683a247eSRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK);
1074acb54baSEdgar E. Iglesias     }
1084acb54baSEdgar E. Iglesias }
1094acb54baSEdgar E. Iglesias 
110d8e59c4aSRichard Henderson static inline void sync_jmpstate(DisasContext *dc)
111d8e59c4aSRichard Henderson {
112d8e59c4aSRichard Henderson     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
113d8e59c4aSRichard Henderson         if (dc->jmp == JMP_DIRECT) {
114d8e59c4aSRichard Henderson             tcg_gen_movi_i32(cpu_btaken, 1);
115d8e59c4aSRichard Henderson         }
116d8e59c4aSRichard Henderson         dc->jmp = JMP_INDIRECT;
117d8e59c4aSRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
118d8e59c4aSRichard Henderson     }
119d8e59c4aSRichard Henderson }
120d8e59c4aSRichard Henderson 
12141ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
1224acb54baSEdgar E. Iglesias {
1234acb54baSEdgar E. Iglesias     TCGv_i32 tmp = tcg_const_i32(index);
1244acb54baSEdgar E. Iglesias 
12564254ebaSBlue Swirl     gen_helper_raise_exception(cpu_env, tmp);
1264acb54baSEdgar E. Iglesias     tcg_temp_free_i32(tmp);
127d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
1284acb54baSEdgar E. Iglesias }
1294acb54baSEdgar E. Iglesias 
13041ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
13141ba37c4SRichard Henderson {
13241ba37c4SRichard Henderson     t_sync_flags(dc);
133d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
13441ba37c4SRichard Henderson     gen_raise_exception(dc, index);
13541ba37c4SRichard Henderson }
13641ba37c4SRichard Henderson 
13741ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
13841ba37c4SRichard Henderson {
13941ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
14041ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
14141ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
14241ba37c4SRichard Henderson 
14341ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
14441ba37c4SRichard Henderson }
14541ba37c4SRichard Henderson 
14690aa39a1SSergey Fedorov static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
14790aa39a1SSergey Fedorov {
14890aa39a1SSergey Fedorov #ifndef CONFIG_USER_ONLY
149d4705ae0SRichard Henderson     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
15090aa39a1SSergey Fedorov #else
15190aa39a1SSergey Fedorov     return true;
15290aa39a1SSergey Fedorov #endif
15390aa39a1SSergey Fedorov }
15490aa39a1SSergey Fedorov 
1554acb54baSEdgar E. Iglesias static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
1564acb54baSEdgar E. Iglesias {
157d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1580b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1590b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1600b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1610b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
1620b46fa08SRichard Henderson     } else if (use_goto_tb(dc, dest)) {
1634acb54baSEdgar E. Iglesias         tcg_gen_goto_tb(n);
1640f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
165d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
1664acb54baSEdgar E. Iglesias     } else {
1670f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
16807ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1694acb54baSEdgar E. Iglesias     }
170d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
1714acb54baSEdgar E. Iglesias }
1724acb54baSEdgar E. Iglesias 
173bdfc1e88SEdgar E. Iglesias /*
1749ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1759ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1769ba8cd45SEdgar E. Iglesias  */
1779ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1789ba8cd45SEdgar E. Iglesias {
1792c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1805143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
18141ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1829ba8cd45SEdgar E. Iglesias     }
1839ba8cd45SEdgar E. Iglesias     return cond;
1849ba8cd45SEdgar E. Iglesias }
1859ba8cd45SEdgar E. Iglesias 
1869ba8cd45SEdgar E. Iglesias /*
187bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
188bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
189bdfc1e88SEdgar E. Iglesias  */
190bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
191bdfc1e88SEdgar E. Iglesias {
192287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
193bdfc1e88SEdgar E. Iglesias 
1942c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
19541ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
196bdfc1e88SEdgar E. Iglesias     }
197bdfc1e88SEdgar E. Iglesias     return cond_user;
198bdfc1e88SEdgar E. Iglesias }
199bdfc1e88SEdgar E. Iglesias 
200d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc)
20161204ce8SEdgar E. Iglesias {
202d7ecb757SRichard Henderson     tcg_debug_assert(dc->type_b);
20320800179SRichard Henderson     return typeb_imm(dc, (int16_t)dc->imm);
20461204ce8SEdgar E. Iglesias }
20561204ce8SEdgar E. Iglesias 
206cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
2074acb54baSEdgar E. Iglesias {
2084acb54baSEdgar E. Iglesias     if (dc->type_b) {
209d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc));
2109b158558SRichard Henderson         return &cpu_imm;
211d7ecb757SRichard Henderson     }
2124acb54baSEdgar E. Iglesias     return &cpu_R[dc->rb];
2134acb54baSEdgar E. Iglesias }
2144acb54baSEdgar E. Iglesias 
21520800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
2164acb54baSEdgar E. Iglesias {
21720800179SRichard Henderson     if (likely(reg != 0)) {
21820800179SRichard Henderson         return cpu_R[reg];
2194acb54baSEdgar E. Iglesias     }
22020800179SRichard Henderson     if (!dc->r0_set) {
22120800179SRichard Henderson         if (dc->r0 == NULL) {
22220800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
2234acb54baSEdgar E. Iglesias         }
22420800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
22520800179SRichard Henderson         dc->r0_set = true;
22620800179SRichard Henderson     }
22720800179SRichard Henderson     return dc->r0;
22840cbf5b7SEdgar E. Iglesias }
22940cbf5b7SEdgar E. Iglesias 
23020800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
23120800179SRichard Henderson {
23220800179SRichard Henderson     if (likely(reg != 0)) {
23320800179SRichard Henderson         return cpu_R[reg];
23420800179SRichard Henderson     }
23520800179SRichard Henderson     if (dc->r0 == NULL) {
23620800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
23720800179SRichard Henderson     }
23820800179SRichard Henderson     return dc->r0;
23940cbf5b7SEdgar E. Iglesias }
24040cbf5b7SEdgar E. Iglesias 
24120800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
24220800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
24320800179SRichard Henderson {
24420800179SRichard Henderson     TCGv_i32 rd, ra, rb;
24520800179SRichard Henderson 
24620800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24720800179SRichard Henderson         return true;
24840cbf5b7SEdgar E. Iglesias     }
24920800179SRichard Henderson 
25020800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
25120800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
25220800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
25320800179SRichard Henderson     fn(rd, ra, rb);
25420800179SRichard Henderson     return true;
25520800179SRichard Henderson }
25620800179SRichard Henderson 
25739cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
25839cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
25939cf3864SRichard Henderson {
26039cf3864SRichard Henderson     TCGv_i32 rd, ra;
26139cf3864SRichard Henderson 
26239cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
26339cf3864SRichard Henderson         return true;
26439cf3864SRichard Henderson     }
26539cf3864SRichard Henderson 
26639cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26739cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
26839cf3864SRichard Henderson     fn(rd, ra);
26939cf3864SRichard Henderson     return true;
27039cf3864SRichard Henderson }
27139cf3864SRichard Henderson 
27220800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
27320800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
27420800179SRichard Henderson {
27520800179SRichard Henderson     TCGv_i32 rd, ra;
27620800179SRichard Henderson 
27720800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
27820800179SRichard Henderson         return true;
27920800179SRichard Henderson     }
28020800179SRichard Henderson 
28120800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
28220800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
28320800179SRichard Henderson     fni(rd, ra, arg->imm);
28420800179SRichard Henderson     return true;
28520800179SRichard Henderson }
28620800179SRichard Henderson 
28720800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
28820800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
28920800179SRichard Henderson {
29020800179SRichard Henderson     TCGv_i32 rd, ra, imm;
29120800179SRichard Henderson 
29220800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
29320800179SRichard Henderson         return true;
29420800179SRichard Henderson     }
29520800179SRichard Henderson 
29620800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
29720800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
29820800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
29920800179SRichard Henderson 
30020800179SRichard Henderson     fn(rd, ra, imm);
30120800179SRichard Henderson 
30220800179SRichard Henderson     tcg_temp_free_i32(imm);
30320800179SRichard Henderson     return true;
30420800179SRichard Henderson }
30520800179SRichard Henderson 
30620800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
30720800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
30820800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
30920800179SRichard Henderson 
310607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
311607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
312607f5767SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); }
313607f5767SRichard Henderson 
31439cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
31539cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
31639cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
31739cf3864SRichard Henderson 
31839cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
31939cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
32039cf3864SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); }
32139cf3864SRichard Henderson 
32220800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
32320800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
32420800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
32520800179SRichard Henderson 
32697955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
32797955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
32897955cebSRichard Henderson     { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); }
32997955cebSRichard Henderson 
33020800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
33120800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
33220800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
33320800179SRichard Henderson 
334d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
335d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
336d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
337d5aead3dSRichard Henderson 
338d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
339d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
340d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
341d5aead3dSRichard Henderson 
34220800179SRichard Henderson /* No input carry, but output carry. */
34320800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
34420800179SRichard Henderson {
34520800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
34620800179SRichard Henderson 
34720800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
34820800179SRichard Henderson 
34920800179SRichard Henderson     tcg_temp_free_i32(zero);
35020800179SRichard Henderson }
35120800179SRichard Henderson 
35220800179SRichard Henderson /* Input and output carry. */
35320800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
35420800179SRichard Henderson {
35520800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
35620800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
35720800179SRichard Henderson 
35820800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
35920800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
36020800179SRichard Henderson 
36120800179SRichard Henderson     tcg_temp_free_i32(tmp);
36220800179SRichard Henderson     tcg_temp_free_i32(zero);
36320800179SRichard Henderson }
36420800179SRichard Henderson 
36520800179SRichard Henderson /* Input carry, but no output carry. */
36620800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
36720800179SRichard Henderson {
36820800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
36920800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
37020800179SRichard Henderson }
37120800179SRichard Henderson 
37220800179SRichard Henderson DO_TYPEA(add, true, gen_add)
37320800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
37420800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
37520800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
37620800179SRichard Henderson 
37720800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
37820800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
37920800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
38020800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
38120800179SRichard Henderson 
382cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
383cb0a0a4cSRichard Henderson {
384cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
385cb0a0a4cSRichard Henderson }
386cb0a0a4cSRichard Henderson 
387cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
388cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
389cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
390cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
391cb0a0a4cSRichard Henderson 
392081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
393081d8e02SRichard Henderson {
394081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
395081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
396081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
397081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
398081d8e02SRichard Henderson }
399081d8e02SRichard Henderson 
400081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
401081d8e02SRichard Henderson {
402081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
403081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
404081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
405081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
406081d8e02SRichard Henderson }
407081d8e02SRichard Henderson 
408081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
409081d8e02SRichard Henderson {
410081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
411081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
412081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
413081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
414081d8e02SRichard Henderson }
415081d8e02SRichard Henderson 
416081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
417081d8e02SRichard Henderson {
418081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
419081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
420081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
421081d8e02SRichard Henderson 
422081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
423081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
424081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
425081d8e02SRichard Henderson                       imm_w, imm_s);
426081d8e02SRichard Henderson     } else {
427081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
428081d8e02SRichard Henderson     }
429081d8e02SRichard Henderson }
430081d8e02SRichard Henderson 
431081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
432081d8e02SRichard Henderson {
433081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
434081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
435081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
436081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
437081d8e02SRichard Henderson 
438081d8e02SRichard Henderson     if (imm_w < imm_s) {
439081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
440081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
441081d8e02SRichard Henderson                       imm_w, imm_s);
442081d8e02SRichard Henderson     } else {
443081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
444081d8e02SRichard Henderson     }
445081d8e02SRichard Henderson }
446081d8e02SRichard Henderson 
447081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
448081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
449081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
450081d8e02SRichard Henderson 
451081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
452081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
453081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
454081d8e02SRichard Henderson 
455081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
456081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
457081d8e02SRichard Henderson 
45839cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
45939cf3864SRichard Henderson {
46039cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
46139cf3864SRichard Henderson }
46239cf3864SRichard Henderson 
46339cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
46439cf3864SRichard Henderson 
46558b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
46658b48b63SRichard Henderson {
46758b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
46858b48b63SRichard Henderson 
46958b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
47058b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
47158b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
47258b48b63SRichard Henderson     tcg_temp_free_i32(lt);
47358b48b63SRichard Henderson }
47458b48b63SRichard Henderson 
47558b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
47658b48b63SRichard Henderson {
47758b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
47858b48b63SRichard Henderson 
47958b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
48058b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
48158b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
48258b48b63SRichard Henderson     tcg_temp_free_i32(lt);
48358b48b63SRichard Henderson }
48458b48b63SRichard Henderson 
48558b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
48658b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
487a2b0b90eSRichard Henderson 
488d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
489d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
490d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
491d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
492d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
493d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
494d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
495d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
496d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
497d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
498d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
499d5aead3dSRichard Henderson 
500d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
501d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
502d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
503d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
504d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
505d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
506d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
507d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
508d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
509d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
510d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
511d5aead3dSRichard Henderson 
512d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
513d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
514d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
515d5aead3dSRichard Henderson 
516d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
517d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
518d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
519d5aead3dSRichard Henderson 
520d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
521b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
522b1354342SRichard Henderson {
523b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
524b1354342SRichard Henderson }
525b1354342SRichard Henderson 
526b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
527b1354342SRichard Henderson {
528b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
529b1354342SRichard Henderson }
530b1354342SRichard Henderson 
531b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
532b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
533b1354342SRichard Henderson 
534e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
535e64b2e5cSRichard Henderson {
536e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
537e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
538e64b2e5cSRichard Henderson     dc->tb_flags |= IMM_FLAG;
539e64b2e5cSRichard Henderson     dc->clear_imm = 0;
540e64b2e5cSRichard Henderson     return true;
541e64b2e5cSRichard Henderson }
542e64b2e5cSRichard Henderson 
54397955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
54497955cebSRichard Henderson {
54597955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
54697955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
54797955cebSRichard Henderson     tcg_temp_free_i32(tmp);
54897955cebSRichard Henderson }
54997955cebSRichard Henderson 
55097955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
55197955cebSRichard Henderson {
55297955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
55397955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
55497955cebSRichard Henderson     tcg_temp_free_i32(tmp);
55597955cebSRichard Henderson }
55697955cebSRichard Henderson 
55797955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
55897955cebSRichard Henderson {
55997955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
56097955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
56197955cebSRichard Henderson     tcg_temp_free_i32(tmp);
56297955cebSRichard Henderson }
56397955cebSRichard Henderson 
56497955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
56597955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
56697955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
56797955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
56897955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
56997955cebSRichard Henderson 
570cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
571cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
572cb0a0a4cSRichard Henderson 
573607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
574607f5767SRichard Henderson {
575607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
576607f5767SRichard Henderson }
577607f5767SRichard Henderson 
578607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
579607f5767SRichard Henderson {
580607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
581607f5767SRichard Henderson }
582607f5767SRichard Henderson 
583607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
584607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
585607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
586607f5767SRichard Henderson 
587a2b0b90eSRichard Henderson /* No input carry, but output carry. */
588a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
589a2b0b90eSRichard Henderson {
590a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
591a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
592a2b0b90eSRichard Henderson }
593a2b0b90eSRichard Henderson 
594a2b0b90eSRichard Henderson /* Input and output carry. */
595a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
596a2b0b90eSRichard Henderson {
597a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
598a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
599a2b0b90eSRichard Henderson 
600a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
601a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
602a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
603a2b0b90eSRichard Henderson 
604a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
605a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
606a2b0b90eSRichard Henderson }
607a2b0b90eSRichard Henderson 
608a2b0b90eSRichard Henderson /* No input or output carry. */
609a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
610a2b0b90eSRichard Henderson {
611a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
612a2b0b90eSRichard Henderson }
613a2b0b90eSRichard Henderson 
614a2b0b90eSRichard Henderson /* Input carry, no output carry. */
615a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
616a2b0b90eSRichard Henderson {
617a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
618a2b0b90eSRichard Henderson 
619a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
620a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
621a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
622a2b0b90eSRichard Henderson 
623a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
624a2b0b90eSRichard Henderson }
625a2b0b90eSRichard Henderson 
626a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
627a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
628a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
629a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
630a2b0b90eSRichard Henderson 
631a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
632a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
633a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
634a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
635a2b0b90eSRichard Henderson 
63639cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
63739cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
63839cf3864SRichard Henderson 
63939cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
64039cf3864SRichard Henderson {
64139cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
64239cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
64339cf3864SRichard Henderson }
64439cf3864SRichard Henderson 
64539cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
64639cf3864SRichard Henderson {
64739cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
64839cf3864SRichard Henderson 
64939cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
65039cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
65139cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
65239cf3864SRichard Henderson 
65339cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
65439cf3864SRichard Henderson }
65539cf3864SRichard Henderson 
65639cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
65739cf3864SRichard Henderson {
65839cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
65939cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
66039cf3864SRichard Henderson }
66139cf3864SRichard Henderson 
66239cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
66339cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
66439cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
66539cf3864SRichard Henderson 
66639cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
66739cf3864SRichard Henderson {
66839cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
66939cf3864SRichard Henderson }
67039cf3864SRichard Henderson 
67139cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
67239cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
67339cf3864SRichard Henderson 
67439cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
67539cf3864SRichard Henderson {
67639cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
67739cf3864SRichard Henderson     trap_userspace(dc, true);
67839cf3864SRichard Henderson     return true;
67939cf3864SRichard Henderson }
68039cf3864SRichard Henderson 
681cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
682cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
683cb0a0a4cSRichard Henderson 
684d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
685d8e59c4aSRichard Henderson {
686d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
687d8e59c4aSRichard Henderson 
688d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
689d8e59c4aSRichard Henderson     if (ra && rb) {
690d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
691d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
692d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
693d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
694d8e59c4aSRichard Henderson     } else if (ra) {
695d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
696d8e59c4aSRichard Henderson     } else if (rb) {
697d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
698d8e59c4aSRichard Henderson     } else {
699d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
700d8e59c4aSRichard Henderson     }
701d8e59c4aSRichard Henderson 
702d8e59c4aSRichard Henderson     if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) {
703d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
704d8e59c4aSRichard Henderson     }
705d8e59c4aSRichard Henderson     return ret;
706d8e59c4aSRichard Henderson }
707d8e59c4aSRichard Henderson 
708d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
709d8e59c4aSRichard Henderson {
710d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
711d8e59c4aSRichard Henderson 
712d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
713d8e59c4aSRichard Henderson     if (ra) {
714d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
715d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
716d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
717d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
718d8e59c4aSRichard Henderson     } else {
719d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
720d8e59c4aSRichard Henderson     }
721d8e59c4aSRichard Henderson 
722d8e59c4aSRichard Henderson     if (ra == 1 && dc->cpu->cfg.stackprot) {
723d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
724d8e59c4aSRichard Henderson     }
725d8e59c4aSRichard Henderson     return ret;
726d8e59c4aSRichard Henderson }
727d8e59c4aSRichard Henderson 
728d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
729d8e59c4aSRichard Henderson {
730d8e59c4aSRichard Henderson     int addr_size = dc->cpu->cfg.addr_size;
731d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
732d8e59c4aSRichard Henderson 
733d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
734d8e59c4aSRichard Henderson         if (rb) {
735d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
736d8e59c4aSRichard Henderson         } else {
737d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
738d8e59c4aSRichard Henderson         }
739d8e59c4aSRichard Henderson     } else {
740d8e59c4aSRichard Henderson         if (rb) {
741d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
742d8e59c4aSRichard Henderson         } else {
743d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
744d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
745d8e59c4aSRichard Henderson         }
746d8e59c4aSRichard Henderson         if (addr_size < 64) {
747d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
748d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
749d8e59c4aSRichard Henderson         }
750d8e59c4aSRichard Henderson     }
751d8e59c4aSRichard Henderson     return ret;
752d8e59c4aSRichard Henderson }
753d8e59c4aSRichard Henderson 
754d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
755d8e59c4aSRichard Henderson                     int mem_index, bool rev)
756d8e59c4aSRichard Henderson {
757d8e59c4aSRichard Henderson     TCGv_i32 v;
758d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
759d8e59c4aSRichard Henderson 
760d8e59c4aSRichard Henderson     /*
761d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
762d8e59c4aSRichard Henderson      *
763d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
764d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
765d8e59c4aSRichard Henderson      */
766d8e59c4aSRichard Henderson     if (rev) {
767d8e59c4aSRichard Henderson         if (size > MO_8) {
768d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
769d8e59c4aSRichard Henderson         }
770d8e59c4aSRichard Henderson         if (size < MO_32) {
771d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
772d8e59c4aSRichard Henderson         }
773d8e59c4aSRichard Henderson     }
774d8e59c4aSRichard Henderson 
775d8e59c4aSRichard Henderson     sync_jmpstate(dc);
776d8e59c4aSRichard Henderson 
777d8e59c4aSRichard Henderson     /*
778d8e59c4aSRichard Henderson      * Microblaze gives MMU faults priority over faults due to
779d8e59c4aSRichard Henderson      * unaligned addresses. That's why we speculatively do the load
780d8e59c4aSRichard Henderson      * into v. If the load succeeds, we verify alignment of the
781d8e59c4aSRichard Henderson      * address and if that succeeds we write into the destination reg.
782d8e59c4aSRichard Henderson      */
783d8e59c4aSRichard Henderson     v = tcg_temp_new_i32();
784d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(v, addr, mem_index, mop);
785d8e59c4aSRichard Henderson 
786d8e59c4aSRichard Henderson     /* TODO: Convert to CPUClass::do_unaligned_access.  */
787d8e59c4aSRichard Henderson     if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) {
788d8e59c4aSRichard Henderson         TCGv_i32 t0 = tcg_const_i32(0);
789d8e59c4aSRichard Henderson         TCGv_i32 treg = tcg_const_i32(rd);
790d8e59c4aSRichard Henderson         TCGv_i32 tsize = tcg_const_i32((1 << size) - 1);
791d8e59c4aSRichard Henderson 
792d8e59c4aSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
793d8e59c4aSRichard Henderson         gen_helper_memalign(cpu_env, addr, treg, t0, tsize);
794d8e59c4aSRichard Henderson 
795d8e59c4aSRichard Henderson         tcg_temp_free_i32(t0);
796d8e59c4aSRichard Henderson         tcg_temp_free_i32(treg);
797d8e59c4aSRichard Henderson         tcg_temp_free_i32(tsize);
798d8e59c4aSRichard Henderson     }
799d8e59c4aSRichard Henderson 
800d8e59c4aSRichard Henderson     if (rd) {
801d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[rd], v);
802d8e59c4aSRichard Henderson     }
803d8e59c4aSRichard Henderson 
804d8e59c4aSRichard Henderson     tcg_temp_free_i32(v);
805d8e59c4aSRichard Henderson     tcg_temp_free(addr);
806d8e59c4aSRichard Henderson     return true;
807d8e59c4aSRichard Henderson }
808d8e59c4aSRichard Henderson 
809d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
810d8e59c4aSRichard Henderson {
811d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
812d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
813d8e59c4aSRichard Henderson }
814d8e59c4aSRichard Henderson 
815d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
816d8e59c4aSRichard Henderson {
817d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
818d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
819d8e59c4aSRichard Henderson }
820d8e59c4aSRichard Henderson 
821d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
822d8e59c4aSRichard Henderson {
823d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
824d8e59c4aSRichard Henderson         return true;
825d8e59c4aSRichard Henderson     }
826d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
827d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
828d8e59c4aSRichard Henderson }
829d8e59c4aSRichard Henderson 
830d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
831d8e59c4aSRichard Henderson {
832d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
833d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
834d8e59c4aSRichard Henderson }
835d8e59c4aSRichard Henderson 
836d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
837d8e59c4aSRichard Henderson {
838d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
839d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
840d8e59c4aSRichard Henderson }
841d8e59c4aSRichard Henderson 
842d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
843d8e59c4aSRichard Henderson {
844d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
845d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
846d8e59c4aSRichard Henderson }
847d8e59c4aSRichard Henderson 
848d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
849d8e59c4aSRichard Henderson {
850d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
851d8e59c4aSRichard Henderson         return true;
852d8e59c4aSRichard Henderson     }
853d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
854d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
855d8e59c4aSRichard Henderson }
856d8e59c4aSRichard Henderson 
857d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
858d8e59c4aSRichard Henderson {
859d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
860d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
861d8e59c4aSRichard Henderson }
862d8e59c4aSRichard Henderson 
863d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
864d8e59c4aSRichard Henderson {
865d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
866d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
867d8e59c4aSRichard Henderson }
868d8e59c4aSRichard Henderson 
869d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
870d8e59c4aSRichard Henderson {
871d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
872d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
873d8e59c4aSRichard Henderson }
874d8e59c4aSRichard Henderson 
875d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
876d8e59c4aSRichard Henderson {
877d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
878d8e59c4aSRichard Henderson         return true;
879d8e59c4aSRichard Henderson     }
880d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
881d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
882d8e59c4aSRichard Henderson }
883d8e59c4aSRichard Henderson 
884d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
885d8e59c4aSRichard Henderson {
886d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
887d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
888d8e59c4aSRichard Henderson }
889d8e59c4aSRichard Henderson 
890d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
891d8e59c4aSRichard Henderson {
892d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
893d8e59c4aSRichard Henderson 
894d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
895d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
896d8e59c4aSRichard Henderson 
897d8e59c4aSRichard Henderson     sync_jmpstate(dc);
898d8e59c4aSRichard Henderson 
899d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
900d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
901d8e59c4aSRichard Henderson     tcg_temp_free(addr);
902d8e59c4aSRichard Henderson 
903d8e59c4aSRichard Henderson     if (arg->rd) {
904d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
905d8e59c4aSRichard Henderson     }
906d8e59c4aSRichard Henderson 
907d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
908d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
909d8e59c4aSRichard Henderson     return true;
910d8e59c4aSRichard Henderson }
911d8e59c4aSRichard Henderson 
912d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
913d8e59c4aSRichard Henderson                      int mem_index, bool rev)
914d8e59c4aSRichard Henderson {
915d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
916d8e59c4aSRichard Henderson 
917d8e59c4aSRichard Henderson     /*
918d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
919d8e59c4aSRichard Henderson      *
920d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
921d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
922d8e59c4aSRichard Henderson      */
923d8e59c4aSRichard Henderson     if (rev) {
924d8e59c4aSRichard Henderson         if (size > MO_8) {
925d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
926d8e59c4aSRichard Henderson         }
927d8e59c4aSRichard Henderson         if (size < MO_32) {
928d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
929d8e59c4aSRichard Henderson         }
930d8e59c4aSRichard Henderson     }
931d8e59c4aSRichard Henderson 
932d8e59c4aSRichard Henderson     sync_jmpstate(dc);
933d8e59c4aSRichard Henderson 
934d8e59c4aSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
935d8e59c4aSRichard Henderson 
936d8e59c4aSRichard Henderson     /* TODO: Convert to CPUClass::do_unaligned_access.  */
937d8e59c4aSRichard Henderson     if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) {
938d8e59c4aSRichard Henderson         TCGv_i32 t1 = tcg_const_i32(1);
939d8e59c4aSRichard Henderson         TCGv_i32 treg = tcg_const_i32(rd);
940d8e59c4aSRichard Henderson         TCGv_i32 tsize = tcg_const_i32((1 << size) - 1);
941d8e59c4aSRichard Henderson 
942d8e59c4aSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
943d8e59c4aSRichard Henderson         /* FIXME: if the alignment is wrong, we should restore the value
944d8e59c4aSRichard Henderson          *        in memory. One possible way to achieve this is to probe
945d8e59c4aSRichard Henderson          *        the MMU prior to the memaccess, thay way we could put
946d8e59c4aSRichard Henderson          *        the alignment checks in between the probe and the mem
947d8e59c4aSRichard Henderson          *        access.
948d8e59c4aSRichard Henderson          */
949d8e59c4aSRichard Henderson         gen_helper_memalign(cpu_env, addr, treg, t1, tsize);
950d8e59c4aSRichard Henderson 
951d8e59c4aSRichard Henderson         tcg_temp_free_i32(t1);
952d8e59c4aSRichard Henderson         tcg_temp_free_i32(treg);
953d8e59c4aSRichard Henderson         tcg_temp_free_i32(tsize);
954d8e59c4aSRichard Henderson     }
955d8e59c4aSRichard Henderson 
956d8e59c4aSRichard Henderson     tcg_temp_free(addr);
957d8e59c4aSRichard Henderson     return true;
958d8e59c4aSRichard Henderson }
959d8e59c4aSRichard Henderson 
960d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
961d8e59c4aSRichard Henderson {
962d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
963d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
964d8e59c4aSRichard Henderson }
965d8e59c4aSRichard Henderson 
966d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
967d8e59c4aSRichard Henderson {
968d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
969d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
970d8e59c4aSRichard Henderson }
971d8e59c4aSRichard Henderson 
972d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
973d8e59c4aSRichard Henderson {
974d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
975d8e59c4aSRichard Henderson         return true;
976d8e59c4aSRichard Henderson     }
977d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
978d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
979d8e59c4aSRichard Henderson }
980d8e59c4aSRichard Henderson 
981d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
982d8e59c4aSRichard Henderson {
983d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
984d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
985d8e59c4aSRichard Henderson }
986d8e59c4aSRichard Henderson 
987d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
988d8e59c4aSRichard Henderson {
989d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
990d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
991d8e59c4aSRichard Henderson }
992d8e59c4aSRichard Henderson 
993d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
994d8e59c4aSRichard Henderson {
995d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
996d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
997d8e59c4aSRichard Henderson }
998d8e59c4aSRichard Henderson 
999d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
1000d8e59c4aSRichard Henderson {
1001d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
1002d8e59c4aSRichard Henderson         return true;
1003d8e59c4aSRichard Henderson     }
1004d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1005d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
1006d8e59c4aSRichard Henderson }
1007d8e59c4aSRichard Henderson 
1008d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
1009d8e59c4aSRichard Henderson {
1010d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1011d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
1012d8e59c4aSRichard Henderson }
1013d8e59c4aSRichard Henderson 
1014d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
1015d8e59c4aSRichard Henderson {
1016d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1017d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1018d8e59c4aSRichard Henderson }
1019d8e59c4aSRichard Henderson 
1020d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
1021d8e59c4aSRichard Henderson {
1022d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1023d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
1024d8e59c4aSRichard Henderson }
1025d8e59c4aSRichard Henderson 
1026d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
1027d8e59c4aSRichard Henderson {
1028d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
1029d8e59c4aSRichard Henderson         return true;
1030d8e59c4aSRichard Henderson     }
1031d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1032d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
1033d8e59c4aSRichard Henderson }
1034d8e59c4aSRichard Henderson 
1035d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1036d8e59c4aSRichard Henderson {
1037d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1038d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1039d8e59c4aSRichard Henderson }
1040d8e59c4aSRichard Henderson 
1041d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1042d8e59c4aSRichard Henderson {
1043d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1044d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1045d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1046d8e59c4aSRichard Henderson     TCGv_i32 tval;
1047d8e59c4aSRichard Henderson 
1048d8e59c4aSRichard Henderson     sync_jmpstate(dc);
1049d8e59c4aSRichard Henderson 
1050d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1051d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1052d8e59c4aSRichard Henderson 
1053d8e59c4aSRichard Henderson     /*
1054d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1055d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1056d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1057d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1058d8e59c4aSRichard Henderson      */
1059d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1060d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1061d8e59c4aSRichard Henderson 
1062d8e59c4aSRichard Henderson     /*
1063d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1064d8e59c4aSRichard Henderson      * the reserved location.
1065d8e59c4aSRichard Henderson      */
1066d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1067d8e59c4aSRichard Henderson 
1068d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1069d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1070d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1071d8e59c4aSRichard Henderson 
1072d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1073d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1074d8e59c4aSRichard Henderson 
1075d8e59c4aSRichard Henderson     /* Success */
1076d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1077d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1078d8e59c4aSRichard Henderson 
1079d8e59c4aSRichard Henderson     /* Failure */
1080d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1081d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1082d8e59c4aSRichard Henderson 
1083d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1084d8e59c4aSRichard Henderson 
1085d8e59c4aSRichard Henderson     /*
1086d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1087d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1088d8e59c4aSRichard Henderson      */
1089d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1090d8e59c4aSRichard Henderson     return true;
1091d8e59c4aSRichard Henderson }
1092d8e59c4aSRichard Henderson 
109320800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
109420800179SRichard Henderson {
109520800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
109620800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
109720800179SRichard Henderson         trap_illegal(dc, true);
109820800179SRichard Henderson         return true;
109920800179SRichard Henderson     }
110020800179SRichard Henderson     /*
110120800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
110220800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
110320800179SRichard Henderson      */
110420800179SRichard Henderson     return false;
110540cbf5b7SEdgar E. Iglesias }
11064acb54baSEdgar E. Iglesias 
11071074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
11084acb54baSEdgar E. Iglesias {
11091074c0fbSRichard Henderson     TCGv_i32 t;
11101074c0fbSRichard Henderson 
11111074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
11121074c0fbSRichard Henderson     t = tcg_temp_new_i32();
11131074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
11141074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
11151074c0fbSRichard Henderson     tcg_temp_free_i32(t);
11164acb54baSEdgar E. Iglesias }
11174acb54baSEdgar E. Iglesias 
11181074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v)
11194acb54baSEdgar E. Iglesias {
11204acb54baSEdgar E. Iglesias     dc->cpustate_changed = 1;
11211074c0fbSRichard Henderson 
11221074c0fbSRichard Henderson     /* Install MSR_C.  */
11231074c0fbSRichard Henderson     tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
11241074c0fbSRichard Henderson 
11251074c0fbSRichard Henderson     /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
11261074c0fbSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
11274acb54baSEdgar E. Iglesias }
11284acb54baSEdgar E. Iglesias 
11294acb54baSEdgar E. Iglesias static void dec_msr(DisasContext *dc)
11304acb54baSEdgar E. Iglesias {
11310063ebd6SAndreas Färber     CPUState *cs = CPU(dc->cpu);
1132cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
11332023e9a3SEdgar E. Iglesias     unsigned int sr, rn;
1134f0f7e7f7SEdgar E. Iglesias     bool to, clrset, extended = false;
11354acb54baSEdgar E. Iglesias 
11362023e9a3SEdgar E. Iglesias     sr = extract32(dc->imm, 0, 14);
11372023e9a3SEdgar E. Iglesias     to = extract32(dc->imm, 14, 1);
11382023e9a3SEdgar E. Iglesias     clrset = extract32(dc->imm, 15, 1) == 0;
11394acb54baSEdgar E. Iglesias     dc->type_b = 1;
11402023e9a3SEdgar E. Iglesias     if (to) {
11414acb54baSEdgar E. Iglesias         dc->cpustate_changed = 1;
1142f0f7e7f7SEdgar E. Iglesias     }
1143f0f7e7f7SEdgar E. Iglesias 
1144f0f7e7f7SEdgar E. Iglesias     /* Extended MSRs are only available if addr_size > 32.  */
1145f0f7e7f7SEdgar E. Iglesias     if (dc->cpu->cfg.addr_size > 32) {
1146f0f7e7f7SEdgar E. Iglesias         /* The E-bit is encoded differently for To/From MSR.  */
1147f0f7e7f7SEdgar E. Iglesias         static const unsigned int e_bit[] = { 19, 24 };
1148f0f7e7f7SEdgar E. Iglesias 
1149f0f7e7f7SEdgar E. Iglesias         extended = extract32(dc->imm, e_bit[to], 1);
11502023e9a3SEdgar E. Iglesias     }
11514acb54baSEdgar E. Iglesias 
11524acb54baSEdgar E. Iglesias     /* msrclr and msrset.  */
11532023e9a3SEdgar E. Iglesias     if (clrset) {
11542023e9a3SEdgar E. Iglesias         bool clr = extract32(dc->ir, 16, 1);
11554acb54baSEdgar E. Iglesias 
115656837509SEdgar E. Iglesias         if (!dc->cpu->cfg.use_msr_instr) {
11571567a005SEdgar E. Iglesias             /* nop??? */
11581567a005SEdgar E. Iglesias             return;
11591567a005SEdgar E. Iglesias         }
11601567a005SEdgar E. Iglesias 
1161bdfc1e88SEdgar E. Iglesias         if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
11621567a005SEdgar E. Iglesias             return;
11631567a005SEdgar E. Iglesias         }
11641567a005SEdgar E. Iglesias 
11654acb54baSEdgar E. Iglesias         if (dc->rd)
11664acb54baSEdgar E. Iglesias             msr_read(dc, cpu_R[dc->rd]);
11674acb54baSEdgar E. Iglesias 
1168cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
1169cfeea807SEdgar E. Iglesias         t1 = tcg_temp_new_i32();
11704acb54baSEdgar E. Iglesias         msr_read(dc, t0);
1171cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
11724acb54baSEdgar E. Iglesias 
11734acb54baSEdgar E. Iglesias         if (clr) {
1174cfeea807SEdgar E. Iglesias             tcg_gen_not_i32(t1, t1);
1175cfeea807SEdgar E. Iglesias             tcg_gen_and_i32(t0, t0, t1);
11764acb54baSEdgar E. Iglesias         } else
1177cfeea807SEdgar E. Iglesias             tcg_gen_or_i32(t0, t0, t1);
11784acb54baSEdgar E. Iglesias         msr_write(dc, t0);
1179cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
1180cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t1);
1181d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1182d4705ae0SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
11834acb54baSEdgar E. Iglesias         return;
11844acb54baSEdgar E. Iglesias     }
11854acb54baSEdgar E. Iglesias 
1186bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, to)) {
11871567a005SEdgar E. Iglesias         return;
11881567a005SEdgar E. Iglesias     }
11891567a005SEdgar E. Iglesias 
11904acb54baSEdgar E. Iglesias #if !defined(CONFIG_USER_ONLY)
11914acb54baSEdgar E. Iglesias     /* Catch read/writes to the mmu block.  */
11924acb54baSEdgar E. Iglesias     if ((sr & ~0xff) == 0x1000) {
1193f0f7e7f7SEdgar E. Iglesias         TCGv_i32 tmp_ext = tcg_const_i32(extended);
119405a9a651SEdgar E. Iglesias         TCGv_i32 tmp_sr;
119505a9a651SEdgar E. Iglesias 
11964acb54baSEdgar E. Iglesias         sr &= 7;
119705a9a651SEdgar E. Iglesias         tmp_sr = tcg_const_i32(sr);
119805a9a651SEdgar E. Iglesias         if (to) {
1199f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
120005a9a651SEdgar E. Iglesias         } else {
1201f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
120205a9a651SEdgar E. Iglesias         }
120305a9a651SEdgar E. Iglesias         tcg_temp_free_i32(tmp_sr);
1204f0f7e7f7SEdgar E. Iglesias         tcg_temp_free_i32(tmp_ext);
12054acb54baSEdgar E. Iglesias         return;
12064acb54baSEdgar E. Iglesias     }
12074acb54baSEdgar E. Iglesias #endif
12084acb54baSEdgar E. Iglesias 
12094acb54baSEdgar E. Iglesias     if (to) {
12104acb54baSEdgar E. Iglesias         switch (sr) {
1211aa28e6d4SRichard Henderson             case SR_PC:
12124acb54baSEdgar E. Iglesias                 break;
1213aa28e6d4SRichard Henderson             case SR_MSR:
12144acb54baSEdgar E. Iglesias                 msr_write(dc, cpu_R[dc->ra]);
12154acb54baSEdgar E. Iglesias                 break;
1216351527b7SEdgar E. Iglesias             case SR_EAR:
1217dbdb77c4SRichard Henderson                 {
1218dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
1219dbdb77c4SRichard Henderson                     tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]);
1220dbdb77c4SRichard Henderson                     tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1221dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
1222dbdb77c4SRichard Henderson                 }
1223aa28e6d4SRichard Henderson                 break;
1224351527b7SEdgar E. Iglesias             case SR_ESR:
122541ba37c4SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
122641ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
1227aa28e6d4SRichard Henderson                 break;
1228ab6dd380SEdgar E. Iglesias             case SR_FSR:
122986017ccfSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
123086017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
1231aa28e6d4SRichard Henderson                 break;
1232aa28e6d4SRichard Henderson             case SR_BTR:
1233ccf628b7SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
1234ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
1235aa28e6d4SRichard Henderson                 break;
1236aa28e6d4SRichard Henderson             case SR_EDR:
123739db007eSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
123839db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
12394acb54baSEdgar E. Iglesias                 break;
12405818dee5SEdgar E. Iglesias             case 0x800:
1241cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
1242cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
12435818dee5SEdgar E. Iglesias                 break;
12445818dee5SEdgar E. Iglesias             case 0x802:
1245cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
1246cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
12475818dee5SEdgar E. Iglesias                 break;
12484acb54baSEdgar E. Iglesias             default:
12490063ebd6SAndreas Färber                 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
12504acb54baSEdgar E. Iglesias                 break;
12514acb54baSEdgar E. Iglesias         }
12524acb54baSEdgar E. Iglesias     } else {
12534acb54baSEdgar E. Iglesias         switch (sr) {
1254aa28e6d4SRichard Henderson             case SR_PC:
1255d4705ae0SRichard Henderson                 tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
12564acb54baSEdgar E. Iglesias                 break;
1257aa28e6d4SRichard Henderson             case SR_MSR:
12584acb54baSEdgar E. Iglesias                 msr_read(dc, cpu_R[dc->rd]);
12594acb54baSEdgar E. Iglesias                 break;
1260351527b7SEdgar E. Iglesias             case SR_EAR:
1261dbdb77c4SRichard Henderson                 {
1262dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
1263dbdb77c4SRichard Henderson                     tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1264a1b48e3aSEdgar E. Iglesias                     if (extended) {
1265dbdb77c4SRichard Henderson                         tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64);
1266aa28e6d4SRichard Henderson                     } else {
1267dbdb77c4SRichard Henderson                         tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64);
1268dbdb77c4SRichard Henderson                     }
1269dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
1270a1b48e3aSEdgar E. Iglesias                 }
1271aa28e6d4SRichard Henderson                 break;
1272351527b7SEdgar E. Iglesias             case SR_ESR:
127341ba37c4SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
127441ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
1275aa28e6d4SRichard Henderson                 break;
1276351527b7SEdgar E. Iglesias             case SR_FSR:
127786017ccfSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
127886017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
1279aa28e6d4SRichard Henderson                 break;
1280351527b7SEdgar E. Iglesias             case SR_BTR:
1281ccf628b7SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
1282ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
1283aa28e6d4SRichard Henderson                 break;
12847cdae31dSTong Ho             case SR_EDR:
128539db007eSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
128639db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
12874acb54baSEdgar E. Iglesias                 break;
12885818dee5SEdgar E. Iglesias             case 0x800:
1289cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1290cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
12915818dee5SEdgar E. Iglesias                 break;
12925818dee5SEdgar E. Iglesias             case 0x802:
1293cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1294cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
12955818dee5SEdgar E. Iglesias                 break;
1296351527b7SEdgar E. Iglesias             case 0x2000 ... 0x200c:
12974acb54baSEdgar E. Iglesias                 rn = sr & 0xf;
1298cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
129968cee38aSAndreas Färber                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
13004acb54baSEdgar E. Iglesias                 break;
13014acb54baSEdgar E. Iglesias             default:
1302a47dddd7SAndreas Färber                 cpu_abort(cs, "unknown mfs reg %x\n", sr);
13034acb54baSEdgar E. Iglesias                 break;
13044acb54baSEdgar E. Iglesias         }
13054acb54baSEdgar E. Iglesias     }
1306ee7dbcf8SEdgar E. Iglesias 
1307ee7dbcf8SEdgar E. Iglesias     if (dc->rd == 0) {
1308cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[0], 0);
1309ee7dbcf8SEdgar E. Iglesias     }
13104acb54baSEdgar E. Iglesias }
13114acb54baSEdgar E. Iglesias 
13124acb54baSEdgar E. Iglesias static inline void eval_cc(DisasContext *dc, unsigned int cc,
13139e6e1828SEdgar E. Iglesias                            TCGv_i32 d, TCGv_i32 a)
13144acb54baSEdgar E. Iglesias {
1315d89b86e9SEdgar E. Iglesias     static const int mb_to_tcg_cc[] = {
1316d89b86e9SEdgar E. Iglesias         [CC_EQ] = TCG_COND_EQ,
1317d89b86e9SEdgar E. Iglesias         [CC_NE] = TCG_COND_NE,
1318d89b86e9SEdgar E. Iglesias         [CC_LT] = TCG_COND_LT,
1319d89b86e9SEdgar E. Iglesias         [CC_LE] = TCG_COND_LE,
1320d89b86e9SEdgar E. Iglesias         [CC_GE] = TCG_COND_GE,
1321d89b86e9SEdgar E. Iglesias         [CC_GT] = TCG_COND_GT,
1322d89b86e9SEdgar E. Iglesias     };
1323d89b86e9SEdgar E. Iglesias 
13244acb54baSEdgar E. Iglesias     switch (cc) {
13254acb54baSEdgar E. Iglesias     case CC_EQ:
13264acb54baSEdgar E. Iglesias     case CC_NE:
13274acb54baSEdgar E. Iglesias     case CC_LT:
13284acb54baSEdgar E. Iglesias     case CC_LE:
13294acb54baSEdgar E. Iglesias     case CC_GE:
13304acb54baSEdgar E. Iglesias     case CC_GT:
13319e6e1828SEdgar E. Iglesias         tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
13324acb54baSEdgar E. Iglesias         break;
13334acb54baSEdgar E. Iglesias     default:
13340063ebd6SAndreas Färber         cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
13354acb54baSEdgar E. Iglesias         break;
13364acb54baSEdgar E. Iglesias     }
13374acb54baSEdgar E. Iglesias }
13384acb54baSEdgar E. Iglesias 
13390f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false)
13404acb54baSEdgar E. Iglesias {
13410f96e96bSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
1342e956caf2SEdgar E. Iglesias 
13430f96e96bSRichard Henderson     tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc,
13449b158558SRichard Henderson                         cpu_btaken, zero,
1345e956caf2SEdgar E. Iglesias                         pc_true, pc_false);
1346e956caf2SEdgar E. Iglesias 
13470f96e96bSRichard Henderson     tcg_temp_free_i32(zero);
13484acb54baSEdgar E. Iglesias }
13494acb54baSEdgar E. Iglesias 
1350f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc)
1351f91c60f0SEdgar E. Iglesias {
1352f91c60f0SEdgar E. Iglesias     dc->delayed_branch = 2;
1353f91c60f0SEdgar E. Iglesias     dc->tb_flags |= D_FLAG;
13547b34f45fSRichard Henderson     if (dc->type_b && (dc->tb_flags & IMM_FLAG)) {
13557b34f45fSRichard Henderson         dc->tb_flags |= BIMM_FLAG;
13567b34f45fSRichard Henderson     }
1357f91c60f0SEdgar E. Iglesias }
1358f91c60f0SEdgar E. Iglesias 
13594acb54baSEdgar E. Iglesias static void dec_bcc(DisasContext *dc)
13604acb54baSEdgar E. Iglesias {
13614acb54baSEdgar E. Iglesias     unsigned int cc;
13624acb54baSEdgar E. Iglesias     unsigned int dslot;
13634acb54baSEdgar E. Iglesias 
13644acb54baSEdgar E. Iglesias     cc = EXTRACT_FIELD(dc->ir, 21, 23);
13654acb54baSEdgar E. Iglesias     dslot = dc->ir & (1 << 25);
13664acb54baSEdgar E. Iglesias 
13674acb54baSEdgar E. Iglesias     dc->delayed_branch = 1;
13684acb54baSEdgar E. Iglesias     if (dslot) {
1369f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
13704acb54baSEdgar E. Iglesias     }
13714acb54baSEdgar E. Iglesias 
1372d7ecb757SRichard Henderson     if (dc->type_b) {
1373844bab60SEdgar E. Iglesias         dc->jmp = JMP_DIRECT_CC;
1374d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1375d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
137661204ce8SEdgar E. Iglesias     } else {
137723979dc5SEdgar E. Iglesias         dc->jmp = JMP_INDIRECT;
1378d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
137961204ce8SEdgar E. Iglesias     }
13809b158558SRichard Henderson     eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]);
13814acb54baSEdgar E. Iglesias }
13824acb54baSEdgar E. Iglesias 
13834acb54baSEdgar E. Iglesias static void dec_br(DisasContext *dc)
13844acb54baSEdgar E. Iglesias {
13859f6113c7SEdgar E. Iglesias     unsigned int dslot, link, abs, mbar;
13864acb54baSEdgar E. Iglesias 
13874acb54baSEdgar E. Iglesias     dslot = dc->ir & (1 << 20);
13884acb54baSEdgar E. Iglesias     abs = dc->ir & (1 << 19);
13894acb54baSEdgar E. Iglesias     link = dc->ir & (1 << 18);
13909f6113c7SEdgar E. Iglesias 
13919f6113c7SEdgar E. Iglesias     /* Memory barrier.  */
13929f6113c7SEdgar E. Iglesias     mbar = (dc->ir >> 16) & 31;
13939f6113c7SEdgar E. Iglesias     if (mbar == 2 && dc->imm == 4) {
1394badcbf9dSEdgar E. Iglesias         uint16_t mbar_imm = dc->rd;
1395badcbf9dSEdgar E. Iglesias 
13963f172744SEdgar E. Iglesias         /* Data access memory barrier.  */
13973f172744SEdgar E. Iglesias         if ((mbar_imm & 2) == 0) {
13983f172744SEdgar E. Iglesias             tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
13993f172744SEdgar E. Iglesias         }
14003f172744SEdgar E. Iglesias 
14015d45de97SEdgar E. Iglesias         /* mbar IMM & 16 decodes to sleep.  */
1402badcbf9dSEdgar E. Iglesias         if (mbar_imm & 16) {
140341ba37c4SRichard Henderson             TCGv_i32 tmp_1;
14045d45de97SEdgar E. Iglesias 
1405b4919e7dSEdgar E. Iglesias             if (trap_userspace(dc, true)) {
1406b4919e7dSEdgar E. Iglesias                 /* Sleep is a privileged instruction.  */
1407b4919e7dSEdgar E. Iglesias                 return;
1408b4919e7dSEdgar E. Iglesias             }
1409b4919e7dSEdgar E. Iglesias 
14105d45de97SEdgar E. Iglesias             t_sync_flags(dc);
141141ba37c4SRichard Henderson 
141241ba37c4SRichard Henderson             tmp_1 = tcg_const_i32(1);
14135d45de97SEdgar E. Iglesias             tcg_gen_st_i32(tmp_1, cpu_env,
14145d45de97SEdgar E. Iglesias                            -offsetof(MicroBlazeCPU, env)
14155d45de97SEdgar E. Iglesias                            +offsetof(CPUState, halted));
14165d45de97SEdgar E. Iglesias             tcg_temp_free_i32(tmp_1);
141741ba37c4SRichard Henderson 
1418d4705ae0SRichard Henderson             tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
141941ba37c4SRichard Henderson 
142041ba37c4SRichard Henderson             gen_raise_exception(dc, EXCP_HLT);
14215d45de97SEdgar E. Iglesias             return;
14225d45de97SEdgar E. Iglesias         }
14239f6113c7SEdgar E. Iglesias         /* Break the TB.  */
14249f6113c7SEdgar E. Iglesias         dc->cpustate_changed = 1;
14259f6113c7SEdgar E. Iglesias         return;
14269f6113c7SEdgar E. Iglesias     }
14279f6113c7SEdgar E. Iglesias 
1428d7ecb757SRichard Henderson     if (abs && link && !dslot) {
1429d7ecb757SRichard Henderson         if (dc->type_b) {
1430d7ecb757SRichard Henderson             /* BRKI */
1431d7ecb757SRichard Henderson             uint32_t imm = dec_alu_typeb_imm(dc);
1432d7ecb757SRichard Henderson             if (trap_userspace(dc, imm != 8 && imm != 0x18)) {
1433d7ecb757SRichard Henderson                 return;
1434d7ecb757SRichard Henderson             }
1435d7ecb757SRichard Henderson         } else {
1436d7ecb757SRichard Henderson             /* BRK */
1437d7ecb757SRichard Henderson             if (trap_userspace(dc, true)) {
1438d7ecb757SRichard Henderson                 return;
1439d7ecb757SRichard Henderson             }
1440d7ecb757SRichard Henderson         }
1441d7ecb757SRichard Henderson     }
1442d7ecb757SRichard Henderson 
14434acb54baSEdgar E. Iglesias     dc->delayed_branch = 1;
14444acb54baSEdgar E. Iglesias     if (dslot) {
1445f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
14464acb54baSEdgar E. Iglesias     }
1447d7ecb757SRichard Henderson     if (link && dc->rd) {
1448d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1449d7ecb757SRichard Henderson     }
14504acb54baSEdgar E. Iglesias 
14514acb54baSEdgar E. Iglesias     if (abs) {
1452d7ecb757SRichard Henderson         if (dc->type_b) {
1453d7ecb757SRichard Henderson             uint32_t dest = dec_alu_typeb_imm(dc);
1454d7ecb757SRichard Henderson 
1455d7ecb757SRichard Henderson             dc->jmp = JMP_DIRECT;
1456d7ecb757SRichard Henderson             dc->jmp_pc = dest;
1457d7ecb757SRichard Henderson             tcg_gen_movi_i32(cpu_btarget, dest);
1458ff21f70aSEdgar E. Iglesias             if (link && !dslot) {
1459d7ecb757SRichard Henderson                 switch (dest) {
1460d7ecb757SRichard Henderson                 case 8:
1461d7ecb757SRichard Henderson                 case 0x18:
1462d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_BREAK);
1463d7ecb757SRichard Henderson                     break;
1464d7ecb757SRichard Henderson                 case 0:
1465d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_DEBUG);
1466d7ecb757SRichard Henderson                     break;
1467d7ecb757SRichard Henderson                 }
1468d7ecb757SRichard Henderson             }
1469d7ecb757SRichard Henderson         } else {
1470d7ecb757SRichard Henderson             dc->jmp = JMP_INDIRECT;
1471d7ecb757SRichard Henderson             tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]);
1472d7ecb757SRichard Henderson             if (link && !dslot) {
147341ba37c4SRichard Henderson                 gen_raise_exception_sync(dc, EXCP_BREAK);
147441ba37c4SRichard Henderson             }
1475ff21f70aSEdgar E. Iglesias         }
1476d7ecb757SRichard Henderson     } else if (dc->type_b) {
147761204ce8SEdgar E. Iglesias         dc->jmp = JMP_DIRECT;
1478d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1479d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
148061204ce8SEdgar E. Iglesias     } else {
1481d7ecb757SRichard Henderson         dc->jmp = JMP_INDIRECT;
1482d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1483d7ecb757SRichard Henderson     }
14849b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
14854acb54baSEdgar E. Iglesias }
14864acb54baSEdgar E. Iglesias 
14874acb54baSEdgar E. Iglesias static inline void do_rti(DisasContext *dc)
14884acb54baSEdgar E. Iglesias {
1489cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1490cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1491cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
14923e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
14930a22f8cfSEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
14940a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_IE);
1495cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
14964acb54baSEdgar E. Iglesias 
1497cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1498cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
14994acb54baSEdgar E. Iglesias     msr_write(dc, t1);
1500cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1501cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
15024acb54baSEdgar E. Iglesias     dc->tb_flags &= ~DRTI_FLAG;
15034acb54baSEdgar E. Iglesias }
15044acb54baSEdgar E. Iglesias 
15054acb54baSEdgar E. Iglesias static inline void do_rtb(DisasContext *dc)
15064acb54baSEdgar E. Iglesias {
1507cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1508cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1509cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
15103e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
15110a22f8cfSEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
1512cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1513cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
15144acb54baSEdgar E. Iglesias 
1515cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1516cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
15174acb54baSEdgar E. Iglesias     msr_write(dc, t1);
1518cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1519cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
15204acb54baSEdgar E. Iglesias     dc->tb_flags &= ~DRTB_FLAG;
15214acb54baSEdgar E. Iglesias }
15224acb54baSEdgar E. Iglesias 
15234acb54baSEdgar E. Iglesias static inline void do_rte(DisasContext *dc)
15244acb54baSEdgar E. Iglesias {
1525cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1526cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1527cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
15284acb54baSEdgar E. Iglesias 
15293e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
15300a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_EE);
1531cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
1532cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1533cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
15344acb54baSEdgar E. Iglesias 
1535cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1536cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
15374acb54baSEdgar E. Iglesias     msr_write(dc, t1);
1538cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1539cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
15404acb54baSEdgar E. Iglesias     dc->tb_flags &= ~DRTE_FLAG;
15414acb54baSEdgar E. Iglesias }
15424acb54baSEdgar E. Iglesias 
15434acb54baSEdgar E. Iglesias static void dec_rts(DisasContext *dc)
15444acb54baSEdgar E. Iglesias {
15454acb54baSEdgar E. Iglesias     unsigned int b_bit, i_bit, e_bit;
15464acb54baSEdgar E. Iglesias 
15474acb54baSEdgar E. Iglesias     i_bit = dc->ir & (1 << 21);
15484acb54baSEdgar E. Iglesias     b_bit = dc->ir & (1 << 22);
15494acb54baSEdgar E. Iglesias     e_bit = dc->ir & (1 << 23);
15504acb54baSEdgar E. Iglesias 
1551bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
1552bdfc1e88SEdgar E. Iglesias         return;
1553bdfc1e88SEdgar E. Iglesias     }
1554bdfc1e88SEdgar E. Iglesias 
1555f91c60f0SEdgar E. Iglesias     dec_setup_dslot(dc);
15564acb54baSEdgar E. Iglesias 
15574acb54baSEdgar E. Iglesias     if (i_bit) {
15584acb54baSEdgar E. Iglesias         dc->tb_flags |= DRTI_FLAG;
15594acb54baSEdgar E. Iglesias     } else if (b_bit) {
15604acb54baSEdgar E. Iglesias         dc->tb_flags |= DRTB_FLAG;
15614acb54baSEdgar E. Iglesias     } else if (e_bit) {
15624acb54baSEdgar E. Iglesias         dc->tb_flags |= DRTE_FLAG;
156311105d67SRichard Henderson     }
15644acb54baSEdgar E. Iglesias 
156523979dc5SEdgar E. Iglesias     dc->jmp = JMP_INDIRECT;
15669b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
15670f96e96bSRichard Henderson     tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc));
15684acb54baSEdgar E. Iglesias }
15694acb54baSEdgar E. Iglesias 
15704acb54baSEdgar E. Iglesias static void dec_null(DisasContext *dc)
15714acb54baSEdgar E. Iglesias {
15729ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, true)) {
157302b33596SEdgar E. Iglesias         return;
157402b33596SEdgar E. Iglesias     }
1575d4705ae0SRichard Henderson     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n",
1576d4705ae0SRichard Henderson                   (uint32_t)dc->base.pc_next, dc->opcode);
15774acb54baSEdgar E. Iglesias     dc->abort_at_next_insn = 1;
15784acb54baSEdgar E. Iglesias }
15794acb54baSEdgar E. Iglesias 
15806d76d23eSEdgar E. Iglesias /* Insns connected to FSL or AXI stream attached devices.  */
15816d76d23eSEdgar E. Iglesias static void dec_stream(DisasContext *dc)
15826d76d23eSEdgar E. Iglesias {
15836d76d23eSEdgar E. Iglesias     TCGv_i32 t_id, t_ctrl;
15846d76d23eSEdgar E. Iglesias     int ctrl;
15856d76d23eSEdgar E. Iglesias 
1586bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
15876d76d23eSEdgar E. Iglesias         return;
15886d76d23eSEdgar E. Iglesias     }
15896d76d23eSEdgar E. Iglesias 
1590cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
15916d76d23eSEdgar E. Iglesias     if (dc->type_b) {
1592cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(t_id, dc->imm & 0xf);
15936d76d23eSEdgar E. Iglesias         ctrl = dc->imm >> 10;
15946d76d23eSEdgar E. Iglesias     } else {
1595cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
15966d76d23eSEdgar E. Iglesias         ctrl = dc->imm >> 5;
15976d76d23eSEdgar E. Iglesias     }
15986d76d23eSEdgar E. Iglesias 
1599cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
16006d76d23eSEdgar E. Iglesias 
16016d76d23eSEdgar E. Iglesias     if (dc->rd == 0) {
16026d76d23eSEdgar E. Iglesias         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
16036d76d23eSEdgar E. Iglesias     } else {
16046d76d23eSEdgar E. Iglesias         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
16056d76d23eSEdgar E. Iglesias     }
1606cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1607cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
16086d76d23eSEdgar E. Iglesias }
16096d76d23eSEdgar E. Iglesias 
16104acb54baSEdgar E. Iglesias static struct decoder_info {
16114acb54baSEdgar E. Iglesias     struct {
16124acb54baSEdgar E. Iglesias         uint32_t bits;
16134acb54baSEdgar E. Iglesias         uint32_t mask;
16144acb54baSEdgar E. Iglesias     };
16154acb54baSEdgar E. Iglesias     void (*dec)(DisasContext *dc);
16164acb54baSEdgar E. Iglesias } decinfo[] = {
16174acb54baSEdgar E. Iglesias     {DEC_BR, dec_br},
16184acb54baSEdgar E. Iglesias     {DEC_BCC, dec_bcc},
16194acb54baSEdgar E. Iglesias     {DEC_RTS, dec_rts},
16204acb54baSEdgar E. Iglesias     {DEC_MSR, dec_msr},
16216d76d23eSEdgar E. Iglesias     {DEC_STREAM, dec_stream},
16224acb54baSEdgar E. Iglesias     {{0, 0}, dec_null}
16234acb54baSEdgar E. Iglesias };
16244acb54baSEdgar E. Iglesias 
162544d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir)
16264acb54baSEdgar E. Iglesias {
16274acb54baSEdgar E. Iglesias     int i;
16284acb54baSEdgar E. Iglesias 
162964254ebaSBlue Swirl     dc->ir = ir;
16304acb54baSEdgar E. Iglesias 
16314acb54baSEdgar E. Iglesias     /* bit 2 seems to indicate insn type.  */
16324acb54baSEdgar E. Iglesias     dc->type_b = ir & (1 << 29);
16334acb54baSEdgar E. Iglesias 
16344acb54baSEdgar E. Iglesias     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
16354acb54baSEdgar E. Iglesias     dc->rd = EXTRACT_FIELD(ir, 21, 25);
16364acb54baSEdgar E. Iglesias     dc->ra = EXTRACT_FIELD(ir, 16, 20);
16374acb54baSEdgar E. Iglesias     dc->rb = EXTRACT_FIELD(ir, 11, 15);
16384acb54baSEdgar E. Iglesias     dc->imm = EXTRACT_FIELD(ir, 0, 15);
16394acb54baSEdgar E. Iglesias 
16404acb54baSEdgar E. Iglesias     /* Large switch for all insns.  */
16414acb54baSEdgar E. Iglesias     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
16424acb54baSEdgar E. Iglesias         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
16434acb54baSEdgar E. Iglesias             decinfo[i].dec(dc);
16444acb54baSEdgar E. Iglesias             break;
16454acb54baSEdgar E. Iglesias         }
16464acb54baSEdgar E. Iglesias     }
16474acb54baSEdgar E. Iglesias }
16484acb54baSEdgar E. Iglesias 
1649372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
16504acb54baSEdgar E. Iglesias {
1651372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1652372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1653372122e3SRichard Henderson     int bound;
16544acb54baSEdgar E. Iglesias 
16550063ebd6SAndreas Färber     dc->cpu = cpu;
1656*683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
16574acb54baSEdgar E. Iglesias     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
1658372122e3SRichard Henderson     dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP;
16594acb54baSEdgar E. Iglesias     dc->cpustate_changed = 0;
16604acb54baSEdgar E. Iglesias     dc->abort_at_next_insn = 0;
1661d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
166220800179SRichard Henderson     dc->r0 = NULL;
166320800179SRichard Henderson     dc->r0_set = false;
1664287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
16654acb54baSEdgar E. Iglesias 
1666372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1667372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1668a47dddd7SAndreas Färber }
16694acb54baSEdgar E. Iglesias 
1670372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
16714acb54baSEdgar E. Iglesias {
1672b933066aSRichard Henderson }
1673b933066aSRichard Henderson 
1674372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1675372122e3SRichard Henderson {
1676*683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1677*683a247eSRichard Henderson 
1678*683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1679*683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1680372122e3SRichard Henderson }
16814acb54baSEdgar E. Iglesias 
1682372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1683372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1684372122e3SRichard Henderson {
1685372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1686372122e3SRichard Henderson 
1687372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1688372122e3SRichard Henderson 
1689372122e3SRichard Henderson     /*
1690372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1691372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1692372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1693372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1694372122e3SRichard Henderson      */
1695372122e3SRichard Henderson     dc->base.pc_next += 4;
1696372122e3SRichard Henderson     return true;
1697372122e3SRichard Henderson }
1698372122e3SRichard Henderson 
1699372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1700372122e3SRichard Henderson {
1701372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1702372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
170344d1432bSRichard Henderson     uint32_t ir;
1704372122e3SRichard Henderson 
1705372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1706372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1707372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1708372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1709959082fcSRichard Henderson     }
17104acb54baSEdgar E. Iglesias 
17114acb54baSEdgar E. Iglesias     dc->clear_imm = 1;
171244d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
171344d1432bSRichard Henderson     if (!decode(dc, ir)) {
171444d1432bSRichard Henderson         old_decode(dc, ir);
171544d1432bSRichard Henderson     }
171620800179SRichard Henderson 
171720800179SRichard Henderson     if (dc->r0) {
171820800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
171920800179SRichard Henderson         dc->r0 = NULL;
172020800179SRichard Henderson         dc->r0_set = false;
172120800179SRichard Henderson     }
172220800179SRichard Henderson 
1723d7ecb757SRichard Henderson     if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) {
17244acb54baSEdgar E. Iglesias         dc->tb_flags &= ~IMM_FLAG;
1725d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1726372122e3SRichard Henderson     }
1727d4705ae0SRichard Henderson     dc->base.pc_next += 4;
17284acb54baSEdgar E. Iglesias 
1729372122e3SRichard Henderson     if (dc->delayed_branch && --dc->delayed_branch == 0) {
1730372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
17314acb54baSEdgar E. Iglesias             do_rti(dc);
1732372122e3SRichard Henderson         }
1733372122e3SRichard Henderson         if (dc->tb_flags & DRTB_FLAG) {
17344acb54baSEdgar E. Iglesias             do_rtb(dc);
1735372122e3SRichard Henderson         }
1736372122e3SRichard Henderson         if (dc->tb_flags & DRTE_FLAG) {
17374acb54baSEdgar E. Iglesias             do_rte(dc);
1738372122e3SRichard Henderson         }
17394acb54baSEdgar E. Iglesias         /* Clear the delay slot flag.  */
17404acb54baSEdgar E. Iglesias         dc->tb_flags &= ~D_FLAG;
1741372122e3SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1742372122e3SRichard Henderson     }
1743372122e3SRichard Henderson 
1744372122e3SRichard Henderson     /* Force an exit if the per-tb cpu state has changed.  */
1745372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
1746372122e3SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1747372122e3SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1748372122e3SRichard Henderson     }
1749372122e3SRichard Henderson }
1750372122e3SRichard Henderson 
1751372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1752372122e3SRichard Henderson {
1753372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1754372122e3SRichard Henderson 
1755372122e3SRichard Henderson     assert(!dc->abort_at_next_insn);
1756372122e3SRichard Henderson 
1757372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1758372122e3SRichard Henderson         /* We have already exited the TB. */
1759372122e3SRichard Henderson         return;
1760372122e3SRichard Henderson     }
1761372122e3SRichard Henderson 
1762372122e3SRichard Henderson     t_sync_flags(dc);
1763372122e3SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1764372122e3SRichard Henderson         sync_jmpstate(dc);
1765372122e3SRichard Henderson         dc->jmp = JMP_NOJMP;
1766372122e3SRichard Henderson     }
1767372122e3SRichard Henderson 
1768372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1769372122e3SRichard Henderson     case DISAS_TOO_MANY:
1770372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1771372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1772372122e3SRichard Henderson         return;
1773372122e3SRichard Henderson 
1774372122e3SRichard Henderson     case DISAS_UPDATE:
1775372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1776372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1777372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1778372122e3SRichard Henderson         } else {
1779372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1780372122e3SRichard Henderson         }
1781372122e3SRichard Henderson         return;
1782372122e3SRichard Henderson 
1783372122e3SRichard Henderson     case DISAS_JUMP:
1784372122e3SRichard Henderson         switch (dc->jmp) {
1785372122e3SRichard Henderson         case JMP_INDIRECT:
1786372122e3SRichard Henderson             {
1787d4705ae0SRichard Henderson                 TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next);
17880f96e96bSRichard Henderson                 eval_cond_jmp(dc, cpu_btarget, tmp_pc);
17890f96e96bSRichard Henderson                 tcg_temp_free_i32(tmp_pc);
1790372122e3SRichard Henderson 
1791372122e3SRichard Henderson                 if (unlikely(cs->singlestep_enabled)) {
1792372122e3SRichard Henderson                     gen_raise_exception(dc, EXCP_DEBUG);
1793372122e3SRichard Henderson                 } else {
1794372122e3SRichard Henderson                     tcg_gen_exit_tb(NULL, 0);
1795372122e3SRichard Henderson                 }
1796372122e3SRichard Henderson             }
1797372122e3SRichard Henderson             return;
1798372122e3SRichard Henderson 
1799372122e3SRichard Henderson         case JMP_DIRECT_CC:
1800372122e3SRichard Henderson             {
180142a268c2SRichard Henderson                 TCGLabel *l1 = gen_new_label();
18029b158558SRichard Henderson                 tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1);
1803d4705ae0SRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
180423979dc5SEdgar E. Iglesias                 gen_set_label(l1);
1805372122e3SRichard Henderson             }
1806372122e3SRichard Henderson             /* fall through */
1807372122e3SRichard Henderson 
1808372122e3SRichard Henderson         case JMP_DIRECT:
180923979dc5SEdgar E. Iglesias             gen_goto_tb(dc, 0, dc->jmp_pc);
1810372122e3SRichard Henderson             return;
18114acb54baSEdgar E. Iglesias         }
1812372122e3SRichard Henderson         /* fall through */
18134acb54baSEdgar E. Iglesias 
1814a2b80dbdSRichard Henderson     default:
1815a2b80dbdSRichard Henderson         g_assert_not_reached();
18164acb54baSEdgar E. Iglesias     }
18174acb54baSEdgar E. Iglesias }
18180a7df5daSRichard Henderson 
1819372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1820372122e3SRichard Henderson {
1821372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1822372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
18234acb54baSEdgar E. Iglesias }
1824372122e3SRichard Henderson 
1825372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1826372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1827372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1828372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1829372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1830372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1831372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1832372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1833372122e3SRichard Henderson };
1834372122e3SRichard Henderson 
1835372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1836372122e3SRichard Henderson {
1837372122e3SRichard Henderson     DisasContext dc;
1838372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
18394acb54baSEdgar E. Iglesias }
18404acb54baSEdgar E. Iglesias 
184190c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
18424acb54baSEdgar E. Iglesias {
1843878096eeSAndreas Färber     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1844878096eeSAndreas Färber     CPUMBState *env = &cpu->env;
18454acb54baSEdgar E. Iglesias     int i;
18464acb54baSEdgar E. Iglesias 
184790c84c56SMarkus Armbruster     if (!env) {
18484acb54baSEdgar E. Iglesias         return;
184990c84c56SMarkus Armbruster     }
18504acb54baSEdgar E. Iglesias 
18510f96e96bSRichard Henderson     qemu_fprintf(f, "IN: PC=%x %s\n",
185276e8187dSRichard Henderson                  env->pc, lookup_symbol(env->pc));
18536efd5599SRichard Henderson     qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " "
1854eb2022b7SRichard Henderson                  "imm=%x iflags=%x fsr=%x rbtr=%x\n",
185578e9caf2SRichard Henderson                  env->msr, env->esr, env->ear,
1856eb2022b7SRichard Henderson                  env->imm, env->iflags, env->fsr, env->btr);
18570f96e96bSRichard Henderson     qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
18584acb54baSEdgar E. Iglesias                  env->btaken, env->btarget,
18592e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18602e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18612e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18622e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18632ead1b18SJoe Komlodi     for (i = 0; i < 12; i++) {
18642ead1b18SJoe Komlodi         qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]);
18652ead1b18SJoe Komlodi         if ((i + 1) % 4 == 0) {
18662ead1b18SJoe Komlodi             qemu_fprintf(f, "\n");
18672ead1b18SJoe Komlodi         }
18682ead1b18SJoe Komlodi     }
186917c52a43SEdgar E. Iglesias 
18702ead1b18SJoe Komlodi     /* Registers that aren't modeled are reported as 0 */
187139db007eSRichard Henderson     qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 "
1872af20a93aSRichard Henderson                     "rtlblo=0 rtlbhi=0\n", env->edr);
18732ead1b18SJoe Komlodi     qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr);
18744acb54baSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
187590c84c56SMarkus Armbruster         qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
18764acb54baSEdgar E. Iglesias         if ((i + 1) % 4 == 0)
187790c84c56SMarkus Armbruster             qemu_fprintf(f, "\n");
18784acb54baSEdgar E. Iglesias         }
187990c84c56SMarkus Armbruster     qemu_fprintf(f, "\n\n");
18804acb54baSEdgar E. Iglesias }
18814acb54baSEdgar E. Iglesias 
1882cd0c24f9SAndreas Färber void mb_tcg_init(void)
1883cd0c24f9SAndreas Färber {
1884480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1885480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
18864acb54baSEdgar E. Iglesias 
1887480d29a8SRichard Henderson     static const struct {
1888480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1889480d29a8SRichard Henderson     } i32s[] = {
1890480d29a8SRichard Henderson         R(0),  R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1891480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1892480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1893480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1894480d29a8SRichard Henderson 
1895480d29a8SRichard Henderson         SP(pc),
1896480d29a8SRichard Henderson         SP(msr),
18971074c0fbSRichard Henderson         SP(msr_c),
1898480d29a8SRichard Henderson         SP(imm),
1899480d29a8SRichard Henderson         SP(iflags),
1900480d29a8SRichard Henderson         SP(btaken),
1901480d29a8SRichard Henderson         SP(btarget),
1902480d29a8SRichard Henderson         SP(res_val),
1903480d29a8SRichard Henderson     };
1904480d29a8SRichard Henderson 
1905480d29a8SRichard Henderson #undef R
1906480d29a8SRichard Henderson #undef SP
1907480d29a8SRichard Henderson 
1908480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1909480d29a8SRichard Henderson         *i32s[i].var =
1910480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
19114acb54baSEdgar E. Iglesias     }
191276e8187dSRichard Henderson 
1913480d29a8SRichard Henderson     cpu_res_addr =
1914480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
19154acb54baSEdgar E. Iglesias }
19164acb54baSEdgar E. Iglesias 
1917bad729e2SRichard Henderson void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1918bad729e2SRichard Henderson                           target_ulong *data)
19194acb54baSEdgar E. Iglesias {
192076e8187dSRichard Henderson     env->pc = data[0];
1921*683a247eSRichard Henderson     env->iflags = data[1];
19224acb54baSEdgar E. Iglesias }
1923