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 37 /* is_jmp field values */ 38 #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 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 #define I_TYPE(instr, code) \ 56 struct { \ 57 uint8_t op; \ 58 union { \ 59 uint16_t u; \ 60 int16_t s; \ 61 } imm16; \ 62 uint8_t b; \ 63 uint8_t a; \ 64 } (instr) = { \ 65 .op = extract32((code), 0, 6), \ 66 .imm16.u = extract32((code), 6, 16), \ 67 .b = extract32((code), 22, 5), \ 68 .a = extract32((code), 27, 5), \ 69 } 70 71 /* R-Type instruction parsing */ 72 #define R_TYPE(instr, code) \ 73 struct { \ 74 uint8_t op; \ 75 uint8_t imm5; \ 76 uint8_t opx; \ 77 uint8_t c; \ 78 uint8_t b; \ 79 uint8_t a; \ 80 } (instr) = { \ 81 .op = extract32((code), 0, 6), \ 82 .imm5 = extract32((code), 6, 5), \ 83 .opx = extract32((code), 11, 6), \ 84 .c = extract32((code), 17, 5), \ 85 .b = extract32((code), 22, 5), \ 86 .a = extract32((code), 27, 5), \ 87 } 88 89 /* J-Type instruction parsing */ 90 #define J_TYPE(instr, code) \ 91 struct { \ 92 uint8_t op; \ 93 uint32_t imm26; \ 94 } (instr) = { \ 95 .op = extract32((code), 0, 6), \ 96 .imm26 = extract32((code), 6, 26), \ 97 } 98 99 typedef struct DisasContext { 100 DisasContextBase base; 101 TCGv_i32 zero; 102 target_ulong pc; 103 int mem_idx; 104 } DisasContext; 105 106 static TCGv cpu_R[NUM_CORE_REGS]; 107 108 typedef struct Nios2Instruction { 109 void (*handler)(DisasContext *dc, uint32_t code, uint32_t flags); 110 uint32_t flags; 111 } Nios2Instruction; 112 113 static uint8_t get_opcode(uint32_t code) 114 { 115 I_TYPE(instr, code); 116 return instr.op; 117 } 118 119 static uint8_t get_opxcode(uint32_t code) 120 { 121 R_TYPE(instr, code); 122 return instr.opx; 123 } 124 125 static TCGv load_zero(DisasContext *dc) 126 { 127 if (!dc->zero) { 128 dc->zero = tcg_const_i32(0); 129 } 130 return dc->zero; 131 } 132 133 static TCGv load_gpr(DisasContext *dc, uint8_t reg) 134 { 135 if (likely(reg != R_ZERO)) { 136 return cpu_R[reg]; 137 } else { 138 return load_zero(dc); 139 } 140 } 141 142 static void t_gen_helper_raise_exception(DisasContext *dc, 143 uint32_t index) 144 { 145 TCGv_i32 tmp = tcg_const_i32(index); 146 147 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc); 148 gen_helper_raise_exception(cpu_env, tmp); 149 tcg_temp_free_i32(tmp); 150 dc->base.is_jmp = DISAS_NORETURN; 151 } 152 153 static bool use_goto_tb(DisasContext *dc, uint32_t dest) 154 { 155 if (unlikely(dc->base.singlestep_enabled)) { 156 return false; 157 } 158 159 #ifndef CONFIG_USER_ONLY 160 return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 161 #else 162 return true; 163 #endif 164 } 165 166 static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest) 167 { 168 const TranslationBlock *tb = dc->base.tb; 169 170 if (use_goto_tb(dc, dest)) { 171 tcg_gen_goto_tb(n); 172 tcg_gen_movi_tl(cpu_R[R_PC], dest); 173 tcg_gen_exit_tb(tb, n); 174 } else { 175 tcg_gen_movi_tl(cpu_R[R_PC], dest); 176 tcg_gen_exit_tb(NULL, 0); 177 } 178 } 179 180 static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags) 181 { 182 t_gen_helper_raise_exception(dc, flags); 183 } 184 185 static void gen_check_supervisor(DisasContext *dc) 186 { 187 if (dc->base.tb->flags & CR_STATUS_U) { 188 /* CPU in user mode, privileged instruction called, stop. */ 189 t_gen_helper_raise_exception(dc, EXCP_SUPERI); 190 } 191 } 192 193 /* 194 * Used as a placeholder for all instructions which do not have 195 * an effect on the simulator (e.g. flush, sync) 196 */ 197 static void nop(DisasContext *dc, uint32_t code, uint32_t flags) 198 { 199 /* Nothing to do here */ 200 } 201 202 /* 203 * J-Type instructions 204 */ 205 static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags) 206 { 207 J_TYPE(instr, code); 208 gen_goto_tb(dc, 0, (dc->pc & 0xF0000000) | (instr.imm26 << 2)); 209 dc->base.is_jmp = DISAS_NORETURN; 210 } 211 212 static void call(DisasContext *dc, uint32_t code, uint32_t flags) 213 { 214 tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next); 215 jmpi(dc, code, flags); 216 } 217 218 /* 219 * I-Type instructions 220 */ 221 /* Load instructions */ 222 static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags) 223 { 224 I_TYPE(instr, code); 225 226 TCGv addr = tcg_temp_new(); 227 TCGv data; 228 229 /* 230 * WARNING: Loads into R_ZERO are ignored, but we must generate the 231 * memory access itself to emulate the CPU precisely. Load 232 * from a protected page to R_ZERO will cause SIGSEGV on 233 * the Nios2 CPU. 234 */ 235 if (likely(instr.b != R_ZERO)) { 236 data = cpu_R[instr.b]; 237 } else { 238 data = tcg_temp_new(); 239 } 240 241 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s); 242 tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags); 243 244 if (unlikely(instr.b == R_ZERO)) { 245 tcg_temp_free(data); 246 } 247 248 tcg_temp_free(addr); 249 } 250 251 /* Store instructions */ 252 static void gen_stx(DisasContext *dc, uint32_t code, uint32_t flags) 253 { 254 I_TYPE(instr, code); 255 TCGv val = load_gpr(dc, instr.b); 256 257 TCGv addr = tcg_temp_new(); 258 tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s); 259 tcg_gen_qemu_st_tl(val, addr, dc->mem_idx, flags); 260 tcg_temp_free(addr); 261 } 262 263 /* Branch instructions */ 264 static void br(DisasContext *dc, uint32_t code, uint32_t flags) 265 { 266 I_TYPE(instr, code); 267 268 gen_goto_tb(dc, 0, dc->base.pc_next + (instr.imm16.s & -4)); 269 dc->base.is_jmp = DISAS_NORETURN; 270 } 271 272 static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags) 273 { 274 I_TYPE(instr, code); 275 276 TCGLabel *l1 = gen_new_label(); 277 tcg_gen_brcond_tl(flags, cpu_R[instr.a], cpu_R[instr.b], l1); 278 gen_goto_tb(dc, 0, dc->base.pc_next); 279 gen_set_label(l1); 280 gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4)); 281 dc->base.is_jmp = DISAS_NORETURN; 282 } 283 284 /* Comparison instructions */ 285 #define gen_i_cmpxx(fname, op3) \ 286 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 287 { \ 288 I_TYPE(instr, (code)); \ 289 tcg_gen_setcondi_tl(flags, cpu_R[instr.b], cpu_R[instr.a], (op3)); \ 290 } 291 292 gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s) 293 gen_i_cmpxx(gen_cmpxxui, instr.imm16.u) 294 295 /* Math/logic instructions */ 296 #define gen_i_math_logic(fname, insn, resimm, op3) \ 297 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 298 { \ 299 I_TYPE(instr, (code)); \ 300 if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */ \ 301 return; \ 302 } else if (instr.a == R_ZERO) { /* MOVxI optimizations */ \ 303 tcg_gen_movi_tl(cpu_R[instr.b], (resimm) ? (op3) : 0); \ 304 } else { \ 305 tcg_gen_##insn##_tl(cpu_R[instr.b], cpu_R[instr.a], (op3)); \ 306 } \ 307 } 308 309 gen_i_math_logic(addi, addi, 1, instr.imm16.s) 310 gen_i_math_logic(muli, muli, 0, instr.imm16.s) 311 312 gen_i_math_logic(andi, andi, 0, instr.imm16.u) 313 gen_i_math_logic(ori, ori, 1, instr.imm16.u) 314 gen_i_math_logic(xori, xori, 1, instr.imm16.u) 315 316 gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16) 317 gen_i_math_logic(orhi , ori, 1, instr.imm16.u << 16) 318 gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16) 319 320 /* Prototype only, defined below */ 321 static void handle_r_type_instr(DisasContext *dc, uint32_t code, 322 uint32_t flags); 323 324 static const Nios2Instruction i_type_instructions[] = { 325 INSTRUCTION(call), /* call */ 326 INSTRUCTION(jmpi), /* jmpi */ 327 INSTRUCTION_ILLEGAL(), 328 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbu */ 329 INSTRUCTION(addi), /* addi */ 330 INSTRUCTION_FLG(gen_stx, MO_UB), /* stb */ 331 INSTRUCTION(br), /* br */ 332 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldb */ 333 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_GE), /* cmpgei */ 334 INSTRUCTION_ILLEGAL(), 335 INSTRUCTION_ILLEGAL(), 336 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhu */ 337 INSTRUCTION(andi), /* andi */ 338 INSTRUCTION_FLG(gen_stx, MO_UW), /* sth */ 339 INSTRUCTION_FLG(gen_bxx, TCG_COND_GE), /* bge */ 340 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldh */ 341 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_LT), /* cmplti */ 342 INSTRUCTION_ILLEGAL(), 343 INSTRUCTION_ILLEGAL(), 344 INSTRUCTION_NOP(), /* initda */ 345 INSTRUCTION(ori), /* ori */ 346 INSTRUCTION_FLG(gen_stx, MO_UL), /* stw */ 347 INSTRUCTION_FLG(gen_bxx, TCG_COND_LT), /* blt */ 348 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldw */ 349 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_NE), /* cmpnei */ 350 INSTRUCTION_ILLEGAL(), 351 INSTRUCTION_ILLEGAL(), 352 INSTRUCTION_NOP(), /* flushda */ 353 INSTRUCTION(xori), /* xori */ 354 INSTRUCTION_ILLEGAL(), 355 INSTRUCTION_FLG(gen_bxx, TCG_COND_NE), /* bne */ 356 INSTRUCTION_ILLEGAL(), 357 INSTRUCTION_FLG(gen_cmpxxsi, TCG_COND_EQ), /* cmpeqi */ 358 INSTRUCTION_ILLEGAL(), 359 INSTRUCTION_ILLEGAL(), 360 INSTRUCTION_FLG(gen_ldx, MO_UB), /* ldbuio */ 361 INSTRUCTION(muli), /* muli */ 362 INSTRUCTION_FLG(gen_stx, MO_UB), /* stbio */ 363 INSTRUCTION_FLG(gen_bxx, TCG_COND_EQ), /* beq */ 364 INSTRUCTION_FLG(gen_ldx, MO_SB), /* ldbio */ 365 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_GEU), /* cmpgeui */ 366 INSTRUCTION_ILLEGAL(), 367 INSTRUCTION_ILLEGAL(), 368 INSTRUCTION_FLG(gen_ldx, MO_UW), /* ldhuio */ 369 INSTRUCTION(andhi), /* andhi */ 370 INSTRUCTION_FLG(gen_stx, MO_UW), /* sthio */ 371 INSTRUCTION_FLG(gen_bxx, TCG_COND_GEU), /* bgeu */ 372 INSTRUCTION_FLG(gen_ldx, MO_SW), /* ldhio */ 373 INSTRUCTION_FLG(gen_cmpxxui, TCG_COND_LTU), /* cmpltui */ 374 INSTRUCTION_ILLEGAL(), 375 INSTRUCTION_UNIMPLEMENTED(), /* custom */ 376 INSTRUCTION_NOP(), /* initd */ 377 INSTRUCTION(orhi), /* orhi */ 378 INSTRUCTION_FLG(gen_stx, MO_SL), /* stwio */ 379 INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU), /* bltu */ 380 INSTRUCTION_FLG(gen_ldx, MO_UL), /* ldwio */ 381 INSTRUCTION_UNIMPLEMENTED(), /* rdprs */ 382 INSTRUCTION_ILLEGAL(), 383 INSTRUCTION_FLG(handle_r_type_instr, 0), /* R-Type */ 384 INSTRUCTION_NOP(), /* flushd */ 385 INSTRUCTION(xorhi), /* xorhi */ 386 INSTRUCTION_ILLEGAL(), 387 INSTRUCTION_ILLEGAL(), 388 INSTRUCTION_ILLEGAL(), 389 }; 390 391 /* 392 * R-Type instructions 393 */ 394 /* 395 * status <- estatus 396 * PC <- ea 397 */ 398 static void eret(DisasContext *dc, uint32_t code, uint32_t flags) 399 { 400 tcg_gen_mov_tl(cpu_R[CR_STATUS], cpu_R[CR_ESTATUS]); 401 tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_EA]); 402 403 dc->base.is_jmp = DISAS_JUMP; 404 } 405 406 /* PC <- ra */ 407 static void ret(DisasContext *dc, uint32_t code, uint32_t flags) 408 { 409 tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_RA]); 410 411 dc->base.is_jmp = DISAS_JUMP; 412 } 413 414 /* PC <- ba */ 415 static void bret(DisasContext *dc, uint32_t code, uint32_t flags) 416 { 417 tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_BA]); 418 419 dc->base.is_jmp = DISAS_JUMP; 420 } 421 422 /* PC <- rA */ 423 static void jmp(DisasContext *dc, uint32_t code, uint32_t flags) 424 { 425 R_TYPE(instr, code); 426 427 tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a)); 428 429 dc->base.is_jmp = DISAS_JUMP; 430 } 431 432 /* rC <- PC + 4 */ 433 static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags) 434 { 435 R_TYPE(instr, code); 436 437 if (likely(instr.c != R_ZERO)) { 438 tcg_gen_movi_tl(cpu_R[instr.c], dc->base.pc_next); 439 } 440 } 441 442 /* 443 * ra <- PC + 4 444 * PC <- rA 445 */ 446 static void callr(DisasContext *dc, uint32_t code, uint32_t flags) 447 { 448 R_TYPE(instr, code); 449 450 tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a)); 451 tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next); 452 453 dc->base.is_jmp = DISAS_JUMP; 454 } 455 456 /* rC <- ctlN */ 457 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags) 458 { 459 R_TYPE(instr, code); 460 461 gen_check_supervisor(dc); 462 463 switch (instr.imm5 + CR_BASE) { 464 case CR_PTEADDR: 465 case CR_TLBACC: 466 case CR_TLBMISC: 467 { 468 #if !defined(CONFIG_USER_ONLY) 469 if (likely(instr.c != R_ZERO)) { 470 tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]); 471 #ifdef DEBUG_MMU 472 TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE); 473 gen_helper_mmu_read_debug(cpu_R[instr.c], cpu_env, tmp); 474 tcg_temp_free_i32(tmp); 475 #endif 476 } 477 #endif 478 break; 479 } 480 481 default: 482 if (likely(instr.c != R_ZERO)) { 483 tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]); 484 } 485 break; 486 } 487 } 488 489 /* ctlN <- rA */ 490 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags) 491 { 492 R_TYPE(instr, code); 493 494 gen_check_supervisor(dc); 495 496 switch (instr.imm5 + CR_BASE) { 497 case CR_PTEADDR: 498 case CR_TLBACC: 499 case CR_TLBMISC: 500 { 501 #if !defined(CONFIG_USER_ONLY) 502 TCGv_i32 tmp = tcg_const_i32(instr.imm5 + CR_BASE); 503 gen_helper_mmu_write(cpu_env, tmp, load_gpr(dc, instr.a)); 504 tcg_temp_free_i32(tmp); 505 #endif 506 break; 507 } 508 509 default: 510 tcg_gen_mov_tl(cpu_R[instr.imm5 + CR_BASE], load_gpr(dc, instr.a)); 511 break; 512 } 513 514 /* If interrupts were enabled using WRCTL, trigger them. */ 515 #if !defined(CONFIG_USER_ONLY) 516 if ((instr.imm5 + CR_BASE) == CR_STATUS) { 517 if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { 518 gen_io_start(); 519 } 520 gen_helper_check_interrupts(cpu_env); 521 dc->base.is_jmp = DISAS_UPDATE; 522 } 523 #endif 524 } 525 526 /* Comparison instructions */ 527 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags) 528 { 529 R_TYPE(instr, code); 530 if (likely(instr.c != R_ZERO)) { 531 tcg_gen_setcond_tl(flags, cpu_R[instr.c], cpu_R[instr.a], 532 cpu_R[instr.b]); 533 } 534 } 535 536 /* Math/logic instructions */ 537 #define gen_r_math_logic(fname, insn, op3) \ 538 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 539 { \ 540 R_TYPE(instr, (code)); \ 541 if (likely(instr.c != R_ZERO)) { \ 542 tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), (op3)); \ 543 } \ 544 } 545 546 gen_r_math_logic(add, add_tl, load_gpr(dc, instr.b)) 547 gen_r_math_logic(sub, sub_tl, load_gpr(dc, instr.b)) 548 gen_r_math_logic(mul, mul_tl, load_gpr(dc, instr.b)) 549 550 gen_r_math_logic(and, and_tl, load_gpr(dc, instr.b)) 551 gen_r_math_logic(or, or_tl, load_gpr(dc, instr.b)) 552 gen_r_math_logic(xor, xor_tl, load_gpr(dc, instr.b)) 553 gen_r_math_logic(nor, nor_tl, load_gpr(dc, instr.b)) 554 555 gen_r_math_logic(srai, sari_tl, instr.imm5) 556 gen_r_math_logic(srli, shri_tl, instr.imm5) 557 gen_r_math_logic(slli, shli_tl, instr.imm5) 558 gen_r_math_logic(roli, rotli_tl, instr.imm5) 559 560 #define gen_r_mul(fname, insn) \ 561 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 562 { \ 563 R_TYPE(instr, (code)); \ 564 if (likely(instr.c != R_ZERO)) { \ 565 TCGv t0 = tcg_temp_new(); \ 566 tcg_gen_##insn(t0, cpu_R[instr.c], \ 567 load_gpr(dc, instr.a), load_gpr(dc, instr.b)); \ 568 tcg_temp_free(t0); \ 569 } \ 570 } 571 572 gen_r_mul(mulxss, muls2_tl) 573 gen_r_mul(mulxuu, mulu2_tl) 574 gen_r_mul(mulxsu, mulsu2_tl) 575 576 #define gen_r_shift_s(fname, insn) \ 577 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags) \ 578 { \ 579 R_TYPE(instr, (code)); \ 580 if (likely(instr.c != R_ZERO)) { \ 581 TCGv t0 = tcg_temp_new(); \ 582 tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31); \ 583 tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), t0); \ 584 tcg_temp_free(t0); \ 585 } \ 586 } 587 588 gen_r_shift_s(sra, sar_tl) 589 gen_r_shift_s(srl, shr_tl) 590 gen_r_shift_s(sll, shl_tl) 591 gen_r_shift_s(rol, rotl_tl) 592 gen_r_shift_s(ror, rotr_tl) 593 594 static void divs(DisasContext *dc, uint32_t code, uint32_t flags) 595 { 596 R_TYPE(instr, (code)); 597 598 /* Stores into R_ZERO are ignored */ 599 if (unlikely(instr.c == R_ZERO)) { 600 return; 601 } 602 603 TCGv t0 = tcg_temp_new(); 604 TCGv t1 = tcg_temp_new(); 605 TCGv t2 = tcg_temp_new(); 606 TCGv t3 = tcg_temp_new(); 607 608 tcg_gen_ext32s_tl(t0, load_gpr(dc, instr.a)); 609 tcg_gen_ext32s_tl(t1, load_gpr(dc, instr.b)); 610 tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); 611 tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); 612 tcg_gen_and_tl(t2, t2, t3); 613 tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); 614 tcg_gen_or_tl(t2, t2, t3); 615 tcg_gen_movi_tl(t3, 0); 616 tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); 617 tcg_gen_div_tl(cpu_R[instr.c], t0, t1); 618 tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]); 619 620 tcg_temp_free(t3); 621 tcg_temp_free(t2); 622 tcg_temp_free(t1); 623 tcg_temp_free(t0); 624 } 625 626 static void divu(DisasContext *dc, uint32_t code, uint32_t flags) 627 { 628 R_TYPE(instr, (code)); 629 630 /* Stores into R_ZERO are ignored */ 631 if (unlikely(instr.c == R_ZERO)) { 632 return; 633 } 634 635 TCGv t0 = tcg_temp_new(); 636 TCGv t1 = tcg_temp_new(); 637 TCGv t2 = tcg_const_tl(0); 638 TCGv t3 = tcg_const_tl(1); 639 640 tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a)); 641 tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b)); 642 tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); 643 tcg_gen_divu_tl(cpu_R[instr.c], t0, t1); 644 tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]); 645 646 tcg_temp_free(t3); 647 tcg_temp_free(t2); 648 tcg_temp_free(t1); 649 tcg_temp_free(t0); 650 } 651 652 static const Nios2Instruction r_type_instructions[] = { 653 INSTRUCTION_ILLEGAL(), 654 INSTRUCTION(eret), /* eret */ 655 INSTRUCTION(roli), /* roli */ 656 INSTRUCTION(rol), /* rol */ 657 INSTRUCTION_NOP(), /* flushp */ 658 INSTRUCTION(ret), /* ret */ 659 INSTRUCTION(nor), /* nor */ 660 INSTRUCTION(mulxuu), /* mulxuu */ 661 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GE), /* cmpge */ 662 INSTRUCTION(bret), /* bret */ 663 INSTRUCTION_ILLEGAL(), 664 INSTRUCTION(ror), /* ror */ 665 INSTRUCTION_NOP(), /* flushi */ 666 INSTRUCTION(jmp), /* jmp */ 667 INSTRUCTION(and), /* and */ 668 INSTRUCTION_ILLEGAL(), 669 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LT), /* cmplt */ 670 INSTRUCTION_ILLEGAL(), 671 INSTRUCTION(slli), /* slli */ 672 INSTRUCTION(sll), /* sll */ 673 INSTRUCTION_UNIMPLEMENTED(), /* wrprs */ 674 INSTRUCTION_ILLEGAL(), 675 INSTRUCTION(or), /* or */ 676 INSTRUCTION(mulxsu), /* mulxsu */ 677 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_NE), /* cmpne */ 678 INSTRUCTION_ILLEGAL(), 679 INSTRUCTION(srli), /* srli */ 680 INSTRUCTION(srl), /* srl */ 681 INSTRUCTION(nextpc), /* nextpc */ 682 INSTRUCTION(callr), /* callr */ 683 INSTRUCTION(xor), /* xor */ 684 INSTRUCTION(mulxss), /* mulxss */ 685 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_EQ), /* cmpeq */ 686 INSTRUCTION_ILLEGAL(), 687 INSTRUCTION_ILLEGAL(), 688 INSTRUCTION_ILLEGAL(), 689 INSTRUCTION(divu), /* divu */ 690 INSTRUCTION(divs), /* div */ 691 INSTRUCTION(rdctl), /* rdctl */ 692 INSTRUCTION(mul), /* mul */ 693 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_GEU), /* cmpgeu */ 694 INSTRUCTION_NOP(), /* initi */ 695 INSTRUCTION_ILLEGAL(), 696 INSTRUCTION_ILLEGAL(), 697 INSTRUCTION_ILLEGAL(), 698 INSTRUCTION_FLG(gen_excp, EXCP_TRAP), /* trap */ 699 INSTRUCTION(wrctl), /* wrctl */ 700 INSTRUCTION_ILLEGAL(), 701 INSTRUCTION_FLG(gen_cmpxx, TCG_COND_LTU), /* cmpltu */ 702 INSTRUCTION(add), /* add */ 703 INSTRUCTION_ILLEGAL(), 704 INSTRUCTION_ILLEGAL(), 705 INSTRUCTION_FLG(gen_excp, EXCP_BREAK), /* break */ 706 INSTRUCTION_ILLEGAL(), 707 INSTRUCTION(nop), /* nop */ 708 INSTRUCTION_ILLEGAL(), 709 INSTRUCTION_ILLEGAL(), 710 INSTRUCTION(sub), /* sub */ 711 INSTRUCTION(srai), /* srai */ 712 INSTRUCTION(sra), /* sra */ 713 INSTRUCTION_ILLEGAL(), 714 INSTRUCTION_ILLEGAL(), 715 INSTRUCTION_ILLEGAL(), 716 INSTRUCTION_ILLEGAL(), 717 }; 718 719 static void handle_r_type_instr(DisasContext *dc, uint32_t code, uint32_t flags) 720 { 721 uint8_t opx; 722 const Nios2Instruction *instr; 723 724 opx = get_opxcode(code); 725 if (unlikely(opx >= ARRAY_SIZE(r_type_instructions))) { 726 goto illegal_op; 727 } 728 729 instr = &r_type_instructions[opx]; 730 instr->handler(dc, code, instr->flags); 731 732 return; 733 734 illegal_op: 735 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); 736 } 737 738 static const char * const regnames[] = { 739 "zero", "at", "r2", "r3", 740 "r4", "r5", "r6", "r7", 741 "r8", "r9", "r10", "r11", 742 "r12", "r13", "r14", "r15", 743 "r16", "r17", "r18", "r19", 744 "r20", "r21", "r22", "r23", 745 "et", "bt", "gp", "sp", 746 "fp", "ea", "ba", "ra", 747 "status", "estatus", "bstatus", "ienable", 748 "ipending", "cpuid", "reserved0", "exception", 749 "pteaddr", "tlbacc", "tlbmisc", "reserved1", 750 "badaddr", "config", "mpubase", "mpuacc", 751 "reserved2", "reserved3", "reserved4", "reserved5", 752 "reserved6", "reserved7", "reserved8", "reserved9", 753 "reserved10", "reserved11", "reserved12", "reserved13", 754 "reserved14", "reserved15", "reserved16", "reserved17", 755 "rpc" 756 }; 757 758 #include "exec/gen-icount.h" 759 760 static void gen_exception(DisasContext *dc, uint32_t excp) 761 { 762 TCGv_i32 tmp = tcg_const_i32(excp); 763 764 tcg_gen_movi_tl(cpu_R[R_PC], dc->pc); 765 gen_helper_raise_exception(cpu_env, tmp); 766 tcg_temp_free_i32(tmp); 767 dc->base.is_jmp = DISAS_NORETURN; 768 } 769 770 /* generate intermediate code for basic block 'tb'. */ 771 static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 772 { 773 DisasContext *dc = container_of(dcbase, DisasContext, base); 774 CPUNios2State *env = cs->env_ptr; 775 int page_insns; 776 777 dc->mem_idx = cpu_mmu_index(env, false); 778 779 /* Bound the number of insns to execute to those left on the page. */ 780 page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 781 dc->base.max_insns = MIN(page_insns, dc->base.max_insns); 782 } 783 784 static void nios2_tr_tb_start(DisasContextBase *db, CPUState *cs) 785 { 786 } 787 788 static void nios2_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 789 { 790 tcg_gen_insn_start(dcbase->pc_next); 791 } 792 793 static bool nios2_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, 794 const CPUBreakpoint *bp) 795 { 796 DisasContext *dc = container_of(dcbase, DisasContext, base); 797 798 gen_exception(dc, EXCP_DEBUG); 799 /* 800 * The address covered by the breakpoint must be included in 801 * [tb->pc, tb->pc + tb->size) in order to for it to be 802 * properly cleared -- thus we increment the PC here so that 803 * the logic setting tb->size below does the right thing. 804 */ 805 dc->base.pc_next += 4; 806 return true; 807 } 808 809 static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 810 { 811 DisasContext *dc = container_of(dcbase, DisasContext, base); 812 CPUNios2State *env = cs->env_ptr; 813 const Nios2Instruction *instr; 814 uint32_t code, pc; 815 uint8_t op; 816 817 pc = dc->base.pc_next; 818 dc->pc = pc; 819 dc->base.pc_next = pc + 4; 820 821 /* Decode an instruction */ 822 823 #if defined(CONFIG_USER_ONLY) 824 /* FIXME: Is this needed ? */ 825 if (pc >= 0x1000 && pc < 0x2000) { 826 t_gen_helper_raise_exception(dc, 0xaa); 827 return; 828 } 829 #endif 830 831 code = cpu_ldl_code(env, pc); 832 op = get_opcode(code); 833 834 if (unlikely(op >= ARRAY_SIZE(i_type_instructions))) { 835 t_gen_helper_raise_exception(dc, EXCP_ILLEGAL); 836 return; 837 } 838 839 dc->zero = NULL; 840 841 instr = &i_type_instructions[op]; 842 instr->handler(dc, code, instr->flags); 843 844 if (dc->zero) { 845 tcg_temp_free(dc->zero); 846 } 847 } 848 849 static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 850 { 851 DisasContext *dc = container_of(dcbase, DisasContext, base); 852 853 /* Indicate where the next block should start */ 854 switch (dc->base.is_jmp) { 855 case DISAS_TOO_MANY: 856 case DISAS_UPDATE: 857 /* Save the current PC back into the CPU register */ 858 tcg_gen_movi_tl(cpu_R[R_PC], dc->base.pc_next); 859 tcg_gen_exit_tb(NULL, 0); 860 break; 861 862 case DISAS_JUMP: 863 /* The jump will already have updated the PC register */ 864 tcg_gen_exit_tb(NULL, 0); 865 break; 866 867 case DISAS_NORETURN: 868 /* nothing more to generate */ 869 break; 870 871 default: 872 g_assert_not_reached(); 873 } 874 } 875 876 static void nios2_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) 877 { 878 qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); 879 log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); 880 } 881 882 static const TranslatorOps nios2_tr_ops = { 883 .init_disas_context = nios2_tr_init_disas_context, 884 .tb_start = nios2_tr_tb_start, 885 .insn_start = nios2_tr_insn_start, 886 .breakpoint_check = nios2_tr_breakpoint_check, 887 .translate_insn = nios2_tr_translate_insn, 888 .tb_stop = nios2_tr_tb_stop, 889 .disas_log = nios2_tr_disas_log, 890 }; 891 892 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) 893 { 894 DisasContext dc; 895 translator_loop(&nios2_tr_ops, &dc.base, cs, tb, max_insns); 896 } 897 898 void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags) 899 { 900 Nios2CPU *cpu = NIOS2_CPU(cs); 901 CPUNios2State *env = &cpu->env; 902 int i; 903 904 if (!env) { 905 return; 906 } 907 908 qemu_fprintf(f, "IN: PC=%x %s\n", 909 env->regs[R_PC], lookup_symbol(env->regs[R_PC])); 910 911 for (i = 0; i < NUM_CORE_REGS; i++) { 912 qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]); 913 if ((i + 1) % 4 == 0) { 914 qemu_fprintf(f, "\n"); 915 } 916 } 917 #if !defined(CONFIG_USER_ONLY) 918 qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n", 919 env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK, 920 (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4, 921 env->mmu.tlbacc_wr); 922 #endif 923 qemu_fprintf(f, "\n\n"); 924 } 925 926 void nios2_tcg_init(void) 927 { 928 int i; 929 930 for (i = 0; i < NUM_CORE_REGS; i++) { 931 cpu_R[i] = tcg_global_mem_new(cpu_env, 932 offsetof(CPUNios2State, regs[i]), 933 regnames[i]); 934 } 935 } 936 937 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb, 938 target_ulong *data) 939 { 940 env->regs[R_PC] = data[0]; 941 } 942