translate.c (54631B)
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 46static TCGv_i32 cpu_R[32]; 47static TCGv_i32 cpu_pc; 48static TCGv_i32 cpu_msr; 49static TCGv_i32 cpu_msr_c; 50static TCGv_i32 cpu_imm; 51static TCGv_i32 cpu_bvalue; 52static TCGv_i32 cpu_btarget; 53static TCGv_i32 cpu_iflags; 54static TCGv cpu_res_addr; 55static TCGv_i32 cpu_res_val; 56 57#include "exec/gen-icount.h" 58 59/* This is the state at translation time. */ 60typedef 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 83static 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 94static 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 102static 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 111static 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 118static 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 127static 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 */ 149static 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 */ 162static 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 */ 176static 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 187static 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 202static 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 213static 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 229static 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 244static 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 259static 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. */ 315static 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. */ 325static 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. */ 338static 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 344DO_TYPEA(add, true, gen_add) 345DO_TYPEA(addc, true, gen_addc) 346DO_TYPEA(addk, false, tcg_gen_add_i32) 347DO_TYPEA(addkc, true, gen_addkc) 348 349DO_TYPEBV(addi, true, gen_add) 350DO_TYPEBV(addic, true, gen_addc) 351DO_TYPEBI(addik, false, tcg_gen_addi_i32) 352DO_TYPEBV(addikc, true, gen_addkc) 353 354static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 355{ 356 tcg_gen_andi_i32(out, ina, ~imm); 357} 358 359DO_TYPEA(and, false, tcg_gen_and_i32) 360DO_TYPEBI(andi, false, tcg_gen_andi_i32) 361DO_TYPEA(andn, false, tcg_gen_andc_i32) 362DO_TYPEBI(andni, false, gen_andni) 363 364static 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 372static 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 380static 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 388static 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 403static 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 419DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 420DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 421DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 422 423DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 424DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 425DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 426 427DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 428DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 429 430static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 431{ 432 tcg_gen_clzi_i32(out, ina, 32); 433} 434 435DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 436 437static 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 447static 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 457DO_TYPEA(cmp, false, gen_cmp) 458DO_TYPEA(cmpu, false, gen_cmpu) 459 460ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 461ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 462ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 463ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 464ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 465ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 466ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 467ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 468ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 469ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 470ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 471 472DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 473DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 474DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 475DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 476DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 477DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 478DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 479DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 480DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 481DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 482DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 483 484ENV_WRAPPER2(gen_flt, gen_helper_flt) 485ENV_WRAPPER2(gen_fint, gen_helper_fint) 486ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 487 488DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 489DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 490DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 491 492/* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 493static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 494{ 495 gen_helper_divs(out, cpu_env, inb, ina); 496} 497 498static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 499{ 500 gen_helper_divu(out, cpu_env, inb, ina); 501} 502 503DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 504DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 505 506static 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 517static 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 524static 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 531static 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 538DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 539DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 540DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 541DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 542DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 543 544DO_TYPEA(or, false, tcg_gen_or_i32) 545DO_TYPEBI(ori, false, tcg_gen_ori_i32) 546 547static 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 552static 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 557DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 558DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 559DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 560 561/* No input carry, but output carry. */ 562static 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. */ 569static 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. */ 583static 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. */ 589static 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 600DO_TYPEA(rsub, true, gen_rsub) 601DO_TYPEA(rsubc, true, gen_rsubc) 602DO_TYPEA(rsubk, false, gen_rsubk) 603DO_TYPEA(rsubkc, true, gen_rsubkc) 604 605DO_TYPEBV(rsubi, true, gen_rsub) 606DO_TYPEBV(rsubic, true, gen_rsubc) 607DO_TYPEBV(rsubik, false, gen_rsubk) 608DO_TYPEBV(rsubikc, true, gen_rsubkc) 609 610DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 611DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 612 613static 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 619static 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 630static 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 636DO_TYPEA0(sra, false, gen_sra) 637DO_TYPEA0(src, false, gen_src) 638DO_TYPEA0(srl, false, gen_srl) 639 640static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 641{ 642 tcg_gen_rotri_i32(out, ina, 16); 643} 644 645DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 646DO_TYPEA0(swaph, false, gen_swaph) 647 648static 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 655DO_TYPEA(xor, false, tcg_gen_xor_i32) 656DO_TYPEBI(xori, false, tcg_gen_xori_i32) 657 658static 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 682static 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 703static 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 730static 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 743static 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 776static 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 782static 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 788static 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 801static 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 807static 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 813static 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 819static 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 832static 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 838static 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 844static 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 850static 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 863static 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 869static 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 889static 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 922static 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 928static 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 934static 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 947static 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 953static 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 959static 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 965static 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 978static 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 984static 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 990static 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 996static 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 1009static 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 1015static 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 1065static 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 1073static 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 1108DO_BR(br, bri, false, false, false) 1109DO_BR(bra, brai, false, true, false) 1110DO_BR(brd, brid, true, false, false) 1111DO_BR(brad, braid, true, true, false) 1112DO_BR(brld, brlid, true, false, true) 1113DO_BR(brald, bralid, true, true, true) 1114 1115static 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 1163DO_BCC(beq, TCG_COND_EQ) 1164DO_BCC(bge, TCG_COND_GE) 1165DO_BCC(bgt, TCG_COND_GT) 1166DO_BCC(ble, TCG_COND_LE) 1167DO_BCC(blt, TCG_COND_LT) 1168DO_BCC(bne, TCG_COND_NE) 1169 1170static 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 1190static 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 1237static 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 1288static 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 1310DO_RTS(rtbd, DRTB_FLAG) 1311DO_RTS(rtid, DRTI_FLAG) 1312DO_RTS(rted, DRTE_FLAG) 1313DO_RTS(rtsd, 0) 1314 1315static 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 1329static 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 1340static 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 1377static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg) 1378{ 1379 return do_msrclrset(dc, arg, false); 1380} 1381 1382static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) 1383{ 1384 return do_msrclrset(dc, arg, true); 1385} 1386 1387static 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 1448static 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 1542static 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 1555static 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 1567static 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. */ 1581static 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 1603static bool trans_get(DisasContext *dc, arg_get *arg) 1604{ 1605 return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl); 1606} 1607 1608static bool trans_getd(DisasContext *dc, arg_getd *arg) 1609{ 1610 return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl); 1611} 1612 1613static 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 1635static bool trans_put(DisasContext *dc, arg_put *arg) 1636{ 1637 return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl); 1638} 1639 1640static bool trans_putd(DisasContext *dc, arg_putd *arg) 1641{ 1642 return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); 1643} 1644 1645static 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 1664static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1665{ 1666} 1667 1668static 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 1676static 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 1755static 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 1830static 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 1836static 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 1845void 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 1851void 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 1901void 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 1942void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1943 target_ulong *data) 1944{ 1945 env->pc = data[0]; 1946 env->iflags = data[1]; 1947}