1 /* 2 * HPPA emulation cpu translation for qemu. 3 * 4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "cpu.h" 22 #include "disas/disas.h" 23 #include "qemu/host-utils.h" 24 #include "exec/exec-all.h" 25 #include "tcg/tcg-op.h" 26 #include "tcg/tcg-op-gvec.h" 27 #include "exec/helper-proto.h" 28 #include "exec/helper-gen.h" 29 #include "exec/translator.h" 30 #include "exec/log.h" 31 32 #define HELPER_H "helper.h" 33 #include "exec/helper-info.c.inc" 34 #undef HELPER_H 35 36 /* Choose to use explicit sizes within this file. */ 37 #undef tcg_temp_new 38 39 typedef struct DisasCond { 40 TCGCond c; 41 TCGv_i64 a0, a1; 42 } DisasCond; 43 44 typedef struct DisasContext { 45 DisasContextBase base; 46 CPUState *cs; 47 TCGOp *insn_start; 48 49 uint64_t iaoq_f; 50 uint64_t iaoq_b; 51 uint64_t iaoq_n; 52 TCGv_i64 iaoq_n_var; 53 54 DisasCond null_cond; 55 TCGLabel *null_lab; 56 57 TCGv_i64 zero; 58 59 uint32_t insn; 60 uint32_t tb_flags; 61 int mmu_idx; 62 int privilege; 63 bool psw_n_nonzero; 64 bool is_pa20; 65 66 #ifdef CONFIG_USER_ONLY 67 MemOp unalign; 68 #endif 69 } DisasContext; 70 71 #ifdef CONFIG_USER_ONLY 72 #define UNALIGN(C) (C)->unalign 73 #define MMU_DISABLED(C) false 74 #else 75 #define UNALIGN(C) MO_ALIGN 76 #define MMU_DISABLED(C) MMU_IDX_MMU_DISABLED((C)->mmu_idx) 77 #endif 78 79 /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 80 static int expand_sm_imm(DisasContext *ctx, int val) 81 { 82 /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */ 83 if (ctx->is_pa20) { 84 if (val & PSW_SM_W) { 85 val |= PSW_W; 86 } 87 val &= ~(PSW_SM_W | PSW_SM_E | PSW_G); 88 } else { 89 val &= ~(PSW_SM_W | PSW_SM_E | PSW_O); 90 } 91 return val; 92 } 93 94 /* Inverted space register indicates 0 means sr0 not inferred from base. */ 95 static int expand_sr3x(DisasContext *ctx, int val) 96 { 97 return ~val; 98 } 99 100 /* Convert the M:A bits within a memory insn to the tri-state value 101 we use for the final M. */ 102 static int ma_to_m(DisasContext *ctx, int val) 103 { 104 return val & 2 ? (val & 1 ? -1 : 1) : 0; 105 } 106 107 /* Convert the sign of the displacement to a pre or post-modify. */ 108 static int pos_to_m(DisasContext *ctx, int val) 109 { 110 return val ? 1 : -1; 111 } 112 113 static int neg_to_m(DisasContext *ctx, int val) 114 { 115 return val ? -1 : 1; 116 } 117 118 /* Used for branch targets and fp memory ops. */ 119 static int expand_shl2(DisasContext *ctx, int val) 120 { 121 return val << 2; 122 } 123 124 /* Used for fp memory ops. */ 125 static int expand_shl3(DisasContext *ctx, int val) 126 { 127 return val << 3; 128 } 129 130 /* Used for assemble_21. */ 131 static int expand_shl11(DisasContext *ctx, int val) 132 { 133 return val << 11; 134 } 135 136 static int assemble_6(DisasContext *ctx, int val) 137 { 138 /* 139 * Officially, 32 * x + 32 - y. 140 * Here, x is already in bit 5, and y is [4:0]. 141 * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1, 142 * with the overflow from bit 4 summing with x. 143 */ 144 return (val ^ 31) + 1; 145 } 146 147 /* Translate CMPI doubleword conditions to standard. */ 148 static int cmpbid_c(DisasContext *ctx, int val) 149 { 150 return val ? val : 4; /* 0 == "*<<" */ 151 } 152 153 154 /* Include the auto-generated decoder. */ 155 #include "decode-insns.c.inc" 156 157 /* We are not using a goto_tb (for whatever reason), but have updated 158 the iaq (for whatever reason), so don't do it again on exit. */ 159 #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 160 161 /* We are exiting the TB, but have neither emitted a goto_tb, nor 162 updated the iaq for the next instruction to be executed. */ 163 #define DISAS_IAQ_N_STALE DISAS_TARGET_1 164 165 /* Similarly, but we want to return to the main loop immediately 166 to recognize unmasked interrupts. */ 167 #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 168 #define DISAS_EXIT DISAS_TARGET_3 169 170 /* global register indexes */ 171 static TCGv_i64 cpu_gr[32]; 172 static TCGv_i64 cpu_sr[4]; 173 static TCGv_i64 cpu_srH; 174 static TCGv_i64 cpu_iaoq_f; 175 static TCGv_i64 cpu_iaoq_b; 176 static TCGv_i64 cpu_iasq_f; 177 static TCGv_i64 cpu_iasq_b; 178 static TCGv_i64 cpu_sar; 179 static TCGv_i64 cpu_psw_n; 180 static TCGv_i64 cpu_psw_v; 181 static TCGv_i64 cpu_psw_cb; 182 static TCGv_i64 cpu_psw_cb_msb; 183 184 void hppa_translate_init(void) 185 { 186 #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 187 188 typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 189 static const GlobalVar vars[] = { 190 { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 191 DEF_VAR(psw_n), 192 DEF_VAR(psw_v), 193 DEF_VAR(psw_cb), 194 DEF_VAR(psw_cb_msb), 195 DEF_VAR(iaoq_f), 196 DEF_VAR(iaoq_b), 197 }; 198 199 #undef DEF_VAR 200 201 /* Use the symbolic register names that match the disassembler. */ 202 static const char gr_names[32][4] = { 203 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 204 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 205 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 206 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 207 }; 208 /* SR[4-7] are not global registers so that we can index them. */ 209 static const char sr_names[5][4] = { 210 "sr0", "sr1", "sr2", "sr3", "srH" 211 }; 212 213 int i; 214 215 cpu_gr[0] = NULL; 216 for (i = 1; i < 32; i++) { 217 cpu_gr[i] = tcg_global_mem_new(tcg_env, 218 offsetof(CPUHPPAState, gr[i]), 219 gr_names[i]); 220 } 221 for (i = 0; i < 4; i++) { 222 cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 223 offsetof(CPUHPPAState, sr[i]), 224 sr_names[i]); 225 } 226 cpu_srH = tcg_global_mem_new_i64(tcg_env, 227 offsetof(CPUHPPAState, sr[4]), 228 sr_names[4]); 229 230 for (i = 0; i < ARRAY_SIZE(vars); ++i) { 231 const GlobalVar *v = &vars[i]; 232 *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 233 } 234 235 cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 236 offsetof(CPUHPPAState, iasq_f), 237 "iasq_f"); 238 cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 239 offsetof(CPUHPPAState, iasq_b), 240 "iasq_b"); 241 } 242 243 static void set_insn_breg(DisasContext *ctx, int breg) 244 { 245 assert(ctx->insn_start != NULL); 246 tcg_set_insn_start_param(ctx->insn_start, 2, breg); 247 ctx->insn_start = NULL; 248 } 249 250 static DisasCond cond_make_f(void) 251 { 252 return (DisasCond){ 253 .c = TCG_COND_NEVER, 254 .a0 = NULL, 255 .a1 = NULL, 256 }; 257 } 258 259 static DisasCond cond_make_t(void) 260 { 261 return (DisasCond){ 262 .c = TCG_COND_ALWAYS, 263 .a0 = NULL, 264 .a1 = NULL, 265 }; 266 } 267 268 static DisasCond cond_make_n(void) 269 { 270 return (DisasCond){ 271 .c = TCG_COND_NE, 272 .a0 = cpu_psw_n, 273 .a1 = tcg_constant_i64(0) 274 }; 275 } 276 277 static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 278 { 279 assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 280 return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 281 } 282 283 static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0) 284 { 285 return cond_make_tmp(c, a0, tcg_constant_i64(0)); 286 } 287 288 static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0) 289 { 290 TCGv_i64 tmp = tcg_temp_new_i64(); 291 tcg_gen_mov_i64(tmp, a0); 292 return cond_make_0_tmp(c, tmp); 293 } 294 295 static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 296 { 297 TCGv_i64 t0 = tcg_temp_new_i64(); 298 TCGv_i64 t1 = tcg_temp_new_i64(); 299 300 tcg_gen_mov_i64(t0, a0); 301 tcg_gen_mov_i64(t1, a1); 302 return cond_make_tmp(c, t0, t1); 303 } 304 305 static void cond_free(DisasCond *cond) 306 { 307 switch (cond->c) { 308 default: 309 cond->a0 = NULL; 310 cond->a1 = NULL; 311 /* fallthru */ 312 case TCG_COND_ALWAYS: 313 cond->c = TCG_COND_NEVER; 314 break; 315 case TCG_COND_NEVER: 316 break; 317 } 318 } 319 320 static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 321 { 322 if (reg == 0) { 323 return ctx->zero; 324 } else { 325 return cpu_gr[reg]; 326 } 327 } 328 329 static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 330 { 331 if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 332 return tcg_temp_new_i64(); 333 } else { 334 return cpu_gr[reg]; 335 } 336 } 337 338 static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 339 { 340 if (ctx->null_cond.c != TCG_COND_NEVER) { 341 tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 342 ctx->null_cond.a1, dest, t); 343 } else { 344 tcg_gen_mov_i64(dest, t); 345 } 346 } 347 348 static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 349 { 350 if (reg != 0) { 351 save_or_nullify(ctx, cpu_gr[reg], t); 352 } 353 } 354 355 #if HOST_BIG_ENDIAN 356 # define HI_OFS 0 357 # define LO_OFS 4 358 #else 359 # define HI_OFS 4 360 # define LO_OFS 0 361 #endif 362 363 static TCGv_i32 load_frw_i32(unsigned rt) 364 { 365 TCGv_i32 ret = tcg_temp_new_i32(); 366 tcg_gen_ld_i32(ret, tcg_env, 367 offsetof(CPUHPPAState, fr[rt & 31]) 368 + (rt & 32 ? LO_OFS : HI_OFS)); 369 return ret; 370 } 371 372 static TCGv_i32 load_frw0_i32(unsigned rt) 373 { 374 if (rt == 0) { 375 TCGv_i32 ret = tcg_temp_new_i32(); 376 tcg_gen_movi_i32(ret, 0); 377 return ret; 378 } else { 379 return load_frw_i32(rt); 380 } 381 } 382 383 static TCGv_i64 load_frw0_i64(unsigned rt) 384 { 385 TCGv_i64 ret = tcg_temp_new_i64(); 386 if (rt == 0) { 387 tcg_gen_movi_i64(ret, 0); 388 } else { 389 tcg_gen_ld32u_i64(ret, tcg_env, 390 offsetof(CPUHPPAState, fr[rt & 31]) 391 + (rt & 32 ? LO_OFS : HI_OFS)); 392 } 393 return ret; 394 } 395 396 static void save_frw_i32(unsigned rt, TCGv_i32 val) 397 { 398 tcg_gen_st_i32(val, tcg_env, 399 offsetof(CPUHPPAState, fr[rt & 31]) 400 + (rt & 32 ? LO_OFS : HI_OFS)); 401 } 402 403 #undef HI_OFS 404 #undef LO_OFS 405 406 static TCGv_i64 load_frd(unsigned rt) 407 { 408 TCGv_i64 ret = tcg_temp_new_i64(); 409 tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 410 return ret; 411 } 412 413 static TCGv_i64 load_frd0(unsigned rt) 414 { 415 if (rt == 0) { 416 TCGv_i64 ret = tcg_temp_new_i64(); 417 tcg_gen_movi_i64(ret, 0); 418 return ret; 419 } else { 420 return load_frd(rt); 421 } 422 } 423 424 static void save_frd(unsigned rt, TCGv_i64 val) 425 { 426 tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 427 } 428 429 static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 430 { 431 #ifdef CONFIG_USER_ONLY 432 tcg_gen_movi_i64(dest, 0); 433 #else 434 if (reg < 4) { 435 tcg_gen_mov_i64(dest, cpu_sr[reg]); 436 } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 437 tcg_gen_mov_i64(dest, cpu_srH); 438 } else { 439 tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 440 } 441 #endif 442 } 443 444 /* Skip over the implementation of an insn that has been nullified. 445 Use this when the insn is too complex for a conditional move. */ 446 static void nullify_over(DisasContext *ctx) 447 { 448 if (ctx->null_cond.c != TCG_COND_NEVER) { 449 /* The always condition should have been handled in the main loop. */ 450 assert(ctx->null_cond.c != TCG_COND_ALWAYS); 451 452 ctx->null_lab = gen_new_label(); 453 454 /* If we're using PSW[N], copy it to a temp because... */ 455 if (ctx->null_cond.a0 == cpu_psw_n) { 456 ctx->null_cond.a0 = tcg_temp_new_i64(); 457 tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 458 } 459 /* ... we clear it before branching over the implementation, 460 so that (1) it's clear after nullifying this insn and 461 (2) if this insn nullifies the next, PSW[N] is valid. */ 462 if (ctx->psw_n_nonzero) { 463 ctx->psw_n_nonzero = false; 464 tcg_gen_movi_i64(cpu_psw_n, 0); 465 } 466 467 tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 468 ctx->null_cond.a1, ctx->null_lab); 469 cond_free(&ctx->null_cond); 470 } 471 } 472 473 /* Save the current nullification state to PSW[N]. */ 474 static void nullify_save(DisasContext *ctx) 475 { 476 if (ctx->null_cond.c == TCG_COND_NEVER) { 477 if (ctx->psw_n_nonzero) { 478 tcg_gen_movi_i64(cpu_psw_n, 0); 479 } 480 return; 481 } 482 if (ctx->null_cond.a0 != cpu_psw_n) { 483 tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 484 ctx->null_cond.a0, ctx->null_cond.a1); 485 ctx->psw_n_nonzero = true; 486 } 487 cond_free(&ctx->null_cond); 488 } 489 490 /* Set a PSW[N] to X. The intention is that this is used immediately 491 before a goto_tb/exit_tb, so that there is no fallthru path to other 492 code within the TB. Therefore we do not update psw_n_nonzero. */ 493 static void nullify_set(DisasContext *ctx, bool x) 494 { 495 if (ctx->psw_n_nonzero || x) { 496 tcg_gen_movi_i64(cpu_psw_n, x); 497 } 498 } 499 500 /* Mark the end of an instruction that may have been nullified. 501 This is the pair to nullify_over. Always returns true so that 502 it may be tail-called from a translate function. */ 503 static bool nullify_end(DisasContext *ctx) 504 { 505 TCGLabel *null_lab = ctx->null_lab; 506 DisasJumpType status = ctx->base.is_jmp; 507 508 /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 509 For UPDATED, we cannot update on the nullified path. */ 510 assert(status != DISAS_IAQ_N_UPDATED); 511 512 if (likely(null_lab == NULL)) { 513 /* The current insn wasn't conditional or handled the condition 514 applied to it without a branch, so the (new) setting of 515 NULL_COND can be applied directly to the next insn. */ 516 return true; 517 } 518 ctx->null_lab = NULL; 519 520 if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 521 /* The next instruction will be unconditional, 522 and NULL_COND already reflects that. */ 523 gen_set_label(null_lab); 524 } else { 525 /* The insn that we just executed is itself nullifying the next 526 instruction. Store the condition in the PSW[N] global. 527 We asserted PSW[N] = 0 in nullify_over, so that after the 528 label we have the proper value in place. */ 529 nullify_save(ctx); 530 gen_set_label(null_lab); 531 ctx->null_cond = cond_make_n(); 532 } 533 if (status == DISAS_NORETURN) { 534 ctx->base.is_jmp = DISAS_NEXT; 535 } 536 return true; 537 } 538 539 static uint64_t gva_offset_mask(DisasContext *ctx) 540 { 541 return (ctx->tb_flags & PSW_W 542 ? MAKE_64BIT_MASK(0, 62) 543 : MAKE_64BIT_MASK(0, 32)); 544 } 545 546 static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 547 uint64_t ival, TCGv_i64 vval) 548 { 549 uint64_t mask = gva_offset_mask(ctx); 550 551 if (ival != -1) { 552 tcg_gen_movi_i64(dest, ival & mask); 553 return; 554 } 555 tcg_debug_assert(vval != NULL); 556 557 /* 558 * We know that the IAOQ is already properly masked. 559 * This optimization is primarily for "iaoq_f = iaoq_b". 560 */ 561 if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) { 562 tcg_gen_mov_i64(dest, vval); 563 } else { 564 tcg_gen_andi_i64(dest, vval, mask); 565 } 566 } 567 568 static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp) 569 { 570 return ctx->iaoq_f + disp + 8; 571 } 572 573 static void gen_excp_1(int exception) 574 { 575 gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 576 } 577 578 static void gen_excp(DisasContext *ctx, int exception) 579 { 580 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 581 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 582 nullify_save(ctx); 583 gen_excp_1(exception); 584 ctx->base.is_jmp = DISAS_NORETURN; 585 } 586 587 static bool gen_excp_iir(DisasContext *ctx, int exc) 588 { 589 nullify_over(ctx); 590 tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 591 tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 592 gen_excp(ctx, exc); 593 return nullify_end(ctx); 594 } 595 596 static bool gen_illegal(DisasContext *ctx) 597 { 598 return gen_excp_iir(ctx, EXCP_ILL); 599 } 600 601 #ifdef CONFIG_USER_ONLY 602 #define CHECK_MOST_PRIVILEGED(EXCP) \ 603 return gen_excp_iir(ctx, EXCP) 604 #else 605 #define CHECK_MOST_PRIVILEGED(EXCP) \ 606 do { \ 607 if (ctx->privilege != 0) { \ 608 return gen_excp_iir(ctx, EXCP); \ 609 } \ 610 } while (0) 611 #endif 612 613 static bool use_goto_tb(DisasContext *ctx, uint64_t dest) 614 { 615 return translator_use_goto_tb(&ctx->base, dest); 616 } 617 618 /* If the next insn is to be nullified, and it's on the same page, 619 and we're not attempting to set a breakpoint on it, then we can 620 totally skip the nullified insn. This avoids creating and 621 executing a TB that merely branches to the next TB. */ 622 static bool use_nullify_skip(DisasContext *ctx) 623 { 624 return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 625 && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 626 } 627 628 static void gen_goto_tb(DisasContext *ctx, int which, 629 uint64_t f, uint64_t b) 630 { 631 if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 632 tcg_gen_goto_tb(which); 633 copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL); 634 copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL); 635 tcg_gen_exit_tb(ctx->base.tb, which); 636 } else { 637 copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b); 638 copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var); 639 tcg_gen_lookup_and_goto_ptr(); 640 } 641 } 642 643 static bool cond_need_sv(int c) 644 { 645 return c == 2 || c == 3 || c == 6; 646 } 647 648 static bool cond_need_cb(int c) 649 { 650 return c == 4 || c == 5; 651 } 652 653 /* Need extensions from TCGv_i32 to TCGv_i64. */ 654 static bool cond_need_ext(DisasContext *ctx, bool d) 655 { 656 return !(ctx->is_pa20 && d); 657 } 658 659 /* 660 * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 661 * the Parisc 1.1 Architecture Reference Manual for details. 662 */ 663 664 static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 665 TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv) 666 { 667 DisasCond cond; 668 TCGv_i64 tmp; 669 670 switch (cf >> 1) { 671 case 0: /* Never / TR (0 / 1) */ 672 cond = cond_make_f(); 673 break; 674 case 1: /* = / <> (Z / !Z) */ 675 if (cond_need_ext(ctx, d)) { 676 tmp = tcg_temp_new_i64(); 677 tcg_gen_ext32u_i64(tmp, res); 678 res = tmp; 679 } 680 cond = cond_make_0(TCG_COND_EQ, res); 681 break; 682 case 2: /* < / >= (N ^ V / !(N ^ V) */ 683 tmp = tcg_temp_new_i64(); 684 tcg_gen_xor_i64(tmp, res, sv); 685 if (cond_need_ext(ctx, d)) { 686 tcg_gen_ext32s_i64(tmp, tmp); 687 } 688 cond = cond_make_0_tmp(TCG_COND_LT, tmp); 689 break; 690 case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 691 /* 692 * Simplify: 693 * (N ^ V) | Z 694 * ((res < 0) ^ (sv < 0)) | !res 695 * ((res ^ sv) < 0) | !res 696 * (~(res ^ sv) >= 0) | !res 697 * !(~(res ^ sv) >> 31) | !res 698 * !(~(res ^ sv) >> 31 & res) 699 */ 700 tmp = tcg_temp_new_i64(); 701 tcg_gen_eqv_i64(tmp, res, sv); 702 if (cond_need_ext(ctx, d)) { 703 tcg_gen_sextract_i64(tmp, tmp, 31, 1); 704 tcg_gen_and_i64(tmp, tmp, res); 705 tcg_gen_ext32u_i64(tmp, tmp); 706 } else { 707 tcg_gen_sari_i64(tmp, tmp, 63); 708 tcg_gen_and_i64(tmp, tmp, res); 709 } 710 cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 711 break; 712 case 4: /* NUV / UV (!C / C) */ 713 /* Only bit 0 of cb_msb is ever set. */ 714 cond = cond_make_0(TCG_COND_EQ, cb_msb); 715 break; 716 case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 717 tmp = tcg_temp_new_i64(); 718 tcg_gen_neg_i64(tmp, cb_msb); 719 tcg_gen_and_i64(tmp, tmp, res); 720 if (cond_need_ext(ctx, d)) { 721 tcg_gen_ext32u_i64(tmp, tmp); 722 } 723 cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 724 break; 725 case 6: /* SV / NSV (V / !V) */ 726 if (cond_need_ext(ctx, d)) { 727 tmp = tcg_temp_new_i64(); 728 tcg_gen_ext32s_i64(tmp, sv); 729 sv = tmp; 730 } 731 cond = cond_make_0(TCG_COND_LT, sv); 732 break; 733 case 7: /* OD / EV */ 734 tmp = tcg_temp_new_i64(); 735 tcg_gen_andi_i64(tmp, res, 1); 736 cond = cond_make_0_tmp(TCG_COND_NE, tmp); 737 break; 738 default: 739 g_assert_not_reached(); 740 } 741 if (cf & 1) { 742 cond.c = tcg_invert_cond(cond.c); 743 } 744 745 return cond; 746 } 747 748 /* Similar, but for the special case of subtraction without borrow, we 749 can use the inputs directly. This can allow other computation to be 750 deleted as unused. */ 751 752 static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 753 TCGv_i64 res, TCGv_i64 in1, 754 TCGv_i64 in2, TCGv_i64 sv) 755 { 756 TCGCond tc; 757 bool ext_uns; 758 759 switch (cf >> 1) { 760 case 1: /* = / <> */ 761 tc = TCG_COND_EQ; 762 ext_uns = true; 763 break; 764 case 2: /* < / >= */ 765 tc = TCG_COND_LT; 766 ext_uns = false; 767 break; 768 case 3: /* <= / > */ 769 tc = TCG_COND_LE; 770 ext_uns = false; 771 break; 772 case 4: /* << / >>= */ 773 tc = TCG_COND_LTU; 774 ext_uns = true; 775 break; 776 case 5: /* <<= / >> */ 777 tc = TCG_COND_LEU; 778 ext_uns = true; 779 break; 780 default: 781 return do_cond(ctx, cf, d, res, NULL, sv); 782 } 783 784 if (cf & 1) { 785 tc = tcg_invert_cond(tc); 786 } 787 if (cond_need_ext(ctx, d)) { 788 TCGv_i64 t1 = tcg_temp_new_i64(); 789 TCGv_i64 t2 = tcg_temp_new_i64(); 790 791 if (ext_uns) { 792 tcg_gen_ext32u_i64(t1, in1); 793 tcg_gen_ext32u_i64(t2, in2); 794 } else { 795 tcg_gen_ext32s_i64(t1, in1); 796 tcg_gen_ext32s_i64(t2, in2); 797 } 798 return cond_make_tmp(tc, t1, t2); 799 } 800 return cond_make(tc, in1, in2); 801 } 802 803 /* 804 * Similar, but for logicals, where the carry and overflow bits are not 805 * computed, and use of them is undefined. 806 * 807 * Undefined or not, hardware does not trap. It seems reasonable to 808 * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 809 * how cases c={2,3} are treated. 810 */ 811 812 static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 813 TCGv_i64 res) 814 { 815 TCGCond tc; 816 bool ext_uns; 817 818 switch (cf) { 819 case 0: /* never */ 820 case 9: /* undef, C */ 821 case 11: /* undef, C & !Z */ 822 case 12: /* undef, V */ 823 return cond_make_f(); 824 825 case 1: /* true */ 826 case 8: /* undef, !C */ 827 case 10: /* undef, !C | Z */ 828 case 13: /* undef, !V */ 829 return cond_make_t(); 830 831 case 2: /* == */ 832 tc = TCG_COND_EQ; 833 ext_uns = true; 834 break; 835 case 3: /* <> */ 836 tc = TCG_COND_NE; 837 ext_uns = true; 838 break; 839 case 4: /* < */ 840 tc = TCG_COND_LT; 841 ext_uns = false; 842 break; 843 case 5: /* >= */ 844 tc = TCG_COND_GE; 845 ext_uns = false; 846 break; 847 case 6: /* <= */ 848 tc = TCG_COND_LE; 849 ext_uns = false; 850 break; 851 case 7: /* > */ 852 tc = TCG_COND_GT; 853 ext_uns = false; 854 break; 855 856 case 14: /* OD */ 857 case 15: /* EV */ 858 return do_cond(ctx, cf, d, res, NULL, NULL); 859 860 default: 861 g_assert_not_reached(); 862 } 863 864 if (cond_need_ext(ctx, d)) { 865 TCGv_i64 tmp = tcg_temp_new_i64(); 866 867 if (ext_uns) { 868 tcg_gen_ext32u_i64(tmp, res); 869 } else { 870 tcg_gen_ext32s_i64(tmp, res); 871 } 872 return cond_make_0_tmp(tc, tmp); 873 } 874 return cond_make_0(tc, res); 875 } 876 877 /* Similar, but for shift/extract/deposit conditions. */ 878 879 static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 880 TCGv_i64 res) 881 { 882 unsigned c, f; 883 884 /* Convert the compressed condition codes to standard. 885 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 886 4-7 are the reverse of 0-3. */ 887 c = orig & 3; 888 if (c == 3) { 889 c = 7; 890 } 891 f = (orig & 4) / 4; 892 893 return do_log_cond(ctx, c * 2 + f, d, res); 894 } 895 896 /* Similar, but for unit conditions. */ 897 898 static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res, 899 TCGv_i64 in1, TCGv_i64 in2) 900 { 901 DisasCond cond; 902 TCGv_i64 tmp, cb = NULL; 903 uint64_t d_repl = d ? 0x0000000100000001ull : 1; 904 905 if (cf & 8) { 906 /* Since we want to test lots of carry-out bits all at once, do not 907 * do our normal thing and compute carry-in of bit B+1 since that 908 * leaves us with carry bits spread across two words. 909 */ 910 cb = tcg_temp_new_i64(); 911 tmp = tcg_temp_new_i64(); 912 tcg_gen_or_i64(cb, in1, in2); 913 tcg_gen_and_i64(tmp, in1, in2); 914 tcg_gen_andc_i64(cb, cb, res); 915 tcg_gen_or_i64(cb, cb, tmp); 916 } 917 918 switch (cf >> 1) { 919 case 0: /* never / TR */ 920 case 1: /* undefined */ 921 case 5: /* undefined */ 922 cond = cond_make_f(); 923 break; 924 925 case 2: /* SBZ / NBZ */ 926 /* See hasless(v,1) from 927 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 928 */ 929 tmp = tcg_temp_new_i64(); 930 tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u); 931 tcg_gen_andc_i64(tmp, tmp, res); 932 tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u); 933 cond = cond_make_0(TCG_COND_NE, tmp); 934 break; 935 936 case 3: /* SHZ / NHZ */ 937 tmp = tcg_temp_new_i64(); 938 tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u); 939 tcg_gen_andc_i64(tmp, tmp, res); 940 tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u); 941 cond = cond_make_0(TCG_COND_NE, tmp); 942 break; 943 944 case 4: /* SDC / NDC */ 945 tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u); 946 cond = cond_make_0(TCG_COND_NE, cb); 947 break; 948 949 case 6: /* SBC / NBC */ 950 tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u); 951 cond = cond_make_0(TCG_COND_NE, cb); 952 break; 953 954 case 7: /* SHC / NHC */ 955 tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u); 956 cond = cond_make_0(TCG_COND_NE, cb); 957 break; 958 959 default: 960 g_assert_not_reached(); 961 } 962 if (cf & 1) { 963 cond.c = tcg_invert_cond(cond.c); 964 } 965 966 return cond; 967 } 968 969 static TCGv_i64 get_carry(DisasContext *ctx, bool d, 970 TCGv_i64 cb, TCGv_i64 cb_msb) 971 { 972 if (cond_need_ext(ctx, d)) { 973 TCGv_i64 t = tcg_temp_new_i64(); 974 tcg_gen_extract_i64(t, cb, 32, 1); 975 return t; 976 } 977 return cb_msb; 978 } 979 980 static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 981 { 982 return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 983 } 984 985 /* Compute signed overflow for addition. */ 986 static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 987 TCGv_i64 in1, TCGv_i64 in2) 988 { 989 TCGv_i64 sv = tcg_temp_new_i64(); 990 TCGv_i64 tmp = tcg_temp_new_i64(); 991 992 tcg_gen_xor_i64(sv, res, in1); 993 tcg_gen_xor_i64(tmp, in1, in2); 994 tcg_gen_andc_i64(sv, sv, tmp); 995 996 return sv; 997 } 998 999 /* Compute signed overflow for subtraction. */ 1000 static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 1001 TCGv_i64 in1, TCGv_i64 in2) 1002 { 1003 TCGv_i64 sv = tcg_temp_new_i64(); 1004 TCGv_i64 tmp = tcg_temp_new_i64(); 1005 1006 tcg_gen_xor_i64(sv, res, in1); 1007 tcg_gen_xor_i64(tmp, in1, in2); 1008 tcg_gen_and_i64(sv, sv, tmp); 1009 1010 return sv; 1011 } 1012 1013 static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 1014 TCGv_i64 in2, unsigned shift, bool is_l, 1015 bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1016 { 1017 TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp; 1018 unsigned c = cf >> 1; 1019 DisasCond cond; 1020 1021 dest = tcg_temp_new_i64(); 1022 cb = NULL; 1023 cb_msb = NULL; 1024 cb_cond = NULL; 1025 1026 if (shift) { 1027 tmp = tcg_temp_new_i64(); 1028 tcg_gen_shli_i64(tmp, in1, shift); 1029 in1 = tmp; 1030 } 1031 1032 if (!is_l || cond_need_cb(c)) { 1033 cb_msb = tcg_temp_new_i64(); 1034 cb = tcg_temp_new_i64(); 1035 1036 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1037 if (is_c) { 1038 tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1039 get_psw_carry(ctx, d), ctx->zero); 1040 } 1041 tcg_gen_xor_i64(cb, in1, in2); 1042 tcg_gen_xor_i64(cb, cb, dest); 1043 if (cond_need_cb(c)) { 1044 cb_cond = get_carry(ctx, d, cb, cb_msb); 1045 } 1046 } else { 1047 tcg_gen_add_i64(dest, in1, in2); 1048 if (is_c) { 1049 tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1050 } 1051 } 1052 1053 /* Compute signed overflow if required. */ 1054 sv = NULL; 1055 if (is_tsv || cond_need_sv(c)) { 1056 sv = do_add_sv(ctx, dest, in1, in2); 1057 if (is_tsv) { 1058 /* ??? Need to include overflow from shift. */ 1059 gen_helper_tsv(tcg_env, sv); 1060 } 1061 } 1062 1063 /* Emit any conditional trap before any writeback. */ 1064 cond = do_cond(ctx, cf, d, dest, cb_cond, sv); 1065 if (is_tc) { 1066 tmp = tcg_temp_new_i64(); 1067 tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1068 gen_helper_tcond(tcg_env, tmp); 1069 } 1070 1071 /* Write back the result. */ 1072 if (!is_l) { 1073 save_or_nullify(ctx, cpu_psw_cb, cb); 1074 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1075 } 1076 save_gpr(ctx, rt, dest); 1077 1078 /* Install the new nullification. */ 1079 cond_free(&ctx->null_cond); 1080 ctx->null_cond = cond; 1081 } 1082 1083 static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 1084 bool is_l, bool is_tsv, bool is_tc, bool is_c) 1085 { 1086 TCGv_i64 tcg_r1, tcg_r2; 1087 1088 if (a->cf) { 1089 nullify_over(ctx); 1090 } 1091 tcg_r1 = load_gpr(ctx, a->r1); 1092 tcg_r2 = load_gpr(ctx, a->r2); 1093 do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1094 is_tsv, is_tc, is_c, a->cf, a->d); 1095 return nullify_end(ctx); 1096 } 1097 1098 static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 1099 bool is_tsv, bool is_tc) 1100 { 1101 TCGv_i64 tcg_im, tcg_r2; 1102 1103 if (a->cf) { 1104 nullify_over(ctx); 1105 } 1106 tcg_im = tcg_constant_i64(a->i); 1107 tcg_r2 = load_gpr(ctx, a->r); 1108 /* All ADDI conditions are 32-bit. */ 1109 do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 1110 return nullify_end(ctx); 1111 } 1112 1113 static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 1114 TCGv_i64 in2, bool is_tsv, bool is_b, 1115 bool is_tc, unsigned cf, bool d) 1116 { 1117 TCGv_i64 dest, sv, cb, cb_msb, tmp; 1118 unsigned c = cf >> 1; 1119 DisasCond cond; 1120 1121 dest = tcg_temp_new_i64(); 1122 cb = tcg_temp_new_i64(); 1123 cb_msb = tcg_temp_new_i64(); 1124 1125 if (is_b) { 1126 /* DEST,C = IN1 + ~IN2 + C. */ 1127 tcg_gen_not_i64(cb, in2); 1128 tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1129 get_psw_carry(ctx, d), ctx->zero); 1130 tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 1131 tcg_gen_xor_i64(cb, cb, in1); 1132 tcg_gen_xor_i64(cb, cb, dest); 1133 } else { 1134 /* 1135 * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1136 * operations by seeding the high word with 1 and subtracting. 1137 */ 1138 TCGv_i64 one = tcg_constant_i64(1); 1139 tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 1140 tcg_gen_eqv_i64(cb, in1, in2); 1141 tcg_gen_xor_i64(cb, cb, dest); 1142 } 1143 1144 /* Compute signed overflow if required. */ 1145 sv = NULL; 1146 if (is_tsv || cond_need_sv(c)) { 1147 sv = do_sub_sv(ctx, dest, in1, in2); 1148 if (is_tsv) { 1149 gen_helper_tsv(tcg_env, sv); 1150 } 1151 } 1152 1153 /* Compute the condition. We cannot use the special case for borrow. */ 1154 if (!is_b) { 1155 cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1156 } else { 1157 cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1158 } 1159 1160 /* Emit any conditional trap before any writeback. */ 1161 if (is_tc) { 1162 tmp = tcg_temp_new_i64(); 1163 tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1164 gen_helper_tcond(tcg_env, tmp); 1165 } 1166 1167 /* Write back the result. */ 1168 save_or_nullify(ctx, cpu_psw_cb, cb); 1169 save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1170 save_gpr(ctx, rt, dest); 1171 1172 /* Install the new nullification. */ 1173 cond_free(&ctx->null_cond); 1174 ctx->null_cond = cond; 1175 } 1176 1177 static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 1178 bool is_tsv, bool is_b, bool is_tc) 1179 { 1180 TCGv_i64 tcg_r1, tcg_r2; 1181 1182 if (a->cf) { 1183 nullify_over(ctx); 1184 } 1185 tcg_r1 = load_gpr(ctx, a->r1); 1186 tcg_r2 = load_gpr(ctx, a->r2); 1187 do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 1188 return nullify_end(ctx); 1189 } 1190 1191 static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 1192 { 1193 TCGv_i64 tcg_im, tcg_r2; 1194 1195 if (a->cf) { 1196 nullify_over(ctx); 1197 } 1198 tcg_im = tcg_constant_i64(a->i); 1199 tcg_r2 = load_gpr(ctx, a->r); 1200 /* All SUBI conditions are 32-bit. */ 1201 do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 1202 return nullify_end(ctx); 1203 } 1204 1205 static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 1206 TCGv_i64 in2, unsigned cf, bool d) 1207 { 1208 TCGv_i64 dest, sv; 1209 DisasCond cond; 1210 1211 dest = tcg_temp_new_i64(); 1212 tcg_gen_sub_i64(dest, in1, in2); 1213 1214 /* Compute signed overflow if required. */ 1215 sv = NULL; 1216 if (cond_need_sv(cf >> 1)) { 1217 sv = do_sub_sv(ctx, dest, in1, in2); 1218 } 1219 1220 /* Form the condition for the compare. */ 1221 cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1222 1223 /* Clear. */ 1224 tcg_gen_movi_i64(dest, 0); 1225 save_gpr(ctx, rt, dest); 1226 1227 /* Install the new nullification. */ 1228 cond_free(&ctx->null_cond); 1229 ctx->null_cond = cond; 1230 } 1231 1232 static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 1233 TCGv_i64 in2, unsigned cf, bool d, 1234 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1235 { 1236 TCGv_i64 dest = dest_gpr(ctx, rt); 1237 1238 /* Perform the operation, and writeback. */ 1239 fn(dest, in1, in2); 1240 save_gpr(ctx, rt, dest); 1241 1242 /* Install the new nullification. */ 1243 cond_free(&ctx->null_cond); 1244 if (cf) { 1245 ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1246 } 1247 } 1248 1249 static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 1250 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1251 { 1252 TCGv_i64 tcg_r1, tcg_r2; 1253 1254 if (a->cf) { 1255 nullify_over(ctx); 1256 } 1257 tcg_r1 = load_gpr(ctx, a->r1); 1258 tcg_r2 = load_gpr(ctx, a->r2); 1259 do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 1260 return nullify_end(ctx); 1261 } 1262 1263 static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 1264 TCGv_i64 in2, unsigned cf, bool d, bool is_tc, 1265 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1266 { 1267 TCGv_i64 dest; 1268 DisasCond cond; 1269 1270 if (cf == 0) { 1271 dest = dest_gpr(ctx, rt); 1272 fn(dest, in1, in2); 1273 save_gpr(ctx, rt, dest); 1274 cond_free(&ctx->null_cond); 1275 } else { 1276 dest = tcg_temp_new_i64(); 1277 fn(dest, in1, in2); 1278 1279 cond = do_unit_cond(cf, d, dest, in1, in2); 1280 1281 if (is_tc) { 1282 TCGv_i64 tmp = tcg_temp_new_i64(); 1283 tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1284 gen_helper_tcond(tcg_env, tmp); 1285 } 1286 save_gpr(ctx, rt, dest); 1287 1288 cond_free(&ctx->null_cond); 1289 ctx->null_cond = cond; 1290 } 1291 } 1292 1293 #ifndef CONFIG_USER_ONLY 1294 /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 1295 from the top 2 bits of the base register. There are a few system 1296 instructions that have a 3-bit space specifier, for which SR0 is 1297 not special. To handle this, pass ~SP. */ 1298 static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 1299 { 1300 TCGv_ptr ptr; 1301 TCGv_i64 tmp; 1302 TCGv_i64 spc; 1303 1304 if (sp != 0) { 1305 if (sp < 0) { 1306 sp = ~sp; 1307 } 1308 spc = tcg_temp_new_i64(); 1309 load_spr(ctx, spc, sp); 1310 return spc; 1311 } 1312 if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1313 return cpu_srH; 1314 } 1315 1316 ptr = tcg_temp_new_ptr(); 1317 tmp = tcg_temp_new_i64(); 1318 spc = tcg_temp_new_i64(); 1319 1320 /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 1321 tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 1322 tcg_gen_andi_i64(tmp, tmp, 030); 1323 tcg_gen_trunc_i64_ptr(ptr, tmp); 1324 1325 tcg_gen_add_ptr(ptr, ptr, tcg_env); 1326 tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 1327 1328 return spc; 1329 } 1330 #endif 1331 1332 static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1333 unsigned rb, unsigned rx, int scale, int64_t disp, 1334 unsigned sp, int modify, bool is_phys) 1335 { 1336 TCGv_i64 base = load_gpr(ctx, rb); 1337 TCGv_i64 ofs; 1338 TCGv_i64 addr; 1339 1340 set_insn_breg(ctx, rb); 1341 1342 /* Note that RX is mutually exclusive with DISP. */ 1343 if (rx) { 1344 ofs = tcg_temp_new_i64(); 1345 tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 1346 tcg_gen_add_i64(ofs, ofs, base); 1347 } else if (disp || modify) { 1348 ofs = tcg_temp_new_i64(); 1349 tcg_gen_addi_i64(ofs, base, disp); 1350 } else { 1351 ofs = base; 1352 } 1353 1354 *pofs = ofs; 1355 *pgva = addr = tcg_temp_new_i64(); 1356 tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx)); 1357 #ifndef CONFIG_USER_ONLY 1358 if (!is_phys) { 1359 tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 1360 } 1361 #endif 1362 } 1363 1364 /* Emit a memory load. The modify parameter should be 1365 * < 0 for pre-modify, 1366 * > 0 for post-modify, 1367 * = 0 for no base register update. 1368 */ 1369 static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1370 unsigned rx, int scale, int64_t disp, 1371 unsigned sp, int modify, MemOp mop) 1372 { 1373 TCGv_i64 ofs; 1374 TCGv_i64 addr; 1375 1376 /* Caller uses nullify_over/nullify_end. */ 1377 assert(ctx->null_cond.c == TCG_COND_NEVER); 1378 1379 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 1380 MMU_DISABLED(ctx)); 1381 tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 1382 if (modify) { 1383 save_gpr(ctx, rb, ofs); 1384 } 1385 } 1386 1387 static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1388 unsigned rx, int scale, int64_t disp, 1389 unsigned sp, int modify, MemOp mop) 1390 { 1391 TCGv_i64 ofs; 1392 TCGv_i64 addr; 1393 1394 /* Caller uses nullify_over/nullify_end. */ 1395 assert(ctx->null_cond.c == TCG_COND_NEVER); 1396 1397 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 1398 MMU_DISABLED(ctx)); 1399 tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 1400 if (modify) { 1401 save_gpr(ctx, rb, ofs); 1402 } 1403 } 1404 1405 static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1406 unsigned rx, int scale, int64_t disp, 1407 unsigned sp, int modify, MemOp mop) 1408 { 1409 TCGv_i64 ofs; 1410 TCGv_i64 addr; 1411 1412 /* Caller uses nullify_over/nullify_end. */ 1413 assert(ctx->null_cond.c == TCG_COND_NEVER); 1414 1415 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 1416 MMU_DISABLED(ctx)); 1417 tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 1418 if (modify) { 1419 save_gpr(ctx, rb, ofs); 1420 } 1421 } 1422 1423 static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1424 unsigned rx, int scale, int64_t disp, 1425 unsigned sp, int modify, MemOp mop) 1426 { 1427 TCGv_i64 ofs; 1428 TCGv_i64 addr; 1429 1430 /* Caller uses nullify_over/nullify_end. */ 1431 assert(ctx->null_cond.c == TCG_COND_NEVER); 1432 1433 form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 1434 MMU_DISABLED(ctx)); 1435 tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 1436 if (modify) { 1437 save_gpr(ctx, rb, ofs); 1438 } 1439 } 1440 1441 static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1442 unsigned rx, int scale, int64_t disp, 1443 unsigned sp, int modify, MemOp mop) 1444 { 1445 TCGv_i64 dest; 1446 1447 nullify_over(ctx); 1448 1449 if (modify == 0) { 1450 /* No base register update. */ 1451 dest = dest_gpr(ctx, rt); 1452 } else { 1453 /* Make sure if RT == RB, we see the result of the load. */ 1454 dest = tcg_temp_new_i64(); 1455 } 1456 do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 1457 save_gpr(ctx, rt, dest); 1458 1459 return nullify_end(ctx); 1460 } 1461 1462 static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1463 unsigned rx, int scale, int64_t disp, 1464 unsigned sp, int modify) 1465 { 1466 TCGv_i32 tmp; 1467 1468 nullify_over(ctx); 1469 1470 tmp = tcg_temp_new_i32(); 1471 do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 1472 save_frw_i32(rt, tmp); 1473 1474 if (rt == 0) { 1475 gen_helper_loaded_fr0(tcg_env); 1476 } 1477 1478 return nullify_end(ctx); 1479 } 1480 1481 static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1482 { 1483 return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1484 a->disp, a->sp, a->m); 1485 } 1486 1487 static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1488 unsigned rx, int scale, int64_t disp, 1489 unsigned sp, int modify) 1490 { 1491 TCGv_i64 tmp; 1492 1493 nullify_over(ctx); 1494 1495 tmp = tcg_temp_new_i64(); 1496 do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 1497 save_frd(rt, tmp); 1498 1499 if (rt == 0) { 1500 gen_helper_loaded_fr0(tcg_env); 1501 } 1502 1503 return nullify_end(ctx); 1504 } 1505 1506 static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1507 { 1508 return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1509 a->disp, a->sp, a->m); 1510 } 1511 1512 static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1513 int64_t disp, unsigned sp, 1514 int modify, MemOp mop) 1515 { 1516 nullify_over(ctx); 1517 do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 1518 return nullify_end(ctx); 1519 } 1520 1521 static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1522 unsigned rx, int scale, int64_t disp, 1523 unsigned sp, int modify) 1524 { 1525 TCGv_i32 tmp; 1526 1527 nullify_over(ctx); 1528 1529 tmp = load_frw_i32(rt); 1530 do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 1531 1532 return nullify_end(ctx); 1533 } 1534 1535 static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1536 { 1537 return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1538 a->disp, a->sp, a->m); 1539 } 1540 1541 static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1542 unsigned rx, int scale, int64_t disp, 1543 unsigned sp, int modify) 1544 { 1545 TCGv_i64 tmp; 1546 1547 nullify_over(ctx); 1548 1549 tmp = load_frd(rt); 1550 do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 1551 1552 return nullify_end(ctx); 1553 } 1554 1555 static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1556 { 1557 return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1558 a->disp, a->sp, a->m); 1559 } 1560 1561 static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1562 void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1563 { 1564 TCGv_i32 tmp; 1565 1566 nullify_over(ctx); 1567 tmp = load_frw0_i32(ra); 1568 1569 func(tmp, tcg_env, tmp); 1570 1571 save_frw_i32(rt, tmp); 1572 return nullify_end(ctx); 1573 } 1574 1575 static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1576 void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1577 { 1578 TCGv_i32 dst; 1579 TCGv_i64 src; 1580 1581 nullify_over(ctx); 1582 src = load_frd(ra); 1583 dst = tcg_temp_new_i32(); 1584 1585 func(dst, tcg_env, src); 1586 1587 save_frw_i32(rt, dst); 1588 return nullify_end(ctx); 1589 } 1590 1591 static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1592 void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1593 { 1594 TCGv_i64 tmp; 1595 1596 nullify_over(ctx); 1597 tmp = load_frd0(ra); 1598 1599 func(tmp, tcg_env, tmp); 1600 1601 save_frd(rt, tmp); 1602 return nullify_end(ctx); 1603 } 1604 1605 static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1606 void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1607 { 1608 TCGv_i32 src; 1609 TCGv_i64 dst; 1610 1611 nullify_over(ctx); 1612 src = load_frw0_i32(ra); 1613 dst = tcg_temp_new_i64(); 1614 1615 func(dst, tcg_env, src); 1616 1617 save_frd(rt, dst); 1618 return nullify_end(ctx); 1619 } 1620 1621 static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1622 unsigned ra, unsigned rb, 1623 void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1624 { 1625 TCGv_i32 a, b; 1626 1627 nullify_over(ctx); 1628 a = load_frw0_i32(ra); 1629 b = load_frw0_i32(rb); 1630 1631 func(a, tcg_env, a, b); 1632 1633 save_frw_i32(rt, a); 1634 return nullify_end(ctx); 1635 } 1636 1637 static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1638 unsigned ra, unsigned rb, 1639 void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1640 { 1641 TCGv_i64 a, b; 1642 1643 nullify_over(ctx); 1644 a = load_frd0(ra); 1645 b = load_frd0(rb); 1646 1647 func(a, tcg_env, a, b); 1648 1649 save_frd(rt, a); 1650 return nullify_end(ctx); 1651 } 1652 1653 /* Emit an unconditional branch to a direct target, which may or may not 1654 have already had nullification handled. */ 1655 static bool do_dbranch(DisasContext *ctx, uint64_t dest, 1656 unsigned link, bool is_n) 1657 { 1658 if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 1659 if (link != 0) { 1660 copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 1661 } 1662 ctx->iaoq_n = dest; 1663 if (is_n) { 1664 ctx->null_cond.c = TCG_COND_ALWAYS; 1665 } 1666 } else { 1667 nullify_over(ctx); 1668 1669 if (link != 0) { 1670 copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 1671 } 1672 1673 if (is_n && use_nullify_skip(ctx)) { 1674 nullify_set(ctx, 0); 1675 gen_goto_tb(ctx, 0, dest, dest + 4); 1676 } else { 1677 nullify_set(ctx, is_n); 1678 gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 1679 } 1680 1681 nullify_end(ctx); 1682 1683 nullify_set(ctx, 0); 1684 gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 1685 ctx->base.is_jmp = DISAS_NORETURN; 1686 } 1687 return true; 1688 } 1689 1690 /* Emit a conditional branch to a direct target. If the branch itself 1691 is nullified, we should have already used nullify_over. */ 1692 static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 1693 DisasCond *cond) 1694 { 1695 uint64_t dest = iaoq_dest(ctx, disp); 1696 TCGLabel *taken = NULL; 1697 TCGCond c = cond->c; 1698 bool n; 1699 1700 assert(ctx->null_cond.c == TCG_COND_NEVER); 1701 1702 /* Handle TRUE and NEVER as direct branches. */ 1703 if (c == TCG_COND_ALWAYS) { 1704 return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 1705 } 1706 if (c == TCG_COND_NEVER) { 1707 return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 1708 } 1709 1710 taken = gen_new_label(); 1711 tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 1712 cond_free(cond); 1713 1714 /* Not taken: Condition not satisfied; nullify on backward branches. */ 1715 n = is_n && disp < 0; 1716 if (n && use_nullify_skip(ctx)) { 1717 nullify_set(ctx, 0); 1718 gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 1719 } else { 1720 if (!n && ctx->null_lab) { 1721 gen_set_label(ctx->null_lab); 1722 ctx->null_lab = NULL; 1723 } 1724 nullify_set(ctx, n); 1725 if (ctx->iaoq_n == -1) { 1726 /* The temporary iaoq_n_var died at the branch above. 1727 Regenerate it here instead of saving it. */ 1728 tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 1729 } 1730 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 1731 } 1732 1733 gen_set_label(taken); 1734 1735 /* Taken: Condition satisfied; nullify on forward branches. */ 1736 n = is_n && disp >= 0; 1737 if (n && use_nullify_skip(ctx)) { 1738 nullify_set(ctx, 0); 1739 gen_goto_tb(ctx, 1, dest, dest + 4); 1740 } else { 1741 nullify_set(ctx, n); 1742 gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 1743 } 1744 1745 /* Not taken: the branch itself was nullified. */ 1746 if (ctx->null_lab) { 1747 gen_set_label(ctx->null_lab); 1748 ctx->null_lab = NULL; 1749 ctx->base.is_jmp = DISAS_IAQ_N_STALE; 1750 } else { 1751 ctx->base.is_jmp = DISAS_NORETURN; 1752 } 1753 return true; 1754 } 1755 1756 /* Emit an unconditional branch to an indirect target. This handles 1757 nullification of the branch itself. */ 1758 static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest, 1759 unsigned link, bool is_n) 1760 { 1761 TCGv_i64 a0, a1, next, tmp; 1762 TCGCond c; 1763 1764 assert(ctx->null_lab == NULL); 1765 1766 if (ctx->null_cond.c == TCG_COND_NEVER) { 1767 if (link != 0) { 1768 copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 1769 } 1770 next = tcg_temp_new_i64(); 1771 tcg_gen_mov_i64(next, dest); 1772 if (is_n) { 1773 if (use_nullify_skip(ctx)) { 1774 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next); 1775 tcg_gen_addi_i64(next, next, 4); 1776 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 1777 nullify_set(ctx, 0); 1778 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 1779 return true; 1780 } 1781 ctx->null_cond.c = TCG_COND_ALWAYS; 1782 } 1783 ctx->iaoq_n = -1; 1784 ctx->iaoq_n_var = next; 1785 } else if (is_n && use_nullify_skip(ctx)) { 1786 /* The (conditional) branch, B, nullifies the next insn, N, 1787 and we're allowed to skip execution N (no single-step or 1788 tracepoint in effect). Since the goto_ptr that we must use 1789 for the indirect branch consumes no special resources, we 1790 can (conditionally) skip B and continue execution. */ 1791 /* The use_nullify_skip test implies we have a known control path. */ 1792 tcg_debug_assert(ctx->iaoq_b != -1); 1793 tcg_debug_assert(ctx->iaoq_n != -1); 1794 1795 /* We do have to handle the non-local temporary, DEST, before 1796 branching. Since IOAQ_F is not really live at this point, we 1797 can simply store DEST optimistically. Similarly with IAOQ_B. */ 1798 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest); 1799 next = tcg_temp_new_i64(); 1800 tcg_gen_addi_i64(next, dest, 4); 1801 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 1802 1803 nullify_over(ctx); 1804 if (link != 0) { 1805 copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 1806 } 1807 tcg_gen_lookup_and_goto_ptr(); 1808 return nullify_end(ctx); 1809 } else { 1810 c = ctx->null_cond.c; 1811 a0 = ctx->null_cond.a0; 1812 a1 = ctx->null_cond.a1; 1813 1814 tmp = tcg_temp_new_i64(); 1815 next = tcg_temp_new_i64(); 1816 1817 copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var); 1818 tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest); 1819 ctx->iaoq_n = -1; 1820 ctx->iaoq_n_var = next; 1821 1822 if (link != 0) { 1823 tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 1824 } 1825 1826 if (is_n) { 1827 /* The branch nullifies the next insn, which means the state of N 1828 after the branch is the inverse of the state of N that applied 1829 to the branch. */ 1830 tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1); 1831 cond_free(&ctx->null_cond); 1832 ctx->null_cond = cond_make_n(); 1833 ctx->psw_n_nonzero = true; 1834 } else { 1835 cond_free(&ctx->null_cond); 1836 } 1837 } 1838 return true; 1839 } 1840 1841 /* Implement 1842 * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1843 * IAOQ_Next{30..31} ← GR[b]{30..31}; 1844 * else 1845 * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1846 * which keeps the privilege level from being increased. 1847 */ 1848 static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1849 { 1850 TCGv_i64 dest; 1851 switch (ctx->privilege) { 1852 case 0: 1853 /* Privilege 0 is maximum and is allowed to decrease. */ 1854 return offset; 1855 case 3: 1856 /* Privilege 3 is minimum and is never allowed to increase. */ 1857 dest = tcg_temp_new_i64(); 1858 tcg_gen_ori_i64(dest, offset, 3); 1859 break; 1860 default: 1861 dest = tcg_temp_new_i64(); 1862 tcg_gen_andi_i64(dest, offset, -4); 1863 tcg_gen_ori_i64(dest, dest, ctx->privilege); 1864 tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset); 1865 break; 1866 } 1867 return dest; 1868 } 1869 1870 #ifdef CONFIG_USER_ONLY 1871 /* On Linux, page zero is normally marked execute only + gateway. 1872 Therefore normal read or write is supposed to fail, but specific 1873 offsets have kernel code mapped to raise permissions to implement 1874 system calls. Handling this via an explicit check here, rather 1875 in than the "be disp(sr2,r0)" instruction that probably sent us 1876 here, is the easiest way to handle the branch delay slot on the 1877 aforementioned BE. */ 1878 static void do_page_zero(DisasContext *ctx) 1879 { 1880 TCGv_i64 tmp; 1881 1882 /* If by some means we get here with PSW[N]=1, that implies that 1883 the B,GATE instruction would be skipped, and we'd fault on the 1884 next insn within the privileged page. */ 1885 switch (ctx->null_cond.c) { 1886 case TCG_COND_NEVER: 1887 break; 1888 case TCG_COND_ALWAYS: 1889 tcg_gen_movi_i64(cpu_psw_n, 0); 1890 goto do_sigill; 1891 default: 1892 /* Since this is always the first (and only) insn within the 1893 TB, we should know the state of PSW[N] from TB->FLAGS. */ 1894 g_assert_not_reached(); 1895 } 1896 1897 /* Check that we didn't arrive here via some means that allowed 1898 non-sequential instruction execution. Normally the PSW[B] bit 1899 detects this by disallowing the B,GATE instruction to execute 1900 under such conditions. */ 1901 if (ctx->iaoq_b != ctx->iaoq_f + 4) { 1902 goto do_sigill; 1903 } 1904 1905 switch (ctx->iaoq_f & -4) { 1906 case 0x00: /* Null pointer call */ 1907 gen_excp_1(EXCP_IMP); 1908 ctx->base.is_jmp = DISAS_NORETURN; 1909 break; 1910 1911 case 0xb0: /* LWS */ 1912 gen_excp_1(EXCP_SYSCALL_LWS); 1913 ctx->base.is_jmp = DISAS_NORETURN; 1914 break; 1915 1916 case 0xe0: /* SET_THREAD_POINTER */ 1917 tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27])); 1918 tmp = tcg_temp_new_i64(); 1919 tcg_gen_ori_i64(tmp, cpu_gr[31], 3); 1920 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 1921 tcg_gen_addi_i64(tmp, tmp, 4); 1922 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 1923 ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 1924 break; 1925 1926 case 0x100: /* SYSCALL */ 1927 gen_excp_1(EXCP_SYSCALL); 1928 ctx->base.is_jmp = DISAS_NORETURN; 1929 break; 1930 1931 default: 1932 do_sigill: 1933 gen_excp_1(EXCP_ILL); 1934 ctx->base.is_jmp = DISAS_NORETURN; 1935 break; 1936 } 1937 } 1938 #endif 1939 1940 static bool trans_nop(DisasContext *ctx, arg_nop *a) 1941 { 1942 cond_free(&ctx->null_cond); 1943 return true; 1944 } 1945 1946 static bool trans_break(DisasContext *ctx, arg_break *a) 1947 { 1948 return gen_excp_iir(ctx, EXCP_BREAK); 1949 } 1950 1951 static bool trans_sync(DisasContext *ctx, arg_sync *a) 1952 { 1953 /* No point in nullifying the memory barrier. */ 1954 tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 1955 1956 cond_free(&ctx->null_cond); 1957 return true; 1958 } 1959 1960 static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 1961 { 1962 unsigned rt = a->t; 1963 TCGv_i64 tmp = dest_gpr(ctx, rt); 1964 tcg_gen_movi_i64(tmp, ctx->iaoq_f); 1965 save_gpr(ctx, rt, tmp); 1966 1967 cond_free(&ctx->null_cond); 1968 return true; 1969 } 1970 1971 static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 1972 { 1973 unsigned rt = a->t; 1974 unsigned rs = a->sp; 1975 TCGv_i64 t0 = tcg_temp_new_i64(); 1976 1977 load_spr(ctx, t0, rs); 1978 tcg_gen_shri_i64(t0, t0, 32); 1979 1980 save_gpr(ctx, rt, t0); 1981 1982 cond_free(&ctx->null_cond); 1983 return true; 1984 } 1985 1986 static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 1987 { 1988 unsigned rt = a->t; 1989 unsigned ctl = a->r; 1990 TCGv_i64 tmp; 1991 1992 switch (ctl) { 1993 case CR_SAR: 1994 if (a->e == 0) { 1995 /* MFSAR without ,W masks low 5 bits. */ 1996 tmp = dest_gpr(ctx, rt); 1997 tcg_gen_andi_i64(tmp, cpu_sar, 31); 1998 save_gpr(ctx, rt, tmp); 1999 goto done; 2000 } 2001 save_gpr(ctx, rt, cpu_sar); 2002 goto done; 2003 case CR_IT: /* Interval Timer */ 2004 /* FIXME: Respect PSW_S bit. */ 2005 nullify_over(ctx); 2006 tmp = dest_gpr(ctx, rt); 2007 if (translator_io_start(&ctx->base)) { 2008 gen_helper_read_interval_timer(tmp); 2009 ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2010 } else { 2011 gen_helper_read_interval_timer(tmp); 2012 } 2013 save_gpr(ctx, rt, tmp); 2014 return nullify_end(ctx); 2015 case 26: 2016 case 27: 2017 break; 2018 default: 2019 /* All other control registers are privileged. */ 2020 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 2021 break; 2022 } 2023 2024 tmp = tcg_temp_new_i64(); 2025 tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2026 save_gpr(ctx, rt, tmp); 2027 2028 done: 2029 cond_free(&ctx->null_cond); 2030 return true; 2031 } 2032 2033 static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 2034 { 2035 unsigned rr = a->r; 2036 unsigned rs = a->sp; 2037 TCGv_i64 tmp; 2038 2039 if (rs >= 5) { 2040 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 2041 } 2042 nullify_over(ctx); 2043 2044 tmp = tcg_temp_new_i64(); 2045 tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 2046 2047 if (rs >= 4) { 2048 tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2049 ctx->tb_flags &= ~TB_FLAG_SR_SAME; 2050 } else { 2051 tcg_gen_mov_i64(cpu_sr[rs], tmp); 2052 } 2053 2054 return nullify_end(ctx); 2055 } 2056 2057 static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 2058 { 2059 unsigned ctl = a->t; 2060 TCGv_i64 reg; 2061 TCGv_i64 tmp; 2062 2063 if (ctl == CR_SAR) { 2064 reg = load_gpr(ctx, a->r); 2065 tmp = tcg_temp_new_i64(); 2066 tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 2067 save_or_nullify(ctx, cpu_sar, tmp); 2068 2069 cond_free(&ctx->null_cond); 2070 return true; 2071 } 2072 2073 /* All other control registers are privileged or read-only. */ 2074 CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 2075 2076 #ifndef CONFIG_USER_ONLY 2077 nullify_over(ctx); 2078 2079 if (ctx->is_pa20) { 2080 reg = load_gpr(ctx, a->r); 2081 } else { 2082 reg = tcg_temp_new_i64(); 2083 tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 2084 } 2085 2086 switch (ctl) { 2087 case CR_IT: 2088 gen_helper_write_interval_timer(tcg_env, reg); 2089 break; 2090 case CR_EIRR: 2091 gen_helper_write_eirr(tcg_env, reg); 2092 break; 2093 case CR_EIEM: 2094 gen_helper_write_eiem(tcg_env, reg); 2095 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 2096 break; 2097 2098 case CR_IIASQ: 2099 case CR_IIAOQ: 2100 /* FIXME: Respect PSW_Q bit */ 2101 /* The write advances the queue and stores to the back element. */ 2102 tmp = tcg_temp_new_i64(); 2103 tcg_gen_ld_i64(tmp, tcg_env, 2104 offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 2105 tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2106 tcg_gen_st_i64(reg, tcg_env, 2107 offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 2108 break; 2109 2110 case CR_PID1: 2111 case CR_PID2: 2112 case CR_PID3: 2113 case CR_PID4: 2114 tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2115 #ifndef CONFIG_USER_ONLY 2116 gen_helper_change_prot_id(tcg_env); 2117 #endif 2118 break; 2119 2120 default: 2121 tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2122 break; 2123 } 2124 return nullify_end(ctx); 2125 #endif 2126 } 2127 2128 static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 2129 { 2130 TCGv_i64 tmp = tcg_temp_new_i64(); 2131 2132 tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 2133 tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 2134 save_or_nullify(ctx, cpu_sar, tmp); 2135 2136 cond_free(&ctx->null_cond); 2137 return true; 2138 } 2139 2140 static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 2141 { 2142 TCGv_i64 dest = dest_gpr(ctx, a->t); 2143 2144 #ifdef CONFIG_USER_ONLY 2145 /* We don't implement space registers in user mode. */ 2146 tcg_gen_movi_i64(dest, 0); 2147 #else 2148 tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2149 tcg_gen_shri_i64(dest, dest, 32); 2150 #endif 2151 save_gpr(ctx, a->t, dest); 2152 2153 cond_free(&ctx->null_cond); 2154 return true; 2155 } 2156 2157 static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2158 { 2159 #ifdef CONFIG_USER_ONLY 2160 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2161 #else 2162 TCGv_i64 tmp; 2163 2164 /* HP-UX 11i and HP ODE use rsm for read-access to PSW */ 2165 if (a->i) { 2166 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2167 } 2168 2169 nullify_over(ctx); 2170 2171 tmp = tcg_temp_new_i64(); 2172 tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 2173 tcg_gen_andi_i64(tmp, tmp, ~a->i); 2174 gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2175 save_gpr(ctx, a->t, tmp); 2176 2177 /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 2178 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 2179 return nullify_end(ctx); 2180 #endif 2181 } 2182 2183 static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2184 { 2185 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2186 #ifndef CONFIG_USER_ONLY 2187 TCGv_i64 tmp; 2188 2189 nullify_over(ctx); 2190 2191 tmp = tcg_temp_new_i64(); 2192 tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 2193 tcg_gen_ori_i64(tmp, tmp, a->i); 2194 gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2195 save_gpr(ctx, a->t, tmp); 2196 2197 /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 2198 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 2199 return nullify_end(ctx); 2200 #endif 2201 } 2202 2203 static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2204 { 2205 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2206 #ifndef CONFIG_USER_ONLY 2207 TCGv_i64 tmp, reg; 2208 nullify_over(ctx); 2209 2210 reg = load_gpr(ctx, a->r); 2211 tmp = tcg_temp_new_i64(); 2212 gen_helper_swap_system_mask(tmp, tcg_env, reg); 2213 2214 /* Exit the TB to recognize new interrupts. */ 2215 ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 2216 return nullify_end(ctx); 2217 #endif 2218 } 2219 2220 static bool do_rfi(DisasContext *ctx, bool rfi_r) 2221 { 2222 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2223 #ifndef CONFIG_USER_ONLY 2224 nullify_over(ctx); 2225 2226 if (rfi_r) { 2227 gen_helper_rfi_r(tcg_env); 2228 } else { 2229 gen_helper_rfi(tcg_env); 2230 } 2231 /* Exit the TB to recognize new interrupts. */ 2232 tcg_gen_exit_tb(NULL, 0); 2233 ctx->base.is_jmp = DISAS_NORETURN; 2234 2235 return nullify_end(ctx); 2236 #endif 2237 } 2238 2239 static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2240 { 2241 return do_rfi(ctx, false); 2242 } 2243 2244 static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2245 { 2246 return do_rfi(ctx, true); 2247 } 2248 2249 static bool trans_halt(DisasContext *ctx, arg_halt *a) 2250 { 2251 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2252 #ifndef CONFIG_USER_ONLY 2253 nullify_over(ctx); 2254 gen_helper_halt(tcg_env); 2255 ctx->base.is_jmp = DISAS_NORETURN; 2256 return nullify_end(ctx); 2257 #endif 2258 } 2259 2260 static bool trans_reset(DisasContext *ctx, arg_reset *a) 2261 { 2262 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2263 #ifndef CONFIG_USER_ONLY 2264 nullify_over(ctx); 2265 gen_helper_reset(tcg_env); 2266 ctx->base.is_jmp = DISAS_NORETURN; 2267 return nullify_end(ctx); 2268 #endif 2269 } 2270 2271 static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 2272 { 2273 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2274 #ifndef CONFIG_USER_ONLY 2275 nullify_over(ctx); 2276 gen_helper_getshadowregs(tcg_env); 2277 return nullify_end(ctx); 2278 #endif 2279 } 2280 2281 static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 2282 { 2283 if (a->m) { 2284 TCGv_i64 dest = dest_gpr(ctx, a->b); 2285 TCGv_i64 src1 = load_gpr(ctx, a->b); 2286 TCGv_i64 src2 = load_gpr(ctx, a->x); 2287 2288 /* The only thing we need to do is the base register modification. */ 2289 tcg_gen_add_i64(dest, src1, src2); 2290 save_gpr(ctx, a->b, dest); 2291 } 2292 cond_free(&ctx->null_cond); 2293 return true; 2294 } 2295 2296 static bool trans_probe(DisasContext *ctx, arg_probe *a) 2297 { 2298 TCGv_i64 dest, ofs; 2299 TCGv_i32 level, want; 2300 TCGv_i64 addr; 2301 2302 nullify_over(ctx); 2303 2304 dest = dest_gpr(ctx, a->t); 2305 form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2306 2307 if (a->imm) { 2308 level = tcg_constant_i32(a->ri & 3); 2309 } else { 2310 level = tcg_temp_new_i32(); 2311 tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2312 tcg_gen_andi_i32(level, level, 3); 2313 } 2314 want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2315 2316 gen_helper_probe(dest, tcg_env, addr, level, want); 2317 2318 save_gpr(ctx, a->t, dest); 2319 return nullify_end(ctx); 2320 } 2321 2322 static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 2323 { 2324 if (ctx->is_pa20) { 2325 return false; 2326 } 2327 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2328 #ifndef CONFIG_USER_ONLY 2329 TCGv_i64 addr; 2330 TCGv_i64 ofs, reg; 2331 2332 nullify_over(ctx); 2333 2334 form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2335 reg = load_gpr(ctx, a->r); 2336 if (a->addr) { 2337 gen_helper_itlba_pa11(tcg_env, addr, reg); 2338 } else { 2339 gen_helper_itlbp_pa11(tcg_env, addr, reg); 2340 } 2341 2342 /* Exit TB for TLB change if mmu is enabled. */ 2343 if (ctx->tb_flags & PSW_C) { 2344 ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2345 } 2346 return nullify_end(ctx); 2347 #endif 2348 } 2349 2350 static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 2351 { 2352 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2353 #ifndef CONFIG_USER_ONLY 2354 TCGv_i64 addr; 2355 TCGv_i64 ofs; 2356 2357 nullify_over(ctx); 2358 2359 form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2360 2361 /* 2362 * Page align now, rather than later, so that we can add in the 2363 * page_size field from pa2.0 from the low 4 bits of GR[b]. 2364 */ 2365 tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2366 if (ctx->is_pa20) { 2367 tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 2368 } 2369 2370 if (local) { 2371 gen_helper_ptlb_l(tcg_env, addr); 2372 } else { 2373 gen_helper_ptlb(tcg_env, addr); 2374 } 2375 2376 if (a->m) { 2377 save_gpr(ctx, a->b, ofs); 2378 } 2379 2380 /* Exit TB for TLB change if mmu is enabled. */ 2381 if (ctx->tb_flags & PSW_C) { 2382 ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2383 } 2384 return nullify_end(ctx); 2385 #endif 2386 } 2387 2388 static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2389 { 2390 return do_pxtlb(ctx, a, false); 2391 } 2392 2393 static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2394 { 2395 return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2396 } 2397 2398 static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2399 { 2400 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2401 #ifndef CONFIG_USER_ONLY 2402 nullify_over(ctx); 2403 2404 trans_nop_addrx(ctx, a); 2405 gen_helper_ptlbe(tcg_env); 2406 2407 /* Exit TB for TLB change if mmu is enabled. */ 2408 if (ctx->tb_flags & PSW_C) { 2409 ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2410 } 2411 return nullify_end(ctx); 2412 #endif 2413 } 2414 2415 /* 2416 * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 2417 * See 2418 * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 2419 * page 13-9 (195/206) 2420 */ 2421 static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 2422 { 2423 if (ctx->is_pa20) { 2424 return false; 2425 } 2426 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2427 #ifndef CONFIG_USER_ONLY 2428 TCGv_i64 addr, atl, stl; 2429 TCGv_i64 reg; 2430 2431 nullify_over(ctx); 2432 2433 /* 2434 * FIXME: 2435 * if (not (pcxl or pcxl2)) 2436 * return gen_illegal(ctx); 2437 */ 2438 2439 atl = tcg_temp_new_i64(); 2440 stl = tcg_temp_new_i64(); 2441 addr = tcg_temp_new_i64(); 2442 2443 tcg_gen_ld32u_i64(stl, tcg_env, 2444 a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 2445 : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2446 tcg_gen_ld32u_i64(atl, tcg_env, 2447 a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 2448 : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 2449 tcg_gen_shli_i64(stl, stl, 32); 2450 tcg_gen_or_i64(addr, atl, stl); 2451 2452 reg = load_gpr(ctx, a->r); 2453 if (a->addr) { 2454 gen_helper_itlba_pa11(tcg_env, addr, reg); 2455 } else { 2456 gen_helper_itlbp_pa11(tcg_env, addr, reg); 2457 } 2458 2459 /* Exit TB for TLB change if mmu is enabled. */ 2460 if (ctx->tb_flags & PSW_C) { 2461 ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2462 } 2463 return nullify_end(ctx); 2464 #endif 2465 } 2466 2467 static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 2468 { 2469 if (!ctx->is_pa20) { 2470 return false; 2471 } 2472 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2473 #ifndef CONFIG_USER_ONLY 2474 nullify_over(ctx); 2475 { 2476 TCGv_i64 src1 = load_gpr(ctx, a->r1); 2477 TCGv_i64 src2 = load_gpr(ctx, a->r2); 2478 2479 if (a->data) { 2480 gen_helper_idtlbt_pa20(tcg_env, src1, src2); 2481 } else { 2482 gen_helper_iitlbt_pa20(tcg_env, src1, src2); 2483 } 2484 } 2485 /* Exit TB for TLB change if mmu is enabled. */ 2486 if (ctx->tb_flags & PSW_C) { 2487 ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2488 } 2489 return nullify_end(ctx); 2490 #endif 2491 } 2492 2493 static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 2494 { 2495 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2496 #ifndef CONFIG_USER_ONLY 2497 TCGv_i64 vaddr; 2498 TCGv_i64 ofs, paddr; 2499 2500 nullify_over(ctx); 2501 2502 form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2503 2504 paddr = tcg_temp_new_i64(); 2505 gen_helper_lpa(paddr, tcg_env, vaddr); 2506 2507 /* Note that physical address result overrides base modification. */ 2508 if (a->m) { 2509 save_gpr(ctx, a->b, ofs); 2510 } 2511 save_gpr(ctx, a->t, paddr); 2512 2513 return nullify_end(ctx); 2514 #endif 2515 } 2516 2517 static bool trans_lci(DisasContext *ctx, arg_lci *a) 2518 { 2519 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2520 2521 /* The Coherence Index is an implementation-defined function of the 2522 physical address. Two addresses with the same CI have a coherent 2523 view of the cache. Our implementation is to return 0 for all, 2524 since the entire address space is coherent. */ 2525 save_gpr(ctx, a->t, ctx->zero); 2526 2527 cond_free(&ctx->null_cond); 2528 return true; 2529 } 2530 2531 static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2532 { 2533 return do_add_reg(ctx, a, false, false, false, false); 2534 } 2535 2536 static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2537 { 2538 return do_add_reg(ctx, a, true, false, false, false); 2539 } 2540 2541 static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2542 { 2543 return do_add_reg(ctx, a, false, true, false, false); 2544 } 2545 2546 static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2547 { 2548 return do_add_reg(ctx, a, false, false, false, true); 2549 } 2550 2551 static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2552 { 2553 return do_add_reg(ctx, a, false, true, false, true); 2554 } 2555 2556 static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 2557 { 2558 return do_sub_reg(ctx, a, false, false, false); 2559 } 2560 2561 static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 2562 { 2563 return do_sub_reg(ctx, a, true, false, false); 2564 } 2565 2566 static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 2567 { 2568 return do_sub_reg(ctx, a, false, false, true); 2569 } 2570 2571 static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 2572 { 2573 return do_sub_reg(ctx, a, true, false, true); 2574 } 2575 2576 static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 2577 { 2578 return do_sub_reg(ctx, a, false, true, false); 2579 } 2580 2581 static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 2582 { 2583 return do_sub_reg(ctx, a, true, true, false); 2584 } 2585 2586 static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 2587 { 2588 return do_log_reg(ctx, a, tcg_gen_andc_i64); 2589 } 2590 2591 static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 2592 { 2593 return do_log_reg(ctx, a, tcg_gen_and_i64); 2594 } 2595 2596 static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 2597 { 2598 if (a->cf == 0) { 2599 unsigned r2 = a->r2; 2600 unsigned r1 = a->r1; 2601 unsigned rt = a->t; 2602 2603 if (rt == 0) { /* NOP */ 2604 cond_free(&ctx->null_cond); 2605 return true; 2606 } 2607 if (r2 == 0) { /* COPY */ 2608 if (r1 == 0) { 2609 TCGv_i64 dest = dest_gpr(ctx, rt); 2610 tcg_gen_movi_i64(dest, 0); 2611 save_gpr(ctx, rt, dest); 2612 } else { 2613 save_gpr(ctx, rt, cpu_gr[r1]); 2614 } 2615 cond_free(&ctx->null_cond); 2616 return true; 2617 } 2618 #ifndef CONFIG_USER_ONLY 2619 /* These are QEMU extensions and are nops in the real architecture: 2620 * 2621 * or %r10,%r10,%r10 -- idle loop; wait for interrupt 2622 * or %r31,%r31,%r31 -- death loop; offline cpu 2623 * currently implemented as idle. 2624 */ 2625 if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 2626 /* No need to check for supervisor, as userland can only pause 2627 until the next timer interrupt. */ 2628 nullify_over(ctx); 2629 2630 /* Advance the instruction queue. */ 2631 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 2632 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 2633 nullify_set(ctx, 0); 2634 2635 /* Tell the qemu main loop to halt until this cpu has work. */ 2636 tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 2637 offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 2638 gen_excp_1(EXCP_HALTED); 2639 ctx->base.is_jmp = DISAS_NORETURN; 2640 2641 return nullify_end(ctx); 2642 } 2643 #endif 2644 } 2645 return do_log_reg(ctx, a, tcg_gen_or_i64); 2646 } 2647 2648 static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2649 { 2650 return do_log_reg(ctx, a, tcg_gen_xor_i64); 2651 } 2652 2653 static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 2654 { 2655 TCGv_i64 tcg_r1, tcg_r2; 2656 2657 if (a->cf) { 2658 nullify_over(ctx); 2659 } 2660 tcg_r1 = load_gpr(ctx, a->r1); 2661 tcg_r2 = load_gpr(ctx, a->r2); 2662 do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 2663 return nullify_end(ctx); 2664 } 2665 2666 static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2667 { 2668 TCGv_i64 tcg_r1, tcg_r2; 2669 2670 if (a->cf) { 2671 nullify_over(ctx); 2672 } 2673 tcg_r1 = load_gpr(ctx, a->r1); 2674 tcg_r2 = load_gpr(ctx, a->r2); 2675 do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64); 2676 return nullify_end(ctx); 2677 } 2678 2679 static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2680 { 2681 TCGv_i64 tcg_r1, tcg_r2, tmp; 2682 2683 if (a->cf) { 2684 nullify_over(ctx); 2685 } 2686 tcg_r1 = load_gpr(ctx, a->r1); 2687 tcg_r2 = load_gpr(ctx, a->r2); 2688 tmp = tcg_temp_new_i64(); 2689 tcg_gen_not_i64(tmp, tcg_r2); 2690 do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64); 2691 return nullify_end(ctx); 2692 } 2693 2694 static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2695 { 2696 return do_uaddcm(ctx, a, false); 2697 } 2698 2699 static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 2700 { 2701 return do_uaddcm(ctx, a, true); 2702 } 2703 2704 static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 2705 { 2706 TCGv_i64 tmp; 2707 2708 nullify_over(ctx); 2709 2710 tmp = tcg_temp_new_i64(); 2711 tcg_gen_shri_i64(tmp, cpu_psw_cb, 3); 2712 if (!is_i) { 2713 tcg_gen_not_i64(tmp, tmp); 2714 } 2715 tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 2716 tcg_gen_muli_i64(tmp, tmp, 6); 2717 do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false, 2718 is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64); 2719 return nullify_end(ctx); 2720 } 2721 2722 static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2723 { 2724 return do_dcor(ctx, a, false); 2725 } 2726 2727 static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 2728 { 2729 return do_dcor(ctx, a, true); 2730 } 2731 2732 static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 2733 { 2734 TCGv_i64 dest, add1, add2, addc, in1, in2; 2735 TCGv_i64 cout; 2736 2737 nullify_over(ctx); 2738 2739 in1 = load_gpr(ctx, a->r1); 2740 in2 = load_gpr(ctx, a->r2); 2741 2742 add1 = tcg_temp_new_i64(); 2743 add2 = tcg_temp_new_i64(); 2744 addc = tcg_temp_new_i64(); 2745 dest = tcg_temp_new_i64(); 2746 2747 /* Form R1 << 1 | PSW[CB]{8}. */ 2748 tcg_gen_add_i64(add1, in1, in1); 2749 tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2750 2751 /* 2752 * Add or subtract R2, depending on PSW[V]. Proper computation of 2753 * carry requires that we subtract via + ~R2 + 1, as described in 2754 * the manual. By extracting and masking V, we can produce the 2755 * proper inputs to the addition without movcond. 2756 */ 2757 tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 2758 tcg_gen_xor_i64(add2, in2, addc); 2759 tcg_gen_andi_i64(addc, addc, 1); 2760 2761 tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2762 tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2763 addc, ctx->zero); 2764 2765 /* Write back the result register. */ 2766 save_gpr(ctx, a->t, dest); 2767 2768 /* Write back PSW[CB]. */ 2769 tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 2770 tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2771 2772 /* Write back PSW[V] for the division step. */ 2773 cout = get_psw_carry(ctx, false); 2774 tcg_gen_neg_i64(cpu_psw_v, cout); 2775 tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2776 2777 /* Install the new nullification. */ 2778 if (a->cf) { 2779 TCGv_i64 sv = NULL; 2780 if (cond_need_sv(a->cf >> 1)) { 2781 /* ??? The lshift is supposed to contribute to overflow. */ 2782 sv = do_add_sv(ctx, dest, add1, add2); 2783 } 2784 ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv); 2785 } 2786 2787 return nullify_end(ctx); 2788 } 2789 2790 static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2791 { 2792 return do_add_imm(ctx, a, false, false); 2793 } 2794 2795 static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 2796 { 2797 return do_add_imm(ctx, a, true, false); 2798 } 2799 2800 static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 2801 { 2802 return do_add_imm(ctx, a, false, true); 2803 } 2804 2805 static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 2806 { 2807 return do_add_imm(ctx, a, true, true); 2808 } 2809 2810 static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 2811 { 2812 return do_sub_imm(ctx, a, false); 2813 } 2814 2815 static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 2816 { 2817 return do_sub_imm(ctx, a, true); 2818 } 2819 2820 static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 2821 { 2822 TCGv_i64 tcg_im, tcg_r2; 2823 2824 if (a->cf) { 2825 nullify_over(ctx); 2826 } 2827 2828 tcg_im = tcg_constant_i64(a->i); 2829 tcg_r2 = load_gpr(ctx, a->r); 2830 do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2831 2832 return nullify_end(ctx); 2833 } 2834 2835 static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 2836 void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 2837 { 2838 TCGv_i64 r1, r2, dest; 2839 2840 if (!ctx->is_pa20) { 2841 return false; 2842 } 2843 2844 nullify_over(ctx); 2845 2846 r1 = load_gpr(ctx, a->r1); 2847 r2 = load_gpr(ctx, a->r2); 2848 dest = dest_gpr(ctx, a->t); 2849 2850 fn(dest, r1, r2); 2851 save_gpr(ctx, a->t, dest); 2852 2853 return nullify_end(ctx); 2854 } 2855 2856 static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 2857 void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 2858 { 2859 TCGv_i64 r, dest; 2860 2861 if (!ctx->is_pa20) { 2862 return false; 2863 } 2864 2865 nullify_over(ctx); 2866 2867 r = load_gpr(ctx, a->r); 2868 dest = dest_gpr(ctx, a->t); 2869 2870 fn(dest, r, a->i); 2871 save_gpr(ctx, a->t, dest); 2872 2873 return nullify_end(ctx); 2874 } 2875 2876 static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 2877 void (*fn)(TCGv_i64, TCGv_i64, 2878 TCGv_i64, TCGv_i32)) 2879 { 2880 TCGv_i64 r1, r2, dest; 2881 2882 if (!ctx->is_pa20) { 2883 return false; 2884 } 2885 2886 nullify_over(ctx); 2887 2888 r1 = load_gpr(ctx, a->r1); 2889 r2 = load_gpr(ctx, a->r2); 2890 dest = dest_gpr(ctx, a->t); 2891 2892 fn(dest, r1, r2, tcg_constant_i32(a->sh)); 2893 save_gpr(ctx, a->t, dest); 2894 2895 return nullify_end(ctx); 2896 } 2897 2898 static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 2899 { 2900 return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 2901 } 2902 2903 static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 2904 { 2905 return do_multimedia(ctx, a, gen_helper_hadd_ss); 2906 } 2907 2908 static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 2909 { 2910 return do_multimedia(ctx, a, gen_helper_hadd_us); 2911 } 2912 2913 static bool trans_havg(DisasContext *ctx, arg_rrr *a) 2914 { 2915 return do_multimedia(ctx, a, gen_helper_havg); 2916 } 2917 2918 static bool trans_hshl(DisasContext *ctx, arg_rri *a) 2919 { 2920 return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 2921 } 2922 2923 static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 2924 { 2925 return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 2926 } 2927 2928 static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 2929 { 2930 return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 2931 } 2932 2933 static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 2934 { 2935 return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 2936 } 2937 2938 static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 2939 { 2940 return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 2941 } 2942 2943 static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 2944 { 2945 return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 2946 } 2947 2948 static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 2949 { 2950 return do_multimedia(ctx, a, gen_helper_hsub_ss); 2951 } 2952 2953 static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 2954 { 2955 return do_multimedia(ctx, a, gen_helper_hsub_us); 2956 } 2957 2958 static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2959 { 2960 uint64_t mask = 0xffff0000ffff0000ull; 2961 TCGv_i64 tmp = tcg_temp_new_i64(); 2962 2963 tcg_gen_andi_i64(tmp, r2, mask); 2964 tcg_gen_andi_i64(dst, r1, mask); 2965 tcg_gen_shri_i64(tmp, tmp, 16); 2966 tcg_gen_or_i64(dst, dst, tmp); 2967 } 2968 2969 static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 2970 { 2971 return do_multimedia(ctx, a, gen_mixh_l); 2972 } 2973 2974 static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2975 { 2976 uint64_t mask = 0x0000ffff0000ffffull; 2977 TCGv_i64 tmp = tcg_temp_new_i64(); 2978 2979 tcg_gen_andi_i64(tmp, r1, mask); 2980 tcg_gen_andi_i64(dst, r2, mask); 2981 tcg_gen_shli_i64(tmp, tmp, 16); 2982 tcg_gen_or_i64(dst, dst, tmp); 2983 } 2984 2985 static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 2986 { 2987 return do_multimedia(ctx, a, gen_mixh_r); 2988 } 2989 2990 static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2991 { 2992 TCGv_i64 tmp = tcg_temp_new_i64(); 2993 2994 tcg_gen_shri_i64(tmp, r2, 32); 2995 tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 2996 } 2997 2998 static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 2999 { 3000 return do_multimedia(ctx, a, gen_mixw_l); 3001 } 3002 3003 static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3004 { 3005 tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 3006 } 3007 3008 static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 3009 { 3010 return do_multimedia(ctx, a, gen_mixw_r); 3011 } 3012 3013 static bool trans_permh(DisasContext *ctx, arg_permh *a) 3014 { 3015 TCGv_i64 r, t0, t1, t2, t3; 3016 3017 if (!ctx->is_pa20) { 3018 return false; 3019 } 3020 3021 nullify_over(ctx); 3022 3023 r = load_gpr(ctx, a->r1); 3024 t0 = tcg_temp_new_i64(); 3025 t1 = tcg_temp_new_i64(); 3026 t2 = tcg_temp_new_i64(); 3027 t3 = tcg_temp_new_i64(); 3028 3029 tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 3030 tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 3031 tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 3032 tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 3033 3034 tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 3035 tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 3036 tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 3037 3038 save_gpr(ctx, a->t, t0); 3039 return nullify_end(ctx); 3040 } 3041 3042 static bool trans_ld(DisasContext *ctx, arg_ldst *a) 3043 { 3044 if (ctx->is_pa20) { 3045 /* 3046 * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3047 * Any base modification still occurs. 3048 */ 3049 if (a->t == 0) { 3050 return trans_nop_addrx(ctx, a); 3051 } 3052 } else if (a->size > MO_32) { 3053 return gen_illegal(ctx); 3054 } 3055 return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 3056 a->disp, a->sp, a->m, a->size | MO_TE); 3057 } 3058 3059 static bool trans_st(DisasContext *ctx, arg_ldst *a) 3060 { 3061 assert(a->x == 0 && a->scale == 0); 3062 if (!ctx->is_pa20 && a->size > MO_32) { 3063 return gen_illegal(ctx); 3064 } 3065 return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 3066 } 3067 3068 static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 3069 { 3070 MemOp mop = MO_TE | MO_ALIGN | a->size; 3071 TCGv_i64 dest, ofs; 3072 TCGv_i64 addr; 3073 3074 if (!ctx->is_pa20 && a->size > MO_32) { 3075 return gen_illegal(ctx); 3076 } 3077 3078 nullify_over(ctx); 3079 3080 if (a->m) { 3081 /* Base register modification. Make sure if RT == RB, 3082 we see the result of the load. */ 3083 dest = tcg_temp_new_i64(); 3084 } else { 3085 dest = dest_gpr(ctx, a->t); 3086 } 3087 3088 form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0, 3089 a->disp, a->sp, a->m, MMU_DISABLED(ctx)); 3090 3091 /* 3092 * For hppa1.1, LDCW is undefined unless aligned mod 16. 3093 * However actual hardware succeeds with aligned mod 4. 3094 * Detect this case and log a GUEST_ERROR. 3095 * 3096 * TODO: HPPA64 relaxes the over-alignment requirement 3097 * with the ,co completer. 3098 */ 3099 gen_helper_ldc_check(addr); 3100 3101 tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3102 3103 if (a->m) { 3104 save_gpr(ctx, a->b, ofs); 3105 } 3106 save_gpr(ctx, a->t, dest); 3107 3108 return nullify_end(ctx); 3109 } 3110 3111 static bool trans_stby(DisasContext *ctx, arg_stby *a) 3112 { 3113 TCGv_i64 ofs, val; 3114 TCGv_i64 addr; 3115 3116 nullify_over(ctx); 3117 3118 form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 3119 MMU_DISABLED(ctx)); 3120 val = load_gpr(ctx, a->r); 3121 if (a->a) { 3122 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3123 gen_helper_stby_e_parallel(tcg_env, addr, val); 3124 } else { 3125 gen_helper_stby_e(tcg_env, addr, val); 3126 } 3127 } else { 3128 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3129 gen_helper_stby_b_parallel(tcg_env, addr, val); 3130 } else { 3131 gen_helper_stby_b(tcg_env, addr, val); 3132 } 3133 } 3134 if (a->m) { 3135 tcg_gen_andi_i64(ofs, ofs, ~3); 3136 save_gpr(ctx, a->b, ofs); 3137 } 3138 3139 return nullify_end(ctx); 3140 } 3141 3142 static bool trans_stdby(DisasContext *ctx, arg_stby *a) 3143 { 3144 TCGv_i64 ofs, val; 3145 TCGv_i64 addr; 3146 3147 if (!ctx->is_pa20) { 3148 return false; 3149 } 3150 nullify_over(ctx); 3151 3152 form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 3153 MMU_DISABLED(ctx)); 3154 val = load_gpr(ctx, a->r); 3155 if (a->a) { 3156 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3157 gen_helper_stdby_e_parallel(tcg_env, addr, val); 3158 } else { 3159 gen_helper_stdby_e(tcg_env, addr, val); 3160 } 3161 } else { 3162 if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3163 gen_helper_stdby_b_parallel(tcg_env, addr, val); 3164 } else { 3165 gen_helper_stdby_b(tcg_env, addr, val); 3166 } 3167 } 3168 if (a->m) { 3169 tcg_gen_andi_i64(ofs, ofs, ~7); 3170 save_gpr(ctx, a->b, ofs); 3171 } 3172 3173 return nullify_end(ctx); 3174 } 3175 3176 static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3177 { 3178 int hold_mmu_idx = ctx->mmu_idx; 3179 3180 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3181 ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 3182 trans_ld(ctx, a); 3183 ctx->mmu_idx = hold_mmu_idx; 3184 return true; 3185 } 3186 3187 static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3188 { 3189 int hold_mmu_idx = ctx->mmu_idx; 3190 3191 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3192 ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 3193 trans_st(ctx, a); 3194 ctx->mmu_idx = hold_mmu_idx; 3195 return true; 3196 } 3197 3198 static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3199 { 3200 TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3201 3202 tcg_gen_movi_i64(tcg_rt, a->i); 3203 save_gpr(ctx, a->t, tcg_rt); 3204 cond_free(&ctx->null_cond); 3205 return true; 3206 } 3207 3208 static bool trans_addil(DisasContext *ctx, arg_addil *a) 3209 { 3210 TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 3211 TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3212 3213 tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3214 save_gpr(ctx, 1, tcg_r1); 3215 cond_free(&ctx->null_cond); 3216 return true; 3217 } 3218 3219 static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3220 { 3221 TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3222 3223 /* Special case rb == 0, for the LDI pseudo-op. 3224 The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 3225 if (a->b == 0) { 3226 tcg_gen_movi_i64(tcg_rt, a->i); 3227 } else { 3228 tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3229 } 3230 save_gpr(ctx, a->t, tcg_rt); 3231 cond_free(&ctx->null_cond); 3232 return true; 3233 } 3234 3235 static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3236 unsigned c, unsigned f, bool d, unsigned n, int disp) 3237 { 3238 TCGv_i64 dest, in2, sv; 3239 DisasCond cond; 3240 3241 in2 = load_gpr(ctx, r); 3242 dest = tcg_temp_new_i64(); 3243 3244 tcg_gen_sub_i64(dest, in1, in2); 3245 3246 sv = NULL; 3247 if (cond_need_sv(c)) { 3248 sv = do_sub_sv(ctx, dest, in1, in2); 3249 } 3250 3251 cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 3252 return do_cbranch(ctx, disp, n, &cond); 3253 } 3254 3255 static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 3256 { 3257 if (!ctx->is_pa20 && a->d) { 3258 return false; 3259 } 3260 nullify_over(ctx); 3261 return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3262 a->c, a->f, a->d, a->n, a->disp); 3263 } 3264 3265 static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 3266 { 3267 if (!ctx->is_pa20 && a->d) { 3268 return false; 3269 } 3270 nullify_over(ctx); 3271 return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3272 a->c, a->f, a->d, a->n, a->disp); 3273 } 3274 3275 static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3276 unsigned c, unsigned f, unsigned n, int disp) 3277 { 3278 TCGv_i64 dest, in2, sv, cb_cond; 3279 DisasCond cond; 3280 bool d = false; 3281 3282 /* 3283 * For hppa64, the ADDB conditions change with PSW.W, 3284 * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3285 */ 3286 if (ctx->tb_flags & PSW_W) { 3287 d = c >= 5; 3288 if (d) { 3289 c &= 3; 3290 } 3291 } 3292 3293 in2 = load_gpr(ctx, r); 3294 dest = tcg_temp_new_i64(); 3295 sv = NULL; 3296 cb_cond = NULL; 3297 3298 if (cond_need_cb(c)) { 3299 TCGv_i64 cb = tcg_temp_new_i64(); 3300 TCGv_i64 cb_msb = tcg_temp_new_i64(); 3301 3302 tcg_gen_movi_i64(cb_msb, 0); 3303 tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 3304 tcg_gen_xor_i64(cb, in1, in2); 3305 tcg_gen_xor_i64(cb, cb, dest); 3306 cb_cond = get_carry(ctx, d, cb, cb_msb); 3307 } else { 3308 tcg_gen_add_i64(dest, in1, in2); 3309 } 3310 if (cond_need_sv(c)) { 3311 sv = do_add_sv(ctx, dest, in1, in2); 3312 } 3313 3314 cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 3315 save_gpr(ctx, r, dest); 3316 return do_cbranch(ctx, disp, n, &cond); 3317 } 3318 3319 static bool trans_addb(DisasContext *ctx, arg_addb *a) 3320 { 3321 nullify_over(ctx); 3322 return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 3323 } 3324 3325 static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 3326 { 3327 nullify_over(ctx); 3328 return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 3329 } 3330 3331 static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 3332 { 3333 TCGv_i64 tmp, tcg_r; 3334 DisasCond cond; 3335 3336 nullify_over(ctx); 3337 3338 tmp = tcg_temp_new_i64(); 3339 tcg_r = load_gpr(ctx, a->r); 3340 if (cond_need_ext(ctx, a->d)) { 3341 /* Force shift into [32,63] */ 3342 tcg_gen_ori_i64(tmp, cpu_sar, 32); 3343 tcg_gen_shl_i64(tmp, tcg_r, tmp); 3344 } else { 3345 tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 3346 } 3347 3348 cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 3349 return do_cbranch(ctx, a->disp, a->n, &cond); 3350 } 3351 3352 static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 3353 { 3354 TCGv_i64 tmp, tcg_r; 3355 DisasCond cond; 3356 int p; 3357 3358 nullify_over(ctx); 3359 3360 tmp = tcg_temp_new_i64(); 3361 tcg_r = load_gpr(ctx, a->r); 3362 p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0); 3363 tcg_gen_shli_i64(tmp, tcg_r, p); 3364 3365 cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 3366 return do_cbranch(ctx, a->disp, a->n, &cond); 3367 } 3368 3369 static bool trans_movb(DisasContext *ctx, arg_movb *a) 3370 { 3371 TCGv_i64 dest; 3372 DisasCond cond; 3373 3374 nullify_over(ctx); 3375 3376 dest = dest_gpr(ctx, a->r2); 3377 if (a->r1 == 0) { 3378 tcg_gen_movi_i64(dest, 0); 3379 } else { 3380 tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 3381 } 3382 3383 /* All MOVB conditions are 32-bit. */ 3384 cond = do_sed_cond(ctx, a->c, false, dest); 3385 return do_cbranch(ctx, a->disp, a->n, &cond); 3386 } 3387 3388 static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 3389 { 3390 TCGv_i64 dest; 3391 DisasCond cond; 3392 3393 nullify_over(ctx); 3394 3395 dest = dest_gpr(ctx, a->r); 3396 tcg_gen_movi_i64(dest, a->i); 3397 3398 /* All MOVBI conditions are 32-bit. */ 3399 cond = do_sed_cond(ctx, a->c, false, dest); 3400 return do_cbranch(ctx, a->disp, a->n, &cond); 3401 } 3402 3403 static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 3404 { 3405 TCGv_i64 dest, src2; 3406 3407 if (!ctx->is_pa20 && a->d) { 3408 return false; 3409 } 3410 if (a->c) { 3411 nullify_over(ctx); 3412 } 3413 3414 dest = dest_gpr(ctx, a->t); 3415 src2 = load_gpr(ctx, a->r2); 3416 if (a->r1 == 0) { 3417 if (a->d) { 3418 tcg_gen_shr_i64(dest, src2, cpu_sar); 3419 } else { 3420 TCGv_i64 tmp = tcg_temp_new_i64(); 3421 3422 tcg_gen_ext32u_i64(dest, src2); 3423 tcg_gen_andi_i64(tmp, cpu_sar, 31); 3424 tcg_gen_shr_i64(dest, dest, tmp); 3425 } 3426 } else if (a->r1 == a->r2) { 3427 if (a->d) { 3428 tcg_gen_rotr_i64(dest, src2, cpu_sar); 3429 } else { 3430 TCGv_i32 t32 = tcg_temp_new_i32(); 3431 TCGv_i32 s32 = tcg_temp_new_i32(); 3432 3433 tcg_gen_extrl_i64_i32(t32, src2); 3434 tcg_gen_extrl_i64_i32(s32, cpu_sar); 3435 tcg_gen_andi_i32(s32, s32, 31); 3436 tcg_gen_rotr_i32(t32, t32, s32); 3437 tcg_gen_extu_i32_i64(dest, t32); 3438 } 3439 } else { 3440 TCGv_i64 src1 = load_gpr(ctx, a->r1); 3441 3442 if (a->d) { 3443 TCGv_i64 t = tcg_temp_new_i64(); 3444 TCGv_i64 n = tcg_temp_new_i64(); 3445 3446 tcg_gen_xori_i64(n, cpu_sar, 63); 3447 tcg_gen_shl_i64(t, src1, n); 3448 tcg_gen_shli_i64(t, t, 1); 3449 tcg_gen_shr_i64(dest, src2, cpu_sar); 3450 tcg_gen_or_i64(dest, dest, t); 3451 } else { 3452 TCGv_i64 t = tcg_temp_new_i64(); 3453 TCGv_i64 s = tcg_temp_new_i64(); 3454 3455 tcg_gen_concat32_i64(t, src2, src1); 3456 tcg_gen_andi_i64(s, cpu_sar, 31); 3457 tcg_gen_shr_i64(dest, t, s); 3458 } 3459 } 3460 save_gpr(ctx, a->t, dest); 3461 3462 /* Install the new nullification. */ 3463 cond_free(&ctx->null_cond); 3464 if (a->c) { 3465 ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 3466 } 3467 return nullify_end(ctx); 3468 } 3469 3470 static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 3471 { 3472 unsigned width, sa; 3473 TCGv_i64 dest, t2; 3474 3475 if (!ctx->is_pa20 && a->d) { 3476 return false; 3477 } 3478 if (a->c) { 3479 nullify_over(ctx); 3480 } 3481 3482 width = a->d ? 64 : 32; 3483 sa = width - 1 - a->cpos; 3484 3485 dest = dest_gpr(ctx, a->t); 3486 t2 = load_gpr(ctx, a->r2); 3487 if (a->r1 == 0) { 3488 tcg_gen_extract_i64(dest, t2, sa, width - sa); 3489 } else if (width == TARGET_LONG_BITS) { 3490 tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3491 } else { 3492 assert(!a->d); 3493 if (a->r1 == a->r2) { 3494 TCGv_i32 t32 = tcg_temp_new_i32(); 3495 tcg_gen_extrl_i64_i32(t32, t2); 3496 tcg_gen_rotri_i32(t32, t32, sa); 3497 tcg_gen_extu_i32_i64(dest, t32); 3498 } else { 3499 tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3500 tcg_gen_extract_i64(dest, dest, sa, 32); 3501 } 3502 } 3503 save_gpr(ctx, a->t, dest); 3504 3505 /* Install the new nullification. */ 3506 cond_free(&ctx->null_cond); 3507 if (a->c) { 3508 ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 3509 } 3510 return nullify_end(ctx); 3511 } 3512 3513 static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 3514 { 3515 unsigned widthm1 = a->d ? 63 : 31; 3516 TCGv_i64 dest, src, tmp; 3517 3518 if (!ctx->is_pa20 && a->d) { 3519 return false; 3520 } 3521 if (a->c) { 3522 nullify_over(ctx); 3523 } 3524 3525 dest = dest_gpr(ctx, a->t); 3526 src = load_gpr(ctx, a->r); 3527 tmp = tcg_temp_new_i64(); 3528 3529 /* Recall that SAR is using big-endian bit numbering. */ 3530 tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 3531 tcg_gen_xori_i64(tmp, tmp, widthm1); 3532 3533 if (a->se) { 3534 if (!a->d) { 3535 tcg_gen_ext32s_i64(dest, src); 3536 src = dest; 3537 } 3538 tcg_gen_sar_i64(dest, src, tmp); 3539 tcg_gen_sextract_i64(dest, dest, 0, a->len); 3540 } else { 3541 if (!a->d) { 3542 tcg_gen_ext32u_i64(dest, src); 3543 src = dest; 3544 } 3545 tcg_gen_shr_i64(dest, src, tmp); 3546 tcg_gen_extract_i64(dest, dest, 0, a->len); 3547 } 3548 save_gpr(ctx, a->t, dest); 3549 3550 /* Install the new nullification. */ 3551 cond_free(&ctx->null_cond); 3552 if (a->c) { 3553 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 3554 } 3555 return nullify_end(ctx); 3556 } 3557 3558 static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 3559 { 3560 unsigned len, cpos, width; 3561 TCGv_i64 dest, src; 3562 3563 if (!ctx->is_pa20 && a->d) { 3564 return false; 3565 } 3566 if (a->c) { 3567 nullify_over(ctx); 3568 } 3569 3570 len = a->len; 3571 width = a->d ? 64 : 32; 3572 cpos = width - 1 - a->pos; 3573 if (cpos + len > width) { 3574 len = width - cpos; 3575 } 3576 3577 dest = dest_gpr(ctx, a->t); 3578 src = load_gpr(ctx, a->r); 3579 if (a->se) { 3580 tcg_gen_sextract_i64(dest, src, cpos, len); 3581 } else { 3582 tcg_gen_extract_i64(dest, src, cpos, len); 3583 } 3584 save_gpr(ctx, a->t, dest); 3585 3586 /* Install the new nullification. */ 3587 cond_free(&ctx->null_cond); 3588 if (a->c) { 3589 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 3590 } 3591 return nullify_end(ctx); 3592 } 3593 3594 static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 3595 { 3596 unsigned len, width; 3597 uint64_t mask0, mask1; 3598 TCGv_i64 dest; 3599 3600 if (!ctx->is_pa20 && a->d) { 3601 return false; 3602 } 3603 if (a->c) { 3604 nullify_over(ctx); 3605 } 3606 3607 len = a->len; 3608 width = a->d ? 64 : 32; 3609 if (a->cpos + len > width) { 3610 len = width - a->cpos; 3611 } 3612 3613 dest = dest_gpr(ctx, a->t); 3614 mask0 = deposit64(0, a->cpos, len, a->i); 3615 mask1 = deposit64(-1, a->cpos, len, a->i); 3616 3617 if (a->nz) { 3618 TCGv_i64 src = load_gpr(ctx, a->t); 3619 tcg_gen_andi_i64(dest, src, mask1); 3620 tcg_gen_ori_i64(dest, dest, mask0); 3621 } else { 3622 tcg_gen_movi_i64(dest, mask0); 3623 } 3624 save_gpr(ctx, a->t, dest); 3625 3626 /* Install the new nullification. */ 3627 cond_free(&ctx->null_cond); 3628 if (a->c) { 3629 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 3630 } 3631 return nullify_end(ctx); 3632 } 3633 3634 static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 3635 { 3636 unsigned rs = a->nz ? a->t : 0; 3637 unsigned len, width; 3638 TCGv_i64 dest, val; 3639 3640 if (!ctx->is_pa20 && a->d) { 3641 return false; 3642 } 3643 if (a->c) { 3644 nullify_over(ctx); 3645 } 3646 3647 len = a->len; 3648 width = a->d ? 64 : 32; 3649 if (a->cpos + len > width) { 3650 len = width - a->cpos; 3651 } 3652 3653 dest = dest_gpr(ctx, a->t); 3654 val = load_gpr(ctx, a->r); 3655 if (rs == 0) { 3656 tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 3657 } else { 3658 tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 3659 } 3660 save_gpr(ctx, a->t, dest); 3661 3662 /* Install the new nullification. */ 3663 cond_free(&ctx->null_cond); 3664 if (a->c) { 3665 ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 3666 } 3667 return nullify_end(ctx); 3668 } 3669 3670 static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 3671 bool d, bool nz, unsigned len, TCGv_i64 val) 3672 { 3673 unsigned rs = nz ? rt : 0; 3674 unsigned widthm1 = d ? 63 : 31; 3675 TCGv_i64 mask, tmp, shift, dest; 3676 uint64_t msb = 1ULL << (len - 1); 3677 3678 dest = dest_gpr(ctx, rt); 3679 shift = tcg_temp_new_i64(); 3680 tmp = tcg_temp_new_i64(); 3681 3682 /* Convert big-endian bit numbering in SAR to left-shift. */ 3683 tcg_gen_andi_i64(shift, cpu_sar, widthm1); 3684 tcg_gen_xori_i64(shift, shift, widthm1); 3685 3686 mask = tcg_temp_new_i64(); 3687 tcg_gen_movi_i64(mask, msb + (msb - 1)); 3688 tcg_gen_and_i64(tmp, val, mask); 3689 if (rs) { 3690 tcg_gen_shl_i64(mask, mask, shift); 3691 tcg_gen_shl_i64(tmp, tmp, shift); 3692 tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 3693 tcg_gen_or_i64(dest, dest, tmp); 3694 } else { 3695 tcg_gen_shl_i64(dest, tmp, shift); 3696 } 3697 save_gpr(ctx, rt, dest); 3698 3699 /* Install the new nullification. */ 3700 cond_free(&ctx->null_cond); 3701 if (c) { 3702 ctx->null_cond = do_sed_cond(ctx, c, d, dest); 3703 } 3704 return nullify_end(ctx); 3705 } 3706 3707 static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 3708 { 3709 if (!ctx->is_pa20 && a->d) { 3710 return false; 3711 } 3712 if (a->c) { 3713 nullify_over(ctx); 3714 } 3715 return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 3716 load_gpr(ctx, a->r)); 3717 } 3718 3719 static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 3720 { 3721 if (!ctx->is_pa20 && a->d) { 3722 return false; 3723 } 3724 if (a->c) { 3725 nullify_over(ctx); 3726 } 3727 return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 3728 tcg_constant_i64(a->i)); 3729 } 3730 3731 static bool trans_be(DisasContext *ctx, arg_be *a) 3732 { 3733 TCGv_i64 tmp; 3734 3735 #ifdef CONFIG_USER_ONLY 3736 /* ??? It seems like there should be a good way of using 3737 "be disp(sr2, r0)", the canonical gateway entry mechanism 3738 to our advantage. But that appears to be inconvenient to 3739 manage along side branch delay slots. Therefore we handle 3740 entry into the gateway page via absolute address. */ 3741 /* Since we don't implement spaces, just branch. Do notice the special 3742 case of "be disp(*,r0)" using a direct branch to disp, so that we can 3743 goto_tb to the TB containing the syscall. */ 3744 if (a->b == 0) { 3745 return do_dbranch(ctx, a->disp, a->l, a->n); 3746 } 3747 #else 3748 nullify_over(ctx); 3749 #endif 3750 3751 tmp = tcg_temp_new_i64(); 3752 tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp); 3753 tmp = do_ibranch_priv(ctx, tmp); 3754 3755 #ifdef CONFIG_USER_ONLY 3756 return do_ibranch(ctx, tmp, a->l, a->n); 3757 #else 3758 TCGv_i64 new_spc = tcg_temp_new_i64(); 3759 3760 load_spr(ctx, new_spc, a->sp); 3761 if (a->l) { 3762 copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); 3763 tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); 3764 } 3765 if (a->n && use_nullify_skip(ctx)) { 3766 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 3767 tcg_gen_addi_i64(tmp, tmp, 4); 3768 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3769 tcg_gen_mov_i64(cpu_iasq_f, new_spc); 3770 tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); 3771 } else { 3772 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3773 if (ctx->iaoq_b == -1) { 3774 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3775 } 3776 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3777 tcg_gen_mov_i64(cpu_iasq_b, new_spc); 3778 nullify_set(ctx, a->n); 3779 } 3780 tcg_gen_lookup_and_goto_ptr(); 3781 ctx->base.is_jmp = DISAS_NORETURN; 3782 return nullify_end(ctx); 3783 #endif 3784 } 3785 3786 static bool trans_bl(DisasContext *ctx, arg_bl *a) 3787 { 3788 return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n); 3789 } 3790 3791 static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 3792 { 3793 uint64_t dest = iaoq_dest(ctx, a->disp); 3794 3795 nullify_over(ctx); 3796 3797 /* Make sure the caller hasn't done something weird with the queue. 3798 * ??? This is not quite the same as the PSW[B] bit, which would be 3799 * expensive to track. Real hardware will trap for 3800 * b gateway 3801 * b gateway+4 (in delay slot of first branch) 3802 * However, checking for a non-sequential instruction queue *will* 3803 * diagnose the security hole 3804 * b gateway 3805 * b evil 3806 * in which instructions at evil would run with increased privs. 3807 */ 3808 if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) { 3809 return gen_illegal(ctx); 3810 } 3811 3812 #ifndef CONFIG_USER_ONLY 3813 if (ctx->tb_flags & PSW_C) { 3814 CPUHPPAState *env = cpu_env(ctx->cs); 3815 int type = hppa_artype_for_page(env, ctx->base.pc_next); 3816 /* If we could not find a TLB entry, then we need to generate an 3817 ITLB miss exception so the kernel will provide it. 3818 The resulting TLB fill operation will invalidate this TB and 3819 we will re-translate, at which point we *will* be able to find 3820 the TLB entry and determine if this is in fact a gateway page. */ 3821 if (type < 0) { 3822 gen_excp(ctx, EXCP_ITLB_MISS); 3823 return true; 3824 } 3825 /* No change for non-gateway pages or for priv decrease. */ 3826 if (type >= 4 && type - 4 < ctx->privilege) { 3827 dest = deposit32(dest, 0, 2, type - 4); 3828 } 3829 } else { 3830 dest &= -4; /* priv = 0 */ 3831 } 3832 #endif 3833 3834 if (a->l) { 3835 TCGv_i64 tmp = dest_gpr(ctx, a->l); 3836 if (ctx->privilege < 3) { 3837 tcg_gen_andi_i64(tmp, tmp, -4); 3838 } 3839 tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 3840 save_gpr(ctx, a->l, tmp); 3841 } 3842 3843 return do_dbranch(ctx, dest, 0, a->n); 3844 } 3845 3846 static bool trans_blr(DisasContext *ctx, arg_blr *a) 3847 { 3848 if (a->x) { 3849 TCGv_i64 tmp = tcg_temp_new_i64(); 3850 tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3); 3851 tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8); 3852 /* The computation here never changes privilege level. */ 3853 return do_ibranch(ctx, tmp, a->l, a->n); 3854 } else { 3855 /* BLR R0,RX is a good way to load PC+8 into RX. */ 3856 return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n); 3857 } 3858 } 3859 3860 static bool trans_bv(DisasContext *ctx, arg_bv *a) 3861 { 3862 TCGv_i64 dest; 3863 3864 if (a->x == 0) { 3865 dest = load_gpr(ctx, a->b); 3866 } else { 3867 dest = tcg_temp_new_i64(); 3868 tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 3869 tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 3870 } 3871 dest = do_ibranch_priv(ctx, dest); 3872 return do_ibranch(ctx, dest, 0, a->n); 3873 } 3874 3875 static bool trans_bve(DisasContext *ctx, arg_bve *a) 3876 { 3877 TCGv_i64 dest; 3878 3879 #ifdef CONFIG_USER_ONLY 3880 dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3881 return do_ibranch(ctx, dest, a->l, a->n); 3882 #else 3883 nullify_over(ctx); 3884 dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3885 3886 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3887 if (ctx->iaoq_b == -1) { 3888 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3889 } 3890 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest); 3891 tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); 3892 if (a->l) { 3893 copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var); 3894 } 3895 nullify_set(ctx, a->n); 3896 tcg_gen_lookup_and_goto_ptr(); 3897 ctx->base.is_jmp = DISAS_NORETURN; 3898 return nullify_end(ctx); 3899 #endif 3900 } 3901 3902 static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 3903 { 3904 /* All branch target stack instructions implement as nop. */ 3905 return ctx->is_pa20; 3906 } 3907 3908 /* 3909 * Float class 0 3910 */ 3911 3912 static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3913 { 3914 tcg_gen_mov_i32(dst, src); 3915 } 3916 3917 static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 3918 { 3919 uint64_t ret; 3920 3921 if (ctx->is_pa20) { 3922 ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 3923 } else { 3924 ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 3925 } 3926 3927 nullify_over(ctx); 3928 save_frd(0, tcg_constant_i64(ret)); 3929 return nullify_end(ctx); 3930 } 3931 3932 static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 3933 { 3934 return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 3935 } 3936 3937 static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3938 { 3939 tcg_gen_mov_i64(dst, src); 3940 } 3941 3942 static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 3943 { 3944 return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 3945 } 3946 3947 static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3948 { 3949 tcg_gen_andi_i32(dst, src, INT32_MAX); 3950 } 3951 3952 static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 3953 { 3954 return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 3955 } 3956 3957 static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3958 { 3959 tcg_gen_andi_i64(dst, src, INT64_MAX); 3960 } 3961 3962 static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 3963 { 3964 return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 3965 } 3966 3967 static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 3968 { 3969 return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 3970 } 3971 3972 static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 3973 { 3974 return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 3975 } 3976 3977 static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 3978 { 3979 return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 3980 } 3981 3982 static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 3983 { 3984 return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 3985 } 3986 3987 static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3988 { 3989 tcg_gen_xori_i32(dst, src, INT32_MIN); 3990 } 3991 3992 static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 3993 { 3994 return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 3995 } 3996 3997 static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3998 { 3999 tcg_gen_xori_i64(dst, src, INT64_MIN); 4000 } 4001 4002 static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 4003 { 4004 return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 4005 } 4006 4007 static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4008 { 4009 tcg_gen_ori_i32(dst, src, INT32_MIN); 4010 } 4011 4012 static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 4013 { 4014 return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 4015 } 4016 4017 static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4018 { 4019 tcg_gen_ori_i64(dst, src, INT64_MIN); 4020 } 4021 4022 static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 4023 { 4024 return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 4025 } 4026 4027 /* 4028 * Float class 1 4029 */ 4030 4031 static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 4032 { 4033 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 4034 } 4035 4036 static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 4037 { 4038 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 4039 } 4040 4041 static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 4042 { 4043 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 4044 } 4045 4046 static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 4047 { 4048 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 4049 } 4050 4051 static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 4052 { 4053 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 4054 } 4055 4056 static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 4057 { 4058 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 4059 } 4060 4061 static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 4062 { 4063 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 4064 } 4065 4066 static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 4067 { 4068 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 4069 } 4070 4071 static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 4072 { 4073 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 4074 } 4075 4076 static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 4077 { 4078 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 4079 } 4080 4081 static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 4082 { 4083 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 4084 } 4085 4086 static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 4087 { 4088 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 4089 } 4090 4091 static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 4092 { 4093 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 4094 } 4095 4096 static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 4097 { 4098 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 4099 } 4100 4101 static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 4102 { 4103 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 4104 } 4105 4106 static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 4107 { 4108 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 4109 } 4110 4111 static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 4112 { 4113 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 4114 } 4115 4116 static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 4117 { 4118 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 4119 } 4120 4121 static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 4122 { 4123 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 4124 } 4125 4126 static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 4127 { 4128 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 4129 } 4130 4131 static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 4132 { 4133 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 4134 } 4135 4136 static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 4137 { 4138 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 4139 } 4140 4141 static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 4142 { 4143 return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 4144 } 4145 4146 static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 4147 { 4148 return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 4149 } 4150 4151 static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 4152 { 4153 return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 4154 } 4155 4156 static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 4157 { 4158 return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 4159 } 4160 4161 /* 4162 * Float class 2 4163 */ 4164 4165 static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4166 { 4167 TCGv_i32 ta, tb, tc, ty; 4168 4169 nullify_over(ctx); 4170 4171 ta = load_frw0_i32(a->r1); 4172 tb = load_frw0_i32(a->r2); 4173 ty = tcg_constant_i32(a->y); 4174 tc = tcg_constant_i32(a->c); 4175 4176 gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4177 4178 return nullify_end(ctx); 4179 } 4180 4181 static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4182 { 4183 TCGv_i64 ta, tb; 4184 TCGv_i32 tc, ty; 4185 4186 nullify_over(ctx); 4187 4188 ta = load_frd0(a->r1); 4189 tb = load_frd0(a->r2); 4190 ty = tcg_constant_i32(a->y); 4191 tc = tcg_constant_i32(a->c); 4192 4193 gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4194 4195 return nullify_end(ctx); 4196 } 4197 4198 static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4199 { 4200 TCGv_i64 t; 4201 4202 nullify_over(ctx); 4203 4204 t = tcg_temp_new_i64(); 4205 tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4206 4207 if (a->y == 1) { 4208 int mask; 4209 bool inv = false; 4210 4211 switch (a->c) { 4212 case 0: /* simple */ 4213 tcg_gen_andi_i64(t, t, 0x4000000); 4214 ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4215 goto done; 4216 case 2: /* rej */ 4217 inv = true; 4218 /* fallthru */ 4219 case 1: /* acc */ 4220 mask = 0x43ff800; 4221 break; 4222 case 6: /* rej8 */ 4223 inv = true; 4224 /* fallthru */ 4225 case 5: /* acc8 */ 4226 mask = 0x43f8000; 4227 break; 4228 case 9: /* acc6 */ 4229 mask = 0x43e0000; 4230 break; 4231 case 13: /* acc4 */ 4232 mask = 0x4380000; 4233 break; 4234 case 17: /* acc2 */ 4235 mask = 0x4200000; 4236 break; 4237 default: 4238 gen_illegal(ctx); 4239 return true; 4240 } 4241 if (inv) { 4242 TCGv_i64 c = tcg_constant_i64(mask); 4243 tcg_gen_or_i64(t, t, c); 4244 ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 4245 } else { 4246 tcg_gen_andi_i64(t, t, mask); 4247 ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 4248 } 4249 } else { 4250 unsigned cbit = (a->y ^ 1) - 1; 4251 4252 tcg_gen_extract_i64(t, t, 21 - cbit, 1); 4253 ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4254 } 4255 4256 done: 4257 return nullify_end(ctx); 4258 } 4259 4260 /* 4261 * Float class 2 4262 */ 4263 4264 static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4265 { 4266 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 4267 } 4268 4269 static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 4270 { 4271 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 4272 } 4273 4274 static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 4275 { 4276 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 4277 } 4278 4279 static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 4280 { 4281 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 4282 } 4283 4284 static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 4285 { 4286 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 4287 } 4288 4289 static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 4290 { 4291 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 4292 } 4293 4294 static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 4295 { 4296 return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 4297 } 4298 4299 static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 4300 { 4301 return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 4302 } 4303 4304 static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 4305 { 4306 TCGv_i64 x, y; 4307 4308 nullify_over(ctx); 4309 4310 x = load_frw0_i64(a->r1); 4311 y = load_frw0_i64(a->r2); 4312 tcg_gen_mul_i64(x, x, y); 4313 save_frd(a->t, x); 4314 4315 return nullify_end(ctx); 4316 } 4317 4318 /* Convert the fmpyadd single-precision register encodings to standard. */ 4319 static inline int fmpyadd_s_reg(unsigned r) 4320 { 4321 return (r & 16) * 2 + 16 + (r & 15); 4322 } 4323 4324 static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4325 { 4326 int tm = fmpyadd_s_reg(a->tm); 4327 int ra = fmpyadd_s_reg(a->ra); 4328 int ta = fmpyadd_s_reg(a->ta); 4329 int rm2 = fmpyadd_s_reg(a->rm2); 4330 int rm1 = fmpyadd_s_reg(a->rm1); 4331 4332 nullify_over(ctx); 4333 4334 do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4335 do_fop_weww(ctx, ta, ta, ra, 4336 is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4337 4338 return nullify_end(ctx); 4339 } 4340 4341 static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4342 { 4343 return do_fmpyadd_s(ctx, a, false); 4344 } 4345 4346 static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4347 { 4348 return do_fmpyadd_s(ctx, a, true); 4349 } 4350 4351 static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4352 { 4353 nullify_over(ctx); 4354 4355 do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4356 do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4357 is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4358 4359 return nullify_end(ctx); 4360 } 4361 4362 static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4363 { 4364 return do_fmpyadd_d(ctx, a, false); 4365 } 4366 4367 static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4368 { 4369 return do_fmpyadd_d(ctx, a, true); 4370 } 4371 4372 static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4373 { 4374 TCGv_i32 x, y, z; 4375 4376 nullify_over(ctx); 4377 x = load_frw0_i32(a->rm1); 4378 y = load_frw0_i32(a->rm2); 4379 z = load_frw0_i32(a->ra3); 4380 4381 if (a->neg) { 4382 gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4383 } else { 4384 gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4385 } 4386 4387 save_frw_i32(a->t, x); 4388 return nullify_end(ctx); 4389 } 4390 4391 static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4392 { 4393 TCGv_i64 x, y, z; 4394 4395 nullify_over(ctx); 4396 x = load_frd0(a->rm1); 4397 y = load_frd0(a->rm2); 4398 z = load_frd0(a->ra3); 4399 4400 if (a->neg) { 4401 gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4402 } else { 4403 gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4404 } 4405 4406 save_frd(a->t, x); 4407 return nullify_end(ctx); 4408 } 4409 4410 static bool trans_diag(DisasContext *ctx, arg_diag *a) 4411 { 4412 CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4413 #ifndef CONFIG_USER_ONLY 4414 if (a->i == 0x100) { 4415 /* emulate PDC BTLB, called by SeaBIOS-hppa */ 4416 nullify_over(ctx); 4417 gen_helper_diag_btlb(tcg_env); 4418 return nullify_end(ctx); 4419 } 4420 if (a->i == 0x101) { 4421 /* print char in %r26 to first serial console, used by SeaBIOS-hppa */ 4422 nullify_over(ctx); 4423 gen_helper_diag_console_output(tcg_env); 4424 return nullify_end(ctx); 4425 } 4426 #endif 4427 qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4428 return true; 4429 } 4430 4431 static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 4432 { 4433 DisasContext *ctx = container_of(dcbase, DisasContext, base); 4434 int bound; 4435 4436 ctx->cs = cs; 4437 ctx->tb_flags = ctx->base.tb->flags; 4438 ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 4439 4440 #ifdef CONFIG_USER_ONLY 4441 ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 4442 ctx->mmu_idx = MMU_USER_IDX; 4443 ctx->iaoq_f = ctx->base.pc_first | ctx->privilege; 4444 ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege; 4445 ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4446 #else 4447 ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4448 ctx->mmu_idx = (ctx->tb_flags & PSW_D 4449 ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4450 : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX); 4451 4452 /* Recover the IAOQ values from the GVA + PRIV. */ 4453 uint64_t cs_base = ctx->base.tb->cs_base; 4454 uint64_t iasq_f = cs_base & ~0xffffffffull; 4455 int32_t diff = cs_base; 4456 4457 ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4458 ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); 4459 #endif 4460 ctx->iaoq_n = -1; 4461 ctx->iaoq_n_var = NULL; 4462 4463 ctx->zero = tcg_constant_i64(0); 4464 4465 /* Bound the number of instructions by those left on the page. */ 4466 bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4467 ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 4468 } 4469 4470 static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 4471 { 4472 DisasContext *ctx = container_of(dcbase, DisasContext, base); 4473 4474 /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 4475 ctx->null_cond = cond_make_f(); 4476 ctx->psw_n_nonzero = false; 4477 if (ctx->tb_flags & PSW_N) { 4478 ctx->null_cond.c = TCG_COND_ALWAYS; 4479 ctx->psw_n_nonzero = true; 4480 } 4481 ctx->null_lab = NULL; 4482 } 4483 4484 static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 4485 { 4486 DisasContext *ctx = container_of(dcbase, DisasContext, base); 4487 4488 tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0); 4489 ctx->insn_start = tcg_last_op(); 4490 } 4491 4492 static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 4493 { 4494 DisasContext *ctx = container_of(dcbase, DisasContext, base); 4495 CPUHPPAState *env = cpu_env(cs); 4496 DisasJumpType ret; 4497 4498 /* Execute one insn. */ 4499 #ifdef CONFIG_USER_ONLY 4500 if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 4501 do_page_zero(ctx); 4502 ret = ctx->base.is_jmp; 4503 assert(ret != DISAS_NEXT); 4504 } else 4505 #endif 4506 { 4507 /* Always fetch the insn, even if nullified, so that we check 4508 the page permissions for execute. */ 4509 uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 4510 4511 /* Set up the IA queue for the next insn. 4512 This will be overwritten by a branch. */ 4513 if (ctx->iaoq_b == -1) { 4514 ctx->iaoq_n = -1; 4515 ctx->iaoq_n_var = tcg_temp_new_i64(); 4516 tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 4517 } else { 4518 ctx->iaoq_n = ctx->iaoq_b + 4; 4519 ctx->iaoq_n_var = NULL; 4520 } 4521 4522 if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 4523 ctx->null_cond.c = TCG_COND_NEVER; 4524 ret = DISAS_NEXT; 4525 } else { 4526 ctx->insn = insn; 4527 if (!decode(ctx, insn)) { 4528 gen_illegal(ctx); 4529 } 4530 ret = ctx->base.is_jmp; 4531 assert(ctx->null_lab == NULL); 4532 } 4533 } 4534 4535 /* Advance the insn queue. Note that this check also detects 4536 a priority change within the instruction queue. */ 4537 if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 4538 if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 4539 && use_goto_tb(ctx, ctx->iaoq_b) 4540 && (ctx->null_cond.c == TCG_COND_NEVER 4541 || ctx->null_cond.c == TCG_COND_ALWAYS)) { 4542 nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 4543 gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 4544 ctx->base.is_jmp = ret = DISAS_NORETURN; 4545 } else { 4546 ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE; 4547 } 4548 } 4549 ctx->iaoq_f = ctx->iaoq_b; 4550 ctx->iaoq_b = ctx->iaoq_n; 4551 ctx->base.pc_next += 4; 4552 4553 switch (ret) { 4554 case DISAS_NORETURN: 4555 case DISAS_IAQ_N_UPDATED: 4556 break; 4557 4558 case DISAS_NEXT: 4559 case DISAS_IAQ_N_STALE: 4560 case DISAS_IAQ_N_STALE_EXIT: 4561 if (ctx->iaoq_f == -1) { 4562 copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b); 4563 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 4564 #ifndef CONFIG_USER_ONLY 4565 tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 4566 #endif 4567 nullify_save(ctx); 4568 ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT 4569 ? DISAS_EXIT 4570 : DISAS_IAQ_N_UPDATED); 4571 } else if (ctx->iaoq_b == -1) { 4572 copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var); 4573 } 4574 break; 4575 4576 default: 4577 g_assert_not_reached(); 4578 } 4579 } 4580 4581 static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 4582 { 4583 DisasContext *ctx = container_of(dcbase, DisasContext, base); 4584 DisasJumpType is_jmp = ctx->base.is_jmp; 4585 4586 switch (is_jmp) { 4587 case DISAS_NORETURN: 4588 break; 4589 case DISAS_TOO_MANY: 4590 case DISAS_IAQ_N_STALE: 4591 case DISAS_IAQ_N_STALE_EXIT: 4592 copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 4593 copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 4594 nullify_save(ctx); 4595 /* FALLTHRU */ 4596 case DISAS_IAQ_N_UPDATED: 4597 if (is_jmp != DISAS_IAQ_N_STALE_EXIT) { 4598 tcg_gen_lookup_and_goto_ptr(); 4599 break; 4600 } 4601 /* FALLTHRU */ 4602 case DISAS_EXIT: 4603 tcg_gen_exit_tb(NULL, 0); 4604 break; 4605 default: 4606 g_assert_not_reached(); 4607 } 4608 } 4609 4610 static void hppa_tr_disas_log(const DisasContextBase *dcbase, 4611 CPUState *cs, FILE *logfile) 4612 { 4613 target_ulong pc = dcbase->pc_first; 4614 4615 #ifdef CONFIG_USER_ONLY 4616 switch (pc) { 4617 case 0x00: 4618 fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4619 return; 4620 case 0xb0: 4621 fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4622 return; 4623 case 0xe0: 4624 fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4625 return; 4626 case 0x100: 4627 fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4628 return; 4629 } 4630 #endif 4631 4632 fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 4633 target_disas(logfile, cs, pc, dcbase->tb->size); 4634 } 4635 4636 static const TranslatorOps hppa_tr_ops = { 4637 .init_disas_context = hppa_tr_init_disas_context, 4638 .tb_start = hppa_tr_tb_start, 4639 .insn_start = hppa_tr_insn_start, 4640 .translate_insn = hppa_tr_translate_insn, 4641 .tb_stop = hppa_tr_tb_stop, 4642 .disas_log = hppa_tr_disas_log, 4643 }; 4644 4645 void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 4646 vaddr pc, void *host_pc) 4647 { 4648 DisasContext ctx; 4649 translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 4650 } 4651