xref: /openbmc/qemu/target/microblaze/translate.c (revision 480d29a8fa842ca94297600397041f0efb0c7bd0)
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 
37fcf5ef2aSThomas Huth #define SIM_COMPAT 0
38fcf5ef2aSThomas Huth #define DISAS_GNU 1
39fcf5ef2aSThomas Huth #define DISAS_MB 1
40fcf5ef2aSThomas Huth #if DISAS_MB && !SIM_COMPAT
41fcf5ef2aSThomas Huth #  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
42fcf5ef2aSThomas Huth #else
43fcf5ef2aSThomas Huth #  define LOG_DIS(...) do { } while (0)
44fcf5ef2aSThomas Huth #endif
45fcf5ef2aSThomas Huth 
46fcf5ef2aSThomas Huth #define D(x)
47fcf5ef2aSThomas Huth 
48fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
49fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
50fcf5ef2aSThomas Huth 
5177fc6f5eSLluís Vilanova /* is_jmp field values */
5277fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
5377fc6f5eSLluís Vilanova #define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
5477fc6f5eSLluís Vilanova #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
5577fc6f5eSLluís Vilanova 
56cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
570f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
583e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
599b158558SRichard Henderson static TCGv_i32 cpu_imm;
609b158558SRichard Henderson static TCGv_i32 cpu_btaken;
610f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
629b158558SRichard Henderson static TCGv_i32 cpu_iflags;
639b158558SRichard Henderson static TCGv cpu_res_addr;
649b158558SRichard Henderson static TCGv_i32 cpu_res_val;
65fcf5ef2aSThomas Huth 
66fcf5ef2aSThomas Huth #include "exec/gen-icount.h"
67fcf5ef2aSThomas Huth 
68fcf5ef2aSThomas Huth /* This is the state at translation time.  */
69fcf5ef2aSThomas Huth typedef struct DisasContext {
70fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu;
71cfeea807SEdgar E. Iglesias     uint32_t pc;
72fcf5ef2aSThomas Huth 
73fcf5ef2aSThomas Huth     /* Decoder.  */
74fcf5ef2aSThomas Huth     int type_b;
75fcf5ef2aSThomas Huth     uint32_t ir;
76fcf5ef2aSThomas Huth     uint8_t opcode;
77fcf5ef2aSThomas Huth     uint8_t rd, ra, rb;
78fcf5ef2aSThomas Huth     uint16_t imm;
79fcf5ef2aSThomas Huth 
80fcf5ef2aSThomas Huth     unsigned int cpustate_changed;
81fcf5ef2aSThomas Huth     unsigned int delayed_branch;
82fcf5ef2aSThomas Huth     unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
83fcf5ef2aSThomas Huth     unsigned int clear_imm;
84fcf5ef2aSThomas Huth     int is_jmp;
85fcf5ef2aSThomas Huth 
86fcf5ef2aSThomas Huth #define JMP_NOJMP     0
87fcf5ef2aSThomas Huth #define JMP_DIRECT    1
88fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2
89fcf5ef2aSThomas Huth #define JMP_INDIRECT  3
90fcf5ef2aSThomas Huth     unsigned int jmp;
91fcf5ef2aSThomas Huth     uint32_t jmp_pc;
92fcf5ef2aSThomas Huth 
93fcf5ef2aSThomas Huth     int abort_at_next_insn;
94fcf5ef2aSThomas Huth     struct TranslationBlock *tb;
95fcf5ef2aSThomas Huth     int singlestep_enabled;
96fcf5ef2aSThomas Huth } DisasContext;
97fcf5ef2aSThomas Huth 
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);
113fcf5ef2aSThomas Huth     dc->is_jmp = DISAS_UPDATE;
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);
11941ba37c4SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->pc);
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
135fcf5ef2aSThomas Huth     return (dc->tb->pc & 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 {
143fcf5ef2aSThomas Huth     if (use_goto_tb(dc, dest)) {
144fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1450f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
14607ea28b4SRichard Henderson         tcg_gen_exit_tb(dc->tb, n);
147fcf5ef2aSThomas Huth     } else {
1480f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
14907ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
150fcf5ef2aSThomas Huth     }
151fcf5ef2aSThomas Huth }
152fcf5ef2aSThomas Huth 
153cfeea807SEdgar E. Iglesias static void read_carry(DisasContext *dc, TCGv_i32 d)
154fcf5ef2aSThomas Huth {
1553e0e16aeSRichard Henderson     tcg_gen_shri_i32(d, cpu_msr, 31);
156fcf5ef2aSThomas Huth }
157fcf5ef2aSThomas Huth 
158fcf5ef2aSThomas Huth /*
159fcf5ef2aSThomas Huth  * write_carry sets the carry bits in MSR based on bit 0 of v.
160fcf5ef2aSThomas Huth  * v[31:1] are ignored.
161fcf5ef2aSThomas Huth  */
162cfeea807SEdgar E. Iglesias static void write_carry(DisasContext *dc, TCGv_i32 v)
163fcf5ef2aSThomas Huth {
1640a22f8cfSEdgar E. Iglesias     /* Deposit bit 0 into MSR_C and the alias MSR_CC.  */
1653e0e16aeSRichard Henderson     tcg_gen_deposit_i32(cpu_msr, cpu_msr, v, 2, 1);
1663e0e16aeSRichard Henderson     tcg_gen_deposit_i32(cpu_msr, cpu_msr, v, 31, 1);
167fcf5ef2aSThomas Huth }
168fcf5ef2aSThomas Huth 
169fcf5ef2aSThomas Huth static void write_carryi(DisasContext *dc, bool carry)
170fcf5ef2aSThomas Huth {
171cfeea807SEdgar E. Iglesias     TCGv_i32 t0 = tcg_temp_new_i32();
172cfeea807SEdgar E. Iglesias     tcg_gen_movi_i32(t0, carry);
173fcf5ef2aSThomas Huth     write_carry(dc, t0);
174cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
175fcf5ef2aSThomas Huth }
176fcf5ef2aSThomas Huth 
177bdfc1e88SEdgar E. Iglesias /*
1789ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1799ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1809ba8cd45SEdgar E. Iglesias  */
1819ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1829ba8cd45SEdgar E. Iglesias {
1839ba8cd45SEdgar E. Iglesias     if (cond && (dc->tb_flags & MSR_EE_FLAG)
1845143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
18541ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1869ba8cd45SEdgar E. Iglesias     }
1879ba8cd45SEdgar E. Iglesias     return cond;
1889ba8cd45SEdgar E. Iglesias }
1899ba8cd45SEdgar E. Iglesias 
1909ba8cd45SEdgar E. Iglesias /*
191bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
192bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
193bdfc1e88SEdgar E. Iglesias  */
194bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
195bdfc1e88SEdgar E. Iglesias {
196bdfc1e88SEdgar E. Iglesias     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
197bdfc1e88SEdgar E. Iglesias     bool cond_user = cond && mem_index == MMU_USER_IDX;
198bdfc1e88SEdgar E. Iglesias 
199bdfc1e88SEdgar E. Iglesias     if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) {
20041ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
201bdfc1e88SEdgar E. Iglesias     }
202bdfc1e88SEdgar E. Iglesias     return cond_user;
203bdfc1e88SEdgar E. Iglesias }
204bdfc1e88SEdgar E. Iglesias 
205fcf5ef2aSThomas Huth /* True if ALU operand b is a small immediate that may deserve
206fcf5ef2aSThomas Huth    faster treatment.  */
207fcf5ef2aSThomas Huth static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
208fcf5ef2aSThomas Huth {
209fcf5ef2aSThomas Huth     /* Immediate insn without the imm prefix ?  */
210fcf5ef2aSThomas Huth     return dc->type_b && !(dc->tb_flags & IMM_FLAG);
211fcf5ef2aSThomas Huth }
212fcf5ef2aSThomas Huth 
213cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
214fcf5ef2aSThomas Huth {
215fcf5ef2aSThomas Huth     if (dc->type_b) {
216fcf5ef2aSThomas Huth         if (dc->tb_flags & IMM_FLAG)
2179b158558SRichard Henderson             tcg_gen_ori_i32(cpu_imm, cpu_imm, dc->imm);
218fcf5ef2aSThomas Huth         else
2199b158558SRichard Henderson             tcg_gen_movi_i32(cpu_imm, (int32_t)((int16_t)dc->imm));
2209b158558SRichard Henderson         return &cpu_imm;
221fcf5ef2aSThomas Huth     } else
222fcf5ef2aSThomas Huth         return &cpu_R[dc->rb];
223fcf5ef2aSThomas Huth }
224fcf5ef2aSThomas Huth 
225fcf5ef2aSThomas Huth static void dec_add(DisasContext *dc)
226fcf5ef2aSThomas Huth {
227fcf5ef2aSThomas Huth     unsigned int k, c;
228cfeea807SEdgar E. Iglesias     TCGv_i32 cf;
229fcf5ef2aSThomas Huth 
230fcf5ef2aSThomas Huth     k = dc->opcode & 4;
231fcf5ef2aSThomas Huth     c = dc->opcode & 2;
232fcf5ef2aSThomas Huth 
233fcf5ef2aSThomas Huth     LOG_DIS("add%s%s%s r%d r%d r%d\n",
234fcf5ef2aSThomas Huth             dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "",
235fcf5ef2aSThomas Huth             dc->rd, dc->ra, dc->rb);
236fcf5ef2aSThomas Huth 
237fcf5ef2aSThomas Huth     /* Take care of the easy cases first.  */
238fcf5ef2aSThomas Huth     if (k) {
239fcf5ef2aSThomas Huth         /* k - keep carry, no need to update MSR.  */
240fcf5ef2aSThomas Huth         /* If rd == r0, it's a nop.  */
241fcf5ef2aSThomas Huth         if (dc->rd) {
242cfeea807SEdgar E. Iglesias             tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
243fcf5ef2aSThomas Huth 
244fcf5ef2aSThomas Huth             if (c) {
245fcf5ef2aSThomas Huth                 /* c - Add carry into the result.  */
246cfeea807SEdgar E. Iglesias                 cf = tcg_temp_new_i32();
247fcf5ef2aSThomas Huth 
248fcf5ef2aSThomas Huth                 read_carry(dc, cf);
249cfeea807SEdgar E. Iglesias                 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
250cfeea807SEdgar E. Iglesias                 tcg_temp_free_i32(cf);
251fcf5ef2aSThomas Huth             }
252fcf5ef2aSThomas Huth         }
253fcf5ef2aSThomas Huth         return;
254fcf5ef2aSThomas Huth     }
255fcf5ef2aSThomas Huth 
256fcf5ef2aSThomas Huth     /* From now on, we can assume k is zero.  So we need to update MSR.  */
257fcf5ef2aSThomas Huth     /* Extract carry.  */
258cfeea807SEdgar E. Iglesias     cf = tcg_temp_new_i32();
259fcf5ef2aSThomas Huth     if (c) {
260fcf5ef2aSThomas Huth         read_carry(dc, cf);
261fcf5ef2aSThomas Huth     } else {
262cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cf, 0);
263fcf5ef2aSThomas Huth     }
264fcf5ef2aSThomas Huth 
265fcf5ef2aSThomas Huth     if (dc->rd) {
266cfeea807SEdgar E. Iglesias         TCGv_i32 ncf = tcg_temp_new_i32();
267fcf5ef2aSThomas Huth         gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
268cfeea807SEdgar E. Iglesias         tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
269cfeea807SEdgar E. Iglesias         tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
270fcf5ef2aSThomas Huth         write_carry(dc, ncf);
271cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(ncf);
272fcf5ef2aSThomas Huth     } else {
273fcf5ef2aSThomas Huth         gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
274fcf5ef2aSThomas Huth         write_carry(dc, cf);
275fcf5ef2aSThomas Huth     }
276cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(cf);
277fcf5ef2aSThomas Huth }
278fcf5ef2aSThomas Huth 
279fcf5ef2aSThomas Huth static void dec_sub(DisasContext *dc)
280fcf5ef2aSThomas Huth {
281fcf5ef2aSThomas Huth     unsigned int u, cmp, k, c;
282cfeea807SEdgar E. Iglesias     TCGv_i32 cf, na;
283fcf5ef2aSThomas Huth 
284fcf5ef2aSThomas Huth     u = dc->imm & 2;
285fcf5ef2aSThomas Huth     k = dc->opcode & 4;
286fcf5ef2aSThomas Huth     c = dc->opcode & 2;
287fcf5ef2aSThomas Huth     cmp = (dc->imm & 1) && (!dc->type_b) && k;
288fcf5ef2aSThomas Huth 
289fcf5ef2aSThomas Huth     if (cmp) {
290fcf5ef2aSThomas Huth         LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir);
291fcf5ef2aSThomas Huth         if (dc->rd) {
292fcf5ef2aSThomas Huth             if (u)
293fcf5ef2aSThomas Huth                 gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
294fcf5ef2aSThomas Huth             else
295fcf5ef2aSThomas Huth                 gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
296fcf5ef2aSThomas Huth         }
297fcf5ef2aSThomas Huth         return;
298fcf5ef2aSThomas Huth     }
299fcf5ef2aSThomas Huth 
300fcf5ef2aSThomas Huth     LOG_DIS("sub%s%s r%d, r%d r%d\n",
301fcf5ef2aSThomas Huth              k ? "k" : "",  c ? "c" : "", dc->rd, dc->ra, dc->rb);
302fcf5ef2aSThomas Huth 
303fcf5ef2aSThomas Huth     /* Take care of the easy cases first.  */
304fcf5ef2aSThomas Huth     if (k) {
305fcf5ef2aSThomas Huth         /* k - keep carry, no need to update MSR.  */
306fcf5ef2aSThomas Huth         /* If rd == r0, it's a nop.  */
307fcf5ef2aSThomas Huth         if (dc->rd) {
308cfeea807SEdgar E. Iglesias             tcg_gen_sub_i32(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
309fcf5ef2aSThomas Huth 
310fcf5ef2aSThomas Huth             if (c) {
311fcf5ef2aSThomas Huth                 /* c - Add carry into the result.  */
312cfeea807SEdgar E. Iglesias                 cf = tcg_temp_new_i32();
313fcf5ef2aSThomas Huth 
314fcf5ef2aSThomas Huth                 read_carry(dc, cf);
315cfeea807SEdgar E. Iglesias                 tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
316cfeea807SEdgar E. Iglesias                 tcg_temp_free_i32(cf);
317fcf5ef2aSThomas Huth             }
318fcf5ef2aSThomas Huth         }
319fcf5ef2aSThomas Huth         return;
320fcf5ef2aSThomas Huth     }
321fcf5ef2aSThomas Huth 
322fcf5ef2aSThomas Huth     /* From now on, we can assume k is zero.  So we need to update MSR.  */
323fcf5ef2aSThomas Huth     /* Extract carry. And complement a into na.  */
324cfeea807SEdgar E. Iglesias     cf = tcg_temp_new_i32();
325cfeea807SEdgar E. Iglesias     na = tcg_temp_new_i32();
326fcf5ef2aSThomas Huth     if (c) {
327fcf5ef2aSThomas Huth         read_carry(dc, cf);
328fcf5ef2aSThomas Huth     } else {
329cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cf, 1);
330fcf5ef2aSThomas Huth     }
331fcf5ef2aSThomas Huth 
332fcf5ef2aSThomas Huth     /* d = b + ~a + c. carry defaults to 1.  */
333cfeea807SEdgar E. Iglesias     tcg_gen_not_i32(na, cpu_R[dc->ra]);
334fcf5ef2aSThomas Huth 
335fcf5ef2aSThomas Huth     if (dc->rd) {
336cfeea807SEdgar E. Iglesias         TCGv_i32 ncf = tcg_temp_new_i32();
337fcf5ef2aSThomas Huth         gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
338cfeea807SEdgar E. Iglesias         tcg_gen_add_i32(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
339cfeea807SEdgar E. Iglesias         tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf);
340fcf5ef2aSThomas Huth         write_carry(dc, ncf);
341cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(ncf);
342fcf5ef2aSThomas Huth     } else {
343fcf5ef2aSThomas Huth         gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
344fcf5ef2aSThomas Huth         write_carry(dc, cf);
345fcf5ef2aSThomas Huth     }
346cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(cf);
347cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(na);
348fcf5ef2aSThomas Huth }
349fcf5ef2aSThomas Huth 
350fcf5ef2aSThomas Huth static void dec_pattern(DisasContext *dc)
351fcf5ef2aSThomas Huth {
352fcf5ef2aSThomas Huth     unsigned int mode;
353fcf5ef2aSThomas Huth 
3549ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) {
3559ba8cd45SEdgar E. Iglesias         return;
356fcf5ef2aSThomas Huth     }
357fcf5ef2aSThomas Huth 
358fcf5ef2aSThomas Huth     mode = dc->opcode & 3;
359fcf5ef2aSThomas Huth     switch (mode) {
360fcf5ef2aSThomas Huth         case 0:
361fcf5ef2aSThomas Huth             /* pcmpbf.  */
362fcf5ef2aSThomas Huth             LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
363fcf5ef2aSThomas Huth             if (dc->rd)
364fcf5ef2aSThomas Huth                 gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
365fcf5ef2aSThomas Huth             break;
366fcf5ef2aSThomas Huth         case 2:
367fcf5ef2aSThomas Huth             LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
368fcf5ef2aSThomas Huth             if (dc->rd) {
369cfeea807SEdgar E. Iglesias                 tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd],
370fcf5ef2aSThomas Huth                                    cpu_R[dc->ra], cpu_R[dc->rb]);
371fcf5ef2aSThomas Huth             }
372fcf5ef2aSThomas Huth             break;
373fcf5ef2aSThomas Huth         case 3:
374fcf5ef2aSThomas Huth             LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
375fcf5ef2aSThomas Huth             if (dc->rd) {
376cfeea807SEdgar E. Iglesias                 tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd],
377fcf5ef2aSThomas Huth                                    cpu_R[dc->ra], cpu_R[dc->rb]);
378fcf5ef2aSThomas Huth             }
379fcf5ef2aSThomas Huth             break;
380fcf5ef2aSThomas Huth         default:
381fcf5ef2aSThomas Huth             cpu_abort(CPU(dc->cpu),
382fcf5ef2aSThomas Huth                       "unsupported pattern insn opcode=%x\n", dc->opcode);
383fcf5ef2aSThomas Huth             break;
384fcf5ef2aSThomas Huth     }
385fcf5ef2aSThomas Huth }
386fcf5ef2aSThomas Huth 
387fcf5ef2aSThomas Huth static void dec_and(DisasContext *dc)
388fcf5ef2aSThomas Huth {
389fcf5ef2aSThomas Huth     unsigned int not;
390fcf5ef2aSThomas Huth 
391fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
392fcf5ef2aSThomas Huth         dec_pattern(dc);
393fcf5ef2aSThomas Huth         return;
394fcf5ef2aSThomas Huth     }
395fcf5ef2aSThomas Huth 
396fcf5ef2aSThomas Huth     not = dc->opcode & (1 << 1);
397fcf5ef2aSThomas Huth     LOG_DIS("and%s\n", not ? "n" : "");
398fcf5ef2aSThomas Huth 
399fcf5ef2aSThomas Huth     if (!dc->rd)
400fcf5ef2aSThomas Huth         return;
401fcf5ef2aSThomas Huth 
402fcf5ef2aSThomas Huth     if (not) {
403cfeea807SEdgar E. Iglesias         tcg_gen_andc_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
404fcf5ef2aSThomas Huth     } else
405cfeea807SEdgar E. Iglesias         tcg_gen_and_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
406fcf5ef2aSThomas Huth }
407fcf5ef2aSThomas Huth 
408fcf5ef2aSThomas Huth static void dec_or(DisasContext *dc)
409fcf5ef2aSThomas Huth {
410fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
411fcf5ef2aSThomas Huth         dec_pattern(dc);
412fcf5ef2aSThomas Huth         return;
413fcf5ef2aSThomas Huth     }
414fcf5ef2aSThomas Huth 
415fcf5ef2aSThomas Huth     LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm);
416fcf5ef2aSThomas Huth     if (dc->rd)
417cfeea807SEdgar E. Iglesias         tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
418fcf5ef2aSThomas Huth }
419fcf5ef2aSThomas Huth 
420fcf5ef2aSThomas Huth static void dec_xor(DisasContext *dc)
421fcf5ef2aSThomas Huth {
422fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
423fcf5ef2aSThomas Huth         dec_pattern(dc);
424fcf5ef2aSThomas Huth         return;
425fcf5ef2aSThomas Huth     }
426fcf5ef2aSThomas Huth 
427fcf5ef2aSThomas Huth     LOG_DIS("xor r%d\n", dc->rd);
428fcf5ef2aSThomas Huth     if (dc->rd)
429cfeea807SEdgar E. Iglesias         tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
430fcf5ef2aSThomas Huth }
431fcf5ef2aSThomas Huth 
432cfeea807SEdgar E. Iglesias static inline void msr_read(DisasContext *dc, TCGv_i32 d)
433fcf5ef2aSThomas Huth {
4343e0e16aeSRichard Henderson     tcg_gen_mov_i32(d, cpu_msr);
435fcf5ef2aSThomas Huth }
436fcf5ef2aSThomas Huth 
437cfeea807SEdgar E. Iglesias static inline void msr_write(DisasContext *dc, TCGv_i32 v)
438fcf5ef2aSThomas Huth {
439fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
4403e0e16aeSRichard Henderson     /* PVR bit is not writable, and is never set. */
4413e0e16aeSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~MSR_PVR);
442fcf5ef2aSThomas Huth }
443fcf5ef2aSThomas Huth 
444fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc)
445fcf5ef2aSThomas Huth {
446fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
447cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
4482023e9a3SEdgar E. Iglesias     unsigned int sr, rn;
449f0f7e7f7SEdgar E. Iglesias     bool to, clrset, extended = false;
450fcf5ef2aSThomas Huth 
4512023e9a3SEdgar E. Iglesias     sr = extract32(dc->imm, 0, 14);
4522023e9a3SEdgar E. Iglesias     to = extract32(dc->imm, 14, 1);
4532023e9a3SEdgar E. Iglesias     clrset = extract32(dc->imm, 15, 1) == 0;
454fcf5ef2aSThomas Huth     dc->type_b = 1;
4552023e9a3SEdgar E. Iglesias     if (to) {
456fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
457f0f7e7f7SEdgar E. Iglesias     }
458f0f7e7f7SEdgar E. Iglesias 
459f0f7e7f7SEdgar E. Iglesias     /* Extended MSRs are only available if addr_size > 32.  */
460f0f7e7f7SEdgar E. Iglesias     if (dc->cpu->cfg.addr_size > 32) {
461f0f7e7f7SEdgar E. Iglesias         /* The E-bit is encoded differently for To/From MSR.  */
462f0f7e7f7SEdgar E. Iglesias         static const unsigned int e_bit[] = { 19, 24 };
463f0f7e7f7SEdgar E. Iglesias 
464f0f7e7f7SEdgar E. Iglesias         extended = extract32(dc->imm, e_bit[to], 1);
4652023e9a3SEdgar E. Iglesias     }
466fcf5ef2aSThomas Huth 
467fcf5ef2aSThomas Huth     /* msrclr and msrset.  */
4682023e9a3SEdgar E. Iglesias     if (clrset) {
4692023e9a3SEdgar E. Iglesias         bool clr = extract32(dc->ir, 16, 1);
470fcf5ef2aSThomas Huth 
471fcf5ef2aSThomas Huth         LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set",
472fcf5ef2aSThomas Huth                 dc->rd, dc->imm);
473fcf5ef2aSThomas Huth 
47456837509SEdgar E. Iglesias         if (!dc->cpu->cfg.use_msr_instr) {
475fcf5ef2aSThomas Huth             /* nop??? */
476fcf5ef2aSThomas Huth             return;
477fcf5ef2aSThomas Huth         }
478fcf5ef2aSThomas Huth 
479bdfc1e88SEdgar E. Iglesias         if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
480fcf5ef2aSThomas Huth             return;
481fcf5ef2aSThomas Huth         }
482fcf5ef2aSThomas Huth 
483fcf5ef2aSThomas Huth         if (dc->rd)
484fcf5ef2aSThomas Huth             msr_read(dc, cpu_R[dc->rd]);
485fcf5ef2aSThomas Huth 
486cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
487cfeea807SEdgar E. Iglesias         t1 = tcg_temp_new_i32();
488fcf5ef2aSThomas Huth         msr_read(dc, t0);
489cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
490fcf5ef2aSThomas Huth 
491fcf5ef2aSThomas Huth         if (clr) {
492cfeea807SEdgar E. Iglesias             tcg_gen_not_i32(t1, t1);
493cfeea807SEdgar E. Iglesias             tcg_gen_and_i32(t0, t0, t1);
494fcf5ef2aSThomas Huth         } else
495cfeea807SEdgar E. Iglesias             tcg_gen_or_i32(t0, t0, t1);
496fcf5ef2aSThomas Huth         msr_write(dc, t0);
497cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
498cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t1);
4990f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->pc + 4);
500fcf5ef2aSThomas Huth         dc->is_jmp = DISAS_UPDATE;
501fcf5ef2aSThomas Huth         return;
502fcf5ef2aSThomas Huth     }
503fcf5ef2aSThomas Huth 
504bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, to)) {
505fcf5ef2aSThomas Huth         return;
506fcf5ef2aSThomas Huth     }
507fcf5ef2aSThomas Huth 
508fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
509fcf5ef2aSThomas Huth     /* Catch read/writes to the mmu block.  */
510fcf5ef2aSThomas Huth     if ((sr & ~0xff) == 0x1000) {
511f0f7e7f7SEdgar E. Iglesias         TCGv_i32 tmp_ext = tcg_const_i32(extended);
51205a9a651SEdgar E. Iglesias         TCGv_i32 tmp_sr;
51305a9a651SEdgar E. Iglesias 
514fcf5ef2aSThomas Huth         sr &= 7;
51505a9a651SEdgar E. Iglesias         tmp_sr = tcg_const_i32(sr);
516fcf5ef2aSThomas Huth         LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
51705a9a651SEdgar E. Iglesias         if (to) {
518f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
51905a9a651SEdgar E. Iglesias         } else {
520f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
52105a9a651SEdgar E. Iglesias         }
52205a9a651SEdgar E. Iglesias         tcg_temp_free_i32(tmp_sr);
523f0f7e7f7SEdgar E. Iglesias         tcg_temp_free_i32(tmp_ext);
524fcf5ef2aSThomas Huth         return;
525fcf5ef2aSThomas Huth     }
526fcf5ef2aSThomas Huth #endif
527fcf5ef2aSThomas Huth 
528fcf5ef2aSThomas Huth     if (to) {
529fcf5ef2aSThomas Huth         LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
530fcf5ef2aSThomas Huth         switch (sr) {
531aa28e6d4SRichard Henderson             case SR_PC:
532fcf5ef2aSThomas Huth                 break;
533aa28e6d4SRichard Henderson             case SR_MSR:
534fcf5ef2aSThomas Huth                 msr_write(dc, cpu_R[dc->ra]);
535fcf5ef2aSThomas Huth                 break;
536351527b7SEdgar E. Iglesias             case SR_EAR:
537dbdb77c4SRichard Henderson                 {
538dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
539dbdb77c4SRichard Henderson                     tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]);
540dbdb77c4SRichard Henderson                     tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear));
541dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
542dbdb77c4SRichard Henderson                 }
543aa28e6d4SRichard Henderson                 break;
544351527b7SEdgar E. Iglesias             case SR_ESR:
54541ba37c4SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
54641ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
547aa28e6d4SRichard Henderson                 break;
548ab6dd380SEdgar E. Iglesias             case SR_FSR:
54986017ccfSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
55086017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
551aa28e6d4SRichard Henderson                 break;
552aa28e6d4SRichard Henderson             case SR_BTR:
553ccf628b7SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
554ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
555aa28e6d4SRichard Henderson                 break;
556aa28e6d4SRichard Henderson             case SR_EDR:
55739db007eSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
55839db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
559fcf5ef2aSThomas Huth                 break;
560fcf5ef2aSThomas Huth             case 0x800:
561cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
562cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
563fcf5ef2aSThomas Huth                 break;
564fcf5ef2aSThomas Huth             case 0x802:
565cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
566cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
567fcf5ef2aSThomas Huth                 break;
568fcf5ef2aSThomas Huth             default:
569fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
570fcf5ef2aSThomas Huth                 break;
571fcf5ef2aSThomas Huth         }
572fcf5ef2aSThomas Huth     } else {
573fcf5ef2aSThomas Huth         LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm);
574fcf5ef2aSThomas Huth 
575fcf5ef2aSThomas Huth         switch (sr) {
576aa28e6d4SRichard Henderson             case SR_PC:
577cfeea807SEdgar E. Iglesias                 tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc);
578fcf5ef2aSThomas Huth                 break;
579aa28e6d4SRichard Henderson             case SR_MSR:
580fcf5ef2aSThomas Huth                 msr_read(dc, cpu_R[dc->rd]);
581fcf5ef2aSThomas Huth                 break;
582351527b7SEdgar E. Iglesias             case SR_EAR:
583dbdb77c4SRichard Henderson                 {
584dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
585dbdb77c4SRichard Henderson                     tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
586a1b48e3aSEdgar E. Iglesias                     if (extended) {
587dbdb77c4SRichard Henderson                         tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64);
588aa28e6d4SRichard Henderson                     } else {
589dbdb77c4SRichard Henderson                         tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64);
590dbdb77c4SRichard Henderson                     }
591dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
592a1b48e3aSEdgar E. Iglesias                 }
593aa28e6d4SRichard Henderson                 break;
594351527b7SEdgar E. Iglesias             case SR_ESR:
59541ba37c4SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
59641ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
597aa28e6d4SRichard Henderson                 break;
598351527b7SEdgar E. Iglesias             case SR_FSR:
59986017ccfSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
60086017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
601aa28e6d4SRichard Henderson                 break;
602351527b7SEdgar E. Iglesias             case SR_BTR:
603ccf628b7SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
604ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
605aa28e6d4SRichard Henderson                 break;
6067cdae31dSTong Ho             case SR_EDR:
60739db007eSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
60839db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
609fcf5ef2aSThomas Huth                 break;
610fcf5ef2aSThomas Huth             case 0x800:
611cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
612cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
613fcf5ef2aSThomas Huth                 break;
614fcf5ef2aSThomas Huth             case 0x802:
615cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
616cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
617fcf5ef2aSThomas Huth                 break;
618351527b7SEdgar E. Iglesias             case 0x2000 ... 0x200c:
619fcf5ef2aSThomas Huth                 rn = sr & 0xf;
620cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
621fcf5ef2aSThomas Huth                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
622fcf5ef2aSThomas Huth                 break;
623fcf5ef2aSThomas Huth             default:
624fcf5ef2aSThomas Huth                 cpu_abort(cs, "unknown mfs reg %x\n", sr);
625fcf5ef2aSThomas Huth                 break;
626fcf5ef2aSThomas Huth         }
627fcf5ef2aSThomas Huth     }
628fcf5ef2aSThomas Huth 
629fcf5ef2aSThomas Huth     if (dc->rd == 0) {
630cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[0], 0);
631fcf5ef2aSThomas Huth     }
632fcf5ef2aSThomas Huth }
633fcf5ef2aSThomas Huth 
634fcf5ef2aSThomas Huth /* Multiplier unit.  */
635fcf5ef2aSThomas Huth static void dec_mul(DisasContext *dc)
636fcf5ef2aSThomas Huth {
637cfeea807SEdgar E. Iglesias     TCGv_i32 tmp;
638fcf5ef2aSThomas Huth     unsigned int subcode;
639fcf5ef2aSThomas Huth 
6409ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_hw_mul)) {
641fcf5ef2aSThomas Huth         return;
642fcf5ef2aSThomas Huth     }
643fcf5ef2aSThomas Huth 
644fcf5ef2aSThomas Huth     subcode = dc->imm & 3;
645fcf5ef2aSThomas Huth 
646fcf5ef2aSThomas Huth     if (dc->type_b) {
647fcf5ef2aSThomas Huth         LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm);
648cfeea807SEdgar E. Iglesias         tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
649fcf5ef2aSThomas Huth         return;
650fcf5ef2aSThomas Huth     }
651fcf5ef2aSThomas Huth 
652fcf5ef2aSThomas Huth     /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2.  */
6539b964318SEdgar E. Iglesias     if (subcode >= 1 && subcode <= 3 && dc->cpu->cfg.use_hw_mul < 2) {
654fcf5ef2aSThomas Huth         /* nop??? */
655fcf5ef2aSThomas Huth     }
656fcf5ef2aSThomas Huth 
657cfeea807SEdgar E. Iglesias     tmp = tcg_temp_new_i32();
658fcf5ef2aSThomas Huth     switch (subcode) {
659fcf5ef2aSThomas Huth         case 0:
660fcf5ef2aSThomas Huth             LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
661cfeea807SEdgar E. Iglesias             tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
662fcf5ef2aSThomas Huth             break;
663fcf5ef2aSThomas Huth         case 1:
664fcf5ef2aSThomas Huth             LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
665cfeea807SEdgar E. Iglesias             tcg_gen_muls2_i32(tmp, cpu_R[dc->rd],
666cfeea807SEdgar E. Iglesias                               cpu_R[dc->ra], cpu_R[dc->rb]);
667fcf5ef2aSThomas Huth             break;
668fcf5ef2aSThomas Huth         case 2:
669fcf5ef2aSThomas Huth             LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
670cfeea807SEdgar E. Iglesias             tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd],
671cfeea807SEdgar E. Iglesias                                cpu_R[dc->ra], cpu_R[dc->rb]);
672fcf5ef2aSThomas Huth             break;
673fcf5ef2aSThomas Huth         case 3:
674fcf5ef2aSThomas Huth             LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
675cfeea807SEdgar E. Iglesias             tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
676fcf5ef2aSThomas Huth             break;
677fcf5ef2aSThomas Huth         default:
678fcf5ef2aSThomas Huth             cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode);
679fcf5ef2aSThomas Huth             break;
680fcf5ef2aSThomas Huth     }
681cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(tmp);
682fcf5ef2aSThomas Huth }
683fcf5ef2aSThomas Huth 
684fcf5ef2aSThomas Huth /* Div unit.  */
685fcf5ef2aSThomas Huth static void dec_div(DisasContext *dc)
686fcf5ef2aSThomas Huth {
687fcf5ef2aSThomas Huth     unsigned int u;
688fcf5ef2aSThomas Huth 
689fcf5ef2aSThomas Huth     u = dc->imm & 2;
690fcf5ef2aSThomas Huth     LOG_DIS("div\n");
691fcf5ef2aSThomas Huth 
6929ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_div)) {
6939ba8cd45SEdgar E. Iglesias         return;
694fcf5ef2aSThomas Huth     }
695fcf5ef2aSThomas Huth 
696fcf5ef2aSThomas Huth     if (u)
697fcf5ef2aSThomas Huth         gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
698fcf5ef2aSThomas Huth                         cpu_R[dc->ra]);
699fcf5ef2aSThomas Huth     else
700fcf5ef2aSThomas Huth         gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
701fcf5ef2aSThomas Huth                         cpu_R[dc->ra]);
702fcf5ef2aSThomas Huth     if (!dc->rd)
703cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[dc->rd], 0);
704fcf5ef2aSThomas Huth }
705fcf5ef2aSThomas Huth 
706fcf5ef2aSThomas Huth static void dec_barrel(DisasContext *dc)
707fcf5ef2aSThomas Huth {
708cfeea807SEdgar E. Iglesias     TCGv_i32 t0;
709faa48d74SEdgar E. Iglesias     unsigned int imm_w, imm_s;
710d09b2585SEdgar E. Iglesias     bool s, t, e = false, i = false;
711fcf5ef2aSThomas Huth 
7129ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) {
713fcf5ef2aSThomas Huth         return;
714fcf5ef2aSThomas Huth     }
715fcf5ef2aSThomas Huth 
716faa48d74SEdgar E. Iglesias     if (dc->type_b) {
717faa48d74SEdgar E. Iglesias         /* Insert and extract are only available in immediate mode.  */
718d09b2585SEdgar E. Iglesias         i = extract32(dc->imm, 15, 1);
719faa48d74SEdgar E. Iglesias         e = extract32(dc->imm, 14, 1);
720faa48d74SEdgar E. Iglesias     }
721e3e84983SEdgar E. Iglesias     s = extract32(dc->imm, 10, 1);
722e3e84983SEdgar E. Iglesias     t = extract32(dc->imm, 9, 1);
723faa48d74SEdgar E. Iglesias     imm_w = extract32(dc->imm, 6, 5);
724faa48d74SEdgar E. Iglesias     imm_s = extract32(dc->imm, 0, 5);
725fcf5ef2aSThomas Huth 
726faa48d74SEdgar E. Iglesias     LOG_DIS("bs%s%s%s r%d r%d r%d\n",
727faa48d74SEdgar E. Iglesias             e ? "e" : "",
728fcf5ef2aSThomas Huth             s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb);
729fcf5ef2aSThomas Huth 
730faa48d74SEdgar E. Iglesias     if (e) {
731faa48d74SEdgar E. Iglesias         if (imm_w + imm_s > 32 || imm_w == 0) {
732faa48d74SEdgar E. Iglesias             /* These inputs have an undefined behavior.  */
733faa48d74SEdgar E. Iglesias             qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
734faa48d74SEdgar E. Iglesias                           imm_w, imm_s);
735faa48d74SEdgar E. Iglesias         } else {
736faa48d74SEdgar E. Iglesias             tcg_gen_extract_i32(cpu_R[dc->rd], cpu_R[dc->ra], imm_s, imm_w);
737faa48d74SEdgar E. Iglesias         }
738d09b2585SEdgar E. Iglesias     } else if (i) {
739d09b2585SEdgar E. Iglesias         int width = imm_w - imm_s + 1;
740d09b2585SEdgar E. Iglesias 
741d09b2585SEdgar E. Iglesias         if (imm_w < imm_s) {
742d09b2585SEdgar E. Iglesias             /* These inputs have an undefined behavior.  */
743d09b2585SEdgar E. Iglesias             qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
744d09b2585SEdgar E. Iglesias                           imm_w, imm_s);
745d09b2585SEdgar E. Iglesias         } else {
746d09b2585SEdgar E. Iglesias             tcg_gen_deposit_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_R[dc->ra],
747d09b2585SEdgar E. Iglesias                                 imm_s, width);
748d09b2585SEdgar E. Iglesias         }
749faa48d74SEdgar E. Iglesias     } else {
750cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
751fcf5ef2aSThomas Huth 
752cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc)));
753cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t0, t0, 31);
754fcf5ef2aSThomas Huth 
7552acf6d53SEdgar E. Iglesias         if (s) {
756cfeea807SEdgar E. Iglesias             tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
7572acf6d53SEdgar E. Iglesias         } else {
7582acf6d53SEdgar E. Iglesias             if (t) {
759cfeea807SEdgar E. Iglesias                 tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
7602acf6d53SEdgar E. Iglesias             } else {
761cfeea807SEdgar E. Iglesias                 tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0);
762fcf5ef2aSThomas Huth             }
763fcf5ef2aSThomas Huth         }
764cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
7652acf6d53SEdgar E. Iglesias     }
766faa48d74SEdgar E. Iglesias }
767fcf5ef2aSThomas Huth 
768fcf5ef2aSThomas Huth static void dec_bit(DisasContext *dc)
769fcf5ef2aSThomas Huth {
770fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
771cfeea807SEdgar E. Iglesias     TCGv_i32 t0;
772fcf5ef2aSThomas Huth     unsigned int op;
773fcf5ef2aSThomas Huth 
774fcf5ef2aSThomas Huth     op = dc->ir & ((1 << 9) - 1);
775fcf5ef2aSThomas Huth     switch (op) {
776fcf5ef2aSThomas Huth         case 0x21:
777fcf5ef2aSThomas Huth             /* src.  */
778cfeea807SEdgar E. Iglesias             t0 = tcg_temp_new_i32();
779fcf5ef2aSThomas Huth 
780fcf5ef2aSThomas Huth             LOG_DIS("src r%d r%d\n", dc->rd, dc->ra);
7813e0e16aeSRichard Henderson             tcg_gen_andi_i32(t0, cpu_msr, MSR_CC);
782fcf5ef2aSThomas Huth             write_carry(dc, cpu_R[dc->ra]);
783fcf5ef2aSThomas Huth             if (dc->rd) {
784cfeea807SEdgar E. Iglesias                 tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
785cfeea807SEdgar E. Iglesias                 tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0);
786fcf5ef2aSThomas Huth             }
787cfeea807SEdgar E. Iglesias             tcg_temp_free_i32(t0);
788fcf5ef2aSThomas Huth             break;
789fcf5ef2aSThomas Huth 
790fcf5ef2aSThomas Huth         case 0x1:
791fcf5ef2aSThomas Huth         case 0x41:
792fcf5ef2aSThomas Huth             /* srl.  */
793fcf5ef2aSThomas Huth             LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra);
794fcf5ef2aSThomas Huth 
795fcf5ef2aSThomas Huth             /* Update carry. Note that write carry only looks at the LSB.  */
796fcf5ef2aSThomas Huth             write_carry(dc, cpu_R[dc->ra]);
797fcf5ef2aSThomas Huth             if (dc->rd) {
798fcf5ef2aSThomas Huth                 if (op == 0x41)
799cfeea807SEdgar E. Iglesias                     tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
800fcf5ef2aSThomas Huth                 else
801cfeea807SEdgar E. Iglesias                     tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1);
802fcf5ef2aSThomas Huth             }
803fcf5ef2aSThomas Huth             break;
804fcf5ef2aSThomas Huth         case 0x60:
805fcf5ef2aSThomas Huth             LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra);
806fcf5ef2aSThomas Huth             tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
807fcf5ef2aSThomas Huth             break;
808fcf5ef2aSThomas Huth         case 0x61:
809fcf5ef2aSThomas Huth             LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra);
810fcf5ef2aSThomas Huth             tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
811fcf5ef2aSThomas Huth             break;
812fcf5ef2aSThomas Huth         case 0x64:
813fcf5ef2aSThomas Huth         case 0x66:
814fcf5ef2aSThomas Huth         case 0x74:
815fcf5ef2aSThomas Huth         case 0x76:
816fcf5ef2aSThomas Huth             /* wdc.  */
817fcf5ef2aSThomas Huth             LOG_DIS("wdc r%d\n", dc->ra);
818bdfc1e88SEdgar E. Iglesias             trap_userspace(dc, true);
819fcf5ef2aSThomas Huth             break;
820fcf5ef2aSThomas Huth         case 0x68:
821fcf5ef2aSThomas Huth             /* wic.  */
822fcf5ef2aSThomas Huth             LOG_DIS("wic r%d\n", dc->ra);
823bdfc1e88SEdgar E. Iglesias             trap_userspace(dc, true);
824fcf5ef2aSThomas Huth             break;
825fcf5ef2aSThomas Huth         case 0xe0:
8269ba8cd45SEdgar E. Iglesias             if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) {
8279ba8cd45SEdgar E. Iglesias                 return;
828fcf5ef2aSThomas Huth             }
8298fc5239eSEdgar E. Iglesias             if (dc->cpu->cfg.use_pcmp_instr) {
8305318420cSRichard Henderson                 tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32);
831fcf5ef2aSThomas Huth             }
832fcf5ef2aSThomas Huth             break;
833fcf5ef2aSThomas Huth         case 0x1e0:
834fcf5ef2aSThomas Huth             /* swapb */
835fcf5ef2aSThomas Huth             LOG_DIS("swapb r%d r%d\n", dc->rd, dc->ra);
836fcf5ef2aSThomas Huth             tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
837fcf5ef2aSThomas Huth             break;
838fcf5ef2aSThomas Huth         case 0x1e2:
839fcf5ef2aSThomas Huth             /*swaph */
840fcf5ef2aSThomas Huth             LOG_DIS("swaph r%d r%d\n", dc->rd, dc->ra);
841fcf5ef2aSThomas Huth             tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16);
842fcf5ef2aSThomas Huth             break;
843fcf5ef2aSThomas Huth         default:
844fcf5ef2aSThomas Huth             cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
845fcf5ef2aSThomas Huth                       dc->pc, op, dc->rd, dc->ra, dc->rb);
846fcf5ef2aSThomas Huth             break;
847fcf5ef2aSThomas Huth     }
848fcf5ef2aSThomas Huth }
849fcf5ef2aSThomas Huth 
850fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc)
851fcf5ef2aSThomas Huth {
852fcf5ef2aSThomas Huth     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
853fcf5ef2aSThomas Huth         if (dc->jmp == JMP_DIRECT) {
8549b158558SRichard Henderson             tcg_gen_movi_i32(cpu_btaken, 1);
855fcf5ef2aSThomas Huth         }
856fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
8570f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
858fcf5ef2aSThomas Huth     }
859fcf5ef2aSThomas Huth }
860fcf5ef2aSThomas Huth 
861fcf5ef2aSThomas Huth static void dec_imm(DisasContext *dc)
862fcf5ef2aSThomas Huth {
863fcf5ef2aSThomas Huth     LOG_DIS("imm %x\n", dc->imm << 16);
8649b158558SRichard Henderson     tcg_gen_movi_i32(cpu_imm, (dc->imm << 16));
865fcf5ef2aSThomas Huth     dc->tb_flags |= IMM_FLAG;
866fcf5ef2aSThomas Huth     dc->clear_imm = 0;
867fcf5ef2aSThomas Huth }
868fcf5ef2aSThomas Huth 
869d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t)
870fcf5ef2aSThomas Huth {
8710e9033c8SEdgar E. Iglesias     bool extimm = dc->tb_flags & IMM_FLAG;
8720e9033c8SEdgar E. Iglesias     /* Should be set to true if r1 is used by loadstores.  */
8730e9033c8SEdgar E. Iglesias     bool stackprot = false;
874403322eaSEdgar E. Iglesias     TCGv_i32 t32;
875fcf5ef2aSThomas Huth 
876fcf5ef2aSThomas Huth     /* All load/stores use ra.  */
877fcf5ef2aSThomas Huth     if (dc->ra == 1 && dc->cpu->cfg.stackprot) {
8780e9033c8SEdgar E. Iglesias         stackprot = true;
879fcf5ef2aSThomas Huth     }
880fcf5ef2aSThomas Huth 
881fcf5ef2aSThomas Huth     /* Treat the common cases first.  */
882fcf5ef2aSThomas Huth     if (!dc->type_b) {
883d248e1beSEdgar E. Iglesias         if (ea) {
884d248e1beSEdgar E. Iglesias             int addr_size = dc->cpu->cfg.addr_size;
885d248e1beSEdgar E. Iglesias 
886d248e1beSEdgar E. Iglesias             if (addr_size == 32) {
887d248e1beSEdgar E. Iglesias                 tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
888d248e1beSEdgar E. Iglesias                 return;
889d248e1beSEdgar E. Iglesias             }
890d248e1beSEdgar E. Iglesias 
891d248e1beSEdgar E. Iglesias             tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]);
892d248e1beSEdgar E. Iglesias             if (addr_size < 64) {
893d248e1beSEdgar E. Iglesias                 /* Mask off out of range bits.  */
894d248e1beSEdgar E. Iglesias                 tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size));
895d248e1beSEdgar E. Iglesias             }
896d248e1beSEdgar E. Iglesias             return;
897d248e1beSEdgar E. Iglesias         }
898d248e1beSEdgar E. Iglesias 
8990dc4af5cSEdgar E. Iglesias         /* If any of the regs is r0, set t to the value of the other reg.  */
900fcf5ef2aSThomas Huth         if (dc->ra == 0) {
901403322eaSEdgar E. Iglesias             tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
9020dc4af5cSEdgar E. Iglesias             return;
903fcf5ef2aSThomas Huth         } else if (dc->rb == 0) {
904403322eaSEdgar E. Iglesias             tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]);
9050dc4af5cSEdgar E. Iglesias             return;
906fcf5ef2aSThomas Huth         }
907fcf5ef2aSThomas Huth 
908fcf5ef2aSThomas Huth         if (dc->rb == 1 && dc->cpu->cfg.stackprot) {
9090e9033c8SEdgar E. Iglesias             stackprot = true;
910fcf5ef2aSThomas Huth         }
911fcf5ef2aSThomas Huth 
912403322eaSEdgar E. Iglesias         t32 = tcg_temp_new_i32();
913403322eaSEdgar E. Iglesias         tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]);
914403322eaSEdgar E. Iglesias         tcg_gen_extu_i32_tl(t, t32);
915403322eaSEdgar E. Iglesias         tcg_temp_free_i32(t32);
916fcf5ef2aSThomas Huth 
917fcf5ef2aSThomas Huth         if (stackprot) {
9180a87e691SEdgar E. Iglesias             gen_helper_stackprot(cpu_env, t);
919fcf5ef2aSThomas Huth         }
9200dc4af5cSEdgar E. Iglesias         return;
921fcf5ef2aSThomas Huth     }
922fcf5ef2aSThomas Huth     /* Immediate.  */
923403322eaSEdgar E. Iglesias     t32 = tcg_temp_new_i32();
924fcf5ef2aSThomas Huth     if (!extimm) {
925f7a66e3aSEdgar E. Iglesias         tcg_gen_addi_i32(t32, cpu_R[dc->ra], (int16_t)dc->imm);
926403322eaSEdgar E. Iglesias     } else {
927403322eaSEdgar E. Iglesias         tcg_gen_add_i32(t32, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
928403322eaSEdgar E. Iglesias     }
929403322eaSEdgar E. Iglesias     tcg_gen_extu_i32_tl(t, t32);
930403322eaSEdgar E. Iglesias     tcg_temp_free_i32(t32);
931fcf5ef2aSThomas Huth 
932fcf5ef2aSThomas Huth     if (stackprot) {
9330a87e691SEdgar E. Iglesias         gen_helper_stackprot(cpu_env, t);
934fcf5ef2aSThomas Huth     }
9350dc4af5cSEdgar E. Iglesias     return;
936fcf5ef2aSThomas Huth }
937fcf5ef2aSThomas Huth 
938fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc)
939fcf5ef2aSThomas Huth {
940403322eaSEdgar E. Iglesias     TCGv_i32 v;
941403322eaSEdgar E. Iglesias     TCGv addr;
9428534063aSEdgar E. Iglesias     unsigned int size;
943d248e1beSEdgar E. Iglesias     bool rev = false, ex = false, ea = false;
944d248e1beSEdgar E. Iglesias     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
94514776ab5STony Nguyen     MemOp mop;
946fcf5ef2aSThomas Huth 
947fcf5ef2aSThomas Huth     mop = dc->opcode & 3;
948fcf5ef2aSThomas Huth     size = 1 << mop;
949fcf5ef2aSThomas Huth     if (!dc->type_b) {
950d248e1beSEdgar E. Iglesias         ea = extract32(dc->ir, 7, 1);
9518534063aSEdgar E. Iglesias         rev = extract32(dc->ir, 9, 1);
9528534063aSEdgar E. Iglesias         ex = extract32(dc->ir, 10, 1);
953fcf5ef2aSThomas Huth     }
954fcf5ef2aSThomas Huth     mop |= MO_TE;
955fcf5ef2aSThomas Huth     if (rev) {
956fcf5ef2aSThomas Huth         mop ^= MO_BSWAP;
957fcf5ef2aSThomas Huth     }
958fcf5ef2aSThomas Huth 
9599ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, size > 4)) {
960fcf5ef2aSThomas Huth         return;
961fcf5ef2aSThomas Huth     }
962fcf5ef2aSThomas Huth 
963d248e1beSEdgar E. Iglesias     if (trap_userspace(dc, ea)) {
964d248e1beSEdgar E. Iglesias         return;
965d248e1beSEdgar E. Iglesias     }
966d248e1beSEdgar E. Iglesias 
967d248e1beSEdgar E. Iglesias     LOG_DIS("l%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
968d248e1beSEdgar E. Iglesias                                                         ex ? "x" : "",
969d248e1beSEdgar E. Iglesias                                                         ea ? "ea" : "");
970fcf5ef2aSThomas Huth 
971fcf5ef2aSThomas Huth     t_sync_flags(dc);
972403322eaSEdgar E. Iglesias     addr = tcg_temp_new();
973d248e1beSEdgar E. Iglesias     compute_ldst_addr(dc, ea, addr);
974d248e1beSEdgar E. Iglesias     /* Extended addressing bypasses the MMU.  */
975d248e1beSEdgar E. Iglesias     mem_index = ea ? MMU_NOMMU_IDX : mem_index;
976fcf5ef2aSThomas Huth 
977fcf5ef2aSThomas Huth     /*
978fcf5ef2aSThomas Huth      * When doing reverse accesses we need to do two things.
979fcf5ef2aSThomas Huth      *
980fcf5ef2aSThomas Huth      * 1. Reverse the address wrt endianness.
981fcf5ef2aSThomas Huth      * 2. Byteswap the data lanes on the way back into the CPU core.
982fcf5ef2aSThomas Huth      */
983fcf5ef2aSThomas Huth     if (rev && size != 4) {
984fcf5ef2aSThomas Huth         /* Endian reverse the address. t is addr.  */
985fcf5ef2aSThomas Huth         switch (size) {
986fcf5ef2aSThomas Huth             case 1:
987fcf5ef2aSThomas Huth             {
988a6338015SEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 3);
989fcf5ef2aSThomas Huth                 break;
990fcf5ef2aSThomas Huth             }
991fcf5ef2aSThomas Huth 
992fcf5ef2aSThomas Huth             case 2:
993fcf5ef2aSThomas Huth                 /* 00 -> 10
994fcf5ef2aSThomas Huth                    10 -> 00.  */
995403322eaSEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 2);
996fcf5ef2aSThomas Huth                 break;
997fcf5ef2aSThomas Huth             default:
998fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
999fcf5ef2aSThomas Huth                 break;
1000fcf5ef2aSThomas Huth         }
1001fcf5ef2aSThomas Huth     }
1002fcf5ef2aSThomas Huth 
1003fcf5ef2aSThomas Huth     /* lwx does not throw unaligned access errors, so force alignment */
1004fcf5ef2aSThomas Huth     if (ex) {
1005403322eaSEdgar E. Iglesias         tcg_gen_andi_tl(addr, addr, ~3);
1006fcf5ef2aSThomas Huth     }
1007fcf5ef2aSThomas Huth 
1008fcf5ef2aSThomas Huth     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
1009fcf5ef2aSThomas Huth     sync_jmpstate(dc);
1010fcf5ef2aSThomas Huth 
1011fcf5ef2aSThomas Huth     /* Verify alignment if needed.  */
1012fcf5ef2aSThomas Huth     /*
1013fcf5ef2aSThomas Huth      * Microblaze gives MMU faults priority over faults due to
1014fcf5ef2aSThomas Huth      * unaligned addresses. That's why we speculatively do the load
1015fcf5ef2aSThomas Huth      * into v. If the load succeeds, we verify alignment of the
1016fcf5ef2aSThomas Huth      * address and if that succeeds we write into the destination reg.
1017fcf5ef2aSThomas Huth      */
1018cfeea807SEdgar E. Iglesias     v = tcg_temp_new_i32();
1019d248e1beSEdgar E. Iglesias     tcg_gen_qemu_ld_i32(v, addr, mem_index, mop);
1020fcf5ef2aSThomas Huth 
10211507e5f6SEdgar E. Iglesias     if (dc->cpu->cfg.unaligned_exceptions && size > 1) {
1022a6338015SEdgar E. Iglesias         TCGv_i32 t0 = tcg_const_i32(0);
1023a6338015SEdgar E. Iglesias         TCGv_i32 treg = tcg_const_i32(dc->rd);
1024a6338015SEdgar E. Iglesias         TCGv_i32 tsize = tcg_const_i32(size - 1);
1025a6338015SEdgar E. Iglesias 
10260f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->pc);
1027a6338015SEdgar E. Iglesias         gen_helper_memalign(cpu_env, addr, treg, t0, tsize);
1028a6338015SEdgar E. Iglesias 
1029a6338015SEdgar E. Iglesias         tcg_temp_free_i32(t0);
1030a6338015SEdgar E. Iglesias         tcg_temp_free_i32(treg);
1031a6338015SEdgar E. Iglesias         tcg_temp_free_i32(tsize);
1032fcf5ef2aSThomas Huth     }
1033fcf5ef2aSThomas Huth 
1034fcf5ef2aSThomas Huth     if (ex) {
10359b158558SRichard Henderson         tcg_gen_mov_tl(cpu_res_addr, addr);
10369b158558SRichard Henderson         tcg_gen_mov_i32(cpu_res_val, v);
1037fcf5ef2aSThomas Huth     }
1038fcf5ef2aSThomas Huth     if (dc->rd) {
1039cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(cpu_R[dc->rd], v);
1040fcf5ef2aSThomas Huth     }
1041cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(v);
1042fcf5ef2aSThomas Huth 
1043fcf5ef2aSThomas Huth     if (ex) { /* lwx */
1044fcf5ef2aSThomas Huth         /* no support for AXI exclusive so always clear C */
1045fcf5ef2aSThomas Huth         write_carryi(dc, 0);
1046fcf5ef2aSThomas Huth     }
1047fcf5ef2aSThomas Huth 
1048403322eaSEdgar E. Iglesias     tcg_temp_free(addr);
1049fcf5ef2aSThomas Huth }
1050fcf5ef2aSThomas Huth 
1051fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc)
1052fcf5ef2aSThomas Huth {
1053403322eaSEdgar E. Iglesias     TCGv addr;
1054fcf5ef2aSThomas Huth     TCGLabel *swx_skip = NULL;
1055b51b3d43SEdgar E. Iglesias     unsigned int size;
1056d248e1beSEdgar E. Iglesias     bool rev = false, ex = false, ea = false;
1057d248e1beSEdgar E. Iglesias     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
105814776ab5STony Nguyen     MemOp mop;
1059fcf5ef2aSThomas Huth 
1060fcf5ef2aSThomas Huth     mop = dc->opcode & 3;
1061fcf5ef2aSThomas Huth     size = 1 << mop;
1062fcf5ef2aSThomas Huth     if (!dc->type_b) {
1063d248e1beSEdgar E. Iglesias         ea = extract32(dc->ir, 7, 1);
1064b51b3d43SEdgar E. Iglesias         rev = extract32(dc->ir, 9, 1);
1065b51b3d43SEdgar E. Iglesias         ex = extract32(dc->ir, 10, 1);
1066fcf5ef2aSThomas Huth     }
1067fcf5ef2aSThomas Huth     mop |= MO_TE;
1068fcf5ef2aSThomas Huth     if (rev) {
1069fcf5ef2aSThomas Huth         mop ^= MO_BSWAP;
1070fcf5ef2aSThomas Huth     }
1071fcf5ef2aSThomas Huth 
10729ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, size > 4)) {
1073fcf5ef2aSThomas Huth         return;
1074fcf5ef2aSThomas Huth     }
1075fcf5ef2aSThomas Huth 
1076d248e1beSEdgar E. Iglesias     trap_userspace(dc, ea);
1077d248e1beSEdgar E. Iglesias 
1078d248e1beSEdgar E. Iglesias     LOG_DIS("s%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
1079d248e1beSEdgar E. Iglesias                                                         ex ? "x" : "",
1080d248e1beSEdgar E. Iglesias                                                         ea ? "ea" : "");
1081fcf5ef2aSThomas Huth     t_sync_flags(dc);
1082fcf5ef2aSThomas Huth     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
1083fcf5ef2aSThomas Huth     sync_jmpstate(dc);
10840dc4af5cSEdgar E. Iglesias     /* SWX needs a temp_local.  */
1085403322eaSEdgar E. Iglesias     addr = ex ? tcg_temp_local_new() : tcg_temp_new();
1086d248e1beSEdgar E. Iglesias     compute_ldst_addr(dc, ea, addr);
1087d248e1beSEdgar E. Iglesias     /* Extended addressing bypasses the MMU.  */
1088d248e1beSEdgar E. Iglesias     mem_index = ea ? MMU_NOMMU_IDX : mem_index;
1089fcf5ef2aSThomas Huth 
1090fcf5ef2aSThomas Huth     if (ex) { /* swx */
1091cfeea807SEdgar E. Iglesias         TCGv_i32 tval;
1092fcf5ef2aSThomas Huth 
1093fcf5ef2aSThomas Huth         /* swx does not throw unaligned access errors, so force alignment */
1094403322eaSEdgar E. Iglesias         tcg_gen_andi_tl(addr, addr, ~3);
1095fcf5ef2aSThomas Huth 
1096fcf5ef2aSThomas Huth         write_carryi(dc, 1);
1097fcf5ef2aSThomas Huth         swx_skip = gen_new_label();
10989b158558SRichard Henderson         tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip);
1099fcf5ef2aSThomas Huth 
1100071cdc67SEdgar E. Iglesias         /*
1101071cdc67SEdgar E. Iglesias          * Compare the value loaded at lwx with current contents of
1102071cdc67SEdgar E. Iglesias          * the reserved location.
1103071cdc67SEdgar E. Iglesias          */
1104cfeea807SEdgar E. Iglesias         tval = tcg_temp_new_i32();
1105071cdc67SEdgar E. Iglesias 
11069b158558SRichard Henderson         tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val,
1107071cdc67SEdgar E. Iglesias                                    cpu_R[dc->rd], mem_index,
1108071cdc67SEdgar E. Iglesias                                    mop);
1109071cdc67SEdgar E. Iglesias 
11109b158558SRichard Henderson         tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip);
1111fcf5ef2aSThomas Huth         write_carryi(dc, 0);
1112cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(tval);
1113fcf5ef2aSThomas Huth     }
1114fcf5ef2aSThomas Huth 
1115fcf5ef2aSThomas Huth     if (rev && size != 4) {
1116fcf5ef2aSThomas Huth         /* Endian reverse the address. t is addr.  */
1117fcf5ef2aSThomas Huth         switch (size) {
1118fcf5ef2aSThomas Huth             case 1:
1119fcf5ef2aSThomas Huth             {
1120a6338015SEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 3);
1121fcf5ef2aSThomas Huth                 break;
1122fcf5ef2aSThomas Huth             }
1123fcf5ef2aSThomas Huth 
1124fcf5ef2aSThomas Huth             case 2:
1125fcf5ef2aSThomas Huth                 /* 00 -> 10
1126fcf5ef2aSThomas Huth                    10 -> 00.  */
1127fcf5ef2aSThomas Huth                 /* Force addr into the temp.  */
1128403322eaSEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 2);
1129fcf5ef2aSThomas Huth                 break;
1130fcf5ef2aSThomas Huth             default:
1131fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
1132fcf5ef2aSThomas Huth                 break;
1133fcf5ef2aSThomas Huth         }
1134fcf5ef2aSThomas Huth     }
1135071cdc67SEdgar E. Iglesias 
1136071cdc67SEdgar E. Iglesias     if (!ex) {
1137d248e1beSEdgar E. Iglesias         tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop);
1138071cdc67SEdgar E. Iglesias     }
1139fcf5ef2aSThomas Huth 
1140fcf5ef2aSThomas Huth     /* Verify alignment if needed.  */
11411507e5f6SEdgar E. Iglesias     if (dc->cpu->cfg.unaligned_exceptions && size > 1) {
1142a6338015SEdgar E. Iglesias         TCGv_i32 t1 = tcg_const_i32(1);
1143a6338015SEdgar E. Iglesias         TCGv_i32 treg = tcg_const_i32(dc->rd);
1144a6338015SEdgar E. Iglesias         TCGv_i32 tsize = tcg_const_i32(size - 1);
1145a6338015SEdgar E. Iglesias 
11460f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->pc);
1147fcf5ef2aSThomas Huth         /* FIXME: if the alignment is wrong, we should restore the value
1148fcf5ef2aSThomas Huth          *        in memory. One possible way to achieve this is to probe
1149fcf5ef2aSThomas Huth          *        the MMU prior to the memaccess, thay way we could put
1150fcf5ef2aSThomas Huth          *        the alignment checks in between the probe and the mem
1151fcf5ef2aSThomas Huth          *        access.
1152fcf5ef2aSThomas Huth          */
1153a6338015SEdgar E. Iglesias         gen_helper_memalign(cpu_env, addr, treg, t1, tsize);
1154a6338015SEdgar E. Iglesias 
1155a6338015SEdgar E. Iglesias         tcg_temp_free_i32(t1);
1156a6338015SEdgar E. Iglesias         tcg_temp_free_i32(treg);
1157a6338015SEdgar E. Iglesias         tcg_temp_free_i32(tsize);
1158fcf5ef2aSThomas Huth     }
1159fcf5ef2aSThomas Huth 
1160fcf5ef2aSThomas Huth     if (ex) {
1161fcf5ef2aSThomas Huth         gen_set_label(swx_skip);
1162fcf5ef2aSThomas Huth     }
1163fcf5ef2aSThomas Huth 
1164403322eaSEdgar E. Iglesias     tcg_temp_free(addr);
1165fcf5ef2aSThomas Huth }
1166fcf5ef2aSThomas Huth 
1167fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc,
11689e6e1828SEdgar E. Iglesias                            TCGv_i32 d, TCGv_i32 a)
1169fcf5ef2aSThomas Huth {
1170d89b86e9SEdgar E. Iglesias     static const int mb_to_tcg_cc[] = {
1171d89b86e9SEdgar E. Iglesias         [CC_EQ] = TCG_COND_EQ,
1172d89b86e9SEdgar E. Iglesias         [CC_NE] = TCG_COND_NE,
1173d89b86e9SEdgar E. Iglesias         [CC_LT] = TCG_COND_LT,
1174d89b86e9SEdgar E. Iglesias         [CC_LE] = TCG_COND_LE,
1175d89b86e9SEdgar E. Iglesias         [CC_GE] = TCG_COND_GE,
1176d89b86e9SEdgar E. Iglesias         [CC_GT] = TCG_COND_GT,
1177d89b86e9SEdgar E. Iglesias     };
1178d89b86e9SEdgar E. Iglesias 
1179fcf5ef2aSThomas Huth     switch (cc) {
1180fcf5ef2aSThomas Huth     case CC_EQ:
1181fcf5ef2aSThomas Huth     case CC_NE:
1182fcf5ef2aSThomas Huth     case CC_LT:
1183fcf5ef2aSThomas Huth     case CC_LE:
1184fcf5ef2aSThomas Huth     case CC_GE:
1185fcf5ef2aSThomas Huth     case CC_GT:
11869e6e1828SEdgar E. Iglesias         tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
1187fcf5ef2aSThomas Huth         break;
1188fcf5ef2aSThomas Huth     default:
1189fcf5ef2aSThomas Huth         cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
1190fcf5ef2aSThomas Huth         break;
1191fcf5ef2aSThomas Huth     }
1192fcf5ef2aSThomas Huth }
1193fcf5ef2aSThomas Huth 
11940f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false)
1195fcf5ef2aSThomas Huth {
11960f96e96bSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
1197e956caf2SEdgar E. Iglesias 
11980f96e96bSRichard Henderson     tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc,
11999b158558SRichard Henderson                         cpu_btaken, zero,
1200e956caf2SEdgar E. Iglesias                         pc_true, pc_false);
1201e956caf2SEdgar E. Iglesias 
12020f96e96bSRichard Henderson     tcg_temp_free_i32(zero);
1203fcf5ef2aSThomas Huth }
1204fcf5ef2aSThomas Huth 
1205f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc)
1206f91c60f0SEdgar E. Iglesias {
1207f91c60f0SEdgar E. Iglesias         TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG));
1208f91c60f0SEdgar E. Iglesias 
1209f91c60f0SEdgar E. Iglesias         dc->delayed_branch = 2;
1210f91c60f0SEdgar E. Iglesias         dc->tb_flags |= D_FLAG;
1211f91c60f0SEdgar E. Iglesias 
1212f91c60f0SEdgar E. Iglesias         tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm));
1213f91c60f0SEdgar E. Iglesias         tcg_temp_free_i32(tmp);
1214f91c60f0SEdgar E. Iglesias }
1215f91c60f0SEdgar E. Iglesias 
1216fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc)
1217fcf5ef2aSThomas Huth {
1218fcf5ef2aSThomas Huth     unsigned int cc;
1219fcf5ef2aSThomas Huth     unsigned int dslot;
1220fcf5ef2aSThomas Huth 
1221fcf5ef2aSThomas Huth     cc = EXTRACT_FIELD(dc->ir, 21, 23);
1222fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 25);
1223fcf5ef2aSThomas Huth     LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm);
1224fcf5ef2aSThomas Huth 
1225fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1226fcf5ef2aSThomas Huth     if (dslot) {
1227f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1228fcf5ef2aSThomas Huth     }
1229fcf5ef2aSThomas Huth 
1230fcf5ef2aSThomas Huth     if (dec_alu_op_b_is_small_imm(dc)) {
1231fcf5ef2aSThomas Huth         int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend.  */
1232fcf5ef2aSThomas Huth 
12330f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->pc + offset);
1234fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT_CC;
1235fcf5ef2aSThomas Huth         dc->jmp_pc = dc->pc + offset;
1236fcf5ef2aSThomas Huth     } else {
1237fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
12380f96e96bSRichard Henderson         tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc);
1239fcf5ef2aSThomas Huth     }
12409b158558SRichard Henderson     eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]);
1241fcf5ef2aSThomas Huth }
1242fcf5ef2aSThomas Huth 
1243fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc)
1244fcf5ef2aSThomas Huth {
1245fcf5ef2aSThomas Huth     unsigned int dslot, link, abs, mbar;
1246fcf5ef2aSThomas Huth 
1247fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 20);
1248fcf5ef2aSThomas Huth     abs = dc->ir & (1 << 19);
1249fcf5ef2aSThomas Huth     link = dc->ir & (1 << 18);
1250fcf5ef2aSThomas Huth 
1251fcf5ef2aSThomas Huth     /* Memory barrier.  */
1252fcf5ef2aSThomas Huth     mbar = (dc->ir >> 16) & 31;
1253fcf5ef2aSThomas Huth     if (mbar == 2 && dc->imm == 4) {
1254badcbf9dSEdgar E. Iglesias         uint16_t mbar_imm = dc->rd;
1255badcbf9dSEdgar E. Iglesias 
12566f3c458bSEdgar E. Iglesias         LOG_DIS("mbar %d\n", mbar_imm);
12576f3c458bSEdgar E. Iglesias 
12583f172744SEdgar E. Iglesias         /* Data access memory barrier.  */
12593f172744SEdgar E. Iglesias         if ((mbar_imm & 2) == 0) {
12603f172744SEdgar E. Iglesias             tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
12613f172744SEdgar E. Iglesias         }
12623f172744SEdgar E. Iglesias 
1263fcf5ef2aSThomas Huth         /* mbar IMM & 16 decodes to sleep.  */
1264badcbf9dSEdgar E. Iglesias         if (mbar_imm & 16) {
126541ba37c4SRichard Henderson             TCGv_i32 tmp_1;
1266fcf5ef2aSThomas Huth 
1267fcf5ef2aSThomas Huth             LOG_DIS("sleep\n");
1268fcf5ef2aSThomas Huth 
1269b4919e7dSEdgar E. Iglesias             if (trap_userspace(dc, true)) {
1270b4919e7dSEdgar E. Iglesias                 /* Sleep is a privileged instruction.  */
1271b4919e7dSEdgar E. Iglesias                 return;
1272b4919e7dSEdgar E. Iglesias             }
1273b4919e7dSEdgar E. Iglesias 
1274fcf5ef2aSThomas Huth             t_sync_flags(dc);
127541ba37c4SRichard Henderson 
127641ba37c4SRichard Henderson             tmp_1 = tcg_const_i32(1);
1277fcf5ef2aSThomas Huth             tcg_gen_st_i32(tmp_1, cpu_env,
1278fcf5ef2aSThomas Huth                            -offsetof(MicroBlazeCPU, env)
1279fcf5ef2aSThomas Huth                            +offsetof(CPUState, halted));
1280fcf5ef2aSThomas Huth             tcg_temp_free_i32(tmp_1);
128141ba37c4SRichard Henderson 
128241ba37c4SRichard Henderson             tcg_gen_movi_i32(cpu_pc, dc->pc + 4);
128341ba37c4SRichard Henderson 
128441ba37c4SRichard Henderson             gen_raise_exception(dc, EXCP_HLT);
1285fcf5ef2aSThomas Huth             return;
1286fcf5ef2aSThomas Huth         }
1287fcf5ef2aSThomas Huth         /* Break the TB.  */
1288fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1289fcf5ef2aSThomas Huth         return;
1290fcf5ef2aSThomas Huth     }
1291fcf5ef2aSThomas Huth 
1292fcf5ef2aSThomas Huth     LOG_DIS("br%s%s%s%s imm=%x\n",
1293fcf5ef2aSThomas Huth              abs ? "a" : "", link ? "l" : "",
1294fcf5ef2aSThomas Huth              dc->type_b ? "i" : "", dslot ? "d" : "",
1295fcf5ef2aSThomas Huth              dc->imm);
1296fcf5ef2aSThomas Huth 
1297fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1298fcf5ef2aSThomas Huth     if (dslot) {
1299f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1300fcf5ef2aSThomas Huth     }
1301fcf5ef2aSThomas Huth     if (link && dc->rd)
1302cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc);
1303fcf5ef2aSThomas Huth 
1304fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
1305fcf5ef2aSThomas Huth     if (abs) {
13069b158558SRichard Henderson         tcg_gen_movi_i32(cpu_btaken, 1);
13070f96e96bSRichard Henderson         tcg_gen_mov_i32(cpu_btarget, *(dec_alu_op_b(dc)));
1308fcf5ef2aSThomas Huth         if (link && !dslot) {
130941ba37c4SRichard Henderson             if (!(dc->tb_flags & IMM_FLAG) &&
131041ba37c4SRichard Henderson                 (dc->imm == 8 || dc->imm == 0x18)) {
131141ba37c4SRichard Henderson                 gen_raise_exception_sync(dc, EXCP_BREAK);
131241ba37c4SRichard Henderson             }
1313fcf5ef2aSThomas Huth             if (dc->imm == 0) {
1314bdfc1e88SEdgar E. Iglesias                 if (trap_userspace(dc, true)) {
1315fcf5ef2aSThomas Huth                     return;
1316fcf5ef2aSThomas Huth                 }
131741ba37c4SRichard Henderson                 gen_raise_exception_sync(dc, EXCP_DEBUG);
1318fcf5ef2aSThomas Huth             }
1319fcf5ef2aSThomas Huth         }
1320fcf5ef2aSThomas Huth     } else {
1321fcf5ef2aSThomas Huth         if (dec_alu_op_b_is_small_imm(dc)) {
1322fcf5ef2aSThomas Huth             dc->jmp = JMP_DIRECT;
1323fcf5ef2aSThomas Huth             dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
1324fcf5ef2aSThomas Huth         } else {
13259b158558SRichard Henderson             tcg_gen_movi_i32(cpu_btaken, 1);
13260f96e96bSRichard Henderson             tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc);
1327fcf5ef2aSThomas Huth         }
1328fcf5ef2aSThomas Huth     }
1329fcf5ef2aSThomas Huth }
1330fcf5ef2aSThomas Huth 
1331fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc)
1332fcf5ef2aSThomas Huth {
1333cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1334cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1335cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
13363e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
13370a22f8cfSEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
13380a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_IE);
1339cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1340fcf5ef2aSThomas Huth 
1341cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1342cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1343fcf5ef2aSThomas Huth     msr_write(dc, t1);
1344cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1345cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1346fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1347fcf5ef2aSThomas Huth }
1348fcf5ef2aSThomas Huth 
1349fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc)
1350fcf5ef2aSThomas Huth {
1351cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1352cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1353cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
13543e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
13550a22f8cfSEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
1356cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1357cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1358fcf5ef2aSThomas Huth 
1359cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1360cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1361fcf5ef2aSThomas Huth     msr_write(dc, t1);
1362cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1363cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1364fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1365fcf5ef2aSThomas Huth }
1366fcf5ef2aSThomas Huth 
1367fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc)
1368fcf5ef2aSThomas Huth {
1369cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1370cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1371cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
1372fcf5ef2aSThomas Huth 
13733e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
13740a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_EE);
1375cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
1376cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1377cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1378fcf5ef2aSThomas Huth 
1379cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1380cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1381fcf5ef2aSThomas Huth     msr_write(dc, t1);
1382cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1383cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1384fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1385fcf5ef2aSThomas Huth }
1386fcf5ef2aSThomas Huth 
1387fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc)
1388fcf5ef2aSThomas Huth {
1389fcf5ef2aSThomas Huth     unsigned int b_bit, i_bit, e_bit;
1390fcf5ef2aSThomas Huth 
1391fcf5ef2aSThomas Huth     i_bit = dc->ir & (1 << 21);
1392fcf5ef2aSThomas Huth     b_bit = dc->ir & (1 << 22);
1393fcf5ef2aSThomas Huth     e_bit = dc->ir & (1 << 23);
1394fcf5ef2aSThomas Huth 
1395bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
1396bdfc1e88SEdgar E. Iglesias         return;
1397bdfc1e88SEdgar E. Iglesias     }
1398bdfc1e88SEdgar E. Iglesias 
1399f91c60f0SEdgar E. Iglesias     dec_setup_dslot(dc);
1400fcf5ef2aSThomas Huth 
1401fcf5ef2aSThomas Huth     if (i_bit) {
1402fcf5ef2aSThomas Huth         LOG_DIS("rtid ir=%x\n", dc->ir);
1403fcf5ef2aSThomas Huth         dc->tb_flags |= DRTI_FLAG;
1404fcf5ef2aSThomas Huth     } else if (b_bit) {
1405fcf5ef2aSThomas Huth         LOG_DIS("rtbd ir=%x\n", dc->ir);
1406fcf5ef2aSThomas Huth         dc->tb_flags |= DRTB_FLAG;
1407fcf5ef2aSThomas Huth     } else if (e_bit) {
1408fcf5ef2aSThomas Huth         LOG_DIS("rted ir=%x\n", dc->ir);
1409fcf5ef2aSThomas Huth         dc->tb_flags |= DRTE_FLAG;
1410fcf5ef2aSThomas Huth     } else
1411fcf5ef2aSThomas Huth         LOG_DIS("rts ir=%x\n", dc->ir);
1412fcf5ef2aSThomas Huth 
1413fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
14149b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
14150f96e96bSRichard Henderson     tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc));
1416fcf5ef2aSThomas Huth }
1417fcf5ef2aSThomas Huth 
1418fcf5ef2aSThomas Huth static int dec_check_fpuv2(DisasContext *dc)
1419fcf5ef2aSThomas Huth {
1420fcf5ef2aSThomas Huth     if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) {
142141ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_FPU);
1422fcf5ef2aSThomas Huth     }
14232016a6a7SJoe Komlodi     return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0;
1424fcf5ef2aSThomas Huth }
1425fcf5ef2aSThomas Huth 
1426fcf5ef2aSThomas Huth static void dec_fpu(DisasContext *dc)
1427fcf5ef2aSThomas Huth {
1428fcf5ef2aSThomas Huth     unsigned int fpu_insn;
1429fcf5ef2aSThomas Huth 
14309ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) {
1431fcf5ef2aSThomas Huth         return;
1432fcf5ef2aSThomas Huth     }
1433fcf5ef2aSThomas Huth 
1434fcf5ef2aSThomas Huth     fpu_insn = (dc->ir >> 7) & 7;
1435fcf5ef2aSThomas Huth 
1436fcf5ef2aSThomas Huth     switch (fpu_insn) {
1437fcf5ef2aSThomas Huth         case 0:
1438fcf5ef2aSThomas Huth             gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1439fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1440fcf5ef2aSThomas Huth             break;
1441fcf5ef2aSThomas Huth 
1442fcf5ef2aSThomas Huth         case 1:
1443fcf5ef2aSThomas Huth             gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1444fcf5ef2aSThomas Huth                              cpu_R[dc->rb]);
1445fcf5ef2aSThomas Huth             break;
1446fcf5ef2aSThomas Huth 
1447fcf5ef2aSThomas Huth         case 2:
1448fcf5ef2aSThomas Huth             gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1449fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1450fcf5ef2aSThomas Huth             break;
1451fcf5ef2aSThomas Huth 
1452fcf5ef2aSThomas Huth         case 3:
1453fcf5ef2aSThomas Huth             gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1454fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1455fcf5ef2aSThomas Huth             break;
1456fcf5ef2aSThomas Huth 
1457fcf5ef2aSThomas Huth         case 4:
1458fcf5ef2aSThomas Huth             switch ((dc->ir >> 4) & 7) {
1459fcf5ef2aSThomas Huth                 case 0:
1460fcf5ef2aSThomas Huth                     gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env,
1461fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1462fcf5ef2aSThomas Huth                     break;
1463fcf5ef2aSThomas Huth                 case 1:
1464fcf5ef2aSThomas Huth                     gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env,
1465fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1466fcf5ef2aSThomas Huth                     break;
1467fcf5ef2aSThomas Huth                 case 2:
1468fcf5ef2aSThomas Huth                     gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env,
1469fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1470fcf5ef2aSThomas Huth                     break;
1471fcf5ef2aSThomas Huth                 case 3:
1472fcf5ef2aSThomas Huth                     gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env,
1473fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1474fcf5ef2aSThomas Huth                     break;
1475fcf5ef2aSThomas Huth                 case 4:
1476fcf5ef2aSThomas Huth                     gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env,
1477fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1478fcf5ef2aSThomas Huth                     break;
1479fcf5ef2aSThomas Huth                 case 5:
1480fcf5ef2aSThomas Huth                     gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env,
1481fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1482fcf5ef2aSThomas Huth                     break;
1483fcf5ef2aSThomas Huth                 case 6:
1484fcf5ef2aSThomas Huth                     gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env,
1485fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1486fcf5ef2aSThomas Huth                     break;
1487fcf5ef2aSThomas Huth                 default:
1488fcf5ef2aSThomas Huth                     qemu_log_mask(LOG_UNIMP,
1489fcf5ef2aSThomas Huth                                   "unimplemented fcmp fpu_insn=%x pc=%x"
1490fcf5ef2aSThomas Huth                                   " opc=%x\n",
1491fcf5ef2aSThomas Huth                                   fpu_insn, dc->pc, dc->opcode);
1492fcf5ef2aSThomas Huth                     dc->abort_at_next_insn = 1;
1493fcf5ef2aSThomas Huth                     break;
1494fcf5ef2aSThomas Huth             }
1495fcf5ef2aSThomas Huth             break;
1496fcf5ef2aSThomas Huth 
1497fcf5ef2aSThomas Huth         case 5:
1498fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1499fcf5ef2aSThomas Huth                 return;
1500fcf5ef2aSThomas Huth             }
1501fcf5ef2aSThomas Huth             gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1502fcf5ef2aSThomas Huth             break;
1503fcf5ef2aSThomas Huth 
1504fcf5ef2aSThomas Huth         case 6:
1505fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1506fcf5ef2aSThomas Huth                 return;
1507fcf5ef2aSThomas Huth             }
1508fcf5ef2aSThomas Huth             gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1509fcf5ef2aSThomas Huth             break;
1510fcf5ef2aSThomas Huth 
1511fcf5ef2aSThomas Huth         case 7:
1512fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1513fcf5ef2aSThomas Huth                 return;
1514fcf5ef2aSThomas Huth             }
1515fcf5ef2aSThomas Huth             gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1516fcf5ef2aSThomas Huth             break;
1517fcf5ef2aSThomas Huth 
1518fcf5ef2aSThomas Huth         default:
1519fcf5ef2aSThomas Huth             qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x"
1520fcf5ef2aSThomas Huth                           " opc=%x\n",
1521fcf5ef2aSThomas Huth                           fpu_insn, dc->pc, dc->opcode);
1522fcf5ef2aSThomas Huth             dc->abort_at_next_insn = 1;
1523fcf5ef2aSThomas Huth             break;
1524fcf5ef2aSThomas Huth     }
1525fcf5ef2aSThomas Huth }
1526fcf5ef2aSThomas Huth 
1527fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc)
1528fcf5ef2aSThomas Huth {
15299ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, true)) {
1530fcf5ef2aSThomas Huth         return;
1531fcf5ef2aSThomas Huth     }
1532fcf5ef2aSThomas Huth     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
1533fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 1;
1534fcf5ef2aSThomas Huth }
1535fcf5ef2aSThomas Huth 
1536fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
1537fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc)
1538fcf5ef2aSThomas Huth {
1539fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1540fcf5ef2aSThomas Huth     int ctrl;
1541fcf5ef2aSThomas Huth 
1542fcf5ef2aSThomas Huth     LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
1543fcf5ef2aSThomas Huth             dc->type_b ? "" : "d", dc->imm);
1544fcf5ef2aSThomas Huth 
1545bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
1546fcf5ef2aSThomas Huth         return;
1547fcf5ef2aSThomas Huth     }
1548fcf5ef2aSThomas Huth 
1549cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
1550fcf5ef2aSThomas Huth     if (dc->type_b) {
1551cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(t_id, dc->imm & 0xf);
1552fcf5ef2aSThomas Huth         ctrl = dc->imm >> 10;
1553fcf5ef2aSThomas Huth     } else {
1554cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
1555fcf5ef2aSThomas Huth         ctrl = dc->imm >> 5;
1556fcf5ef2aSThomas Huth     }
1557fcf5ef2aSThomas Huth 
1558cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
1559fcf5ef2aSThomas Huth 
1560fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1561fcf5ef2aSThomas Huth         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1562fcf5ef2aSThomas Huth     } else {
1563fcf5ef2aSThomas Huth         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1564fcf5ef2aSThomas Huth     }
1565cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1566cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
1567fcf5ef2aSThomas Huth }
1568fcf5ef2aSThomas Huth 
1569fcf5ef2aSThomas Huth static struct decoder_info {
1570fcf5ef2aSThomas Huth     struct {
1571fcf5ef2aSThomas Huth         uint32_t bits;
1572fcf5ef2aSThomas Huth         uint32_t mask;
1573fcf5ef2aSThomas Huth     };
1574fcf5ef2aSThomas Huth     void (*dec)(DisasContext *dc);
1575fcf5ef2aSThomas Huth } decinfo[] = {
1576fcf5ef2aSThomas Huth     {DEC_ADD, dec_add},
1577fcf5ef2aSThomas Huth     {DEC_SUB, dec_sub},
1578fcf5ef2aSThomas Huth     {DEC_AND, dec_and},
1579fcf5ef2aSThomas Huth     {DEC_XOR, dec_xor},
1580fcf5ef2aSThomas Huth     {DEC_OR, dec_or},
1581fcf5ef2aSThomas Huth     {DEC_BIT, dec_bit},
1582fcf5ef2aSThomas Huth     {DEC_BARREL, dec_barrel},
1583fcf5ef2aSThomas Huth     {DEC_LD, dec_load},
1584fcf5ef2aSThomas Huth     {DEC_ST, dec_store},
1585fcf5ef2aSThomas Huth     {DEC_IMM, dec_imm},
1586fcf5ef2aSThomas Huth     {DEC_BR, dec_br},
1587fcf5ef2aSThomas Huth     {DEC_BCC, dec_bcc},
1588fcf5ef2aSThomas Huth     {DEC_RTS, dec_rts},
1589fcf5ef2aSThomas Huth     {DEC_FPU, dec_fpu},
1590fcf5ef2aSThomas Huth     {DEC_MUL, dec_mul},
1591fcf5ef2aSThomas Huth     {DEC_DIV, dec_div},
1592fcf5ef2aSThomas Huth     {DEC_MSR, dec_msr},
1593fcf5ef2aSThomas Huth     {DEC_STREAM, dec_stream},
1594fcf5ef2aSThomas Huth     {{0, 0}, dec_null}
1595fcf5ef2aSThomas Huth };
1596fcf5ef2aSThomas Huth 
1597fcf5ef2aSThomas Huth static inline void decode(DisasContext *dc, uint32_t ir)
1598fcf5ef2aSThomas Huth {
1599fcf5ef2aSThomas Huth     int i;
1600fcf5ef2aSThomas Huth 
1601fcf5ef2aSThomas Huth     dc->ir = ir;
1602fcf5ef2aSThomas Huth     LOG_DIS("%8.8x\t", dc->ir);
1603fcf5ef2aSThomas Huth 
1604462c2544SEdgar E. Iglesias     if (ir == 0) {
16051ee1bd28SEdgar E. Iglesias         trap_illegal(dc, dc->cpu->cfg.opcode_0_illegal);
1606462c2544SEdgar E. Iglesias         /* Don't decode nop/zero instructions any further.  */
1607462c2544SEdgar E. Iglesias         return;
1608462c2544SEdgar E. Iglesias     }
1609fcf5ef2aSThomas Huth 
1610fcf5ef2aSThomas Huth     /* bit 2 seems to indicate insn type.  */
1611fcf5ef2aSThomas Huth     dc->type_b = ir & (1 << 29);
1612fcf5ef2aSThomas Huth 
1613fcf5ef2aSThomas Huth     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1614fcf5ef2aSThomas Huth     dc->rd = EXTRACT_FIELD(ir, 21, 25);
1615fcf5ef2aSThomas Huth     dc->ra = EXTRACT_FIELD(ir, 16, 20);
1616fcf5ef2aSThomas Huth     dc->rb = EXTRACT_FIELD(ir, 11, 15);
1617fcf5ef2aSThomas Huth     dc->imm = EXTRACT_FIELD(ir, 0, 15);
1618fcf5ef2aSThomas Huth 
1619fcf5ef2aSThomas Huth     /* Large switch for all insns.  */
1620fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1621fcf5ef2aSThomas Huth         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1622fcf5ef2aSThomas Huth             decinfo[i].dec(dc);
1623fcf5ef2aSThomas Huth             break;
1624fcf5ef2aSThomas Huth         }
1625fcf5ef2aSThomas Huth     }
1626fcf5ef2aSThomas Huth }
1627fcf5ef2aSThomas Huth 
1628fcf5ef2aSThomas Huth /* generate intermediate code for basic block 'tb'.  */
16298b86d6d2SRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
1630fcf5ef2aSThomas Huth {
16319c489ea6SLluís Vilanova     CPUMBState *env = cs->env_ptr;
1632f5c7e93aSRichard Henderson     MicroBlazeCPU *cpu = env_archcpu(env);
1633fcf5ef2aSThomas Huth     uint32_t pc_start;
1634fcf5ef2aSThomas Huth     struct DisasContext ctx;
1635fcf5ef2aSThomas Huth     struct DisasContext *dc = &ctx;
163656371527SEmilio G. Cota     uint32_t page_start, org_flags;
1637cfeea807SEdgar E. Iglesias     uint32_t npc;
1638fcf5ef2aSThomas Huth     int num_insns;
1639fcf5ef2aSThomas Huth 
1640fcf5ef2aSThomas Huth     pc_start = tb->pc;
1641fcf5ef2aSThomas Huth     dc->cpu = cpu;
1642fcf5ef2aSThomas Huth     dc->tb = tb;
1643fcf5ef2aSThomas Huth     org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
1644fcf5ef2aSThomas Huth 
1645fcf5ef2aSThomas Huth     dc->is_jmp = DISAS_NEXT;
1646fcf5ef2aSThomas Huth     dc->jmp = 0;
1647fcf5ef2aSThomas Huth     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
1648fcf5ef2aSThomas Huth     if (dc->delayed_branch) {
1649fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
1650fcf5ef2aSThomas Huth     }
1651fcf5ef2aSThomas Huth     dc->pc = pc_start;
1652fcf5ef2aSThomas Huth     dc->singlestep_enabled = cs->singlestep_enabled;
1653fcf5ef2aSThomas Huth     dc->cpustate_changed = 0;
1654fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 0;
1655fcf5ef2aSThomas Huth 
1656fcf5ef2aSThomas Huth     if (pc_start & 3) {
1657fcf5ef2aSThomas Huth         cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
1658fcf5ef2aSThomas Huth     }
1659fcf5ef2aSThomas Huth 
166056371527SEmilio G. Cota     page_start = pc_start & TARGET_PAGE_MASK;
1661fcf5ef2aSThomas Huth     num_insns = 0;
1662fcf5ef2aSThomas Huth 
1663fcf5ef2aSThomas Huth     gen_tb_start(tb);
1664fcf5ef2aSThomas Huth     do
1665fcf5ef2aSThomas Huth     {
1666fcf5ef2aSThomas Huth         tcg_gen_insn_start(dc->pc);
1667fcf5ef2aSThomas Huth         num_insns++;
1668fcf5ef2aSThomas Huth 
1669fcf5ef2aSThomas Huth         if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
167041ba37c4SRichard Henderson             gen_raise_exception_sync(dc, EXCP_DEBUG);
1671fcf5ef2aSThomas Huth             /* The address covered by the breakpoint must be included in
1672fcf5ef2aSThomas Huth                [tb->pc, tb->pc + tb->size) in order to for it to be
1673fcf5ef2aSThomas Huth                properly cleared -- thus we increment the PC here so that
1674fcf5ef2aSThomas Huth                the logic setting tb->size below does the right thing.  */
1675fcf5ef2aSThomas Huth             dc->pc += 4;
1676fcf5ef2aSThomas Huth             break;
1677fcf5ef2aSThomas Huth         }
1678fcf5ef2aSThomas Huth 
1679fcf5ef2aSThomas Huth         /* Pretty disas.  */
1680fcf5ef2aSThomas Huth         LOG_DIS("%8.8x:\t", dc->pc);
1681fcf5ef2aSThomas Huth 
1682c5a49c63SEmilio G. Cota         if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
1683fcf5ef2aSThomas Huth             gen_io_start();
1684fcf5ef2aSThomas Huth         }
1685fcf5ef2aSThomas Huth 
1686fcf5ef2aSThomas Huth         dc->clear_imm = 1;
1687fcf5ef2aSThomas Huth         decode(dc, cpu_ldl_code(env, dc->pc));
1688fcf5ef2aSThomas Huth         if (dc->clear_imm)
1689fcf5ef2aSThomas Huth             dc->tb_flags &= ~IMM_FLAG;
1690fcf5ef2aSThomas Huth         dc->pc += 4;
1691fcf5ef2aSThomas Huth 
1692fcf5ef2aSThomas Huth         if (dc->delayed_branch) {
1693fcf5ef2aSThomas Huth             dc->delayed_branch--;
1694fcf5ef2aSThomas Huth             if (!dc->delayed_branch) {
1695fcf5ef2aSThomas Huth                 if (dc->tb_flags & DRTI_FLAG)
1696fcf5ef2aSThomas Huth                     do_rti(dc);
1697fcf5ef2aSThomas Huth                  if (dc->tb_flags & DRTB_FLAG)
1698fcf5ef2aSThomas Huth                     do_rtb(dc);
1699fcf5ef2aSThomas Huth                 if (dc->tb_flags & DRTE_FLAG)
1700fcf5ef2aSThomas Huth                     do_rte(dc);
1701fcf5ef2aSThomas Huth                 /* Clear the delay slot flag.  */
1702fcf5ef2aSThomas Huth                 dc->tb_flags &= ~D_FLAG;
1703fcf5ef2aSThomas Huth                 /* If it is a direct jump, try direct chaining.  */
1704fcf5ef2aSThomas Huth                 if (dc->jmp == JMP_INDIRECT) {
17050f96e96bSRichard Henderson                     TCGv_i32 tmp_pc = tcg_const_i32(dc->pc);
17060f96e96bSRichard Henderson                     eval_cond_jmp(dc, cpu_btarget, tmp_pc);
17070f96e96bSRichard Henderson                     tcg_temp_free_i32(tmp_pc);
1708fcf5ef2aSThomas Huth                     dc->is_jmp = DISAS_JUMP;
1709fcf5ef2aSThomas Huth                 } else if (dc->jmp == JMP_DIRECT) {
1710fcf5ef2aSThomas Huth                     t_sync_flags(dc);
1711fcf5ef2aSThomas Huth                     gen_goto_tb(dc, 0, dc->jmp_pc);
1712fcf5ef2aSThomas Huth                     dc->is_jmp = DISAS_TB_JUMP;
1713fcf5ef2aSThomas Huth                 } else if (dc->jmp == JMP_DIRECT_CC) {
1714fcf5ef2aSThomas Huth                     TCGLabel *l1 = gen_new_label();
1715fcf5ef2aSThomas Huth                     t_sync_flags(dc);
1716fcf5ef2aSThomas Huth                     /* Conditional jmp.  */
17179b158558SRichard Henderson                     tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1);
1718fcf5ef2aSThomas Huth                     gen_goto_tb(dc, 1, dc->pc);
1719fcf5ef2aSThomas Huth                     gen_set_label(l1);
1720fcf5ef2aSThomas Huth                     gen_goto_tb(dc, 0, dc->jmp_pc);
1721fcf5ef2aSThomas Huth 
1722fcf5ef2aSThomas Huth                     dc->is_jmp = DISAS_TB_JUMP;
1723fcf5ef2aSThomas Huth                 }
1724fcf5ef2aSThomas Huth                 break;
1725fcf5ef2aSThomas Huth             }
1726fcf5ef2aSThomas Huth         }
1727fcf5ef2aSThomas Huth         if (cs->singlestep_enabled) {
1728fcf5ef2aSThomas Huth             break;
1729fcf5ef2aSThomas Huth         }
1730fcf5ef2aSThomas Huth     } while (!dc->is_jmp && !dc->cpustate_changed
1731fcf5ef2aSThomas Huth              && !tcg_op_buf_full()
1732fcf5ef2aSThomas Huth              && !singlestep
173356371527SEmilio G. Cota              && (dc->pc - page_start < TARGET_PAGE_SIZE)
1734fcf5ef2aSThomas Huth              && num_insns < max_insns);
1735fcf5ef2aSThomas Huth 
1736fcf5ef2aSThomas Huth     npc = dc->pc;
1737fcf5ef2aSThomas Huth     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
1738fcf5ef2aSThomas Huth         if (dc->tb_flags & D_FLAG) {
1739fcf5ef2aSThomas Huth             dc->is_jmp = DISAS_UPDATE;
17400f96e96bSRichard Henderson             tcg_gen_movi_i32(cpu_pc, npc);
1741fcf5ef2aSThomas Huth             sync_jmpstate(dc);
1742fcf5ef2aSThomas Huth         } else
1743fcf5ef2aSThomas Huth             npc = dc->jmp_pc;
1744fcf5ef2aSThomas Huth     }
1745fcf5ef2aSThomas Huth 
1746fcf5ef2aSThomas Huth     /* Force an update if the per-tb cpu state has changed.  */
1747fcf5ef2aSThomas Huth     if (dc->is_jmp == DISAS_NEXT
1748fcf5ef2aSThomas Huth         && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
1749fcf5ef2aSThomas Huth         dc->is_jmp = DISAS_UPDATE;
17500f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, npc);
1751fcf5ef2aSThomas Huth     }
1752fcf5ef2aSThomas Huth     t_sync_flags(dc);
1753fcf5ef2aSThomas Huth 
1754fcf5ef2aSThomas Huth     if (unlikely(cs->singlestep_enabled)) {
1755fcf5ef2aSThomas Huth         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1756fcf5ef2aSThomas Huth 
1757fcf5ef2aSThomas Huth         if (dc->is_jmp != DISAS_JUMP) {
17580f96e96bSRichard Henderson             tcg_gen_movi_i32(cpu_pc, npc);
1759fcf5ef2aSThomas Huth         }
1760fcf5ef2aSThomas Huth         gen_helper_raise_exception(cpu_env, tmp);
1761fcf5ef2aSThomas Huth         tcg_temp_free_i32(tmp);
1762fcf5ef2aSThomas Huth     } else {
1763fcf5ef2aSThomas Huth         switch(dc->is_jmp) {
1764fcf5ef2aSThomas Huth             case DISAS_NEXT:
1765fcf5ef2aSThomas Huth                 gen_goto_tb(dc, 1, npc);
1766fcf5ef2aSThomas Huth                 break;
1767fcf5ef2aSThomas Huth             default:
1768fcf5ef2aSThomas Huth             case DISAS_JUMP:
1769fcf5ef2aSThomas Huth             case DISAS_UPDATE:
1770fcf5ef2aSThomas Huth                 /* indicate that the hash table must be used
1771fcf5ef2aSThomas Huth                    to find the next TB */
177207ea28b4SRichard Henderson                 tcg_gen_exit_tb(NULL, 0);
1773fcf5ef2aSThomas Huth                 break;
1774fcf5ef2aSThomas Huth             case DISAS_TB_JUMP:
1775fcf5ef2aSThomas Huth                 /* nothing more to generate */
1776fcf5ef2aSThomas Huth                 break;
1777fcf5ef2aSThomas Huth         }
1778fcf5ef2aSThomas Huth     }
1779fcf5ef2aSThomas Huth     gen_tb_end(tb, num_insns);
1780fcf5ef2aSThomas Huth 
1781fcf5ef2aSThomas Huth     tb->size = dc->pc - pc_start;
1782fcf5ef2aSThomas Huth     tb->icount = num_insns;
1783fcf5ef2aSThomas Huth 
1784fcf5ef2aSThomas Huth #ifdef DEBUG_DISAS
1785fcf5ef2aSThomas Huth #if !SIM_COMPAT
1786fcf5ef2aSThomas Huth     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
1787fcf5ef2aSThomas Huth         && qemu_log_in_addr_range(pc_start)) {
1788fc59d2d8SRobert Foley         FILE *logfile = qemu_log_lock();
1789fcf5ef2aSThomas Huth         qemu_log("--------------\n");
17901d48474dSRichard Henderson         log_target_disas(cs, pc_start, dc->pc - pc_start);
1791fc59d2d8SRobert Foley         qemu_log_unlock(logfile);
1792fcf5ef2aSThomas Huth     }
1793fcf5ef2aSThomas Huth #endif
1794fcf5ef2aSThomas Huth #endif
1795fcf5ef2aSThomas Huth     assert(!dc->abort_at_next_insn);
1796fcf5ef2aSThomas Huth }
1797fcf5ef2aSThomas Huth 
179890c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1799fcf5ef2aSThomas Huth {
1800fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1801fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
1802fcf5ef2aSThomas Huth     int i;
1803fcf5ef2aSThomas Huth 
180490c84c56SMarkus Armbruster     if (!env) {
1805fcf5ef2aSThomas Huth         return;
180690c84c56SMarkus Armbruster     }
1807fcf5ef2aSThomas Huth 
18080f96e96bSRichard Henderson     qemu_fprintf(f, "IN: PC=%x %s\n",
180976e8187dSRichard Henderson                  env->pc, lookup_symbol(env->pc));
18106efd5599SRichard Henderson     qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " "
1811eb2022b7SRichard Henderson                  "imm=%x iflags=%x fsr=%x rbtr=%x\n",
181278e9caf2SRichard Henderson                  env->msr, env->esr, env->ear,
1813eb2022b7SRichard Henderson                  env->imm, env->iflags, env->fsr, env->btr);
18140f96e96bSRichard Henderson     qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
1815fcf5ef2aSThomas Huth                  env->btaken, env->btarget,
18162e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18172e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18182e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18192e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18202ead1b18SJoe Komlodi     for (i = 0; i < 12; i++) {
18212ead1b18SJoe Komlodi         qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]);
18222ead1b18SJoe Komlodi         if ((i + 1) % 4 == 0) {
18232ead1b18SJoe Komlodi             qemu_fprintf(f, "\n");
18242ead1b18SJoe Komlodi         }
18252ead1b18SJoe Komlodi     }
1826fcf5ef2aSThomas Huth 
18272ead1b18SJoe Komlodi     /* Registers that aren't modeled are reported as 0 */
182839db007eSRichard Henderson     qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 "
1829af20a93aSRichard Henderson                     "rtlblo=0 rtlbhi=0\n", env->edr);
18302ead1b18SJoe Komlodi     qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr);
1831fcf5ef2aSThomas Huth     for (i = 0; i < 32; i++) {
183290c84c56SMarkus Armbruster         qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1833fcf5ef2aSThomas Huth         if ((i + 1) % 4 == 0)
183490c84c56SMarkus Armbruster             qemu_fprintf(f, "\n");
1835fcf5ef2aSThomas Huth         }
183690c84c56SMarkus Armbruster     qemu_fprintf(f, "\n\n");
1837fcf5ef2aSThomas Huth }
1838fcf5ef2aSThomas Huth 
1839fcf5ef2aSThomas Huth void mb_tcg_init(void)
1840fcf5ef2aSThomas Huth {
1841*480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1842*480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1843fcf5ef2aSThomas Huth 
1844*480d29a8SRichard Henderson     static const struct {
1845*480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1846*480d29a8SRichard Henderson     } i32s[] = {
1847*480d29a8SRichard Henderson         R(0),  R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1848*480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1849*480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1850*480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1851*480d29a8SRichard Henderson 
1852*480d29a8SRichard Henderson         SP(pc),
1853*480d29a8SRichard Henderson         SP(msr),
1854*480d29a8SRichard Henderson         SP(imm),
1855*480d29a8SRichard Henderson         SP(iflags),
1856*480d29a8SRichard Henderson         SP(btaken),
1857*480d29a8SRichard Henderson         SP(btarget),
1858*480d29a8SRichard Henderson         SP(res_val),
1859*480d29a8SRichard Henderson     };
1860*480d29a8SRichard Henderson 
1861*480d29a8SRichard Henderson #undef R
1862*480d29a8SRichard Henderson #undef SP
1863*480d29a8SRichard Henderson 
1864*480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1865*480d29a8SRichard Henderson         *i32s[i].var =
1866*480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1867fcf5ef2aSThomas Huth     }
186876e8187dSRichard Henderson 
1869*480d29a8SRichard Henderson     cpu_res_addr =
1870*480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1871fcf5ef2aSThomas Huth }
1872fcf5ef2aSThomas Huth 
1873fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1874fcf5ef2aSThomas Huth                           target_ulong *data)
1875fcf5ef2aSThomas Huth {
187676e8187dSRichard Henderson     env->pc = data[0];
1877fcf5ef2aSThomas Huth }
1878