xref: /openbmc/qemu/target/microblaze/translate.c (revision fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0)
1*fcf5ef2aSThomas Huth /*
2*fcf5ef2aSThomas Huth  *  Xilinx MicroBlaze emulation for qemu: main translation routines.
3*fcf5ef2aSThomas Huth  *
4*fcf5ef2aSThomas Huth  *  Copyright (c) 2009 Edgar E. Iglesias.
5*fcf5ef2aSThomas Huth  *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
6*fcf5ef2aSThomas Huth  *
7*fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8*fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9*fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
10*fcf5ef2aSThomas Huth  * version 2 of the License, or (at your option) any later version.
11*fcf5ef2aSThomas Huth  *
12*fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13*fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16*fcf5ef2aSThomas Huth  *
17*fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18*fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19*fcf5ef2aSThomas Huth  */
20*fcf5ef2aSThomas Huth 
21*fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22*fcf5ef2aSThomas Huth #include "cpu.h"
23*fcf5ef2aSThomas Huth #include "disas/disas.h"
24*fcf5ef2aSThomas Huth #include "exec/exec-all.h"
25*fcf5ef2aSThomas Huth #include "tcg-op.h"
26*fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
27*fcf5ef2aSThomas Huth #include "microblaze-decode.h"
28*fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h"
29*fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
30*fcf5ef2aSThomas Huth 
31*fcf5ef2aSThomas Huth #include "trace-tcg.h"
32*fcf5ef2aSThomas Huth #include "exec/log.h"
33*fcf5ef2aSThomas Huth 
34*fcf5ef2aSThomas Huth 
35*fcf5ef2aSThomas Huth #define SIM_COMPAT 0
36*fcf5ef2aSThomas Huth #define DISAS_GNU 1
37*fcf5ef2aSThomas Huth #define DISAS_MB 1
38*fcf5ef2aSThomas Huth #if DISAS_MB && !SIM_COMPAT
39*fcf5ef2aSThomas Huth #  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
40*fcf5ef2aSThomas Huth #else
41*fcf5ef2aSThomas Huth #  define LOG_DIS(...) do { } while (0)
42*fcf5ef2aSThomas Huth #endif
43*fcf5ef2aSThomas Huth 
44*fcf5ef2aSThomas Huth #define D(x)
45*fcf5ef2aSThomas Huth 
46*fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
47*fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
48*fcf5ef2aSThomas Huth 
49*fcf5ef2aSThomas Huth static TCGv env_debug;
50*fcf5ef2aSThomas Huth static TCGv_env cpu_env;
51*fcf5ef2aSThomas Huth static TCGv cpu_R[32];
52*fcf5ef2aSThomas Huth static TCGv cpu_SR[18];
53*fcf5ef2aSThomas Huth static TCGv env_imm;
54*fcf5ef2aSThomas Huth static TCGv env_btaken;
55*fcf5ef2aSThomas Huth static TCGv env_btarget;
56*fcf5ef2aSThomas Huth static TCGv env_iflags;
57*fcf5ef2aSThomas Huth static TCGv env_res_addr;
58*fcf5ef2aSThomas Huth static TCGv env_res_val;
59*fcf5ef2aSThomas Huth 
60*fcf5ef2aSThomas Huth #include "exec/gen-icount.h"
61*fcf5ef2aSThomas Huth 
62*fcf5ef2aSThomas Huth /* This is the state at translation time.  */
63*fcf5ef2aSThomas Huth typedef struct DisasContext {
64*fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu;
65*fcf5ef2aSThomas Huth     target_ulong pc;
66*fcf5ef2aSThomas Huth 
67*fcf5ef2aSThomas Huth     /* Decoder.  */
68*fcf5ef2aSThomas Huth     int type_b;
69*fcf5ef2aSThomas Huth     uint32_t ir;
70*fcf5ef2aSThomas Huth     uint8_t opcode;
71*fcf5ef2aSThomas Huth     uint8_t rd, ra, rb;
72*fcf5ef2aSThomas Huth     uint16_t imm;
73*fcf5ef2aSThomas Huth 
74*fcf5ef2aSThomas Huth     unsigned int cpustate_changed;
75*fcf5ef2aSThomas Huth     unsigned int delayed_branch;
76*fcf5ef2aSThomas Huth     unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
77*fcf5ef2aSThomas Huth     unsigned int clear_imm;
78*fcf5ef2aSThomas Huth     int is_jmp;
79*fcf5ef2aSThomas Huth 
80*fcf5ef2aSThomas Huth #define JMP_NOJMP     0
81*fcf5ef2aSThomas Huth #define JMP_DIRECT    1
82*fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2
83*fcf5ef2aSThomas Huth #define JMP_INDIRECT  3
84*fcf5ef2aSThomas Huth     unsigned int jmp;
85*fcf5ef2aSThomas Huth     uint32_t jmp_pc;
86*fcf5ef2aSThomas Huth 
87*fcf5ef2aSThomas Huth     int abort_at_next_insn;
88*fcf5ef2aSThomas Huth     int nr_nops;
89*fcf5ef2aSThomas Huth     struct TranslationBlock *tb;
90*fcf5ef2aSThomas Huth     int singlestep_enabled;
91*fcf5ef2aSThomas Huth } DisasContext;
92*fcf5ef2aSThomas Huth 
93*fcf5ef2aSThomas Huth static const char *regnames[] =
94*fcf5ef2aSThomas Huth {
95*fcf5ef2aSThomas Huth     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
96*fcf5ef2aSThomas Huth     "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
97*fcf5ef2aSThomas Huth     "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
98*fcf5ef2aSThomas Huth     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
99*fcf5ef2aSThomas Huth };
100*fcf5ef2aSThomas Huth 
101*fcf5ef2aSThomas Huth static const char *special_regnames[] =
102*fcf5ef2aSThomas Huth {
103*fcf5ef2aSThomas Huth     "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
104*fcf5ef2aSThomas Huth     "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
105*fcf5ef2aSThomas Huth     "sr16", "sr17", "sr18"
106*fcf5ef2aSThomas Huth };
107*fcf5ef2aSThomas Huth 
108*fcf5ef2aSThomas Huth static inline void t_sync_flags(DisasContext *dc)
109*fcf5ef2aSThomas Huth {
110*fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
111*fcf5ef2aSThomas Huth     if (dc->tb_flags != dc->synced_flags) {
112*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(env_iflags, dc->tb_flags);
113*fcf5ef2aSThomas Huth         dc->synced_flags = dc->tb_flags;
114*fcf5ef2aSThomas Huth     }
115*fcf5ef2aSThomas Huth }
116*fcf5ef2aSThomas Huth 
117*fcf5ef2aSThomas Huth static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
118*fcf5ef2aSThomas Huth {
119*fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
120*fcf5ef2aSThomas Huth 
121*fcf5ef2aSThomas Huth     t_sync_flags(dc);
122*fcf5ef2aSThomas Huth     tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
123*fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
124*fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
125*fcf5ef2aSThomas Huth     dc->is_jmp = DISAS_UPDATE;
126*fcf5ef2aSThomas Huth }
127*fcf5ef2aSThomas Huth 
128*fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
129*fcf5ef2aSThomas Huth {
130*fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
131*fcf5ef2aSThomas Huth     return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
132*fcf5ef2aSThomas Huth #else
133*fcf5ef2aSThomas Huth     return true;
134*fcf5ef2aSThomas Huth #endif
135*fcf5ef2aSThomas Huth }
136*fcf5ef2aSThomas Huth 
137*fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
138*fcf5ef2aSThomas Huth {
139*fcf5ef2aSThomas Huth     if (use_goto_tb(dc, dest)) {
140*fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
141*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
142*fcf5ef2aSThomas Huth         tcg_gen_exit_tb((uintptr_t)dc->tb + n);
143*fcf5ef2aSThomas Huth     } else {
144*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
145*fcf5ef2aSThomas Huth         tcg_gen_exit_tb(0);
146*fcf5ef2aSThomas Huth     }
147*fcf5ef2aSThomas Huth }
148*fcf5ef2aSThomas Huth 
149*fcf5ef2aSThomas Huth static void read_carry(DisasContext *dc, TCGv d)
150*fcf5ef2aSThomas Huth {
151*fcf5ef2aSThomas Huth     tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
152*fcf5ef2aSThomas Huth }
153*fcf5ef2aSThomas Huth 
154*fcf5ef2aSThomas Huth /*
155*fcf5ef2aSThomas Huth  * write_carry sets the carry bits in MSR based on bit 0 of v.
156*fcf5ef2aSThomas Huth  * v[31:1] are ignored.
157*fcf5ef2aSThomas Huth  */
158*fcf5ef2aSThomas Huth static void write_carry(DisasContext *dc, TCGv v)
159*fcf5ef2aSThomas Huth {
160*fcf5ef2aSThomas Huth     TCGv t0 = tcg_temp_new();
161*fcf5ef2aSThomas Huth     tcg_gen_shli_tl(t0, v, 31);
162*fcf5ef2aSThomas Huth     tcg_gen_sari_tl(t0, t0, 31);
163*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
164*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
165*fcf5ef2aSThomas Huth                     ~(MSR_C | MSR_CC));
166*fcf5ef2aSThomas Huth     tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
167*fcf5ef2aSThomas Huth     tcg_temp_free(t0);
168*fcf5ef2aSThomas Huth }
169*fcf5ef2aSThomas Huth 
170*fcf5ef2aSThomas Huth static void write_carryi(DisasContext *dc, bool carry)
171*fcf5ef2aSThomas Huth {
172*fcf5ef2aSThomas Huth     TCGv t0 = tcg_temp_new();
173*fcf5ef2aSThomas Huth     tcg_gen_movi_tl(t0, carry);
174*fcf5ef2aSThomas Huth     write_carry(dc, t0);
175*fcf5ef2aSThomas Huth     tcg_temp_free(t0);
176*fcf5ef2aSThomas Huth }
177*fcf5ef2aSThomas Huth 
178*fcf5ef2aSThomas Huth /* True if ALU operand b is a small immediate that may deserve
179*fcf5ef2aSThomas Huth    faster treatment.  */
180*fcf5ef2aSThomas Huth static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
181*fcf5ef2aSThomas Huth {
182*fcf5ef2aSThomas Huth     /* Immediate insn without the imm prefix ?  */
183*fcf5ef2aSThomas Huth     return dc->type_b && !(dc->tb_flags & IMM_FLAG);
184*fcf5ef2aSThomas Huth }
185*fcf5ef2aSThomas Huth 
186*fcf5ef2aSThomas Huth static inline TCGv *dec_alu_op_b(DisasContext *dc)
187*fcf5ef2aSThomas Huth {
188*fcf5ef2aSThomas Huth     if (dc->type_b) {
189*fcf5ef2aSThomas Huth         if (dc->tb_flags & IMM_FLAG)
190*fcf5ef2aSThomas Huth             tcg_gen_ori_tl(env_imm, env_imm, dc->imm);
191*fcf5ef2aSThomas Huth         else
192*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(env_imm, (int32_t)((int16_t)dc->imm));
193*fcf5ef2aSThomas Huth         return &env_imm;
194*fcf5ef2aSThomas Huth     } else
195*fcf5ef2aSThomas Huth         return &cpu_R[dc->rb];
196*fcf5ef2aSThomas Huth }
197*fcf5ef2aSThomas Huth 
198*fcf5ef2aSThomas Huth static void dec_add(DisasContext *dc)
199*fcf5ef2aSThomas Huth {
200*fcf5ef2aSThomas Huth     unsigned int k, c;
201*fcf5ef2aSThomas Huth     TCGv cf;
202*fcf5ef2aSThomas Huth 
203*fcf5ef2aSThomas Huth     k = dc->opcode & 4;
204*fcf5ef2aSThomas Huth     c = dc->opcode & 2;
205*fcf5ef2aSThomas Huth 
206*fcf5ef2aSThomas Huth     LOG_DIS("add%s%s%s r%d r%d r%d\n",
207*fcf5ef2aSThomas Huth             dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "",
208*fcf5ef2aSThomas Huth             dc->rd, dc->ra, dc->rb);
209*fcf5ef2aSThomas Huth 
210*fcf5ef2aSThomas Huth     /* Take care of the easy cases first.  */
211*fcf5ef2aSThomas Huth     if (k) {
212*fcf5ef2aSThomas Huth         /* k - keep carry, no need to update MSR.  */
213*fcf5ef2aSThomas Huth         /* If rd == r0, it's a nop.  */
214*fcf5ef2aSThomas Huth         if (dc->rd) {
215*fcf5ef2aSThomas Huth             tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
216*fcf5ef2aSThomas Huth 
217*fcf5ef2aSThomas Huth             if (c) {
218*fcf5ef2aSThomas Huth                 /* c - Add carry into the result.  */
219*fcf5ef2aSThomas Huth                 cf = tcg_temp_new();
220*fcf5ef2aSThomas Huth 
221*fcf5ef2aSThomas Huth                 read_carry(dc, cf);
222*fcf5ef2aSThomas Huth                 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
223*fcf5ef2aSThomas Huth                 tcg_temp_free(cf);
224*fcf5ef2aSThomas Huth             }
225*fcf5ef2aSThomas Huth         }
226*fcf5ef2aSThomas Huth         return;
227*fcf5ef2aSThomas Huth     }
228*fcf5ef2aSThomas Huth 
229*fcf5ef2aSThomas Huth     /* From now on, we can assume k is zero.  So we need to update MSR.  */
230*fcf5ef2aSThomas Huth     /* Extract carry.  */
231*fcf5ef2aSThomas Huth     cf = tcg_temp_new();
232*fcf5ef2aSThomas Huth     if (c) {
233*fcf5ef2aSThomas Huth         read_carry(dc, cf);
234*fcf5ef2aSThomas Huth     } else {
235*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cf, 0);
236*fcf5ef2aSThomas Huth     }
237*fcf5ef2aSThomas Huth 
238*fcf5ef2aSThomas Huth     if (dc->rd) {
239*fcf5ef2aSThomas Huth         TCGv ncf = tcg_temp_new();
240*fcf5ef2aSThomas Huth         gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
241*fcf5ef2aSThomas Huth         tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
242*fcf5ef2aSThomas Huth         tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
243*fcf5ef2aSThomas Huth         write_carry(dc, ncf);
244*fcf5ef2aSThomas Huth         tcg_temp_free(ncf);
245*fcf5ef2aSThomas Huth     } else {
246*fcf5ef2aSThomas Huth         gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
247*fcf5ef2aSThomas Huth         write_carry(dc, cf);
248*fcf5ef2aSThomas Huth     }
249*fcf5ef2aSThomas Huth     tcg_temp_free(cf);
250*fcf5ef2aSThomas Huth }
251*fcf5ef2aSThomas Huth 
252*fcf5ef2aSThomas Huth static void dec_sub(DisasContext *dc)
253*fcf5ef2aSThomas Huth {
254*fcf5ef2aSThomas Huth     unsigned int u, cmp, k, c;
255*fcf5ef2aSThomas Huth     TCGv cf, na;
256*fcf5ef2aSThomas Huth 
257*fcf5ef2aSThomas Huth     u = dc->imm & 2;
258*fcf5ef2aSThomas Huth     k = dc->opcode & 4;
259*fcf5ef2aSThomas Huth     c = dc->opcode & 2;
260*fcf5ef2aSThomas Huth     cmp = (dc->imm & 1) && (!dc->type_b) && k;
261*fcf5ef2aSThomas Huth 
262*fcf5ef2aSThomas Huth     if (cmp) {
263*fcf5ef2aSThomas Huth         LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir);
264*fcf5ef2aSThomas Huth         if (dc->rd) {
265*fcf5ef2aSThomas Huth             if (u)
266*fcf5ef2aSThomas Huth                 gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
267*fcf5ef2aSThomas Huth             else
268*fcf5ef2aSThomas Huth                 gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
269*fcf5ef2aSThomas Huth         }
270*fcf5ef2aSThomas Huth         return;
271*fcf5ef2aSThomas Huth     }
272*fcf5ef2aSThomas Huth 
273*fcf5ef2aSThomas Huth     LOG_DIS("sub%s%s r%d, r%d r%d\n",
274*fcf5ef2aSThomas Huth              k ? "k" : "",  c ? "c" : "", dc->rd, dc->ra, dc->rb);
275*fcf5ef2aSThomas Huth 
276*fcf5ef2aSThomas Huth     /* Take care of the easy cases first.  */
277*fcf5ef2aSThomas Huth     if (k) {
278*fcf5ef2aSThomas Huth         /* k - keep carry, no need to update MSR.  */
279*fcf5ef2aSThomas Huth         /* If rd == r0, it's a nop.  */
280*fcf5ef2aSThomas Huth         if (dc->rd) {
281*fcf5ef2aSThomas Huth             tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
282*fcf5ef2aSThomas Huth 
283*fcf5ef2aSThomas Huth             if (c) {
284*fcf5ef2aSThomas Huth                 /* c - Add carry into the result.  */
285*fcf5ef2aSThomas Huth                 cf = tcg_temp_new();
286*fcf5ef2aSThomas Huth 
287*fcf5ef2aSThomas Huth                 read_carry(dc, cf);
288*fcf5ef2aSThomas Huth                 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
289*fcf5ef2aSThomas Huth                 tcg_temp_free(cf);
290*fcf5ef2aSThomas Huth             }
291*fcf5ef2aSThomas Huth         }
292*fcf5ef2aSThomas Huth         return;
293*fcf5ef2aSThomas Huth     }
294*fcf5ef2aSThomas Huth 
295*fcf5ef2aSThomas Huth     /* From now on, we can assume k is zero.  So we need to update MSR.  */
296*fcf5ef2aSThomas Huth     /* Extract carry. And complement a into na.  */
297*fcf5ef2aSThomas Huth     cf = tcg_temp_new();
298*fcf5ef2aSThomas Huth     na = tcg_temp_new();
299*fcf5ef2aSThomas Huth     if (c) {
300*fcf5ef2aSThomas Huth         read_carry(dc, cf);
301*fcf5ef2aSThomas Huth     } else {
302*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cf, 1);
303*fcf5ef2aSThomas Huth     }
304*fcf5ef2aSThomas Huth 
305*fcf5ef2aSThomas Huth     /* d = b + ~a + c. carry defaults to 1.  */
306*fcf5ef2aSThomas Huth     tcg_gen_not_tl(na, cpu_R[dc->ra]);
307*fcf5ef2aSThomas Huth 
308*fcf5ef2aSThomas Huth     if (dc->rd) {
309*fcf5ef2aSThomas Huth         TCGv ncf = tcg_temp_new();
310*fcf5ef2aSThomas Huth         gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
311*fcf5ef2aSThomas Huth         tcg_gen_add_tl(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
312*fcf5ef2aSThomas Huth         tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
313*fcf5ef2aSThomas Huth         write_carry(dc, ncf);
314*fcf5ef2aSThomas Huth         tcg_temp_free(ncf);
315*fcf5ef2aSThomas Huth     } else {
316*fcf5ef2aSThomas Huth         gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
317*fcf5ef2aSThomas Huth         write_carry(dc, cf);
318*fcf5ef2aSThomas Huth     }
319*fcf5ef2aSThomas Huth     tcg_temp_free(cf);
320*fcf5ef2aSThomas Huth     tcg_temp_free(na);
321*fcf5ef2aSThomas Huth }
322*fcf5ef2aSThomas Huth 
323*fcf5ef2aSThomas Huth static void dec_pattern(DisasContext *dc)
324*fcf5ef2aSThomas Huth {
325*fcf5ef2aSThomas Huth     unsigned int mode;
326*fcf5ef2aSThomas Huth 
327*fcf5ef2aSThomas Huth     if ((dc->tb_flags & MSR_EE_FLAG)
328*fcf5ef2aSThomas Huth           && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
329*fcf5ef2aSThomas Huth           && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
330*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
331*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
332*fcf5ef2aSThomas Huth     }
333*fcf5ef2aSThomas Huth 
334*fcf5ef2aSThomas Huth     mode = dc->opcode & 3;
335*fcf5ef2aSThomas Huth     switch (mode) {
336*fcf5ef2aSThomas Huth         case 0:
337*fcf5ef2aSThomas Huth             /* pcmpbf.  */
338*fcf5ef2aSThomas Huth             LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
339*fcf5ef2aSThomas Huth             if (dc->rd)
340*fcf5ef2aSThomas Huth                 gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
341*fcf5ef2aSThomas Huth             break;
342*fcf5ef2aSThomas Huth         case 2:
343*fcf5ef2aSThomas Huth             LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
344*fcf5ef2aSThomas Huth             if (dc->rd) {
345*fcf5ef2aSThomas Huth                 tcg_gen_setcond_tl(TCG_COND_EQ, cpu_R[dc->rd],
346*fcf5ef2aSThomas Huth                                    cpu_R[dc->ra], cpu_R[dc->rb]);
347*fcf5ef2aSThomas Huth             }
348*fcf5ef2aSThomas Huth             break;
349*fcf5ef2aSThomas Huth         case 3:
350*fcf5ef2aSThomas Huth             LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
351*fcf5ef2aSThomas Huth             if (dc->rd) {
352*fcf5ef2aSThomas Huth                 tcg_gen_setcond_tl(TCG_COND_NE, cpu_R[dc->rd],
353*fcf5ef2aSThomas Huth                                    cpu_R[dc->ra], cpu_R[dc->rb]);
354*fcf5ef2aSThomas Huth             }
355*fcf5ef2aSThomas Huth             break;
356*fcf5ef2aSThomas Huth         default:
357*fcf5ef2aSThomas Huth             cpu_abort(CPU(dc->cpu),
358*fcf5ef2aSThomas Huth                       "unsupported pattern insn opcode=%x\n", dc->opcode);
359*fcf5ef2aSThomas Huth             break;
360*fcf5ef2aSThomas Huth     }
361*fcf5ef2aSThomas Huth }
362*fcf5ef2aSThomas Huth 
363*fcf5ef2aSThomas Huth static void dec_and(DisasContext *dc)
364*fcf5ef2aSThomas Huth {
365*fcf5ef2aSThomas Huth     unsigned int not;
366*fcf5ef2aSThomas Huth 
367*fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
368*fcf5ef2aSThomas Huth         dec_pattern(dc);
369*fcf5ef2aSThomas Huth         return;
370*fcf5ef2aSThomas Huth     }
371*fcf5ef2aSThomas Huth 
372*fcf5ef2aSThomas Huth     not = dc->opcode & (1 << 1);
373*fcf5ef2aSThomas Huth     LOG_DIS("and%s\n", not ? "n" : "");
374*fcf5ef2aSThomas Huth 
375*fcf5ef2aSThomas Huth     if (!dc->rd)
376*fcf5ef2aSThomas Huth         return;
377*fcf5ef2aSThomas Huth 
378*fcf5ef2aSThomas Huth     if (not) {
379*fcf5ef2aSThomas Huth         tcg_gen_andc_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
380*fcf5ef2aSThomas Huth     } else
381*fcf5ef2aSThomas Huth         tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
382*fcf5ef2aSThomas Huth }
383*fcf5ef2aSThomas Huth 
384*fcf5ef2aSThomas Huth static void dec_or(DisasContext *dc)
385*fcf5ef2aSThomas Huth {
386*fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
387*fcf5ef2aSThomas Huth         dec_pattern(dc);
388*fcf5ef2aSThomas Huth         return;
389*fcf5ef2aSThomas Huth     }
390*fcf5ef2aSThomas Huth 
391*fcf5ef2aSThomas Huth     LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm);
392*fcf5ef2aSThomas Huth     if (dc->rd)
393*fcf5ef2aSThomas Huth         tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
394*fcf5ef2aSThomas Huth }
395*fcf5ef2aSThomas Huth 
396*fcf5ef2aSThomas Huth static void dec_xor(DisasContext *dc)
397*fcf5ef2aSThomas Huth {
398*fcf5ef2aSThomas Huth     if (!dc->type_b && (dc->imm & (1 << 10))) {
399*fcf5ef2aSThomas Huth         dec_pattern(dc);
400*fcf5ef2aSThomas Huth         return;
401*fcf5ef2aSThomas Huth     }
402*fcf5ef2aSThomas Huth 
403*fcf5ef2aSThomas Huth     LOG_DIS("xor r%d\n", dc->rd);
404*fcf5ef2aSThomas Huth     if (dc->rd)
405*fcf5ef2aSThomas Huth         tcg_gen_xor_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
406*fcf5ef2aSThomas Huth }
407*fcf5ef2aSThomas Huth 
408*fcf5ef2aSThomas Huth static inline void msr_read(DisasContext *dc, TCGv d)
409*fcf5ef2aSThomas Huth {
410*fcf5ef2aSThomas Huth     tcg_gen_mov_tl(d, cpu_SR[SR_MSR]);
411*fcf5ef2aSThomas Huth }
412*fcf5ef2aSThomas Huth 
413*fcf5ef2aSThomas Huth static inline void msr_write(DisasContext *dc, TCGv v)
414*fcf5ef2aSThomas Huth {
415*fcf5ef2aSThomas Huth     TCGv t;
416*fcf5ef2aSThomas Huth 
417*fcf5ef2aSThomas Huth     t = tcg_temp_new();
418*fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
419*fcf5ef2aSThomas Huth     /* PVR bit is not writable.  */
420*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t, v, ~MSR_PVR);
421*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
422*fcf5ef2aSThomas Huth     tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], v);
423*fcf5ef2aSThomas Huth     tcg_temp_free(t);
424*fcf5ef2aSThomas Huth }
425*fcf5ef2aSThomas Huth 
426*fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc)
427*fcf5ef2aSThomas Huth {
428*fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
429*fcf5ef2aSThomas Huth     TCGv t0, t1;
430*fcf5ef2aSThomas Huth     unsigned int sr, to, rn;
431*fcf5ef2aSThomas Huth     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
432*fcf5ef2aSThomas Huth 
433*fcf5ef2aSThomas Huth     sr = dc->imm & ((1 << 14) - 1);
434*fcf5ef2aSThomas Huth     to = dc->imm & (1 << 14);
435*fcf5ef2aSThomas Huth     dc->type_b = 1;
436*fcf5ef2aSThomas Huth     if (to)
437*fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
438*fcf5ef2aSThomas Huth 
439*fcf5ef2aSThomas Huth     /* msrclr and msrset.  */
440*fcf5ef2aSThomas Huth     if (!(dc->imm & (1 << 15))) {
441*fcf5ef2aSThomas Huth         unsigned int clr = dc->ir & (1 << 16);
442*fcf5ef2aSThomas Huth 
443*fcf5ef2aSThomas Huth         LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set",
444*fcf5ef2aSThomas Huth                 dc->rd, dc->imm);
445*fcf5ef2aSThomas Huth 
446*fcf5ef2aSThomas Huth         if (!(dc->cpu->env.pvr.regs[2] & PVR2_USE_MSR_INSTR)) {
447*fcf5ef2aSThomas Huth             /* nop??? */
448*fcf5ef2aSThomas Huth             return;
449*fcf5ef2aSThomas Huth         }
450*fcf5ef2aSThomas Huth 
451*fcf5ef2aSThomas Huth         if ((dc->tb_flags & MSR_EE_FLAG)
452*fcf5ef2aSThomas Huth             && mem_index == MMU_USER_IDX && (dc->imm != 4 && dc->imm != 0)) {
453*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
454*fcf5ef2aSThomas Huth             t_gen_raise_exception(dc, EXCP_HW_EXCP);
455*fcf5ef2aSThomas Huth             return;
456*fcf5ef2aSThomas Huth         }
457*fcf5ef2aSThomas Huth 
458*fcf5ef2aSThomas Huth         if (dc->rd)
459*fcf5ef2aSThomas Huth             msr_read(dc, cpu_R[dc->rd]);
460*fcf5ef2aSThomas Huth 
461*fcf5ef2aSThomas Huth         t0 = tcg_temp_new();
462*fcf5ef2aSThomas Huth         t1 = tcg_temp_new();
463*fcf5ef2aSThomas Huth         msr_read(dc, t0);
464*fcf5ef2aSThomas Huth         tcg_gen_mov_tl(t1, *(dec_alu_op_b(dc)));
465*fcf5ef2aSThomas Huth 
466*fcf5ef2aSThomas Huth         if (clr) {
467*fcf5ef2aSThomas Huth             tcg_gen_not_tl(t1, t1);
468*fcf5ef2aSThomas Huth             tcg_gen_and_tl(t0, t0, t1);
469*fcf5ef2aSThomas Huth         } else
470*fcf5ef2aSThomas Huth             tcg_gen_or_tl(t0, t0, t1);
471*fcf5ef2aSThomas Huth         msr_write(dc, t0);
472*fcf5ef2aSThomas Huth         tcg_temp_free(t0);
473*fcf5ef2aSThomas Huth         tcg_temp_free(t1);
474*fcf5ef2aSThomas Huth 	tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4);
475*fcf5ef2aSThomas Huth         dc->is_jmp = DISAS_UPDATE;
476*fcf5ef2aSThomas Huth         return;
477*fcf5ef2aSThomas Huth     }
478*fcf5ef2aSThomas Huth 
479*fcf5ef2aSThomas Huth     if (to) {
480*fcf5ef2aSThomas Huth         if ((dc->tb_flags & MSR_EE_FLAG)
481*fcf5ef2aSThomas Huth              && mem_index == MMU_USER_IDX) {
482*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
483*fcf5ef2aSThomas Huth             t_gen_raise_exception(dc, EXCP_HW_EXCP);
484*fcf5ef2aSThomas Huth             return;
485*fcf5ef2aSThomas Huth         }
486*fcf5ef2aSThomas Huth     }
487*fcf5ef2aSThomas Huth 
488*fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
489*fcf5ef2aSThomas Huth     /* Catch read/writes to the mmu block.  */
490*fcf5ef2aSThomas Huth     if ((sr & ~0xff) == 0x1000) {
491*fcf5ef2aSThomas Huth         sr &= 7;
492*fcf5ef2aSThomas Huth         LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
493*fcf5ef2aSThomas Huth         if (to)
494*fcf5ef2aSThomas Huth             gen_helper_mmu_write(cpu_env, tcg_const_tl(sr), cpu_R[dc->ra]);
495*fcf5ef2aSThomas Huth         else
496*fcf5ef2aSThomas Huth             gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tcg_const_tl(sr));
497*fcf5ef2aSThomas Huth         return;
498*fcf5ef2aSThomas Huth     }
499*fcf5ef2aSThomas Huth #endif
500*fcf5ef2aSThomas Huth 
501*fcf5ef2aSThomas Huth     if (to) {
502*fcf5ef2aSThomas Huth         LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
503*fcf5ef2aSThomas Huth         switch (sr) {
504*fcf5ef2aSThomas Huth             case 0:
505*fcf5ef2aSThomas Huth                 break;
506*fcf5ef2aSThomas Huth             case 1:
507*fcf5ef2aSThomas Huth                 msr_write(dc, cpu_R[dc->ra]);
508*fcf5ef2aSThomas Huth                 break;
509*fcf5ef2aSThomas Huth             case 0x3:
510*fcf5ef2aSThomas Huth                 tcg_gen_mov_tl(cpu_SR[SR_EAR], cpu_R[dc->ra]);
511*fcf5ef2aSThomas Huth                 break;
512*fcf5ef2aSThomas Huth             case 0x5:
513*fcf5ef2aSThomas Huth                 tcg_gen_mov_tl(cpu_SR[SR_ESR], cpu_R[dc->ra]);
514*fcf5ef2aSThomas Huth                 break;
515*fcf5ef2aSThomas Huth             case 0x7:
516*fcf5ef2aSThomas Huth                 tcg_gen_andi_tl(cpu_SR[SR_FSR], cpu_R[dc->ra], 31);
517*fcf5ef2aSThomas Huth                 break;
518*fcf5ef2aSThomas Huth             case 0x800:
519*fcf5ef2aSThomas Huth                 tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, slr));
520*fcf5ef2aSThomas Huth                 break;
521*fcf5ef2aSThomas Huth             case 0x802:
522*fcf5ef2aSThomas Huth                 tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, shr));
523*fcf5ef2aSThomas Huth                 break;
524*fcf5ef2aSThomas Huth             default:
525*fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
526*fcf5ef2aSThomas Huth                 break;
527*fcf5ef2aSThomas Huth         }
528*fcf5ef2aSThomas Huth     } else {
529*fcf5ef2aSThomas Huth         LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm);
530*fcf5ef2aSThomas Huth 
531*fcf5ef2aSThomas Huth         switch (sr) {
532*fcf5ef2aSThomas Huth             case 0:
533*fcf5ef2aSThomas Huth                 tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
534*fcf5ef2aSThomas Huth                 break;
535*fcf5ef2aSThomas Huth             case 1:
536*fcf5ef2aSThomas Huth                 msr_read(dc, cpu_R[dc->rd]);
537*fcf5ef2aSThomas Huth                 break;
538*fcf5ef2aSThomas Huth             case 0x3:
539*fcf5ef2aSThomas Huth                 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_EAR]);
540*fcf5ef2aSThomas Huth                 break;
541*fcf5ef2aSThomas Huth             case 0x5:
542*fcf5ef2aSThomas Huth                 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_ESR]);
543*fcf5ef2aSThomas Huth                 break;
544*fcf5ef2aSThomas Huth              case 0x7:
545*fcf5ef2aSThomas Huth                 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_FSR]);
546*fcf5ef2aSThomas Huth                 break;
547*fcf5ef2aSThomas Huth             case 0xb:
548*fcf5ef2aSThomas Huth                 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_BTR]);
549*fcf5ef2aSThomas Huth                 break;
550*fcf5ef2aSThomas Huth             case 0x800:
551*fcf5ef2aSThomas Huth                 tcg_gen_ld_tl(cpu_R[dc->rd], cpu_env, offsetof(CPUMBState, slr));
552*fcf5ef2aSThomas Huth                 break;
553*fcf5ef2aSThomas Huth             case 0x802:
554*fcf5ef2aSThomas Huth                 tcg_gen_ld_tl(cpu_R[dc->rd], cpu_env, offsetof(CPUMBState, shr));
555*fcf5ef2aSThomas Huth                 break;
556*fcf5ef2aSThomas Huth             case 0x2000:
557*fcf5ef2aSThomas Huth             case 0x2001:
558*fcf5ef2aSThomas Huth             case 0x2002:
559*fcf5ef2aSThomas Huth             case 0x2003:
560*fcf5ef2aSThomas Huth             case 0x2004:
561*fcf5ef2aSThomas Huth             case 0x2005:
562*fcf5ef2aSThomas Huth             case 0x2006:
563*fcf5ef2aSThomas Huth             case 0x2007:
564*fcf5ef2aSThomas Huth             case 0x2008:
565*fcf5ef2aSThomas Huth             case 0x2009:
566*fcf5ef2aSThomas Huth             case 0x200a:
567*fcf5ef2aSThomas Huth             case 0x200b:
568*fcf5ef2aSThomas Huth             case 0x200c:
569*fcf5ef2aSThomas Huth                 rn = sr & 0xf;
570*fcf5ef2aSThomas Huth                 tcg_gen_ld_tl(cpu_R[dc->rd],
571*fcf5ef2aSThomas Huth                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
572*fcf5ef2aSThomas Huth                 break;
573*fcf5ef2aSThomas Huth             default:
574*fcf5ef2aSThomas Huth                 cpu_abort(cs, "unknown mfs reg %x\n", sr);
575*fcf5ef2aSThomas Huth                 break;
576*fcf5ef2aSThomas Huth         }
577*fcf5ef2aSThomas Huth     }
578*fcf5ef2aSThomas Huth 
579*fcf5ef2aSThomas Huth     if (dc->rd == 0) {
580*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_R[0], 0);
581*fcf5ef2aSThomas Huth     }
582*fcf5ef2aSThomas Huth }
583*fcf5ef2aSThomas Huth 
584*fcf5ef2aSThomas Huth /* Multiplier unit.  */
585*fcf5ef2aSThomas Huth static void dec_mul(DisasContext *dc)
586*fcf5ef2aSThomas Huth {
587*fcf5ef2aSThomas Huth     TCGv tmp;
588*fcf5ef2aSThomas Huth     unsigned int subcode;
589*fcf5ef2aSThomas Huth 
590*fcf5ef2aSThomas Huth     if ((dc->tb_flags & MSR_EE_FLAG)
591*fcf5ef2aSThomas Huth          && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
592*fcf5ef2aSThomas Huth          && !(dc->cpu->env.pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) {
593*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
594*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
595*fcf5ef2aSThomas Huth         return;
596*fcf5ef2aSThomas Huth     }
597*fcf5ef2aSThomas Huth 
598*fcf5ef2aSThomas Huth     subcode = dc->imm & 3;
599*fcf5ef2aSThomas Huth 
600*fcf5ef2aSThomas Huth     if (dc->type_b) {
601*fcf5ef2aSThomas Huth         LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm);
602*fcf5ef2aSThomas Huth         tcg_gen_mul_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
603*fcf5ef2aSThomas Huth         return;
604*fcf5ef2aSThomas Huth     }
605*fcf5ef2aSThomas Huth 
606*fcf5ef2aSThomas Huth     /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2.  */
607*fcf5ef2aSThomas Huth     if (subcode >= 1 && subcode <= 3
608*fcf5ef2aSThomas Huth         && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_MUL64_MASK))) {
609*fcf5ef2aSThomas Huth         /* nop??? */
610*fcf5ef2aSThomas Huth     }
611*fcf5ef2aSThomas Huth 
612*fcf5ef2aSThomas Huth     tmp = tcg_temp_new();
613*fcf5ef2aSThomas Huth     switch (subcode) {
614*fcf5ef2aSThomas Huth         case 0:
615*fcf5ef2aSThomas Huth             LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
616*fcf5ef2aSThomas Huth             tcg_gen_mul_tl(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
617*fcf5ef2aSThomas Huth             break;
618*fcf5ef2aSThomas Huth         case 1:
619*fcf5ef2aSThomas Huth             LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
620*fcf5ef2aSThomas Huth             tcg_gen_muls2_tl(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
621*fcf5ef2aSThomas Huth             break;
622*fcf5ef2aSThomas Huth         case 2:
623*fcf5ef2aSThomas Huth             LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
624*fcf5ef2aSThomas Huth             tcg_gen_mulsu2_tl(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
625*fcf5ef2aSThomas Huth             break;
626*fcf5ef2aSThomas Huth         case 3:
627*fcf5ef2aSThomas Huth             LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
628*fcf5ef2aSThomas Huth             tcg_gen_mulu2_tl(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
629*fcf5ef2aSThomas Huth             break;
630*fcf5ef2aSThomas Huth         default:
631*fcf5ef2aSThomas Huth             cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode);
632*fcf5ef2aSThomas Huth             break;
633*fcf5ef2aSThomas Huth     }
634*fcf5ef2aSThomas Huth     tcg_temp_free(tmp);
635*fcf5ef2aSThomas Huth }
636*fcf5ef2aSThomas Huth 
637*fcf5ef2aSThomas Huth /* Div unit.  */
638*fcf5ef2aSThomas Huth static void dec_div(DisasContext *dc)
639*fcf5ef2aSThomas Huth {
640*fcf5ef2aSThomas Huth     unsigned int u;
641*fcf5ef2aSThomas Huth 
642*fcf5ef2aSThomas Huth     u = dc->imm & 2;
643*fcf5ef2aSThomas Huth     LOG_DIS("div\n");
644*fcf5ef2aSThomas Huth 
645*fcf5ef2aSThomas Huth     if ((dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
646*fcf5ef2aSThomas Huth           && !((dc->cpu->env.pvr.regs[0] & PVR0_USE_DIV_MASK))) {
647*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
648*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
649*fcf5ef2aSThomas Huth     }
650*fcf5ef2aSThomas Huth 
651*fcf5ef2aSThomas Huth     if (u)
652*fcf5ef2aSThomas Huth         gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
653*fcf5ef2aSThomas Huth                         cpu_R[dc->ra]);
654*fcf5ef2aSThomas Huth     else
655*fcf5ef2aSThomas Huth         gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
656*fcf5ef2aSThomas Huth                         cpu_R[dc->ra]);
657*fcf5ef2aSThomas Huth     if (!dc->rd)
658*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_R[dc->rd], 0);
659*fcf5ef2aSThomas Huth }
660*fcf5ef2aSThomas Huth 
661*fcf5ef2aSThomas Huth static void dec_barrel(DisasContext *dc)
662*fcf5ef2aSThomas Huth {
663*fcf5ef2aSThomas Huth     TCGv t0;
664*fcf5ef2aSThomas Huth     unsigned int s, t;
665*fcf5ef2aSThomas Huth 
666*fcf5ef2aSThomas Huth     if ((dc->tb_flags & MSR_EE_FLAG)
667*fcf5ef2aSThomas Huth           && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
668*fcf5ef2aSThomas Huth           && !(dc->cpu->env.pvr.regs[0] & PVR0_USE_BARREL_MASK)) {
669*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
670*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
671*fcf5ef2aSThomas Huth         return;
672*fcf5ef2aSThomas Huth     }
673*fcf5ef2aSThomas Huth 
674*fcf5ef2aSThomas Huth     s = dc->imm & (1 << 10);
675*fcf5ef2aSThomas Huth     t = dc->imm & (1 << 9);
676*fcf5ef2aSThomas Huth 
677*fcf5ef2aSThomas Huth     LOG_DIS("bs%s%s r%d r%d r%d\n",
678*fcf5ef2aSThomas Huth             s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb);
679*fcf5ef2aSThomas Huth 
680*fcf5ef2aSThomas Huth     t0 = tcg_temp_new();
681*fcf5ef2aSThomas Huth 
682*fcf5ef2aSThomas Huth     tcg_gen_mov_tl(t0, *(dec_alu_op_b(dc)));
683*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t0, t0, 31);
684*fcf5ef2aSThomas Huth 
685*fcf5ef2aSThomas Huth     if (s)
686*fcf5ef2aSThomas Huth         tcg_gen_shl_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
687*fcf5ef2aSThomas Huth     else {
688*fcf5ef2aSThomas Huth         if (t)
689*fcf5ef2aSThomas Huth             tcg_gen_sar_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
690*fcf5ef2aSThomas Huth         else
691*fcf5ef2aSThomas Huth             tcg_gen_shr_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
692*fcf5ef2aSThomas Huth     }
693*fcf5ef2aSThomas Huth }
694*fcf5ef2aSThomas Huth 
695*fcf5ef2aSThomas Huth static void dec_bit(DisasContext *dc)
696*fcf5ef2aSThomas Huth {
697*fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
698*fcf5ef2aSThomas Huth     TCGv t0;
699*fcf5ef2aSThomas Huth     unsigned int op;
700*fcf5ef2aSThomas Huth     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
701*fcf5ef2aSThomas Huth 
702*fcf5ef2aSThomas Huth     op = dc->ir & ((1 << 9) - 1);
703*fcf5ef2aSThomas Huth     switch (op) {
704*fcf5ef2aSThomas Huth         case 0x21:
705*fcf5ef2aSThomas Huth             /* src.  */
706*fcf5ef2aSThomas Huth             t0 = tcg_temp_new();
707*fcf5ef2aSThomas Huth 
708*fcf5ef2aSThomas Huth             LOG_DIS("src r%d r%d\n", dc->rd, dc->ra);
709*fcf5ef2aSThomas Huth             tcg_gen_andi_tl(t0, cpu_SR[SR_MSR], MSR_CC);
710*fcf5ef2aSThomas Huth             write_carry(dc, cpu_R[dc->ra]);
711*fcf5ef2aSThomas Huth             if (dc->rd) {
712*fcf5ef2aSThomas Huth                 tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
713*fcf5ef2aSThomas Huth                 tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->rd], t0);
714*fcf5ef2aSThomas Huth             }
715*fcf5ef2aSThomas Huth             tcg_temp_free(t0);
716*fcf5ef2aSThomas Huth             break;
717*fcf5ef2aSThomas Huth 
718*fcf5ef2aSThomas Huth         case 0x1:
719*fcf5ef2aSThomas Huth         case 0x41:
720*fcf5ef2aSThomas Huth             /* srl.  */
721*fcf5ef2aSThomas Huth             LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra);
722*fcf5ef2aSThomas Huth 
723*fcf5ef2aSThomas Huth             /* Update carry. Note that write carry only looks at the LSB.  */
724*fcf5ef2aSThomas Huth             write_carry(dc, cpu_R[dc->ra]);
725*fcf5ef2aSThomas Huth             if (dc->rd) {
726*fcf5ef2aSThomas Huth                 if (op == 0x41)
727*fcf5ef2aSThomas Huth                     tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
728*fcf5ef2aSThomas Huth                 else
729*fcf5ef2aSThomas Huth                     tcg_gen_sari_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
730*fcf5ef2aSThomas Huth             }
731*fcf5ef2aSThomas Huth             break;
732*fcf5ef2aSThomas Huth         case 0x60:
733*fcf5ef2aSThomas Huth             LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra);
734*fcf5ef2aSThomas Huth             tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
735*fcf5ef2aSThomas Huth             break;
736*fcf5ef2aSThomas Huth         case 0x61:
737*fcf5ef2aSThomas Huth             LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra);
738*fcf5ef2aSThomas Huth             tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
739*fcf5ef2aSThomas Huth             break;
740*fcf5ef2aSThomas Huth         case 0x64:
741*fcf5ef2aSThomas Huth         case 0x66:
742*fcf5ef2aSThomas Huth         case 0x74:
743*fcf5ef2aSThomas Huth         case 0x76:
744*fcf5ef2aSThomas Huth             /* wdc.  */
745*fcf5ef2aSThomas Huth             LOG_DIS("wdc r%d\n", dc->ra);
746*fcf5ef2aSThomas Huth             if ((dc->tb_flags & MSR_EE_FLAG)
747*fcf5ef2aSThomas Huth                  && mem_index == MMU_USER_IDX) {
748*fcf5ef2aSThomas Huth                 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
749*fcf5ef2aSThomas Huth                 t_gen_raise_exception(dc, EXCP_HW_EXCP);
750*fcf5ef2aSThomas Huth                 return;
751*fcf5ef2aSThomas Huth             }
752*fcf5ef2aSThomas Huth             break;
753*fcf5ef2aSThomas Huth         case 0x68:
754*fcf5ef2aSThomas Huth             /* wic.  */
755*fcf5ef2aSThomas Huth             LOG_DIS("wic r%d\n", dc->ra);
756*fcf5ef2aSThomas Huth             if ((dc->tb_flags & MSR_EE_FLAG)
757*fcf5ef2aSThomas Huth                  && mem_index == MMU_USER_IDX) {
758*fcf5ef2aSThomas Huth                 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
759*fcf5ef2aSThomas Huth                 t_gen_raise_exception(dc, EXCP_HW_EXCP);
760*fcf5ef2aSThomas Huth                 return;
761*fcf5ef2aSThomas Huth             }
762*fcf5ef2aSThomas Huth             break;
763*fcf5ef2aSThomas Huth         case 0xe0:
764*fcf5ef2aSThomas Huth             if ((dc->tb_flags & MSR_EE_FLAG)
765*fcf5ef2aSThomas Huth                 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
766*fcf5ef2aSThomas Huth                 && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
767*fcf5ef2aSThomas Huth                 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
768*fcf5ef2aSThomas Huth                 t_gen_raise_exception(dc, EXCP_HW_EXCP);
769*fcf5ef2aSThomas Huth             }
770*fcf5ef2aSThomas Huth             if (dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR) {
771*fcf5ef2aSThomas Huth                 gen_helper_clz(cpu_R[dc->rd], cpu_R[dc->ra]);
772*fcf5ef2aSThomas Huth             }
773*fcf5ef2aSThomas Huth             break;
774*fcf5ef2aSThomas Huth         case 0x1e0:
775*fcf5ef2aSThomas Huth             /* swapb */
776*fcf5ef2aSThomas Huth             LOG_DIS("swapb r%d r%d\n", dc->rd, dc->ra);
777*fcf5ef2aSThomas Huth             tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
778*fcf5ef2aSThomas Huth             break;
779*fcf5ef2aSThomas Huth         case 0x1e2:
780*fcf5ef2aSThomas Huth             /*swaph */
781*fcf5ef2aSThomas Huth             LOG_DIS("swaph r%d r%d\n", dc->rd, dc->ra);
782*fcf5ef2aSThomas Huth             tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16);
783*fcf5ef2aSThomas Huth             break;
784*fcf5ef2aSThomas Huth         default:
785*fcf5ef2aSThomas Huth             cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
786*fcf5ef2aSThomas Huth                       dc->pc, op, dc->rd, dc->ra, dc->rb);
787*fcf5ef2aSThomas Huth             break;
788*fcf5ef2aSThomas Huth     }
789*fcf5ef2aSThomas Huth }
790*fcf5ef2aSThomas Huth 
791*fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc)
792*fcf5ef2aSThomas Huth {
793*fcf5ef2aSThomas Huth     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
794*fcf5ef2aSThomas Huth         if (dc->jmp == JMP_DIRECT) {
795*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(env_btaken, 1);
796*fcf5ef2aSThomas Huth         }
797*fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
798*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
799*fcf5ef2aSThomas Huth     }
800*fcf5ef2aSThomas Huth }
801*fcf5ef2aSThomas Huth 
802*fcf5ef2aSThomas Huth static void dec_imm(DisasContext *dc)
803*fcf5ef2aSThomas Huth {
804*fcf5ef2aSThomas Huth     LOG_DIS("imm %x\n", dc->imm << 16);
805*fcf5ef2aSThomas Huth     tcg_gen_movi_tl(env_imm, (dc->imm << 16));
806*fcf5ef2aSThomas Huth     dc->tb_flags |= IMM_FLAG;
807*fcf5ef2aSThomas Huth     dc->clear_imm = 0;
808*fcf5ef2aSThomas Huth }
809*fcf5ef2aSThomas Huth 
810*fcf5ef2aSThomas Huth static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
811*fcf5ef2aSThomas Huth {
812*fcf5ef2aSThomas Huth     unsigned int extimm = dc->tb_flags & IMM_FLAG;
813*fcf5ef2aSThomas Huth     /* Should be set to one if r1 is used by loadstores.  */
814*fcf5ef2aSThomas Huth     int stackprot = 0;
815*fcf5ef2aSThomas Huth 
816*fcf5ef2aSThomas Huth     /* All load/stores use ra.  */
817*fcf5ef2aSThomas Huth     if (dc->ra == 1 && dc->cpu->cfg.stackprot) {
818*fcf5ef2aSThomas Huth         stackprot = 1;
819*fcf5ef2aSThomas Huth     }
820*fcf5ef2aSThomas Huth 
821*fcf5ef2aSThomas Huth     /* Treat the common cases first.  */
822*fcf5ef2aSThomas Huth     if (!dc->type_b) {
823*fcf5ef2aSThomas Huth         /* If any of the regs is r0, return a ptr to the other.  */
824*fcf5ef2aSThomas Huth         if (dc->ra == 0) {
825*fcf5ef2aSThomas Huth             return &cpu_R[dc->rb];
826*fcf5ef2aSThomas Huth         } else if (dc->rb == 0) {
827*fcf5ef2aSThomas Huth             return &cpu_R[dc->ra];
828*fcf5ef2aSThomas Huth         }
829*fcf5ef2aSThomas Huth 
830*fcf5ef2aSThomas Huth         if (dc->rb == 1 && dc->cpu->cfg.stackprot) {
831*fcf5ef2aSThomas Huth             stackprot = 1;
832*fcf5ef2aSThomas Huth         }
833*fcf5ef2aSThomas Huth 
834*fcf5ef2aSThomas Huth         *t = tcg_temp_new();
835*fcf5ef2aSThomas Huth         tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]);
836*fcf5ef2aSThomas Huth 
837*fcf5ef2aSThomas Huth         if (stackprot) {
838*fcf5ef2aSThomas Huth             gen_helper_stackprot(cpu_env, *t);
839*fcf5ef2aSThomas Huth         }
840*fcf5ef2aSThomas Huth         return t;
841*fcf5ef2aSThomas Huth     }
842*fcf5ef2aSThomas Huth     /* Immediate.  */
843*fcf5ef2aSThomas Huth     if (!extimm) {
844*fcf5ef2aSThomas Huth         if (dc->imm == 0) {
845*fcf5ef2aSThomas Huth             return &cpu_R[dc->ra];
846*fcf5ef2aSThomas Huth         }
847*fcf5ef2aSThomas Huth         *t = tcg_temp_new();
848*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(*t, (int32_t)((int16_t)dc->imm));
849*fcf5ef2aSThomas Huth         tcg_gen_add_tl(*t, cpu_R[dc->ra], *t);
850*fcf5ef2aSThomas Huth     } else {
851*fcf5ef2aSThomas Huth         *t = tcg_temp_new();
852*fcf5ef2aSThomas Huth         tcg_gen_add_tl(*t, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
853*fcf5ef2aSThomas Huth     }
854*fcf5ef2aSThomas Huth 
855*fcf5ef2aSThomas Huth     if (stackprot) {
856*fcf5ef2aSThomas Huth         gen_helper_stackprot(cpu_env, *t);
857*fcf5ef2aSThomas Huth     }
858*fcf5ef2aSThomas Huth     return t;
859*fcf5ef2aSThomas Huth }
860*fcf5ef2aSThomas Huth 
861*fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc)
862*fcf5ef2aSThomas Huth {
863*fcf5ef2aSThomas Huth     TCGv t, v, *addr;
864*fcf5ef2aSThomas Huth     unsigned int size, rev = 0, ex = 0;
865*fcf5ef2aSThomas Huth     TCGMemOp mop;
866*fcf5ef2aSThomas Huth 
867*fcf5ef2aSThomas Huth     mop = dc->opcode & 3;
868*fcf5ef2aSThomas Huth     size = 1 << mop;
869*fcf5ef2aSThomas Huth     if (!dc->type_b) {
870*fcf5ef2aSThomas Huth         rev = (dc->ir >> 9) & 1;
871*fcf5ef2aSThomas Huth         ex = (dc->ir >> 10) & 1;
872*fcf5ef2aSThomas Huth     }
873*fcf5ef2aSThomas Huth     mop |= MO_TE;
874*fcf5ef2aSThomas Huth     if (rev) {
875*fcf5ef2aSThomas Huth         mop ^= MO_BSWAP;
876*fcf5ef2aSThomas Huth     }
877*fcf5ef2aSThomas Huth 
878*fcf5ef2aSThomas Huth     if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
879*fcf5ef2aSThomas Huth           && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
880*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
881*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
882*fcf5ef2aSThomas Huth         return;
883*fcf5ef2aSThomas Huth     }
884*fcf5ef2aSThomas Huth 
885*fcf5ef2aSThomas Huth     LOG_DIS("l%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
886*fcf5ef2aSThomas Huth                                                         ex ? "x" : "");
887*fcf5ef2aSThomas Huth 
888*fcf5ef2aSThomas Huth     t_sync_flags(dc);
889*fcf5ef2aSThomas Huth     addr = compute_ldst_addr(dc, &t);
890*fcf5ef2aSThomas Huth 
891*fcf5ef2aSThomas Huth     /*
892*fcf5ef2aSThomas Huth      * When doing reverse accesses we need to do two things.
893*fcf5ef2aSThomas Huth      *
894*fcf5ef2aSThomas Huth      * 1. Reverse the address wrt endianness.
895*fcf5ef2aSThomas Huth      * 2. Byteswap the data lanes on the way back into the CPU core.
896*fcf5ef2aSThomas Huth      */
897*fcf5ef2aSThomas Huth     if (rev && size != 4) {
898*fcf5ef2aSThomas Huth         /* Endian reverse the address. t is addr.  */
899*fcf5ef2aSThomas Huth         switch (size) {
900*fcf5ef2aSThomas Huth             case 1:
901*fcf5ef2aSThomas Huth             {
902*fcf5ef2aSThomas Huth                 /* 00 -> 11
903*fcf5ef2aSThomas Huth                    01 -> 10
904*fcf5ef2aSThomas Huth                    10 -> 10
905*fcf5ef2aSThomas Huth                    11 -> 00 */
906*fcf5ef2aSThomas Huth                 TCGv low = tcg_temp_new();
907*fcf5ef2aSThomas Huth 
908*fcf5ef2aSThomas Huth                 /* Force addr into the temp.  */
909*fcf5ef2aSThomas Huth                 if (addr != &t) {
910*fcf5ef2aSThomas Huth                     t = tcg_temp_new();
911*fcf5ef2aSThomas Huth                     tcg_gen_mov_tl(t, *addr);
912*fcf5ef2aSThomas Huth                     addr = &t;
913*fcf5ef2aSThomas Huth                 }
914*fcf5ef2aSThomas Huth 
915*fcf5ef2aSThomas Huth                 tcg_gen_andi_tl(low, t, 3);
916*fcf5ef2aSThomas Huth                 tcg_gen_sub_tl(low, tcg_const_tl(3), low);
917*fcf5ef2aSThomas Huth                 tcg_gen_andi_tl(t, t, ~3);
918*fcf5ef2aSThomas Huth                 tcg_gen_or_tl(t, t, low);
919*fcf5ef2aSThomas Huth                 tcg_gen_mov_tl(env_imm, t);
920*fcf5ef2aSThomas Huth                 tcg_temp_free(low);
921*fcf5ef2aSThomas Huth                 break;
922*fcf5ef2aSThomas Huth             }
923*fcf5ef2aSThomas Huth 
924*fcf5ef2aSThomas Huth             case 2:
925*fcf5ef2aSThomas Huth                 /* 00 -> 10
926*fcf5ef2aSThomas Huth                    10 -> 00.  */
927*fcf5ef2aSThomas Huth                 /* Force addr into the temp.  */
928*fcf5ef2aSThomas Huth                 if (addr != &t) {
929*fcf5ef2aSThomas Huth                     t = tcg_temp_new();
930*fcf5ef2aSThomas Huth                     tcg_gen_xori_tl(t, *addr, 2);
931*fcf5ef2aSThomas Huth                     addr = &t;
932*fcf5ef2aSThomas Huth                 } else {
933*fcf5ef2aSThomas Huth                     tcg_gen_xori_tl(t, t, 2);
934*fcf5ef2aSThomas Huth                 }
935*fcf5ef2aSThomas Huth                 break;
936*fcf5ef2aSThomas Huth             default:
937*fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
938*fcf5ef2aSThomas Huth                 break;
939*fcf5ef2aSThomas Huth         }
940*fcf5ef2aSThomas Huth     }
941*fcf5ef2aSThomas Huth 
942*fcf5ef2aSThomas Huth     /* lwx does not throw unaligned access errors, so force alignment */
943*fcf5ef2aSThomas Huth     if (ex) {
944*fcf5ef2aSThomas Huth         /* Force addr into the temp.  */
945*fcf5ef2aSThomas Huth         if (addr != &t) {
946*fcf5ef2aSThomas Huth             t = tcg_temp_new();
947*fcf5ef2aSThomas Huth             tcg_gen_mov_tl(t, *addr);
948*fcf5ef2aSThomas Huth             addr = &t;
949*fcf5ef2aSThomas Huth         }
950*fcf5ef2aSThomas Huth         tcg_gen_andi_tl(t, t, ~3);
951*fcf5ef2aSThomas Huth     }
952*fcf5ef2aSThomas Huth 
953*fcf5ef2aSThomas Huth     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
954*fcf5ef2aSThomas Huth     sync_jmpstate(dc);
955*fcf5ef2aSThomas Huth 
956*fcf5ef2aSThomas Huth     /* Verify alignment if needed.  */
957*fcf5ef2aSThomas Huth     /*
958*fcf5ef2aSThomas Huth      * Microblaze gives MMU faults priority over faults due to
959*fcf5ef2aSThomas Huth      * unaligned addresses. That's why we speculatively do the load
960*fcf5ef2aSThomas Huth      * into v. If the load succeeds, we verify alignment of the
961*fcf5ef2aSThomas Huth      * address and if that succeeds we write into the destination reg.
962*fcf5ef2aSThomas Huth      */
963*fcf5ef2aSThomas Huth     v = tcg_temp_new();
964*fcf5ef2aSThomas Huth     tcg_gen_qemu_ld_tl(v, *addr, cpu_mmu_index(&dc->cpu->env, false), mop);
965*fcf5ef2aSThomas Huth 
966*fcf5ef2aSThomas Huth     if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
967*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
968*fcf5ef2aSThomas Huth         gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
969*fcf5ef2aSThomas Huth                             tcg_const_tl(0), tcg_const_tl(size - 1));
970*fcf5ef2aSThomas Huth     }
971*fcf5ef2aSThomas Huth 
972*fcf5ef2aSThomas Huth     if (ex) {
973*fcf5ef2aSThomas Huth         tcg_gen_mov_tl(env_res_addr, *addr);
974*fcf5ef2aSThomas Huth         tcg_gen_mov_tl(env_res_val, v);
975*fcf5ef2aSThomas Huth     }
976*fcf5ef2aSThomas Huth     if (dc->rd) {
977*fcf5ef2aSThomas Huth         tcg_gen_mov_tl(cpu_R[dc->rd], v);
978*fcf5ef2aSThomas Huth     }
979*fcf5ef2aSThomas Huth     tcg_temp_free(v);
980*fcf5ef2aSThomas Huth 
981*fcf5ef2aSThomas Huth     if (ex) { /* lwx */
982*fcf5ef2aSThomas Huth         /* no support for AXI exclusive so always clear C */
983*fcf5ef2aSThomas Huth         write_carryi(dc, 0);
984*fcf5ef2aSThomas Huth     }
985*fcf5ef2aSThomas Huth 
986*fcf5ef2aSThomas Huth     if (addr == &t)
987*fcf5ef2aSThomas Huth         tcg_temp_free(t);
988*fcf5ef2aSThomas Huth }
989*fcf5ef2aSThomas Huth 
990*fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc)
991*fcf5ef2aSThomas Huth {
992*fcf5ef2aSThomas Huth     TCGv t, *addr, swx_addr;
993*fcf5ef2aSThomas Huth     TCGLabel *swx_skip = NULL;
994*fcf5ef2aSThomas Huth     unsigned int size, rev = 0, ex = 0;
995*fcf5ef2aSThomas Huth     TCGMemOp mop;
996*fcf5ef2aSThomas Huth 
997*fcf5ef2aSThomas Huth     mop = dc->opcode & 3;
998*fcf5ef2aSThomas Huth     size = 1 << mop;
999*fcf5ef2aSThomas Huth     if (!dc->type_b) {
1000*fcf5ef2aSThomas Huth         rev = (dc->ir >> 9) & 1;
1001*fcf5ef2aSThomas Huth         ex = (dc->ir >> 10) & 1;
1002*fcf5ef2aSThomas Huth     }
1003*fcf5ef2aSThomas Huth     mop |= MO_TE;
1004*fcf5ef2aSThomas Huth     if (rev) {
1005*fcf5ef2aSThomas Huth         mop ^= MO_BSWAP;
1006*fcf5ef2aSThomas Huth     }
1007*fcf5ef2aSThomas Huth 
1008*fcf5ef2aSThomas Huth     if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
1009*fcf5ef2aSThomas Huth           && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
1010*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1011*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
1012*fcf5ef2aSThomas Huth         return;
1013*fcf5ef2aSThomas Huth     }
1014*fcf5ef2aSThomas Huth 
1015*fcf5ef2aSThomas Huth     LOG_DIS("s%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
1016*fcf5ef2aSThomas Huth                                                         ex ? "x" : "");
1017*fcf5ef2aSThomas Huth     t_sync_flags(dc);
1018*fcf5ef2aSThomas Huth     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
1019*fcf5ef2aSThomas Huth     sync_jmpstate(dc);
1020*fcf5ef2aSThomas Huth     addr = compute_ldst_addr(dc, &t);
1021*fcf5ef2aSThomas Huth 
1022*fcf5ef2aSThomas Huth     swx_addr = tcg_temp_local_new();
1023*fcf5ef2aSThomas Huth     if (ex) { /* swx */
1024*fcf5ef2aSThomas Huth         TCGv tval;
1025*fcf5ef2aSThomas Huth 
1026*fcf5ef2aSThomas Huth         /* Force addr into the swx_addr. */
1027*fcf5ef2aSThomas Huth         tcg_gen_mov_tl(swx_addr, *addr);
1028*fcf5ef2aSThomas Huth         addr = &swx_addr;
1029*fcf5ef2aSThomas Huth         /* swx does not throw unaligned access errors, so force alignment */
1030*fcf5ef2aSThomas Huth         tcg_gen_andi_tl(swx_addr, swx_addr, ~3);
1031*fcf5ef2aSThomas Huth 
1032*fcf5ef2aSThomas Huth         write_carryi(dc, 1);
1033*fcf5ef2aSThomas Huth         swx_skip = gen_new_label();
1034*fcf5ef2aSThomas Huth         tcg_gen_brcond_tl(TCG_COND_NE, env_res_addr, swx_addr, swx_skip);
1035*fcf5ef2aSThomas Huth 
1036*fcf5ef2aSThomas Huth         /* Compare the value loaded at lwx with current contents of
1037*fcf5ef2aSThomas Huth            the reserved location.
1038*fcf5ef2aSThomas Huth            FIXME: This only works for system emulation where we can expect
1039*fcf5ef2aSThomas Huth            this compare and the following write to be atomic. For user
1040*fcf5ef2aSThomas Huth            emulation we need to add atomicity between threads.  */
1041*fcf5ef2aSThomas Huth         tval = tcg_temp_new();
1042*fcf5ef2aSThomas Huth         tcg_gen_qemu_ld_tl(tval, swx_addr, cpu_mmu_index(&dc->cpu->env, false),
1043*fcf5ef2aSThomas Huth                            MO_TEUL);
1044*fcf5ef2aSThomas Huth         tcg_gen_brcond_tl(TCG_COND_NE, env_res_val, tval, swx_skip);
1045*fcf5ef2aSThomas Huth         write_carryi(dc, 0);
1046*fcf5ef2aSThomas Huth         tcg_temp_free(tval);
1047*fcf5ef2aSThomas Huth     }
1048*fcf5ef2aSThomas Huth 
1049*fcf5ef2aSThomas Huth     if (rev && size != 4) {
1050*fcf5ef2aSThomas Huth         /* Endian reverse the address. t is addr.  */
1051*fcf5ef2aSThomas Huth         switch (size) {
1052*fcf5ef2aSThomas Huth             case 1:
1053*fcf5ef2aSThomas Huth             {
1054*fcf5ef2aSThomas Huth                 /* 00 -> 11
1055*fcf5ef2aSThomas Huth                    01 -> 10
1056*fcf5ef2aSThomas Huth                    10 -> 10
1057*fcf5ef2aSThomas Huth                    11 -> 00 */
1058*fcf5ef2aSThomas Huth                 TCGv low = tcg_temp_new();
1059*fcf5ef2aSThomas Huth 
1060*fcf5ef2aSThomas Huth                 /* Force addr into the temp.  */
1061*fcf5ef2aSThomas Huth                 if (addr != &t) {
1062*fcf5ef2aSThomas Huth                     t = tcg_temp_new();
1063*fcf5ef2aSThomas Huth                     tcg_gen_mov_tl(t, *addr);
1064*fcf5ef2aSThomas Huth                     addr = &t;
1065*fcf5ef2aSThomas Huth                 }
1066*fcf5ef2aSThomas Huth 
1067*fcf5ef2aSThomas Huth                 tcg_gen_andi_tl(low, t, 3);
1068*fcf5ef2aSThomas Huth                 tcg_gen_sub_tl(low, tcg_const_tl(3), low);
1069*fcf5ef2aSThomas Huth                 tcg_gen_andi_tl(t, t, ~3);
1070*fcf5ef2aSThomas Huth                 tcg_gen_or_tl(t, t, low);
1071*fcf5ef2aSThomas Huth                 tcg_gen_mov_tl(env_imm, t);
1072*fcf5ef2aSThomas Huth                 tcg_temp_free(low);
1073*fcf5ef2aSThomas Huth                 break;
1074*fcf5ef2aSThomas Huth             }
1075*fcf5ef2aSThomas Huth 
1076*fcf5ef2aSThomas Huth             case 2:
1077*fcf5ef2aSThomas Huth                 /* 00 -> 10
1078*fcf5ef2aSThomas Huth                    10 -> 00.  */
1079*fcf5ef2aSThomas Huth                 /* Force addr into the temp.  */
1080*fcf5ef2aSThomas Huth                 if (addr != &t) {
1081*fcf5ef2aSThomas Huth                     t = tcg_temp_new();
1082*fcf5ef2aSThomas Huth                     tcg_gen_xori_tl(t, *addr, 2);
1083*fcf5ef2aSThomas Huth                     addr = &t;
1084*fcf5ef2aSThomas Huth                 } else {
1085*fcf5ef2aSThomas Huth                     tcg_gen_xori_tl(t, t, 2);
1086*fcf5ef2aSThomas Huth                 }
1087*fcf5ef2aSThomas Huth                 break;
1088*fcf5ef2aSThomas Huth             default:
1089*fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
1090*fcf5ef2aSThomas Huth                 break;
1091*fcf5ef2aSThomas Huth         }
1092*fcf5ef2aSThomas Huth     }
1093*fcf5ef2aSThomas Huth     tcg_gen_qemu_st_tl(cpu_R[dc->rd], *addr, cpu_mmu_index(&dc->cpu->env, false), mop);
1094*fcf5ef2aSThomas Huth 
1095*fcf5ef2aSThomas Huth     /* Verify alignment if needed.  */
1096*fcf5ef2aSThomas Huth     if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
1097*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
1098*fcf5ef2aSThomas Huth         /* FIXME: if the alignment is wrong, we should restore the value
1099*fcf5ef2aSThomas Huth          *        in memory. One possible way to achieve this is to probe
1100*fcf5ef2aSThomas Huth          *        the MMU prior to the memaccess, thay way we could put
1101*fcf5ef2aSThomas Huth          *        the alignment checks in between the probe and the mem
1102*fcf5ef2aSThomas Huth          *        access.
1103*fcf5ef2aSThomas Huth          */
1104*fcf5ef2aSThomas Huth         gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
1105*fcf5ef2aSThomas Huth                             tcg_const_tl(1), tcg_const_tl(size - 1));
1106*fcf5ef2aSThomas Huth     }
1107*fcf5ef2aSThomas Huth 
1108*fcf5ef2aSThomas Huth     if (ex) {
1109*fcf5ef2aSThomas Huth         gen_set_label(swx_skip);
1110*fcf5ef2aSThomas Huth     }
1111*fcf5ef2aSThomas Huth     tcg_temp_free(swx_addr);
1112*fcf5ef2aSThomas Huth 
1113*fcf5ef2aSThomas Huth     if (addr == &t)
1114*fcf5ef2aSThomas Huth         tcg_temp_free(t);
1115*fcf5ef2aSThomas Huth }
1116*fcf5ef2aSThomas Huth 
1117*fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc,
1118*fcf5ef2aSThomas Huth                            TCGv d, TCGv a, TCGv b)
1119*fcf5ef2aSThomas Huth {
1120*fcf5ef2aSThomas Huth     switch (cc) {
1121*fcf5ef2aSThomas Huth         case CC_EQ:
1122*fcf5ef2aSThomas Huth             tcg_gen_setcond_tl(TCG_COND_EQ, d, a, b);
1123*fcf5ef2aSThomas Huth             break;
1124*fcf5ef2aSThomas Huth         case CC_NE:
1125*fcf5ef2aSThomas Huth             tcg_gen_setcond_tl(TCG_COND_NE, d, a, b);
1126*fcf5ef2aSThomas Huth             break;
1127*fcf5ef2aSThomas Huth         case CC_LT:
1128*fcf5ef2aSThomas Huth             tcg_gen_setcond_tl(TCG_COND_LT, d, a, b);
1129*fcf5ef2aSThomas Huth             break;
1130*fcf5ef2aSThomas Huth         case CC_LE:
1131*fcf5ef2aSThomas Huth             tcg_gen_setcond_tl(TCG_COND_LE, d, a, b);
1132*fcf5ef2aSThomas Huth             break;
1133*fcf5ef2aSThomas Huth         case CC_GE:
1134*fcf5ef2aSThomas Huth             tcg_gen_setcond_tl(TCG_COND_GE, d, a, b);
1135*fcf5ef2aSThomas Huth             break;
1136*fcf5ef2aSThomas Huth         case CC_GT:
1137*fcf5ef2aSThomas Huth             tcg_gen_setcond_tl(TCG_COND_GT, d, a, b);
1138*fcf5ef2aSThomas Huth             break;
1139*fcf5ef2aSThomas Huth         default:
1140*fcf5ef2aSThomas Huth             cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
1141*fcf5ef2aSThomas Huth             break;
1142*fcf5ef2aSThomas Huth     }
1143*fcf5ef2aSThomas Huth }
1144*fcf5ef2aSThomas Huth 
1145*fcf5ef2aSThomas Huth static void eval_cond_jmp(DisasContext *dc, TCGv pc_true, TCGv pc_false)
1146*fcf5ef2aSThomas Huth {
1147*fcf5ef2aSThomas Huth     TCGLabel *l1 = gen_new_label();
1148*fcf5ef2aSThomas Huth     /* Conditional jmp.  */
1149*fcf5ef2aSThomas Huth     tcg_gen_mov_tl(cpu_SR[SR_PC], pc_false);
1150*fcf5ef2aSThomas Huth     tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
1151*fcf5ef2aSThomas Huth     tcg_gen_mov_tl(cpu_SR[SR_PC], pc_true);
1152*fcf5ef2aSThomas Huth     gen_set_label(l1);
1153*fcf5ef2aSThomas Huth }
1154*fcf5ef2aSThomas Huth 
1155*fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc)
1156*fcf5ef2aSThomas Huth {
1157*fcf5ef2aSThomas Huth     unsigned int cc;
1158*fcf5ef2aSThomas Huth     unsigned int dslot;
1159*fcf5ef2aSThomas Huth 
1160*fcf5ef2aSThomas Huth     cc = EXTRACT_FIELD(dc->ir, 21, 23);
1161*fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 25);
1162*fcf5ef2aSThomas Huth     LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm);
1163*fcf5ef2aSThomas Huth 
1164*fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1165*fcf5ef2aSThomas Huth     if (dslot) {
1166*fcf5ef2aSThomas Huth         dc->delayed_branch = 2;
1167*fcf5ef2aSThomas Huth         dc->tb_flags |= D_FLAG;
1168*fcf5ef2aSThomas Huth         tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
1169*fcf5ef2aSThomas Huth                       cpu_env, offsetof(CPUMBState, bimm));
1170*fcf5ef2aSThomas Huth     }
1171*fcf5ef2aSThomas Huth 
1172*fcf5ef2aSThomas Huth     if (dec_alu_op_b_is_small_imm(dc)) {
1173*fcf5ef2aSThomas Huth         int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend.  */
1174*fcf5ef2aSThomas Huth 
1175*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(env_btarget, dc->pc + offset);
1176*fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT_CC;
1177*fcf5ef2aSThomas Huth         dc->jmp_pc = dc->pc + offset;
1178*fcf5ef2aSThomas Huth     } else {
1179*fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
1180*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(env_btarget, dc->pc);
1181*fcf5ef2aSThomas Huth         tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
1182*fcf5ef2aSThomas Huth     }
1183*fcf5ef2aSThomas Huth     eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
1184*fcf5ef2aSThomas Huth }
1185*fcf5ef2aSThomas Huth 
1186*fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc)
1187*fcf5ef2aSThomas Huth {
1188*fcf5ef2aSThomas Huth     unsigned int dslot, link, abs, mbar;
1189*fcf5ef2aSThomas Huth     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
1190*fcf5ef2aSThomas Huth 
1191*fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 20);
1192*fcf5ef2aSThomas Huth     abs = dc->ir & (1 << 19);
1193*fcf5ef2aSThomas Huth     link = dc->ir & (1 << 18);
1194*fcf5ef2aSThomas Huth 
1195*fcf5ef2aSThomas Huth     /* Memory barrier.  */
1196*fcf5ef2aSThomas Huth     mbar = (dc->ir >> 16) & 31;
1197*fcf5ef2aSThomas Huth     if (mbar == 2 && dc->imm == 4) {
1198*fcf5ef2aSThomas Huth         /* mbar IMM & 16 decodes to sleep.  */
1199*fcf5ef2aSThomas Huth         if (dc->rd & 16) {
1200*fcf5ef2aSThomas Huth             TCGv_i32 tmp_hlt = tcg_const_i32(EXCP_HLT);
1201*fcf5ef2aSThomas Huth             TCGv_i32 tmp_1 = tcg_const_i32(1);
1202*fcf5ef2aSThomas Huth 
1203*fcf5ef2aSThomas Huth             LOG_DIS("sleep\n");
1204*fcf5ef2aSThomas Huth 
1205*fcf5ef2aSThomas Huth             t_sync_flags(dc);
1206*fcf5ef2aSThomas Huth             tcg_gen_st_i32(tmp_1, cpu_env,
1207*fcf5ef2aSThomas Huth                            -offsetof(MicroBlazeCPU, env)
1208*fcf5ef2aSThomas Huth                            +offsetof(CPUState, halted));
1209*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4);
1210*fcf5ef2aSThomas Huth             gen_helper_raise_exception(cpu_env, tmp_hlt);
1211*fcf5ef2aSThomas Huth             tcg_temp_free_i32(tmp_hlt);
1212*fcf5ef2aSThomas Huth             tcg_temp_free_i32(tmp_1);
1213*fcf5ef2aSThomas Huth             return;
1214*fcf5ef2aSThomas Huth         }
1215*fcf5ef2aSThomas Huth         LOG_DIS("mbar %d\n", dc->rd);
1216*fcf5ef2aSThomas Huth         /* Break the TB.  */
1217*fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1218*fcf5ef2aSThomas Huth         return;
1219*fcf5ef2aSThomas Huth     }
1220*fcf5ef2aSThomas Huth 
1221*fcf5ef2aSThomas Huth     LOG_DIS("br%s%s%s%s imm=%x\n",
1222*fcf5ef2aSThomas Huth              abs ? "a" : "", link ? "l" : "",
1223*fcf5ef2aSThomas Huth              dc->type_b ? "i" : "", dslot ? "d" : "",
1224*fcf5ef2aSThomas Huth              dc->imm);
1225*fcf5ef2aSThomas Huth 
1226*fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1227*fcf5ef2aSThomas Huth     if (dslot) {
1228*fcf5ef2aSThomas Huth         dc->delayed_branch = 2;
1229*fcf5ef2aSThomas Huth         dc->tb_flags |= D_FLAG;
1230*fcf5ef2aSThomas Huth         tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
1231*fcf5ef2aSThomas Huth                       cpu_env, offsetof(CPUMBState, bimm));
1232*fcf5ef2aSThomas Huth     }
1233*fcf5ef2aSThomas Huth     if (link && dc->rd)
1234*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
1235*fcf5ef2aSThomas Huth 
1236*fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
1237*fcf5ef2aSThomas Huth     if (abs) {
1238*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(env_btaken, 1);
1239*fcf5ef2aSThomas Huth         tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
1240*fcf5ef2aSThomas Huth         if (link && !dslot) {
1241*fcf5ef2aSThomas Huth             if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
1242*fcf5ef2aSThomas Huth                 t_gen_raise_exception(dc, EXCP_BREAK);
1243*fcf5ef2aSThomas Huth             if (dc->imm == 0) {
1244*fcf5ef2aSThomas Huth                 if ((dc->tb_flags & MSR_EE_FLAG) && mem_index == MMU_USER_IDX) {
1245*fcf5ef2aSThomas Huth                     tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1246*fcf5ef2aSThomas Huth                     t_gen_raise_exception(dc, EXCP_HW_EXCP);
1247*fcf5ef2aSThomas Huth                     return;
1248*fcf5ef2aSThomas Huth                 }
1249*fcf5ef2aSThomas Huth 
1250*fcf5ef2aSThomas Huth                 t_gen_raise_exception(dc, EXCP_DEBUG);
1251*fcf5ef2aSThomas Huth             }
1252*fcf5ef2aSThomas Huth         }
1253*fcf5ef2aSThomas Huth     } else {
1254*fcf5ef2aSThomas Huth         if (dec_alu_op_b_is_small_imm(dc)) {
1255*fcf5ef2aSThomas Huth             dc->jmp = JMP_DIRECT;
1256*fcf5ef2aSThomas Huth             dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
1257*fcf5ef2aSThomas Huth         } else {
1258*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(env_btaken, 1);
1259*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(env_btarget, dc->pc);
1260*fcf5ef2aSThomas Huth             tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
1261*fcf5ef2aSThomas Huth         }
1262*fcf5ef2aSThomas Huth     }
1263*fcf5ef2aSThomas Huth }
1264*fcf5ef2aSThomas Huth 
1265*fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc)
1266*fcf5ef2aSThomas Huth {
1267*fcf5ef2aSThomas Huth     TCGv t0, t1;
1268*fcf5ef2aSThomas Huth     t0 = tcg_temp_new();
1269*fcf5ef2aSThomas Huth     t1 = tcg_temp_new();
1270*fcf5ef2aSThomas Huth     tcg_gen_shri_tl(t0, cpu_SR[SR_MSR], 1);
1271*fcf5ef2aSThomas Huth     tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_IE);
1272*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
1273*fcf5ef2aSThomas Huth 
1274*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
1275*fcf5ef2aSThomas Huth     tcg_gen_or_tl(t1, t1, t0);
1276*fcf5ef2aSThomas Huth     msr_write(dc, t1);
1277*fcf5ef2aSThomas Huth     tcg_temp_free(t1);
1278*fcf5ef2aSThomas Huth     tcg_temp_free(t0);
1279*fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1280*fcf5ef2aSThomas Huth }
1281*fcf5ef2aSThomas Huth 
1282*fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc)
1283*fcf5ef2aSThomas Huth {
1284*fcf5ef2aSThomas Huth     TCGv t0, t1;
1285*fcf5ef2aSThomas Huth     t0 = tcg_temp_new();
1286*fcf5ef2aSThomas Huth     t1 = tcg_temp_new();
1287*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t1, cpu_SR[SR_MSR], ~MSR_BIP);
1288*fcf5ef2aSThomas Huth     tcg_gen_shri_tl(t0, t1, 1);
1289*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
1290*fcf5ef2aSThomas Huth 
1291*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
1292*fcf5ef2aSThomas Huth     tcg_gen_or_tl(t1, t1, t0);
1293*fcf5ef2aSThomas Huth     msr_write(dc, t1);
1294*fcf5ef2aSThomas Huth     tcg_temp_free(t1);
1295*fcf5ef2aSThomas Huth     tcg_temp_free(t0);
1296*fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1297*fcf5ef2aSThomas Huth }
1298*fcf5ef2aSThomas Huth 
1299*fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc)
1300*fcf5ef2aSThomas Huth {
1301*fcf5ef2aSThomas Huth     TCGv t0, t1;
1302*fcf5ef2aSThomas Huth     t0 = tcg_temp_new();
1303*fcf5ef2aSThomas Huth     t1 = tcg_temp_new();
1304*fcf5ef2aSThomas Huth 
1305*fcf5ef2aSThomas Huth     tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_EE);
1306*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t1, t1, ~MSR_EIP);
1307*fcf5ef2aSThomas Huth     tcg_gen_shri_tl(t0, t1, 1);
1308*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
1309*fcf5ef2aSThomas Huth 
1310*fcf5ef2aSThomas Huth     tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
1311*fcf5ef2aSThomas Huth     tcg_gen_or_tl(t1, t1, t0);
1312*fcf5ef2aSThomas Huth     msr_write(dc, t1);
1313*fcf5ef2aSThomas Huth     tcg_temp_free(t1);
1314*fcf5ef2aSThomas Huth     tcg_temp_free(t0);
1315*fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1316*fcf5ef2aSThomas Huth }
1317*fcf5ef2aSThomas Huth 
1318*fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc)
1319*fcf5ef2aSThomas Huth {
1320*fcf5ef2aSThomas Huth     unsigned int b_bit, i_bit, e_bit;
1321*fcf5ef2aSThomas Huth     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
1322*fcf5ef2aSThomas Huth 
1323*fcf5ef2aSThomas Huth     i_bit = dc->ir & (1 << 21);
1324*fcf5ef2aSThomas Huth     b_bit = dc->ir & (1 << 22);
1325*fcf5ef2aSThomas Huth     e_bit = dc->ir & (1 << 23);
1326*fcf5ef2aSThomas Huth 
1327*fcf5ef2aSThomas Huth     dc->delayed_branch = 2;
1328*fcf5ef2aSThomas Huth     dc->tb_flags |= D_FLAG;
1329*fcf5ef2aSThomas Huth     tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
1330*fcf5ef2aSThomas Huth                   cpu_env, offsetof(CPUMBState, bimm));
1331*fcf5ef2aSThomas Huth 
1332*fcf5ef2aSThomas Huth     if (i_bit) {
1333*fcf5ef2aSThomas Huth         LOG_DIS("rtid ir=%x\n", dc->ir);
1334*fcf5ef2aSThomas Huth         if ((dc->tb_flags & MSR_EE_FLAG)
1335*fcf5ef2aSThomas Huth              && mem_index == MMU_USER_IDX) {
1336*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1337*fcf5ef2aSThomas Huth             t_gen_raise_exception(dc, EXCP_HW_EXCP);
1338*fcf5ef2aSThomas Huth         }
1339*fcf5ef2aSThomas Huth         dc->tb_flags |= DRTI_FLAG;
1340*fcf5ef2aSThomas Huth     } else if (b_bit) {
1341*fcf5ef2aSThomas Huth         LOG_DIS("rtbd ir=%x\n", dc->ir);
1342*fcf5ef2aSThomas Huth         if ((dc->tb_flags & MSR_EE_FLAG)
1343*fcf5ef2aSThomas Huth              && mem_index == MMU_USER_IDX) {
1344*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1345*fcf5ef2aSThomas Huth             t_gen_raise_exception(dc, EXCP_HW_EXCP);
1346*fcf5ef2aSThomas Huth         }
1347*fcf5ef2aSThomas Huth         dc->tb_flags |= DRTB_FLAG;
1348*fcf5ef2aSThomas Huth     } else if (e_bit) {
1349*fcf5ef2aSThomas Huth         LOG_DIS("rted ir=%x\n", dc->ir);
1350*fcf5ef2aSThomas Huth         if ((dc->tb_flags & MSR_EE_FLAG)
1351*fcf5ef2aSThomas Huth              && mem_index == MMU_USER_IDX) {
1352*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1353*fcf5ef2aSThomas Huth             t_gen_raise_exception(dc, EXCP_HW_EXCP);
1354*fcf5ef2aSThomas Huth         }
1355*fcf5ef2aSThomas Huth         dc->tb_flags |= DRTE_FLAG;
1356*fcf5ef2aSThomas Huth     } else
1357*fcf5ef2aSThomas Huth         LOG_DIS("rts ir=%x\n", dc->ir);
1358*fcf5ef2aSThomas Huth 
1359*fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
1360*fcf5ef2aSThomas Huth     tcg_gen_movi_tl(env_btaken, 1);
1361*fcf5ef2aSThomas Huth     tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
1362*fcf5ef2aSThomas Huth }
1363*fcf5ef2aSThomas Huth 
1364*fcf5ef2aSThomas Huth static int dec_check_fpuv2(DisasContext *dc)
1365*fcf5ef2aSThomas Huth {
1366*fcf5ef2aSThomas Huth     if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) {
1367*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_FPU);
1368*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
1369*fcf5ef2aSThomas Huth     }
1370*fcf5ef2aSThomas Huth     return (dc->cpu->cfg.use_fpu == 2) ? 0 : PVR2_USE_FPU2_MASK;
1371*fcf5ef2aSThomas Huth }
1372*fcf5ef2aSThomas Huth 
1373*fcf5ef2aSThomas Huth static void dec_fpu(DisasContext *dc)
1374*fcf5ef2aSThomas Huth {
1375*fcf5ef2aSThomas Huth     unsigned int fpu_insn;
1376*fcf5ef2aSThomas Huth 
1377*fcf5ef2aSThomas Huth     if ((dc->tb_flags & MSR_EE_FLAG)
1378*fcf5ef2aSThomas Huth           && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
1379*fcf5ef2aSThomas Huth           && (dc->cpu->cfg.use_fpu != 1)) {
1380*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1381*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
1382*fcf5ef2aSThomas Huth         return;
1383*fcf5ef2aSThomas Huth     }
1384*fcf5ef2aSThomas Huth 
1385*fcf5ef2aSThomas Huth     fpu_insn = (dc->ir >> 7) & 7;
1386*fcf5ef2aSThomas Huth 
1387*fcf5ef2aSThomas Huth     switch (fpu_insn) {
1388*fcf5ef2aSThomas Huth         case 0:
1389*fcf5ef2aSThomas Huth             gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1390*fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1391*fcf5ef2aSThomas Huth             break;
1392*fcf5ef2aSThomas Huth 
1393*fcf5ef2aSThomas Huth         case 1:
1394*fcf5ef2aSThomas Huth             gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1395*fcf5ef2aSThomas Huth                              cpu_R[dc->rb]);
1396*fcf5ef2aSThomas Huth             break;
1397*fcf5ef2aSThomas Huth 
1398*fcf5ef2aSThomas Huth         case 2:
1399*fcf5ef2aSThomas Huth             gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1400*fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1401*fcf5ef2aSThomas Huth             break;
1402*fcf5ef2aSThomas Huth 
1403*fcf5ef2aSThomas Huth         case 3:
1404*fcf5ef2aSThomas Huth             gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1405*fcf5ef2aSThomas Huth                             cpu_R[dc->rb]);
1406*fcf5ef2aSThomas Huth             break;
1407*fcf5ef2aSThomas Huth 
1408*fcf5ef2aSThomas Huth         case 4:
1409*fcf5ef2aSThomas Huth             switch ((dc->ir >> 4) & 7) {
1410*fcf5ef2aSThomas Huth                 case 0:
1411*fcf5ef2aSThomas Huth                     gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env,
1412*fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1413*fcf5ef2aSThomas Huth                     break;
1414*fcf5ef2aSThomas Huth                 case 1:
1415*fcf5ef2aSThomas Huth                     gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env,
1416*fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1417*fcf5ef2aSThomas Huth                     break;
1418*fcf5ef2aSThomas Huth                 case 2:
1419*fcf5ef2aSThomas Huth                     gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env,
1420*fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1421*fcf5ef2aSThomas Huth                     break;
1422*fcf5ef2aSThomas Huth                 case 3:
1423*fcf5ef2aSThomas Huth                     gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env,
1424*fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1425*fcf5ef2aSThomas Huth                     break;
1426*fcf5ef2aSThomas Huth                 case 4:
1427*fcf5ef2aSThomas Huth                     gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env,
1428*fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1429*fcf5ef2aSThomas Huth                     break;
1430*fcf5ef2aSThomas Huth                 case 5:
1431*fcf5ef2aSThomas Huth                     gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env,
1432*fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1433*fcf5ef2aSThomas Huth                     break;
1434*fcf5ef2aSThomas Huth                 case 6:
1435*fcf5ef2aSThomas Huth                     gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env,
1436*fcf5ef2aSThomas Huth                                        cpu_R[dc->ra], cpu_R[dc->rb]);
1437*fcf5ef2aSThomas Huth                     break;
1438*fcf5ef2aSThomas Huth                 default:
1439*fcf5ef2aSThomas Huth                     qemu_log_mask(LOG_UNIMP,
1440*fcf5ef2aSThomas Huth                                   "unimplemented fcmp fpu_insn=%x pc=%x"
1441*fcf5ef2aSThomas Huth                                   " opc=%x\n",
1442*fcf5ef2aSThomas Huth                                   fpu_insn, dc->pc, dc->opcode);
1443*fcf5ef2aSThomas Huth                     dc->abort_at_next_insn = 1;
1444*fcf5ef2aSThomas Huth                     break;
1445*fcf5ef2aSThomas Huth             }
1446*fcf5ef2aSThomas Huth             break;
1447*fcf5ef2aSThomas Huth 
1448*fcf5ef2aSThomas Huth         case 5:
1449*fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1450*fcf5ef2aSThomas Huth                 return;
1451*fcf5ef2aSThomas Huth             }
1452*fcf5ef2aSThomas Huth             gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1453*fcf5ef2aSThomas Huth             break;
1454*fcf5ef2aSThomas Huth 
1455*fcf5ef2aSThomas Huth         case 6:
1456*fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1457*fcf5ef2aSThomas Huth                 return;
1458*fcf5ef2aSThomas Huth             }
1459*fcf5ef2aSThomas Huth             gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1460*fcf5ef2aSThomas Huth             break;
1461*fcf5ef2aSThomas Huth 
1462*fcf5ef2aSThomas Huth         case 7:
1463*fcf5ef2aSThomas Huth             if (!dec_check_fpuv2(dc)) {
1464*fcf5ef2aSThomas Huth                 return;
1465*fcf5ef2aSThomas Huth             }
1466*fcf5ef2aSThomas Huth             gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
1467*fcf5ef2aSThomas Huth             break;
1468*fcf5ef2aSThomas Huth 
1469*fcf5ef2aSThomas Huth         default:
1470*fcf5ef2aSThomas Huth             qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x"
1471*fcf5ef2aSThomas Huth                           " opc=%x\n",
1472*fcf5ef2aSThomas Huth                           fpu_insn, dc->pc, dc->opcode);
1473*fcf5ef2aSThomas Huth             dc->abort_at_next_insn = 1;
1474*fcf5ef2aSThomas Huth             break;
1475*fcf5ef2aSThomas Huth     }
1476*fcf5ef2aSThomas Huth }
1477*fcf5ef2aSThomas Huth 
1478*fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc)
1479*fcf5ef2aSThomas Huth {
1480*fcf5ef2aSThomas Huth     if ((dc->tb_flags & MSR_EE_FLAG)
1481*fcf5ef2aSThomas Huth           && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
1482*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1483*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
1484*fcf5ef2aSThomas Huth         return;
1485*fcf5ef2aSThomas Huth     }
1486*fcf5ef2aSThomas Huth     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
1487*fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 1;
1488*fcf5ef2aSThomas Huth }
1489*fcf5ef2aSThomas Huth 
1490*fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
1491*fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc)
1492*fcf5ef2aSThomas Huth {
1493*fcf5ef2aSThomas Huth     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
1494*fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1495*fcf5ef2aSThomas Huth     int ctrl;
1496*fcf5ef2aSThomas Huth 
1497*fcf5ef2aSThomas Huth     LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
1498*fcf5ef2aSThomas Huth             dc->type_b ? "" : "d", dc->imm);
1499*fcf5ef2aSThomas Huth 
1500*fcf5ef2aSThomas Huth     if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) {
1501*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1502*fcf5ef2aSThomas Huth         t_gen_raise_exception(dc, EXCP_HW_EXCP);
1503*fcf5ef2aSThomas Huth         return;
1504*fcf5ef2aSThomas Huth     }
1505*fcf5ef2aSThomas Huth 
1506*fcf5ef2aSThomas Huth     t_id = tcg_temp_new();
1507*fcf5ef2aSThomas Huth     if (dc->type_b) {
1508*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(t_id, dc->imm & 0xf);
1509*fcf5ef2aSThomas Huth         ctrl = dc->imm >> 10;
1510*fcf5ef2aSThomas Huth     } else {
1511*fcf5ef2aSThomas Huth         tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf);
1512*fcf5ef2aSThomas Huth         ctrl = dc->imm >> 5;
1513*fcf5ef2aSThomas Huth     }
1514*fcf5ef2aSThomas Huth 
1515*fcf5ef2aSThomas Huth     t_ctrl = tcg_const_tl(ctrl);
1516*fcf5ef2aSThomas Huth 
1517*fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1518*fcf5ef2aSThomas Huth         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1519*fcf5ef2aSThomas Huth     } else {
1520*fcf5ef2aSThomas Huth         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1521*fcf5ef2aSThomas Huth     }
1522*fcf5ef2aSThomas Huth     tcg_temp_free(t_id);
1523*fcf5ef2aSThomas Huth     tcg_temp_free(t_ctrl);
1524*fcf5ef2aSThomas Huth }
1525*fcf5ef2aSThomas Huth 
1526*fcf5ef2aSThomas Huth static struct decoder_info {
1527*fcf5ef2aSThomas Huth     struct {
1528*fcf5ef2aSThomas Huth         uint32_t bits;
1529*fcf5ef2aSThomas Huth         uint32_t mask;
1530*fcf5ef2aSThomas Huth     };
1531*fcf5ef2aSThomas Huth     void (*dec)(DisasContext *dc);
1532*fcf5ef2aSThomas Huth } decinfo[] = {
1533*fcf5ef2aSThomas Huth     {DEC_ADD, dec_add},
1534*fcf5ef2aSThomas Huth     {DEC_SUB, dec_sub},
1535*fcf5ef2aSThomas Huth     {DEC_AND, dec_and},
1536*fcf5ef2aSThomas Huth     {DEC_XOR, dec_xor},
1537*fcf5ef2aSThomas Huth     {DEC_OR, dec_or},
1538*fcf5ef2aSThomas Huth     {DEC_BIT, dec_bit},
1539*fcf5ef2aSThomas Huth     {DEC_BARREL, dec_barrel},
1540*fcf5ef2aSThomas Huth     {DEC_LD, dec_load},
1541*fcf5ef2aSThomas Huth     {DEC_ST, dec_store},
1542*fcf5ef2aSThomas Huth     {DEC_IMM, dec_imm},
1543*fcf5ef2aSThomas Huth     {DEC_BR, dec_br},
1544*fcf5ef2aSThomas Huth     {DEC_BCC, dec_bcc},
1545*fcf5ef2aSThomas Huth     {DEC_RTS, dec_rts},
1546*fcf5ef2aSThomas Huth     {DEC_FPU, dec_fpu},
1547*fcf5ef2aSThomas Huth     {DEC_MUL, dec_mul},
1548*fcf5ef2aSThomas Huth     {DEC_DIV, dec_div},
1549*fcf5ef2aSThomas Huth     {DEC_MSR, dec_msr},
1550*fcf5ef2aSThomas Huth     {DEC_STREAM, dec_stream},
1551*fcf5ef2aSThomas Huth     {{0, 0}, dec_null}
1552*fcf5ef2aSThomas Huth };
1553*fcf5ef2aSThomas Huth 
1554*fcf5ef2aSThomas Huth static inline void decode(DisasContext *dc, uint32_t ir)
1555*fcf5ef2aSThomas Huth {
1556*fcf5ef2aSThomas Huth     int i;
1557*fcf5ef2aSThomas Huth 
1558*fcf5ef2aSThomas Huth     dc->ir = ir;
1559*fcf5ef2aSThomas Huth     LOG_DIS("%8.8x\t", dc->ir);
1560*fcf5ef2aSThomas Huth 
1561*fcf5ef2aSThomas Huth     if (dc->ir)
1562*fcf5ef2aSThomas Huth         dc->nr_nops = 0;
1563*fcf5ef2aSThomas Huth     else {
1564*fcf5ef2aSThomas Huth         if ((dc->tb_flags & MSR_EE_FLAG)
1565*fcf5ef2aSThomas Huth               && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
1566*fcf5ef2aSThomas Huth               && (dc->cpu->env.pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
1567*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1568*fcf5ef2aSThomas Huth             t_gen_raise_exception(dc, EXCP_HW_EXCP);
1569*fcf5ef2aSThomas Huth             return;
1570*fcf5ef2aSThomas Huth         }
1571*fcf5ef2aSThomas Huth 
1572*fcf5ef2aSThomas Huth         LOG_DIS("nr_nops=%d\t", dc->nr_nops);
1573*fcf5ef2aSThomas Huth         dc->nr_nops++;
1574*fcf5ef2aSThomas Huth         if (dc->nr_nops > 4) {
1575*fcf5ef2aSThomas Huth             cpu_abort(CPU(dc->cpu), "fetching nop sequence\n");
1576*fcf5ef2aSThomas Huth         }
1577*fcf5ef2aSThomas Huth     }
1578*fcf5ef2aSThomas Huth     /* bit 2 seems to indicate insn type.  */
1579*fcf5ef2aSThomas Huth     dc->type_b = ir & (1 << 29);
1580*fcf5ef2aSThomas Huth 
1581*fcf5ef2aSThomas Huth     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1582*fcf5ef2aSThomas Huth     dc->rd = EXTRACT_FIELD(ir, 21, 25);
1583*fcf5ef2aSThomas Huth     dc->ra = EXTRACT_FIELD(ir, 16, 20);
1584*fcf5ef2aSThomas Huth     dc->rb = EXTRACT_FIELD(ir, 11, 15);
1585*fcf5ef2aSThomas Huth     dc->imm = EXTRACT_FIELD(ir, 0, 15);
1586*fcf5ef2aSThomas Huth 
1587*fcf5ef2aSThomas Huth     /* Large switch for all insns.  */
1588*fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1589*fcf5ef2aSThomas Huth         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1590*fcf5ef2aSThomas Huth             decinfo[i].dec(dc);
1591*fcf5ef2aSThomas Huth             break;
1592*fcf5ef2aSThomas Huth         }
1593*fcf5ef2aSThomas Huth     }
1594*fcf5ef2aSThomas Huth }
1595*fcf5ef2aSThomas Huth 
1596*fcf5ef2aSThomas Huth /* generate intermediate code for basic block 'tb'.  */
1597*fcf5ef2aSThomas Huth void gen_intermediate_code(CPUMBState *env, struct TranslationBlock *tb)
1598*fcf5ef2aSThomas Huth {
1599*fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = mb_env_get_cpu(env);
1600*fcf5ef2aSThomas Huth     CPUState *cs = CPU(cpu);
1601*fcf5ef2aSThomas Huth     uint32_t pc_start;
1602*fcf5ef2aSThomas Huth     struct DisasContext ctx;
1603*fcf5ef2aSThomas Huth     struct DisasContext *dc = &ctx;
1604*fcf5ef2aSThomas Huth     uint32_t next_page_start, org_flags;
1605*fcf5ef2aSThomas Huth     target_ulong npc;
1606*fcf5ef2aSThomas Huth     int num_insns;
1607*fcf5ef2aSThomas Huth     int max_insns;
1608*fcf5ef2aSThomas Huth 
1609*fcf5ef2aSThomas Huth     pc_start = tb->pc;
1610*fcf5ef2aSThomas Huth     dc->cpu = cpu;
1611*fcf5ef2aSThomas Huth     dc->tb = tb;
1612*fcf5ef2aSThomas Huth     org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
1613*fcf5ef2aSThomas Huth 
1614*fcf5ef2aSThomas Huth     dc->is_jmp = DISAS_NEXT;
1615*fcf5ef2aSThomas Huth     dc->jmp = 0;
1616*fcf5ef2aSThomas Huth     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
1617*fcf5ef2aSThomas Huth     if (dc->delayed_branch) {
1618*fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
1619*fcf5ef2aSThomas Huth     }
1620*fcf5ef2aSThomas Huth     dc->pc = pc_start;
1621*fcf5ef2aSThomas Huth     dc->singlestep_enabled = cs->singlestep_enabled;
1622*fcf5ef2aSThomas Huth     dc->cpustate_changed = 0;
1623*fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 0;
1624*fcf5ef2aSThomas Huth     dc->nr_nops = 0;
1625*fcf5ef2aSThomas Huth 
1626*fcf5ef2aSThomas Huth     if (pc_start & 3) {
1627*fcf5ef2aSThomas Huth         cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
1628*fcf5ef2aSThomas Huth     }
1629*fcf5ef2aSThomas Huth 
1630*fcf5ef2aSThomas Huth     next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
1631*fcf5ef2aSThomas Huth     num_insns = 0;
1632*fcf5ef2aSThomas Huth     max_insns = tb->cflags & CF_COUNT_MASK;
1633*fcf5ef2aSThomas Huth     if (max_insns == 0) {
1634*fcf5ef2aSThomas Huth         max_insns = CF_COUNT_MASK;
1635*fcf5ef2aSThomas Huth     }
1636*fcf5ef2aSThomas Huth     if (max_insns > TCG_MAX_INSNS) {
1637*fcf5ef2aSThomas Huth         max_insns = TCG_MAX_INSNS;
1638*fcf5ef2aSThomas Huth     }
1639*fcf5ef2aSThomas Huth 
1640*fcf5ef2aSThomas Huth     gen_tb_start(tb);
1641*fcf5ef2aSThomas Huth     do
1642*fcf5ef2aSThomas Huth     {
1643*fcf5ef2aSThomas Huth         tcg_gen_insn_start(dc->pc);
1644*fcf5ef2aSThomas Huth         num_insns++;
1645*fcf5ef2aSThomas Huth 
1646*fcf5ef2aSThomas Huth #if SIM_COMPAT
1647*fcf5ef2aSThomas Huth         if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1648*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
1649*fcf5ef2aSThomas Huth             gen_helper_debug();
1650*fcf5ef2aSThomas Huth         }
1651*fcf5ef2aSThomas Huth #endif
1652*fcf5ef2aSThomas Huth 
1653*fcf5ef2aSThomas Huth         if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
1654*fcf5ef2aSThomas Huth             t_gen_raise_exception(dc, EXCP_DEBUG);
1655*fcf5ef2aSThomas Huth             dc->is_jmp = DISAS_UPDATE;
1656*fcf5ef2aSThomas Huth             /* The address covered by the breakpoint must be included in
1657*fcf5ef2aSThomas Huth                [tb->pc, tb->pc + tb->size) in order to for it to be
1658*fcf5ef2aSThomas Huth                properly cleared -- thus we increment the PC here so that
1659*fcf5ef2aSThomas Huth                the logic setting tb->size below does the right thing.  */
1660*fcf5ef2aSThomas Huth             dc->pc += 4;
1661*fcf5ef2aSThomas Huth             break;
1662*fcf5ef2aSThomas Huth         }
1663*fcf5ef2aSThomas Huth 
1664*fcf5ef2aSThomas Huth         /* Pretty disas.  */
1665*fcf5ef2aSThomas Huth         LOG_DIS("%8.8x:\t", dc->pc);
1666*fcf5ef2aSThomas Huth 
1667*fcf5ef2aSThomas Huth         if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
1668*fcf5ef2aSThomas Huth             gen_io_start();
1669*fcf5ef2aSThomas Huth         }
1670*fcf5ef2aSThomas Huth 
1671*fcf5ef2aSThomas Huth         dc->clear_imm = 1;
1672*fcf5ef2aSThomas Huth         decode(dc, cpu_ldl_code(env, dc->pc));
1673*fcf5ef2aSThomas Huth         if (dc->clear_imm)
1674*fcf5ef2aSThomas Huth             dc->tb_flags &= ~IMM_FLAG;
1675*fcf5ef2aSThomas Huth         dc->pc += 4;
1676*fcf5ef2aSThomas Huth 
1677*fcf5ef2aSThomas Huth         if (dc->delayed_branch) {
1678*fcf5ef2aSThomas Huth             dc->delayed_branch--;
1679*fcf5ef2aSThomas Huth             if (!dc->delayed_branch) {
1680*fcf5ef2aSThomas Huth                 if (dc->tb_flags & DRTI_FLAG)
1681*fcf5ef2aSThomas Huth                     do_rti(dc);
1682*fcf5ef2aSThomas Huth                  if (dc->tb_flags & DRTB_FLAG)
1683*fcf5ef2aSThomas Huth                     do_rtb(dc);
1684*fcf5ef2aSThomas Huth                 if (dc->tb_flags & DRTE_FLAG)
1685*fcf5ef2aSThomas Huth                     do_rte(dc);
1686*fcf5ef2aSThomas Huth                 /* Clear the delay slot flag.  */
1687*fcf5ef2aSThomas Huth                 dc->tb_flags &= ~D_FLAG;
1688*fcf5ef2aSThomas Huth                 /* If it is a direct jump, try direct chaining.  */
1689*fcf5ef2aSThomas Huth                 if (dc->jmp == JMP_INDIRECT) {
1690*fcf5ef2aSThomas Huth                     eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
1691*fcf5ef2aSThomas Huth                     dc->is_jmp = DISAS_JUMP;
1692*fcf5ef2aSThomas Huth                 } else if (dc->jmp == JMP_DIRECT) {
1693*fcf5ef2aSThomas Huth                     t_sync_flags(dc);
1694*fcf5ef2aSThomas Huth                     gen_goto_tb(dc, 0, dc->jmp_pc);
1695*fcf5ef2aSThomas Huth                     dc->is_jmp = DISAS_TB_JUMP;
1696*fcf5ef2aSThomas Huth                 } else if (dc->jmp == JMP_DIRECT_CC) {
1697*fcf5ef2aSThomas Huth                     TCGLabel *l1 = gen_new_label();
1698*fcf5ef2aSThomas Huth                     t_sync_flags(dc);
1699*fcf5ef2aSThomas Huth                     /* Conditional jmp.  */
1700*fcf5ef2aSThomas Huth                     tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);
1701*fcf5ef2aSThomas Huth                     gen_goto_tb(dc, 1, dc->pc);
1702*fcf5ef2aSThomas Huth                     gen_set_label(l1);
1703*fcf5ef2aSThomas Huth                     gen_goto_tb(dc, 0, dc->jmp_pc);
1704*fcf5ef2aSThomas Huth 
1705*fcf5ef2aSThomas Huth                     dc->is_jmp = DISAS_TB_JUMP;
1706*fcf5ef2aSThomas Huth                 }
1707*fcf5ef2aSThomas Huth                 break;
1708*fcf5ef2aSThomas Huth             }
1709*fcf5ef2aSThomas Huth         }
1710*fcf5ef2aSThomas Huth         if (cs->singlestep_enabled) {
1711*fcf5ef2aSThomas Huth             break;
1712*fcf5ef2aSThomas Huth         }
1713*fcf5ef2aSThomas Huth     } while (!dc->is_jmp && !dc->cpustate_changed
1714*fcf5ef2aSThomas Huth              && !tcg_op_buf_full()
1715*fcf5ef2aSThomas Huth              && !singlestep
1716*fcf5ef2aSThomas Huth              && (dc->pc < next_page_start)
1717*fcf5ef2aSThomas Huth              && num_insns < max_insns);
1718*fcf5ef2aSThomas Huth 
1719*fcf5ef2aSThomas Huth     npc = dc->pc;
1720*fcf5ef2aSThomas Huth     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
1721*fcf5ef2aSThomas Huth         if (dc->tb_flags & D_FLAG) {
1722*fcf5ef2aSThomas Huth             dc->is_jmp = DISAS_UPDATE;
1723*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
1724*fcf5ef2aSThomas Huth             sync_jmpstate(dc);
1725*fcf5ef2aSThomas Huth         } else
1726*fcf5ef2aSThomas Huth             npc = dc->jmp_pc;
1727*fcf5ef2aSThomas Huth     }
1728*fcf5ef2aSThomas Huth 
1729*fcf5ef2aSThomas Huth     if (tb->cflags & CF_LAST_IO)
1730*fcf5ef2aSThomas Huth         gen_io_end();
1731*fcf5ef2aSThomas Huth     /* Force an update if the per-tb cpu state has changed.  */
1732*fcf5ef2aSThomas Huth     if (dc->is_jmp == DISAS_NEXT
1733*fcf5ef2aSThomas Huth         && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
1734*fcf5ef2aSThomas Huth         dc->is_jmp = DISAS_UPDATE;
1735*fcf5ef2aSThomas Huth         tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
1736*fcf5ef2aSThomas Huth     }
1737*fcf5ef2aSThomas Huth     t_sync_flags(dc);
1738*fcf5ef2aSThomas Huth 
1739*fcf5ef2aSThomas Huth     if (unlikely(cs->singlestep_enabled)) {
1740*fcf5ef2aSThomas Huth         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1741*fcf5ef2aSThomas Huth 
1742*fcf5ef2aSThomas Huth         if (dc->is_jmp != DISAS_JUMP) {
1743*fcf5ef2aSThomas Huth             tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
1744*fcf5ef2aSThomas Huth         }
1745*fcf5ef2aSThomas Huth         gen_helper_raise_exception(cpu_env, tmp);
1746*fcf5ef2aSThomas Huth         tcg_temp_free_i32(tmp);
1747*fcf5ef2aSThomas Huth     } else {
1748*fcf5ef2aSThomas Huth         switch(dc->is_jmp) {
1749*fcf5ef2aSThomas Huth             case DISAS_NEXT:
1750*fcf5ef2aSThomas Huth                 gen_goto_tb(dc, 1, npc);
1751*fcf5ef2aSThomas Huth                 break;
1752*fcf5ef2aSThomas Huth             default:
1753*fcf5ef2aSThomas Huth             case DISAS_JUMP:
1754*fcf5ef2aSThomas Huth             case DISAS_UPDATE:
1755*fcf5ef2aSThomas Huth                 /* indicate that the hash table must be used
1756*fcf5ef2aSThomas Huth                    to find the next TB */
1757*fcf5ef2aSThomas Huth                 tcg_gen_exit_tb(0);
1758*fcf5ef2aSThomas Huth                 break;
1759*fcf5ef2aSThomas Huth             case DISAS_TB_JUMP:
1760*fcf5ef2aSThomas Huth                 /* nothing more to generate */
1761*fcf5ef2aSThomas Huth                 break;
1762*fcf5ef2aSThomas Huth         }
1763*fcf5ef2aSThomas Huth     }
1764*fcf5ef2aSThomas Huth     gen_tb_end(tb, num_insns);
1765*fcf5ef2aSThomas Huth 
1766*fcf5ef2aSThomas Huth     tb->size = dc->pc - pc_start;
1767*fcf5ef2aSThomas Huth     tb->icount = num_insns;
1768*fcf5ef2aSThomas Huth 
1769*fcf5ef2aSThomas Huth #ifdef DEBUG_DISAS
1770*fcf5ef2aSThomas Huth #if !SIM_COMPAT
1771*fcf5ef2aSThomas Huth     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
1772*fcf5ef2aSThomas Huth         && qemu_log_in_addr_range(pc_start)) {
1773*fcf5ef2aSThomas Huth         qemu_log_lock();
1774*fcf5ef2aSThomas Huth         qemu_log("--------------\n");
1775*fcf5ef2aSThomas Huth #if DISAS_GNU
1776*fcf5ef2aSThomas Huth         log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
1777*fcf5ef2aSThomas Huth #endif
1778*fcf5ef2aSThomas Huth         qemu_log("\nisize=%d osize=%d\n",
1779*fcf5ef2aSThomas Huth                  dc->pc - pc_start, tcg_op_buf_count());
1780*fcf5ef2aSThomas Huth         qemu_log_unlock();
1781*fcf5ef2aSThomas Huth     }
1782*fcf5ef2aSThomas Huth #endif
1783*fcf5ef2aSThomas Huth #endif
1784*fcf5ef2aSThomas Huth     assert(!dc->abort_at_next_insn);
1785*fcf5ef2aSThomas Huth }
1786*fcf5ef2aSThomas Huth 
1787*fcf5ef2aSThomas Huth void mb_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
1788*fcf5ef2aSThomas Huth                        int flags)
1789*fcf5ef2aSThomas Huth {
1790*fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1791*fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
1792*fcf5ef2aSThomas Huth     int i;
1793*fcf5ef2aSThomas Huth 
1794*fcf5ef2aSThomas Huth     if (!env || !f)
1795*fcf5ef2aSThomas Huth         return;
1796*fcf5ef2aSThomas Huth 
1797*fcf5ef2aSThomas Huth     cpu_fprintf(f, "IN: PC=%x %s\n",
1798*fcf5ef2aSThomas Huth                 env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC]));
1799*fcf5ef2aSThomas Huth     cpu_fprintf(f, "rmsr=%x resr=%x rear=%x debug=%x imm=%x iflags=%x fsr=%x\n",
1800*fcf5ef2aSThomas Huth              env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
1801*fcf5ef2aSThomas Huth              env->debug, env->imm, env->iflags, env->sregs[SR_FSR]);
1802*fcf5ef2aSThomas Huth     cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
1803*fcf5ef2aSThomas Huth              env->btaken, env->btarget,
1804*fcf5ef2aSThomas Huth              (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
1805*fcf5ef2aSThomas Huth              (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
1806*fcf5ef2aSThomas Huth              (env->sregs[SR_MSR] & MSR_EIP),
1807*fcf5ef2aSThomas Huth              (env->sregs[SR_MSR] & MSR_IE));
1808*fcf5ef2aSThomas Huth 
1809*fcf5ef2aSThomas Huth     for (i = 0; i < 32; i++) {
1810*fcf5ef2aSThomas Huth         cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1811*fcf5ef2aSThomas Huth         if ((i + 1) % 4 == 0)
1812*fcf5ef2aSThomas Huth             cpu_fprintf(f, "\n");
1813*fcf5ef2aSThomas Huth         }
1814*fcf5ef2aSThomas Huth     cpu_fprintf(f, "\n\n");
1815*fcf5ef2aSThomas Huth }
1816*fcf5ef2aSThomas Huth 
1817*fcf5ef2aSThomas Huth MicroBlazeCPU *cpu_mb_init(const char *cpu_model)
1818*fcf5ef2aSThomas Huth {
1819*fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu;
1820*fcf5ef2aSThomas Huth 
1821*fcf5ef2aSThomas Huth     cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
1822*fcf5ef2aSThomas Huth 
1823*fcf5ef2aSThomas Huth     object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
1824*fcf5ef2aSThomas Huth 
1825*fcf5ef2aSThomas Huth     return cpu;
1826*fcf5ef2aSThomas Huth }
1827*fcf5ef2aSThomas Huth 
1828*fcf5ef2aSThomas Huth void mb_tcg_init(void)
1829*fcf5ef2aSThomas Huth {
1830*fcf5ef2aSThomas Huth     int i;
1831*fcf5ef2aSThomas Huth 
1832*fcf5ef2aSThomas Huth     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
1833*fcf5ef2aSThomas Huth     tcg_ctx.tcg_env = cpu_env;
1834*fcf5ef2aSThomas Huth 
1835*fcf5ef2aSThomas Huth     env_debug = tcg_global_mem_new(cpu_env,
1836*fcf5ef2aSThomas Huth                     offsetof(CPUMBState, debug),
1837*fcf5ef2aSThomas Huth                     "debug0");
1838*fcf5ef2aSThomas Huth     env_iflags = tcg_global_mem_new(cpu_env,
1839*fcf5ef2aSThomas Huth                     offsetof(CPUMBState, iflags),
1840*fcf5ef2aSThomas Huth                     "iflags");
1841*fcf5ef2aSThomas Huth     env_imm = tcg_global_mem_new(cpu_env,
1842*fcf5ef2aSThomas Huth                     offsetof(CPUMBState, imm),
1843*fcf5ef2aSThomas Huth                     "imm");
1844*fcf5ef2aSThomas Huth     env_btarget = tcg_global_mem_new(cpu_env,
1845*fcf5ef2aSThomas Huth                      offsetof(CPUMBState, btarget),
1846*fcf5ef2aSThomas Huth                      "btarget");
1847*fcf5ef2aSThomas Huth     env_btaken = tcg_global_mem_new(cpu_env,
1848*fcf5ef2aSThomas Huth                      offsetof(CPUMBState, btaken),
1849*fcf5ef2aSThomas Huth                      "btaken");
1850*fcf5ef2aSThomas Huth     env_res_addr = tcg_global_mem_new(cpu_env,
1851*fcf5ef2aSThomas Huth                      offsetof(CPUMBState, res_addr),
1852*fcf5ef2aSThomas Huth                      "res_addr");
1853*fcf5ef2aSThomas Huth     env_res_val = tcg_global_mem_new(cpu_env,
1854*fcf5ef2aSThomas Huth                      offsetof(CPUMBState, res_val),
1855*fcf5ef2aSThomas Huth                      "res_val");
1856*fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
1857*fcf5ef2aSThomas Huth         cpu_R[i] = tcg_global_mem_new(cpu_env,
1858*fcf5ef2aSThomas Huth                           offsetof(CPUMBState, regs[i]),
1859*fcf5ef2aSThomas Huth                           regnames[i]);
1860*fcf5ef2aSThomas Huth     }
1861*fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) {
1862*fcf5ef2aSThomas Huth         cpu_SR[i] = tcg_global_mem_new(cpu_env,
1863*fcf5ef2aSThomas Huth                           offsetof(CPUMBState, sregs[i]),
1864*fcf5ef2aSThomas Huth                           special_regnames[i]);
1865*fcf5ef2aSThomas Huth     }
1866*fcf5ef2aSThomas Huth }
1867*fcf5ef2aSThomas Huth 
1868*fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1869*fcf5ef2aSThomas Huth                           target_ulong *data)
1870*fcf5ef2aSThomas Huth {
1871*fcf5ef2aSThomas Huth     env->sregs[SR_PC] = data[0];
1872*fcf5ef2aSThomas Huth }
1873