1 /* 2 * Altera Nios II emulation for qemu: main translation routines. 3 * 4 * Copyright (C) 2016 Marek Vasut <marex@denx.de> 5 * Copyright (C) 2012 Chris Wulff <crwulff@gmail.com> 6 * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> 7 * (Portions of this file that were originally from nios2sim-ng.) 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, see 21 * <http://www.gnu.org/licenses/lgpl-2.1.html> 22 */ 23 24 #include "qemu/osdep.h" 25 #include "cpu.h" 26 #include "tcg/tcg-op.h" 27 #include "exec/exec-all.h" 28 #include "disas/disas.h" 29 #include "exec/helper-proto.h" 30 #include "exec/helper-gen.h" 31 #include "exec/log.h" 32 #include "exec/cpu_ldst.h" 33 #include "exec/translator.h" 34 #include "qemu/qemu-print.h" 35 #include "exec/gen-icount.h" 36 #include "semihosting/semihost.h" 37 38 /* is_jmp field values */ 39 #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ 40 41 #define INSTRUCTION_FLG(func, flags) { (func), (flags) } 42 #define INSTRUCTION(func) \ 43 INSTRUCTION_FLG(func, 0) 44 #define INSTRUCTION_NOP() \ 45 INSTRUCTION_FLG(nop, 0) 46 #define INSTRUCTION_UNIMPLEMENTED() \ 47 INSTRUCTION_FLG(gen_excp, EXCP_UNIMPL) 48 #define INSTRUCTION_ILLEGAL() \ 49 INSTRUCTION_FLG(gen_excp, EXCP_ILLEGAL) 50 51 /* Special R-Type instruction opcode */ 52 #define INSN_R_TYPE 0x3A 53 54 /* I-Type instruction parsing */ 55 typedef struct { 56 uint8_t op; 57 union { 58 uint16_t u; 59 int16_t s; 60 } imm16; 61 uint8_t b; 62 uint8_t a; 63 } InstrIType; 64 65 #define I_TYPE(instr, code) \ 66 InstrIType (instr) = { \ 67 .op = extract32((code), 0, 6), \ 68 .imm16.u = extract32((code), 6, 16), \ 69 .b = extract32((code), 22, 5), \ 70 .a = extract32((code), 27, 5), \ 71 } 72 73 typedef target_ulong ImmFromIType(const InstrIType *); 74 75 static target_ulong imm_unsigned(const InstrIType *i) 76 { 77 return i->imm16.u; 78 } 79 80 static target_ulong imm_signed(const InstrIType *i) 81 { 82 return i->imm16.s; 83 } 84 85 static target_ulong imm_shifted(const InstrIType *i) 86 { 87 return i->imm16.u << 16; 88 } 89 90 /* R-Type instruction parsing */ 91 typedef struct { 92 uint8_t op; 93 uint8_t imm5; 94 uint8_t opx; 95 uint8_t c; 96 uint8_t b; 97 uint8_t a; 98 } InstrRType; 99 100 #define R_TYPE(instr, code) \ 101 InstrRType (instr) = { \ 102 .op = extract32((code), 0, 6), \ 103 .imm5 = extract32((code), 6, 5), \ 104 .opx = extract32((code), 11, 6), \ 105 .c = extract32((code), 17, 5), \ 106 .b = extract32((code), 22, 5), \ 107 .a = extract32((code), 27, 5), \ 108 } 109 110 /* J-Type instruction parsing */ 111 typedef struct { 112 uint8_t op; 113 uint32_t imm26; 114 } InstrJType; 115 116 #define J_TYPE(instr, code) \ 117 InstrJType (instr) = { \ 118 .op = extract32((code), 0, 6), \ 119 .imm26 = extract32((code), 6, 26), \ 120 } 121 122 typedef void GenFn2i(TCGv, TCGv, target_long); 123 typedef void GenFn3(TCGv, TCGv, TCGv); 124 typedef void GenFn4(TCGv, TCGv, TCGv, TCGv); 125 126 typedef struct DisasContext { 127 DisasContextBase base; 128 target_ulong pc; 129 int mem_idx; 130 uint32_t tb_flags; 131 TCGv sink; 132 const ControlRegState *cr_state; 133 bool eic_present; 134 } DisasContext; 135 136 static TCGv cpu_R[NUM_GP_REGS]; 137 static TCGv cpu_pc; 138 #ifndef CONFIG_USER_ONLY 139 static TCGv cpu_crs_R[NUM_GP_REGS]; 140 #endif 141 142 typedef struct Nios2Instruction { 143 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags); 144 uint32_t flags; 145 } Nios2Instruction; 146 147 static uint8_t get_opcode(uint32_t code) 148 { 149 I_TYPE(instr, code); 150 return instr.op; 151 } 152 153 static uint8_t get_opxcode(uint32_t code) 154 { 155 R_TYPE(instr, code); 156 return instr.opx; 157 } 158 159 static TCGv load_gpr(DisasContext *dc, unsigned reg) 160 { 161 assert(reg < NUM_GP_REGS); 162 163 /* 164 * With shadow register sets, register r0 does not necessarily contain 0, 165 * but it is overwhelmingly likely that it does -- software is supposed 166 * to have set r0 to 0 in every shadow register set before use. 167 */ 168 if (unlikely(reg == R_ZERO) && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) { 169 return tcg_constant_tl(0); 170 } 171 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { 172 return cpu_R[reg]; 173 } 174 #ifdef CONFIG_USER_ONLY 175 g_assert_not_reached(); 176 #else 177 return cpu_crs_R[reg]; 178 #endif 179 } 180 181 static TCGv dest_gpr(DisasContext *dc, unsigned reg) 182 { 183 assert(reg < NUM_GP_REGS); 184 185 /* 186 * The spec for shadow register sets isn't clear, but we assume that 187 * writes to r0 are discarded regardless of CRS. 188 */ 189 if (unlikely(reg == R_ZERO)) { 190 if (dc->sink == NULL) { 191 dc->sink = tcg_temp_new(); 192 } 193 return dc->sink; 194 } 195 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { 196 return cpu_R[reg]; 197 } 198 #ifdef CONFIG_USER_ONLY 199 g_assert_not_reached(); 200 #else 201 return cpu_crs_R[reg]; 202 #endif 203 } 204 205 static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index) 206 { 207 /* Note that PC is advanced for all hardware exceptions. */ 208 tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); 209 gen_helper_raise_exception(cpu_env, tcg_constant_i32(index)); 210 dc->base.is_jmp = DISAS_NORETURN; 211 } 212 213 static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest) 214 { 215 const TranslationBlock *tb = dc->base.tb; 216 217 if (translator_use_goto_tb(&dc->base, dest)) { 218 tcg_gen_goto_tb(n); 219 tcg_gen_movi_tl(cpu_pc, dest); 220 tcg_gen_exit_tb(tb, n); 221 } else { 222 tcg_gen_movi_tl(cpu_pc, dest); 223 tcg_gen_lookup_and_goto_ptr(); 224 } 225 dc->base.is_jmp = DISAS_NORETURN; 226 } 227 228 static void gen_jumpr(DisasContext *dc, int regno, bool is_call) 229 { 230 TCGLabel *l = gen_new_label(); 231 TCGv test = tcg_temp_new(); 232 TCGv dest = load_gpr(dc, regno); 233 234 tcg_gen_andi_tl(test, dest, 3); 235 tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l); 236 tcg_temp_free(test); 237 238 tcg_gen_mov_tl(cpu_pc, dest); 239 if (is_call) { 240 tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next); 241 } 242 tcg_gen_lookup_and_goto_ptr(); 243 244 gen_set_label(l); 245 tcg_gen_st_tl(dest, cpu_env, offsetof(CPUNios2State, ctrl[CR_BADADDR])); 246 t_gen_helper_raise_exception(dc, EXCP_UNALIGND); 247 248 dc->base.is_jmp = DISAS_NORETURN; 249 } 250 251 static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags) 252 { 253 t_gen_helper_raise_exception(dc, flags); 254 } 255 256 static bool gen_check_supervisor(DisasContext *dc) 257 { 258 if (FIELD_EX32(dc->tb_flags, TBFLAGS, U)) { 259 /* CPU in user mode, privileged instruction called, stop. */ 260 t_gen_helper_raise_exception(dc, EXCP_SUPERI); 261 return false; 262 } 263 return true; 264 } 265 266 /* 267 * Used as a placeholder for all instructions which do not have 268 * an effect on the simulator (e.g. flush, sync) 269 */ 270 static void nop(DisasContext *dc, uint32_t code, uint32_t flags) 271 { 272 /* Nothing to do here */ 273 } 274 275 /* 276 * J-Type instructions 277 */ 278 static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags) 279 { 280 J_TYPE(instr, code); 281 gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2)); 282 } 283 284 static void call(DisasContext *dc, uint32_t code, uint32_t flags) 285 { 286 tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next); 287 jmpi(dc, code, flags); 288 } 289 290 /* 291 * I-Type instructions 292 */ 293 /* Load instructions */ 294 static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags) 295 { 296 I_TYPE(instr, code); 297 298 TCGv addr = tcg_temp_new(); 299 TCGv data = dest_gpr(dc, instr.b); 300 301 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s); 302 tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags); 303 tcg_temp_free(addr); 304 } 305 306 /* Store instructions */ 307 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags) 308 { 309 I_TYPE(instr, code); 310 TCGv val = load_gpr(dc, instr.b); 311 312 TCGv addr = tcg_temp_new(); 313 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s); 314 tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags); 315 tcg_temp_free(addr); 316 } 317 318 /* Branch instructions */ 319 static void br(DisasContext *dc, uint32_t code, uint32_t flags) 320 { 321 I_TYPE(instr, code); 322 323 gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4)); 324 } 325 326 static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags) 327 { 328 I_TYPE(instr, code); 329 330 TCGLabel *l1 = gen_new_label(); 331 tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1); 332 gen_goto_tb(dc, 0, dc->base.pc_next); 333 gen_set_label(l1); 334 gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4)); 335 } 336 337 /* Comparison instructions */ 338 static void do_i_cmpxx(DisasContext *dc, uint32_t insn, 339 TCGCond cond, ImmFromIType *imm) 340 { 341 I_TYPE(instr, insn); 342 tcg_gen_setcondi_tl(cond, dest_gpr(dc, instr.b), 343 load_gpr(dc, instr.a), imm(&instr)); 344 } 345 346 #define gen_i_cmpxx(fname, imm) \ 347 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 348 { do_i_cmpxx(dc, code, flags, imm); } 349 350 gen_i_cmpxx(gen_cmpxxsi, imm_signed) 351 gen_i_cmpxx(gen_cmpxxui, imm_unsigned) 352 353 /* Math/logic instructions */ 354 static void do_i_math_logic(DisasContext *dc, uint32_t insn, 355 GenFn2i *fn, ImmFromIType *imm, 356 bool x_op_0_eq_x) 357 { 358 I_TYPE(instr, insn); 359 target_ulong val; 360 361 if (unlikely(instr.b == R_ZERO)) { 362 /* Store to R_ZERO is ignored -- this catches the canonical NOP. */ 363 return; 364 } 365 366 val = imm(&instr); 367 368 if (instr.a == R_ZERO && FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0)) { 369 /* This catches the canonical expansions of movi and movhi. */ 370 tcg_gen_movi_tl(dest_gpr(dc, instr.b), x_op_0_eq_x ? val : 0); 371 } else { 372 fn(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), val); 373 } 374 } 375 376 #define gen_i_math_logic(fname, insn, x_op_0, imm) \ 377 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 378 { do_i_math_logic(dc, code, tcg_gen_##insn##_tl, imm, x_op_0); } 379 380 gen_i_math_logic(addi, addi, 1, imm_signed) 381 gen_i_math_logic(muli, muli, 0, imm_signed) 382 383 gen_i_math_logic(andi, andi, 0, imm_unsigned) 384 gen_i_math_logic(ori, ori, 1, imm_unsigned) 385 gen_i_math_logic(xori, xori, 1, imm_unsigned) 386 387 gen_i_math_logic(andhi, andi, 0, imm_shifted) 388 gen_i_math_logic(orhi , ori, 1, imm_shifted) 389 gen_i_math_logic(xorhi, xori, 1, imm_shifted) 390 391 /* rB <- prs.rA + sigma(IMM16) */ 392 static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags) 393 { 394 if (!dc->eic_present) { 395 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); 396 return; 397 } 398 if (!gen_check_supervisor(dc)) { 399 return; 400 } 401 402 #ifdef CONFIG_USER_ONLY 403 g_assert_not_reached(); 404 #else 405 I_TYPE(instr, code); 406 TCGv dest = dest_gpr(dc, instr.b); 407 gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a)); 408 tcg_gen_addi_tl(dest, dest, instr.imm16.s); 409 #endif 410 } 411 412 /* Prototype only, defined below */ 413 static void handle_r_type_instr(DisasContext *dc, uint32_t code, 414 uint32_t flags); 415 416 static const Nios2Instruction i_type_instructions[] = { 417 INSTRUCTION(call), /* call */ 418 INSTRUCTION(jmpi), /* jmpi */ 419 INSTRUCTION_ILLEGAL(), 420 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */ 421 INSTRUCTION(addi), /* addi */ 422 INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */ 423 INSTRUCTION(br), /* br */ 424 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */ 425 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */ 426 INSTRUCTION_ILLEGAL(), 427 INSTRUCTION_ILLEGAL(), 428 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhu */ 429 INSTRUCTION(andi), /* andi */ 430 INSTRUCTION_FLG(gen_stx, MO_UW), /* sth */ 431 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */ 432 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldh */ 433 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */ 434 INSTRUCTION_ILLEGAL(), 435 INSTRUCTION_ILLEGAL(), 436 INSTRUCTION_NOP(), /* initda */ 437 INSTRUCTION(ori), /* ori */ 438 INSTRUCTION_FLG(gen_stx, MO_UL), /* stw */ 439 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */ 440 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldw */ 441 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */ 442 INSTRUCTION_ILLEGAL(), 443 INSTRUCTION_ILLEGAL(), 444 INSTRUCTION_NOP(), /* flushda */ 445 INSTRUCTION(xori), /* xori */ 446 INSTRUCTION_ILLEGAL(), 447 INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */ 448 INSTRUCTION_ILLEGAL(), 449 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */ 450 INSTRUCTION_ILLEGAL(), 451 INSTRUCTION_ILLEGAL(), 452 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */ 453 INSTRUCTION(muli), /* muli */ 454 INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */ 455 INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */ 456 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */ 457 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */ 458 INSTRUCTION_ILLEGAL(), 459 INSTRUCTION_ILLEGAL(), 460 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhuio */ 461 INSTRUCTION(andhi), /* andhi */ 462 INSTRUCTION_FLG(gen_stx, MO_UW), /* sthio */ 463 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */ 464 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldhio */ 465 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */ 466 INSTRUCTION_ILLEGAL(), 467 INSTRUCTION_UNIMPLEMENTED(), /* custom */ 468 INSTRUCTION_NOP(), /* initd */ 469 INSTRUCTION(orhi), /* orhi */ 470 INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */ 471 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */ 472 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */ 473 INSTRUCTION(rdprs), /* rdprs */ 474 INSTRUCTION_ILLEGAL(), 475 INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */ 476 INSTRUCTION_NOP(), /* flushd */ 477 INSTRUCTION(xorhi), /* xorhi */ 478 INSTRUCTION_ILLEGAL(), 479 INSTRUCTION_ILLEGAL(), 480 INSTRUCTION_ILLEGAL(), 481 }; 482 483 /* 484 * R-Type instructions 485 */ 486 /* 487 * status <- estatus 488 * PC <- ea 489 */ 490 static void eret(DisasContext *dc, uint32_t code, uint32_t flags) 491 { 492 if (!gen_check_supervisor(dc)) { 493 return; 494 } 495 496 #ifdef CONFIG_USER_ONLY 497 g_assert_not_reached(); 498 #else 499 if (FIELD_EX32(dc->tb_flags, TBFLAGS, CRS0)) { 500 TCGv tmp = tcg_temp_new(); 501 tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_ESTATUS])); 502 gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_EA)); 503 tcg_temp_free(tmp); 504 } else { 505 gen_helper_eret(cpu_env, load_gpr(dc, R_SSTATUS), load_gpr(dc, R_EA)); 506 } 507 dc->base.is_jmp = DISAS_NORETURN; 508 #endif 509 } 510 511 /* PC <- ra */ 512 static void ret(DisasContext *dc, uint32_t code, uint32_t flags) 513 { 514 gen_jumpr(dc, R_RA, false); 515 } 516 517 /* 518 * status <- bstatus 519 * PC <- ba 520 */ 521 static void bret(DisasContext *dc, uint32_t code, uint32_t flags) 522 { 523 if (!gen_check_supervisor(dc)) { 524 return; 525 } 526 527 #ifdef CONFIG_USER_ONLY 528 g_assert_not_reached(); 529 #else 530 TCGv tmp = tcg_temp_new(); 531 tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPUNios2State, ctrl[CR_BSTATUS])); 532 gen_helper_eret(cpu_env, tmp, load_gpr(dc, R_BA)); 533 tcg_temp_free(tmp); 534 535 dc->base.is_jmp = DISAS_NORETURN; 536 #endif 537 } 538 539 /* PC <- rA */ 540 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags) 541 { 542 R_TYPE(instr, code); 543 544 gen_jumpr(dc, instr.a, false); 545 } 546 547 /* rC <- PC + 4 */ 548 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags) 549 { 550 R_TYPE(instr, code); 551 552 tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next); 553 } 554 555 /* 556 * ra <- PC + 4 557 * PC <- rA 558 */ 559 static void callr(DisasContext *dc, uint32_t code, uint32_t flags) 560 { 561 R_TYPE(instr, code); 562 563 gen_jumpr(dc, instr.a, true); 564 } 565 566 /* rC <- ctlN */ 567 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags) 568 { 569 if (!gen_check_supervisor(dc)) { 570 return; 571 } 572 573 #ifdef CONFIG_USER_ONLY 574 g_assert_not_reached(); 575 #else 576 R_TYPE(instr, code); 577 TCGv t1, t2, dest = dest_gpr(dc, instr.c); 578 579 /* Reserved registers read as zero. */ 580 if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) { 581 tcg_gen_movi_tl(dest, 0); 582 return; 583 } 584 585 switch (instr.imm5) { 586 case CR_IPENDING: 587 /* 588 * The value of the ipending register is synthetic. 589 * In hw, this is the AND of a set of hardware irq lines 590 * with the ienable register. In qemu, we re-use the space 591 * of CR_IPENDING to store the set of irq lines, and so we 592 * must perform the AND here, and anywhere else we need the 593 * guest value of ipending. 594 */ 595 t1 = tcg_temp_new(); 596 t2 = tcg_temp_new(); 597 tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ctrl[CR_IPENDING])); 598 tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ctrl[CR_IENABLE])); 599 tcg_gen_and_tl(dest, t1, t2); 600 tcg_temp_free(t1); 601 tcg_temp_free(t2); 602 break; 603 default: 604 tcg_gen_ld_tl(dest, cpu_env, 605 offsetof(CPUNios2State, ctrl[instr.imm5])); 606 break; 607 } 608 #endif 609 } 610 611 /* ctlN <- rA */ 612 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) 613 { 614 if (!gen_check_supervisor(dc)) { 615 return; 616 } 617 618 #ifdef CONFIG_USER_ONLY 619 g_assert_not_reached(); 620 #else 621 R_TYPE(instr, code); 622 TCGv v = load_gpr(dc, instr.a); 623 uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]); 624 uint32_t wr = dc->cr_state[instr.imm5].writable; 625 uint32_t ro = dc->cr_state[instr.imm5].readonly; 626 627 /* Skip reserved or readonly registers. */ 628 if (wr == 0) { 629 return; 630 } 631 632 switch (instr.imm5) { 633 case CR_PTEADDR: 634 gen_helper_mmu_write_pteaddr(cpu_env, v); 635 break; 636 case CR_TLBACC: 637 gen_helper_mmu_write_tlbacc(cpu_env, v); 638 break; 639 case CR_TLBMISC: 640 gen_helper_mmu_write_tlbmisc(cpu_env, v); 641 break; 642 case CR_STATUS: 643 case CR_IENABLE: 644 /* If interrupts were enabled using WRCTL, trigger them. */ 645 dc->base.is_jmp = DISAS_UPDATE; 646 /* fall through */ 647 default: 648 if (wr == -1) { 649 /* The register is entirely writable. */ 650 tcg_gen_st_tl(v, cpu_env, ofs); 651 } else { 652 /* 653 * The register is partially read-only or reserved: 654 * merge the value. 655 */ 656 TCGv n = tcg_temp_new(); 657 658 tcg_gen_andi_tl(n, v, wr); 659 660 if (ro != 0) { 661 TCGv o = tcg_temp_new(); 662 tcg_gen_ld_tl(o, cpu_env, ofs); 663 tcg_gen_andi_tl(o, o, ro); 664 tcg_gen_or_tl(n, n, o); 665 tcg_temp_free(o); 666 } 667 668 tcg_gen_st_tl(n, cpu_env, ofs); 669 tcg_temp_free(n); 670 } 671 break; 672 } 673 #endif 674 } 675 676 /* prs.rC <- rA */ 677 static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags) 678 { 679 if (!dc->eic_present) { 680 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); 681 return; 682 } 683 if (!gen_check_supervisor(dc)) { 684 return; 685 } 686 687 #ifdef CONFIG_USER_ONLY 688 g_assert_not_reached(); 689 #else 690 R_TYPE(instr, code); 691 gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c), 692 load_gpr(dc, instr.a)); 693 /* 694 * The expected write to PRS[r0] is 0, from CRS[r0]. 695 * If not, and CRS == PRS (which we cannot tell from here), 696 * we may now have a non-zero value in our current r0. 697 * By ending the TB, we re-evaluate tb_flags and find out. 698 */ 699 if (instr.c == 0 700 && (instr.a != 0 || !FIELD_EX32(dc->tb_flags, TBFLAGS, R0_0))) { 701 dc->base.is_jmp = DISAS_UPDATE; 702 } 703 #endif 704 } 705 706 /* Comparison instructions */ 707 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags) 708 { 709 R_TYPE(instr, code); 710 tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c), 711 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); 712 } 713 714 /* Math/logic instructions */ 715 static void do_ri_math_logic(DisasContext *dc, uint32_t insn, GenFn2i *fn) 716 { 717 R_TYPE(instr, insn); 718 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), instr.imm5); 719 } 720 721 static void do_rr_math_logic(DisasContext *dc, uint32_t insn, GenFn3 *fn) 722 { 723 R_TYPE(instr, insn); 724 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), load_gpr(dc, instr.b)); 725 } 726 727 #define gen_ri_math_logic(fname, insn) \ 728 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 729 { do_ri_math_logic(dc, code, tcg_gen_##insn##_tl); } 730 731 #define gen_rr_math_logic(fname, insn) \ 732 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 733 { do_rr_math_logic(dc, code, tcg_gen_##insn##_tl); } 734 735 gen_rr_math_logic(add, add) 736 gen_rr_math_logic(sub, sub) 737 gen_rr_math_logic(mul, mul) 738 739 gen_rr_math_logic(and, and) 740 gen_rr_math_logic(or, or) 741 gen_rr_math_logic(xor, xor) 742 gen_rr_math_logic(nor, nor) 743 744 gen_ri_math_logic(srai, sari) 745 gen_ri_math_logic(srli, shri) 746 gen_ri_math_logic(slli, shli) 747 gen_ri_math_logic(roli, rotli) 748 749 static void do_rr_mul_high(DisasContext *dc, uint32_t insn, GenFn4 *fn) 750 { 751 R_TYPE(instr, insn); 752 TCGv discard = tcg_temp_new(); 753 754 fn(discard, dest_gpr(dc, instr.c), 755 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); 756 tcg_temp_free(discard); 757 } 758 759 #define gen_rr_mul_high(fname, insn) \ 760 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 761 { do_rr_mul_high(dc, code, tcg_gen_##insn##_tl); } 762 763 gen_rr_mul_high(mulxss, muls2) 764 gen_rr_mul_high(mulxuu, mulu2) 765 gen_rr_mul_high(mulxsu, mulsu2) 766 767 static void do_rr_shift(DisasContext *dc, uint32_t insn, GenFn3 *fn) 768 { 769 R_TYPE(instr, insn); 770 TCGv sh = tcg_temp_new(); 771 772 tcg_gen_andi_tl(sh, load_gpr(dc, instr.b), 31); 773 fn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), sh); 774 tcg_temp_free(sh); 775 } 776 777 #define gen_rr_shift(fname, insn) \ 778 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 779 { do_rr_shift(dc, code, tcg_gen_##insn##_tl); } 780 781 gen_rr_shift(sra, sar) 782 gen_rr_shift(srl, shr) 783 gen_rr_shift(sll, shl) 784 gen_rr_shift(rol, rotl) 785 gen_rr_shift(ror, rotr) 786 787 static void divs(DisasContext *dc, uint32_t code, uint32_t flags) 788 { 789 R_TYPE(instr, (code)); 790 gen_helper_divs(dest_gpr(dc, instr.c), cpu_env, 791 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); 792 } 793 794 static void divu(DisasContext *dc, uint32_t code, uint32_t flags) 795 { 796 R_TYPE(instr, (code)); 797 gen_helper_divu(dest_gpr(dc, instr.c), cpu_env, 798 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); 799 } 800 801 static void trap(DisasContext *dc, uint32_t code, uint32_t flags) 802 { 803 #ifdef CONFIG_USER_ONLY 804 /* 805 * The imm5 field is not stored anywhere on real hw; the kernel 806 * has to load the insn and extract the field. But we can make 807 * things easier for cpu_loop if we pop this into env->error_code. 808 */ 809 R_TYPE(instr, code); 810 tcg_gen_st_i32(tcg_constant_i32(instr.imm5), cpu_env, 811 offsetof(CPUNios2State, error_code)); 812 #endif 813 t_gen_helper_raise_exception(dc, EXCP_TRAP); 814 } 815 816 static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags) 817 { 818 #ifndef CONFIG_USER_ONLY 819 /* The semihosting instruction is "break 1". */ 820 bool is_user = FIELD_EX32(dc->tb_flags, TBFLAGS, U); 821 R_TYPE(instr, code); 822 if (semihosting_enabled(is_user) && instr.imm5 == 1) { 823 t_gen_helper_raise_exception(dc, EXCP_SEMIHOST); 824 return; 825 } 826 #endif 827 828 t_gen_helper_raise_exception(dc, EXCP_BREAK); 829 } 830 831 static const Nios2Instruction r_type_instructions[] = { 832 INSTRUCTION_ILLEGAL(), 833 INSTRUCTION(eret), /* eret */ 834 INSTRUCTION(roli), /* roli */ 835 INSTRUCTION(rol), /* rol */ 836 INSTRUCTION_NOP(), /* flushp */ 837 INSTRUCTION(ret), /* ret */ 838 INSTRUCTION(nor), /* nor */ 839 INSTRUCTION(mulxuu), /* mulxuu */ 840 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */ 841 INSTRUCTION(bret), /* bret */ 842 INSTRUCTION_ILLEGAL(), 843 INSTRUCTION(ror), /* ror */ 844 INSTRUCTION_NOP(), /* flushi */ 845 INSTRUCTION(jmp), /* jmp */ 846 INSTRUCTION(and), /* and */ 847 INSTRUCTION_ILLEGAL(), 848 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */ 849 INSTRUCTION_ILLEGAL(), 850 INSTRUCTION(slli), /* slli */ 851 INSTRUCTION(sll), /* sll */ 852 INSTRUCTION(wrprs), /* wrprs */ 853 INSTRUCTION_ILLEGAL(), 854 INSTRUCTION(or), /* or */ 855 INSTRUCTION(mulxsu), /* mulxsu */ 856 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */ 857 INSTRUCTION_ILLEGAL(), 858 INSTRUCTION(srli), /* srli */ 859 INSTRUCTION(srl), /* srl */ 860 INSTRUCTION(nextpc), /* nextpc */ 861 INSTRUCTION(callr), /* callr */ 862 INSTRUCTION(xor), /* xor */ 863 INSTRUCTION(mulxss), /* mulxss */ 864 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */ 865 INSTRUCTION_ILLEGAL(), 866 INSTRUCTION_ILLEGAL(), 867 INSTRUCTION_ILLEGAL(), 868 INSTRUCTION(divu), /* divu */ 869 INSTRUCTION(divs), /* div */ 870 INSTRUCTION(rdctl), /* rdctl */ 871 INSTRUCTION(mul), /* mul */ 872 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */ 873 INSTRUCTION_NOP(), /* initi */ 874 INSTRUCTION_ILLEGAL(), 875 INSTRUCTION_ILLEGAL(), 876 INSTRUCTION_ILLEGAL(), 877 INSTRUCTION(trap), /* trap */ 878 INSTRUCTION(wrctl), /* wrctl */ 879 INSTRUCTION_ILLEGAL(), 880 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */ 881 INSTRUCTION(add), /* add */ 882 INSTRUCTION_ILLEGAL(), 883 INSTRUCTION_ILLEGAL(), 884 INSTRUCTION(gen_break), /* break */ 885 INSTRUCTION_ILLEGAL(), 886 INSTRUCTION(nop), /* nop */ 887 INSTRUCTION_ILLEGAL(), 888 INSTRUCTION_ILLEGAL(), 889 INSTRUCTION(sub), /* sub */ 890 INSTRUCTION(srai), /* srai */ 891 INSTRUCTION(sra), /* sra */ 892 INSTRUCTION_ILLEGAL(), 893 INSTRUCTION_ILLEGAL(), 894 INSTRUCTION_ILLEGAL(), 895 INSTRUCTION_ILLEGAL(), 896 }; 897 898 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags) 899 { 900 uint8_t opx; 901 const Nios2Instruction *instr; 902 903 opx = get_opxcode(code); 904 if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) { 905 goto illegal_op; 906 } 907 908 instr = &r_type_instructions[opx]; 909 instr->handler(dc, code, instr->flags); 910 911 return; 912 913 illegal_op: 914 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); 915 } 916 917 static const char * const gr_regnames[NUM_GP_REGS] = { 918 "zero", "at", "r2", "r3", 919 "r4", "r5", "r6", "r7", 920 "r8", "r9", "r10", "r11", 921 "r12", "r13", "r14", "r15", 922 "r16", "r17", "r18", "r19", 923 "r20", "r21", "r22", "r23", 924 "et", "bt", "gp", "sp", 925 "fp", "ea", "ba", "ra", 926 }; 927 928 #ifndef CONFIG_USER_ONLY 929 static const char * const cr_regnames[NUM_CR_REGS] = { 930 "status", "estatus", "bstatus", "ienable", 931 "ipending", "cpuid", "res6", "exception", 932 "pteaddr", "tlbacc", "tlbmisc", "reserved1", 933 "badaddr", "config", "mpubase", "mpuacc", 934 "res16", "res17", "res18", "res19", 935 "res20", "res21", "res22", "res23", 936 "res24", "res25", "res26", "res27", 937 "res28", "res29", "res30", "res31", 938 }; 939 #endif 940 941 #include "exec/gen-icount.h" 942 943 /* generate intermediate code for basic block 'tb'. */ 944 static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 945 { 946 DisasContext *dc = container_of(dcbase, DisasContext, base); 947 CPUNios2State *env = cs->env_ptr; 948 Nios2CPU *cpu = env_archcpu(env); 949 int page_insns; 950 951 dc->mem_idx = cpu_mmu_index(env, false); 952 dc->cr_state = cpu->cr_state; 953 dc->tb_flags = dc->base.tb->flags; 954 dc->eic_present = cpu->eic_present; 955 956 /* Bound the number of insns to execute to those left on the page. */ 957 page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 958 dc->base.max_insns = MIN(page_insns, dc->base.max_insns); 959 } 960 961 static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs) 962 { 963 } 964 965 static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 966 { 967 tcg_gen_insn_start(dcbase->pc_next); 968 } 969 970 static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 971 { 972 DisasContext *dc = container_of(dcbase, DisasContext, base); 973 CPUNios2State *env = cs->env_ptr; 974 const Nios2Instruction *instr; 975 uint32_t code, pc; 976 uint8_t op; 977 978 pc = dc->base.pc_next; 979 dc->pc = pc; 980 dc->base.pc_next = pc + 4; 981 982 /* Decode an instruction */ 983 code = cpu_ldl_code(env, pc); 984 op = get_opcode(code); 985 986 if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) { 987 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); 988 return; 989 } 990 991 dc->sink = NULL; 992 993 instr = &i_type_instructions[op]; 994 instr->handler(dc, code, instr->flags); 995 996 if (dc->sink) { 997 tcg_temp_free(dc->sink); 998 } 999 } 1000 1001 static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 1002 { 1003 DisasContext *dc = container_of(dcbase, DisasContext, base); 1004 1005 /* Indicate where the next block should start */ 1006 switch (dc->base.is_jmp) { 1007 case DISAS_TOO_MANY: 1008 gen_goto_tb(dc, 0, dc->base.pc_next); 1009 break; 1010 1011 case DISAS_UPDATE: 1012 /* Save the current PC, and return to the main loop. */ 1013 tcg_gen_movi_tl(cpu_pc, dc->base.pc_next); 1014 tcg_gen_exit_tb(NULL, 0); 1015 break; 1016 1017 case DISAS_NORETURN: 1018 /* nothing more to generate */ 1019 break; 1020 1021 default: 1022 g_assert_not_reached(); 1023 } 1024 } 1025 1026 static void nios2_tr_disas_log(const DisasContextBase *dcbase, 1027 CPUState *cpu, FILE *logfile) 1028 { 1029 fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); 1030 target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); 1031 } 1032 1033 static const TranslatorOps nios2_tr_ops = { 1034 .init_disas_context = nios2_tr_init_disas_context, 1035 .tb_start = nios2_tr_tb_start, 1036 .insn_start = nios2_tr_insn_start, 1037 .translate_insn = nios2_tr_translate_insn, 1038 .tb_stop = nios2_tr_tb_stop, 1039 .disas_log = nios2_tr_disas_log, 1040 }; 1041 1042 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns, 1043 target_ulong pc, void *host_pc) 1044 { 1045 DisasContext dc; 1046 translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base); 1047 } 1048 1049 void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1050 { 1051 Nios2CPU *cpu = NIOS2_CPU(cs); 1052 CPUNios2State *env = &cpu->env; 1053 int i; 1054 1055 qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc)); 1056 1057 for (i = 0; i < NUM_GP_REGS; i++) { 1058 qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]); 1059 if ((i + 1) % 4 == 0) { 1060 qemu_fprintf(f, "\n"); 1061 } 1062 } 1063 1064 #if !defined(CONFIG_USER_ONLY) 1065 int j; 1066 1067 for (i = j = 0; i < NUM_CR_REGS; i++) { 1068 if (!nios2_cr_reserved(&cpu->cr_state[i])) { 1069 qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]); 1070 if (++j % 4 == 0) { 1071 qemu_fprintf(f, "\n"); 1072 } 1073 } 1074 } 1075 if (j % 4 != 0) { 1076 qemu_fprintf(f, "\n"); 1077 } 1078 if (cpu->mmu_present) { 1079 qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n", 1080 env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK, 1081 FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID), 1082 env->mmu.tlbacc_wr); 1083 } 1084 #endif 1085 qemu_fprintf(f, "\n\n"); 1086 } 1087 1088 void nios2_tcg_init(void) 1089 { 1090 #ifndef CONFIG_USER_ONLY 1091 TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env, 1092 offsetof(CPUNios2State, regs), "crs"); 1093 1094 for (int i = 0; i < NUM_GP_REGS; i++) { 1095 cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]); 1096 } 1097 1098 #define offsetof_regs0(N) offsetof(CPUNios2State, shadow_regs[0][N]) 1099 #else 1100 #define offsetof_regs0(N) offsetof(CPUNios2State, regs[N]) 1101 #endif 1102 1103 for (int i = 0; i < NUM_GP_REGS; i++) { 1104 cpu_R[i] = tcg_global_mem_new(cpu_env, offsetof_regs0(i), 1105 gr_regnames[i]); 1106 } 1107 1108 #undef offsetof_regs0 1109 1110 cpu_pc = tcg_global_mem_new(cpu_env, 1111 offsetof(CPUNios2State, pc), "pc"); 1112 } 1113 1114 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb, 1115 target_ulong *data) 1116 { 1117 env->pc = data[0]; 1118 } 1119