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