1 /*
2 * Xilinx MicroBlaze emulation for qemu: main translation routines.
3 *
4 * Copyright (c) 2009 Edgar E. Iglesias.
5 * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/exec-all.h"
24 #include "exec/cpu_ldst.h"
25 #include "tcg/tcg-op.h"
26 #include "exec/helper-proto.h"
27 #include "exec/helper-gen.h"
28 #include "exec/translator.h"
29 #include "qemu/qemu-print.h"
30
31 #include "exec/log.h"
32
33 #define HELPER_H "helper.h"
34 #include "exec/helper-info.c.inc"
35 #undef HELPER_H
36
37 #define EXTRACT_FIELD(src, start, end) \
38 (((src) >> start) & ((1 << (end - start + 1)) - 1))
39
40 /* is_jmp field values */
41 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
42 #define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */
43
44 /* cpu state besides pc was modified dynamically; update pc to next */
45 #define DISAS_EXIT_NEXT DISAS_TARGET_2
46 /* cpu state besides pc was modified dynamically; update pc to btarget */
47 #define DISAS_EXIT_JUMP DISAS_TARGET_3
48
49 static TCGv_i32 cpu_R[32];
50 static TCGv_i32 cpu_pc;
51 static TCGv_i32 cpu_msr;
52 static TCGv_i32 cpu_msr_c;
53 static TCGv_i32 cpu_imm;
54 static TCGv_i32 cpu_bvalue;
55 static TCGv_i32 cpu_btarget;
56 static TCGv_i32 cpu_iflags;
57 static TCGv cpu_res_addr;
58 static TCGv_i32 cpu_res_val;
59
60 /* This is the state at translation time. */
61 typedef struct DisasContext {
62 DisasContextBase base;
63 const MicroBlazeCPUConfig *cfg;
64
65 TCGv_i32 r0;
66 bool r0_set;
67
68 /* Decoder. */
69 uint32_t ext_imm;
70 unsigned int tb_flags;
71 unsigned int tb_flags_to_set;
72 int mem_index;
73
74 /* Condition under which to jump, including NEVER and ALWAYS. */
75 TCGCond jmp_cond;
76
77 /* Immediate branch-taken destination, or -1 for indirect. */
78 uint32_t jmp_dest;
79 } DisasContext;
80
typeb_imm(DisasContext * dc,int x)81 static int typeb_imm(DisasContext *dc, int x)
82 {
83 if (dc->tb_flags & IMM_FLAG) {
84 return deposit32(dc->ext_imm, 0, 16, x);
85 }
86 return x;
87 }
88
89 /* Include the auto-generated decoder. */
90 #include "decode-insns.c.inc"
91
t_sync_flags(DisasContext * dc)92 static void t_sync_flags(DisasContext *dc)
93 {
94 /* Synch the tb dependent flags between translator and runtime. */
95 if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
96 tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
97 }
98 }
99
gen_raise_exception(DisasContext * dc,uint32_t index)100 static void gen_raise_exception(DisasContext *dc, uint32_t index)
101 {
102 gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
103 dc->base.is_jmp = DISAS_NORETURN;
104 }
105
gen_raise_exception_sync(DisasContext * dc,uint32_t index)106 static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
107 {
108 t_sync_flags(dc);
109 tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
110 gen_raise_exception(dc, index);
111 }
112
gen_raise_hw_excp(DisasContext * dc,uint32_t esr_ec)113 static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
114 {
115 TCGv_i32 tmp = tcg_constant_i32(esr_ec);
116 tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUMBState, esr));
117
118 gen_raise_exception_sync(dc, EXCP_HW_EXCP);
119 }
120
gen_goto_tb(DisasContext * dc,int n,target_ulong dest)121 static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
122 {
123 if (translator_use_goto_tb(&dc->base, dest)) {
124 tcg_gen_goto_tb(n);
125 tcg_gen_movi_i32(cpu_pc, dest);
126 tcg_gen_exit_tb(dc->base.tb, n);
127 } else {
128 tcg_gen_movi_i32(cpu_pc, dest);
129 tcg_gen_lookup_and_goto_ptr();
130 }
131 dc->base.is_jmp = DISAS_NORETURN;
132 }
133
134 /*
135 * Returns true if the insn an illegal operation.
136 * If exceptions are enabled, an exception is raised.
137 */
trap_illegal(DisasContext * dc,bool cond)138 static bool trap_illegal(DisasContext *dc, bool cond)
139 {
140 if (cond && (dc->tb_flags & MSR_EE)
141 && dc->cfg->illegal_opcode_exception) {
142 gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
143 }
144 return cond;
145 }
146
147 /*
148 * Returns true if the insn is illegal in userspace.
149 * If exceptions are enabled, an exception is raised.
150 */
trap_userspace(DisasContext * dc,bool cond)151 static bool trap_userspace(DisasContext *dc, bool cond)
152 {
153 bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
154
155 if (cond_user && (dc->tb_flags & MSR_EE)) {
156 gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
157 }
158 return cond_user;
159 }
160
161 /*
162 * Return true, and log an error, if the current insn is
163 * within a delay slot.
164 */
invalid_delay_slot(DisasContext * dc,const char * insn_type)165 static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
166 {
167 if (dc->tb_flags & D_FLAG) {
168 qemu_log_mask(LOG_GUEST_ERROR,
169 "Invalid insn in delay slot: %s at %08x\n",
170 insn_type, (uint32_t)dc->base.pc_next);
171 return true;
172 }
173 return false;
174 }
175
reg_for_read(DisasContext * dc,int reg)176 static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
177 {
178 if (likely(reg != 0)) {
179 return cpu_R[reg];
180 }
181 if (!dc->r0_set) {
182 if (dc->r0 == NULL) {
183 dc->r0 = tcg_temp_new_i32();
184 }
185 tcg_gen_movi_i32(dc->r0, 0);
186 dc->r0_set = true;
187 }
188 return dc->r0;
189 }
190
reg_for_write(DisasContext * dc,int reg)191 static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
192 {
193 if (likely(reg != 0)) {
194 return cpu_R[reg];
195 }
196 if (dc->r0 == NULL) {
197 dc->r0 = tcg_temp_new_i32();
198 }
199 return dc->r0;
200 }
201
do_typea(DisasContext * dc,arg_typea * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32,TCGv_i32))202 static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
203 void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
204 {
205 TCGv_i32 rd, ra, rb;
206
207 if (arg->rd == 0 && !side_effects) {
208 return true;
209 }
210
211 rd = reg_for_write(dc, arg->rd);
212 ra = reg_for_read(dc, arg->ra);
213 rb = reg_for_read(dc, arg->rb);
214 fn(rd, ra, rb);
215 return true;
216 }
217
do_typea0(DisasContext * dc,arg_typea0 * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32))218 static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
219 void (*fn)(TCGv_i32, TCGv_i32))
220 {
221 TCGv_i32 rd, ra;
222
223 if (arg->rd == 0 && !side_effects) {
224 return true;
225 }
226
227 rd = reg_for_write(dc, arg->rd);
228 ra = reg_for_read(dc, arg->ra);
229 fn(rd, ra);
230 return true;
231 }
232
do_typeb_imm(DisasContext * dc,arg_typeb * arg,bool side_effects,void (* fni)(TCGv_i32,TCGv_i32,int32_t))233 static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
234 void (*fni)(TCGv_i32, TCGv_i32, int32_t))
235 {
236 TCGv_i32 rd, ra;
237
238 if (arg->rd == 0 && !side_effects) {
239 return true;
240 }
241
242 rd = reg_for_write(dc, arg->rd);
243 ra = reg_for_read(dc, arg->ra);
244 fni(rd, ra, arg->imm);
245 return true;
246 }
247
do_typeb_val(DisasContext * dc,arg_typeb * arg,bool side_effects,void (* fn)(TCGv_i32,TCGv_i32,TCGv_i32))248 static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
249 void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
250 {
251 TCGv_i32 rd, ra, imm;
252
253 if (arg->rd == 0 && !side_effects) {
254 return true;
255 }
256
257 rd = reg_for_write(dc, arg->rd);
258 ra = reg_for_read(dc, arg->ra);
259 imm = tcg_constant_i32(arg->imm);
260
261 fn(rd, ra, imm);
262 return true;
263 }
264
265 #define DO_TYPEA(NAME, SE, FN) \
266 static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
267 { return do_typea(dc, a, SE, FN); }
268
269 #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
270 static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
271 { return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
272
273 #define DO_TYPEA0(NAME, SE, FN) \
274 static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
275 { return do_typea0(dc, a, SE, FN); }
276
277 #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
278 static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
279 { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
280
281 #define DO_TYPEBI(NAME, SE, FNI) \
282 static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
283 { return do_typeb_imm(dc, a, SE, FNI); }
284
285 #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
286 static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
287 { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
288
289 #define DO_TYPEBV(NAME, SE, FN) \
290 static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
291 { return do_typeb_val(dc, a, SE, FN); }
292
293 #define ENV_WRAPPER2(NAME, HELPER) \
294 static void NAME(TCGv_i32 out, TCGv_i32 ina) \
295 { HELPER(out, tcg_env, ina); }
296
297 #define ENV_WRAPPER3(NAME, HELPER) \
298 static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
299 { HELPER(out, tcg_env, ina, inb); }
300
301 /* No input carry, but output carry. */
gen_add(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)302 static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
303 {
304 TCGv_i32 zero = tcg_constant_i32(0);
305
306 tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
307 }
308
309 /* Input and output carry. */
gen_addc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)310 static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
311 {
312 TCGv_i32 zero = tcg_constant_i32(0);
313 TCGv_i32 tmp = tcg_temp_new_i32();
314
315 tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
316 tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
317 }
318
319 /* Input carry, but no output carry. */
gen_addkc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)320 static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
321 {
322 tcg_gen_add_i32(out, ina, inb);
323 tcg_gen_add_i32(out, out, cpu_msr_c);
324 }
325
DO_TYPEA(add,true,gen_add)326 DO_TYPEA(add, true, gen_add)
327 DO_TYPEA(addc, true, gen_addc)
328 DO_TYPEA(addk, false, tcg_gen_add_i32)
329 DO_TYPEA(addkc, true, gen_addkc)
330
331 DO_TYPEBV(addi, true, gen_add)
332 DO_TYPEBV(addic, true, gen_addc)
333 DO_TYPEBI(addik, false, tcg_gen_addi_i32)
334 DO_TYPEBV(addikc, true, gen_addkc)
335
336 static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
337 {
338 tcg_gen_andi_i32(out, ina, ~imm);
339 }
340
DO_TYPEA(and,false,tcg_gen_and_i32)341 DO_TYPEA(and, false, tcg_gen_and_i32)
342 DO_TYPEBI(andi, false, tcg_gen_andi_i32)
343 DO_TYPEA(andn, false, tcg_gen_andc_i32)
344 DO_TYPEBI(andni, false, gen_andni)
345
346 static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
347 {
348 TCGv_i32 tmp = tcg_temp_new_i32();
349 tcg_gen_andi_i32(tmp, inb, 31);
350 tcg_gen_sar_i32(out, ina, tmp);
351 }
352
gen_bsrl(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)353 static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
354 {
355 TCGv_i32 tmp = tcg_temp_new_i32();
356 tcg_gen_andi_i32(tmp, inb, 31);
357 tcg_gen_shr_i32(out, ina, tmp);
358 }
359
gen_bsll(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)360 static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
361 {
362 TCGv_i32 tmp = tcg_temp_new_i32();
363 tcg_gen_andi_i32(tmp, inb, 31);
364 tcg_gen_shl_i32(out, ina, tmp);
365 }
366
gen_bsefi(TCGv_i32 out,TCGv_i32 ina,int32_t imm)367 static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
368 {
369 /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
370 int imm_w = extract32(imm, 5, 5);
371 int imm_s = extract32(imm, 0, 5);
372
373 if (imm_w + imm_s > 32 || imm_w == 0) {
374 /* These inputs have an undefined behavior. */
375 qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
376 imm_w, imm_s);
377 } else {
378 tcg_gen_extract_i32(out, ina, imm_s, imm_w);
379 }
380 }
381
gen_bsifi(TCGv_i32 out,TCGv_i32 ina,int32_t imm)382 static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
383 {
384 /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
385 int imm_w = extract32(imm, 5, 5);
386 int imm_s = extract32(imm, 0, 5);
387 int width = imm_w - imm_s + 1;
388
389 if (imm_w < imm_s) {
390 /* These inputs have an undefined behavior. */
391 qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
392 imm_w, imm_s);
393 } else {
394 tcg_gen_deposit_i32(out, out, ina, imm_s, width);
395 }
396 }
397
DO_TYPEA_CFG(bsra,use_barrel,false,gen_bsra)398 DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
399 DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
400 DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
401
402 DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
403 DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
404 DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
405
406 DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
407 DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
408
409 static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
410 {
411 tcg_gen_clzi_i32(out, ina, 32);
412 }
413
DO_TYPEA0_CFG(clz,use_pcmp_instr,false,gen_clz)414 DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
415
416 static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
417 {
418 TCGv_i32 lt = tcg_temp_new_i32();
419
420 tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
421 tcg_gen_sub_i32(out, inb, ina);
422 tcg_gen_deposit_i32(out, out, lt, 31, 1);
423 }
424
gen_cmpu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)425 static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
426 {
427 TCGv_i32 lt = tcg_temp_new_i32();
428
429 tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
430 tcg_gen_sub_i32(out, inb, ina);
431 tcg_gen_deposit_i32(out, out, lt, 31, 1);
432 }
433
DO_TYPEA(cmp,false,gen_cmp)434 DO_TYPEA(cmp, false, gen_cmp)
435 DO_TYPEA(cmpu, false, gen_cmpu)
436
437 ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
438 ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
439 ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
440 ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
441 ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
442 ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
443 ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
444 ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
445 ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
446 ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
447 ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
448
449 DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
450 DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
451 DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
452 DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
453 DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
454 DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
455 DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
456 DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
457 DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
458 DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
459 DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
460
461 ENV_WRAPPER2(gen_flt, gen_helper_flt)
462 ENV_WRAPPER2(gen_fint, gen_helper_fint)
463 ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
464
465 DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
466 DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
467 DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
468
469 /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
470 static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
471 {
472 gen_helper_divs(out, tcg_env, inb, ina);
473 }
474
gen_idivu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)475 static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
476 {
477 gen_helper_divu(out, tcg_env, inb, ina);
478 }
479
DO_TYPEA_CFG(idiv,use_div,true,gen_idiv)480 DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
481 DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
482
483 static bool trans_imm(DisasContext *dc, arg_imm *arg)
484 {
485 if (invalid_delay_slot(dc, "imm")) {
486 return true;
487 }
488 dc->ext_imm = arg->imm << 16;
489 tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
490 dc->tb_flags_to_set = IMM_FLAG;
491 return true;
492 }
493
gen_mulh(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)494 static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
495 {
496 TCGv_i32 tmp = tcg_temp_new_i32();
497 tcg_gen_muls2_i32(tmp, out, ina, inb);
498 }
499
gen_mulhu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)500 static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
501 {
502 TCGv_i32 tmp = tcg_temp_new_i32();
503 tcg_gen_mulu2_i32(tmp, out, ina, inb);
504 }
505
gen_mulhsu(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)506 static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
507 {
508 TCGv_i32 tmp = tcg_temp_new_i32();
509 tcg_gen_mulsu2_i32(tmp, out, ina, inb);
510 }
511
DO_TYPEA_CFG(mul,use_hw_mul,false,tcg_gen_mul_i32)512 DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
513 DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
514 DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
515 DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
516 DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
517
518 DO_TYPEA(or, false, tcg_gen_or_i32)
519 DO_TYPEBI(ori, false, tcg_gen_ori_i32)
520
521 static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
522 {
523 tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
524 }
525
gen_pcmpne(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)526 static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
527 {
528 tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
529 }
530
DO_TYPEA_CFG(pcmpbf,use_pcmp_instr,false,gen_helper_pcmpbf)531 DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
532 DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
533 DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
534
535 /* No input carry, but output carry. */
536 static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
537 {
538 tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
539 tcg_gen_sub_i32(out, inb, ina);
540 }
541
542 /* Input and output carry. */
gen_rsubc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)543 static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
544 {
545 TCGv_i32 zero = tcg_constant_i32(0);
546 TCGv_i32 tmp = tcg_temp_new_i32();
547
548 tcg_gen_not_i32(tmp, ina);
549 tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
550 tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
551 }
552
553 /* No input or output carry. */
gen_rsubk(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)554 static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
555 {
556 tcg_gen_sub_i32(out, inb, ina);
557 }
558
559 /* Input carry, no output carry. */
gen_rsubkc(TCGv_i32 out,TCGv_i32 ina,TCGv_i32 inb)560 static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
561 {
562 TCGv_i32 nota = tcg_temp_new_i32();
563
564 tcg_gen_not_i32(nota, ina);
565 tcg_gen_add_i32(out, inb, nota);
566 tcg_gen_add_i32(out, out, cpu_msr_c);
567 }
568
DO_TYPEA(rsub,true,gen_rsub)569 DO_TYPEA(rsub, true, gen_rsub)
570 DO_TYPEA(rsubc, true, gen_rsubc)
571 DO_TYPEA(rsubk, false, gen_rsubk)
572 DO_TYPEA(rsubkc, true, gen_rsubkc)
573
574 DO_TYPEBV(rsubi, true, gen_rsub)
575 DO_TYPEBV(rsubic, true, gen_rsubc)
576 DO_TYPEBV(rsubik, false, gen_rsubk)
577 DO_TYPEBV(rsubikc, true, gen_rsubkc)
578
579 DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
580 DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
581
582 static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
583 {
584 tcg_gen_andi_i32(cpu_msr_c, ina, 1);
585 tcg_gen_sari_i32(out, ina, 1);
586 }
587
gen_src(TCGv_i32 out,TCGv_i32 ina)588 static void gen_src(TCGv_i32 out, TCGv_i32 ina)
589 {
590 TCGv_i32 tmp = tcg_temp_new_i32();
591
592 tcg_gen_mov_i32(tmp, cpu_msr_c);
593 tcg_gen_andi_i32(cpu_msr_c, ina, 1);
594 tcg_gen_extract2_i32(out, ina, tmp, 1);
595 }
596
gen_srl(TCGv_i32 out,TCGv_i32 ina)597 static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
598 {
599 tcg_gen_andi_i32(cpu_msr_c, ina, 1);
600 tcg_gen_shri_i32(out, ina, 1);
601 }
602
DO_TYPEA0(sra,false,gen_sra)603 DO_TYPEA0(sra, false, gen_sra)
604 DO_TYPEA0(src, false, gen_src)
605 DO_TYPEA0(srl, false, gen_srl)
606
607 static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
608 {
609 tcg_gen_rotri_i32(out, ina, 16);
610 }
611
DO_TYPEA0(swapb,false,tcg_gen_bswap32_i32)612 DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
613 DO_TYPEA0(swaph, false, gen_swaph)
614
615 static bool trans_wdic(DisasContext *dc, arg_wdic *a)
616 {
617 /* Cache operations are nops: only check for supervisor mode. */
618 trap_userspace(dc, true);
619 return true;
620 }
621
DO_TYPEA(xor,false,tcg_gen_xor_i32)622 DO_TYPEA(xor, false, tcg_gen_xor_i32)
623 DO_TYPEBI(xori, false, tcg_gen_xori_i32)
624
625 static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
626 {
627 TCGv ret = tcg_temp_new();
628
629 /* If any of the regs is r0, set t to the value of the other reg. */
630 if (ra && rb) {
631 TCGv_i32 tmp = tcg_temp_new_i32();
632 tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
633 tcg_gen_extu_i32_tl(ret, tmp);
634 } else if (ra) {
635 tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
636 } else if (rb) {
637 tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
638 } else {
639 tcg_gen_movi_tl(ret, 0);
640 }
641
642 if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
643 gen_helper_stackprot(tcg_env, ret);
644 }
645 return ret;
646 }
647
compute_ldst_addr_typeb(DisasContext * dc,int ra,int imm)648 static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
649 {
650 TCGv ret = tcg_temp_new();
651
652 /* If any of the regs is r0, set t to the value of the other reg. */
653 if (ra) {
654 TCGv_i32 tmp = tcg_temp_new_i32();
655 tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
656 tcg_gen_extu_i32_tl(ret, tmp);
657 } else {
658 tcg_gen_movi_tl(ret, (uint32_t)imm);
659 }
660
661 if (ra == 1 && dc->cfg->stackprot) {
662 gen_helper_stackprot(tcg_env, ret);
663 }
664 return ret;
665 }
666
667 #ifndef CONFIG_USER_ONLY
compute_ldst_addr_ea(DisasContext * dc,int ra,int rb)668 static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
669 {
670 int addr_size = dc->cfg->addr_size;
671 TCGv ret = tcg_temp_new();
672
673 if (addr_size == 32 || ra == 0) {
674 if (rb) {
675 tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
676 } else {
677 tcg_gen_movi_tl(ret, 0);
678 }
679 } else {
680 if (rb) {
681 tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
682 } else {
683 tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
684 tcg_gen_shli_tl(ret, ret, 32);
685 }
686 if (addr_size < 64) {
687 /* Mask off out of range bits. */
688 tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
689 }
690 }
691 return ret;
692 }
693 #endif
694
695 #ifndef CONFIG_USER_ONLY
record_unaligned_ess(DisasContext * dc,int rd,MemOp size,bool store)696 static void record_unaligned_ess(DisasContext *dc, int rd,
697 MemOp size, bool store)
698 {
699 uint32_t iflags = tcg_get_insn_start_param(dc->base.insn_start, 1);
700
701 iflags |= ESR_ESS_FLAG;
702 iflags |= rd << 5;
703 iflags |= store * ESR_S;
704 iflags |= (size == MO_32) * ESR_W;
705
706 tcg_set_insn_start_param(dc->base.insn_start, 1, iflags);
707 }
708 #endif
709
do_load(DisasContext * dc,int rd,TCGv addr,MemOp mop,int mem_index,bool rev)710 static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
711 int mem_index, bool rev)
712 {
713 MemOp size = mop & MO_SIZE;
714
715 /*
716 * When doing reverse accesses we need to do two things.
717 *
718 * 1. Reverse the address wrt endianness.
719 * 2. Byteswap the data lanes on the way back into the CPU core.
720 */
721 if (rev) {
722 if (size > MO_8) {
723 mop ^= MO_BSWAP;
724 }
725 if (size < MO_32) {
726 tcg_gen_xori_tl(addr, addr, 3 - size);
727 }
728 }
729
730 /*
731 * For system mode, enforce alignment if the cpu configuration
732 * requires it. For user-mode, the Linux kernel will have fixed up
733 * any unaligned access, so emulate that by *not* setting MO_ALIGN.
734 */
735 #ifndef CONFIG_USER_ONLY
736 if (size > MO_8 &&
737 (dc->tb_flags & MSR_EE) &&
738 dc->cfg->unaligned_exceptions) {
739 record_unaligned_ess(dc, rd, size, false);
740 mop |= MO_ALIGN;
741 }
742 #endif
743
744 tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
745 return true;
746 }
747
trans_lbu(DisasContext * dc,arg_typea * arg)748 static bool trans_lbu(DisasContext *dc, arg_typea *arg)
749 {
750 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
751 return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
752 }
753
trans_lbur(DisasContext * dc,arg_typea * arg)754 static bool trans_lbur(DisasContext *dc, arg_typea *arg)
755 {
756 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
757 return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
758 }
759
trans_lbuea(DisasContext * dc,arg_typea * arg)760 static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
761 {
762 if (trap_userspace(dc, true)) {
763 return true;
764 }
765 #ifdef CONFIG_USER_ONLY
766 return true;
767 #else
768 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
769 return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
770 #endif
771 }
772
trans_lbui(DisasContext * dc,arg_typeb * arg)773 static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
774 {
775 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
776 return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
777 }
778
trans_lhu(DisasContext * dc,arg_typea * arg)779 static bool trans_lhu(DisasContext *dc, arg_typea *arg)
780 {
781 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
782 return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
783 }
784
trans_lhur(DisasContext * dc,arg_typea * arg)785 static bool trans_lhur(DisasContext *dc, arg_typea *arg)
786 {
787 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
788 return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
789 }
790
trans_lhuea(DisasContext * dc,arg_typea * arg)791 static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
792 {
793 if (trap_userspace(dc, true)) {
794 return true;
795 }
796 #ifdef CONFIG_USER_ONLY
797 return true;
798 #else
799 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
800 return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
801 #endif
802 }
803
trans_lhui(DisasContext * dc,arg_typeb * arg)804 static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
805 {
806 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
807 return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
808 }
809
trans_lw(DisasContext * dc,arg_typea * arg)810 static bool trans_lw(DisasContext *dc, arg_typea *arg)
811 {
812 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
813 return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
814 }
815
trans_lwr(DisasContext * dc,arg_typea * arg)816 static bool trans_lwr(DisasContext *dc, arg_typea *arg)
817 {
818 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
819 return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
820 }
821
trans_lwea(DisasContext * dc,arg_typea * arg)822 static bool trans_lwea(DisasContext *dc, arg_typea *arg)
823 {
824 if (trap_userspace(dc, true)) {
825 return true;
826 }
827 #ifdef CONFIG_USER_ONLY
828 return true;
829 #else
830 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
831 return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
832 #endif
833 }
834
trans_lwi(DisasContext * dc,arg_typeb * arg)835 static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
836 {
837 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
838 return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
839 }
840
trans_lwx(DisasContext * dc,arg_typea * arg)841 static bool trans_lwx(DisasContext *dc, arg_typea *arg)
842 {
843 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
844
845 /* lwx does not throw unaligned access errors, so force alignment */
846 tcg_gen_andi_tl(addr, addr, ~3);
847
848 tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
849 tcg_gen_mov_tl(cpu_res_addr, addr);
850
851 if (arg->rd) {
852 tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
853 }
854
855 /* No support for AXI exclusive so always clear C */
856 tcg_gen_movi_i32(cpu_msr_c, 0);
857 return true;
858 }
859
do_store(DisasContext * dc,int rd,TCGv addr,MemOp mop,int mem_index,bool rev)860 static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
861 int mem_index, bool rev)
862 {
863 MemOp size = mop & MO_SIZE;
864
865 /*
866 * When doing reverse accesses we need to do two things.
867 *
868 * 1. Reverse the address wrt endianness.
869 * 2. Byteswap the data lanes on the way back into the CPU core.
870 */
871 if (rev) {
872 if (size > MO_8) {
873 mop ^= MO_BSWAP;
874 }
875 if (size < MO_32) {
876 tcg_gen_xori_tl(addr, addr, 3 - size);
877 }
878 }
879
880 /*
881 * For system mode, enforce alignment if the cpu configuration
882 * requires it. For user-mode, the Linux kernel will have fixed up
883 * any unaligned access, so emulate that by *not* setting MO_ALIGN.
884 */
885 #ifndef CONFIG_USER_ONLY
886 if (size > MO_8 &&
887 (dc->tb_flags & MSR_EE) &&
888 dc->cfg->unaligned_exceptions) {
889 record_unaligned_ess(dc, rd, size, true);
890 mop |= MO_ALIGN;
891 }
892 #endif
893
894 tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
895 return true;
896 }
897
trans_sb(DisasContext * dc,arg_typea * arg)898 static bool trans_sb(DisasContext *dc, arg_typea *arg)
899 {
900 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
901 return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
902 }
903
trans_sbr(DisasContext * dc,arg_typea * arg)904 static bool trans_sbr(DisasContext *dc, arg_typea *arg)
905 {
906 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
907 return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
908 }
909
trans_sbea(DisasContext * dc,arg_typea * arg)910 static bool trans_sbea(DisasContext *dc, arg_typea *arg)
911 {
912 if (trap_userspace(dc, true)) {
913 return true;
914 }
915 #ifdef CONFIG_USER_ONLY
916 return true;
917 #else
918 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
919 return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
920 #endif
921 }
922
trans_sbi(DisasContext * dc,arg_typeb * arg)923 static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
924 {
925 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
926 return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
927 }
928
trans_sh(DisasContext * dc,arg_typea * arg)929 static bool trans_sh(DisasContext *dc, arg_typea *arg)
930 {
931 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
932 return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
933 }
934
trans_shr(DisasContext * dc,arg_typea * arg)935 static bool trans_shr(DisasContext *dc, arg_typea *arg)
936 {
937 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
938 return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
939 }
940
trans_shea(DisasContext * dc,arg_typea * arg)941 static bool trans_shea(DisasContext *dc, arg_typea *arg)
942 {
943 if (trap_userspace(dc, true)) {
944 return true;
945 }
946 #ifdef CONFIG_USER_ONLY
947 return true;
948 #else
949 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
950 return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
951 #endif
952 }
953
trans_shi(DisasContext * dc,arg_typeb * arg)954 static bool trans_shi(DisasContext *dc, arg_typeb *arg)
955 {
956 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
957 return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
958 }
959
trans_sw(DisasContext * dc,arg_typea * arg)960 static bool trans_sw(DisasContext *dc, arg_typea *arg)
961 {
962 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
963 return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
964 }
965
trans_swr(DisasContext * dc,arg_typea * arg)966 static bool trans_swr(DisasContext *dc, arg_typea *arg)
967 {
968 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
969 return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
970 }
971
trans_swea(DisasContext * dc,arg_typea * arg)972 static bool trans_swea(DisasContext *dc, arg_typea *arg)
973 {
974 if (trap_userspace(dc, true)) {
975 return true;
976 }
977 #ifdef CONFIG_USER_ONLY
978 return true;
979 #else
980 TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
981 return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
982 #endif
983 }
984
trans_swi(DisasContext * dc,arg_typeb * arg)985 static bool trans_swi(DisasContext *dc, arg_typeb *arg)
986 {
987 TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
988 return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
989 }
990
trans_swx(DisasContext * dc,arg_typea * arg)991 static bool trans_swx(DisasContext *dc, arg_typea *arg)
992 {
993 TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
994 TCGLabel *swx_done = gen_new_label();
995 TCGLabel *swx_fail = gen_new_label();
996 TCGv_i32 tval;
997
998 /* swx does not throw unaligned access errors, so force alignment */
999 tcg_gen_andi_tl(addr, addr, ~3);
1000
1001 /*
1002 * Compare the address vs the one we used during lwx.
1003 * On mismatch, the operation fails. On match, addr dies at the
1004 * branch, but we know we can use the equal version in the global.
1005 * In either case, addr is no longer needed.
1006 */
1007 tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1008
1009 /*
1010 * Compare the value loaded during lwx with current contents of
1011 * the reserved location.
1012 */
1013 tval = tcg_temp_new_i32();
1014
1015 tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1016 reg_for_write(dc, arg->rd),
1017 dc->mem_index, MO_TEUL);
1018
1019 tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1020
1021 /* Success */
1022 tcg_gen_movi_i32(cpu_msr_c, 0);
1023 tcg_gen_br(swx_done);
1024
1025 /* Failure */
1026 gen_set_label(swx_fail);
1027 tcg_gen_movi_i32(cpu_msr_c, 1);
1028
1029 gen_set_label(swx_done);
1030
1031 /*
1032 * Prevent the saved address from working again without another ldx.
1033 * Akin to the pseudocode setting reservation = 0.
1034 */
1035 tcg_gen_movi_tl(cpu_res_addr, -1);
1036 return true;
1037 }
1038
setup_dslot(DisasContext * dc,bool type_b)1039 static void setup_dslot(DisasContext *dc, bool type_b)
1040 {
1041 dc->tb_flags_to_set |= D_FLAG;
1042 if (type_b && (dc->tb_flags & IMM_FLAG)) {
1043 dc->tb_flags_to_set |= BIMM_FLAG;
1044 }
1045 }
1046
do_branch(DisasContext * dc,int dest_rb,int dest_imm,bool delay,bool abs,int link)1047 static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
1048 bool delay, bool abs, int link)
1049 {
1050 uint32_t add_pc;
1051
1052 if (invalid_delay_slot(dc, "branch")) {
1053 return true;
1054 }
1055 if (delay) {
1056 setup_dslot(dc, dest_rb < 0);
1057 }
1058
1059 if (link) {
1060 tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
1061 }
1062
1063 /* Store the branch taken destination into btarget. */
1064 add_pc = abs ? 0 : dc->base.pc_next;
1065 if (dest_rb > 0) {
1066 dc->jmp_dest = -1;
1067 tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
1068 } else {
1069 dc->jmp_dest = add_pc + dest_imm;
1070 tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1071 }
1072 dc->jmp_cond = TCG_COND_ALWAYS;
1073 return true;
1074 }
1075
1076 #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \
1077 static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \
1078 { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \
1079 static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \
1080 { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
1081
DO_BR(br,bri,false,false,false)1082 DO_BR(br, bri, false, false, false)
1083 DO_BR(bra, brai, false, true, false)
1084 DO_BR(brd, brid, true, false, false)
1085 DO_BR(brad, braid, true, true, false)
1086 DO_BR(brld, brlid, true, false, true)
1087 DO_BR(brald, bralid, true, true, true)
1088
1089 static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1090 TCGCond cond, int ra, bool delay)
1091 {
1092 TCGv_i32 zero, next;
1093
1094 if (invalid_delay_slot(dc, "bcc")) {
1095 return true;
1096 }
1097 if (delay) {
1098 setup_dslot(dc, dest_rb < 0);
1099 }
1100
1101 dc->jmp_cond = cond;
1102
1103 /* Cache the condition register in cpu_bvalue across any delay slot. */
1104 tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1105
1106 /* Store the branch taken destination into btarget. */
1107 if (dest_rb > 0) {
1108 dc->jmp_dest = -1;
1109 tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1110 } else {
1111 dc->jmp_dest = dc->base.pc_next + dest_imm;
1112 tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1113 }
1114
1115 /* Compute the final destination into btarget. */
1116 zero = tcg_constant_i32(0);
1117 next = tcg_constant_i32(dc->base.pc_next + (delay + 1) * 4);
1118 tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1119 reg_for_read(dc, ra), zero,
1120 cpu_btarget, next);
1121
1122 return true;
1123 }
1124
1125 #define DO_BCC(NAME, COND) \
1126 static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \
1127 { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \
1128 static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \
1129 { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \
1130 static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \
1131 { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \
1132 static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \
1133 { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1134
DO_BCC(beq,TCG_COND_EQ)1135 DO_BCC(beq, TCG_COND_EQ)
1136 DO_BCC(bge, TCG_COND_GE)
1137 DO_BCC(bgt, TCG_COND_GT)
1138 DO_BCC(ble, TCG_COND_LE)
1139 DO_BCC(blt, TCG_COND_LT)
1140 DO_BCC(bne, TCG_COND_NE)
1141
1142 static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1143 {
1144 if (trap_userspace(dc, true)) {
1145 return true;
1146 }
1147 if (invalid_delay_slot(dc, "brk")) {
1148 return true;
1149 }
1150
1151 tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1152 if (arg->rd) {
1153 tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1154 }
1155 tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1156 tcg_gen_movi_tl(cpu_res_addr, -1);
1157
1158 dc->base.is_jmp = DISAS_EXIT;
1159 return true;
1160 }
1161
trans_brki(DisasContext * dc,arg_typeb_br * arg)1162 static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1163 {
1164 uint32_t imm = arg->imm;
1165
1166 if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1167 return true;
1168 }
1169 if (invalid_delay_slot(dc, "brki")) {
1170 return true;
1171 }
1172
1173 tcg_gen_movi_i32(cpu_pc, imm);
1174 if (arg->rd) {
1175 tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1176 }
1177 tcg_gen_movi_tl(cpu_res_addr, -1);
1178
1179 #ifdef CONFIG_USER_ONLY
1180 switch (imm) {
1181 case 0x8: /* syscall trap */
1182 gen_raise_exception_sync(dc, EXCP_SYSCALL);
1183 break;
1184 case 0x18: /* debug trap */
1185 gen_raise_exception_sync(dc, EXCP_DEBUG);
1186 break;
1187 default: /* eliminated with trap_userspace check */
1188 g_assert_not_reached();
1189 }
1190 #else
1191 uint32_t msr_to_set = 0;
1192
1193 if (imm != 0x18) {
1194 msr_to_set |= MSR_BIP;
1195 }
1196 if (imm == 0x8 || imm == 0x18) {
1197 /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1198 msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1199 tcg_gen_andi_i32(cpu_msr, cpu_msr,
1200 ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1201 }
1202 tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
1203 dc->base.is_jmp = DISAS_EXIT;
1204 #endif
1205
1206 return true;
1207 }
1208
trans_mbar(DisasContext * dc,arg_mbar * arg)1209 static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1210 {
1211 int mbar_imm = arg->imm;
1212
1213 /* Note that mbar is a specialized branch instruction. */
1214 if (invalid_delay_slot(dc, "mbar")) {
1215 return true;
1216 }
1217
1218 /* Data access memory barrier. */
1219 if ((mbar_imm & 2) == 0) {
1220 tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1221 }
1222
1223 /* Sleep. */
1224 if (mbar_imm & 16) {
1225 if (trap_userspace(dc, true)) {
1226 /* Sleep is a privileged instruction. */
1227 return true;
1228 }
1229
1230 t_sync_flags(dc);
1231
1232 tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
1233 -offsetof(MicroBlazeCPU, env)
1234 +offsetof(CPUState, halted));
1235
1236 tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1237
1238 gen_raise_exception(dc, EXCP_HLT);
1239 }
1240
1241 /*
1242 * If !(mbar_imm & 1), this is an instruction access memory barrier
1243 * and we need to end the TB so that we recognize self-modified
1244 * code immediately.
1245 *
1246 * However, there are some data mbars that need the TB break
1247 * (and return to main loop) to recognize interrupts right away.
1248 * E.g. recognizing a change to an interrupt controller register.
1249 *
1250 * Therefore, choose to end the TB always.
1251 */
1252 dc->base.is_jmp = DISAS_EXIT_NEXT;
1253 return true;
1254 }
1255
do_rts(DisasContext * dc,arg_typeb_bc * arg,int to_set)1256 static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1257 {
1258 if (trap_userspace(dc, to_set)) {
1259 return true;
1260 }
1261 if (invalid_delay_slot(dc, "rts")) {
1262 return true;
1263 }
1264
1265 dc->tb_flags_to_set |= to_set;
1266 setup_dslot(dc, true);
1267
1268 dc->jmp_cond = TCG_COND_ALWAYS;
1269 dc->jmp_dest = -1;
1270 tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1271 return true;
1272 }
1273
1274 #define DO_RTS(NAME, IFLAG) \
1275 static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1276 { return do_rts(dc, arg, IFLAG); }
1277
DO_RTS(rtbd,DRTB_FLAG)1278 DO_RTS(rtbd, DRTB_FLAG)
1279 DO_RTS(rtid, DRTI_FLAG)
1280 DO_RTS(rted, DRTE_FLAG)
1281 DO_RTS(rtsd, 0)
1282
1283 static bool trans_zero(DisasContext *dc, arg_zero *arg)
1284 {
1285 /* If opcode_0_illegal, trap. */
1286 if (dc->cfg->opcode_0_illegal) {
1287 trap_illegal(dc, true);
1288 return true;
1289 }
1290 /*
1291 * Otherwise, this is "add r0, r0, r0".
1292 * Continue to trans_add so that MSR[C] gets cleared.
1293 */
1294 return false;
1295 }
1296
msr_read(DisasContext * dc,TCGv_i32 d)1297 static void msr_read(DisasContext *dc, TCGv_i32 d)
1298 {
1299 TCGv_i32 t;
1300
1301 /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
1302 t = tcg_temp_new_i32();
1303 tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
1304 tcg_gen_or_i32(d, cpu_msr, t);
1305 }
1306
do_msrclrset(DisasContext * dc,arg_type_msr * arg,bool set)1307 static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1308 {
1309 uint32_t imm = arg->imm;
1310
1311 if (trap_userspace(dc, imm != MSR_C)) {
1312 return true;
1313 }
1314
1315 if (arg->rd) {
1316 msr_read(dc, cpu_R[arg->rd]);
1317 }
1318
1319 /*
1320 * Handle the carry bit separately.
1321 * This is the only bit that userspace can modify.
1322 */
1323 if (imm & MSR_C) {
1324 tcg_gen_movi_i32(cpu_msr_c, set);
1325 }
1326
1327 /*
1328 * MSR_C and MSR_CC set above.
1329 * MSR_PVR is not writable, and is always clear.
1330 */
1331 imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1332
1333 if (imm != 0) {
1334 if (set) {
1335 tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1336 } else {
1337 tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1338 }
1339 dc->base.is_jmp = DISAS_EXIT_NEXT;
1340 }
1341 return true;
1342 }
1343
trans_msrclr(DisasContext * dc,arg_type_msr * arg)1344 static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1345 {
1346 return do_msrclrset(dc, arg, false);
1347 }
1348
trans_msrset(DisasContext * dc,arg_type_msr * arg)1349 static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1350 {
1351 return do_msrclrset(dc, arg, true);
1352 }
1353
trans_mts(DisasContext * dc,arg_mts * arg)1354 static bool trans_mts(DisasContext *dc, arg_mts *arg)
1355 {
1356 if (trap_userspace(dc, true)) {
1357 return true;
1358 }
1359
1360 #ifdef CONFIG_USER_ONLY
1361 g_assert_not_reached();
1362 #else
1363 if (arg->e && arg->rs != 0x1003) {
1364 qemu_log_mask(LOG_GUEST_ERROR,
1365 "Invalid extended mts reg 0x%x\n", arg->rs);
1366 return true;
1367 }
1368
1369 TCGv_i32 src = reg_for_read(dc, arg->ra);
1370 switch (arg->rs) {
1371 case SR_MSR:
1372 /* Install MSR_C. */
1373 tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
1374 /*
1375 * Clear MSR_C and MSR_CC;
1376 * MSR_PVR is not writable, and is always clear.
1377 */
1378 tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
1379 break;
1380 case SR_FSR:
1381 tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, fsr));
1382 break;
1383 case 0x800:
1384 tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, slr));
1385 break;
1386 case 0x802:
1387 tcg_gen_st_i32(src, tcg_env, offsetof(CPUMBState, shr));
1388 break;
1389
1390 case 0x1000: /* PID */
1391 case 0x1001: /* ZPR */
1392 case 0x1002: /* TLBX */
1393 case 0x1003: /* TLBLO */
1394 case 0x1004: /* TLBHI */
1395 case 0x1005: /* TLBSX */
1396 {
1397 TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1398 TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
1399
1400 gen_helper_mmu_write(tcg_env, tmp_ext, tmp_reg, src);
1401 }
1402 break;
1403
1404 default:
1405 qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
1406 return true;
1407 }
1408 dc->base.is_jmp = DISAS_EXIT_NEXT;
1409 return true;
1410 #endif
1411 }
1412
trans_mfs(DisasContext * dc,arg_mfs * arg)1413 static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
1414 {
1415 TCGv_i32 dest = reg_for_write(dc, arg->rd);
1416
1417 if (arg->e) {
1418 switch (arg->rs) {
1419 case SR_EAR:
1420 {
1421 TCGv_i64 t64 = tcg_temp_new_i64();
1422 tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
1423 tcg_gen_extrh_i64_i32(dest, t64);
1424 }
1425 return true;
1426 #ifndef CONFIG_USER_ONLY
1427 case 0x1003: /* TLBLO */
1428 /* Handled below. */
1429 break;
1430 #endif
1431 case 0x2006 ... 0x2009:
1432 /* High bits of PVR6-9 not implemented. */
1433 tcg_gen_movi_i32(dest, 0);
1434 return true;
1435 default:
1436 qemu_log_mask(LOG_GUEST_ERROR,
1437 "Invalid extended mfs reg 0x%x\n", arg->rs);
1438 return true;
1439 }
1440 }
1441
1442 switch (arg->rs) {
1443 case SR_PC:
1444 tcg_gen_movi_i32(dest, dc->base.pc_next);
1445 break;
1446 case SR_MSR:
1447 msr_read(dc, dest);
1448 break;
1449 case SR_EAR:
1450 {
1451 TCGv_i64 t64 = tcg_temp_new_i64();
1452 tcg_gen_ld_i64(t64, tcg_env, offsetof(CPUMBState, ear));
1453 tcg_gen_extrl_i64_i32(dest, t64);
1454 }
1455 break;
1456 case SR_ESR:
1457 tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, esr));
1458 break;
1459 case SR_FSR:
1460 tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, fsr));
1461 break;
1462 case SR_BTR:
1463 tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, btr));
1464 break;
1465 case SR_EDR:
1466 tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, edr));
1467 break;
1468 case 0x800:
1469 tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, slr));
1470 break;
1471 case 0x802:
1472 tcg_gen_ld_i32(dest, tcg_env, offsetof(CPUMBState, shr));
1473 break;
1474
1475 #ifndef CONFIG_USER_ONLY
1476 case 0x1000: /* PID */
1477 case 0x1001: /* ZPR */
1478 case 0x1002: /* TLBX */
1479 case 0x1003: /* TLBLO */
1480 case 0x1004: /* TLBHI */
1481 case 0x1005: /* TLBSX */
1482 {
1483 TCGv_i32 tmp_ext = tcg_constant_i32(arg->e);
1484 TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7);
1485
1486 gen_helper_mmu_read(dest, tcg_env, tmp_ext, tmp_reg);
1487 }
1488 break;
1489 #endif
1490
1491 case 0x2000 ... 0x200c:
1492 tcg_gen_ld_i32(dest, tcg_env,
1493 offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1494 - offsetof(MicroBlazeCPU, env));
1495 break;
1496 default:
1497 qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1498 break;
1499 }
1500 return true;
1501 }
1502
do_rti(DisasContext * dc)1503 static void do_rti(DisasContext *dc)
1504 {
1505 TCGv_i32 tmp = tcg_temp_new_i32();
1506
1507 tcg_gen_shri_i32(tmp, cpu_msr, 1);
1508 tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
1509 tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
1510 tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
1511 tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1512 }
1513
do_rtb(DisasContext * dc)1514 static void do_rtb(DisasContext *dc)
1515 {
1516 TCGv_i32 tmp = tcg_temp_new_i32();
1517
1518 tcg_gen_shri_i32(tmp, cpu_msr, 1);
1519 tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
1520 tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
1521 tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1522 }
1523
do_rte(DisasContext * dc)1524 static void do_rte(DisasContext *dc)
1525 {
1526 TCGv_i32 tmp = tcg_temp_new_i32();
1527
1528 tcg_gen_shri_i32(tmp, cpu_msr, 1);
1529 tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
1530 tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
1531 tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
1532 tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1533 }
1534
1535 /* Insns connected to FSL or AXI stream attached devices. */
do_get(DisasContext * dc,int rd,int rb,int imm,int ctrl)1536 static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1537 {
1538 TCGv_i32 t_id, t_ctrl;
1539
1540 if (trap_userspace(dc, true)) {
1541 return true;
1542 }
1543
1544 t_id = tcg_temp_new_i32();
1545 if (rb) {
1546 tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1547 } else {
1548 tcg_gen_movi_i32(t_id, imm);
1549 }
1550
1551 t_ctrl = tcg_constant_i32(ctrl);
1552 gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
1553 return true;
1554 }
1555
trans_get(DisasContext * dc,arg_get * arg)1556 static bool trans_get(DisasContext *dc, arg_get *arg)
1557 {
1558 return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
1559 }
1560
trans_getd(DisasContext * dc,arg_getd * arg)1561 static bool trans_getd(DisasContext *dc, arg_getd *arg)
1562 {
1563 return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
1564 }
1565
do_put(DisasContext * dc,int ra,int rb,int imm,int ctrl)1566 static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
1567 {
1568 TCGv_i32 t_id, t_ctrl;
1569
1570 if (trap_userspace(dc, true)) {
1571 return true;
1572 }
1573
1574 t_id = tcg_temp_new_i32();
1575 if (rb) {
1576 tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1577 } else {
1578 tcg_gen_movi_i32(t_id, imm);
1579 }
1580
1581 t_ctrl = tcg_constant_i32(ctrl);
1582 gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
1583 return true;
1584 }
1585
trans_put(DisasContext * dc,arg_put * arg)1586 static bool trans_put(DisasContext *dc, arg_put *arg)
1587 {
1588 return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
1589 }
1590
trans_putd(DisasContext * dc,arg_putd * arg)1591 static bool trans_putd(DisasContext *dc, arg_putd *arg)
1592 {
1593 return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1594 }
1595
mb_tr_init_disas_context(DisasContextBase * dcb,CPUState * cs)1596 static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1597 {
1598 DisasContext *dc = container_of(dcb, DisasContext, base);
1599 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1600 int bound;
1601
1602 dc->cfg = &cpu->cfg;
1603 dc->tb_flags = dc->base.tb->flags;
1604 dc->ext_imm = dc->base.tb->cs_base;
1605 dc->r0 = NULL;
1606 dc->r0_set = false;
1607 dc->mem_index = cpu_mmu_index(cs, false);
1608 dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1609 dc->jmp_dest = -1;
1610
1611 bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1612 dc->base.max_insns = MIN(dc->base.max_insns, bound);
1613 }
1614
mb_tr_tb_start(DisasContextBase * dcb,CPUState * cs)1615 static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1616 {
1617 }
1618
mb_tr_insn_start(DisasContextBase * dcb,CPUState * cs)1619 static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1620 {
1621 DisasContext *dc = container_of(dcb, DisasContext, base);
1622
1623 tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1624 }
1625
mb_tr_translate_insn(DisasContextBase * dcb,CPUState * cs)1626 static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1627 {
1628 DisasContext *dc = container_of(dcb, DisasContext, base);
1629 uint32_t ir;
1630
1631 /* TODO: This should raise an exception, not terminate qemu. */
1632 if (dc->base.pc_next & 3) {
1633 cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1634 (uint32_t)dc->base.pc_next);
1635 }
1636
1637 dc->tb_flags_to_set = 0;
1638
1639 ir = translator_ldl(cpu_env(cs), &dc->base, dc->base.pc_next);
1640 if (!decode(dc, ir)) {
1641 trap_illegal(dc, true);
1642 }
1643
1644 if (dc->r0) {
1645 dc->r0 = NULL;
1646 dc->r0_set = false;
1647 }
1648
1649 /* Discard the imm global when its contents cannot be used. */
1650 if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1651 tcg_gen_discard_i32(cpu_imm);
1652 }
1653
1654 dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
1655 dc->tb_flags |= dc->tb_flags_to_set;
1656 dc->base.pc_next += 4;
1657
1658 if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
1659 /*
1660 * Finish any return-from branch.
1661 */
1662 uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
1663 if (unlikely(rt_ibe != 0)) {
1664 dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
1665 if (rt_ibe & DRTI_FLAG) {
1666 do_rti(dc);
1667 } else if (rt_ibe & DRTB_FLAG) {
1668 do_rtb(dc);
1669 } else {
1670 do_rte(dc);
1671 }
1672 }
1673
1674 /* Complete the branch, ending the TB. */
1675 switch (dc->base.is_jmp) {
1676 case DISAS_NORETURN:
1677 /*
1678 * E.g. illegal insn in a delay slot. We've already exited
1679 * and will handle D_FLAG in mb_cpu_do_interrupt.
1680 */
1681 break;
1682 case DISAS_NEXT:
1683 /*
1684 * Normal insn a delay slot.
1685 * However, the return-from-exception type insns should
1686 * return to the main loop, as they have adjusted MSR.
1687 */
1688 dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
1689 break;
1690 case DISAS_EXIT_NEXT:
1691 /*
1692 * E.g. mts insn in a delay slot. Continue with btarget,
1693 * but still return to the main loop.
1694 */
1695 dc->base.is_jmp = DISAS_EXIT_JUMP;
1696 break;
1697 default:
1698 g_assert_not_reached();
1699 }
1700 }
1701 }
1702
mb_tr_tb_stop(DisasContextBase * dcb,CPUState * cs)1703 static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1704 {
1705 DisasContext *dc = container_of(dcb, DisasContext, base);
1706
1707 if (dc->base.is_jmp == DISAS_NORETURN) {
1708 /* We have already exited the TB. */
1709 return;
1710 }
1711
1712 t_sync_flags(dc);
1713
1714 switch (dc->base.is_jmp) {
1715 case DISAS_TOO_MANY:
1716 gen_goto_tb(dc, 0, dc->base.pc_next);
1717 return;
1718
1719 case DISAS_EXIT:
1720 break;
1721 case DISAS_EXIT_NEXT:
1722 tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1723 break;
1724 case DISAS_EXIT_JUMP:
1725 tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1726 tcg_gen_discard_i32(cpu_btarget);
1727 break;
1728
1729 case DISAS_JUMP:
1730 if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
1731 /* Direct jump. */
1732 tcg_gen_discard_i32(cpu_btarget);
1733
1734 if (dc->jmp_cond != TCG_COND_ALWAYS) {
1735 /* Conditional direct jump. */
1736 TCGLabel *taken = gen_new_label();
1737 TCGv_i32 tmp = tcg_temp_new_i32();
1738
1739 /*
1740 * Copy bvalue to a temp now, so we can discard bvalue.
1741 * This can avoid writing bvalue to memory when the
1742 * delay slot cannot raise an exception.
1743 */
1744 tcg_gen_mov_i32(tmp, cpu_bvalue);
1745 tcg_gen_discard_i32(cpu_bvalue);
1746
1747 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1748 gen_goto_tb(dc, 1, dc->base.pc_next);
1749 gen_set_label(taken);
1750 }
1751 gen_goto_tb(dc, 0, dc->jmp_dest);
1752 return;
1753 }
1754
1755 /* Indirect jump (or direct jump w/ goto_tb disabled) */
1756 tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1757 tcg_gen_discard_i32(cpu_btarget);
1758 tcg_gen_lookup_and_goto_ptr();
1759 return;
1760
1761 default:
1762 g_assert_not_reached();
1763 }
1764
1765 /* Finish DISAS_EXIT_* */
1766 if (unlikely(cs->singlestep_enabled)) {
1767 gen_raise_exception(dc, EXCP_DEBUG);
1768 } else {
1769 tcg_gen_exit_tb(NULL, 0);
1770 }
1771 }
1772
1773 static const TranslatorOps mb_tr_ops = {
1774 .init_disas_context = mb_tr_init_disas_context,
1775 .tb_start = mb_tr_tb_start,
1776 .insn_start = mb_tr_insn_start,
1777 .translate_insn = mb_tr_translate_insn,
1778 .tb_stop = mb_tr_tb_stop,
1779 };
1780
gen_intermediate_code(CPUState * cpu,TranslationBlock * tb,int * max_insns,vaddr pc,void * host_pc)1781 void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
1782 vaddr pc, void *host_pc)
1783 {
1784 DisasContext dc;
1785 translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base);
1786 }
1787
mb_cpu_dump_state(CPUState * cs,FILE * f,int flags)1788 void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1789 {
1790 CPUMBState *env = cpu_env(cs);
1791 uint32_t iflags;
1792 int i;
1793
1794 qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
1795 env->pc, env->msr,
1796 (env->msr & MSR_UM) ? "user" : "kernel",
1797 (env->msr & MSR_UMS) ? "user" : "kernel",
1798 (bool)(env->msr & MSR_EIP),
1799 (bool)(env->msr & MSR_IE));
1800
1801 iflags = env->iflags;
1802 qemu_fprintf(f, "iflags: 0x%08x", iflags);
1803 if (iflags & IMM_FLAG) {
1804 qemu_fprintf(f, " IMM(0x%08x)", env->imm);
1805 }
1806 if (iflags & BIMM_FLAG) {
1807 qemu_fprintf(f, " BIMM");
1808 }
1809 if (iflags & D_FLAG) {
1810 qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
1811 }
1812 if (iflags & DRTI_FLAG) {
1813 qemu_fprintf(f, " DRTI");
1814 }
1815 if (iflags & DRTE_FLAG) {
1816 qemu_fprintf(f, " DRTE");
1817 }
1818 if (iflags & DRTB_FLAG) {
1819 qemu_fprintf(f, " DRTB");
1820 }
1821 if (iflags & ESR_ESS_FLAG) {
1822 qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
1823 }
1824
1825 qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
1826 "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
1827 env->esr, env->fsr, env->btr, env->edr,
1828 env->ear, env->slr, env->shr);
1829
1830 for (i = 0; i < 32; i++) {
1831 qemu_fprintf(f, "r%2.2d=%08x%c",
1832 i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
1833 }
1834 qemu_fprintf(f, "\n");
1835 }
1836
mb_tcg_init(void)1837 void mb_tcg_init(void)
1838 {
1839 #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1840 #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1841
1842 static const struct {
1843 TCGv_i32 *var; int ofs; char name[8];
1844 } i32s[] = {
1845 /*
1846 * Note that r0 is handled specially in reg_for_read
1847 * and reg_for_write. Nothing should touch cpu_R[0].
1848 * Leave that element NULL, which will assert quickly
1849 * inside the tcg generator functions.
1850 */
1851 R(1), R(2), R(3), R(4), R(5), R(6), R(7),
1852 R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
1853 R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1854 R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1855
1856 SP(pc),
1857 SP(msr),
1858 SP(msr_c),
1859 SP(imm),
1860 SP(iflags),
1861 SP(bvalue),
1862 SP(btarget),
1863 SP(res_val),
1864 };
1865
1866 #undef R
1867 #undef SP
1868
1869 for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1870 *i32s[i].var =
1871 tcg_global_mem_new_i32(tcg_env, i32s[i].ofs, i32s[i].name);
1872 }
1873
1874 cpu_res_addr =
1875 tcg_global_mem_new(tcg_env, offsetof(CPUMBState, res_addr), "res_addr");
1876 }
1877