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