xref: /qemu/target/microblaze/translate.c (revision 3072961b6edc99abfbd87caac3de29bb58a52ccf)
14acb54baSEdgar E. Iglesias /*
24acb54baSEdgar E. Iglesias  *  Xilinx MicroBlaze emulation for qemu: main translation routines.
34acb54baSEdgar E. Iglesias  *
44acb54baSEdgar E. Iglesias  *  Copyright (c) 2009 Edgar E. Iglesias.
5dadc1064SPeter A. G. Crosthwaite  *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
64acb54baSEdgar E. Iglesias  *
74acb54baSEdgar E. Iglesias  * This library is free software; you can redistribute it and/or
84acb54baSEdgar E. Iglesias  * modify it under the terms of the GNU Lesser General Public
94acb54baSEdgar E. Iglesias  * License as published by the Free Software Foundation; either
10ee452036SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
114acb54baSEdgar E. Iglesias  *
124acb54baSEdgar E. Iglesias  * This library is distributed in the hope that it will be useful,
134acb54baSEdgar E. Iglesias  * but WITHOUT ANY WARRANTY; without even the implied warranty of
144acb54baSEdgar E. Iglesias  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
154acb54baSEdgar E. Iglesias  * Lesser General Public License for more details.
164acb54baSEdgar E. Iglesias  *
174acb54baSEdgar E. Iglesias  * You should have received a copy of the GNU Lesser General Public
188167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
194acb54baSEdgar E. Iglesias  */
204acb54baSEdgar E. Iglesias 
218fd9deceSPeter Maydell #include "qemu/osdep.h"
224acb54baSEdgar E. Iglesias #include "cpu.h"
2342fa9665SPhilippe Mathieu-Daudé #include "accel/tcg/cpu-ldst.h"
24dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
252ef6175aSRichard Henderson #include "exec/helper-proto.h"
262ef6175aSRichard Henderson #include "exec/helper-gen.h"
2777fc6f5eSLluís Vilanova #include "exec/translator.h"
2868df8c8dSPhilippe Mathieu-Daudé #include "exec/translation-block.h"
299c2ff9cdSPierrick Bouvier #include "exec/target_page.h"
3090c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
314acb54baSEdgar E. Iglesias 
32508127e2SPaolo Bonzini #include "exec/log.h"
33a7e30d84SLluís Vilanova 
34d53106c9SRichard Henderson #define HELPER_H "helper.h"
35d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
36d53106c9SRichard Henderson #undef  HELPER_H
37d53106c9SRichard Henderson 
384acb54baSEdgar E. Iglesias #define EXTRACT_FIELD(src, start, end) \
394acb54baSEdgar E. Iglesias             (((src) >> start) & ((1 << (end - start + 1)) - 1))
404acb54baSEdgar E. Iglesias 
4177fc6f5eSLluís Vilanova /* is_jmp field values */
4277fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
4317e77796SRichard Henderson #define DISAS_EXIT    DISAS_TARGET_1 /* all cpu state modified dynamically */
4477fc6f5eSLluís Vilanova 
45f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */
46f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2
47f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */
48f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3
49f6278ca9SRichard Henderson 
50cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
510f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
523e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
531074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
549b158558SRichard Henderson static TCGv_i32 cpu_imm;
55b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
560f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
579b158558SRichard Henderson static TCGv_i32 cpu_iflags;
589b158558SRichard Henderson static TCGv cpu_res_addr;
599b158558SRichard Henderson static TCGv_i32 cpu_res_val;
604acb54baSEdgar E. Iglesias 
614acb54baSEdgar E. Iglesias /* This is the state at translation time.  */
624acb54baSEdgar E. Iglesias typedef struct DisasContext {
63d4705ae0SRichard Henderson     DisasContextBase base;
644b893631SRichard Henderson     const MicroBlazeCPUConfig *cfg;
654acb54baSEdgar E. Iglesias 
664acb54baSEdgar E. Iglesias     /* Decoder.  */
67d7ecb757SRichard Henderson     uint32_t ext_imm;
68683a247eSRichard Henderson     unsigned int tb_flags;
696f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
70287b1defSRichard Henderson     int mem_index;
714acb54baSEdgar E. Iglesias 
72b9c58aabSRichard Henderson     /* Condition under which to jump, including NEVER and ALWAYS. */
73b9c58aabSRichard Henderson     TCGCond jmp_cond;
74b9c58aabSRichard Henderson 
75b9c58aabSRichard Henderson     /* Immediate branch-taken destination, or -1 for indirect. */
76b9c58aabSRichard Henderson     uint32_t jmp_dest;
774acb54baSEdgar E. Iglesias } DisasContext;
784acb54baSEdgar E. Iglesias 
typeb_imm(DisasContext * dc,int x)7920800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8020800179SRichard Henderson {
8120800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
8220800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
8320800179SRichard Henderson     }
8420800179SRichard Henderson     return x;
8520800179SRichard Henderson }
8620800179SRichard Henderson 
8744d1432bSRichard Henderson /* Include the auto-generated decoder.  */
8844d1432bSRichard Henderson #include "decode-insns.c.inc"
8944d1432bSRichard Henderson 
t_sync_flags(DisasContext * dc)90683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
914acb54baSEdgar E. Iglesias {
924abf79a4SDong Xu Wang     /* Synch the tb dependent flags between translator and runtime.  */
9388e74b61SRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
9488e74b61SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
954acb54baSEdgar E. Iglesias     }
964acb54baSEdgar E. Iglesias }
974acb54baSEdgar E. Iglesias 
gen_raise_exception(DisasContext * dc,uint32_t index)9841ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
994acb54baSEdgar E. Iglesias {
100ad75a51eSRichard Henderson     gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
101d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
1024acb54baSEdgar E. Iglesias }
1034acb54baSEdgar E. Iglesias 
gen_raise_exception_sync(DisasContext * dc,uint32_t index)10441ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
10541ba37c4SRichard Henderson {
10641ba37c4SRichard Henderson     t_sync_flags(dc);
107d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
10841ba37c4SRichard Henderson     gen_raise_exception(dc, index);
10941ba37c4SRichard Henderson }
11041ba37c4SRichard Henderson 
gen_raise_hw_excp(DisasContext * dc,uint32_t esr_ec)11141ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
11241ba37c4SRichard Henderson {
113a5ea3dd7SRichard Henderson     TCGv_i32 tmp = tcg_constant_i32(esr_ec);
114ad75a51eSRichard Henderson     tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUMBState, esr));
11541ba37c4SRichard Henderson 
11641ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
11741ba37c4SRichard Henderson }
11841ba37c4SRichard Henderson 
gen_goto_tb(DisasContext * dc,int n,target_ulong dest)1194acb54baSEdgar E. Iglesias static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
1204acb54baSEdgar E. Iglesias {
12166345580SRichard Henderson     if (translator_use_goto_tb(&dc->base, dest)) {
1224acb54baSEdgar E. Iglesias         tcg_gen_goto_tb(n);
1230f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
124d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
1254acb54baSEdgar E. Iglesias     } else {
1260f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1274059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
1284acb54baSEdgar E. Iglesias     }
129d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
1304acb54baSEdgar E. Iglesias }
1314acb54baSEdgar E. Iglesias 
132bdfc1e88SEdgar E. Iglesias /*
1339ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1349ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1359ba8cd45SEdgar E. Iglesias  */
trap_illegal(DisasContext * dc,bool cond)1369ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1379ba8cd45SEdgar E. Iglesias {
1382c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1394b893631SRichard Henderson         && dc->cfg->illegal_opcode_exception) {
14041ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1419ba8cd45SEdgar E. Iglesias     }
1429ba8cd45SEdgar E. Iglesias     return cond;
1439ba8cd45SEdgar E. Iglesias }
1449ba8cd45SEdgar E. Iglesias 
1459ba8cd45SEdgar E. Iglesias /*
146bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
147bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
148bdfc1e88SEdgar E. Iglesias  */
trap_userspace(DisasContext * dc,bool cond)149bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
150bdfc1e88SEdgar E. Iglesias {
151287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
152bdfc1e88SEdgar E. Iglesias 
1532c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
15441ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
155bdfc1e88SEdgar E. Iglesias     }
156bdfc1e88SEdgar E. Iglesias     return cond_user;
157bdfc1e88SEdgar E. Iglesias }
158bdfc1e88SEdgar E. Iglesias 
1592a7567a2SRichard Henderson /*
1602a7567a2SRichard Henderson  * Return true, and log an error, if the current insn is
1612a7567a2SRichard Henderson  * within a delay slot.
1622a7567a2SRichard Henderson  */
invalid_delay_slot(DisasContext * dc,const char * insn_type)1632a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
1642a7567a2SRichard Henderson {
1652a7567a2SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1662a7567a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
1672a7567a2SRichard Henderson                       "Invalid insn in delay slot: %s at %08x\n",
1682a7567a2SRichard Henderson                       insn_type, (uint32_t)dc->base.pc_next);
1692a7567a2SRichard Henderson         return true;
1702a7567a2SRichard Henderson     }
1712a7567a2SRichard Henderson     return false;
1722a7567a2SRichard Henderson }
1732a7567a2SRichard Henderson 
reg_for_read(DisasContext * dc,int reg)17420800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
1754acb54baSEdgar E. Iglesias {
17620800179SRichard Henderson     if (likely(reg != 0)) {
17720800179SRichard Henderson         return cpu_R[reg];
1784acb54baSEdgar E. Iglesias     }
179bd07403fSRichard Henderson     return tcg_constant_i32(0);
18040cbf5b7SEdgar E. Iglesias }
18140cbf5b7SEdgar E. Iglesias 
reg_for_write(DisasContext * dc,int reg)18220800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
18320800179SRichard Henderson {
18420800179SRichard Henderson     if (likely(reg != 0)) {
18520800179SRichard Henderson         return cpu_R[reg];
18620800179SRichard Henderson     }
187bd07403fSRichard Henderson     return tcg_temp_new_i32();
18840cbf5b7SEdgar E. Iglesias }
18940cbf5b7SEdgar E. Iglesias 
do_typea(DisasContext * dc,arg_typea * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32,TCGv_i32))19020800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
19120800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
19220800179SRichard Henderson {
19320800179SRichard Henderson     TCGv_i32 rd, ra, rb;
19420800179SRichard Henderson 
19520800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
19620800179SRichard Henderson         return true;
19740cbf5b7SEdgar E. Iglesias     }
19820800179SRichard Henderson 
19920800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
20020800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
20120800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
20220800179SRichard Henderson     fn(rd, ra, rb);
20320800179SRichard Henderson     return true;
20420800179SRichard Henderson }
20520800179SRichard Henderson 
do_typea0(DisasContext * dc,arg_typea0 * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32))20639cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
20739cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
20839cf3864SRichard Henderson {
20939cf3864SRichard Henderson     TCGv_i32 rd, ra;
21039cf3864SRichard Henderson 
21139cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
21239cf3864SRichard Henderson         return true;
21339cf3864SRichard Henderson     }
21439cf3864SRichard Henderson 
21539cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
21639cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
21739cf3864SRichard Henderson     fn(rd, ra);
21839cf3864SRichard Henderson     return true;
21939cf3864SRichard Henderson }
22039cf3864SRichard Henderson 
do_typeb_imm(DisasContext * dc,arg_typeb * arg,bool side_effects,void (* fni)(TCGv_i32,TCGv_i32,int32_t))22120800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
22220800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
22320800179SRichard Henderson {
22420800179SRichard Henderson     TCGv_i32 rd, ra;
22520800179SRichard Henderson 
22620800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
22720800179SRichard Henderson         return true;
22820800179SRichard Henderson     }
22920800179SRichard Henderson 
23020800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
23120800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
23220800179SRichard Henderson     fni(rd, ra, arg->imm);
23320800179SRichard Henderson     return true;
23420800179SRichard Henderson }
23520800179SRichard Henderson 
do_typeb_val(DisasContext * dc,arg_typeb * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32,TCGv_i32))23620800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
23720800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
23820800179SRichard Henderson {
23920800179SRichard Henderson     TCGv_i32 rd, ra, imm;
24020800179SRichard Henderson 
24120800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24220800179SRichard Henderson         return true;
24320800179SRichard Henderson     }
24420800179SRichard Henderson 
24520800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
24620800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
247a5ea3dd7SRichard Henderson     imm = tcg_constant_i32(arg->imm);
24820800179SRichard Henderson 
24920800179SRichard Henderson     fn(rd, ra, imm);
25020800179SRichard Henderson     return true;
25120800179SRichard Henderson }
25220800179SRichard Henderson 
25320800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
25420800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
25520800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
25620800179SRichard Henderson 
257607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
258607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
2594b893631SRichard Henderson     { return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
260607f5767SRichard Henderson 
26139cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
26239cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
26339cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
26439cf3864SRichard Henderson 
26539cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
26639cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
2674b893631SRichard Henderson     { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
26839cf3864SRichard Henderson 
26920800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
27020800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
27120800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
27220800179SRichard Henderson 
27397955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
27497955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
2754b893631SRichard Henderson     { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
27697955cebSRichard Henderson 
27720800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
27820800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
27920800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
28020800179SRichard Henderson 
281d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
282d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
283ad75a51eSRichard Henderson     { HELPER(out, tcg_env, ina); }
284d5aead3dSRichard Henderson 
285d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
286d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
287ad75a51eSRichard Henderson     { HELPER(out, tcg_env, ina, inb); }
288d5aead3dSRichard Henderson 
28920800179SRichard Henderson /* No input carry, but output carry. */
gen_add(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)29020800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
29120800179SRichard Henderson {
292a5ea3dd7SRichard Henderson     TCGv_i32 zero = tcg_constant_i32(0);
29320800179SRichard Henderson 
29420800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
29520800179SRichard Henderson }
29620800179SRichard Henderson 
29720800179SRichard Henderson /* Input and output carry. */
gen_addc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)29820800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
29920800179SRichard Henderson {
300fcfbd8f4SRichard Henderson     tcg_gen_addcio_i32(out, cpu_msr_c, ina, inb, cpu_msr_c);
30120800179SRichard Henderson }
30220800179SRichard Henderson 
30320800179SRichard Henderson /* Input carry, but no output carry. */
gen_addkc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)30420800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
30520800179SRichard Henderson {
30620800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
30720800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
30820800179SRichard Henderson }
30920800179SRichard Henderson 
DO_TYPEA(add,true,gen_add)31020800179SRichard Henderson DO_TYPEA(add, true, gen_add)
31120800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
31220800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
31320800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
31420800179SRichard Henderson 
31520800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
31620800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
31720800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
31820800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
31920800179SRichard Henderson 
320cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
321cb0a0a4cSRichard Henderson {
322cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
323cb0a0a4cSRichard Henderson }
324cb0a0a4cSRichard Henderson 
DO_TYPEA(and,false,tcg_gen_and_i32)325cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
326cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
327cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
328cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
329cb0a0a4cSRichard Henderson 
330081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
331081d8e02SRichard Henderson {
332081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
333081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
334081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
335081d8e02SRichard Henderson }
336081d8e02SRichard Henderson 
gen_bsrl(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)337081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
338081d8e02SRichard Henderson {
339081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
340081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
341081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
342081d8e02SRichard Henderson }
343081d8e02SRichard Henderson 
gen_bsll(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)344081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
345081d8e02SRichard Henderson {
346081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
347081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
348081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
349081d8e02SRichard Henderson }
350081d8e02SRichard Henderson 
gen_bsefi(TCGv_i32 out,TCGv_i32 ina,int32_t imm)351081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
352081d8e02SRichard Henderson {
353081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
354081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
355081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
356081d8e02SRichard Henderson 
357081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
358081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
359081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
360081d8e02SRichard Henderson                       imm_w, imm_s);
361081d8e02SRichard Henderson     } else {
362081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
363081d8e02SRichard Henderson     }
364081d8e02SRichard Henderson }
365081d8e02SRichard Henderson 
gen_bsifi(TCGv_i32 out,TCGv_i32 ina,int32_t imm)366081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
367081d8e02SRichard Henderson {
368081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
369081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
370081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
371081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
372081d8e02SRichard Henderson 
373081d8e02SRichard Henderson     if (imm_w < imm_s) {
374081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
375081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
376081d8e02SRichard Henderson                       imm_w, imm_s);
377081d8e02SRichard Henderson     } else {
378081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
379081d8e02SRichard Henderson     }
380081d8e02SRichard Henderson }
381081d8e02SRichard Henderson 
DO_TYPEA_CFG(bsra,use_barrel,false,gen_bsra)382081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
383081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
384081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
385081d8e02SRichard Henderson 
386081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
387081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
388081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
389081d8e02SRichard Henderson 
390081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
391081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
392081d8e02SRichard Henderson 
39339cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
39439cf3864SRichard Henderson {
39539cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
39639cf3864SRichard Henderson }
39739cf3864SRichard Henderson 
DO_TYPEA0_CFG(clz,use_pcmp_instr,false,gen_clz)39839cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
39939cf3864SRichard Henderson 
40058b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
40158b48b63SRichard Henderson {
40258b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
40358b48b63SRichard Henderson 
40458b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
40558b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
40658b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
40758b48b63SRichard Henderson }
40858b48b63SRichard Henderson 
gen_cmpu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)40958b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
41058b48b63SRichard Henderson {
41158b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
41258b48b63SRichard Henderson 
41358b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
41458b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
41558b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
41658b48b63SRichard Henderson }
41758b48b63SRichard Henderson 
DO_TYPEA(cmp,false,gen_cmp)41858b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
41958b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
420a2b0b90eSRichard Henderson 
421d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
422d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
423d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
424d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
425d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
426d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
427d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
428d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
429d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
430d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
431d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
432d5aead3dSRichard Henderson 
433d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
434d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
435d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
436d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
437d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
438d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
439d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
440d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
441d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
442d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
443d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
444d5aead3dSRichard Henderson 
445d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
446d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
447d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
448d5aead3dSRichard Henderson 
449d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
450d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
451d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
452d5aead3dSRichard Henderson 
453d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
454b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
455b1354342SRichard Henderson {
456ad75a51eSRichard Henderson     gen_helper_divs(out, tcg_env, inb, ina);
457b1354342SRichard Henderson }
458b1354342SRichard Henderson 
gen_idivu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)459b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
460b1354342SRichard Henderson {
461ad75a51eSRichard Henderson     gen_helper_divu(out, tcg_env, inb, ina);
462b1354342SRichard Henderson }
463b1354342SRichard Henderson 
DO_TYPEA_CFG(idiv,use_div,true,gen_idiv)464b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
465b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
466b1354342SRichard Henderson 
467e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
468e64b2e5cSRichard Henderson {
4692a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "imm")) {
4702a7567a2SRichard Henderson         return true;
4712a7567a2SRichard Henderson     }
472e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
473e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
4746f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
475e64b2e5cSRichard Henderson     return true;
476e64b2e5cSRichard Henderson }
477e64b2e5cSRichard Henderson 
gen_mulh(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)47897955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
47997955cebSRichard Henderson {
48097955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
48197955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
48297955cebSRichard Henderson }
48397955cebSRichard Henderson 
gen_mulhu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)48497955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
48597955cebSRichard Henderson {
48697955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
48797955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
48897955cebSRichard Henderson }
48997955cebSRichard Henderson 
gen_mulhsu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)49097955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
49197955cebSRichard Henderson {
49297955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
49397955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
49497955cebSRichard Henderson }
49597955cebSRichard Henderson 
DO_TYPEA_CFG(mul,use_hw_mul,false,tcg_gen_mul_i32)49697955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
49797955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
49897955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
49997955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
50097955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
50197955cebSRichard Henderson 
502cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
503cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
504cb0a0a4cSRichard Henderson 
505607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
506607f5767SRichard Henderson {
507607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
508607f5767SRichard Henderson }
509607f5767SRichard Henderson 
gen_pcmpne(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)510607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
511607f5767SRichard Henderson {
512607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
513607f5767SRichard Henderson }
514607f5767SRichard Henderson 
DO_TYPEA_CFG(pcmpbf,use_pcmp_instr,false,gen_helper_pcmpbf)515607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
516607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
517607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
518607f5767SRichard Henderson 
519a2b0b90eSRichard Henderson /* No input carry, but output carry. */
520a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
521a2b0b90eSRichard Henderson {
522a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
523a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
524a2b0b90eSRichard Henderson }
525a2b0b90eSRichard Henderson 
526a2b0b90eSRichard Henderson /* Input and output carry. */
gen_rsubc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)527a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
528a2b0b90eSRichard Henderson {
529a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
530a2b0b90eSRichard Henderson 
531a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
532fcfbd8f4SRichard Henderson     tcg_gen_addcio_i32(out, cpu_msr_c, tmp, inb, cpu_msr_c);
533a2b0b90eSRichard Henderson }
534a2b0b90eSRichard Henderson 
535a2b0b90eSRichard Henderson /* No input or output carry. */
gen_rsubk(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)536a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
537a2b0b90eSRichard Henderson {
538a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
539a2b0b90eSRichard Henderson }
540a2b0b90eSRichard Henderson 
541a2b0b90eSRichard Henderson /* Input carry, no output carry. */
gen_rsubkc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)542a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
543a2b0b90eSRichard Henderson {
544a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
545a2b0b90eSRichard Henderson 
546a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
547a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
548a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
549a2b0b90eSRichard Henderson }
550a2b0b90eSRichard Henderson 
DO_TYPEA(rsub,true,gen_rsub)551a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
552a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
553a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
554a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
555a2b0b90eSRichard Henderson 
556a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
557a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
558a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
559a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
560a2b0b90eSRichard Henderson 
56139cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
56239cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
56339cf3864SRichard Henderson 
56439cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
56539cf3864SRichard Henderson {
56639cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
56739cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
56839cf3864SRichard Henderson }
56939cf3864SRichard Henderson 
gen_src(TCGv_i32 out,TCGv_i32 ina)57039cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
57139cf3864SRichard Henderson {
57239cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
57339cf3864SRichard Henderson 
57439cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
57539cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
57639cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
57739cf3864SRichard Henderson }
57839cf3864SRichard Henderson 
gen_srl(TCGv_i32 out,TCGv_i32 ina)57939cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
58039cf3864SRichard Henderson {
58139cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
58239cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
58339cf3864SRichard Henderson }
58439cf3864SRichard Henderson 
DO_TYPEA0(sra,false,gen_sra)58539cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
58639cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
58739cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
58839cf3864SRichard Henderson 
58939cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
59039cf3864SRichard Henderson {
59139cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
59239cf3864SRichard Henderson }
59339cf3864SRichard Henderson 
DO_TYPEA0(swapb,false,tcg_gen_bswap32_i32)59439cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
59539cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
59639cf3864SRichard Henderson 
59739cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
59839cf3864SRichard Henderson {
59939cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
60039cf3864SRichard Henderson     trap_userspace(dc, true);
60139cf3864SRichard Henderson     return true;
60239cf3864SRichard Henderson }
60339cf3864SRichard Henderson 
DO_TYPEA(xor,false,tcg_gen_xor_i32)604cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
605cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
606cb0a0a4cSRichard Henderson 
607d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
608d8e59c4aSRichard Henderson {
609*36a9529eSRichard Henderson     TCGv ret;
610d8e59c4aSRichard Henderson 
611d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
612d8e59c4aSRichard Henderson     if (ra && rb) {
613*36a9529eSRichard Henderson         ret = tcg_temp_new_i32();
614*36a9529eSRichard Henderson         tcg_gen_add_i32(ret, cpu_R[ra], cpu_R[rb]);
615d8e59c4aSRichard Henderson     } else if (ra) {
616*36a9529eSRichard Henderson         ret = cpu_R[ra];
617d8e59c4aSRichard Henderson     } else if (rb) {
618*36a9529eSRichard Henderson         ret = cpu_R[rb];
619d8e59c4aSRichard Henderson     } else {
620*36a9529eSRichard Henderson         ret = tcg_constant_i32(0);
621d8e59c4aSRichard Henderson     }
622d8e59c4aSRichard Henderson 
6234b893631SRichard Henderson     if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
624ad75a51eSRichard Henderson         gen_helper_stackprot(tcg_env, ret);
625d8e59c4aSRichard Henderson     }
626d8e59c4aSRichard Henderson     return ret;
627d8e59c4aSRichard Henderson }
628d8e59c4aSRichard Henderson 
compute_ldst_addr_typeb(DisasContext * dc,int ra,int imm)629d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
630d8e59c4aSRichard Henderson {
631*36a9529eSRichard Henderson     TCGv ret;
632d8e59c4aSRichard Henderson 
633d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
634*36a9529eSRichard Henderson     if (ra && imm) {
635*36a9529eSRichard Henderson         ret = tcg_temp_new_i32();
636*36a9529eSRichard Henderson         tcg_gen_addi_i32(ret, cpu_R[ra], imm);
637*36a9529eSRichard Henderson     } else if (ra) {
638*36a9529eSRichard Henderson         ret = cpu_R[ra];
639d8e59c4aSRichard Henderson     } else {
640*36a9529eSRichard Henderson         ret = tcg_constant_i32(imm);
641d8e59c4aSRichard Henderson     }
642d8e59c4aSRichard Henderson 
6434b893631SRichard Henderson     if (ra == 1 && dc->cfg->stackprot) {
644ad75a51eSRichard Henderson         gen_helper_stackprot(tcg_env, ret);
645d8e59c4aSRichard Henderson     }
646d8e59c4aSRichard Henderson     return ret;
647d8e59c4aSRichard Henderson }
648d8e59c4aSRichard Henderson 
64919f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
compute_ldst_addr_ea(DisasContext * dc,int ra,int rb)65014c1d813SRichard Henderson static TCGv_i64 compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
651d8e59c4aSRichard Henderson {
6524b893631SRichard Henderson     int addr_size = dc->cfg->addr_size;
65314c1d813SRichard Henderson     TCGv_i64 ret = tcg_temp_new_i64();
654d8e59c4aSRichard Henderson 
655d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
656d8e59c4aSRichard Henderson         if (rb) {
65714c1d813SRichard Henderson             tcg_gen_extu_i32_i64(ret, cpu_R[rb]);
658d8e59c4aSRichard Henderson         } else {
65914c1d813SRichard Henderson             return tcg_constant_i64(0);
660d8e59c4aSRichard Henderson         }
661d8e59c4aSRichard Henderson     } else {
662d8e59c4aSRichard Henderson         if (rb) {
663d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
664d8e59c4aSRichard Henderson         } else {
66514c1d813SRichard Henderson             tcg_gen_extu_i32_i64(ret, cpu_R[ra]);
66614c1d813SRichard Henderson             tcg_gen_shli_i64(ret, ret, 32);
667d8e59c4aSRichard Henderson         }
668d8e59c4aSRichard Henderson         if (addr_size < 64) {
669d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
670d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
671d8e59c4aSRichard Henderson         }
672d8e59c4aSRichard Henderson     }
673d8e59c4aSRichard Henderson     return ret;
674d8e59c4aSRichard Henderson }
67519f27b6cSRichard Henderson #endif
676d8e59c4aSRichard Henderson 
677b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
record_unaligned_ess(DisasContext * dc,int rd,MemOp size,bool store)678ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
679ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
680ab0c8d0fSRichard Henderson {
681e2313450SRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->base.insn_start, 1);
682ab0c8d0fSRichard Henderson 
683ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
684ab0c8d0fSRichard Henderson     iflags |= rd << 5;
685ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
686ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
687ab0c8d0fSRichard Henderson 
688e2313450SRichard Henderson     tcg_set_insn_start_param(dc->base.insn_start, 1, iflags);
689ab0c8d0fSRichard Henderson }
690beea7726SRichard Henderson 
gen_alignment_check_ea(DisasContext * dc,TCGv_i64 ea,int rb,int rd,MemOp size,bool store)691beea7726SRichard Henderson static void gen_alignment_check_ea(DisasContext *dc, TCGv_i64 ea, int rb,
692beea7726SRichard Henderson                                    int rd, MemOp size, bool store)
693beea7726SRichard Henderson {
694beea7726SRichard Henderson     if (rb && (dc->tb_flags & MSR_EE) && dc->cfg->unaligned_exceptions) {
695beea7726SRichard Henderson         TCGLabel *over = gen_new_label();
696beea7726SRichard Henderson 
697beea7726SRichard Henderson         record_unaligned_ess(dc, rd, size, store);
698beea7726SRichard Henderson 
699beea7726SRichard Henderson         tcg_gen_brcondi_i64(TCG_COND_TSTEQ, ea, (1 << size) - 1, over);
700beea7726SRichard Henderson         gen_helper_unaligned_access(tcg_env, ea);
701beea7726SRichard Henderson         gen_set_label(over);
702beea7726SRichard Henderson     }
703beea7726SRichard Henderson }
704b414df75SRichard Henderson #endif
705ab0c8d0fSRichard Henderson 
mo_endian(DisasContext * dc)7062c9e8dddSPhilippe Mathieu-Daudé static inline MemOp mo_endian(DisasContext *dc)
7072c9e8dddSPhilippe Mathieu-Daudé {
708415aae54SPhilippe Mathieu-Daudé     return dc->cfg->endi ? MO_LE : MO_BE;
7092c9e8dddSPhilippe Mathieu-Daudé }
7102c9e8dddSPhilippe Mathieu-Daudé 
do_load(DisasContext * dc,int rd,TCGv addr,MemOp mop,int mem_index,bool rev)711d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
712d8e59c4aSRichard Henderson                     int mem_index, bool rev)
713d8e59c4aSRichard Henderson {
714d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
715d8e59c4aSRichard Henderson 
7162c9e8dddSPhilippe Mathieu-Daudé     mop |= mo_endian(dc);
717401bd7d3SPhilippe Mathieu-Daudé 
718d8e59c4aSRichard Henderson     /*
719d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
720d8e59c4aSRichard Henderson      *
721d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
722d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
723d8e59c4aSRichard Henderson      */
724d8e59c4aSRichard Henderson     if (rev) {
725d8e59c4aSRichard Henderson         if (size > MO_8) {
726d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
727d8e59c4aSRichard Henderson         }
728d8e59c4aSRichard Henderson         if (size < MO_32) {
729d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
730d8e59c4aSRichard Henderson         }
731d8e59c4aSRichard Henderson     }
732d8e59c4aSRichard Henderson 
733b414df75SRichard Henderson     /*
734b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
735b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
736b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
737b414df75SRichard Henderson      */
738b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
739ab0c8d0fSRichard Henderson     if (size > MO_8 &&
740ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
7414b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
742ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
743ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
744d8e59c4aSRichard Henderson     }
745b414df75SRichard Henderson #endif
746d8e59c4aSRichard Henderson 
747ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
748d8e59c4aSRichard Henderson     return true;
749d8e59c4aSRichard Henderson }
750d8e59c4aSRichard Henderson 
trans_lbu(DisasContext * dc,arg_typea * arg)751d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
752d8e59c4aSRichard Henderson {
753d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
754d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
755d8e59c4aSRichard Henderson }
756d8e59c4aSRichard Henderson 
trans_lbur(DisasContext * dc,arg_typea * arg)757d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
758d8e59c4aSRichard Henderson {
759d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
760d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
761d8e59c4aSRichard Henderson }
762d8e59c4aSRichard Henderson 
trans_lbuea(DisasContext * dc,arg_typea * arg)763d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
764d8e59c4aSRichard Henderson {
765d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
766d8e59c4aSRichard Henderson         return true;
767d8e59c4aSRichard Henderson     }
76819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
769beea7726SRichard Henderson     g_assert_not_reached();
77019f27b6cSRichard Henderson #else
77114c1d813SRichard Henderson     TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
772beea7726SRichard Henderson     gen_helper_lbuea(reg_for_write(dc, arg->rd), tcg_env, addr);
773beea7726SRichard Henderson     return true;
77419f27b6cSRichard Henderson #endif
775d8e59c4aSRichard Henderson }
776d8e59c4aSRichard Henderson 
trans_lbui(DisasContext * dc,arg_typeb * arg)777d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
778d8e59c4aSRichard Henderson {
779d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
780d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
781d8e59c4aSRichard Henderson }
782d8e59c4aSRichard Henderson 
trans_lhu(DisasContext * dc,arg_typea * arg)783d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
784d8e59c4aSRichard Henderson {
785d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
786401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UW, dc->mem_index, false);
787d8e59c4aSRichard Henderson }
788d8e59c4aSRichard Henderson 
trans_lhur(DisasContext * dc,arg_typea * arg)789d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
790d8e59c4aSRichard Henderson {
791d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
792401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UW, dc->mem_index, true);
793d8e59c4aSRichard Henderson }
794d8e59c4aSRichard Henderson 
trans_lhuea(DisasContext * dc,arg_typea * arg)795d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
796d8e59c4aSRichard Henderson {
797d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
798d8e59c4aSRichard Henderson         return true;
799d8e59c4aSRichard Henderson     }
80019f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
801beea7726SRichard Henderson     g_assert_not_reached();
80219f27b6cSRichard Henderson #else
80314c1d813SRichard Henderson     TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
804beea7726SRichard Henderson     gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_16, false);
805beea7726SRichard Henderson     (mo_endian(dc) == MO_BE ? gen_helper_lhuea_be : gen_helper_lhuea_le)
806beea7726SRichard Henderson         (reg_for_write(dc, arg->rd), tcg_env, addr);
807beea7726SRichard Henderson     return true;
80819f27b6cSRichard Henderson #endif
809d8e59c4aSRichard Henderson }
810d8e59c4aSRichard Henderson 
trans_lhui(DisasContext * dc,arg_typeb * arg)811d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
812d8e59c4aSRichard Henderson {
813d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
814401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UW, dc->mem_index, false);
815d8e59c4aSRichard Henderson }
816d8e59c4aSRichard Henderson 
trans_lw(DisasContext * dc,arg_typea * arg)817d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
818d8e59c4aSRichard Henderson {
819d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
820401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UL, dc->mem_index, false);
821d8e59c4aSRichard Henderson }
822d8e59c4aSRichard Henderson 
trans_lwr(DisasContext * dc,arg_typea * arg)823d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
824d8e59c4aSRichard Henderson {
825d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
826401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UL, dc->mem_index, true);
827d8e59c4aSRichard Henderson }
828d8e59c4aSRichard Henderson 
trans_lwea(DisasContext * dc,arg_typea * arg)829d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
830d8e59c4aSRichard Henderson {
831d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
832d8e59c4aSRichard Henderson         return true;
833d8e59c4aSRichard Henderson     }
83419f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
835beea7726SRichard Henderson     g_assert_not_reached();
83619f27b6cSRichard Henderson #else
83714c1d813SRichard Henderson     TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
838beea7726SRichard Henderson     gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_32, false);
839beea7726SRichard Henderson     (mo_endian(dc) == MO_BE ? gen_helper_lwea_be : gen_helper_lwea_le)
840beea7726SRichard Henderson         (reg_for_write(dc, arg->rd), tcg_env, addr);
841beea7726SRichard Henderson     return true;
84219f27b6cSRichard Henderson #endif
843d8e59c4aSRichard Henderson }
844d8e59c4aSRichard Henderson 
trans_lwi(DisasContext * dc,arg_typeb * arg)845d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
846d8e59c4aSRichard Henderson {
847d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
848401bd7d3SPhilippe Mathieu-Daudé     return do_load(dc, arg->rd, addr, MO_UL, dc->mem_index, false);
849d8e59c4aSRichard Henderson }
850d8e59c4aSRichard Henderson 
trans_lwx(DisasContext * dc,arg_typea * arg)851d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
852d8e59c4aSRichard Henderson {
853d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
854d8e59c4aSRichard Henderson 
855d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
856d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
857d8e59c4aSRichard Henderson 
8582c9e8dddSPhilippe Mathieu-Daudé     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index,
8592c9e8dddSPhilippe Mathieu-Daudé                         mo_endian(dc) | MO_UL);
860d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
861d8e59c4aSRichard Henderson 
862d8e59c4aSRichard Henderson     if (arg->rd) {
863d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
864d8e59c4aSRichard Henderson     }
865d8e59c4aSRichard Henderson 
866d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
867d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
868d8e59c4aSRichard Henderson     return true;
869d8e59c4aSRichard Henderson }
870d8e59c4aSRichard Henderson 
do_store(DisasContext * dc,int rd,TCGv addr,MemOp mop,int mem_index,bool rev)871d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
872d8e59c4aSRichard Henderson                      int mem_index, bool rev)
873d8e59c4aSRichard Henderson {
874d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
875d8e59c4aSRichard Henderson 
8762c9e8dddSPhilippe Mathieu-Daudé     mop |= mo_endian(dc);
877401bd7d3SPhilippe Mathieu-Daudé 
878d8e59c4aSRichard Henderson     /*
879d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
880d8e59c4aSRichard Henderson      *
881d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
882d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
883d8e59c4aSRichard Henderson      */
884d8e59c4aSRichard Henderson     if (rev) {
885d8e59c4aSRichard Henderson         if (size > MO_8) {
886d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
887d8e59c4aSRichard Henderson         }
888d8e59c4aSRichard Henderson         if (size < MO_32) {
889d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
890d8e59c4aSRichard Henderson         }
891d8e59c4aSRichard Henderson     }
892d8e59c4aSRichard Henderson 
893b414df75SRichard Henderson     /*
894b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
895b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
896b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
897b414df75SRichard Henderson      */
898b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
899ab0c8d0fSRichard Henderson     if (size > MO_8 &&
900ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
9014b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
902ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
903ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
904d8e59c4aSRichard Henderson     }
905b414df75SRichard Henderson #endif
906d8e59c4aSRichard Henderson 
907ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
908d8e59c4aSRichard Henderson     return true;
909d8e59c4aSRichard Henderson }
910d8e59c4aSRichard Henderson 
trans_sb(DisasContext * dc,arg_typea * arg)911d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
912d8e59c4aSRichard Henderson {
913d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
914d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
915d8e59c4aSRichard Henderson }
916d8e59c4aSRichard Henderson 
trans_sbr(DisasContext * dc,arg_typea * arg)917d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
918d8e59c4aSRichard Henderson {
919d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
920d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
921d8e59c4aSRichard Henderson }
922d8e59c4aSRichard Henderson 
trans_sbea(DisasContext * dc,arg_typea * arg)923d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
924d8e59c4aSRichard Henderson {
925d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
926d8e59c4aSRichard Henderson         return true;
927d8e59c4aSRichard Henderson     }
92819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
929beea7726SRichard Henderson     g_assert_not_reached();
93019f27b6cSRichard Henderson #else
93114c1d813SRichard Henderson     TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
932beea7726SRichard Henderson     gen_helper_sbea(tcg_env, reg_for_read(dc, arg->rd), addr);
933beea7726SRichard Henderson     return true;
93419f27b6cSRichard Henderson #endif
935d8e59c4aSRichard Henderson }
936d8e59c4aSRichard Henderson 
trans_sbi(DisasContext * dc,arg_typeb * arg)937d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
938d8e59c4aSRichard Henderson {
939d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
940d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
941d8e59c4aSRichard Henderson }
942d8e59c4aSRichard Henderson 
trans_sh(DisasContext * dc,arg_typea * arg)943d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
944d8e59c4aSRichard Henderson {
945d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
946401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UW, dc->mem_index, false);
947d8e59c4aSRichard Henderson }
948d8e59c4aSRichard Henderson 
trans_shr(DisasContext * dc,arg_typea * arg)949d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
950d8e59c4aSRichard Henderson {
951d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
952401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UW, dc->mem_index, true);
953d8e59c4aSRichard Henderson }
954d8e59c4aSRichard Henderson 
trans_shea(DisasContext * dc,arg_typea * arg)955d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
956d8e59c4aSRichard Henderson {
957d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
958d8e59c4aSRichard Henderson         return true;
959d8e59c4aSRichard Henderson     }
96019f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
961beea7726SRichard Henderson     g_assert_not_reached();
96219f27b6cSRichard Henderson #else
96314c1d813SRichard Henderson     TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
964beea7726SRichard Henderson     gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_16, true);
965beea7726SRichard Henderson     (mo_endian(dc) == MO_BE ? gen_helper_shea_be : gen_helper_shea_le)
966beea7726SRichard Henderson         (tcg_env, reg_for_read(dc, arg->rd), addr);
967beea7726SRichard Henderson     return true;
96819f27b6cSRichard Henderson #endif
969d8e59c4aSRichard Henderson }
970d8e59c4aSRichard Henderson 
trans_shi(DisasContext * dc,arg_typeb * arg)971d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
972d8e59c4aSRichard Henderson {
973d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
974401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UW, dc->mem_index, false);
975d8e59c4aSRichard Henderson }
976d8e59c4aSRichard Henderson 
trans_sw(DisasContext * dc,arg_typea * arg)977d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
978d8e59c4aSRichard Henderson {
979d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
980401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UL, dc->mem_index, false);
981d8e59c4aSRichard Henderson }
982d8e59c4aSRichard Henderson 
trans_swr(DisasContext * dc,arg_typea * arg)983d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
984d8e59c4aSRichard Henderson {
985d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
986401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UL, dc->mem_index, true);
987d8e59c4aSRichard Henderson }
988d8e59c4aSRichard Henderson 
trans_swea(DisasContext * dc,arg_typea * arg)989d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
990d8e59c4aSRichard Henderson {
991d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
992d8e59c4aSRichard Henderson         return true;
993d8e59c4aSRichard Henderson     }
99419f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
995beea7726SRichard Henderson     g_assert_not_reached();
99619f27b6cSRichard Henderson #else
99714c1d813SRichard Henderson     TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
998beea7726SRichard Henderson     gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_32, true);
999beea7726SRichard Henderson     (mo_endian(dc) == MO_BE ? gen_helper_swea_be : gen_helper_swea_le)
1000beea7726SRichard Henderson         (tcg_env, reg_for_read(dc, arg->rd), addr);
1001beea7726SRichard Henderson     return true;
100219f27b6cSRichard Henderson #endif
1003d8e59c4aSRichard Henderson }
1004d8e59c4aSRichard Henderson 
trans_swi(DisasContext * dc,arg_typeb * arg)1005d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1006d8e59c4aSRichard Henderson {
1007d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1008401bd7d3SPhilippe Mathieu-Daudé     return do_store(dc, arg->rd, addr, MO_UL, dc->mem_index, false);
1009d8e59c4aSRichard Henderson }
1010d8e59c4aSRichard Henderson 
trans_swx(DisasContext * dc,arg_typea * arg)1011d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1012d8e59c4aSRichard Henderson {
1013d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1014d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1015d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1016d8e59c4aSRichard Henderson     TCGv_i32 tval;
1017d8e59c4aSRichard Henderson 
1018d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1019d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1020d8e59c4aSRichard Henderson 
1021d8e59c4aSRichard Henderson     /*
1022d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1023d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1024d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1025d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1026d8e59c4aSRichard Henderson      */
1027d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1028d8e59c4aSRichard Henderson 
1029d8e59c4aSRichard Henderson     /*
1030d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1031d8e59c4aSRichard Henderson      * the reserved location.
1032d8e59c4aSRichard Henderson      */
1033d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1034d8e59c4aSRichard Henderson 
1035d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1036d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
10372c9e8dddSPhilippe Mathieu-Daudé                                dc->mem_index, mo_endian(dc) | MO_UL);
1038d8e59c4aSRichard Henderson 
1039d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1040d8e59c4aSRichard Henderson 
1041d8e59c4aSRichard Henderson     /* Success */
1042d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1043d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1044d8e59c4aSRichard Henderson 
1045d8e59c4aSRichard Henderson     /* Failure */
1046d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1047d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1048d8e59c4aSRichard Henderson 
1049d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1050d8e59c4aSRichard Henderson 
1051d8e59c4aSRichard Henderson     /*
1052d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1053d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1054d8e59c4aSRichard Henderson      */
1055d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1056d8e59c4aSRichard Henderson     return true;
1057d8e59c4aSRichard Henderson }
1058d8e59c4aSRichard Henderson 
setup_dslot(DisasContext * dc,bool type_b)105916bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
106016bbbbc9SRichard Henderson {
106116bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
106216bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
106316bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
106416bbbbc9SRichard Henderson     }
106516bbbbc9SRichard Henderson }
106616bbbbc9SRichard Henderson 
do_branch(DisasContext * dc,int dest_rb,int dest_imm,bool delay,bool abs,int link)106716bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
106816bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
106916bbbbc9SRichard Henderson {
107016bbbbc9SRichard Henderson     uint32_t add_pc;
107116bbbbc9SRichard Henderson 
10722a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "branch")) {
10732a7567a2SRichard Henderson         return true;
10742a7567a2SRichard Henderson     }
107516bbbbc9SRichard Henderson     if (delay) {
107616bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
107716bbbbc9SRichard Henderson     }
107816bbbbc9SRichard Henderson 
107916bbbbc9SRichard Henderson     if (link) {
108016bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
108116bbbbc9SRichard Henderson     }
108216bbbbc9SRichard Henderson 
108316bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
108416bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
108516bbbbc9SRichard Henderson     if (dest_rb > 0) {
108616bbbbc9SRichard Henderson         dc->jmp_dest = -1;
108716bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
108816bbbbc9SRichard Henderson     } else {
108916bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
109016bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
109116bbbbc9SRichard Henderson     }
109216bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
109316bbbbc9SRichard Henderson     return true;
109416bbbbc9SRichard Henderson }
109516bbbbc9SRichard Henderson 
109616bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
109716bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
109816bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
109916bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
110016bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
110116bbbbc9SRichard Henderson 
DO_BR(br,bri,false,false,false)110216bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
110316bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
110416bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
110516bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
110616bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
110716bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
110816bbbbc9SRichard Henderson 
1109fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1110fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1111fd779113SRichard Henderson {
1112fd779113SRichard Henderson     TCGv_i32 zero, next;
1113fd779113SRichard Henderson 
11142a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "bcc")) {
11152a7567a2SRichard Henderson         return true;
11162a7567a2SRichard Henderson     }
1117fd779113SRichard Henderson     if (delay) {
1118fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1119fd779113SRichard Henderson     }
1120fd779113SRichard Henderson 
1121fd779113SRichard Henderson     dc->jmp_cond = cond;
1122fd779113SRichard Henderson 
1123fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1124fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1125fd779113SRichard Henderson 
1126fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1127fd779113SRichard Henderson     if (dest_rb > 0) {
1128fd779113SRichard Henderson         dc->jmp_dest = -1;
1129fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1130fd779113SRichard Henderson     } else {
1131fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1132fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1133fd779113SRichard Henderson     }
1134fd779113SRichard Henderson 
1135fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1136a5ea3dd7SRichard Henderson     zero = tcg_constant_i32(0);
1137a5ea3dd7SRichard Henderson     next = tcg_constant_i32(dc->base.pc_next + (delay + 1) * 4);
1138fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1139fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1140fd779113SRichard Henderson                         cpu_btarget, next);
1141fd779113SRichard Henderson 
1142fd779113SRichard Henderson     return true;
1143fd779113SRichard Henderson }
1144fd779113SRichard Henderson 
1145fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1146fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1147fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1148fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1149fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1150fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1151fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1152fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1153fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1154fd779113SRichard Henderson 
DO_BCC(beq,TCG_COND_EQ)1155fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1156fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1157fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1158fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1159fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1160fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1161fd779113SRichard Henderson 
1162f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1163f5235314SRichard Henderson {
1164f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1165f5235314SRichard Henderson         return true;
1166f5235314SRichard Henderson     }
11672a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brk")) {
11682a7567a2SRichard Henderson         return true;
11692a7567a2SRichard Henderson     }
11702a7567a2SRichard Henderson 
1171f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1172f5235314SRichard Henderson     if (arg->rd) {
1173f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1174f5235314SRichard Henderson     }
1175f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1176f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1177f5235314SRichard Henderson 
117817e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1179f5235314SRichard Henderson     return true;
1180f5235314SRichard Henderson }
1181f5235314SRichard Henderson 
trans_brki(DisasContext * dc,arg_typeb_br * arg)1182f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1183f5235314SRichard Henderson {
1184f5235314SRichard Henderson     uint32_t imm = arg->imm;
1185f5235314SRichard Henderson 
1186f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1187f5235314SRichard Henderson         return true;
1188f5235314SRichard Henderson     }
11892a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brki")) {
11902a7567a2SRichard Henderson         return true;
11912a7567a2SRichard Henderson     }
11922a7567a2SRichard Henderson 
1193f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1194f5235314SRichard Henderson     if (arg->rd) {
1195f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1196f5235314SRichard Henderson     }
1197f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1198f5235314SRichard Henderson 
1199f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1200f5235314SRichard Henderson     switch (imm) {
1201f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1202f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1203f5235314SRichard Henderson         break;
1204f5235314SRichard Henderson     case 0x18: /* debug trap */
1205f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1206f5235314SRichard Henderson         break;
1207f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1208f5235314SRichard Henderson         g_assert_not_reached();
1209f5235314SRichard Henderson     }
1210f5235314SRichard Henderson #else
1211f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1212f5235314SRichard Henderson 
1213f5235314SRichard Henderson     if (imm != 0x18) {
1214f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1215f5235314SRichard Henderson     }
1216f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1217f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1218f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1219f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1220f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1221f5235314SRichard Henderson     }
1222f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
122317e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1224f5235314SRichard Henderson #endif
1225f5235314SRichard Henderson 
1226f5235314SRichard Henderson     return true;
1227f5235314SRichard Henderson }
1228f5235314SRichard Henderson 
trans_mbar(DisasContext * dc,arg_mbar * arg)1229ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1230ee8c7f9fSRichard Henderson {
1231ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1232ee8c7f9fSRichard Henderson 
12332a7567a2SRichard Henderson     /* Note that mbar is a specialized branch instruction. */
12342a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "mbar")) {
12352a7567a2SRichard Henderson         return true;
12362a7567a2SRichard Henderson     }
12372a7567a2SRichard Henderson 
1238ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1239ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1240ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1241ee8c7f9fSRichard Henderson     }
1242ee8c7f9fSRichard Henderson 
1243ee8c7f9fSRichard Henderson     /* Sleep. */
1244ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1245ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1246ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1247ee8c7f9fSRichard Henderson             return true;
1248ee8c7f9fSRichard Henderson         }
1249ee8c7f9fSRichard Henderson 
1250ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1251ee8c7f9fSRichard Henderson 
1252ad75a51eSRichard Henderson         tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
1253ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1254ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1255ee8c7f9fSRichard Henderson 
1256ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1257ee8c7f9fSRichard Henderson 
1258ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1259ee8c7f9fSRichard Henderson     }
1260ee8c7f9fSRichard Henderson 
1261ee8c7f9fSRichard Henderson     /*
1262ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1263ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1264ee8c7f9fSRichard Henderson      * code immediately.
1265ee8c7f9fSRichard Henderson      *
1266ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1267ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1268ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1269ee8c7f9fSRichard Henderson      *
1270ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1271ee8c7f9fSRichard Henderson      */
127243b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
1273ee8c7f9fSRichard Henderson     return true;
1274ee8c7f9fSRichard Henderson }
1275ee8c7f9fSRichard Henderson 
do_rts(DisasContext * dc,arg_typeb_bc * arg,int to_set)1276e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1277e6cb0354SRichard Henderson {
1278e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1279e6cb0354SRichard Henderson         return true;
1280e6cb0354SRichard Henderson     }
12812a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "rts")) {
12822a7567a2SRichard Henderson         return true;
12832a7567a2SRichard Henderson     }
12842a7567a2SRichard Henderson 
1285e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1286e6cb0354SRichard Henderson     setup_dslot(dc, true);
1287e6cb0354SRichard Henderson 
1288e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1289e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1290e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1291e6cb0354SRichard Henderson     return true;
1292e6cb0354SRichard Henderson }
1293e6cb0354SRichard Henderson 
1294e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1295e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1296e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1297e6cb0354SRichard Henderson 
DO_RTS(rtbd,DRTB_FLAG)1298e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1299e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1300e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1301e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1302e6cb0354SRichard Henderson 
130320800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
130420800179SRichard Henderson {
130520800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
13064b893631SRichard Henderson     if (dc->cfg->opcode_0_illegal) {
130720800179SRichard Henderson         trap_illegal(dc, true);
130820800179SRichard Henderson         return true;
130920800179SRichard Henderson     }
131020800179SRichard Henderson     /*
131120800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
131220800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
131320800179SRichard Henderson      */
131420800179SRichard Henderson     return false;
131540cbf5b7SEdgar E. Iglesias }
13164acb54baSEdgar E. Iglesias 
msr_read(DisasContext * dc,TCGv_i32 d)13171074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
13184acb54baSEdgar E. Iglesias {
13191074c0fbSRichard Henderson     TCGv_i32 t;
13201074c0fbSRichard Henderson 
13211074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
13221074c0fbSRichard Henderson     t = tcg_temp_new_i32();
13231074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13241074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
13254acb54baSEdgar E. Iglesias }
13264acb54baSEdgar E. Iglesias 
do_msrclrset(DisasContext * dc,arg_type_msr * arg,bool set)1327536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1328536e340fSRichard Henderson {
1329536e340fSRichard Henderson     uint32_t imm = arg->imm;
1330536e340fSRichard Henderson 
1331536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1332536e340fSRichard Henderson         return true;
1333536e340fSRichard Henderson     }
1334536e340fSRichard Henderson 
1335536e340fSRichard Henderson     if (arg->rd) {
1336536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1337536e340fSRichard Henderson     }
1338536e340fSRichard Henderson 
1339536e340fSRichard Henderson     /*
1340536e340fSRichard Henderson      * Handle the carry bit separately.
1341536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1342536e340fSRichard Henderson      */
1343536e340fSRichard Henderson     if (imm & MSR_C) {
1344536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1345536e340fSRichard Henderson     }
1346536e340fSRichard Henderson 
1347536e340fSRichard Henderson     /*
1348536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1349536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1350536e340fSRichard Henderson      */
1351536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1352536e340fSRichard Henderson 
1353536e340fSRichard Henderson     if (imm != 0) {
1354536e340fSRichard Henderson         if (set) {
1355536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1356536e340fSRichard Henderson         } else {
1357536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1358536e340fSRichard Henderson         }
135943b34134SRichard Henderson         dc->base.is_jmp = DISAS_EXIT_NEXT;
1360536e340fSRichard Henderson     }
1361536e340fSRichard Henderson     return true;
1362536e340fSRichard Henderson }
1363536e340fSRichard Henderson 
trans_msrclr(DisasContext * dc,arg_type_msr * arg)1364536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1365536e340fSRichard Henderson {
1366536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1367536e340fSRichard Henderson }
1368536e340fSRichard Henderson 
trans_msrset(DisasContext * dc,arg_type_msr * arg)1369536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1370536e340fSRichard Henderson {
1371536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1372536e340fSRichard Henderson }
1373536e340fSRichard Henderson 
trans_mts(DisasContext * dc,arg_mts * arg)13749df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
13754acb54baSEdgar E. Iglesias {
13769df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
13779df297a2SRichard Henderson         return true;
1378f0f7e7f7SEdgar E. Iglesias     }
1379f0f7e7f7SEdgar E. Iglesias 
13809df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
13819df297a2SRichard Henderson     g_assert_not_reached();
13829df297a2SRichard Henderson #else
13839df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
13849df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
13859df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
13869df297a2SRichard Henderson         return true;
13872023e9a3SEdgar E. Iglesias     }
13884acb54baSEdgar E. Iglesias 
13899df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
13909df297a2SRichard Henderson     switch (arg->rs) {
1391aa28e6d4SRichard Henderson     case SR_MSR:
139243b34134SRichard Henderson         /* Install MSR_C.  */
139343b34134SRichard Henderson         tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
139443b34134SRichard Henderson         /*
139543b34134SRichard Henderson          * Clear MSR_C and MSR_CC;
139643b34134SRichard Henderson          * MSR_PVR is not writable, and is always clear.
139743b34134SRichard Henderson          */
139843b34134SRichard Henderson         tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
13994acb54baSEdgar E. Iglesias         break;
14009df297a2SRichard Henderson     case SR_FSR:
1401ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, fsr));
14029df297a2SRichard Henderson         break;
14039df297a2SRichard Henderson     case 0x800:
1404ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, slr));
14059df297a2SRichard Henderson         break;
14069df297a2SRichard Henderson     case 0x802:
1407ad75a51eSRichard Henderson         tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, shr));
14089df297a2SRichard Henderson         break;
14099df297a2SRichard Henderson 
14109df297a2SRichard Henderson     case 0x1000: /* PID */
14119df297a2SRichard Henderson     case 0x1001: /* ZPR */
14129df297a2SRichard Henderson     case 0x1002: /* TLBX */
14139df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14149df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14159df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14169df297a2SRichard Henderson         {
1417a5ea3dd7SRichard Henderson             TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1418a5ea3dd7SRichard Henderson             TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
14199df297a2SRichard Henderson 
1420ad75a51eSRichard Henderson             gen_helper_mmu_write(tcg_env, tmp_ext, tmp_reg, src);
14219df297a2SRichard Henderson         }
14229df297a2SRichard Henderson         break;
14239df297a2SRichard Henderson 
14249df297a2SRichard Henderson     default:
14259df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14269df297a2SRichard Henderson         return true;
14279df297a2SRichard Henderson     }
142843b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
14299df297a2SRichard Henderson     return true;
14309df297a2SRichard Henderson #endif
14319df297a2SRichard Henderson }
14329df297a2SRichard Henderson 
trans_mfs(DisasContext * dc,arg_mfs * arg)14339df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14349df297a2SRichard Henderson {
14359df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
14369df297a2SRichard Henderson 
14379df297a2SRichard Henderson     if (arg->e) {
14389df297a2SRichard Henderson         switch (arg->rs) {
1439351527b7SEdgar E. Iglesias         case SR_EAR:
1440dbdb77c4SRichard Henderson             {
1441dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
1442ad75a51eSRichard Henderson                 tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14439df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1444dbdb77c4SRichard Henderson             }
14459df297a2SRichard Henderson             return true;
14469df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14479df297a2SRichard Henderson         case 0x1003: /* TLBLO */
14489df297a2SRichard Henderson             /* Handled below. */
1449aa28e6d4SRichard Henderson             break;
14509df297a2SRichard Henderson #endif
14519df297a2SRichard Henderson         case 0x2006 ... 0x2009:
14529df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
14539df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
14549df297a2SRichard Henderson             return true;
14554acb54baSEdgar E. Iglesias         default:
14569df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
14579df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
14589df297a2SRichard Henderson             return true;
14594acb54baSEdgar E. Iglesias         }
14609df297a2SRichard Henderson     }
14619df297a2SRichard Henderson 
14629df297a2SRichard Henderson     switch (arg->rs) {
1463aa28e6d4SRichard Henderson     case SR_PC:
14649df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
14654acb54baSEdgar E. Iglesias         break;
1466aa28e6d4SRichard Henderson     case SR_MSR:
14679df297a2SRichard Henderson         msr_read(dc, dest);
14684acb54baSEdgar E. Iglesias         break;
1469351527b7SEdgar E. Iglesias     case SR_EAR:
1470dbdb77c4SRichard Henderson         {
1471dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1472ad75a51eSRichard Henderson             tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14739df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1474a1b48e3aSEdgar E. Iglesias         }
1475aa28e6d4SRichard Henderson         break;
1476351527b7SEdgar E. Iglesias     case SR_ESR:
1477ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, esr));
1478aa28e6d4SRichard Henderson         break;
1479351527b7SEdgar E. Iglesias     case SR_FSR:
1480ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, fsr));
1481aa28e6d4SRichard Henderson         break;
1482351527b7SEdgar E. Iglesias     case SR_BTR:
1483ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, btr));
1484aa28e6d4SRichard Henderson         break;
14857cdae31dSTong Ho     case SR_EDR:
1486ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, edr));
14874acb54baSEdgar E. Iglesias         break;
14885818dee5SEdgar E. Iglesias     case 0x800:
1489ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, slr));
14905818dee5SEdgar E. Iglesias         break;
14915818dee5SEdgar E. Iglesias     case 0x802:
1492ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, shr));
14935818dee5SEdgar E. Iglesias         break;
14949df297a2SRichard Henderson 
14959df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14969df297a2SRichard Henderson     case 0x1000: /* PID */
14979df297a2SRichard Henderson     case 0x1001: /* ZPR */
14989df297a2SRichard Henderson     case 0x1002: /* TLBX */
14999df297a2SRichard Henderson     case 0x1003: /* TLBLO */
15009df297a2SRichard Henderson     case 0x1004: /* TLBHI */
15019df297a2SRichard Henderson     case 0x1005: /* TLBSX */
15029df297a2SRichard Henderson         {
1503a5ea3dd7SRichard Henderson             TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1504a5ea3dd7SRichard Henderson             TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
15059df297a2SRichard Henderson 
1506ad75a51eSRichard Henderson             gen_helper_mmu_read(dest, tcg_env, tmp_ext, tmp_reg);
15079df297a2SRichard Henderson         }
15089df297a2SRichard Henderson         break;
15099df297a2SRichard Henderson #endif
15109df297a2SRichard Henderson 
1511351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
1512ad75a51eSRichard Henderson         tcg_gen_ld_i32(dest, tcg_env,
1513a4bcfc33SRichard Henderson                        offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1514a4bcfc33SRichard Henderson                        - offsetof(MicroBlazeCPU, env));
15154acb54baSEdgar E. Iglesias         break;
15164acb54baSEdgar E. Iglesias     default:
15179df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
15184acb54baSEdgar E. Iglesias         break;
15194acb54baSEdgar E. Iglesias     }
15209df297a2SRichard Henderson     return true;
15214acb54baSEdgar E. Iglesias }
15224acb54baSEdgar E. Iglesias 
do_rti(DisasContext * dc)15233fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
15244acb54baSEdgar E. Iglesias {
15253fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
15264acb54baSEdgar E. Iglesias 
15273fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15283fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15293fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15303fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15313fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15324acb54baSEdgar E. Iglesias }
15334acb54baSEdgar E. Iglesias 
do_rtb(DisasContext * dc)15343fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
15354acb54baSEdgar E. Iglesias {
15363fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
15374acb54baSEdgar E. Iglesias 
15383fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15393fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15403fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15413fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15424acb54baSEdgar E. Iglesias }
15434acb54baSEdgar E. Iglesias 
do_rte(DisasContext * dc)15443fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
15454acb54baSEdgar E. Iglesias {
15463fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
15474acb54baSEdgar E. Iglesias 
15483fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15493fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15503fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15513fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15523fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15534acb54baSEdgar E. Iglesias }
15544acb54baSEdgar E. Iglesias 
15556d76d23eSEdgar E. Iglesias /* Insns connected to FSL or AXI stream attached devices.  */
do_get(DisasContext * dc,int rd,int rb,int imm,int ctrl)155652065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
15576d76d23eSEdgar E. Iglesias {
15586d76d23eSEdgar E. Iglesias     TCGv_i32 t_id, t_ctrl;
15596d76d23eSEdgar E. Iglesias 
1560bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
156152065d8fSRichard Henderson         return true;
15626d76d23eSEdgar E. Iglesias     }
15636d76d23eSEdgar E. Iglesias 
1564cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
156552065d8fSRichard Henderson     if (rb) {
156652065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
15676d76d23eSEdgar E. Iglesias     } else {
156852065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
15696d76d23eSEdgar E. Iglesias     }
15706d76d23eSEdgar E. Iglesias 
1571a5ea3dd7SRichard Henderson     t_ctrl = tcg_constant_i32(ctrl);
157252065d8fSRichard Henderson     gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
157352065d8fSRichard Henderson     return true;
157452065d8fSRichard Henderson }
157552065d8fSRichard Henderson 
trans_get(DisasContext * dc,arg_get * arg)157652065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
157752065d8fSRichard Henderson {
157852065d8fSRichard Henderson     return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
157952065d8fSRichard Henderson }
158052065d8fSRichard Henderson 
trans_getd(DisasContext * dc,arg_getd * arg)158152065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
158252065d8fSRichard Henderson {
158352065d8fSRichard Henderson     return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
158452065d8fSRichard Henderson }
158552065d8fSRichard Henderson 
do_put(DisasContext * dc,int ra,int rb,int imm,int ctrl)158652065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
158752065d8fSRichard Henderson {
158852065d8fSRichard Henderson     TCGv_i32 t_id, t_ctrl;
158952065d8fSRichard Henderson 
159052065d8fSRichard Henderson     if (trap_userspace(dc, true)) {
159152065d8fSRichard Henderson         return true;
159252065d8fSRichard Henderson     }
159352065d8fSRichard Henderson 
159452065d8fSRichard Henderson     t_id = tcg_temp_new_i32();
159552065d8fSRichard Henderson     if (rb) {
159652065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
159752065d8fSRichard Henderson     } else {
159852065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
159952065d8fSRichard Henderson     }
160052065d8fSRichard Henderson 
1601a5ea3dd7SRichard Henderson     t_ctrl = tcg_constant_i32(ctrl);
160252065d8fSRichard Henderson     gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
160352065d8fSRichard Henderson     return true;
160452065d8fSRichard Henderson }
160552065d8fSRichard Henderson 
trans_put(DisasContext * dc,arg_put * arg)160652065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
160752065d8fSRichard Henderson {
160852065d8fSRichard Henderson     return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
160952065d8fSRichard Henderson }
161052065d8fSRichard Henderson 
trans_putd(DisasContext * dc,arg_putd * arg)161152065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
161252065d8fSRichard Henderson {
161352065d8fSRichard Henderson     return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
16146d76d23eSEdgar E. Iglesias }
16156d76d23eSEdgar E. Iglesias 
mb_tr_init_disas_context(DisasContextBase * dcb,CPUState * cs)1616372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
16174acb54baSEdgar E. Iglesias {
1618372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1619372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1620372122e3SRichard Henderson     int bound;
16214acb54baSEdgar E. Iglesias 
16224b893631SRichard Henderson     dc->cfg = &cpu->cfg;
1623683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1624d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
16253b916140SRichard Henderson     dc->mem_index = cpu_mmu_index(cs, false);
1626b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1627b9c58aabSRichard Henderson     dc->jmp_dest = -1;
16284acb54baSEdgar E. Iglesias 
1629372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1630372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1631a47dddd7SAndreas Färber }
16324acb54baSEdgar E. Iglesias 
mb_tr_tb_start(DisasContextBase * dcb,CPUState * cs)1633372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
16344acb54baSEdgar E. Iglesias {
1635b933066aSRichard Henderson }
1636b933066aSRichard Henderson 
mb_tr_insn_start(DisasContextBase * dcb,CPUState * cs)1637372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1638372122e3SRichard Henderson {
1639683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1640683a247eSRichard Henderson 
1641683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1642372122e3SRichard Henderson }
16434acb54baSEdgar E. Iglesias 
mb_tr_translate_insn(DisasContextBase * dcb,CPUState * cs)1644372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1645372122e3SRichard Henderson {
1646372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
164744d1432bSRichard Henderson     uint32_t ir;
1648372122e3SRichard Henderson 
1649372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1650372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1651372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1652372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1653959082fcSRichard Henderson     }
16544acb54baSEdgar E. Iglesias 
16556f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
16566f9642d7SRichard Henderson 
1657415aae54SPhilippe Mathieu-Daudé     ir = translator_ldl_swap(cpu_env(cs), &dc->base, dc->base.pc_next,
1658415aae54SPhilippe Mathieu-Daudé                              mb_cpu_is_big_endian(cs) != TARGET_BIG_ENDIAN);
165944d1432bSRichard Henderson     if (!decode(dc, ir)) {
1660921afa9dSRichard Henderson         trap_illegal(dc, true);
166144d1432bSRichard Henderson     }
166220800179SRichard Henderson 
16636f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
16646f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1665d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1666372122e3SRichard Henderson     }
16676f9642d7SRichard Henderson 
16681e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
16696f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1670d4705ae0SRichard Henderson     dc->base.pc_next += 4;
16714acb54baSEdgar E. Iglesias 
1672b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
16733d35bcc2SRichard Henderson         /*
16743d35bcc2SRichard Henderson          * Finish any return-from branch.
16753d35bcc2SRichard Henderson          */
16763c745866SRichard Henderson         uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16773c745866SRichard Henderson         if (unlikely(rt_ibe != 0)) {
16783c745866SRichard Henderson             dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16793c745866SRichard Henderson             if (rt_ibe & DRTI_FLAG) {
16804acb54baSEdgar E. Iglesias                 do_rti(dc);
16813c745866SRichard Henderson             } else if (rt_ibe & DRTB_FLAG) {
16824acb54baSEdgar E. Iglesias                 do_rtb(dc);
16833c745866SRichard Henderson             } else {
16844acb54baSEdgar E. Iglesias                 do_rte(dc);
1685372122e3SRichard Henderson             }
16863c745866SRichard Henderson         }
16873d35bcc2SRichard Henderson 
16883d35bcc2SRichard Henderson         /* Complete the branch, ending the TB. */
16893d35bcc2SRichard Henderson         switch (dc->base.is_jmp) {
16903d35bcc2SRichard Henderson         case DISAS_NORETURN:
16913d35bcc2SRichard Henderson             /*
16923d35bcc2SRichard Henderson              * E.g. illegal insn in a delay slot.  We've already exited
16933d35bcc2SRichard Henderson              * and will handle D_FLAG in mb_cpu_do_interrupt.
16943d35bcc2SRichard Henderson              */
16953d35bcc2SRichard Henderson             break;
16963d35bcc2SRichard Henderson         case DISAS_NEXT:
16973c745866SRichard Henderson             /*
16983c745866SRichard Henderson              * Normal insn a delay slot.
16993c745866SRichard Henderson              * However, the return-from-exception type insns should
17003c745866SRichard Henderson              * return to the main loop, as they have adjusted MSR.
17013c745866SRichard Henderson              */
17023c745866SRichard Henderson             dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
17033d35bcc2SRichard Henderson             break;
17043d35bcc2SRichard Henderson         case DISAS_EXIT_NEXT:
17053d35bcc2SRichard Henderson             /*
17063d35bcc2SRichard Henderson              * E.g. mts insn in a delay slot.  Continue with btarget,
17073d35bcc2SRichard Henderson              * but still return to the main loop.
17083d35bcc2SRichard Henderson              */
17093d35bcc2SRichard Henderson             dc->base.is_jmp = DISAS_EXIT_JUMP;
17103d35bcc2SRichard Henderson             break;
17113d35bcc2SRichard Henderson         default:
17123d35bcc2SRichard Henderson             g_assert_not_reached();
17133d35bcc2SRichard Henderson         }
1714372122e3SRichard Henderson     }
1715372122e3SRichard Henderson }
1716372122e3SRichard Henderson 
mb_tr_tb_stop(DisasContextBase * dcb,CPUState * cs)1717372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1718372122e3SRichard Henderson {
1719372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1720372122e3SRichard Henderson 
1721372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1722372122e3SRichard Henderson         /* We have already exited the TB. */
1723372122e3SRichard Henderson         return;
1724372122e3SRichard Henderson     }
1725372122e3SRichard Henderson 
1726372122e3SRichard Henderson     t_sync_flags(dc);
1727372122e3SRichard Henderson 
1728372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1729372122e3SRichard Henderson     case DISAS_TOO_MANY:
1730372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1731372122e3SRichard Henderson         return;
1732372122e3SRichard Henderson 
173317e77796SRichard Henderson     case DISAS_EXIT:
1734f6278ca9SRichard Henderson         break;
1735f6278ca9SRichard Henderson     case DISAS_EXIT_NEXT:
1736f6278ca9SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1737f6278ca9SRichard Henderson         break;
1738f6278ca9SRichard Henderson     case DISAS_EXIT_JUMP:
1739f6278ca9SRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1740f6278ca9SRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1741f6278ca9SRichard Henderson         break;
1742372122e3SRichard Henderson 
1743372122e3SRichard Henderson     case DISAS_JUMP:
1744fbafb3a4SRichard Henderson         if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
1745b9c58aabSRichard Henderson             /* Direct jump. */
1746b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1747b9c58aabSRichard Henderson 
1748b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1749b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1750b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1751b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1752b9c58aabSRichard Henderson 
1753b9c58aabSRichard Henderson                 /*
1754b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1755b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1756b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1757b9c58aabSRichard Henderson                  */
1758b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1759b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1760b9c58aabSRichard Henderson 
1761b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1762b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1763b9c58aabSRichard Henderson                 gen_set_label(taken);
1764b9c58aabSRichard Henderson             }
1765b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1766b9c58aabSRichard Henderson             return;
1767b9c58aabSRichard Henderson         }
1768b9c58aabSRichard Henderson 
1769fbafb3a4SRichard Henderson         /* Indirect jump (or direct jump w/ goto_tb disabled) */
1770b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1771b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
17724059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
1773372122e3SRichard Henderson         return;
1774372122e3SRichard Henderson 
1775a2b80dbdSRichard Henderson     default:
1776a2b80dbdSRichard Henderson         g_assert_not_reached();
17774acb54baSEdgar E. Iglesias     }
1778f6278ca9SRichard Henderson 
1779f6278ca9SRichard Henderson     /* Finish DISAS_EXIT_* */
1780f6278ca9SRichard Henderson     if (unlikely(cs->singlestep_enabled)) {
1781f6278ca9SRichard Henderson         gen_raise_exception(dc, EXCP_DEBUG);
1782f6278ca9SRichard Henderson     } else {
1783f6278ca9SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1784f6278ca9SRichard Henderson     }
17854acb54baSEdgar E. Iglesias }
17860a7df5daSRichard Henderson 
1787372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1788372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1789372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1790372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1791372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1792372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1793372122e3SRichard Henderson };
1794372122e3SRichard Henderson 
mb_translate_code(CPUState * cpu,TranslationBlock * tb,int * max_insns,vaddr pc,void * host_pc)1795e4a8e093SRichard Henderson void mb_translate_code(CPUState *cpu, TranslationBlock *tb,
1796e4a8e093SRichard Henderson                        int *max_insns, vaddr pc, void *host_pc)
1797372122e3SRichard Henderson {
1798372122e3SRichard Henderson     DisasContext dc;
1799306c8721SRichard Henderson     translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base);
18004acb54baSEdgar E. Iglesias }
18014acb54baSEdgar E. Iglesias 
mb_cpu_dump_state(CPUState * cs,FILE * f,int flags)180290c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
18034acb54baSEdgar E. Iglesias {
1804da953643SPhilippe Mathieu-Daudé     CPUMBState *env = cpu_env(cs);
18050c3da918SRichard Henderson     uint32_t iflags;
18064acb54baSEdgar E. Iglesias     int i;
18074acb54baSEdgar E. Iglesias 
18080c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18090c3da918SRichard Henderson                  env->pc, env->msr,
18102e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18112e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18122e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18132e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18140c3da918SRichard Henderson 
18150c3da918SRichard Henderson     iflags = env->iflags;
18160c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18170c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18180c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18192ead1b18SJoe Komlodi     }
18200c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18210c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18220c3da918SRichard Henderson     }
18230c3da918SRichard Henderson     if (iflags & D_FLAG) {
1824b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18250c3da918SRichard Henderson     }
18260c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18270c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18280c3da918SRichard Henderson     }
18290c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18300c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18310c3da918SRichard Henderson     }
18320c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18330c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18340c3da918SRichard Henderson     }
18350c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18360c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18372ead1b18SJoe Komlodi     }
183817c52a43SEdgar E. Iglesias 
18390c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
18408cea8bd4SRichard Henderson                  "ear=0x%" PRIx64 " slr=0x%x shr=0x%x\n",
18410c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18420c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18430c3da918SRichard Henderson 
18440c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18450c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18460c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18470c3da918SRichard Henderson     }
18480c3da918SRichard Henderson     qemu_fprintf(f, "\n");
18494acb54baSEdgar E. Iglesias }
18504acb54baSEdgar E. Iglesias 
mb_tcg_init(void)1851cd0c24f9SAndreas Färber void mb_tcg_init(void)
1852cd0c24f9SAndreas Färber {
1853480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1854480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
18554acb54baSEdgar E. Iglesias 
1856480d29a8SRichard Henderson     static const struct {
1857480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1858480d29a8SRichard Henderson     } i32s[] = {
1859e47c2231SRichard Henderson         /*
1860e47c2231SRichard Henderson          * Note that r0 is handled specially in reg_for_read
1861e47c2231SRichard Henderson          * and reg_for_write.  Nothing should touch cpu_R[0].
1862e47c2231SRichard Henderson          * Leave that element NULL, which will assert quickly
1863e47c2231SRichard Henderson          * inside the tcg generator functions.
1864e47c2231SRichard Henderson          */
1865e47c2231SRichard Henderson                R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1866480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1867480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1868480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1869480d29a8SRichard Henderson 
1870480d29a8SRichard Henderson         SP(pc),
1871480d29a8SRichard Henderson         SP(msr),
18721074c0fbSRichard Henderson         SP(msr_c),
1873480d29a8SRichard Henderson         SP(imm),
1874480d29a8SRichard Henderson         SP(iflags),
1875b9c58aabSRichard Henderson         SP(bvalue),
1876480d29a8SRichard Henderson         SP(btarget),
1877480d29a8SRichard Henderson         SP(res_val),
1878480d29a8SRichard Henderson     };
1879480d29a8SRichard Henderson 
1880480d29a8SRichard Henderson #undef R
1881480d29a8SRichard Henderson #undef SP
1882480d29a8SRichard Henderson 
1883480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1884480d29a8SRichard Henderson         *i32s[i].var =
1885ad75a51eSRichard Henderson           tcg_global_mem_new_i32(tcg_env, i32s[i].ofs, i32s[i].name);
18864acb54baSEdgar E. Iglesias     }
188776e8187dSRichard Henderson 
1888480d29a8SRichard Henderson     cpu_res_addr =
1889ad75a51eSRichard Henderson         tcg_global_mem_new(tcg_env, offsetof(CPUMBState, res_addr), "res_addr");
18904acb54baSEdgar E. Iglesias }
1891