xref: /openbmc/qemu/target/microblaze/translate.c (revision 20800179655d9262716ff20895c3c9d81ecb2d17)
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
10fcf5ef2aSThomas Huth  * version 2 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth  */
20fcf5ef2aSThomas Huth 
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "disas/disas.h"
24fcf5ef2aSThomas Huth #include "exec/exec-all.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
26fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
27fcf5ef2aSThomas Huth #include "microblaze-decode.h"
28fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h"
29fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
3077fc6f5eSLluís Vilanova #include "exec/translator.h"
3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
32fcf5ef2aSThomas Huth 
33fcf5ef2aSThomas Huth #include "trace-tcg.h"
34fcf5ef2aSThomas Huth #include "exec/log.h"
35fcf5ef2aSThomas Huth 
36fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
37fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
38fcf5ef2aSThomas Huth 
3977fc6f5eSLluís Vilanova /* is_jmp field values */
4077fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
4177fc6f5eSLluís Vilanova #define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
4277fc6f5eSLluís Vilanova 
43cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
440f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
453e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
461074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
479b158558SRichard Henderson static TCGv_i32 cpu_imm;
489b158558SRichard Henderson static TCGv_i32 cpu_btaken;
490f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
509b158558SRichard Henderson static TCGv_i32 cpu_iflags;
519b158558SRichard Henderson static TCGv cpu_res_addr;
529b158558SRichard Henderson static TCGv_i32 cpu_res_val;
53fcf5ef2aSThomas Huth 
54fcf5ef2aSThomas Huth #include "exec/gen-icount.h"
55fcf5ef2aSThomas Huth 
56fcf5ef2aSThomas Huth /* This is the state at translation time.  */
57fcf5ef2aSThomas Huth typedef struct DisasContext {
58d4705ae0SRichard Henderson     DisasContextBase base;
59fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu;
60fcf5ef2aSThomas Huth 
61*20800179SRichard Henderson     TCGv_i32 r0;
62*20800179SRichard Henderson     bool r0_set;
63*20800179SRichard Henderson 
64fcf5ef2aSThomas Huth     /* Decoder.  */
65fcf5ef2aSThomas Huth     int type_b;
66fcf5ef2aSThomas Huth     uint32_t ir;
67d7ecb757SRichard Henderson     uint32_t ext_imm;
68fcf5ef2aSThomas Huth     uint8_t opcode;
69fcf5ef2aSThomas Huth     uint8_t rd, ra, rb;
70fcf5ef2aSThomas Huth     uint16_t imm;
71fcf5ef2aSThomas Huth 
72fcf5ef2aSThomas Huth     unsigned int cpustate_changed;
73fcf5ef2aSThomas Huth     unsigned int delayed_branch;
74fcf5ef2aSThomas Huth     unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
75fcf5ef2aSThomas Huth     unsigned int clear_imm;
76fcf5ef2aSThomas Huth 
77fcf5ef2aSThomas Huth #define JMP_NOJMP     0
78fcf5ef2aSThomas Huth #define JMP_DIRECT    1
79fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2
80fcf5ef2aSThomas Huth #define JMP_INDIRECT  3
81fcf5ef2aSThomas Huth     unsigned int jmp;
82fcf5ef2aSThomas Huth     uint32_t jmp_pc;
83fcf5ef2aSThomas Huth 
84fcf5ef2aSThomas Huth     int abort_at_next_insn;
85fcf5ef2aSThomas Huth } DisasContext;
86fcf5ef2aSThomas Huth 
87*20800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
88*20800179SRichard Henderson {
89*20800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
90*20800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
91*20800179SRichard Henderson     }
92*20800179SRichard Henderson     return x;
93*20800179SRichard Henderson }
94*20800179SRichard Henderson 
9544d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9644d1432bSRichard Henderson #include "decode-insns.c.inc"
9744d1432bSRichard Henderson 
98fcf5ef2aSThomas Huth static inline void t_sync_flags(DisasContext *dc)
99fcf5ef2aSThomas Huth {
100fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
101fcf5ef2aSThomas Huth     if (dc->tb_flags != dc->synced_flags) {
1029b158558SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags);
103fcf5ef2aSThomas Huth         dc->synced_flags = dc->tb_flags;
104fcf5ef2aSThomas Huth     }
105fcf5ef2aSThomas Huth }
106fcf5ef2aSThomas Huth 
10741ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
108fcf5ef2aSThomas Huth {
109fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
110fcf5ef2aSThomas Huth 
111fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
112fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
113d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
114fcf5ef2aSThomas Huth }
115fcf5ef2aSThomas Huth 
11641ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
11741ba37c4SRichard Henderson {
11841ba37c4SRichard Henderson     t_sync_flags(dc);
119d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
12041ba37c4SRichard Henderson     gen_raise_exception(dc, index);
12141ba37c4SRichard Henderson }
12241ba37c4SRichard Henderson 
12341ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
12441ba37c4SRichard Henderson {
12541ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
12641ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
12741ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
12841ba37c4SRichard Henderson 
12941ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
13041ba37c4SRichard Henderson }
13141ba37c4SRichard Henderson 
132fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
133fcf5ef2aSThomas Huth {
134fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
135d4705ae0SRichard Henderson     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
136fcf5ef2aSThomas Huth #else
137fcf5ef2aSThomas Huth     return true;
138fcf5ef2aSThomas Huth #endif
139fcf5ef2aSThomas Huth }
140fcf5ef2aSThomas Huth 
141fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
142fcf5ef2aSThomas Huth {
143d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1440b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1450b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1460b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1470b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
1480b46fa08SRichard Henderson     } else if (use_goto_tb(dc, dest)) {
149fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1500f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
151d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
152fcf5ef2aSThomas Huth     } else {
1530f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
15407ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
155fcf5ef2aSThomas Huth     }
156d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
157fcf5ef2aSThomas Huth }
158fcf5ef2aSThomas Huth 
159bdfc1e88SEdgar E. Iglesias /*
1609ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1619ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1629ba8cd45SEdgar E. Iglesias  */
1639ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1649ba8cd45SEdgar E. Iglesias {
1659ba8cd45SEdgar E. Iglesias     if (cond && (dc->tb_flags & MSR_EE_FLAG)
1665143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
16741ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1689ba8cd45SEdgar E. Iglesias     }
1699ba8cd45SEdgar E. Iglesias     return cond;
1709ba8cd45SEdgar E. Iglesias }
1719ba8cd45SEdgar E. Iglesias 
1729ba8cd45SEdgar E. Iglesias /*
173bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
174bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
175bdfc1e88SEdgar E. Iglesias  */
176bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
177bdfc1e88SEdgar E. Iglesias {
178bdfc1e88SEdgar E. Iglesias     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
179bdfc1e88SEdgar E. Iglesias     bool cond_user = cond && mem_index == MMU_USER_IDX;
180bdfc1e88SEdgar E. Iglesias 
181bdfc1e88SEdgar E. Iglesias     if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) {
18241ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
183bdfc1e88SEdgar E. Iglesias     }
184bdfc1e88SEdgar E. Iglesias     return cond_user;
185bdfc1e88SEdgar E. Iglesias }
186bdfc1e88SEdgar E. Iglesias 
187d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc)
188fcf5ef2aSThomas Huth {
189d7ecb757SRichard Henderson     tcg_debug_assert(dc->type_b);
190*20800179SRichard Henderson     return typeb_imm(dc, (int16_t)dc->imm);
191fcf5ef2aSThomas Huth }
192fcf5ef2aSThomas Huth 
193cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
194fcf5ef2aSThomas Huth {
195fcf5ef2aSThomas Huth     if (dc->type_b) {
196d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc));
1979b158558SRichard Henderson         return &cpu_imm;
198d7ecb757SRichard Henderson     }
199fcf5ef2aSThomas Huth     return &cpu_R[dc->rb];
200fcf5ef2aSThomas Huth }
201fcf5ef2aSThomas Huth 
202*20800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
203fcf5ef2aSThomas Huth {
204*20800179SRichard Henderson     if (likely(reg != 0)) {
205*20800179SRichard Henderson         return cpu_R[reg];
206fcf5ef2aSThomas Huth     }
207*20800179SRichard Henderson     if (!dc->r0_set) {
208*20800179SRichard Henderson         if (dc->r0 == NULL) {
209*20800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
210fcf5ef2aSThomas Huth         }
211*20800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
212*20800179SRichard Henderson         dc->r0_set = true;
213*20800179SRichard Henderson     }
214*20800179SRichard Henderson     return dc->r0;
215fcf5ef2aSThomas Huth }
216fcf5ef2aSThomas Huth 
217*20800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
218*20800179SRichard Henderson {
219*20800179SRichard Henderson     if (likely(reg != 0)) {
220*20800179SRichard Henderson         return cpu_R[reg];
221*20800179SRichard Henderson     }
222*20800179SRichard Henderson     if (dc->r0 == NULL) {
223*20800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
224*20800179SRichard Henderson     }
225*20800179SRichard Henderson     return dc->r0;
226fcf5ef2aSThomas Huth }
227fcf5ef2aSThomas Huth 
228*20800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
229*20800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
230*20800179SRichard Henderson {
231*20800179SRichard Henderson     TCGv_i32 rd, ra, rb;
232*20800179SRichard Henderson 
233*20800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
234*20800179SRichard Henderson         return true;
235fcf5ef2aSThomas Huth     }
236*20800179SRichard Henderson 
237*20800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
238*20800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
239*20800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
240*20800179SRichard Henderson     fn(rd, ra, rb);
241*20800179SRichard Henderson     return true;
242*20800179SRichard Henderson }
243*20800179SRichard Henderson 
244*20800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
245*20800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
246*20800179SRichard Henderson {
247*20800179SRichard Henderson     TCGv_i32 rd, ra;
248*20800179SRichard Henderson 
249*20800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
250*20800179SRichard Henderson         return true;
251*20800179SRichard Henderson     }
252*20800179SRichard Henderson 
253*20800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
254*20800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
255*20800179SRichard Henderson     fni(rd, ra, arg->imm);
256*20800179SRichard Henderson     return true;
257*20800179SRichard Henderson }
258*20800179SRichard Henderson 
259*20800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
260*20800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
261*20800179SRichard Henderson {
262*20800179SRichard Henderson     TCGv_i32 rd, ra, imm;
263*20800179SRichard Henderson 
264*20800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
265*20800179SRichard Henderson         return true;
266*20800179SRichard Henderson     }
267*20800179SRichard Henderson 
268*20800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
269*20800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
270*20800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
271*20800179SRichard Henderson 
272*20800179SRichard Henderson     fn(rd, ra, imm);
273*20800179SRichard Henderson 
274*20800179SRichard Henderson     tcg_temp_free_i32(imm);
275*20800179SRichard Henderson     return true;
276*20800179SRichard Henderson }
277*20800179SRichard Henderson 
278*20800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
279*20800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
280*20800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
281*20800179SRichard Henderson 
282*20800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
283*20800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
284*20800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
285*20800179SRichard Henderson 
286*20800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
287*20800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
288*20800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
289*20800179SRichard Henderson 
290*20800179SRichard Henderson /* No input carry, but output carry. */
291*20800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
292*20800179SRichard Henderson {
293*20800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
294*20800179SRichard Henderson 
295*20800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
296*20800179SRichard Henderson 
297*20800179SRichard Henderson     tcg_temp_free_i32(zero);
298*20800179SRichard Henderson }
299*20800179SRichard Henderson 
300*20800179SRichard Henderson /* Input and output carry. */
301*20800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
302*20800179SRichard Henderson {
303*20800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
304*20800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
305*20800179SRichard Henderson 
306*20800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
307*20800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
308*20800179SRichard Henderson 
309*20800179SRichard Henderson     tcg_temp_free_i32(tmp);
310*20800179SRichard Henderson     tcg_temp_free_i32(zero);
311*20800179SRichard Henderson }
312*20800179SRichard Henderson 
313*20800179SRichard Henderson /* Input carry, but no output carry. */
314*20800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
315*20800179SRichard Henderson {
316*20800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
317*20800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
318*20800179SRichard Henderson }
319*20800179SRichard Henderson 
320*20800179SRichard Henderson DO_TYPEA(add, true, gen_add)
321*20800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
322*20800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
323*20800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
324*20800179SRichard Henderson 
325*20800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
326*20800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
327*20800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
328*20800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
329*20800179SRichard Henderson 
330*20800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
331*20800179SRichard Henderson {
332*20800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
333*20800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
334*20800179SRichard Henderson         trap_illegal(dc, true);
335*20800179SRichard Henderson         return true;
336*20800179SRichard Henderson     }
337*20800179SRichard Henderson     /*
338*20800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
339*20800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
340*20800179SRichard Henderson      */
341*20800179SRichard Henderson     return false;
342fcf5ef2aSThomas Huth }
343fcf5ef2aSThomas Huth 
344fcf5ef2aSThomas Huth static void dec_sub(DisasContext *dc)
345fcf5ef2aSThomas Huth {
346fcf5ef2aSThomas Huth     unsigned int u, cmp, k, c;
347cfeea807SEdgar E. Iglesias     TCGv_i32 cf, na;
348fcf5ef2aSThomas Huth 
349fcf5ef2aSThomas Huth     u = dc->imm & 2;
350fcf5ef2aSThomas Huth     k = dc->opcode & 4;
351fcf5ef2aSThomas Huth     c = dc->opcode & 2;
352fcf5ef2aSThomas Huth     cmp = (dc->imm & 1) && (!dc->type_b) && k;
353fcf5ef2aSThomas Huth 
354fcf5ef2aSThomas Huth     if (cmp) {
355fcf5ef2aSThomas Huth         if (dc->rd) {
356fcf5ef2aSThomas Huth             if (u)
357fcf5ef2aSThomas Huth                 gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
358fcf5ef2aSThomas Huth             else
359fcf5ef2aSThomas Huth                 gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
360fcf5ef2aSThomas Huth         }
361fcf5ef2aSThomas Huth         return;
362fcf5ef2aSThomas Huth     }
363fcf5ef2aSThomas Huth 
364fcf5ef2aSThomas Huth     /* Take care of the easy cases first.  */
365fcf5ef2aSThomas Huth     if (k) {
366fcf5ef2aSThomas Huth         /* k - keep carry, no need to update MSR.  */
367fcf5ef2aSThomas Huth         /* If rd == r0, it's a nop.  */
368fcf5ef2aSThomas Huth         if (dc->rd) {
369cfeea807SEdgar E. Iglesias             tcg_gen_sub_i32(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
370fcf5ef2aSThomas Huth 
371fcf5ef2aSThomas Huth             if (c) {
372fcf5ef2aSThomas Huth                 /* c - Add carry into the result.  */
3731074c0fbSRichard Henderson                 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_msr_c);
374fcf5ef2aSThomas Huth             }
375fcf5ef2aSThomas Huth         }
376fcf5ef2aSThomas Huth         return;
377fcf5ef2aSThomas Huth     }
378fcf5ef2aSThomas Huth 
379fcf5ef2aSThomas Huth     /* From now on, we can assume k is zero.  So we need to update MSR.  */
380fcf5ef2aSThomas Huth     /* Extract carry. And complement a into na.  */
381cfeea807SEdgar E. Iglesias     cf = tcg_temp_new_i32();
382cfeea807SEdgar E. Iglesias     na = tcg_temp_new_i32();
383fcf5ef2aSThomas Huth     if (c) {
3841074c0fbSRichard Henderson         tcg_gen_mov_i32(cf, cpu_msr_c);
385fcf5ef2aSThomas Huth     } else {
386cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cf, 1);
387fcf5ef2aSThomas Huth     }
388fcf5ef2aSThomas Huth 
389fcf5ef2aSThomas Huth     /* d = b + ~a + c. carry defaults to 1.  */
390cfeea807SEdgar E. Iglesias     tcg_gen_not_i32(na, cpu_R[dc->ra]);
391fcf5ef2aSThomas Huth 
3921074c0fbSRichard Henderson     gen_helper_carry(cpu_msr_c, na, *(dec_alu_op_b(dc)), cf);
393fcf5ef2aSThomas Huth     if (dc->rd) {
394cfeea807SEdgar E. Iglesias         tcg_gen_add_i32(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
395cfeea807SEdgar E. Iglesias         tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
396fcf5ef2aSThomas Huth     }
397cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(cf);
398cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(na);
399fcf5ef2aSThomas Huth }
400fcf5ef2aSThomas Huth 
401fcf5ef2aSThomas Huth static void dec_pattern(DisasContext *dc)
402fcf5ef2aSThomas Huth {
403fcf5ef2aSThomas Huth     unsigned int mode;
404fcf5ef2aSThomas Huth 
4059ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) {
4069ba8cd45SEdgar E. Iglesias         return;
407fcf5ef2aSThomas Huth     }
408fcf5ef2aSThomas Huth 
409fcf5ef2aSThomas Huth     mode = dc->opcode & 3;
410fcf5ef2aSThomas Huth     switch (mode) {
411fcf5ef2aSThomas Huth         case 0:
412fcf5ef2aSThomas Huth             /* pcmpbf.  */
413fcf5ef2aSThomas Huth             if (dc->rd)
414fcf5ef2aSThomas Huth                 gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
415fcf5ef2aSThomas Huth             break;
416fcf5ef2aSThomas Huth         case 2:
417fcf5ef2aSThomas Huth             if (dc->rd) {
418cfeea807SEdgar E. Iglesias                 tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd],
419fcf5ef2aSThomas Huth                                    cpu_R[dc->ra], cpu_R[dc->rb]);
420fcf5ef2aSThomas Huth             }
421fcf5ef2aSThomas Huth             break;
422fcf5ef2aSThomas Huth         case 3:
423fcf5ef2aSThomas Huth             if (dc->rd) {
424cfeea807SEdgar E. Iglesias                 tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd],
425fcf5ef2aSThomas Huth                                    cpu_R[dc->ra], cpu_R[dc->rb]);
426fcf5ef2aSThomas Huth             }
427fcf5ef2aSThomas Huth             break;
428fcf5ef2aSThomas Huth         default:
429fcf5ef2aSThomas Huth             cpu_abort(CPU(dc->cpu),
430fcf5ef2aSThomas Huth                       "unsupported pattern insn opcode=%x\n", dc->opcode);
431fcf5ef2aSThomas Huth             break;
432fcf5ef2aSThomas Huth     }
433fcf5ef2aSThomas Huth }
434fcf5ef2aSThomas Huth 
435fcf5ef2aSThomas Huth static void dec_and(DisasContext *dc)
436fcf5ef2aSThomas Huth {
437fcf5ef2aSThomas Huth     unsigned int not;
438fcf5ef2aSThomas Huth 
439fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
440fcf5ef2aSThomas Huth         dec_pattern(dc);
441fcf5ef2aSThomas Huth         return;
442fcf5ef2aSThomas Huth     }
443fcf5ef2aSThomas Huth 
444fcf5ef2aSThomas Huth     not = dc->opcode & (1 << 1);
445fcf5ef2aSThomas Huth 
446fcf5ef2aSThomas Huth     if (!dc->rd)
447fcf5ef2aSThomas Huth         return;
448fcf5ef2aSThomas Huth 
449fcf5ef2aSThomas Huth     if (not) {
450cfeea807SEdgar E. Iglesias         tcg_gen_andc_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
451fcf5ef2aSThomas Huth     } else
452cfeea807SEdgar E. Iglesias         tcg_gen_and_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
453fcf5ef2aSThomas Huth }
454fcf5ef2aSThomas Huth 
455fcf5ef2aSThomas Huth static void dec_or(DisasContext *dc)
456fcf5ef2aSThomas Huth {
457fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
458fcf5ef2aSThomas Huth         dec_pattern(dc);
459fcf5ef2aSThomas Huth         return;
460fcf5ef2aSThomas Huth     }
461fcf5ef2aSThomas Huth 
462fcf5ef2aSThomas Huth     if (dc->rd)
463cfeea807SEdgar E. Iglesias         tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
464fcf5ef2aSThomas Huth }
465fcf5ef2aSThomas Huth 
466fcf5ef2aSThomas Huth static void dec_xor(DisasContext *dc)
467fcf5ef2aSThomas Huth {
468fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
469fcf5ef2aSThomas Huth         dec_pattern(dc);
470fcf5ef2aSThomas Huth         return;
471fcf5ef2aSThomas Huth     }
472fcf5ef2aSThomas Huth 
473fcf5ef2aSThomas Huth     if (dc->rd)
474cfeea807SEdgar E. Iglesias         tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
475fcf5ef2aSThomas Huth }
476fcf5ef2aSThomas Huth 
4771074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
478fcf5ef2aSThomas Huth {
4791074c0fbSRichard Henderson     TCGv_i32 t;
4801074c0fbSRichard Henderson 
4811074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
4821074c0fbSRichard Henderson     t = tcg_temp_new_i32();
4831074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
4841074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
4851074c0fbSRichard Henderson     tcg_temp_free_i32(t);
486fcf5ef2aSThomas Huth }
487fcf5ef2aSThomas Huth 
4881074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v)
489fcf5ef2aSThomas Huth {
490fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
4911074c0fbSRichard Henderson 
4921074c0fbSRichard Henderson     /* Install MSR_C.  */
4931074c0fbSRichard Henderson     tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
4941074c0fbSRichard Henderson 
4951074c0fbSRichard Henderson     /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
4961074c0fbSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
497fcf5ef2aSThomas Huth }
498fcf5ef2aSThomas Huth 
499fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc)
500fcf5ef2aSThomas Huth {
501fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
502cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
5032023e9a3SEdgar E. Iglesias     unsigned int sr, rn;
504f0f7e7f7SEdgar E. Iglesias     bool to, clrset, extended = false;
505fcf5ef2aSThomas Huth 
5062023e9a3SEdgar E. Iglesias     sr = extract32(dc->imm, 0, 14);
5072023e9a3SEdgar E. Iglesias     to = extract32(dc->imm, 14, 1);
5082023e9a3SEdgar E. Iglesias     clrset = extract32(dc->imm, 15, 1) == 0;
509fcf5ef2aSThomas Huth     dc->type_b = 1;
5102023e9a3SEdgar E. Iglesias     if (to) {
511fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
512f0f7e7f7SEdgar E. Iglesias     }
513f0f7e7f7SEdgar E. Iglesias 
514f0f7e7f7SEdgar E. Iglesias     /* Extended MSRs are only available if addr_size > 32.  */
515f0f7e7f7SEdgar E. Iglesias     if (dc->cpu->cfg.addr_size > 32) {
516f0f7e7f7SEdgar E. Iglesias         /* The E-bit is encoded differently for To/From MSR.  */
517f0f7e7f7SEdgar E. Iglesias         static const unsigned int e_bit[] = { 19, 24 };
518f0f7e7f7SEdgar E. Iglesias 
519f0f7e7f7SEdgar E. Iglesias         extended = extract32(dc->imm, e_bit[to], 1);
5202023e9a3SEdgar E. Iglesias     }
521fcf5ef2aSThomas Huth 
522fcf5ef2aSThomas Huth     /* msrclr and msrset.  */
5232023e9a3SEdgar E. Iglesias     if (clrset) {
5242023e9a3SEdgar E. Iglesias         bool clr = extract32(dc->ir, 16, 1);
525fcf5ef2aSThomas Huth 
52656837509SEdgar E. Iglesias         if (!dc->cpu->cfg.use_msr_instr) {
527fcf5ef2aSThomas Huth             /* nop??? */
528fcf5ef2aSThomas Huth             return;
529fcf5ef2aSThomas Huth         }
530fcf5ef2aSThomas Huth 
531bdfc1e88SEdgar E. Iglesias         if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
532fcf5ef2aSThomas Huth             return;
533fcf5ef2aSThomas Huth         }
534fcf5ef2aSThomas Huth 
535fcf5ef2aSThomas Huth         if (dc->rd)
536fcf5ef2aSThomas Huth             msr_read(dc, cpu_R[dc->rd]);
537fcf5ef2aSThomas Huth 
538cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
539cfeea807SEdgar E. Iglesias         t1 = tcg_temp_new_i32();
540fcf5ef2aSThomas Huth         msr_read(dc, t0);
541cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
542fcf5ef2aSThomas Huth 
543fcf5ef2aSThomas Huth         if (clr) {
544cfeea807SEdgar E. Iglesias             tcg_gen_not_i32(t1, t1);
545cfeea807SEdgar E. Iglesias             tcg_gen_and_i32(t0, t0, t1);
546fcf5ef2aSThomas Huth         } else
547cfeea807SEdgar E. Iglesias             tcg_gen_or_i32(t0, t0, t1);
548fcf5ef2aSThomas Huth         msr_write(dc, t0);
549cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
550cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t1);
551d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
552d4705ae0SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
553fcf5ef2aSThomas Huth         return;
554fcf5ef2aSThomas Huth     }
555fcf5ef2aSThomas Huth 
556bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, to)) {
557fcf5ef2aSThomas Huth         return;
558fcf5ef2aSThomas Huth     }
559fcf5ef2aSThomas Huth 
560fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
561fcf5ef2aSThomas Huth     /* Catch read/writes to the mmu block.  */
562fcf5ef2aSThomas Huth     if ((sr & ~0xff) == 0x1000) {
563f0f7e7f7SEdgar E. Iglesias         TCGv_i32 tmp_ext = tcg_const_i32(extended);
56405a9a651SEdgar E. Iglesias         TCGv_i32 tmp_sr;
56505a9a651SEdgar E. Iglesias 
566fcf5ef2aSThomas Huth         sr &= 7;
56705a9a651SEdgar E. Iglesias         tmp_sr = tcg_const_i32(sr);
56805a9a651SEdgar E. Iglesias         if (to) {
569f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
57005a9a651SEdgar E. Iglesias         } else {
571f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
57205a9a651SEdgar E. Iglesias         }
57305a9a651SEdgar E. Iglesias         tcg_temp_free_i32(tmp_sr);
574f0f7e7f7SEdgar E. Iglesias         tcg_temp_free_i32(tmp_ext);
575fcf5ef2aSThomas Huth         return;
576fcf5ef2aSThomas Huth     }
577fcf5ef2aSThomas Huth #endif
578fcf5ef2aSThomas Huth 
579fcf5ef2aSThomas Huth     if (to) {
580fcf5ef2aSThomas Huth         switch (sr) {
581aa28e6d4SRichard Henderson             case SR_PC:
582fcf5ef2aSThomas Huth                 break;
583aa28e6d4SRichard Henderson             case SR_MSR:
584fcf5ef2aSThomas Huth                 msr_write(dc, cpu_R[dc->ra]);
585fcf5ef2aSThomas Huth                 break;
586351527b7SEdgar E. Iglesias             case SR_EAR:
587dbdb77c4SRichard Henderson                 {
588dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
589dbdb77c4SRichard Henderson                     tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]);
590dbdb77c4SRichard Henderson                     tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear));
591dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
592dbdb77c4SRichard Henderson                 }
593aa28e6d4SRichard Henderson                 break;
594351527b7SEdgar E. Iglesias             case SR_ESR:
59541ba37c4SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
59641ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
597aa28e6d4SRichard Henderson                 break;
598ab6dd380SEdgar E. Iglesias             case SR_FSR:
59986017ccfSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
60086017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
601aa28e6d4SRichard Henderson                 break;
602aa28e6d4SRichard Henderson             case SR_BTR:
603ccf628b7SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
604ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
605aa28e6d4SRichard Henderson                 break;
606aa28e6d4SRichard Henderson             case SR_EDR:
60739db007eSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
60839db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
609fcf5ef2aSThomas Huth                 break;
610fcf5ef2aSThomas Huth             case 0x800:
611cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
612cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
613fcf5ef2aSThomas Huth                 break;
614fcf5ef2aSThomas Huth             case 0x802:
615cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
616cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
617fcf5ef2aSThomas Huth                 break;
618fcf5ef2aSThomas Huth             default:
619fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
620fcf5ef2aSThomas Huth                 break;
621fcf5ef2aSThomas Huth         }
622fcf5ef2aSThomas Huth     } else {
623fcf5ef2aSThomas Huth         switch (sr) {
624aa28e6d4SRichard Henderson             case SR_PC:
625d4705ae0SRichard Henderson                 tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
626fcf5ef2aSThomas Huth                 break;
627aa28e6d4SRichard Henderson             case SR_MSR:
628fcf5ef2aSThomas Huth                 msr_read(dc, cpu_R[dc->rd]);
629fcf5ef2aSThomas Huth                 break;
630351527b7SEdgar E. Iglesias             case SR_EAR:
631dbdb77c4SRichard Henderson                 {
632dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
633dbdb77c4SRichard Henderson                     tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
634a1b48e3aSEdgar E. Iglesias                     if (extended) {
635dbdb77c4SRichard Henderson                         tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64);
636aa28e6d4SRichard Henderson                     } else {
637dbdb77c4SRichard Henderson                         tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64);
638dbdb77c4SRichard Henderson                     }
639dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
640a1b48e3aSEdgar E. Iglesias                 }
641aa28e6d4SRichard Henderson                 break;
642351527b7SEdgar E. Iglesias             case SR_ESR:
64341ba37c4SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
64441ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
645aa28e6d4SRichard Henderson                 break;
646351527b7SEdgar E. Iglesias             case SR_FSR:
64786017ccfSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
64886017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
649aa28e6d4SRichard Henderson                 break;
650351527b7SEdgar E. Iglesias             case SR_BTR:
651ccf628b7SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
652ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
653aa28e6d4SRichard Henderson                 break;
6547cdae31dSTong Ho             case SR_EDR:
65539db007eSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
65639db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
657fcf5ef2aSThomas Huth                 break;
658fcf5ef2aSThomas Huth             case 0x800:
659cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
660cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
661fcf5ef2aSThomas Huth                 break;
662fcf5ef2aSThomas Huth             case 0x802:
663cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
664cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
665fcf5ef2aSThomas Huth                 break;
666351527b7SEdgar E. Iglesias             case 0x2000 ... 0x200c:
667fcf5ef2aSThomas Huth                 rn = sr & 0xf;
668cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
669fcf5ef2aSThomas Huth                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
670fcf5ef2aSThomas Huth                 break;
671fcf5ef2aSThomas Huth             default:
672fcf5ef2aSThomas Huth                 cpu_abort(cs, "unknown mfs reg %x\n", sr);
673fcf5ef2aSThomas Huth                 break;
674fcf5ef2aSThomas Huth         }
675fcf5ef2aSThomas Huth     }
676fcf5ef2aSThomas Huth 
677fcf5ef2aSThomas Huth     if (dc->rd == 0) {
678cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[0], 0);
679fcf5ef2aSThomas Huth     }
680fcf5ef2aSThomas Huth }
681fcf5ef2aSThomas Huth 
682fcf5ef2aSThomas Huth /* Multiplier unit.  */
683fcf5ef2aSThomas Huth static void dec_mul(DisasContext *dc)
684fcf5ef2aSThomas Huth {
685cfeea807SEdgar E. Iglesias     TCGv_i32 tmp;
686fcf5ef2aSThomas Huth     unsigned int subcode;
687fcf5ef2aSThomas Huth 
6889ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_hw_mul)) {
689fcf5ef2aSThomas Huth         return;
690fcf5ef2aSThomas Huth     }
691fcf5ef2aSThomas Huth 
692fcf5ef2aSThomas Huth     subcode = dc->imm & 3;
693fcf5ef2aSThomas Huth 
694fcf5ef2aSThomas Huth     if (dc->type_b) {
695cfeea807SEdgar E. Iglesias         tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
696fcf5ef2aSThomas Huth         return;
697fcf5ef2aSThomas Huth     }
698fcf5ef2aSThomas Huth 
699fcf5ef2aSThomas Huth     /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2.  */
7009b964318SEdgar E. Iglesias     if (subcode >= 1 && subcode <= 3 && dc->cpu->cfg.use_hw_mul < 2) {
701fcf5ef2aSThomas Huth         /* nop??? */
702fcf5ef2aSThomas Huth     }
703fcf5ef2aSThomas Huth 
704cfeea807SEdgar E. Iglesias     tmp = tcg_temp_new_i32();
705fcf5ef2aSThomas Huth     switch (subcode) {
706fcf5ef2aSThomas Huth         case 0:
707cfeea807SEdgar E. Iglesias             tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
708fcf5ef2aSThomas Huth             break;
709fcf5ef2aSThomas Huth         case 1:
710cfeea807SEdgar E. Iglesias             tcg_gen_muls2_i32(tmp, cpu_R[dc->rd],
711cfeea807SEdgar E. Iglesias                               cpu_R[dc->ra], cpu_R[dc->rb]);
712fcf5ef2aSThomas Huth             break;
713fcf5ef2aSThomas Huth         case 2:
714cfeea807SEdgar E. Iglesias             tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd],
715cfeea807SEdgar E. Iglesias                                cpu_R[dc->ra], cpu_R[dc->rb]);
716fcf5ef2aSThomas Huth             break;
717fcf5ef2aSThomas Huth         case 3:
718cfeea807SEdgar E. Iglesias             tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
719fcf5ef2aSThomas Huth             break;
720fcf5ef2aSThomas Huth         default:
721fcf5ef2aSThomas Huth             cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode);
722fcf5ef2aSThomas Huth             break;
723fcf5ef2aSThomas Huth     }
724cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(tmp);
725fcf5ef2aSThomas Huth }
726fcf5ef2aSThomas Huth 
727fcf5ef2aSThomas Huth /* Div unit.  */
728fcf5ef2aSThomas Huth static void dec_div(DisasContext *dc)
729fcf5ef2aSThomas Huth {
730fcf5ef2aSThomas Huth     unsigned int u;
731fcf5ef2aSThomas Huth 
732fcf5ef2aSThomas Huth     u = dc->imm & 2;
733fcf5ef2aSThomas Huth 
7349ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_div)) {
7359ba8cd45SEdgar E. Iglesias         return;
736fcf5ef2aSThomas Huth     }
737fcf5ef2aSThomas Huth 
738fcf5ef2aSThomas Huth     if (u)
739fcf5ef2aSThomas Huth         gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
740fcf5ef2aSThomas Huth                         cpu_R[dc->ra]);
741fcf5ef2aSThomas Huth     else
742fcf5ef2aSThomas Huth         gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
743fcf5ef2aSThomas Huth                         cpu_R[dc->ra]);
744fcf5ef2aSThomas Huth     if (!dc->rd)
745cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[dc->rd], 0);
746fcf5ef2aSThomas Huth }
747fcf5ef2aSThomas Huth 
748fcf5ef2aSThomas Huth static void dec_barrel(DisasContext *dc)
749fcf5ef2aSThomas Huth {
750cfeea807SEdgar E. Iglesias     TCGv_i32 t0;
751faa48d74SEdgar E. Iglesias     unsigned int imm_w, imm_s;
752d09b2585SEdgar E. Iglesias     bool s, t, e = false, i = false;
753fcf5ef2aSThomas Huth 
7549ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) {
755fcf5ef2aSThomas Huth         return;
756fcf5ef2aSThomas Huth     }
757fcf5ef2aSThomas Huth 
758faa48d74SEdgar E. Iglesias     if (dc->type_b) {
759faa48d74SEdgar E. Iglesias         /* Insert and extract are only available in immediate mode.  */
760d09b2585SEdgar E. Iglesias         i = extract32(dc->imm, 15, 1);
761faa48d74SEdgar E. Iglesias         e = extract32(dc->imm, 14, 1);
762faa48d74SEdgar E. Iglesias     }
763e3e84983SEdgar E. Iglesias     s = extract32(dc->imm, 10, 1);
764e3e84983SEdgar E. Iglesias     t = extract32(dc->imm, 9, 1);
765faa48d74SEdgar E. Iglesias     imm_w = extract32(dc->imm, 6, 5);
766faa48d74SEdgar E. Iglesias     imm_s = extract32(dc->imm, 0, 5);
767fcf5ef2aSThomas Huth 
768faa48d74SEdgar E. Iglesias     if (e) {
769faa48d74SEdgar E. Iglesias         if (imm_w + imm_s > 32 || imm_w == 0) {
770faa48d74SEdgar E. Iglesias             /* These inputs have an undefined behavior.  */
771faa48d74SEdgar E. Iglesias             qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
772faa48d74SEdgar E. Iglesias                           imm_w, imm_s);
773faa48d74SEdgar E. Iglesias         } else {
774faa48d74SEdgar E. Iglesias             tcg_gen_extract_i32(cpu_R[dc->rd], cpu_R[dc->ra], imm_s, imm_w);
775faa48d74SEdgar E. Iglesias         }
776d09b2585SEdgar E. Iglesias     } else if (i) {
777d09b2585SEdgar E. Iglesias         int width = imm_w - imm_s + 1;
778d09b2585SEdgar E. Iglesias 
779d09b2585SEdgar E. Iglesias         if (imm_w < imm_s) {
780d09b2585SEdgar E. Iglesias             /* These inputs have an undefined behavior.  */
781d09b2585SEdgar E. Iglesias             qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
782d09b2585SEdgar E. Iglesias                           imm_w, imm_s);
783d09b2585SEdgar E. Iglesias         } else {
784d09b2585SEdgar E. Iglesias             tcg_gen_deposit_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_R[dc->ra],
785d09b2585SEdgar E. Iglesias                                 imm_s, width);
786d09b2585SEdgar E. Iglesias         }
787faa48d74SEdgar E. Iglesias     } else {
788cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
789fcf5ef2aSThomas Huth 
790cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc)));
791cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t0, t0, 31);
792fcf5ef2aSThomas Huth 
7932acf6d53SEdgar E. Iglesias         if (s) {
794cfeea807SEdgar E. Iglesias             tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
7952acf6d53SEdgar E. Iglesias         } else {
7962acf6d53SEdgar E. Iglesias             if (t) {
797cfeea807SEdgar E. Iglesias                 tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
7982acf6d53SEdgar E. Iglesias             } else {
799cfeea807SEdgar E. Iglesias                 tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
800fcf5ef2aSThomas Huth             }
801fcf5ef2aSThomas Huth         }
802cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
8032acf6d53SEdgar E. Iglesias     }
804faa48d74SEdgar E. Iglesias }
805fcf5ef2aSThomas Huth 
806fcf5ef2aSThomas Huth static void dec_bit(DisasContext *dc)
807fcf5ef2aSThomas Huth {
808fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
809cfeea807SEdgar E. Iglesias     TCGv_i32 t0;
810fcf5ef2aSThomas Huth     unsigned int op;
811fcf5ef2aSThomas Huth 
812fcf5ef2aSThomas Huth     op = dc->ir & ((1 << 9) - 1);
813fcf5ef2aSThomas Huth     switch (op) {
814fcf5ef2aSThomas Huth         case 0x21:
815fcf5ef2aSThomas Huth             /* src.  */
816cfeea807SEdgar E. Iglesias             t0 = tcg_temp_new_i32();
817fcf5ef2aSThomas Huth 
8181074c0fbSRichard Henderson             tcg_gen_shli_i32(t0, cpu_msr_c, 31);
8191074c0fbSRichard Henderson             tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1);
820fcf5ef2aSThomas Huth             if (dc->rd) {
821cfeea807SEdgar E. Iglesias                 tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
822cfeea807SEdgar E. Iglesias                 tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0);
823fcf5ef2aSThomas Huth             }
824cfeea807SEdgar E. Iglesias             tcg_temp_free_i32(t0);
825fcf5ef2aSThomas Huth             break;
826fcf5ef2aSThomas Huth 
827fcf5ef2aSThomas Huth         case 0x1:
828fcf5ef2aSThomas Huth         case 0x41:
829fcf5ef2aSThomas Huth             /* srl.  */
8301074c0fbSRichard Henderson             tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1);
831fcf5ef2aSThomas Huth             if (dc->rd) {
832fcf5ef2aSThomas Huth                 if (op == 0x41)
833cfeea807SEdgar E. Iglesias                     tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
834fcf5ef2aSThomas Huth                 else
835cfeea807SEdgar E. Iglesias                     tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
836fcf5ef2aSThomas Huth             }
837fcf5ef2aSThomas Huth             break;
838fcf5ef2aSThomas Huth         case 0x60:
839fcf5ef2aSThomas Huth             tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
840fcf5ef2aSThomas Huth             break;
841fcf5ef2aSThomas Huth         case 0x61:
842fcf5ef2aSThomas Huth             tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
843fcf5ef2aSThomas Huth             break;
844fcf5ef2aSThomas Huth         case 0x64:
845fcf5ef2aSThomas Huth         case 0x66:
846fcf5ef2aSThomas Huth         case 0x74:
847fcf5ef2aSThomas Huth         case 0x76:
848fcf5ef2aSThomas Huth             /* wdc.  */
849bdfc1e88SEdgar E. Iglesias             trap_userspace(dc, true);
850fcf5ef2aSThomas Huth             break;
851fcf5ef2aSThomas Huth         case 0x68:
852fcf5ef2aSThomas Huth             /* wic.  */
853bdfc1e88SEdgar E. Iglesias             trap_userspace(dc, true);
854fcf5ef2aSThomas Huth             break;
855fcf5ef2aSThomas Huth         case 0xe0:
8569ba8cd45SEdgar E. Iglesias             if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) {
8579ba8cd45SEdgar E. Iglesias                 return;
858fcf5ef2aSThomas Huth             }
8598fc5239eSEdgar E. Iglesias             if (dc->cpu->cfg.use_pcmp_instr) {
8605318420cSRichard Henderson                 tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32);
861fcf5ef2aSThomas Huth             }
862fcf5ef2aSThomas Huth             break;
863fcf5ef2aSThomas Huth         case 0x1e0:
864fcf5ef2aSThomas Huth             /* swapb */
865fcf5ef2aSThomas Huth             tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
866fcf5ef2aSThomas Huth             break;
867fcf5ef2aSThomas Huth         case 0x1e2:
868fcf5ef2aSThomas Huth             /*swaph */
869fcf5ef2aSThomas Huth             tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16);
870fcf5ef2aSThomas Huth             break;
871fcf5ef2aSThomas Huth         default:
872fcf5ef2aSThomas Huth             cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
873d4705ae0SRichard Henderson                       (uint32_t)dc->base.pc_next, op, dc->rd, dc->ra, dc->rb);
874fcf5ef2aSThomas Huth             break;
875fcf5ef2aSThomas Huth     }
876fcf5ef2aSThomas Huth }
877fcf5ef2aSThomas Huth 
878fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc)
879fcf5ef2aSThomas Huth {
880fcf5ef2aSThomas Huth     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
881fcf5ef2aSThomas Huth         if (dc->jmp == JMP_DIRECT) {
8829b158558SRichard Henderson             tcg_gen_movi_i32(cpu_btaken, 1);
883fcf5ef2aSThomas Huth         }
884fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
8850f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
886fcf5ef2aSThomas Huth     }
887fcf5ef2aSThomas Huth }
888fcf5ef2aSThomas Huth 
889fcf5ef2aSThomas Huth static void dec_imm(DisasContext *dc)
890fcf5ef2aSThomas Huth {
891d7ecb757SRichard Henderson     dc->ext_imm = dc->imm << 16;
892d7ecb757SRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
893fcf5ef2aSThomas Huth     dc->tb_flags |= IMM_FLAG;
894fcf5ef2aSThomas Huth     dc->clear_imm = 0;
895fcf5ef2aSThomas Huth }
896fcf5ef2aSThomas Huth 
897d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t)
898fcf5ef2aSThomas Huth {
8990e9033c8SEdgar E. Iglesias     /* Should be set to true if r1 is used by loadstores.  */
9000e9033c8SEdgar E. Iglesias     bool stackprot = false;
901403322eaSEdgar E. Iglesias     TCGv_i32 t32;
902fcf5ef2aSThomas Huth 
903fcf5ef2aSThomas Huth     /* All load/stores use ra.  */
904fcf5ef2aSThomas Huth     if (dc->ra == 1 && dc->cpu->cfg.stackprot) {
9050e9033c8SEdgar E. Iglesias         stackprot = true;
906fcf5ef2aSThomas Huth     }
907fcf5ef2aSThomas Huth 
908fcf5ef2aSThomas Huth     /* Treat the common cases first.  */
909fcf5ef2aSThomas Huth     if (!dc->type_b) {
910d248e1beSEdgar E. Iglesias         if (ea) {
911d248e1beSEdgar E. Iglesias             int addr_size = dc->cpu->cfg.addr_size;
912d248e1beSEdgar E. Iglesias 
913d248e1beSEdgar E. Iglesias             if (addr_size == 32) {
914d248e1beSEdgar E. Iglesias                 tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
915d248e1beSEdgar E. Iglesias                 return;
916d248e1beSEdgar E. Iglesias             }
917d248e1beSEdgar E. Iglesias 
918d248e1beSEdgar E. Iglesias             tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]);
919d248e1beSEdgar E. Iglesias             if (addr_size < 64) {
920d248e1beSEdgar E. Iglesias                 /* Mask off out of range bits.  */
921d248e1beSEdgar E. Iglesias                 tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size));
922d248e1beSEdgar E. Iglesias             }
923d248e1beSEdgar E. Iglesias             return;
924d248e1beSEdgar E. Iglesias         }
925d248e1beSEdgar E. Iglesias 
9260dc4af5cSEdgar E. Iglesias         /* If any of the regs is r0, set t to the value of the other reg.  */
927fcf5ef2aSThomas Huth         if (dc->ra == 0) {
928403322eaSEdgar E. Iglesias             tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
9290dc4af5cSEdgar E. Iglesias             return;
930fcf5ef2aSThomas Huth         } else if (dc->rb == 0) {
931403322eaSEdgar E. Iglesias             tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]);
9320dc4af5cSEdgar E. Iglesias             return;
933fcf5ef2aSThomas Huth         }
934fcf5ef2aSThomas Huth 
935fcf5ef2aSThomas Huth         if (dc->rb == 1 && dc->cpu->cfg.stackprot) {
9360e9033c8SEdgar E. Iglesias             stackprot = true;
937fcf5ef2aSThomas Huth         }
938fcf5ef2aSThomas Huth 
939403322eaSEdgar E. Iglesias         t32 = tcg_temp_new_i32();
940403322eaSEdgar E. Iglesias         tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]);
941403322eaSEdgar E. Iglesias         tcg_gen_extu_i32_tl(t, t32);
942403322eaSEdgar E. Iglesias         tcg_temp_free_i32(t32);
943fcf5ef2aSThomas Huth 
944fcf5ef2aSThomas Huth         if (stackprot) {
9450a87e691SEdgar E. Iglesias             gen_helper_stackprot(cpu_env, t);
946fcf5ef2aSThomas Huth         }
9470dc4af5cSEdgar E. Iglesias         return;
948fcf5ef2aSThomas Huth     }
949fcf5ef2aSThomas Huth     /* Immediate.  */
950403322eaSEdgar E. Iglesias     t32 = tcg_temp_new_i32();
951d7ecb757SRichard Henderson     tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc));
952403322eaSEdgar E. Iglesias     tcg_gen_extu_i32_tl(t, t32);
953403322eaSEdgar E. Iglesias     tcg_temp_free_i32(t32);
954fcf5ef2aSThomas Huth 
955fcf5ef2aSThomas Huth     if (stackprot) {
9560a87e691SEdgar E. Iglesias         gen_helper_stackprot(cpu_env, t);
957fcf5ef2aSThomas Huth     }
9580dc4af5cSEdgar E. Iglesias     return;
959fcf5ef2aSThomas Huth }
960fcf5ef2aSThomas Huth 
961fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc)
962fcf5ef2aSThomas Huth {
963403322eaSEdgar E. Iglesias     TCGv_i32 v;
964403322eaSEdgar E. Iglesias     TCGv addr;
9658534063aSEdgar E. Iglesias     unsigned int size;
966d248e1beSEdgar E. Iglesias     bool rev = false, ex = false, ea = false;
967d248e1beSEdgar E. Iglesias     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
96814776ab5STony Nguyen     MemOp mop;
969fcf5ef2aSThomas Huth 
970fcf5ef2aSThomas Huth     mop = dc->opcode & 3;
971fcf5ef2aSThomas Huth     size = 1 << mop;
972fcf5ef2aSThomas Huth     if (!dc->type_b) {
973d248e1beSEdgar E. Iglesias         ea = extract32(dc->ir, 7, 1);
9748534063aSEdgar E. Iglesias         rev = extract32(dc->ir, 9, 1);
9758534063aSEdgar E. Iglesias         ex = extract32(dc->ir, 10, 1);
976fcf5ef2aSThomas Huth     }
977fcf5ef2aSThomas Huth     mop |= MO_TE;
978fcf5ef2aSThomas Huth     if (rev) {
979fcf5ef2aSThomas Huth         mop ^= MO_BSWAP;
980fcf5ef2aSThomas Huth     }
981fcf5ef2aSThomas Huth 
9829ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, size > 4)) {
983fcf5ef2aSThomas Huth         return;
984fcf5ef2aSThomas Huth     }
985fcf5ef2aSThomas Huth 
986d248e1beSEdgar E. Iglesias     if (trap_userspace(dc, ea)) {
987d248e1beSEdgar E. Iglesias         return;
988d248e1beSEdgar E. Iglesias     }
989d248e1beSEdgar E. Iglesias 
990fcf5ef2aSThomas Huth     t_sync_flags(dc);
991403322eaSEdgar E. Iglesias     addr = tcg_temp_new();
992d248e1beSEdgar E. Iglesias     compute_ldst_addr(dc, ea, addr);
993d248e1beSEdgar E. Iglesias     /* Extended addressing bypasses the MMU.  */
994d248e1beSEdgar E. Iglesias     mem_index = ea ? MMU_NOMMU_IDX : mem_index;
995fcf5ef2aSThomas Huth 
996fcf5ef2aSThomas Huth     /*
997fcf5ef2aSThomas Huth      * When doing reverse accesses we need to do two things.
998fcf5ef2aSThomas Huth      *
999fcf5ef2aSThomas Huth      * 1. Reverse the address wrt endianness.
1000fcf5ef2aSThomas Huth      * 2. Byteswap the data lanes on the way back into the CPU core.
1001fcf5ef2aSThomas Huth      */
1002fcf5ef2aSThomas Huth     if (rev && size != 4) {
1003fcf5ef2aSThomas Huth         /* Endian reverse the address. t is addr.  */
1004fcf5ef2aSThomas Huth         switch (size) {
1005fcf5ef2aSThomas Huth             case 1:
1006fcf5ef2aSThomas Huth             {
1007a6338015SEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 3);
1008fcf5ef2aSThomas Huth                 break;
1009fcf5ef2aSThomas Huth             }
1010fcf5ef2aSThomas Huth 
1011fcf5ef2aSThomas Huth             case 2:
1012fcf5ef2aSThomas Huth                 /* 00 -> 10
1013fcf5ef2aSThomas Huth                    10 -> 00.  */
1014403322eaSEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 2);
1015fcf5ef2aSThomas Huth                 break;
1016fcf5ef2aSThomas Huth             default:
1017fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
1018fcf5ef2aSThomas Huth                 break;
1019fcf5ef2aSThomas Huth         }
1020fcf5ef2aSThomas Huth     }
1021fcf5ef2aSThomas Huth 
1022fcf5ef2aSThomas Huth     /* lwx does not throw unaligned access errors, so force alignment */
1023fcf5ef2aSThomas Huth     if (ex) {
1024403322eaSEdgar E. Iglesias         tcg_gen_andi_tl(addr, addr, ~3);
1025fcf5ef2aSThomas Huth     }
1026fcf5ef2aSThomas Huth 
1027fcf5ef2aSThomas Huth     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
1028fcf5ef2aSThomas Huth     sync_jmpstate(dc);
1029fcf5ef2aSThomas Huth 
1030fcf5ef2aSThomas Huth     /* Verify alignment if needed.  */
1031fcf5ef2aSThomas Huth     /*
1032fcf5ef2aSThomas Huth      * Microblaze gives MMU faults priority over faults due to
1033fcf5ef2aSThomas Huth      * unaligned addresses. That's why we speculatively do the load
1034fcf5ef2aSThomas Huth      * into v. If the load succeeds, we verify alignment of the
1035fcf5ef2aSThomas Huth      * address and if that succeeds we write into the destination reg.
1036fcf5ef2aSThomas Huth      */
1037cfeea807SEdgar E. Iglesias     v = tcg_temp_new_i32();
1038d248e1beSEdgar E. Iglesias     tcg_gen_qemu_ld_i32(v, addr, mem_index, mop);
1039fcf5ef2aSThomas Huth 
10401507e5f6SEdgar E. Iglesias     if (dc->cpu->cfg.unaligned_exceptions && size > 1) {
1041a6338015SEdgar E. Iglesias         TCGv_i32 t0 = tcg_const_i32(0);
1042a6338015SEdgar E. Iglesias         TCGv_i32 treg = tcg_const_i32(dc->rd);
1043a6338015SEdgar E. Iglesias         TCGv_i32 tsize = tcg_const_i32(size - 1);
1044a6338015SEdgar E. Iglesias 
1045d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1046a6338015SEdgar E. Iglesias         gen_helper_memalign(cpu_env, addr, treg, t0, tsize);
1047a6338015SEdgar E. Iglesias 
1048a6338015SEdgar E. Iglesias         tcg_temp_free_i32(t0);
1049a6338015SEdgar E. Iglesias         tcg_temp_free_i32(treg);
1050a6338015SEdgar E. Iglesias         tcg_temp_free_i32(tsize);
1051fcf5ef2aSThomas Huth     }
1052fcf5ef2aSThomas Huth 
1053fcf5ef2aSThomas Huth     if (ex) {
10549b158558SRichard Henderson         tcg_gen_mov_tl(cpu_res_addr, addr);
10559b158558SRichard Henderson         tcg_gen_mov_i32(cpu_res_val, v);
1056fcf5ef2aSThomas Huth     }
1057fcf5ef2aSThomas Huth     if (dc->rd) {
1058cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(cpu_R[dc->rd], v);
1059fcf5ef2aSThomas Huth     }
1060cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(v);
1061fcf5ef2aSThomas Huth 
1062fcf5ef2aSThomas Huth     if (ex) { /* lwx */
1063fcf5ef2aSThomas Huth         /* no support for AXI exclusive so always clear C */
10641074c0fbSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, 0);
1065fcf5ef2aSThomas Huth     }
1066fcf5ef2aSThomas Huth 
1067403322eaSEdgar E. Iglesias     tcg_temp_free(addr);
1068fcf5ef2aSThomas Huth }
1069fcf5ef2aSThomas Huth 
1070fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc)
1071fcf5ef2aSThomas Huth {
1072403322eaSEdgar E. Iglesias     TCGv addr;
1073fcf5ef2aSThomas Huth     TCGLabel *swx_skip = NULL;
1074b51b3d43SEdgar E. Iglesias     unsigned int size;
1075d248e1beSEdgar E. Iglesias     bool rev = false, ex = false, ea = false;
1076d248e1beSEdgar E. Iglesias     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
107714776ab5STony Nguyen     MemOp mop;
1078fcf5ef2aSThomas Huth 
1079fcf5ef2aSThomas Huth     mop = dc->opcode & 3;
1080fcf5ef2aSThomas Huth     size = 1 << mop;
1081fcf5ef2aSThomas Huth     if (!dc->type_b) {
1082d248e1beSEdgar E. Iglesias         ea = extract32(dc->ir, 7, 1);
1083b51b3d43SEdgar E. Iglesias         rev = extract32(dc->ir, 9, 1);
1084b51b3d43SEdgar E. Iglesias         ex = extract32(dc->ir, 10, 1);
1085fcf5ef2aSThomas Huth     }
1086fcf5ef2aSThomas Huth     mop |= MO_TE;
1087fcf5ef2aSThomas Huth     if (rev) {
1088fcf5ef2aSThomas Huth         mop ^= MO_BSWAP;
1089fcf5ef2aSThomas Huth     }
1090fcf5ef2aSThomas Huth 
10919ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, size > 4)) {
1092fcf5ef2aSThomas Huth         return;
1093fcf5ef2aSThomas Huth     }
1094fcf5ef2aSThomas Huth 
1095d248e1beSEdgar E. Iglesias     trap_userspace(dc, ea);
1096d248e1beSEdgar E. Iglesias 
1097fcf5ef2aSThomas Huth     t_sync_flags(dc);
1098fcf5ef2aSThomas Huth     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
1099fcf5ef2aSThomas Huth     sync_jmpstate(dc);
11000dc4af5cSEdgar E. Iglesias     /* SWX needs a temp_local.  */
1101403322eaSEdgar E. Iglesias     addr = ex ? tcg_temp_local_new() : tcg_temp_new();
1102d248e1beSEdgar E. Iglesias     compute_ldst_addr(dc, ea, addr);
1103d248e1beSEdgar E. Iglesias     /* Extended addressing bypasses the MMU.  */
1104d248e1beSEdgar E. Iglesias     mem_index = ea ? MMU_NOMMU_IDX : mem_index;
1105fcf5ef2aSThomas Huth 
1106fcf5ef2aSThomas Huth     if (ex) { /* swx */
1107cfeea807SEdgar E. Iglesias         TCGv_i32 tval;
1108fcf5ef2aSThomas Huth 
1109fcf5ef2aSThomas Huth         /* swx does not throw unaligned access errors, so force alignment */
1110403322eaSEdgar E. Iglesias         tcg_gen_andi_tl(addr, addr, ~3);
1111fcf5ef2aSThomas Huth 
11121074c0fbSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, 1);
1113fcf5ef2aSThomas Huth         swx_skip = gen_new_label();
11149b158558SRichard Henderson         tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip);
1115fcf5ef2aSThomas Huth 
1116071cdc67SEdgar E. Iglesias         /*
1117071cdc67SEdgar E. Iglesias          * Compare the value loaded at lwx with current contents of
1118071cdc67SEdgar E. Iglesias          * the reserved location.
1119071cdc67SEdgar E. Iglesias          */
1120cfeea807SEdgar E. Iglesias         tval = tcg_temp_new_i32();
1121071cdc67SEdgar E. Iglesias 
11229b158558SRichard Henderson         tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val,
1123071cdc67SEdgar E. Iglesias                                    cpu_R[dc->rd], mem_index,
1124071cdc67SEdgar E. Iglesias                                    mop);
1125071cdc67SEdgar E. Iglesias 
11269b158558SRichard Henderson         tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip);
11271074c0fbSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, 0);
1128cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(tval);
1129fcf5ef2aSThomas Huth     }
1130fcf5ef2aSThomas Huth 
1131fcf5ef2aSThomas Huth     if (rev && size != 4) {
1132fcf5ef2aSThomas Huth         /* Endian reverse the address. t is addr.  */
1133fcf5ef2aSThomas Huth         switch (size) {
1134fcf5ef2aSThomas Huth             case 1:
1135fcf5ef2aSThomas Huth             {
1136a6338015SEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 3);
1137fcf5ef2aSThomas Huth                 break;
1138fcf5ef2aSThomas Huth             }
1139fcf5ef2aSThomas Huth 
1140fcf5ef2aSThomas Huth             case 2:
1141fcf5ef2aSThomas Huth                 /* 00 -> 10
1142fcf5ef2aSThomas Huth                    10 -> 00.  */
1143fcf5ef2aSThomas Huth                 /* Force addr into the temp.  */
1144403322eaSEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 2);
1145fcf5ef2aSThomas Huth                 break;
1146fcf5ef2aSThomas Huth             default:
1147fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
1148fcf5ef2aSThomas Huth                 break;
1149fcf5ef2aSThomas Huth         }
1150fcf5ef2aSThomas Huth     }
1151071cdc67SEdgar E. Iglesias 
1152071cdc67SEdgar E. Iglesias     if (!ex) {
1153d248e1beSEdgar E. Iglesias         tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop);
1154071cdc67SEdgar E. Iglesias     }
1155fcf5ef2aSThomas Huth 
1156fcf5ef2aSThomas Huth     /* Verify alignment if needed.  */
11571507e5f6SEdgar E. Iglesias     if (dc->cpu->cfg.unaligned_exceptions && size > 1) {
1158a6338015SEdgar E. Iglesias         TCGv_i32 t1 = tcg_const_i32(1);
1159a6338015SEdgar E. Iglesias         TCGv_i32 treg = tcg_const_i32(dc->rd);
1160a6338015SEdgar E. Iglesias         TCGv_i32 tsize = tcg_const_i32(size - 1);
1161a6338015SEdgar E. Iglesias 
1162d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1163fcf5ef2aSThomas Huth         /* FIXME: if the alignment is wrong, we should restore the value
1164fcf5ef2aSThomas Huth          *        in memory. One possible way to achieve this is to probe
1165fcf5ef2aSThomas Huth          *        the MMU prior to the memaccess, thay way we could put
1166fcf5ef2aSThomas Huth          *        the alignment checks in between the probe and the mem
1167fcf5ef2aSThomas Huth          *        access.
1168fcf5ef2aSThomas Huth          */
1169a6338015SEdgar E. Iglesias         gen_helper_memalign(cpu_env, addr, treg, t1, tsize);
1170a6338015SEdgar E. Iglesias 
1171a6338015SEdgar E. Iglesias         tcg_temp_free_i32(t1);
1172a6338015SEdgar E. Iglesias         tcg_temp_free_i32(treg);
1173a6338015SEdgar E. Iglesias         tcg_temp_free_i32(tsize);
1174fcf5ef2aSThomas Huth     }
1175fcf5ef2aSThomas Huth 
1176fcf5ef2aSThomas Huth     if (ex) {
1177fcf5ef2aSThomas Huth         gen_set_label(swx_skip);
1178fcf5ef2aSThomas Huth     }
1179fcf5ef2aSThomas Huth 
1180403322eaSEdgar E. Iglesias     tcg_temp_free(addr);
1181fcf5ef2aSThomas Huth }
1182fcf5ef2aSThomas Huth 
1183fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc,
11849e6e1828SEdgar E. Iglesias                            TCGv_i32 d, TCGv_i32 a)
1185fcf5ef2aSThomas Huth {
1186d89b86e9SEdgar E. Iglesias     static const int mb_to_tcg_cc[] = {
1187d89b86e9SEdgar E. Iglesias         [CC_EQ] = TCG_COND_EQ,
1188d89b86e9SEdgar E. Iglesias         [CC_NE] = TCG_COND_NE,
1189d89b86e9SEdgar E. Iglesias         [CC_LT] = TCG_COND_LT,
1190d89b86e9SEdgar E. Iglesias         [CC_LE] = TCG_COND_LE,
1191d89b86e9SEdgar E. Iglesias         [CC_GE] = TCG_COND_GE,
1192d89b86e9SEdgar E. Iglesias         [CC_GT] = TCG_COND_GT,
1193d89b86e9SEdgar E. Iglesias     };
1194d89b86e9SEdgar E. Iglesias 
1195fcf5ef2aSThomas Huth     switch (cc) {
1196fcf5ef2aSThomas Huth     case CC_EQ:
1197fcf5ef2aSThomas Huth     case CC_NE:
1198fcf5ef2aSThomas Huth     case CC_LT:
1199fcf5ef2aSThomas Huth     case CC_LE:
1200fcf5ef2aSThomas Huth     case CC_GE:
1201fcf5ef2aSThomas Huth     case CC_GT:
12029e6e1828SEdgar E. Iglesias         tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
1203fcf5ef2aSThomas Huth         break;
1204fcf5ef2aSThomas Huth     default:
1205fcf5ef2aSThomas Huth         cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
1206fcf5ef2aSThomas Huth         break;
1207fcf5ef2aSThomas Huth     }
1208fcf5ef2aSThomas Huth }
1209fcf5ef2aSThomas Huth 
12100f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false)
1211fcf5ef2aSThomas Huth {
12120f96e96bSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
1213e956caf2SEdgar E. Iglesias 
12140f96e96bSRichard Henderson     tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc,
12159b158558SRichard Henderson                         cpu_btaken, zero,
1216e956caf2SEdgar E. Iglesias                         pc_true, pc_false);
1217e956caf2SEdgar E. Iglesias 
12180f96e96bSRichard Henderson     tcg_temp_free_i32(zero);
1219fcf5ef2aSThomas Huth }
1220fcf5ef2aSThomas Huth 
1221f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc)
1222f91c60f0SEdgar E. Iglesias {
1223f91c60f0SEdgar E. Iglesias         TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG));
1224f91c60f0SEdgar E. Iglesias 
1225f91c60f0SEdgar E. Iglesias         dc->delayed_branch = 2;
1226f91c60f0SEdgar E. Iglesias         dc->tb_flags |= D_FLAG;
1227f91c60f0SEdgar E. Iglesias 
1228f91c60f0SEdgar E. Iglesias         tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm));
1229f91c60f0SEdgar E. Iglesias         tcg_temp_free_i32(tmp);
1230f91c60f0SEdgar E. Iglesias }
1231f91c60f0SEdgar E. Iglesias 
1232fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc)
1233fcf5ef2aSThomas Huth {
1234fcf5ef2aSThomas Huth     unsigned int cc;
1235fcf5ef2aSThomas Huth     unsigned int dslot;
1236fcf5ef2aSThomas Huth 
1237fcf5ef2aSThomas Huth     cc = EXTRACT_FIELD(dc->ir, 21, 23);
1238fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 25);
1239fcf5ef2aSThomas Huth 
1240fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1241fcf5ef2aSThomas Huth     if (dslot) {
1242f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1243fcf5ef2aSThomas Huth     }
1244fcf5ef2aSThomas Huth 
1245d7ecb757SRichard Henderson     if (dc->type_b) {
1246fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT_CC;
1247d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1248d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1249fcf5ef2aSThomas Huth     } else {
1250fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
1251d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1252fcf5ef2aSThomas Huth     }
12539b158558SRichard Henderson     eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]);
1254fcf5ef2aSThomas Huth }
1255fcf5ef2aSThomas Huth 
1256fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc)
1257fcf5ef2aSThomas Huth {
1258fcf5ef2aSThomas Huth     unsigned int dslot, link, abs, mbar;
1259fcf5ef2aSThomas Huth 
1260fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 20);
1261fcf5ef2aSThomas Huth     abs = dc->ir & (1 << 19);
1262fcf5ef2aSThomas Huth     link = dc->ir & (1 << 18);
1263fcf5ef2aSThomas Huth 
1264fcf5ef2aSThomas Huth     /* Memory barrier.  */
1265fcf5ef2aSThomas Huth     mbar = (dc->ir >> 16) & 31;
1266fcf5ef2aSThomas Huth     if (mbar == 2 && dc->imm == 4) {
1267badcbf9dSEdgar E. Iglesias         uint16_t mbar_imm = dc->rd;
1268badcbf9dSEdgar E. Iglesias 
12693f172744SEdgar E. Iglesias         /* Data access memory barrier.  */
12703f172744SEdgar E. Iglesias         if ((mbar_imm & 2) == 0) {
12713f172744SEdgar E. Iglesias             tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
12723f172744SEdgar E. Iglesias         }
12733f172744SEdgar E. Iglesias 
1274fcf5ef2aSThomas Huth         /* mbar IMM & 16 decodes to sleep.  */
1275badcbf9dSEdgar E. Iglesias         if (mbar_imm & 16) {
127641ba37c4SRichard Henderson             TCGv_i32 tmp_1;
1277fcf5ef2aSThomas Huth 
1278b4919e7dSEdgar E. Iglesias             if (trap_userspace(dc, true)) {
1279b4919e7dSEdgar E. Iglesias                 /* Sleep is a privileged instruction.  */
1280b4919e7dSEdgar E. Iglesias                 return;
1281b4919e7dSEdgar E. Iglesias             }
1282b4919e7dSEdgar E. Iglesias 
1283fcf5ef2aSThomas Huth             t_sync_flags(dc);
128441ba37c4SRichard Henderson 
128541ba37c4SRichard Henderson             tmp_1 = tcg_const_i32(1);
1286fcf5ef2aSThomas Huth             tcg_gen_st_i32(tmp_1, cpu_env,
1287fcf5ef2aSThomas Huth                            -offsetof(MicroBlazeCPU, env)
1288fcf5ef2aSThomas Huth                            +offsetof(CPUState, halted));
1289fcf5ef2aSThomas Huth             tcg_temp_free_i32(tmp_1);
129041ba37c4SRichard Henderson 
1291d4705ae0SRichard Henderson             tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
129241ba37c4SRichard Henderson 
129341ba37c4SRichard Henderson             gen_raise_exception(dc, EXCP_HLT);
1294fcf5ef2aSThomas Huth             return;
1295fcf5ef2aSThomas Huth         }
1296fcf5ef2aSThomas Huth         /* Break the TB.  */
1297fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1298fcf5ef2aSThomas Huth         return;
1299fcf5ef2aSThomas Huth     }
1300fcf5ef2aSThomas Huth 
1301d7ecb757SRichard Henderson     if (abs && link && !dslot) {
1302d7ecb757SRichard Henderson         if (dc->type_b) {
1303d7ecb757SRichard Henderson             /* BRKI */
1304d7ecb757SRichard Henderson             uint32_t imm = dec_alu_typeb_imm(dc);
1305d7ecb757SRichard Henderson             if (trap_userspace(dc, imm != 8 && imm != 0x18)) {
1306d7ecb757SRichard Henderson                 return;
1307d7ecb757SRichard Henderson             }
1308d7ecb757SRichard Henderson         } else {
1309d7ecb757SRichard Henderson             /* BRK */
1310d7ecb757SRichard Henderson             if (trap_userspace(dc, true)) {
1311d7ecb757SRichard Henderson                 return;
1312d7ecb757SRichard Henderson             }
1313d7ecb757SRichard Henderson         }
1314d7ecb757SRichard Henderson     }
1315d7ecb757SRichard Henderson 
1316fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1317fcf5ef2aSThomas Huth     if (dslot) {
1318f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1319fcf5ef2aSThomas Huth     }
1320d7ecb757SRichard Henderson     if (link && dc->rd) {
1321d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1322d7ecb757SRichard Henderson     }
1323fcf5ef2aSThomas Huth 
1324fcf5ef2aSThomas Huth     if (abs) {
1325d7ecb757SRichard Henderson         if (dc->type_b) {
1326d7ecb757SRichard Henderson             uint32_t dest = dec_alu_typeb_imm(dc);
1327d7ecb757SRichard Henderson 
1328d7ecb757SRichard Henderson             dc->jmp = JMP_DIRECT;
1329d7ecb757SRichard Henderson             dc->jmp_pc = dest;
1330d7ecb757SRichard Henderson             tcg_gen_movi_i32(cpu_btarget, dest);
1331fcf5ef2aSThomas Huth             if (link && !dslot) {
1332d7ecb757SRichard Henderson                 switch (dest) {
1333d7ecb757SRichard Henderson                 case 8:
1334d7ecb757SRichard Henderson                 case 0x18:
1335d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_BREAK);
1336d7ecb757SRichard Henderson                     break;
1337d7ecb757SRichard Henderson                 case 0:
1338d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_DEBUG);
1339d7ecb757SRichard Henderson                     break;
1340d7ecb757SRichard Henderson                 }
1341d7ecb757SRichard Henderson             }
1342d7ecb757SRichard Henderson         } else {
1343d7ecb757SRichard Henderson             dc->jmp = JMP_INDIRECT;
1344d7ecb757SRichard Henderson             tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]);
1345d7ecb757SRichard Henderson             if (link && !dslot) {
134641ba37c4SRichard Henderson                 gen_raise_exception_sync(dc, EXCP_BREAK);
134741ba37c4SRichard Henderson             }
1348fcf5ef2aSThomas Huth         }
1349d7ecb757SRichard Henderson     } else if (dc->type_b) {
1350fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT;
1351d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1352d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1353fcf5ef2aSThomas Huth     } else {
1354d7ecb757SRichard Henderson         dc->jmp = JMP_INDIRECT;
1355d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1356d7ecb757SRichard Henderson     }
13579b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
1358fcf5ef2aSThomas Huth }
1359fcf5ef2aSThomas Huth 
1360fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc)
1361fcf5ef2aSThomas Huth {
1362cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1363cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1364cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
13653e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
13660a22f8cfSEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
13670a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_IE);
1368cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1369fcf5ef2aSThomas Huth 
1370cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1371cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1372fcf5ef2aSThomas Huth     msr_write(dc, t1);
1373cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1374cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1375fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1376fcf5ef2aSThomas Huth }
1377fcf5ef2aSThomas Huth 
1378fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc)
1379fcf5ef2aSThomas Huth {
1380cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1381cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1382cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
13833e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
13840a22f8cfSEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
1385cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1386cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1387fcf5ef2aSThomas Huth 
1388cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1389cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1390fcf5ef2aSThomas Huth     msr_write(dc, t1);
1391cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1392cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1393fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1394fcf5ef2aSThomas Huth }
1395fcf5ef2aSThomas Huth 
1396fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc)
1397fcf5ef2aSThomas Huth {
1398cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1399cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1400cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
1401fcf5ef2aSThomas Huth 
14023e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
14030a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_EE);
1404cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
1405cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1406cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1407fcf5ef2aSThomas Huth 
1408cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1409cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1410fcf5ef2aSThomas Huth     msr_write(dc, t1);
1411cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1412cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1413fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1414fcf5ef2aSThomas Huth }
1415fcf5ef2aSThomas Huth 
1416fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc)
1417fcf5ef2aSThomas Huth {
1418fcf5ef2aSThomas Huth     unsigned int b_bit, i_bit, e_bit;
1419fcf5ef2aSThomas Huth 
1420fcf5ef2aSThomas Huth     i_bit = dc->ir & (1 << 21);
1421fcf5ef2aSThomas Huth     b_bit = dc->ir & (1 << 22);
1422fcf5ef2aSThomas Huth     e_bit = dc->ir & (1 << 23);
1423fcf5ef2aSThomas Huth 
1424bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
1425bdfc1e88SEdgar E. Iglesias         return;
1426bdfc1e88SEdgar E. Iglesias     }
1427bdfc1e88SEdgar E. Iglesias 
1428f91c60f0SEdgar E. Iglesias     dec_setup_dslot(dc);
1429fcf5ef2aSThomas Huth 
1430fcf5ef2aSThomas Huth     if (i_bit) {
1431fcf5ef2aSThomas Huth         dc->tb_flags |= DRTI_FLAG;
1432fcf5ef2aSThomas Huth     } else if (b_bit) {
1433fcf5ef2aSThomas Huth         dc->tb_flags |= DRTB_FLAG;
1434fcf5ef2aSThomas Huth     } else if (e_bit) {
1435fcf5ef2aSThomas Huth         dc->tb_flags |= DRTE_FLAG;
143611105d67SRichard Henderson     }
1437fcf5ef2aSThomas Huth 
1438fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
14399b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
14400f96e96bSRichard Henderson     tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc));
1441fcf5ef2aSThomas Huth }
1442fcf5ef2aSThomas Huth 
1443fcf5ef2aSThomas Huth static int dec_check_fpuv2(DisasContext *dc)
1444fcf5ef2aSThomas Huth {
1445fcf5ef2aSThomas Huth     if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) {
144641ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_FPU);
1447fcf5ef2aSThomas Huth     }
14482016a6a7SJoe Komlodi     return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0;
1449fcf5ef2aSThomas Huth }
1450fcf5ef2aSThomas Huth 
1451fcf5ef2aSThomas Huth static void dec_fpu(DisasContext *dc)
1452fcf5ef2aSThomas Huth {
1453fcf5ef2aSThomas Huth     unsigned int fpu_insn;
1454fcf5ef2aSThomas Huth 
14559ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) {
1456fcf5ef2aSThomas Huth         return;
1457fcf5ef2aSThomas Huth     }
1458fcf5ef2aSThomas Huth 
1459fcf5ef2aSThomas Huth     fpu_insn = (dc->ir >> 7) & 7;
1460fcf5ef2aSThomas Huth 
1461fcf5ef2aSThomas Huth     switch (fpu_insn) {
1462fcf5ef2aSThomas Huth         case 0:
1463fcf5ef2aSThomas Huth             gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1464fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1465fcf5ef2aSThomas Huth             break;
1466fcf5ef2aSThomas Huth 
1467fcf5ef2aSThomas Huth         case 1:
1468fcf5ef2aSThomas Huth             gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1469fcf5ef2aSThomas Huth                              cpu_R[dc->rb]);
1470fcf5ef2aSThomas Huth             break;
1471fcf5ef2aSThomas Huth 
1472fcf5ef2aSThomas Huth         case 2:
1473fcf5ef2aSThomas Huth             gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1474fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1475fcf5ef2aSThomas Huth             break;
1476fcf5ef2aSThomas Huth 
1477fcf5ef2aSThomas Huth         case 3:
1478fcf5ef2aSThomas Huth             gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1479fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1480fcf5ef2aSThomas Huth             break;
1481fcf5ef2aSThomas Huth 
1482fcf5ef2aSThomas Huth         case 4:
1483fcf5ef2aSThomas Huth             switch ((dc->ir >> 4) & 7) {
1484fcf5ef2aSThomas Huth                 case 0:
1485fcf5ef2aSThomas Huth                     gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env,
1486fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1487fcf5ef2aSThomas Huth                     break;
1488fcf5ef2aSThomas Huth                 case 1:
1489fcf5ef2aSThomas Huth                     gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env,
1490fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1491fcf5ef2aSThomas Huth                     break;
1492fcf5ef2aSThomas Huth                 case 2:
1493fcf5ef2aSThomas Huth                     gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env,
1494fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1495fcf5ef2aSThomas Huth                     break;
1496fcf5ef2aSThomas Huth                 case 3:
1497fcf5ef2aSThomas Huth                     gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env,
1498fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1499fcf5ef2aSThomas Huth                     break;
1500fcf5ef2aSThomas Huth                 case 4:
1501fcf5ef2aSThomas Huth                     gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env,
1502fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1503fcf5ef2aSThomas Huth                     break;
1504fcf5ef2aSThomas Huth                 case 5:
1505fcf5ef2aSThomas Huth                     gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env,
1506fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1507fcf5ef2aSThomas Huth                     break;
1508fcf5ef2aSThomas Huth                 case 6:
1509fcf5ef2aSThomas Huth                     gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env,
1510fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1511fcf5ef2aSThomas Huth                     break;
1512fcf5ef2aSThomas Huth                 default:
1513fcf5ef2aSThomas Huth                     qemu_log_mask(LOG_UNIMP,
1514fcf5ef2aSThomas Huth                                   "unimplemented fcmp fpu_insn=%x pc=%x"
1515fcf5ef2aSThomas Huth                                   " opc=%x\n",
1516d4705ae0SRichard Henderson                                   fpu_insn, (uint32_t)dc->base.pc_next,
1517d4705ae0SRichard Henderson                                   dc->opcode);
1518fcf5ef2aSThomas Huth                     dc->abort_at_next_insn = 1;
1519fcf5ef2aSThomas Huth                     break;
1520fcf5ef2aSThomas Huth             }
1521fcf5ef2aSThomas Huth             break;
1522fcf5ef2aSThomas Huth 
1523fcf5ef2aSThomas Huth         case 5:
1524fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1525fcf5ef2aSThomas Huth                 return;
1526fcf5ef2aSThomas Huth             }
1527fcf5ef2aSThomas Huth             gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1528fcf5ef2aSThomas Huth             break;
1529fcf5ef2aSThomas Huth 
1530fcf5ef2aSThomas Huth         case 6:
1531fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1532fcf5ef2aSThomas Huth                 return;
1533fcf5ef2aSThomas Huth             }
1534fcf5ef2aSThomas Huth             gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1535fcf5ef2aSThomas Huth             break;
1536fcf5ef2aSThomas Huth 
1537fcf5ef2aSThomas Huth         case 7:
1538fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1539fcf5ef2aSThomas Huth                 return;
1540fcf5ef2aSThomas Huth             }
1541fcf5ef2aSThomas Huth             gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1542fcf5ef2aSThomas Huth             break;
1543fcf5ef2aSThomas Huth 
1544fcf5ef2aSThomas Huth         default:
1545fcf5ef2aSThomas Huth             qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x"
1546fcf5ef2aSThomas Huth                           " opc=%x\n",
1547d4705ae0SRichard Henderson                           fpu_insn, (uint32_t)dc->base.pc_next, dc->opcode);
1548fcf5ef2aSThomas Huth             dc->abort_at_next_insn = 1;
1549fcf5ef2aSThomas Huth             break;
1550fcf5ef2aSThomas Huth     }
1551fcf5ef2aSThomas Huth }
1552fcf5ef2aSThomas Huth 
1553fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc)
1554fcf5ef2aSThomas Huth {
15559ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, true)) {
1556fcf5ef2aSThomas Huth         return;
1557fcf5ef2aSThomas Huth     }
1558d4705ae0SRichard Henderson     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n",
1559d4705ae0SRichard Henderson                   (uint32_t)dc->base.pc_next, dc->opcode);
1560fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 1;
1561fcf5ef2aSThomas Huth }
1562fcf5ef2aSThomas Huth 
1563fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
1564fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc)
1565fcf5ef2aSThomas Huth {
1566fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1567fcf5ef2aSThomas Huth     int ctrl;
1568fcf5ef2aSThomas Huth 
1569bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
1570fcf5ef2aSThomas Huth         return;
1571fcf5ef2aSThomas Huth     }
1572fcf5ef2aSThomas Huth 
1573cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
1574fcf5ef2aSThomas Huth     if (dc->type_b) {
1575cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(t_id, dc->imm & 0xf);
1576fcf5ef2aSThomas Huth         ctrl = dc->imm >> 10;
1577fcf5ef2aSThomas Huth     } else {
1578cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
1579fcf5ef2aSThomas Huth         ctrl = dc->imm >> 5;
1580fcf5ef2aSThomas Huth     }
1581fcf5ef2aSThomas Huth 
1582cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
1583fcf5ef2aSThomas Huth 
1584fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1585fcf5ef2aSThomas Huth         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1586fcf5ef2aSThomas Huth     } else {
1587fcf5ef2aSThomas Huth         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1588fcf5ef2aSThomas Huth     }
1589cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1590cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
1591fcf5ef2aSThomas Huth }
1592fcf5ef2aSThomas Huth 
1593fcf5ef2aSThomas Huth static struct decoder_info {
1594fcf5ef2aSThomas Huth     struct {
1595fcf5ef2aSThomas Huth         uint32_t bits;
1596fcf5ef2aSThomas Huth         uint32_t mask;
1597fcf5ef2aSThomas Huth     };
1598fcf5ef2aSThomas Huth     void (*dec)(DisasContext *dc);
1599fcf5ef2aSThomas Huth } decinfo[] = {
1600fcf5ef2aSThomas Huth     {DEC_SUB, dec_sub},
1601fcf5ef2aSThomas Huth     {DEC_AND, dec_and},
1602fcf5ef2aSThomas Huth     {DEC_XOR, dec_xor},
1603fcf5ef2aSThomas Huth     {DEC_OR, dec_or},
1604fcf5ef2aSThomas Huth     {DEC_BIT, dec_bit},
1605fcf5ef2aSThomas Huth     {DEC_BARREL, dec_barrel},
1606fcf5ef2aSThomas Huth     {DEC_LD, dec_load},
1607fcf5ef2aSThomas Huth     {DEC_ST, dec_store},
1608fcf5ef2aSThomas Huth     {DEC_IMM, dec_imm},
1609fcf5ef2aSThomas Huth     {DEC_BR, dec_br},
1610fcf5ef2aSThomas Huth     {DEC_BCC, dec_bcc},
1611fcf5ef2aSThomas Huth     {DEC_RTS, dec_rts},
1612fcf5ef2aSThomas Huth     {DEC_FPU, dec_fpu},
1613fcf5ef2aSThomas Huth     {DEC_MUL, dec_mul},
1614fcf5ef2aSThomas Huth     {DEC_DIV, dec_div},
1615fcf5ef2aSThomas Huth     {DEC_MSR, dec_msr},
1616fcf5ef2aSThomas Huth     {DEC_STREAM, dec_stream},
1617fcf5ef2aSThomas Huth     {{0, 0}, dec_null}
1618fcf5ef2aSThomas Huth };
1619fcf5ef2aSThomas Huth 
162044d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir)
1621fcf5ef2aSThomas Huth {
1622fcf5ef2aSThomas Huth     int i;
1623fcf5ef2aSThomas Huth 
1624fcf5ef2aSThomas Huth     dc->ir = ir;
1625fcf5ef2aSThomas Huth 
1626fcf5ef2aSThomas Huth     /* bit 2 seems to indicate insn type.  */
1627fcf5ef2aSThomas Huth     dc->type_b = ir & (1 << 29);
1628fcf5ef2aSThomas Huth 
1629fcf5ef2aSThomas Huth     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1630fcf5ef2aSThomas Huth     dc->rd = EXTRACT_FIELD(ir, 21, 25);
1631fcf5ef2aSThomas Huth     dc->ra = EXTRACT_FIELD(ir, 16, 20);
1632fcf5ef2aSThomas Huth     dc->rb = EXTRACT_FIELD(ir, 11, 15);
1633fcf5ef2aSThomas Huth     dc->imm = EXTRACT_FIELD(ir, 0, 15);
1634fcf5ef2aSThomas Huth 
1635fcf5ef2aSThomas Huth     /* Large switch for all insns.  */
1636fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1637fcf5ef2aSThomas Huth         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1638fcf5ef2aSThomas Huth             decinfo[i].dec(dc);
1639fcf5ef2aSThomas Huth             break;
1640fcf5ef2aSThomas Huth         }
1641fcf5ef2aSThomas Huth     }
1642fcf5ef2aSThomas Huth }
1643fcf5ef2aSThomas Huth 
1644372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1645fcf5ef2aSThomas Huth {
1646372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1647372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1648372122e3SRichard Henderson     int bound;
1649fcf5ef2aSThomas Huth 
1650fcf5ef2aSThomas Huth     dc->cpu = cpu;
1651372122e3SRichard Henderson     dc->synced_flags = dc->tb_flags = dc->base.tb->flags;
1652fcf5ef2aSThomas Huth     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
1653372122e3SRichard Henderson     dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP;
1654fcf5ef2aSThomas Huth     dc->cpustate_changed = 0;
1655fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 0;
1656d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
1657*20800179SRichard Henderson     dc->r0 = NULL;
1658*20800179SRichard Henderson     dc->r0_set = false;
1659fcf5ef2aSThomas Huth 
1660372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1661372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1662fcf5ef2aSThomas Huth }
1663fcf5ef2aSThomas Huth 
1664372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1665fcf5ef2aSThomas Huth {
1666fcf5ef2aSThomas Huth }
1667fcf5ef2aSThomas Huth 
1668372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1669372122e3SRichard Henderson {
1670372122e3SRichard Henderson     tcg_gen_insn_start(dcb->pc_next);
1671372122e3SRichard Henderson }
1672fcf5ef2aSThomas Huth 
1673372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1674372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1675372122e3SRichard Henderson {
1676372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1677372122e3SRichard Henderson 
1678372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1679372122e3SRichard Henderson 
1680372122e3SRichard Henderson     /*
1681372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1682372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1683372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1684372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1685372122e3SRichard Henderson      */
1686372122e3SRichard Henderson     dc->base.pc_next += 4;
1687372122e3SRichard Henderson     return true;
1688372122e3SRichard Henderson }
1689372122e3SRichard Henderson 
1690372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1691372122e3SRichard Henderson {
1692372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1693372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
169444d1432bSRichard Henderson     uint32_t ir;
1695372122e3SRichard Henderson 
1696372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1697372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1698372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1699372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1700fcf5ef2aSThomas Huth     }
1701fcf5ef2aSThomas Huth 
1702fcf5ef2aSThomas Huth     dc->clear_imm = 1;
170344d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
170444d1432bSRichard Henderson     if (!decode(dc, ir)) {
170544d1432bSRichard Henderson         old_decode(dc, ir);
170644d1432bSRichard Henderson     }
1707*20800179SRichard Henderson 
1708*20800179SRichard Henderson     if (dc->r0) {
1709*20800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
1710*20800179SRichard Henderson         dc->r0 = NULL;
1711*20800179SRichard Henderson         dc->r0_set = false;
1712*20800179SRichard Henderson     }
1713*20800179SRichard Henderson 
1714d7ecb757SRichard Henderson     if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) {
1715fcf5ef2aSThomas Huth         dc->tb_flags &= ~IMM_FLAG;
1716d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1717372122e3SRichard Henderson     }
1718d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1719fcf5ef2aSThomas Huth 
1720372122e3SRichard Henderson     if (dc->delayed_branch && --dc->delayed_branch == 0) {
1721372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
1722fcf5ef2aSThomas Huth             do_rti(dc);
1723372122e3SRichard Henderson         }
1724372122e3SRichard Henderson         if (dc->tb_flags & DRTB_FLAG) {
1725fcf5ef2aSThomas Huth             do_rtb(dc);
1726372122e3SRichard Henderson         }
1727372122e3SRichard Henderson         if (dc->tb_flags & DRTE_FLAG) {
1728fcf5ef2aSThomas Huth             do_rte(dc);
1729372122e3SRichard Henderson         }
1730fcf5ef2aSThomas Huth         /* Clear the delay slot flag.  */
1731fcf5ef2aSThomas Huth         dc->tb_flags &= ~D_FLAG;
1732372122e3SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1733372122e3SRichard Henderson     }
1734372122e3SRichard Henderson 
1735372122e3SRichard Henderson     /* Force an exit if the per-tb cpu state has changed.  */
1736372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
1737372122e3SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1738372122e3SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1739372122e3SRichard Henderson     }
1740372122e3SRichard Henderson }
1741372122e3SRichard Henderson 
1742372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1743372122e3SRichard Henderson {
1744372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1745372122e3SRichard Henderson 
1746372122e3SRichard Henderson     assert(!dc->abort_at_next_insn);
1747372122e3SRichard Henderson 
1748372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1749372122e3SRichard Henderson         /* We have already exited the TB. */
1750372122e3SRichard Henderson         return;
1751372122e3SRichard Henderson     }
1752372122e3SRichard Henderson 
1753372122e3SRichard Henderson     t_sync_flags(dc);
1754372122e3SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1755372122e3SRichard Henderson         sync_jmpstate(dc);
1756372122e3SRichard Henderson         dc->jmp = JMP_NOJMP;
1757372122e3SRichard Henderson     }
1758372122e3SRichard Henderson 
1759372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1760372122e3SRichard Henderson     case DISAS_TOO_MANY:
1761372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1762372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1763372122e3SRichard Henderson         return;
1764372122e3SRichard Henderson 
1765372122e3SRichard Henderson     case DISAS_UPDATE:
1766372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1767372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1768372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1769372122e3SRichard Henderson         } else {
1770372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1771372122e3SRichard Henderson         }
1772372122e3SRichard Henderson         return;
1773372122e3SRichard Henderson 
1774372122e3SRichard Henderson     case DISAS_JUMP:
1775372122e3SRichard Henderson         switch (dc->jmp) {
1776372122e3SRichard Henderson         case JMP_INDIRECT:
1777372122e3SRichard Henderson             {
1778d4705ae0SRichard Henderson                 TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next);
17790f96e96bSRichard Henderson                 eval_cond_jmp(dc, cpu_btarget, tmp_pc);
17800f96e96bSRichard Henderson                 tcg_temp_free_i32(tmp_pc);
1781372122e3SRichard Henderson 
1782372122e3SRichard Henderson                 if (unlikely(cs->singlestep_enabled)) {
1783372122e3SRichard Henderson                     gen_raise_exception(dc, EXCP_DEBUG);
1784372122e3SRichard Henderson                 } else {
1785372122e3SRichard Henderson                     tcg_gen_exit_tb(NULL, 0);
1786372122e3SRichard Henderson                 }
1787372122e3SRichard Henderson             }
1788372122e3SRichard Henderson             return;
1789372122e3SRichard Henderson 
1790372122e3SRichard Henderson         case JMP_DIRECT_CC:
1791372122e3SRichard Henderson             {
1792fcf5ef2aSThomas Huth                 TCGLabel *l1 = gen_new_label();
17939b158558SRichard Henderson                 tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1);
1794d4705ae0SRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1795fcf5ef2aSThomas Huth                 gen_set_label(l1);
1796372122e3SRichard Henderson             }
1797372122e3SRichard Henderson             /* fall through */
1798372122e3SRichard Henderson 
1799372122e3SRichard Henderson         case JMP_DIRECT:
1800fcf5ef2aSThomas Huth             gen_goto_tb(dc, 0, dc->jmp_pc);
1801372122e3SRichard Henderson             return;
1802fcf5ef2aSThomas Huth         }
1803372122e3SRichard Henderson         /* fall through */
1804fcf5ef2aSThomas Huth 
1805a2b80dbdSRichard Henderson     default:
1806a2b80dbdSRichard Henderson         g_assert_not_reached();
1807fcf5ef2aSThomas Huth     }
1808fcf5ef2aSThomas Huth }
1809fcf5ef2aSThomas Huth 
1810372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1811372122e3SRichard Henderson {
1812372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1813372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1814fcf5ef2aSThomas Huth }
1815372122e3SRichard Henderson 
1816372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1817372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1818372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1819372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1820372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1821372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1822372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1823372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1824372122e3SRichard Henderson };
1825372122e3SRichard Henderson 
1826372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1827372122e3SRichard Henderson {
1828372122e3SRichard Henderson     DisasContext dc;
1829372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1830fcf5ef2aSThomas Huth }
1831fcf5ef2aSThomas Huth 
183290c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1833fcf5ef2aSThomas Huth {
1834fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1835fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
1836fcf5ef2aSThomas Huth     int i;
1837fcf5ef2aSThomas Huth 
183890c84c56SMarkus Armbruster     if (!env) {
1839fcf5ef2aSThomas Huth         return;
184090c84c56SMarkus Armbruster     }
1841fcf5ef2aSThomas Huth 
18420f96e96bSRichard Henderson     qemu_fprintf(f, "IN: PC=%x %s\n",
184376e8187dSRichard Henderson                  env->pc, lookup_symbol(env->pc));
18446efd5599SRichard Henderson     qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " "
1845eb2022b7SRichard Henderson                  "imm=%x iflags=%x fsr=%x rbtr=%x\n",
184678e9caf2SRichard Henderson                  env->msr, env->esr, env->ear,
1847eb2022b7SRichard Henderson                  env->imm, env->iflags, env->fsr, env->btr);
18480f96e96bSRichard Henderson     qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
1849fcf5ef2aSThomas Huth                  env->btaken, env->btarget,
18502e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18512e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18522e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18532e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18542ead1b18SJoe Komlodi     for (i = 0; i < 12; i++) {
18552ead1b18SJoe Komlodi         qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]);
18562ead1b18SJoe Komlodi         if ((i + 1) % 4 == 0) {
18572ead1b18SJoe Komlodi             qemu_fprintf(f, "\n");
18582ead1b18SJoe Komlodi         }
18592ead1b18SJoe Komlodi     }
1860fcf5ef2aSThomas Huth 
18612ead1b18SJoe Komlodi     /* Registers that aren't modeled are reported as 0 */
186239db007eSRichard Henderson     qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 "
1863af20a93aSRichard Henderson                     "rtlblo=0 rtlbhi=0\n", env->edr);
18642ead1b18SJoe Komlodi     qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr);
1865fcf5ef2aSThomas Huth     for (i = 0; i < 32; i++) {
186690c84c56SMarkus Armbruster         qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1867fcf5ef2aSThomas Huth         if ((i + 1) % 4 == 0)
186890c84c56SMarkus Armbruster             qemu_fprintf(f, "\n");
1869fcf5ef2aSThomas Huth         }
187090c84c56SMarkus Armbruster     qemu_fprintf(f, "\n\n");
1871fcf5ef2aSThomas Huth }
1872fcf5ef2aSThomas Huth 
1873fcf5ef2aSThomas Huth void mb_tcg_init(void)
1874fcf5ef2aSThomas Huth {
1875480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1876480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1877fcf5ef2aSThomas Huth 
1878480d29a8SRichard Henderson     static const struct {
1879480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1880480d29a8SRichard Henderson     } i32s[] = {
1881480d29a8SRichard Henderson         R(0),  R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1882480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1883480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1884480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1885480d29a8SRichard Henderson 
1886480d29a8SRichard Henderson         SP(pc),
1887480d29a8SRichard Henderson         SP(msr),
18881074c0fbSRichard Henderson         SP(msr_c),
1889480d29a8SRichard Henderson         SP(imm),
1890480d29a8SRichard Henderson         SP(iflags),
1891480d29a8SRichard Henderson         SP(btaken),
1892480d29a8SRichard Henderson         SP(btarget),
1893480d29a8SRichard Henderson         SP(res_val),
1894480d29a8SRichard Henderson     };
1895480d29a8SRichard Henderson 
1896480d29a8SRichard Henderson #undef R
1897480d29a8SRichard Henderson #undef SP
1898480d29a8SRichard Henderson 
1899480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1900480d29a8SRichard Henderson         *i32s[i].var =
1901480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1902fcf5ef2aSThomas Huth     }
190376e8187dSRichard Henderson 
1904480d29a8SRichard Henderson     cpu_res_addr =
1905480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1906fcf5ef2aSThomas Huth }
1907fcf5ef2aSThomas Huth 
1908fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1909fcf5ef2aSThomas Huth                           target_ulong *data)
1910fcf5ef2aSThomas Huth {
191176e8187dSRichard Henderson     env->pc = data[0];
1912fcf5ef2aSThomas Huth }
1913