1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth * Xilinx MicroBlaze emulation for qemu: main translation routines.
3fcf5ef2aSThomas Huth *
4fcf5ef2aSThomas Huth * Copyright (c) 2009 Edgar E. Iglesias.
5fcf5ef2aSThomas Huth * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
6fcf5ef2aSThomas Huth *
7fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either
10ee452036SChetan Pant * version 2.1 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth *
12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15fcf5ef2aSThomas Huth * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth *
17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth */
20fcf5ef2aSThomas Huth
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "exec/exec-all.h"
244597463bSPhilippe Mathieu-Daudé #include "exec/cpu_ldst.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
26fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
27fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
2877fc6f5eSLluís Vilanova #include "exec/translator.h"
2990c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
30fcf5ef2aSThomas Huth
31fcf5ef2aSThomas Huth #include "exec/log.h"
32fcf5ef2aSThomas Huth
33d53106c9SRichard Henderson #define HELPER_H "helper.h"
34d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
35d53106c9SRichard Henderson #undef HELPER_H
36d53106c9SRichard Henderson
37fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
38fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1))
39fcf5ef2aSThomas Huth
4077fc6f5eSLluís Vilanova /* is_jmp field values */
4177fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
4217e77796SRichard Henderson #define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */
4377fc6f5eSLluís Vilanova
44f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */
45f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2
46f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */
47f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3
48f6278ca9SRichard Henderson
49cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
500f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
513e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
521074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
539b158558SRichard Henderson static TCGv_i32 cpu_imm;
54b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
550f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
569b158558SRichard Henderson static TCGv_i32 cpu_iflags;
579b158558SRichard Henderson static TCGv cpu_res_addr;
589b158558SRichard Henderson static TCGv_i32 cpu_res_val;
59fcf5ef2aSThomas Huth
60fcf5ef2aSThomas Huth /* This is the state at translation time. */
61fcf5ef2aSThomas Huth typedef struct DisasContext {
62d4705ae0SRichard Henderson DisasContextBase base;
634b893631SRichard Henderson const MicroBlazeCPUConfig *cfg;
64fcf5ef2aSThomas Huth
6520800179SRichard Henderson TCGv_i32 r0;
6620800179SRichard Henderson bool r0_set;
6720800179SRichard Henderson
68fcf5ef2aSThomas Huth /* Decoder. */
69d7ecb757SRichard Henderson uint32_t ext_imm;
70683a247eSRichard Henderson unsigned int tb_flags;
716f9642d7SRichard Henderson unsigned int tb_flags_to_set;
72287b1defSRichard Henderson int mem_index;
73fcf5ef2aSThomas Huth
74b9c58aabSRichard Henderson /* Condition under which to jump, including NEVER and ALWAYS. */
75b9c58aabSRichard Henderson TCGCond jmp_cond;
76b9c58aabSRichard Henderson
77b9c58aabSRichard Henderson /* Immediate branch-taken destination, or -1 for indirect. */
78b9c58aabSRichard Henderson uint32_t jmp_dest;
79fcf5ef2aSThomas Huth } DisasContext;
80fcf5ef2aSThomas Huth
typeb_imm(DisasContext * dc,int x)8120800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8220800179SRichard Henderson {
8320800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) {
8420800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x);
8520800179SRichard Henderson }
8620800179SRichard Henderson return x;
8720800179SRichard Henderson }
8820800179SRichard Henderson
8944d1432bSRichard Henderson /* Include the auto-generated decoder. */
9044d1432bSRichard Henderson #include "decode-insns.c.inc"
9144d1432bSRichard Henderson
t_sync_flags(DisasContext * dc)92683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
93fcf5ef2aSThomas Huth {
94fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */
9588e74b61SRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
9688e74b61SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
97fcf5ef2aSThomas Huth }
98fcf5ef2aSThomas Huth }
99fcf5ef2aSThomas Huth
gen_raise_exception(DisasContext * dc,uint32_t index)10041ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
101fcf5ef2aSThomas Huth {
102ad75a51eSRichard Henderson gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
103d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN;
104fcf5ef2aSThomas Huth }
105fcf5ef2aSThomas Huth
gen_raise_exception_sync(DisasContext * dc,uint32_t index)10641ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
10741ba37c4SRichard Henderson {
10841ba37c4SRichard Henderson t_sync_flags(dc);
109d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
11041ba37c4SRichard Henderson gen_raise_exception(dc, index);
11141ba37c4SRichard Henderson }
11241ba37c4SRichard Henderson
gen_raise_hw_excp(DisasContext * dc,uint32_t esr_ec)11341ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
11441ba37c4SRichard Henderson {
115a5ea3dd7SRichard Henderson TCGv_i32 tmp = tcg_constant_i32(esr_ec);
116ad75a51eSRichard Henderson tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUMBState, esr));
11741ba37c4SRichard Henderson
11841ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP);
11941ba37c4SRichard Henderson }
12041ba37c4SRichard Henderson
gen_goto_tb(DisasContext * dc,int n,target_ulong dest)121fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
122fcf5ef2aSThomas Huth {
12366345580SRichard Henderson if (translator_use_goto_tb(&dc->base, dest)) {
124fcf5ef2aSThomas Huth tcg_gen_goto_tb(n);
1250f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest);
126d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n);
127fcf5ef2aSThomas Huth } else {
1280f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest);
1294059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr();
130fcf5ef2aSThomas Huth }
131d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN;
132fcf5ef2aSThomas Huth }
133fcf5ef2aSThomas Huth
134bdfc1e88SEdgar E. Iglesias /*
1359ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation.
1369ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised.
1379ba8cd45SEdgar E. Iglesias */
trap_illegal(DisasContext * dc,bool cond)1389ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1399ba8cd45SEdgar E. Iglesias {
1402c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE)
1414b893631SRichard Henderson && dc->cfg->illegal_opcode_exception) {
14241ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1439ba8cd45SEdgar E. Iglesias }
1449ba8cd45SEdgar E. Iglesias return cond;
1459ba8cd45SEdgar E. Iglesias }
1469ba8cd45SEdgar E. Iglesias
1479ba8cd45SEdgar E. Iglesias /*
148bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace.
149bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised.
150bdfc1e88SEdgar E. Iglesias */
trap_userspace(DisasContext * dc,bool cond)151bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
152bdfc1e88SEdgar E. Iglesias {
153287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
154bdfc1e88SEdgar E. Iglesias
1552c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) {
15641ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
157bdfc1e88SEdgar E. Iglesias }
158bdfc1e88SEdgar E. Iglesias return cond_user;
159bdfc1e88SEdgar E. Iglesias }
160bdfc1e88SEdgar E. Iglesias
1612a7567a2SRichard Henderson /*
1622a7567a2SRichard Henderson * Return true, and log an error, if the current insn is
1632a7567a2SRichard Henderson * within a delay slot.
1642a7567a2SRichard Henderson */
invalid_delay_slot(DisasContext * dc,const char * insn_type)1652a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
1662a7567a2SRichard Henderson {
1672a7567a2SRichard Henderson if (dc->tb_flags & D_FLAG) {
1682a7567a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR,
1692a7567a2SRichard Henderson "Invalid insn in delay slot: %s at %08x\n",
1702a7567a2SRichard Henderson insn_type, (uint32_t)dc->base.pc_next);
1712a7567a2SRichard Henderson return true;
1722a7567a2SRichard Henderson }
1732a7567a2SRichard Henderson return false;
1742a7567a2SRichard Henderson }
1752a7567a2SRichard Henderson
reg_for_read(DisasContext * dc,int reg)17620800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
177fcf5ef2aSThomas Huth {
17820800179SRichard Henderson if (likely(reg != 0)) {
17920800179SRichard Henderson return cpu_R[reg];
180fcf5ef2aSThomas Huth }
18120800179SRichard Henderson if (!dc->r0_set) {
18220800179SRichard Henderson if (dc->r0 == NULL) {
18320800179SRichard Henderson dc->r0 = tcg_temp_new_i32();
184fcf5ef2aSThomas Huth }
18520800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0);
18620800179SRichard Henderson dc->r0_set = true;
18720800179SRichard Henderson }
18820800179SRichard Henderson return dc->r0;
189fcf5ef2aSThomas Huth }
190fcf5ef2aSThomas Huth
reg_for_write(DisasContext * dc,int reg)19120800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
19220800179SRichard Henderson {
19320800179SRichard Henderson if (likely(reg != 0)) {
19420800179SRichard Henderson return cpu_R[reg];
19520800179SRichard Henderson }
19620800179SRichard Henderson if (dc->r0 == NULL) {
19720800179SRichard Henderson dc->r0 = tcg_temp_new_i32();
19820800179SRichard Henderson }
19920800179SRichard Henderson return dc->r0;
200fcf5ef2aSThomas Huth }
201fcf5ef2aSThomas Huth
do_typea(DisasContext * dc,arg_typea * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32,TCGv_i32))20220800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
20320800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
20420800179SRichard Henderson {
20520800179SRichard Henderson TCGv_i32 rd, ra, rb;
20620800179SRichard Henderson
20720800179SRichard Henderson if (arg->rd == 0 && !side_effects) {
20820800179SRichard Henderson return true;
209fcf5ef2aSThomas Huth }
21020800179SRichard Henderson
21120800179SRichard Henderson rd = reg_for_write(dc, arg->rd);
21220800179SRichard Henderson ra = reg_for_read(dc, arg->ra);
21320800179SRichard Henderson rb = reg_for_read(dc, arg->rb);
21420800179SRichard Henderson fn(rd, ra, rb);
21520800179SRichard Henderson return true;
21620800179SRichard Henderson }
21720800179SRichard Henderson
do_typea0(DisasContext * dc,arg_typea0 * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32))21839cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
21939cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32))
22039cf3864SRichard Henderson {
22139cf3864SRichard Henderson TCGv_i32 rd, ra;
22239cf3864SRichard Henderson
22339cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) {
22439cf3864SRichard Henderson return true;
22539cf3864SRichard Henderson }
22639cf3864SRichard Henderson
22739cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd);
22839cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra);
22939cf3864SRichard Henderson fn(rd, ra);
23039cf3864SRichard Henderson return true;
23139cf3864SRichard Henderson }
23239cf3864SRichard Henderson
do_typeb_imm(DisasContext * dc,arg_typeb * arg,bool side_effects,void (* fni)(TCGv_i32,TCGv_i32,int32_t))23320800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
23420800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t))
23520800179SRichard Henderson {
23620800179SRichard Henderson TCGv_i32 rd, ra;
23720800179SRichard Henderson
23820800179SRichard Henderson if (arg->rd == 0 && !side_effects) {
23920800179SRichard Henderson return true;
24020800179SRichard Henderson }
24120800179SRichard Henderson
24220800179SRichard Henderson rd = reg_for_write(dc, arg->rd);
24320800179SRichard Henderson ra = reg_for_read(dc, arg->ra);
24420800179SRichard Henderson fni(rd, ra, arg->imm);
24520800179SRichard Henderson return true;
24620800179SRichard Henderson }
24720800179SRichard Henderson
do_typeb_val(DisasContext * dc,arg_typeb * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32,TCGv_i32))24820800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
24920800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
25020800179SRichard Henderson {
25120800179SRichard Henderson TCGv_i32 rd, ra, imm;
25220800179SRichard Henderson
25320800179SRichard Henderson if (arg->rd == 0 && !side_effects) {
25420800179SRichard Henderson return true;
25520800179SRichard Henderson }
25620800179SRichard Henderson
25720800179SRichard Henderson rd = reg_for_write(dc, arg->rd);
25820800179SRichard Henderson ra = reg_for_read(dc, arg->ra);
259a5ea3dd7SRichard Henderson imm = tcg_constant_i32(arg->imm);
26020800179SRichard Henderson
26120800179SRichard Henderson fn(rd, ra, imm);
26220800179SRichard Henderson return true;
26320800179SRichard Henderson }
26420800179SRichard Henderson
26520800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
26620800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
26720800179SRichard Henderson { return do_typea(dc, a, SE, FN); }
26820800179SRichard Henderson
269607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
270607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
2714b893631SRichard Henderson { return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
272607f5767SRichard Henderson
27339cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
27439cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
27539cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); }
27639cf3864SRichard Henderson
27739cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
27839cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
2794b893631SRichard Henderson { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
28039cf3864SRichard Henderson
28120800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
28220800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
28320800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); }
28420800179SRichard Henderson
28597955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
28697955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
2874b893631SRichard Henderson { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
28897955cebSRichard Henderson
28920800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
29020800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29120800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); }
29220800179SRichard Henderson
293d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
294d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \
295ad75a51eSRichard Henderson { HELPER(out, tcg_env, ina); }
296d5aead3dSRichard Henderson
297d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
298d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
299ad75a51eSRichard Henderson { HELPER(out, tcg_env, ina, inb); }
300d5aead3dSRichard Henderson
30120800179SRichard Henderson /* No input carry, but output carry. */
gen_add(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)30220800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
30320800179SRichard Henderson {
304a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0);
30520800179SRichard Henderson
30620800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
30720800179SRichard Henderson }
30820800179SRichard Henderson
30920800179SRichard Henderson /* Input and output carry. */
gen_addc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)31020800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
31120800179SRichard Henderson {
312a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0);
31320800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
31420800179SRichard Henderson
31520800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
31620800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
31720800179SRichard Henderson }
31820800179SRichard Henderson
31920800179SRichard Henderson /* Input carry, but no output carry. */
gen_addkc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)32020800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
32120800179SRichard Henderson {
32220800179SRichard Henderson tcg_gen_add_i32(out, ina, inb);
32320800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c);
32420800179SRichard Henderson }
32520800179SRichard Henderson
DO_TYPEA(add,true,gen_add)32620800179SRichard Henderson DO_TYPEA(add, true, gen_add)
32720800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
32820800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
32920800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
33020800179SRichard Henderson
33120800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
33220800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
33320800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
33420800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
33520800179SRichard Henderson
336cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
337cb0a0a4cSRichard Henderson {
338cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm);
339cb0a0a4cSRichard Henderson }
340cb0a0a4cSRichard Henderson
DO_TYPEA(and,false,tcg_gen_and_i32)341cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
342cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
343cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
344cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
345cb0a0a4cSRichard Henderson
346081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
347081d8e02SRichard Henderson {
348081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
349081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31);
350081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp);
351081d8e02SRichard Henderson }
352081d8e02SRichard Henderson
gen_bsrl(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)353081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
354081d8e02SRichard Henderson {
355081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
356081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31);
357081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp);
358081d8e02SRichard Henderson }
359081d8e02SRichard Henderson
gen_bsll(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)360081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
361081d8e02SRichard Henderson {
362081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
363081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31);
364081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp);
365081d8e02SRichard Henderson }
366081d8e02SRichard Henderson
gen_bsefi(TCGv_i32 out,TCGv_i32 ina,int32_t imm)367081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
368081d8e02SRichard Henderson {
369081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
370081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5);
371081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5);
372081d8e02SRichard Henderson
373081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) {
374081d8e02SRichard Henderson /* These inputs have an undefined behavior. */
375081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
376081d8e02SRichard Henderson imm_w, imm_s);
377081d8e02SRichard Henderson } else {
378081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w);
379081d8e02SRichard Henderson }
380081d8e02SRichard Henderson }
381081d8e02SRichard Henderson
gen_bsifi(TCGv_i32 out,TCGv_i32 ina,int32_t imm)382081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
383081d8e02SRichard Henderson {
384081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
385081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5);
386081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5);
387081d8e02SRichard Henderson int width = imm_w - imm_s + 1;
388081d8e02SRichard Henderson
389081d8e02SRichard Henderson if (imm_w < imm_s) {
390081d8e02SRichard Henderson /* These inputs have an undefined behavior. */
391081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
392081d8e02SRichard Henderson imm_w, imm_s);
393081d8e02SRichard Henderson } else {
394081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width);
395081d8e02SRichard Henderson }
396081d8e02SRichard Henderson }
397081d8e02SRichard Henderson
DO_TYPEA_CFG(bsra,use_barrel,false,gen_bsra)398081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
399081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
400081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
401081d8e02SRichard Henderson
402081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
403081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
404081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
405081d8e02SRichard Henderson
406081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
407081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
408081d8e02SRichard Henderson
40939cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
41039cf3864SRichard Henderson {
41139cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32);
41239cf3864SRichard Henderson }
41339cf3864SRichard Henderson
DO_TYPEA0_CFG(clz,use_pcmp_instr,false,gen_clz)41439cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
41539cf3864SRichard Henderson
41658b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
41758b48b63SRichard Henderson {
41858b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32();
41958b48b63SRichard Henderson
42058b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
42158b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina);
42258b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1);
42358b48b63SRichard Henderson }
42458b48b63SRichard Henderson
gen_cmpu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)42558b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
42658b48b63SRichard Henderson {
42758b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32();
42858b48b63SRichard Henderson
42958b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
43058b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina);
43158b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1);
43258b48b63SRichard Henderson }
43358b48b63SRichard Henderson
DO_TYPEA(cmp,false,gen_cmp)43458b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
43558b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
436a2b0b90eSRichard Henderson
437d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
438d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
439d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
440d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
441d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
442d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
443d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
444d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
445d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
446d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
447d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
448d5aead3dSRichard Henderson
449d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
450d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
451d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
452d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
453d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
454d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
455d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
456d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
457d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
458d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
459d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
460d5aead3dSRichard Henderson
461d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
462d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
463d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
464d5aead3dSRichard Henderson
465d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
466d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
467d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
468d5aead3dSRichard Henderson
469d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
470b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
471b1354342SRichard Henderson {
472ad75a51eSRichard Henderson gen_helper_divs(out, tcg_env, inb, ina);
473b1354342SRichard Henderson }
474b1354342SRichard Henderson
gen_idivu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)475b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
476b1354342SRichard Henderson {
477ad75a51eSRichard Henderson gen_helper_divu(out, tcg_env, inb, ina);
478b1354342SRichard Henderson }
479b1354342SRichard Henderson
DO_TYPEA_CFG(idiv,use_div,true,gen_idiv)480b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
481b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
482b1354342SRichard Henderson
483e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
484e64b2e5cSRichard Henderson {
4852a7567a2SRichard Henderson if (invalid_delay_slot(dc, "imm")) {
4862a7567a2SRichard Henderson return true;
4872a7567a2SRichard Henderson }
488e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16;
489e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
4906f9642d7SRichard Henderson dc->tb_flags_to_set = IMM_FLAG;
491e64b2e5cSRichard Henderson return true;
492e64b2e5cSRichard Henderson }
493e64b2e5cSRichard Henderson
gen_mulh(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)49497955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
49597955cebSRichard Henderson {
49697955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
49797955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb);
49897955cebSRichard Henderson }
49997955cebSRichard Henderson
gen_mulhu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)50097955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
50197955cebSRichard Henderson {
50297955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
50397955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb);
50497955cebSRichard Henderson }
50597955cebSRichard Henderson
gen_mulhsu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)50697955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
50797955cebSRichard Henderson {
50897955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
50997955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb);
51097955cebSRichard Henderson }
51197955cebSRichard Henderson
DO_TYPEA_CFG(mul,use_hw_mul,false,tcg_gen_mul_i32)51297955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
51397955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
51497955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
51597955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
51697955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
51797955cebSRichard Henderson
518cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
519cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
520cb0a0a4cSRichard Henderson
521607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
522607f5767SRichard Henderson {
523607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
524607f5767SRichard Henderson }
525607f5767SRichard Henderson
gen_pcmpne(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)526607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
527607f5767SRichard Henderson {
528607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
529607f5767SRichard Henderson }
530607f5767SRichard Henderson
DO_TYPEA_CFG(pcmpbf,use_pcmp_instr,false,gen_helper_pcmpbf)531607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
532607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
533607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
534607f5767SRichard Henderson
535a2b0b90eSRichard Henderson /* No input carry, but output carry. */
536a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
537a2b0b90eSRichard Henderson {
538a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
539a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina);
540a2b0b90eSRichard Henderson }
541a2b0b90eSRichard Henderson
542a2b0b90eSRichard Henderson /* Input and output carry. */
gen_rsubc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)543a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
544a2b0b90eSRichard Henderson {
545a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0);
546a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
547a2b0b90eSRichard Henderson
548a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina);
549a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
550a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
551a2b0b90eSRichard Henderson }
552a2b0b90eSRichard Henderson
553a2b0b90eSRichard Henderson /* No input or output carry. */
gen_rsubk(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)554a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
555a2b0b90eSRichard Henderson {
556a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina);
557a2b0b90eSRichard Henderson }
558a2b0b90eSRichard Henderson
559a2b0b90eSRichard Henderson /* Input carry, no output carry. */
gen_rsubkc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)560a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
561a2b0b90eSRichard Henderson {
562a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32();
563a2b0b90eSRichard Henderson
564a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina);
565a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota);
566a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c);
567a2b0b90eSRichard Henderson }
568a2b0b90eSRichard Henderson
DO_TYPEA(rsub,true,gen_rsub)569a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
570a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
571a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
572a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
573a2b0b90eSRichard Henderson
574a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
575a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
576a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
577a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
578a2b0b90eSRichard Henderson
57939cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
58039cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
58139cf3864SRichard Henderson
58239cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
58339cf3864SRichard Henderson {
58439cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1);
58539cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1);
58639cf3864SRichard Henderson }
58739cf3864SRichard Henderson
gen_src(TCGv_i32 out,TCGv_i32 ina)58839cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
58939cf3864SRichard Henderson {
59039cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
59139cf3864SRichard Henderson
59239cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c);
59339cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1);
59439cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1);
59539cf3864SRichard Henderson }
59639cf3864SRichard Henderson
gen_srl(TCGv_i32 out,TCGv_i32 ina)59739cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
59839cf3864SRichard Henderson {
59939cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1);
60039cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1);
60139cf3864SRichard Henderson }
60239cf3864SRichard Henderson
DO_TYPEA0(sra,false,gen_sra)60339cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
60439cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
60539cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
60639cf3864SRichard Henderson
60739cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
60839cf3864SRichard Henderson {
60939cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16);
61039cf3864SRichard Henderson }
61139cf3864SRichard Henderson
DO_TYPEA0(swapb,false,tcg_gen_bswap32_i32)61239cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
61339cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
61439cf3864SRichard Henderson
61539cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
61639cf3864SRichard Henderson {
61739cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */
61839cf3864SRichard Henderson trap_userspace(dc, true);
61939cf3864SRichard Henderson return true;
62039cf3864SRichard Henderson }
62139cf3864SRichard Henderson
DO_TYPEA(xor,false,tcg_gen_xor_i32)622cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
623cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
624cb0a0a4cSRichard Henderson
625d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
626d8e59c4aSRichard Henderson {
627d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new();
628d8e59c4aSRichard Henderson
629d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */
630d8e59c4aSRichard Henderson if (ra && rb) {
631d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
632d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
633d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp);
634d8e59c4aSRichard Henderson } else if (ra) {
635d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
636d8e59c4aSRichard Henderson } else if (rb) {
637d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
638d8e59c4aSRichard Henderson } else {
639d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0);
640d8e59c4aSRichard Henderson }
641d8e59c4aSRichard Henderson
6424b893631SRichard Henderson if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
643ad75a51eSRichard Henderson gen_helper_stackprot(tcg_env, ret);
644d8e59c4aSRichard Henderson }
645d8e59c4aSRichard Henderson return ret;
646d8e59c4aSRichard Henderson }
647d8e59c4aSRichard Henderson
compute_ldst_addr_typeb(DisasContext * dc,int ra,int imm)648d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
649d8e59c4aSRichard Henderson {
650d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new();
651d8e59c4aSRichard Henderson
652d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */
653d8e59c4aSRichard Henderson if (ra) {
654d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
655d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
656d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp);
657d8e59c4aSRichard Henderson } else {
658d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm);
659d8e59c4aSRichard Henderson }
660d8e59c4aSRichard Henderson
6614b893631SRichard Henderson if (ra == 1 && dc->cfg->stackprot) {
662ad75a51eSRichard Henderson gen_helper_stackprot(tcg_env, ret);
663d8e59c4aSRichard Henderson }
664d8e59c4aSRichard Henderson return ret;
665d8e59c4aSRichard Henderson }
666d8e59c4aSRichard Henderson
66719f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
compute_ldst_addr_ea(DisasContext * dc,int ra,int rb)668d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
669d8e59c4aSRichard Henderson {
6704b893631SRichard Henderson int addr_size = dc->cfg->addr_size;
671d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new();
672d8e59c4aSRichard Henderson
673d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) {
674d8e59c4aSRichard Henderson if (rb) {
675d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
676d8e59c4aSRichard Henderson } else {
677d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0);
678d8e59c4aSRichard Henderson }
679d8e59c4aSRichard Henderson } else {
680d8e59c4aSRichard Henderson if (rb) {
681d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
682d8e59c4aSRichard Henderson } else {
683d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
684d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32);
685d8e59c4aSRichard Henderson }
686d8e59c4aSRichard Henderson if (addr_size < 64) {
687d8e59c4aSRichard Henderson /* Mask off out of range bits. */
688d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
689d8e59c4aSRichard Henderson }
690d8e59c4aSRichard Henderson }
691d8e59c4aSRichard Henderson return ret;
692d8e59c4aSRichard Henderson }
69319f27b6cSRichard Henderson #endif
694d8e59c4aSRichard Henderson
695b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
record_unaligned_ess(DisasContext * dc,int rd,MemOp size,bool store)696ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
697ab0c8d0fSRichard Henderson MemOp size, bool store)
698ab0c8d0fSRichard Henderson {
699e2313450SRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->base.insn_start, 1);
700ab0c8d0fSRichard Henderson
701ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG;
702ab0c8d0fSRichard Henderson iflags |= rd << 5;
703ab0c8d0fSRichard Henderson iflags |= store * ESR_S;
704ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W;
705ab0c8d0fSRichard Henderson
706e2313450SRichard Henderson tcg_set_insn_start_param(dc->base.insn_start, 1, iflags);
707ab0c8d0fSRichard Henderson }
708b414df75SRichard Henderson #endif
709ab0c8d0fSRichard Henderson
do_load(DisasContext * dc,int rd,TCGv addr,MemOp mop,int mem_index,bool rev)710d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
711d8e59c4aSRichard Henderson int mem_index, bool rev)
712d8e59c4aSRichard Henderson {
713d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE;
714d8e59c4aSRichard Henderson
715d8e59c4aSRichard Henderson /*
716d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things.
717d8e59c4aSRichard Henderson *
718d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness.
719d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core.
720d8e59c4aSRichard Henderson */
721d8e59c4aSRichard Henderson if (rev) {
722d8e59c4aSRichard Henderson if (size > MO_8) {
723d8e59c4aSRichard Henderson mop ^= MO_BSWAP;
724d8e59c4aSRichard Henderson }
725d8e59c4aSRichard Henderson if (size < MO_32) {
726d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size);
727d8e59c4aSRichard Henderson }
728d8e59c4aSRichard Henderson }
729d8e59c4aSRichard Henderson
730b414df75SRichard Henderson /*
731b414df75SRichard Henderson * For system mode, enforce alignment if the cpu configuration
732b414df75SRichard Henderson * requires it. For user-mode, the Linux kernel will have fixed up
733b414df75SRichard Henderson * any unaligned access, so emulate that by *not* setting MO_ALIGN.
734b414df75SRichard Henderson */
735b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
736ab0c8d0fSRichard Henderson if (size > MO_8 &&
737ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) &&
7384b893631SRichard Henderson dc->cfg->unaligned_exceptions) {
739ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false);
740ab0c8d0fSRichard Henderson mop |= MO_ALIGN;
741d8e59c4aSRichard Henderson }
742b414df75SRichard Henderson #endif
743d8e59c4aSRichard Henderson
744ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
745d8e59c4aSRichard Henderson return true;
746d8e59c4aSRichard Henderson }
747d8e59c4aSRichard Henderson
trans_lbu(DisasContext * dc,arg_typea * arg)748d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
749d8e59c4aSRichard Henderson {
750d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
751d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
752d8e59c4aSRichard Henderson }
753d8e59c4aSRichard Henderson
trans_lbur(DisasContext * dc,arg_typea * arg)754d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
755d8e59c4aSRichard Henderson {
756d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
757d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
758d8e59c4aSRichard Henderson }
759d8e59c4aSRichard Henderson
trans_lbuea(DisasContext * dc,arg_typea * arg)760d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
761d8e59c4aSRichard Henderson {
762d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) {
763d8e59c4aSRichard Henderson return true;
764d8e59c4aSRichard Henderson }
76519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
76619f27b6cSRichard Henderson return true;
76719f27b6cSRichard Henderson #else
768d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
769d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
77019f27b6cSRichard Henderson #endif
771d8e59c4aSRichard Henderson }
772d8e59c4aSRichard Henderson
trans_lbui(DisasContext * dc,arg_typeb * arg)773d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
774d8e59c4aSRichard Henderson {
775d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
776d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
777d8e59c4aSRichard Henderson }
778d8e59c4aSRichard Henderson
trans_lhu(DisasContext * dc,arg_typea * arg)779d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
780d8e59c4aSRichard Henderson {
781d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
782d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
783d8e59c4aSRichard Henderson }
784d8e59c4aSRichard Henderson
trans_lhur(DisasContext * dc,arg_typea * arg)785d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
786d8e59c4aSRichard Henderson {
787d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
788d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
789d8e59c4aSRichard Henderson }
790d8e59c4aSRichard Henderson
trans_lhuea(DisasContext * dc,arg_typea * arg)791d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
792d8e59c4aSRichard Henderson {
793d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) {
794d8e59c4aSRichard Henderson return true;
795d8e59c4aSRichard Henderson }
79619f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
79719f27b6cSRichard Henderson return true;
79819f27b6cSRichard Henderson #else
799d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
800d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
80119f27b6cSRichard Henderson #endif
802d8e59c4aSRichard Henderson }
803d8e59c4aSRichard Henderson
trans_lhui(DisasContext * dc,arg_typeb * arg)804d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
805d8e59c4aSRichard Henderson {
806d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
807d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
808d8e59c4aSRichard Henderson }
809d8e59c4aSRichard Henderson
trans_lw(DisasContext * dc,arg_typea * arg)810d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
811d8e59c4aSRichard Henderson {
812d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
813d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
814d8e59c4aSRichard Henderson }
815d8e59c4aSRichard Henderson
trans_lwr(DisasContext * dc,arg_typea * arg)816d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
817d8e59c4aSRichard Henderson {
818d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
819d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
820d8e59c4aSRichard Henderson }
821d8e59c4aSRichard Henderson
trans_lwea(DisasContext * dc,arg_typea * arg)822d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
823d8e59c4aSRichard Henderson {
824d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) {
825d8e59c4aSRichard Henderson return true;
826d8e59c4aSRichard Henderson }
82719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
82819f27b6cSRichard Henderson return true;
82919f27b6cSRichard Henderson #else
830d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
831d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
83219f27b6cSRichard Henderson #endif
833d8e59c4aSRichard Henderson }
834d8e59c4aSRichard Henderson
trans_lwi(DisasContext * dc,arg_typeb * arg)835d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
836d8e59c4aSRichard Henderson {
837d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
838d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
839d8e59c4aSRichard Henderson }
840d8e59c4aSRichard Henderson
trans_lwx(DisasContext * dc,arg_typea * arg)841d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
842d8e59c4aSRichard Henderson {
843d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
844d8e59c4aSRichard Henderson
845d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */
846d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3);
847d8e59c4aSRichard Henderson
848d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
849d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr);
850d8e59c4aSRichard Henderson
851d8e59c4aSRichard Henderson if (arg->rd) {
852d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
853d8e59c4aSRichard Henderson }
854d8e59c4aSRichard Henderson
855d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */
856d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0);
857d8e59c4aSRichard Henderson return true;
858d8e59c4aSRichard Henderson }
859d8e59c4aSRichard Henderson
do_store(DisasContext * dc,int rd,TCGv addr,MemOp mop,int mem_index,bool rev)860d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
861d8e59c4aSRichard Henderson int mem_index, bool rev)
862d8e59c4aSRichard Henderson {
863d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE;
864d8e59c4aSRichard Henderson
865d8e59c4aSRichard Henderson /*
866d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things.
867d8e59c4aSRichard Henderson *
868d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness.
869d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core.
870d8e59c4aSRichard Henderson */
871d8e59c4aSRichard Henderson if (rev) {
872d8e59c4aSRichard Henderson if (size > MO_8) {
873d8e59c4aSRichard Henderson mop ^= MO_BSWAP;
874d8e59c4aSRichard Henderson }
875d8e59c4aSRichard Henderson if (size < MO_32) {
876d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size);
877d8e59c4aSRichard Henderson }
878d8e59c4aSRichard Henderson }
879d8e59c4aSRichard Henderson
880b414df75SRichard Henderson /*
881b414df75SRichard Henderson * For system mode, enforce alignment if the cpu configuration
882b414df75SRichard Henderson * requires it. For user-mode, the Linux kernel will have fixed up
883b414df75SRichard Henderson * any unaligned access, so emulate that by *not* setting MO_ALIGN.
884b414df75SRichard Henderson */
885b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
886ab0c8d0fSRichard Henderson if (size > MO_8 &&
887ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) &&
8884b893631SRichard Henderson dc->cfg->unaligned_exceptions) {
889ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true);
890ab0c8d0fSRichard Henderson mop |= MO_ALIGN;
891d8e59c4aSRichard Henderson }
892b414df75SRichard Henderson #endif
893d8e59c4aSRichard Henderson
894ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
895d8e59c4aSRichard Henderson return true;
896d8e59c4aSRichard Henderson }
897d8e59c4aSRichard Henderson
trans_sb(DisasContext * dc,arg_typea * arg)898d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
899d8e59c4aSRichard Henderson {
900d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
901d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
902d8e59c4aSRichard Henderson }
903d8e59c4aSRichard Henderson
trans_sbr(DisasContext * dc,arg_typea * arg)904d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
905d8e59c4aSRichard Henderson {
906d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
907d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
908d8e59c4aSRichard Henderson }
909d8e59c4aSRichard Henderson
trans_sbea(DisasContext * dc,arg_typea * arg)910d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
911d8e59c4aSRichard Henderson {
912d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) {
913d8e59c4aSRichard Henderson return true;
914d8e59c4aSRichard Henderson }
91519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
91619f27b6cSRichard Henderson return true;
91719f27b6cSRichard Henderson #else
918d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
919d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
92019f27b6cSRichard Henderson #endif
921d8e59c4aSRichard Henderson }
922d8e59c4aSRichard Henderson
trans_sbi(DisasContext * dc,arg_typeb * arg)923d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
924d8e59c4aSRichard Henderson {
925d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
926d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
927d8e59c4aSRichard Henderson }
928d8e59c4aSRichard Henderson
trans_sh(DisasContext * dc,arg_typea * arg)929d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
930d8e59c4aSRichard Henderson {
931d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
932d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
933d8e59c4aSRichard Henderson }
934d8e59c4aSRichard Henderson
trans_shr(DisasContext * dc,arg_typea * arg)935d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
936d8e59c4aSRichard Henderson {
937d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
938d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
939d8e59c4aSRichard Henderson }
940d8e59c4aSRichard Henderson
trans_shea(DisasContext * dc,arg_typea * arg)941d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
942d8e59c4aSRichard Henderson {
943d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) {
944d8e59c4aSRichard Henderson return true;
945d8e59c4aSRichard Henderson }
94619f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
94719f27b6cSRichard Henderson return true;
94819f27b6cSRichard Henderson #else
949d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
950d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
95119f27b6cSRichard Henderson #endif
952d8e59c4aSRichard Henderson }
953d8e59c4aSRichard Henderson
trans_shi(DisasContext * dc,arg_typeb * arg)954d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
955d8e59c4aSRichard Henderson {
956d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
957d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
958d8e59c4aSRichard Henderson }
959d8e59c4aSRichard Henderson
trans_sw(DisasContext * dc,arg_typea * arg)960d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
961d8e59c4aSRichard Henderson {
962d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
963d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
964d8e59c4aSRichard Henderson }
965d8e59c4aSRichard Henderson
trans_swr(DisasContext * dc,arg_typea * arg)966d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
967d8e59c4aSRichard Henderson {
968d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
969d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
970d8e59c4aSRichard Henderson }
971d8e59c4aSRichard Henderson
trans_swea(DisasContext * dc,arg_typea * arg)972d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
973d8e59c4aSRichard Henderson {
974d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) {
975d8e59c4aSRichard Henderson return true;
976d8e59c4aSRichard Henderson }
97719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
97819f27b6cSRichard Henderson return true;
97919f27b6cSRichard Henderson #else
980d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
981d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
98219f27b6cSRichard Henderson #endif
983d8e59c4aSRichard Henderson }
984d8e59c4aSRichard Henderson
trans_swi(DisasContext * dc,arg_typeb * arg)985d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
986d8e59c4aSRichard Henderson {
987d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
988d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
989d8e59c4aSRichard Henderson }
990d8e59c4aSRichard Henderson
trans_swx(DisasContext * dc,arg_typea * arg)991d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
992d8e59c4aSRichard Henderson {
993d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
994d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label();
995d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label();
996d8e59c4aSRichard Henderson TCGv_i32 tval;
997d8e59c4aSRichard Henderson
998d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */
999d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3);
1000d8e59c4aSRichard Henderson
1001d8e59c4aSRichard Henderson /*
1002d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx.
1003d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the
1004d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global.
1005d8e59c4aSRichard Henderson * In either case, addr is no longer needed.
1006d8e59c4aSRichard Henderson */
1007d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1008d8e59c4aSRichard Henderson
1009d8e59c4aSRichard Henderson /*
1010d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of
1011d8e59c4aSRichard Henderson * the reserved location.
1012d8e59c4aSRichard Henderson */
1013d8e59c4aSRichard Henderson tval = tcg_temp_new_i32();
1014d8e59c4aSRichard Henderson
1015d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1016d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd),
1017d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL);
1018d8e59c4aSRichard Henderson
1019d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1020d8e59c4aSRichard Henderson
1021d8e59c4aSRichard Henderson /* Success */
1022d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0);
1023d8e59c4aSRichard Henderson tcg_gen_br(swx_done);
1024d8e59c4aSRichard Henderson
1025d8e59c4aSRichard Henderson /* Failure */
1026d8e59c4aSRichard Henderson gen_set_label(swx_fail);
1027d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1);
1028d8e59c4aSRichard Henderson
1029d8e59c4aSRichard Henderson gen_set_label(swx_done);
1030d8e59c4aSRichard Henderson
1031d8e59c4aSRichard Henderson /*
1032d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx.
1033d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0.
1034d8e59c4aSRichard Henderson */
1035d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1);
1036d8e59c4aSRichard Henderson return true;
1037d8e59c4aSRichard Henderson }
1038d8e59c4aSRichard Henderson
setup_dslot(DisasContext * dc,bool type_b)103916bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
104016bbbbc9SRichard Henderson {
104116bbbbc9SRichard Henderson dc->tb_flags_to_set |= D_FLAG;
104216bbbbc9SRichard Henderson if (type_b && (dc->tb_flags & IMM_FLAG)) {
104316bbbbc9SRichard Henderson dc->tb_flags_to_set |= BIMM_FLAG;
104416bbbbc9SRichard Henderson }
104516bbbbc9SRichard Henderson }
104616bbbbc9SRichard Henderson
do_branch(DisasContext * dc,int dest_rb,int dest_imm,bool delay,bool abs,int link)104716bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
104816bbbbc9SRichard Henderson bool delay, bool abs, int link)
104916bbbbc9SRichard Henderson {
105016bbbbc9SRichard Henderson uint32_t add_pc;
105116bbbbc9SRichard Henderson
10522a7567a2SRichard Henderson if (invalid_delay_slot(dc, "branch")) {
10532a7567a2SRichard Henderson return true;
10542a7567a2SRichard Henderson }
105516bbbbc9SRichard Henderson if (delay) {
105616bbbbc9SRichard Henderson setup_dslot(dc, dest_rb < 0);
105716bbbbc9SRichard Henderson }
105816bbbbc9SRichard Henderson
105916bbbbc9SRichard Henderson if (link) {
106016bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
106116bbbbc9SRichard Henderson }
106216bbbbc9SRichard Henderson
106316bbbbc9SRichard Henderson /* Store the branch taken destination into btarget. */
106416bbbbc9SRichard Henderson add_pc = abs ? 0 : dc->base.pc_next;
106516bbbbc9SRichard Henderson if (dest_rb > 0) {
106616bbbbc9SRichard Henderson dc->jmp_dest = -1;
106716bbbbc9SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
106816bbbbc9SRichard Henderson } else {
106916bbbbc9SRichard Henderson dc->jmp_dest = add_pc + dest_imm;
107016bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
107116bbbbc9SRichard Henderson }
107216bbbbc9SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS;
107316bbbbc9SRichard Henderson return true;
107416bbbbc9SRichard Henderson }
107516bbbbc9SRichard Henderson
107616bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \
107716bbbbc9SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \
107816bbbbc9SRichard Henderson { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \
107916bbbbc9SRichard Henderson static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \
108016bbbbc9SRichard Henderson { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
108116bbbbc9SRichard Henderson
DO_BR(br,bri,false,false,false)108216bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
108316bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
108416bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
108516bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
108616bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
108716bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
108816bbbbc9SRichard Henderson
1089fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1090fd779113SRichard Henderson TCGCond cond, int ra, bool delay)
1091fd779113SRichard Henderson {
1092fd779113SRichard Henderson TCGv_i32 zero, next;
1093fd779113SRichard Henderson
10942a7567a2SRichard Henderson if (invalid_delay_slot(dc, "bcc")) {
10952a7567a2SRichard Henderson return true;
10962a7567a2SRichard Henderson }
1097fd779113SRichard Henderson if (delay) {
1098fd779113SRichard Henderson setup_dslot(dc, dest_rb < 0);
1099fd779113SRichard Henderson }
1100fd779113SRichard Henderson
1101fd779113SRichard Henderson dc->jmp_cond = cond;
1102fd779113SRichard Henderson
1103fd779113SRichard Henderson /* Cache the condition register in cpu_bvalue across any delay slot. */
1104fd779113SRichard Henderson tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1105fd779113SRichard Henderson
1106fd779113SRichard Henderson /* Store the branch taken destination into btarget. */
1107fd779113SRichard Henderson if (dest_rb > 0) {
1108fd779113SRichard Henderson dc->jmp_dest = -1;
1109fd779113SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1110fd779113SRichard Henderson } else {
1111fd779113SRichard Henderson dc->jmp_dest = dc->base.pc_next + dest_imm;
1112fd779113SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1113fd779113SRichard Henderson }
1114fd779113SRichard Henderson
1115fd779113SRichard Henderson /* Compute the final destination into btarget. */
1116a5ea3dd7SRichard Henderson zero = tcg_constant_i32(0);
1117a5ea3dd7SRichard Henderson next = tcg_constant_i32(dc->base.pc_next + (delay + 1) * 4);
1118fd779113SRichard Henderson tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1119fd779113SRichard Henderson reg_for_read(dc, ra), zero,
1120fd779113SRichard Henderson cpu_btarget, next);
1121fd779113SRichard Henderson
1122fd779113SRichard Henderson return true;
1123fd779113SRichard Henderson }
1124fd779113SRichard Henderson
1125fd779113SRichard Henderson #define DO_BCC(NAME, COND) \
1126fd779113SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \
1127fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \
1128fd779113SRichard Henderson static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \
1129fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \
1130fd779113SRichard Henderson static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \
1131fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \
1132fd779113SRichard Henderson static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \
1133fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1134fd779113SRichard Henderson
DO_BCC(beq,TCG_COND_EQ)1135fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1136fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1137fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1138fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1139fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1140fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1141fd779113SRichard Henderson
1142f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1143f5235314SRichard Henderson {
1144f5235314SRichard Henderson if (trap_userspace(dc, true)) {
1145f5235314SRichard Henderson return true;
1146f5235314SRichard Henderson }
11472a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brk")) {
11482a7567a2SRichard Henderson return true;
11492a7567a2SRichard Henderson }
11502a7567a2SRichard Henderson
1151f5235314SRichard Henderson tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1152f5235314SRichard Henderson if (arg->rd) {
1153f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1154f5235314SRichard Henderson }
1155f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1156f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1);
1157f5235314SRichard Henderson
115817e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT;
1159f5235314SRichard Henderson return true;
1160f5235314SRichard Henderson }
1161f5235314SRichard Henderson
trans_brki(DisasContext * dc,arg_typeb_br * arg)1162f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1163f5235314SRichard Henderson {
1164f5235314SRichard Henderson uint32_t imm = arg->imm;
1165f5235314SRichard Henderson
1166f5235314SRichard Henderson if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1167f5235314SRichard Henderson return true;
1168f5235314SRichard Henderson }
11692a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brki")) {
11702a7567a2SRichard Henderson return true;
11712a7567a2SRichard Henderson }
11722a7567a2SRichard Henderson
1173f5235314SRichard Henderson tcg_gen_movi_i32(cpu_pc, imm);
1174f5235314SRichard Henderson if (arg->rd) {
1175f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1176f5235314SRichard Henderson }
1177f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1);
1178f5235314SRichard Henderson
1179f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1180f5235314SRichard Henderson switch (imm) {
1181f5235314SRichard Henderson case 0x8: /* syscall trap */
1182f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_SYSCALL);
1183f5235314SRichard Henderson break;
1184f5235314SRichard Henderson case 0x18: /* debug trap */
1185f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG);
1186f5235314SRichard Henderson break;
1187f5235314SRichard Henderson default: /* eliminated with trap_userspace check */
1188f5235314SRichard Henderson g_assert_not_reached();
1189f5235314SRichard Henderson }
1190f5235314SRichard Henderson #else
1191f5235314SRichard Henderson uint32_t msr_to_set = 0;
1192f5235314SRichard Henderson
1193f5235314SRichard Henderson if (imm != 0x18) {
1194f5235314SRichard Henderson msr_to_set |= MSR_BIP;
1195f5235314SRichard Henderson }
1196f5235314SRichard Henderson if (imm == 0x8 || imm == 0x18) {
1197f5235314SRichard Henderson /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1198f5235314SRichard Henderson msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1199f5235314SRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr,
1200f5235314SRichard Henderson ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1201f5235314SRichard Henderson }
1202f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
120317e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT;
1204f5235314SRichard Henderson #endif
1205f5235314SRichard Henderson
1206f5235314SRichard Henderson return true;
1207f5235314SRichard Henderson }
1208f5235314SRichard Henderson
trans_mbar(DisasContext * dc,arg_mbar * arg)1209ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1210ee8c7f9fSRichard Henderson {
1211ee8c7f9fSRichard Henderson int mbar_imm = arg->imm;
1212ee8c7f9fSRichard Henderson
12132a7567a2SRichard Henderson /* Note that mbar is a specialized branch instruction. */
12142a7567a2SRichard Henderson if (invalid_delay_slot(dc, "mbar")) {
12152a7567a2SRichard Henderson return true;
12162a7567a2SRichard Henderson }
12172a7567a2SRichard Henderson
1218ee8c7f9fSRichard Henderson /* Data access memory barrier. */
1219ee8c7f9fSRichard Henderson if ((mbar_imm & 2) == 0) {
1220ee8c7f9fSRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1221ee8c7f9fSRichard Henderson }
1222ee8c7f9fSRichard Henderson
1223ee8c7f9fSRichard Henderson /* Sleep. */
1224ee8c7f9fSRichard Henderson if (mbar_imm & 16) {
1225ee8c7f9fSRichard Henderson if (trap_userspace(dc, true)) {
1226ee8c7f9fSRichard Henderson /* Sleep is a privileged instruction. */
1227ee8c7f9fSRichard Henderson return true;
1228ee8c7f9fSRichard Henderson }
1229ee8c7f9fSRichard Henderson
1230ee8c7f9fSRichard Henderson t_sync_flags(dc);
1231ee8c7f9fSRichard Henderson
1232ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
1233ee8c7f9fSRichard Henderson -offsetof(MicroBlazeCPU, env)
1234ee8c7f9fSRichard Henderson +offsetof(CPUState, halted));
1235ee8c7f9fSRichard Henderson
1236ee8c7f9fSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1237ee8c7f9fSRichard Henderson
1238ee8c7f9fSRichard Henderson gen_raise_exception(dc, EXCP_HLT);
1239ee8c7f9fSRichard Henderson }
1240ee8c7f9fSRichard Henderson
1241ee8c7f9fSRichard Henderson /*
1242ee8c7f9fSRichard Henderson * If !(mbar_imm & 1), this is an instruction access memory barrier
1243ee8c7f9fSRichard Henderson * and we need to end the TB so that we recognize self-modified
1244ee8c7f9fSRichard Henderson * code immediately.
1245ee8c7f9fSRichard Henderson *
1246ee8c7f9fSRichard Henderson * However, there are some data mbars that need the TB break
1247ee8c7f9fSRichard Henderson * (and return to main loop) to recognize interrupts right away.
1248ee8c7f9fSRichard Henderson * E.g. recognizing a change to an interrupt controller register.
1249ee8c7f9fSRichard Henderson *
1250ee8c7f9fSRichard Henderson * Therefore, choose to end the TB always.
1251ee8c7f9fSRichard Henderson */
125243b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT;
1253ee8c7f9fSRichard Henderson return true;
1254ee8c7f9fSRichard Henderson }
1255ee8c7f9fSRichard Henderson
do_rts(DisasContext * dc,arg_typeb_bc * arg,int to_set)1256e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1257e6cb0354SRichard Henderson {
1258e6cb0354SRichard Henderson if (trap_userspace(dc, to_set)) {
1259e6cb0354SRichard Henderson return true;
1260e6cb0354SRichard Henderson }
12612a7567a2SRichard Henderson if (invalid_delay_slot(dc, "rts")) {
12622a7567a2SRichard Henderson return true;
12632a7567a2SRichard Henderson }
12642a7567a2SRichard Henderson
1265e6cb0354SRichard Henderson dc->tb_flags_to_set |= to_set;
1266e6cb0354SRichard Henderson setup_dslot(dc, true);
1267e6cb0354SRichard Henderson
1268e6cb0354SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS;
1269e6cb0354SRichard Henderson dc->jmp_dest = -1;
1270e6cb0354SRichard Henderson tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1271e6cb0354SRichard Henderson return true;
1272e6cb0354SRichard Henderson }
1273e6cb0354SRichard Henderson
1274e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1275e6cb0354SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1276e6cb0354SRichard Henderson { return do_rts(dc, arg, IFLAG); }
1277e6cb0354SRichard Henderson
DO_RTS(rtbd,DRTB_FLAG)1278e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1279e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1280e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1281e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1282e6cb0354SRichard Henderson
128320800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
128420800179SRichard Henderson {
128520800179SRichard Henderson /* If opcode_0_illegal, trap. */
12864b893631SRichard Henderson if (dc->cfg->opcode_0_illegal) {
128720800179SRichard Henderson trap_illegal(dc, true);
128820800179SRichard Henderson return true;
128920800179SRichard Henderson }
129020800179SRichard Henderson /*
129120800179SRichard Henderson * Otherwise, this is "add r0, r0, r0".
129220800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared.
129320800179SRichard Henderson */
129420800179SRichard Henderson return false;
1295fcf5ef2aSThomas Huth }
1296fcf5ef2aSThomas Huth
msr_read(DisasContext * dc,TCGv_i32 d)12971074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1298fcf5ef2aSThomas Huth {
12991074c0fbSRichard Henderson TCGv_i32 t;
13001074c0fbSRichard Henderson
13011074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
13021074c0fbSRichard Henderson t = tcg_temp_new_i32();
13031074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13041074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t);
1305fcf5ef2aSThomas Huth }
1306fcf5ef2aSThomas Huth
do_msrclrset(DisasContext * dc,arg_type_msr * arg,bool set)1307536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1308536e340fSRichard Henderson {
1309536e340fSRichard Henderson uint32_t imm = arg->imm;
1310536e340fSRichard Henderson
1311536e340fSRichard Henderson if (trap_userspace(dc, imm != MSR_C)) {
1312536e340fSRichard Henderson return true;
1313536e340fSRichard Henderson }
1314536e340fSRichard Henderson
1315536e340fSRichard Henderson if (arg->rd) {
1316536e340fSRichard Henderson msr_read(dc, cpu_R[arg->rd]);
1317536e340fSRichard Henderson }
1318536e340fSRichard Henderson
1319536e340fSRichard Henderson /*
1320536e340fSRichard Henderson * Handle the carry bit separately.
1321536e340fSRichard Henderson * This is the only bit that userspace can modify.
1322536e340fSRichard Henderson */
1323536e340fSRichard Henderson if (imm & MSR_C) {
1324536e340fSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, set);
1325536e340fSRichard Henderson }
1326536e340fSRichard Henderson
1327536e340fSRichard Henderson /*
1328536e340fSRichard Henderson * MSR_C and MSR_CC set above.
1329536e340fSRichard Henderson * MSR_PVR is not writable, and is always clear.
1330536e340fSRichard Henderson */
1331536e340fSRichard Henderson imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1332536e340fSRichard Henderson
1333536e340fSRichard Henderson if (imm != 0) {
1334536e340fSRichard Henderson if (set) {
1335536e340fSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1336536e340fSRichard Henderson } else {
1337536e340fSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1338536e340fSRichard Henderson }
133943b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT;
1340536e340fSRichard Henderson }
1341536e340fSRichard Henderson return true;
1342536e340fSRichard Henderson }
1343536e340fSRichard Henderson
trans_msrclr(DisasContext * dc,arg_type_msr * arg)1344536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1345536e340fSRichard Henderson {
1346536e340fSRichard Henderson return do_msrclrset(dc, arg, false);
1347536e340fSRichard Henderson }
1348536e340fSRichard Henderson
trans_msrset(DisasContext * dc,arg_type_msr * arg)1349536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1350536e340fSRichard Henderson {
1351536e340fSRichard Henderson return do_msrclrset(dc, arg, true);
1352536e340fSRichard Henderson }
1353536e340fSRichard Henderson
trans_mts(DisasContext * dc,arg_mts * arg)13549df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
1355fcf5ef2aSThomas Huth {
13569df297a2SRichard Henderson if (trap_userspace(dc, true)) {
13579df297a2SRichard Henderson return true;
1358f0f7e7f7SEdgar E. Iglesias }
1359f0f7e7f7SEdgar E. Iglesias
13609df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
13619df297a2SRichard Henderson g_assert_not_reached();
13629df297a2SRichard Henderson #else
13639df297a2SRichard Henderson if (arg->e && arg->rs != 0x1003) {
13649df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR,
13659df297a2SRichard Henderson "Invalid extended mts reg 0x%x\n", arg->rs);
13669df297a2SRichard Henderson return true;
13672023e9a3SEdgar E. Iglesias }
1368fcf5ef2aSThomas Huth
13699df297a2SRichard Henderson TCGv_i32 src = reg_for_read(dc, arg->ra);
13709df297a2SRichard Henderson switch (arg->rs) {
1371aa28e6d4SRichard Henderson case SR_MSR:
137243b34134SRichard Henderson /* Install MSR_C. */
137343b34134SRichard Henderson tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
137443b34134SRichard Henderson /*
137543b34134SRichard Henderson * Clear MSR_C and MSR_CC;
137643b34134SRichard Henderson * MSR_PVR is not writable, and is always clear.
137743b34134SRichard Henderson */
137843b34134SRichard Henderson tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
1379fcf5ef2aSThomas Huth break;
13809df297a2SRichard Henderson case SR_FSR:
1381ad75a51eSRichard Henderson tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, fsr));
13829df297a2SRichard Henderson break;
13839df297a2SRichard Henderson case 0x800:
1384ad75a51eSRichard Henderson tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, slr));
13859df297a2SRichard Henderson break;
13869df297a2SRichard Henderson case 0x802:
1387ad75a51eSRichard Henderson tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, shr));
13889df297a2SRichard Henderson break;
13899df297a2SRichard Henderson
13909df297a2SRichard Henderson case 0x1000: /* PID */
13919df297a2SRichard Henderson case 0x1001: /* ZPR */
13929df297a2SRichard Henderson case 0x1002: /* TLBX */
13939df297a2SRichard Henderson case 0x1003: /* TLBLO */
13949df297a2SRichard Henderson case 0x1004: /* TLBHI */
13959df297a2SRichard Henderson case 0x1005: /* TLBSX */
13969df297a2SRichard Henderson {
1397a5ea3dd7SRichard Henderson TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1398a5ea3dd7SRichard Henderson TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
13999df297a2SRichard Henderson
1400ad75a51eSRichard Henderson gen_helper_mmu_write(tcg_env, tmp_ext, tmp_reg, src);
14019df297a2SRichard Henderson }
14029df297a2SRichard Henderson break;
14039df297a2SRichard Henderson
14049df297a2SRichard Henderson default:
14059df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14069df297a2SRichard Henderson return true;
14079df297a2SRichard Henderson }
140843b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT;
14099df297a2SRichard Henderson return true;
14109df297a2SRichard Henderson #endif
14119df297a2SRichard Henderson }
14129df297a2SRichard Henderson
trans_mfs(DisasContext * dc,arg_mfs * arg)14139df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14149df297a2SRichard Henderson {
14159df297a2SRichard Henderson TCGv_i32 dest = reg_for_write(dc, arg->rd);
14169df297a2SRichard Henderson
14179df297a2SRichard Henderson if (arg->e) {
14189df297a2SRichard Henderson switch (arg->rs) {
1419351527b7SEdgar E. Iglesias case SR_EAR:
1420dbdb77c4SRichard Henderson {
1421dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64();
1422ad75a51eSRichard Henderson tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14239df297a2SRichard Henderson tcg_gen_extrh_i64_i32(dest, t64);
1424dbdb77c4SRichard Henderson }
14259df297a2SRichard Henderson return true;
14269df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14279df297a2SRichard Henderson case 0x1003: /* TLBLO */
14289df297a2SRichard Henderson /* Handled below. */
1429aa28e6d4SRichard Henderson break;
14309df297a2SRichard Henderson #endif
14319df297a2SRichard Henderson case 0x2006 ... 0x2009:
14329df297a2SRichard Henderson /* High bits of PVR6-9 not implemented. */
14339df297a2SRichard Henderson tcg_gen_movi_i32(dest, 0);
14349df297a2SRichard Henderson return true;
1435fcf5ef2aSThomas Huth default:
14369df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR,
14379df297a2SRichard Henderson "Invalid extended mfs reg 0x%x\n", arg->rs);
14389df297a2SRichard Henderson return true;
1439fcf5ef2aSThomas Huth }
14409df297a2SRichard Henderson }
14419df297a2SRichard Henderson
14429df297a2SRichard Henderson switch (arg->rs) {
1443aa28e6d4SRichard Henderson case SR_PC:
14449df297a2SRichard Henderson tcg_gen_movi_i32(dest, dc->base.pc_next);
1445fcf5ef2aSThomas Huth break;
1446aa28e6d4SRichard Henderson case SR_MSR:
14479df297a2SRichard Henderson msr_read(dc, dest);
1448fcf5ef2aSThomas Huth break;
1449351527b7SEdgar E. Iglesias case SR_EAR:
1450dbdb77c4SRichard Henderson {
1451dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64();
1452ad75a51eSRichard Henderson tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
14539df297a2SRichard Henderson tcg_gen_extrl_i64_i32(dest, t64);
1454a1b48e3aSEdgar E. Iglesias }
1455aa28e6d4SRichard Henderson break;
1456351527b7SEdgar E. Iglesias case SR_ESR:
1457ad75a51eSRichard Henderson tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, esr));
1458aa28e6d4SRichard Henderson break;
1459351527b7SEdgar E. Iglesias case SR_FSR:
1460ad75a51eSRichard Henderson tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, fsr));
1461aa28e6d4SRichard Henderson break;
1462351527b7SEdgar E. Iglesias case SR_BTR:
1463ad75a51eSRichard Henderson tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, btr));
1464aa28e6d4SRichard Henderson break;
14657cdae31dSTong Ho case SR_EDR:
1466ad75a51eSRichard Henderson tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, edr));
1467fcf5ef2aSThomas Huth break;
1468fcf5ef2aSThomas Huth case 0x800:
1469ad75a51eSRichard Henderson tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, slr));
1470fcf5ef2aSThomas Huth break;
1471fcf5ef2aSThomas Huth case 0x802:
1472ad75a51eSRichard Henderson tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, shr));
1473fcf5ef2aSThomas Huth break;
14749df297a2SRichard Henderson
14759df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14769df297a2SRichard Henderson case 0x1000: /* PID */
14779df297a2SRichard Henderson case 0x1001: /* ZPR */
14789df297a2SRichard Henderson case 0x1002: /* TLBX */
14799df297a2SRichard Henderson case 0x1003: /* TLBLO */
14809df297a2SRichard Henderson case 0x1004: /* TLBHI */
14819df297a2SRichard Henderson case 0x1005: /* TLBSX */
14829df297a2SRichard Henderson {
1483a5ea3dd7SRichard Henderson TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1484a5ea3dd7SRichard Henderson TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
14859df297a2SRichard Henderson
1486ad75a51eSRichard Henderson gen_helper_mmu_read(dest, tcg_env, tmp_ext, tmp_reg);
14879df297a2SRichard Henderson }
14889df297a2SRichard Henderson break;
14899df297a2SRichard Henderson #endif
14909df297a2SRichard Henderson
1491351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c:
1492ad75a51eSRichard Henderson tcg_gen_ld_i32(dest, tcg_env,
1493a4bcfc33SRichard Henderson offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1494a4bcfc33SRichard Henderson - offsetof(MicroBlazeCPU, env));
1495fcf5ef2aSThomas Huth break;
1496fcf5ef2aSThomas Huth default:
14979df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1498fcf5ef2aSThomas Huth break;
1499fcf5ef2aSThomas Huth }
15009df297a2SRichard Henderson return true;
1501fcf5ef2aSThomas Huth }
1502fcf5ef2aSThomas Huth
do_rti(DisasContext * dc)15033fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
1504fcf5ef2aSThomas Huth {
15053fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
1506fcf5ef2aSThomas Huth
15073fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1);
15083fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15093fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15103fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15113fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1512fcf5ef2aSThomas Huth }
1513fcf5ef2aSThomas Huth
do_rtb(DisasContext * dc)15143fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
1515fcf5ef2aSThomas Huth {
15163fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
1517fcf5ef2aSThomas Huth
15183fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1);
15193fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15203fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15213fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1522fcf5ef2aSThomas Huth }
1523fcf5ef2aSThomas Huth
do_rte(DisasContext * dc)15243fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
1525fcf5ef2aSThomas Huth {
15263fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
1527fcf5ef2aSThomas Huth
15283fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1);
15293fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15303fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15313fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15323fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1533fcf5ef2aSThomas Huth }
1534fcf5ef2aSThomas Huth
1535fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */
do_get(DisasContext * dc,int rd,int rb,int imm,int ctrl)153652065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1537fcf5ef2aSThomas Huth {
1538fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl;
1539fcf5ef2aSThomas Huth
1540bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) {
154152065d8fSRichard Henderson return true;
1542fcf5ef2aSThomas Huth }
1543fcf5ef2aSThomas Huth
1544cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32();
154552065d8fSRichard Henderson if (rb) {
154652065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1547fcf5ef2aSThomas Huth } else {
154852065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm);
1549fcf5ef2aSThomas Huth }
1550fcf5ef2aSThomas Huth
1551a5ea3dd7SRichard Henderson t_ctrl = tcg_constant_i32(ctrl);
155252065d8fSRichard Henderson gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
155352065d8fSRichard Henderson return true;
155452065d8fSRichard Henderson }
155552065d8fSRichard Henderson
trans_get(DisasContext * dc,arg_get * arg)155652065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
155752065d8fSRichard Henderson {
155852065d8fSRichard Henderson return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
155952065d8fSRichard Henderson }
156052065d8fSRichard Henderson
trans_getd(DisasContext * dc,arg_getd * arg)156152065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
156252065d8fSRichard Henderson {
156352065d8fSRichard Henderson return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
156452065d8fSRichard Henderson }
156552065d8fSRichard Henderson
do_put(DisasContext * dc,int ra,int rb,int imm,int ctrl)156652065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
156752065d8fSRichard Henderson {
156852065d8fSRichard Henderson TCGv_i32 t_id, t_ctrl;
156952065d8fSRichard Henderson
157052065d8fSRichard Henderson if (trap_userspace(dc, true)) {
157152065d8fSRichard Henderson return true;
157252065d8fSRichard Henderson }
157352065d8fSRichard Henderson
157452065d8fSRichard Henderson t_id = tcg_temp_new_i32();
157552065d8fSRichard Henderson if (rb) {
157652065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
157752065d8fSRichard Henderson } else {
157852065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm);
157952065d8fSRichard Henderson }
158052065d8fSRichard Henderson
1581a5ea3dd7SRichard Henderson t_ctrl = tcg_constant_i32(ctrl);
158252065d8fSRichard Henderson gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
158352065d8fSRichard Henderson return true;
158452065d8fSRichard Henderson }
158552065d8fSRichard Henderson
trans_put(DisasContext * dc,arg_put * arg)158652065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
158752065d8fSRichard Henderson {
158852065d8fSRichard Henderson return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
158952065d8fSRichard Henderson }
159052065d8fSRichard Henderson
trans_putd(DisasContext * dc,arg_putd * arg)159152065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
159252065d8fSRichard Henderson {
159352065d8fSRichard Henderson return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1594fcf5ef2aSThomas Huth }
1595fcf5ef2aSThomas Huth
mb_tr_init_disas_context(DisasContextBase * dcb,CPUState * cs)1596372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1597fcf5ef2aSThomas Huth {
1598372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base);
1599372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1600372122e3SRichard Henderson int bound;
1601fcf5ef2aSThomas Huth
16024b893631SRichard Henderson dc->cfg = &cpu->cfg;
1603683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags;
1604d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base;
160520800179SRichard Henderson dc->r0 = NULL;
160620800179SRichard Henderson dc->r0_set = false;
16073b916140SRichard Henderson dc->mem_index = cpu_mmu_index(cs, false);
1608b9c58aabSRichard Henderson dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1609b9c58aabSRichard Henderson dc->jmp_dest = -1;
1610fcf5ef2aSThomas Huth
1611372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1612372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound);
1613fcf5ef2aSThomas Huth }
1614fcf5ef2aSThomas Huth
mb_tr_tb_start(DisasContextBase * dcb,CPUState * cs)1615372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1616fcf5ef2aSThomas Huth {
1617fcf5ef2aSThomas Huth }
1618fcf5ef2aSThomas Huth
mb_tr_insn_start(DisasContextBase * dcb,CPUState * cs)1619372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1620372122e3SRichard Henderson {
1621683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base);
1622683a247eSRichard Henderson
1623683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1624372122e3SRichard Henderson }
1625fcf5ef2aSThomas Huth
mb_tr_translate_insn(DisasContextBase * dcb,CPUState * cs)1626372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1627372122e3SRichard Henderson {
1628372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base);
162944d1432bSRichard Henderson uint32_t ir;
1630372122e3SRichard Henderson
1631372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */
1632372122e3SRichard Henderson if (dc->base.pc_next & 3) {
1633372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1634372122e3SRichard Henderson (uint32_t)dc->base.pc_next);
1635fcf5ef2aSThomas Huth }
1636fcf5ef2aSThomas Huth
16376f9642d7SRichard Henderson dc->tb_flags_to_set = 0;
16386f9642d7SRichard Henderson
1639*1561fee6SRichard Henderson ir = translator_ldl(cpu_env(cs), &dc->base, dc->base.pc_next);
164044d1432bSRichard Henderson if (!decode(dc, ir)) {
1641921afa9dSRichard Henderson trap_illegal(dc, true);
164244d1432bSRichard Henderson }
164320800179SRichard Henderson
164420800179SRichard Henderson if (dc->r0) {
164520800179SRichard Henderson dc->r0 = NULL;
164620800179SRichard Henderson dc->r0_set = false;
164720800179SRichard Henderson }
164820800179SRichard Henderson
16496f9642d7SRichard Henderson /* Discard the imm global when its contents cannot be used. */
16506f9642d7SRichard Henderson if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1651d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm);
1652372122e3SRichard Henderson }
16536f9642d7SRichard Henderson
16541e521ce3SRichard Henderson dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
16556f9642d7SRichard Henderson dc->tb_flags |= dc->tb_flags_to_set;
1656d4705ae0SRichard Henderson dc->base.pc_next += 4;
1657fcf5ef2aSThomas Huth
1658b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
16593d35bcc2SRichard Henderson /*
16603d35bcc2SRichard Henderson * Finish any return-from branch.
16613d35bcc2SRichard Henderson */
16623c745866SRichard Henderson uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16633c745866SRichard Henderson if (unlikely(rt_ibe != 0)) {
16643c745866SRichard Henderson dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
16653c745866SRichard Henderson if (rt_ibe & DRTI_FLAG) {
1666fcf5ef2aSThomas Huth do_rti(dc);
16673c745866SRichard Henderson } else if (rt_ibe & DRTB_FLAG) {
1668fcf5ef2aSThomas Huth do_rtb(dc);
16693c745866SRichard Henderson } else {
1670fcf5ef2aSThomas Huth do_rte(dc);
1671372122e3SRichard Henderson }
16723c745866SRichard Henderson }
16733d35bcc2SRichard Henderson
16743d35bcc2SRichard Henderson /* Complete the branch, ending the TB. */
16753d35bcc2SRichard Henderson switch (dc->base.is_jmp) {
16763d35bcc2SRichard Henderson case DISAS_NORETURN:
16773d35bcc2SRichard Henderson /*
16783d35bcc2SRichard Henderson * E.g. illegal insn in a delay slot. We've already exited
16793d35bcc2SRichard Henderson * and will handle D_FLAG in mb_cpu_do_interrupt.
16803d35bcc2SRichard Henderson */
16813d35bcc2SRichard Henderson break;
16823d35bcc2SRichard Henderson case DISAS_NEXT:
16833c745866SRichard Henderson /*
16843c745866SRichard Henderson * Normal insn a delay slot.
16853c745866SRichard Henderson * However, the return-from-exception type insns should
16863c745866SRichard Henderson * return to the main loop, as they have adjusted MSR.
16873c745866SRichard Henderson */
16883c745866SRichard Henderson dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
16893d35bcc2SRichard Henderson break;
16903d35bcc2SRichard Henderson case DISAS_EXIT_NEXT:
16913d35bcc2SRichard Henderson /*
16923d35bcc2SRichard Henderson * E.g. mts insn in a delay slot. Continue with btarget,
16933d35bcc2SRichard Henderson * but still return to the main loop.
16943d35bcc2SRichard Henderson */
16953d35bcc2SRichard Henderson dc->base.is_jmp = DISAS_EXIT_JUMP;
16963d35bcc2SRichard Henderson break;
16973d35bcc2SRichard Henderson default:
16983d35bcc2SRichard Henderson g_assert_not_reached();
16993d35bcc2SRichard Henderson }
1700372122e3SRichard Henderson }
1701372122e3SRichard Henderson }
1702372122e3SRichard Henderson
mb_tr_tb_stop(DisasContextBase * dcb,CPUState * cs)1703372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1704372122e3SRichard Henderson {
1705372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base);
1706372122e3SRichard Henderson
1707372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) {
1708372122e3SRichard Henderson /* We have already exited the TB. */
1709372122e3SRichard Henderson return;
1710372122e3SRichard Henderson }
1711372122e3SRichard Henderson
1712372122e3SRichard Henderson t_sync_flags(dc);
1713372122e3SRichard Henderson
1714372122e3SRichard Henderson switch (dc->base.is_jmp) {
1715372122e3SRichard Henderson case DISAS_TOO_MANY:
1716372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next);
1717372122e3SRichard Henderson return;
1718372122e3SRichard Henderson
171917e77796SRichard Henderson case DISAS_EXIT:
1720f6278ca9SRichard Henderson break;
1721f6278ca9SRichard Henderson case DISAS_EXIT_NEXT:
1722f6278ca9SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1723f6278ca9SRichard Henderson break;
1724f6278ca9SRichard Henderson case DISAS_EXIT_JUMP:
1725f6278ca9SRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1726f6278ca9SRichard Henderson tcg_gen_discard_i32(cpu_btarget);
1727f6278ca9SRichard Henderson break;
1728372122e3SRichard Henderson
1729372122e3SRichard Henderson case DISAS_JUMP:
1730fbafb3a4SRichard Henderson if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
1731b9c58aabSRichard Henderson /* Direct jump. */
1732b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget);
1733b9c58aabSRichard Henderson
1734b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_ALWAYS) {
1735b9c58aabSRichard Henderson /* Conditional direct jump. */
1736b9c58aabSRichard Henderson TCGLabel *taken = gen_new_label();
1737b9c58aabSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32();
1738b9c58aabSRichard Henderson
1739b9c58aabSRichard Henderson /*
1740b9c58aabSRichard Henderson * Copy bvalue to a temp now, so we can discard bvalue.
1741b9c58aabSRichard Henderson * This can avoid writing bvalue to memory when the
1742b9c58aabSRichard Henderson * delay slot cannot raise an exception.
1743b9c58aabSRichard Henderson */
1744b9c58aabSRichard Henderson tcg_gen_mov_i32(tmp, cpu_bvalue);
1745b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_bvalue);
1746b9c58aabSRichard Henderson
1747b9c58aabSRichard Henderson tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1748b9c58aabSRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next);
1749b9c58aabSRichard Henderson gen_set_label(taken);
1750b9c58aabSRichard Henderson }
1751b9c58aabSRichard Henderson gen_goto_tb(dc, 0, dc->jmp_dest);
1752b9c58aabSRichard Henderson return;
1753b9c58aabSRichard Henderson }
1754b9c58aabSRichard Henderson
1755fbafb3a4SRichard Henderson /* Indirect jump (or direct jump w/ goto_tb disabled) */
1756b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1757b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget);
17584059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr();
1759372122e3SRichard Henderson return;
1760372122e3SRichard Henderson
1761a2b80dbdSRichard Henderson default:
1762a2b80dbdSRichard Henderson g_assert_not_reached();
1763fcf5ef2aSThomas Huth }
1764f6278ca9SRichard Henderson
1765f6278ca9SRichard Henderson /* Finish DISAS_EXIT_* */
1766f6278ca9SRichard Henderson if (unlikely(cs->singlestep_enabled)) {
1767f6278ca9SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG);
1768f6278ca9SRichard Henderson } else {
1769f6278ca9SRichard Henderson tcg_gen_exit_tb(NULL, 0);
1770f6278ca9SRichard Henderson }
1771fcf5ef2aSThomas Huth }
1772fcf5ef2aSThomas Huth
1773372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1774372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context,
1775372122e3SRichard Henderson .tb_start = mb_tr_tb_start,
1776372122e3SRichard Henderson .insn_start = mb_tr_insn_start,
1777372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn,
1778372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop,
1779372122e3SRichard Henderson };
1780372122e3SRichard Henderson
gen_intermediate_code(CPUState * cpu,TranslationBlock * tb,int * max_insns,vaddr pc,void * host_pc)1781597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
178232f0c394SAnton Johansson vaddr pc, void *host_pc)
1783372122e3SRichard Henderson {
1784372122e3SRichard Henderson DisasContext dc;
1785306c8721SRichard Henderson translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base);
1786fcf5ef2aSThomas Huth }
1787fcf5ef2aSThomas Huth
mb_cpu_dump_state(CPUState * cs,FILE * f,int flags)178890c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1789fcf5ef2aSThomas Huth {
1790da953643SPhilippe Mathieu-Daudé CPUMBState *env = cpu_env(cs);
17910c3da918SRichard Henderson uint32_t iflags;
1792fcf5ef2aSThomas Huth int i;
1793fcf5ef2aSThomas Huth
17940c3da918SRichard Henderson qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
17950c3da918SRichard Henderson env->pc, env->msr,
17962e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel",
17972e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel",
17982e5282caSRichard Henderson (bool)(env->msr & MSR_EIP),
17992e5282caSRichard Henderson (bool)(env->msr & MSR_IE));
18000c3da918SRichard Henderson
18010c3da918SRichard Henderson iflags = env->iflags;
18020c3da918SRichard Henderson qemu_fprintf(f, "iflags: 0x%08x", iflags);
18030c3da918SRichard Henderson if (iflags & IMM_FLAG) {
18040c3da918SRichard Henderson qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18052ead1b18SJoe Komlodi }
18060c3da918SRichard Henderson if (iflags & BIMM_FLAG) {
18070c3da918SRichard Henderson qemu_fprintf(f, " BIMM");
18080c3da918SRichard Henderson }
18090c3da918SRichard Henderson if (iflags & D_FLAG) {
1810b9c58aabSRichard Henderson qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18110c3da918SRichard Henderson }
18120c3da918SRichard Henderson if (iflags & DRTI_FLAG) {
18130c3da918SRichard Henderson qemu_fprintf(f, " DRTI");
18140c3da918SRichard Henderson }
18150c3da918SRichard Henderson if (iflags & DRTE_FLAG) {
18160c3da918SRichard Henderson qemu_fprintf(f, " DRTE");
18170c3da918SRichard Henderson }
18180c3da918SRichard Henderson if (iflags & DRTB_FLAG) {
18190c3da918SRichard Henderson qemu_fprintf(f, " DRTB");
18200c3da918SRichard Henderson }
18210c3da918SRichard Henderson if (iflags & ESR_ESS_FLAG) {
18220c3da918SRichard Henderson qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18232ead1b18SJoe Komlodi }
1824fcf5ef2aSThomas Huth
18250c3da918SRichard Henderson qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
182619f27b6cSRichard Henderson "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
18270c3da918SRichard Henderson env->esr, env->fsr, env->btr, env->edr,
18280c3da918SRichard Henderson env->ear, env->slr, env->shr);
18290c3da918SRichard Henderson
18300c3da918SRichard Henderson for (i = 0; i < 32; i++) {
18310c3da918SRichard Henderson qemu_fprintf(f, "r%2.2d=%08x%c",
18320c3da918SRichard Henderson i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18330c3da918SRichard Henderson }
18340c3da918SRichard Henderson qemu_fprintf(f, "\n");
1835fcf5ef2aSThomas Huth }
1836fcf5ef2aSThomas Huth
mb_tcg_init(void)1837fcf5ef2aSThomas Huth void mb_tcg_init(void)
1838fcf5ef2aSThomas Huth {
1839480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1840480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1841fcf5ef2aSThomas Huth
1842480d29a8SRichard Henderson static const struct {
1843480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8];
1844480d29a8SRichard Henderson } i32s[] = {
1845e47c2231SRichard Henderson /*
1846e47c2231SRichard Henderson * Note that r0 is handled specially in reg_for_read
1847e47c2231SRichard Henderson * and reg_for_write. Nothing should touch cpu_R[0].
1848e47c2231SRichard Henderson * Leave that element NULL, which will assert quickly
1849e47c2231SRichard Henderson * inside the tcg generator functions.
1850e47c2231SRichard Henderson */
1851e47c2231SRichard Henderson R(1), R(2), R(3), R(4), R(5), R(6), R(7),
1852480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
1853480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1854480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1855480d29a8SRichard Henderson
1856480d29a8SRichard Henderson SP(pc),
1857480d29a8SRichard Henderson SP(msr),
18581074c0fbSRichard Henderson SP(msr_c),
1859480d29a8SRichard Henderson SP(imm),
1860480d29a8SRichard Henderson SP(iflags),
1861b9c58aabSRichard Henderson SP(bvalue),
1862480d29a8SRichard Henderson SP(btarget),
1863480d29a8SRichard Henderson SP(res_val),
1864480d29a8SRichard Henderson };
1865480d29a8SRichard Henderson
1866480d29a8SRichard Henderson #undef R
1867480d29a8SRichard Henderson #undef SP
1868480d29a8SRichard Henderson
1869480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1870480d29a8SRichard Henderson *i32s[i].var =
1871ad75a51eSRichard Henderson tcg_global_mem_new_i32(tcg_env, i32s[i].ofs, i32s[i].name);
1872fcf5ef2aSThomas Huth }
187376e8187dSRichard Henderson
1874480d29a8SRichard Henderson cpu_res_addr =
1875ad75a51eSRichard Henderson tcg_global_mem_new(tcg_env, offsetof(CPUMBState, res_addr), "res_addr");
1876fcf5ef2aSThomas Huth }
1877