1 /* 2 * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "qemu/osdep.h" 19 #include "cpu.h" 20 #include "internal.h" 21 #include "tcg/tcg-op.h" 22 #include "tcg/tcg-op-gvec.h" 23 #include "insn.h" 24 #include "opcodes.h" 25 #include "translate.h" 26 #define QEMU_GENERATE /* Used internally by macros.h */ 27 #include "macros.h" 28 #include "mmvec/macros.h" 29 #undef QEMU_GENERATE 30 #include "gen_tcg.h" 31 #include "gen_tcg_hvx.h" 32 #include "genptr.h" 33 34 TCGv gen_read_reg(TCGv result, int num) 35 { 36 tcg_gen_mov_tl(result, hex_gpr[num]); 37 return result; 38 } 39 40 TCGv gen_read_preg(TCGv pred, uint8_t num) 41 { 42 tcg_gen_mov_tl(pred, hex_pred[num]); 43 return pred; 44 } 45 46 #define IMMUTABLE (~0) 47 48 const target_ulong reg_immut_masks[TOTAL_PER_THREAD_REGS] = { 49 [HEX_REG_USR] = 0xc13000c0, 50 [HEX_REG_PC] = IMMUTABLE, 51 [HEX_REG_GP] = 0x3f, 52 [HEX_REG_UPCYCLELO] = IMMUTABLE, 53 [HEX_REG_UPCYCLEHI] = IMMUTABLE, 54 [HEX_REG_UTIMERLO] = IMMUTABLE, 55 [HEX_REG_UTIMERHI] = IMMUTABLE, 56 }; 57 58 static inline void gen_masked_reg_write(TCGv new_val, TCGv cur_val, 59 target_ulong reg_mask) 60 { 61 if (reg_mask) { 62 TCGv tmp = tcg_temp_new(); 63 64 /* new_val = (new_val & ~reg_mask) | (cur_val & reg_mask) */ 65 tcg_gen_andi_tl(new_val, new_val, ~reg_mask); 66 tcg_gen_andi_tl(tmp, cur_val, reg_mask); 67 tcg_gen_or_tl(new_val, new_val, tmp); 68 } 69 } 70 71 TCGv get_result_gpr(DisasContext *ctx, int rnum) 72 { 73 if (ctx->need_commit) { 74 if (rnum == HEX_REG_USR) { 75 return hex_new_value_usr; 76 } else { 77 if (ctx->new_value[rnum] == NULL) { 78 ctx->new_value[rnum] = tcg_temp_new(); 79 tcg_gen_movi_tl(ctx->new_value[rnum], 0); 80 } 81 return ctx->new_value[rnum]; 82 } 83 } else { 84 return hex_gpr[rnum]; 85 } 86 } 87 88 static TCGv_i64 get_result_gpr_pair(DisasContext *ctx, int rnum) 89 { 90 TCGv_i64 result = tcg_temp_new_i64(); 91 tcg_gen_concat_i32_i64(result, get_result_gpr(ctx, rnum), 92 get_result_gpr(ctx, rnum + 1)); 93 return result; 94 } 95 96 void gen_log_reg_write(DisasContext *ctx, int rnum, TCGv val) 97 { 98 const target_ulong reg_mask = reg_immut_masks[rnum]; 99 100 gen_masked_reg_write(val, hex_gpr[rnum], reg_mask); 101 tcg_gen_mov_tl(get_result_gpr(ctx, rnum), val); 102 if (HEX_DEBUG) { 103 /* Do this so HELPER(debug_commit_end) will know */ 104 tcg_gen_movi_tl(hex_reg_written[rnum], 1); 105 } 106 } 107 108 static void gen_log_reg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val) 109 { 110 TCGv val32 = tcg_temp_new(); 111 112 /* Low word */ 113 tcg_gen_extrl_i64_i32(val32, val); 114 gen_log_reg_write(ctx, rnum, val32); 115 116 /* High word */ 117 tcg_gen_extrh_i64_i32(val32, val); 118 gen_log_reg_write(ctx, rnum + 1, val32); 119 } 120 121 TCGv get_result_pred(DisasContext *ctx, int pnum) 122 { 123 if (ctx->need_commit) { 124 if (ctx->new_pred_value[pnum] == NULL) { 125 ctx->new_pred_value[pnum] = tcg_temp_new(); 126 tcg_gen_movi_tl(ctx->new_pred_value[pnum], 0); 127 } 128 return ctx->new_pred_value[pnum]; 129 } else { 130 return hex_pred[pnum]; 131 } 132 } 133 134 void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val) 135 { 136 TCGv pred = get_result_pred(ctx, pnum); 137 TCGv base_val = tcg_temp_new(); 138 139 tcg_gen_andi_tl(base_val, val, 0xff); 140 141 /* 142 * Section 6.1.3 of the Hexagon V67 Programmer's Reference Manual 143 * 144 * Multiple writes to the same preg are and'ed together 145 * If this is the first predicate write in the packet, do a 146 * straight assignment. Otherwise, do an and. 147 */ 148 if (!test_bit(pnum, ctx->pregs_written)) { 149 tcg_gen_mov_tl(pred, base_val); 150 } else { 151 tcg_gen_and_tl(pred, pred, base_val); 152 } 153 if (HEX_DEBUG) { 154 tcg_gen_ori_tl(ctx->pred_written, ctx->pred_written, 1 << pnum); 155 } 156 set_bit(pnum, ctx->pregs_written); 157 } 158 159 static inline void gen_read_p3_0(TCGv control_reg) 160 { 161 tcg_gen_movi_tl(control_reg, 0); 162 for (int i = 0; i < NUM_PREGS; i++) { 163 tcg_gen_deposit_tl(control_reg, control_reg, hex_pred[i], i * 8, 8); 164 } 165 } 166 167 /* 168 * Certain control registers require special handling on read 169 * HEX_REG_P3_0_ALIASED aliased to the predicate registers 170 * -> concat the 4 predicate registers together 171 * HEX_REG_PC actual value stored in DisasContext 172 * -> assign from ctx->base.pc_next 173 * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext 174 * -> add current TB changes to existing reg value 175 */ 176 static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num, 177 TCGv dest) 178 { 179 if (reg_num == HEX_REG_P3_0_ALIASED) { 180 gen_read_p3_0(dest); 181 } else if (reg_num == HEX_REG_PC) { 182 tcg_gen_movi_tl(dest, ctx->base.pc_next); 183 } else if (reg_num == HEX_REG_QEMU_PKT_CNT) { 184 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_PKT_CNT], 185 ctx->num_packets); 186 } else if (reg_num == HEX_REG_QEMU_INSN_CNT) { 187 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_INSN_CNT], 188 ctx->num_insns); 189 } else if (reg_num == HEX_REG_QEMU_HVX_CNT) { 190 tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT], 191 ctx->num_hvx_insns); 192 } else { 193 tcg_gen_mov_tl(dest, hex_gpr[reg_num]); 194 } 195 } 196 197 static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num, 198 TCGv_i64 dest) 199 { 200 if (reg_num == HEX_REG_P3_0_ALIASED) { 201 TCGv p3_0 = tcg_temp_new(); 202 gen_read_p3_0(p3_0); 203 tcg_gen_concat_i32_i64(dest, p3_0, hex_gpr[reg_num + 1]); 204 } else if (reg_num == HEX_REG_PC - 1) { 205 TCGv pc = tcg_constant_tl(ctx->base.pc_next); 206 tcg_gen_concat_i32_i64(dest, hex_gpr[reg_num], pc); 207 } else if (reg_num == HEX_REG_QEMU_PKT_CNT) { 208 TCGv pkt_cnt = tcg_temp_new(); 209 TCGv insn_cnt = tcg_temp_new(); 210 tcg_gen_addi_tl(pkt_cnt, hex_gpr[HEX_REG_QEMU_PKT_CNT], 211 ctx->num_packets); 212 tcg_gen_addi_tl(insn_cnt, hex_gpr[HEX_REG_QEMU_INSN_CNT], 213 ctx->num_insns); 214 tcg_gen_concat_i32_i64(dest, pkt_cnt, insn_cnt); 215 } else if (reg_num == HEX_REG_QEMU_HVX_CNT) { 216 TCGv hvx_cnt = tcg_temp_new(); 217 tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT], 218 ctx->num_hvx_insns); 219 tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]); 220 } else { 221 tcg_gen_concat_i32_i64(dest, 222 hex_gpr[reg_num], 223 hex_gpr[reg_num + 1]); 224 } 225 } 226 227 static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg) 228 { 229 TCGv hex_p8 = tcg_temp_new(); 230 for (int i = 0; i < NUM_PREGS; i++) { 231 tcg_gen_extract_tl(hex_p8, control_reg, i * 8, 8); 232 gen_log_pred_write(ctx, i, hex_p8); 233 } 234 } 235 236 /* 237 * Certain control registers require special handling on write 238 * HEX_REG_P3_0_ALIASED aliased to the predicate registers 239 * -> break the value across 4 predicate registers 240 * HEX_REG_QEMU_*_CNT changes in current TB in DisasContext 241 * -> clear the changes 242 */ 243 static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num, 244 TCGv val) 245 { 246 if (reg_num == HEX_REG_P3_0_ALIASED) { 247 gen_write_p3_0(ctx, val); 248 } else { 249 gen_log_reg_write(ctx, reg_num, val); 250 if (reg_num == HEX_REG_QEMU_PKT_CNT) { 251 ctx->num_packets = 0; 252 } 253 if (reg_num == HEX_REG_QEMU_INSN_CNT) { 254 ctx->num_insns = 0; 255 } 256 if (reg_num == HEX_REG_QEMU_HVX_CNT) { 257 ctx->num_hvx_insns = 0; 258 } 259 } 260 } 261 262 static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num, 263 TCGv_i64 val) 264 { 265 if (reg_num == HEX_REG_P3_0_ALIASED) { 266 TCGv result = get_result_gpr(ctx, reg_num + 1); 267 TCGv val32 = tcg_temp_new(); 268 tcg_gen_extrl_i64_i32(val32, val); 269 gen_write_p3_0(ctx, val32); 270 tcg_gen_extrh_i64_i32(val32, val); 271 tcg_gen_mov_tl(result, val32); 272 } else { 273 gen_log_reg_write_pair(ctx, reg_num, val); 274 if (reg_num == HEX_REG_QEMU_PKT_CNT) { 275 ctx->num_packets = 0; 276 ctx->num_insns = 0; 277 } 278 if (reg_num == HEX_REG_QEMU_HVX_CNT) { 279 ctx->num_hvx_insns = 0; 280 } 281 } 282 } 283 284 TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign) 285 { 286 if (sign) { 287 tcg_gen_sextract_tl(result, src, N * 8, 8); 288 } else { 289 tcg_gen_extract_tl(result, src, N * 8, 8); 290 } 291 return result; 292 } 293 294 TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign) 295 { 296 TCGv_i64 res64 = tcg_temp_new_i64(); 297 if (sign) { 298 tcg_gen_sextract_i64(res64, src, N * 8, 8); 299 } else { 300 tcg_gen_extract_i64(res64, src, N * 8, 8); 301 } 302 tcg_gen_extrl_i64_i32(result, res64); 303 304 return result; 305 } 306 307 TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign) 308 { 309 if (sign) { 310 tcg_gen_sextract_tl(result, src, N * 16, 16); 311 } else { 312 tcg_gen_extract_tl(result, src, N * 16, 16); 313 } 314 return result; 315 } 316 317 void gen_set_half(int N, TCGv result, TCGv src) 318 { 319 tcg_gen_deposit_tl(result, result, src, N * 16, 16); 320 } 321 322 void gen_set_half_i64(int N, TCGv_i64 result, TCGv src) 323 { 324 TCGv_i64 src64 = tcg_temp_new_i64(); 325 tcg_gen_extu_i32_i64(src64, src); 326 tcg_gen_deposit_i64(result, result, src64, N * 16, 16); 327 } 328 329 void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) 330 { 331 TCGv_i64 src64 = tcg_temp_new_i64(); 332 tcg_gen_extu_i32_i64(src64, src); 333 tcg_gen_deposit_i64(result, result, src64, N * 8, 8); 334 } 335 336 static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index) 337 { 338 tcg_gen_qemu_ld_tl(dest, vaddr, mem_index, MO_TEUL); 339 tcg_gen_mov_tl(hex_llsc_addr, vaddr); 340 tcg_gen_mov_tl(hex_llsc_val, dest); 341 } 342 343 static inline void gen_load_locked8u(TCGv_i64 dest, TCGv vaddr, int mem_index) 344 { 345 tcg_gen_qemu_ld_i64(dest, vaddr, mem_index, MO_TEUQ); 346 tcg_gen_mov_tl(hex_llsc_addr, vaddr); 347 tcg_gen_mov_i64(hex_llsc_val_i64, dest); 348 } 349 350 static inline void gen_store_conditional4(DisasContext *ctx, 351 TCGv pred, TCGv vaddr, TCGv src) 352 { 353 TCGLabel *fail = gen_new_label(); 354 TCGLabel *done = gen_new_label(); 355 TCGv one, zero, tmp; 356 357 tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail); 358 359 one = tcg_constant_tl(0xff); 360 zero = tcg_constant_tl(0); 361 tmp = tcg_temp_new(); 362 tcg_gen_atomic_cmpxchg_tl(tmp, hex_llsc_addr, hex_llsc_val, src, 363 ctx->mem_idx, MO_32); 364 tcg_gen_movcond_tl(TCG_COND_EQ, pred, tmp, hex_llsc_val, 365 one, zero); 366 tcg_gen_br(done); 367 368 gen_set_label(fail); 369 tcg_gen_movi_tl(pred, 0); 370 371 gen_set_label(done); 372 tcg_gen_movi_tl(hex_llsc_addr, ~0); 373 } 374 375 static inline void gen_store_conditional8(DisasContext *ctx, 376 TCGv pred, TCGv vaddr, TCGv_i64 src) 377 { 378 TCGLabel *fail = gen_new_label(); 379 TCGLabel *done = gen_new_label(); 380 TCGv_i64 one, zero, tmp; 381 382 tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail); 383 384 one = tcg_constant_i64(0xff); 385 zero = tcg_constant_i64(0); 386 tmp = tcg_temp_new_i64(); 387 tcg_gen_atomic_cmpxchg_i64(tmp, hex_llsc_addr, hex_llsc_val_i64, src, 388 ctx->mem_idx, MO_64); 389 tcg_gen_movcond_i64(TCG_COND_EQ, tmp, tmp, hex_llsc_val_i64, 390 one, zero); 391 tcg_gen_extrl_i64_i32(pred, tmp); 392 tcg_gen_br(done); 393 394 gen_set_label(fail); 395 tcg_gen_movi_tl(pred, 0); 396 397 gen_set_label(done); 398 tcg_gen_movi_tl(hex_llsc_addr, ~0); 399 } 400 401 #ifndef CONFIG_HEXAGON_IDEF_PARSER 402 static TCGv gen_slotval(DisasContext *ctx) 403 { 404 int slotval = (ctx->pkt->pkt_has_store_s1 & 1) | (ctx->insn->slot << 1); 405 return tcg_constant_tl(slotval); 406 } 407 #endif 408 409 void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot) 410 { 411 tcg_gen_mov_tl(hex_store_addr[slot], vaddr); 412 tcg_gen_movi_tl(hex_store_width[slot], width); 413 tcg_gen_mov_tl(hex_store_val32[slot], src); 414 } 415 416 void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) 417 { 418 gen_store32(vaddr, src, 1, slot); 419 } 420 421 void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) 422 { 423 TCGv tmp = tcg_constant_tl(src); 424 gen_store1(cpu_env, vaddr, tmp, slot); 425 } 426 427 void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) 428 { 429 gen_store32(vaddr, src, 2, slot); 430 } 431 432 void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) 433 { 434 TCGv tmp = tcg_constant_tl(src); 435 gen_store2(cpu_env, vaddr, tmp, slot); 436 } 437 438 void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot) 439 { 440 gen_store32(vaddr, src, 4, slot); 441 } 442 443 void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot) 444 { 445 TCGv tmp = tcg_constant_tl(src); 446 gen_store4(cpu_env, vaddr, tmp, slot); 447 } 448 449 void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, uint32_t slot) 450 { 451 tcg_gen_mov_tl(hex_store_addr[slot], vaddr); 452 tcg_gen_movi_tl(hex_store_width[slot], 8); 453 tcg_gen_mov_i64(hex_store_val64[slot], src); 454 } 455 456 void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot) 457 { 458 TCGv_i64 tmp = tcg_constant_i64(src); 459 gen_store8(cpu_env, vaddr, tmp, slot); 460 } 461 462 TCGv gen_8bitsof(TCGv result, TCGv value) 463 { 464 TCGv zero = tcg_constant_tl(0); 465 TCGv ones = tcg_constant_tl(0xff); 466 tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero); 467 468 return result; 469 } 470 471 static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr, 472 TCGCond cond, TCGv pred) 473 { 474 TCGLabel *pred_false = NULL; 475 if (cond != TCG_COND_ALWAYS) { 476 pred_false = gen_new_label(); 477 tcg_gen_brcondi_tl(cond, pred, 0, pred_false); 478 } 479 480 if (ctx->pkt->pkt_has_multi_cof) { 481 /* If there are multiple branches in a packet, ignore the second one */ 482 tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC], 483 ctx->branch_taken, tcg_constant_tl(0), 484 hex_gpr[HEX_REG_PC], addr); 485 tcg_gen_movi_tl(ctx->branch_taken, 1); 486 } else { 487 tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr); 488 } 489 490 if (cond != TCG_COND_ALWAYS) { 491 gen_set_label(pred_false); 492 } 493 } 494 495 static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off, 496 TCGCond cond, TCGv pred) 497 { 498 target_ulong dest = ctx->pkt->pc + pc_off; 499 if (ctx->pkt->pkt_has_multi_cof) { 500 gen_write_new_pc_addr(ctx, tcg_constant_tl(dest), cond, pred); 501 } else { 502 /* Defer this jump to the end of the TB */ 503 ctx->branch_cond = TCG_COND_ALWAYS; 504 if (pred != NULL) { 505 ctx->branch_cond = cond; 506 tcg_gen_mov_tl(ctx->branch_taken, pred); 507 } 508 ctx->branch_dest = dest; 509 } 510 } 511 512 void gen_set_usr_field(DisasContext *ctx, int field, TCGv val) 513 { 514 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 515 tcg_gen_deposit_tl(usr, usr, val, 516 reg_field_info[field].offset, 517 reg_field_info[field].width); 518 } 519 520 void gen_set_usr_fieldi(DisasContext *ctx, int field, int x) 521 { 522 if (reg_field_info[field].width == 1) { 523 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 524 target_ulong bit = 1 << reg_field_info[field].offset; 525 if ((x & 1) == 1) { 526 tcg_gen_ori_tl(usr, usr, bit); 527 } else { 528 tcg_gen_andi_tl(usr, usr, ~bit); 529 } 530 } else { 531 TCGv val = tcg_constant_tl(x); 532 gen_set_usr_field(ctx, field, val); 533 } 534 } 535 536 static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2) 537 { 538 TCGv one = tcg_constant_tl(0xff); 539 TCGv zero = tcg_constant_tl(0); 540 541 tcg_gen_movcond_tl(cond, res, arg1, arg2, one, zero); 542 } 543 544 #ifndef CONFIG_HEXAGON_IDEF_PARSER 545 static inline void gen_loop0r(DisasContext *ctx, TCGv RsV, int riV) 546 { 547 fIMMEXT(riV); 548 fPCALIGN(riV); 549 gen_log_reg_write(ctx, HEX_REG_LC0, RsV); 550 gen_log_reg_write(ctx, HEX_REG_SA0, tcg_constant_tl(ctx->pkt->pc + riV)); 551 gen_set_usr_fieldi(ctx, USR_LPCFG, 0); 552 } 553 554 static void gen_loop0i(DisasContext *ctx, int count, int riV) 555 { 556 gen_loop0r(ctx, tcg_constant_tl(count), riV); 557 } 558 559 static inline void gen_loop1r(DisasContext *ctx, TCGv RsV, int riV) 560 { 561 fIMMEXT(riV); 562 fPCALIGN(riV); 563 gen_log_reg_write(ctx, HEX_REG_LC1, RsV); 564 gen_log_reg_write(ctx, HEX_REG_SA1, tcg_constant_tl(ctx->pkt->pc + riV)); 565 } 566 567 static void gen_loop1i(DisasContext *ctx, int count, int riV) 568 { 569 gen_loop1r(ctx, tcg_constant_tl(count), riV); 570 } 571 572 static void gen_ploopNsr(DisasContext *ctx, int N, TCGv RsV, int riV) 573 { 574 fIMMEXT(riV); 575 fPCALIGN(riV); 576 gen_log_reg_write(ctx, HEX_REG_LC0, RsV); 577 gen_log_reg_write(ctx, HEX_REG_SA0, tcg_constant_tl(ctx->pkt->pc + riV)); 578 gen_set_usr_fieldi(ctx, USR_LPCFG, N); 579 gen_log_pred_write(ctx, 3, tcg_constant_tl(0)); 580 } 581 582 static void gen_ploopNsi(DisasContext *ctx, int N, int count, int riV) 583 { 584 gen_ploopNsr(ctx, N, tcg_constant_tl(count), riV); 585 } 586 587 static inline void gen_comparei(TCGCond cond, TCGv res, TCGv arg1, int arg2) 588 { 589 gen_compare(cond, res, arg1, tcg_constant_tl(arg2)); 590 } 591 #endif 592 593 static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc, 594 TCGCond cond, TCGv pred) 595 { 596 gen_write_new_pc_addr(ctx, dst_pc, cond, pred); 597 } 598 599 static void gen_cond_jumpr31(DisasContext *ctx, TCGCond cond, TCGv pred) 600 { 601 TCGv LSB = tcg_temp_new(); 602 tcg_gen_andi_tl(LSB, pred, 1); 603 gen_cond_jumpr(ctx, hex_gpr[HEX_REG_LR], cond, LSB); 604 } 605 606 static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred, 607 int pc_off) 608 { 609 gen_write_new_pc_pcrel(ctx, pc_off, cond, pred); 610 } 611 612 static void gen_cmpnd_cmp_jmp(DisasContext *ctx, 613 int pnum, TCGCond cond1, TCGv arg1, TCGv arg2, 614 TCGCond cond2, int pc_off) 615 { 616 if (ctx->insn->part1) { 617 TCGv pred = tcg_temp_new(); 618 gen_compare(cond1, pred, arg1, arg2); 619 gen_log_pred_write(ctx, pnum, pred); 620 } else { 621 TCGv pred = tcg_temp_new(); 622 tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]); 623 gen_cond_jump(ctx, cond2, pred, pc_off); 624 } 625 } 626 627 static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx, 628 int pnum, TCGCond cond, TCGv arg1, TCGv arg2, 629 int pc_off) 630 { 631 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_EQ, pc_off); 632 } 633 634 static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx, 635 int pnum, TCGCond cond, TCGv arg1, TCGv arg2, 636 int pc_off) 637 { 638 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_NE, pc_off); 639 } 640 641 static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx, 642 int pnum, TCGCond cond, TCGv arg1, int arg2, 643 int pc_off) 644 { 645 TCGv tmp = tcg_constant_tl(arg2); 646 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_EQ, pc_off); 647 } 648 649 static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx, 650 int pnum, TCGCond cond, TCGv arg1, int arg2, 651 int pc_off) 652 { 653 TCGv tmp = tcg_constant_tl(arg2); 654 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_NE, pc_off); 655 } 656 657 static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond, 658 TCGv arg, int pc_off) 659 { 660 gen_cmpnd_cmpi_jmp_t(ctx, pnum, cond, arg, -1, pc_off); 661 } 662 663 static void gen_cmpnd_cmp_n1_jmp_f(DisasContext *ctx, int pnum, TCGCond cond, 664 TCGv arg, int pc_off) 665 { 666 gen_cmpnd_cmpi_jmp_f(ctx, pnum, cond, arg, -1, pc_off); 667 } 668 669 static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx, 670 int pnum, TCGv arg, TCGCond cond, int pc_off) 671 { 672 if (ctx->insn->part1) { 673 TCGv pred = tcg_temp_new(); 674 tcg_gen_andi_tl(pred, arg, 1); 675 gen_8bitsof(pred, pred); 676 gen_log_pred_write(ctx, pnum, pred); 677 } else { 678 TCGv pred = tcg_temp_new(); 679 tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]); 680 gen_cond_jump(ctx, cond, pred, pc_off); 681 } 682 } 683 684 static void gen_testbit0_jumpnv(DisasContext *ctx, 685 TCGv arg, TCGCond cond, int pc_off) 686 { 687 TCGv pred = tcg_temp_new(); 688 tcg_gen_andi_tl(pred, arg, 1); 689 gen_cond_jump(ctx, cond, pred, pc_off); 690 } 691 692 static void gen_jump(DisasContext *ctx, int pc_off) 693 { 694 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL); 695 } 696 697 static void gen_jumpr(DisasContext *ctx, TCGv new_pc) 698 { 699 gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL); 700 } 701 702 static void gen_call(DisasContext *ctx, int pc_off) 703 { 704 TCGv lr = get_result_gpr(ctx, HEX_REG_LR); 705 tcg_gen_movi_tl(lr, ctx->next_PC); 706 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL); 707 } 708 709 static void gen_callr(DisasContext *ctx, TCGv new_pc) 710 { 711 TCGv lr = get_result_gpr(ctx, HEX_REG_LR); 712 tcg_gen_movi_tl(lr, ctx->next_PC); 713 gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL); 714 } 715 716 static void gen_cond_call(DisasContext *ctx, TCGv pred, 717 TCGCond cond, int pc_off) 718 { 719 TCGv lr = get_result_gpr(ctx, HEX_REG_LR); 720 TCGv lsb = tcg_temp_new(); 721 TCGLabel *skip = gen_new_label(); 722 tcg_gen_andi_tl(lsb, pred, 1); 723 gen_write_new_pc_pcrel(ctx, pc_off, cond, lsb); 724 tcg_gen_brcondi_tl(cond, lsb, 0, skip); 725 tcg_gen_movi_tl(lr, ctx->next_PC); 726 gen_set_label(skip); 727 } 728 729 static void gen_cond_callr(DisasContext *ctx, 730 TCGCond cond, TCGv pred, TCGv new_pc) 731 { 732 TCGv lsb = tcg_temp_new(); 733 TCGLabel *skip = gen_new_label(); 734 tcg_gen_andi_tl(lsb, pred, 1); 735 tcg_gen_brcondi_tl(cond, lsb, 0, skip); 736 gen_callr(ctx, new_pc); 737 gen_set_label(skip); 738 } 739 740 #ifndef CONFIG_HEXAGON_IDEF_PARSER 741 /* frame = ((LR << 32) | FP) ^ (FRAMEKEY << 32)) */ 742 static TCGv_i64 gen_frame_scramble(void) 743 { 744 TCGv_i64 frame = tcg_temp_new_i64(); 745 TCGv tmp = tcg_temp_new(); 746 tcg_gen_xor_tl(tmp, hex_gpr[HEX_REG_LR], hex_gpr[HEX_REG_FRAMEKEY]); 747 tcg_gen_concat_i32_i64(frame, hex_gpr[HEX_REG_FP], tmp); 748 return frame; 749 } 750 #endif 751 752 /* frame ^= (int64_t)FRAMEKEY << 32 */ 753 static void gen_frame_unscramble(TCGv_i64 frame) 754 { 755 TCGv_i64 framekey = tcg_temp_new_i64(); 756 tcg_gen_extu_i32_i64(framekey, hex_gpr[HEX_REG_FRAMEKEY]); 757 tcg_gen_shli_i64(framekey, framekey, 32); 758 tcg_gen_xor_i64(frame, frame, framekey); 759 } 760 761 static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA) 762 { 763 Insn *insn = ctx->insn; /* Needed for CHECK_NOSHUF */ 764 CHECK_NOSHUF(EA, 8); 765 tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_TEUQ); 766 } 767 768 #ifndef CONFIG_HEXAGON_IDEF_PARSER 769 /* Stack overflow check */ 770 static void gen_framecheck(TCGv EA, int framesize) 771 { 772 /* Not modelled in linux-user mode */ 773 /* Placeholder for system mode */ 774 #ifndef CONFIG_USER_ONLY 775 g_assert_not_reached(); 776 #endif 777 } 778 779 static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize) 780 { 781 TCGv r30 = tcg_temp_new(); 782 TCGv_i64 frame; 783 tcg_gen_addi_tl(r30, r29, -8); 784 frame = gen_frame_scramble(); 785 gen_store8(cpu_env, r30, frame, ctx->insn->slot); 786 gen_log_reg_write(ctx, HEX_REG_FP, r30); 787 gen_framecheck(r30, framesize); 788 tcg_gen_subi_tl(r29, r30, framesize); 789 } 790 791 static void gen_deallocframe(DisasContext *ctx, TCGv_i64 r31_30, TCGv r30) 792 { 793 TCGv r29 = tcg_temp_new(); 794 TCGv_i64 frame = tcg_temp_new_i64(); 795 gen_load_frame(ctx, frame, r30); 796 gen_frame_unscramble(frame); 797 tcg_gen_mov_i64(r31_30, frame); 798 tcg_gen_addi_tl(r29, r30, 8); 799 gen_log_reg_write(ctx, HEX_REG_SP, r29); 800 } 801 #endif 802 803 static void gen_return(DisasContext *ctx, TCGv_i64 dst, TCGv src) 804 { 805 /* 806 * frame = *src 807 * dst = frame_unscramble(frame) 808 * SP = src + 8 809 * PC = dst.w[1] 810 */ 811 TCGv_i64 frame = tcg_temp_new_i64(); 812 TCGv r31 = tcg_temp_new(); 813 TCGv r29 = get_result_gpr(ctx, HEX_REG_SP); 814 815 gen_load_frame(ctx, frame, src); 816 gen_frame_unscramble(frame); 817 tcg_gen_mov_i64(dst, frame); 818 tcg_gen_addi_tl(r29, src, 8); 819 tcg_gen_extrh_i64_i32(r31, dst); 820 gen_jumpr(ctx, r31); 821 } 822 823 /* if (pred) dst = dealloc_return(src):raw */ 824 static void gen_cond_return(DisasContext *ctx, TCGv_i64 dst, TCGv src, 825 TCGv pred, TCGCond cond) 826 { 827 TCGv LSB = tcg_temp_new(); 828 TCGLabel *skip = gen_new_label(); 829 tcg_gen_andi_tl(LSB, pred, 1); 830 831 tcg_gen_brcondi_tl(cond, LSB, 0, skip); 832 gen_return(ctx, dst, src); 833 gen_set_label(skip); 834 } 835 836 /* sub-instruction version (no RddV, so handle it manually) */ 837 static void gen_cond_return_subinsn(DisasContext *ctx, TCGCond cond, TCGv pred) 838 { 839 TCGv_i64 RddV = get_result_gpr_pair(ctx, HEX_REG_FP); 840 gen_cond_return(ctx, RddV, hex_gpr[HEX_REG_FP], pred, cond); 841 gen_log_reg_write_pair(ctx, HEX_REG_FP, RddV); 842 } 843 844 static void gen_endloop0(DisasContext *ctx) 845 { 846 TCGv lpcfg = tcg_temp_new(); 847 848 GET_USR_FIELD(USR_LPCFG, lpcfg); 849 850 /* 851 * if (lpcfg == 1) { 852 * p3 = 0xff; 853 * } 854 */ 855 TCGLabel *label1 = gen_new_label(); 856 tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1); 857 { 858 gen_log_pred_write(ctx, 3, tcg_constant_tl(0xff)); 859 } 860 gen_set_label(label1); 861 862 /* 863 * if (lpcfg) { 864 * SET_USR_FIELD(USR_LPCFG, lpcfg - 1); 865 * } 866 */ 867 TCGLabel *label2 = gen_new_label(); 868 tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2); 869 { 870 tcg_gen_subi_tl(lpcfg, lpcfg, 1); 871 gen_set_usr_field(ctx, USR_LPCFG, lpcfg); 872 } 873 gen_set_label(label2); 874 875 /* 876 * If we're in a tight loop, we'll do this at the end of the TB to take 877 * advantage of direct block chaining. 878 */ 879 if (!ctx->is_tight_loop) { 880 /* 881 * if (LC0 > 1) { 882 * PC = SA0; 883 * LC0--; 884 * } 885 */ 886 TCGLabel *label3 = gen_new_label(); 887 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3); 888 { 889 TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0); 890 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]); 891 tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1); 892 } 893 gen_set_label(label3); 894 } 895 } 896 897 static void gen_endloop1(DisasContext *ctx) 898 { 899 /* 900 * if (LC1 > 1) { 901 * PC = SA1; 902 * LC1--; 903 * } 904 */ 905 TCGLabel *label = gen_new_label(); 906 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, label); 907 { 908 TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1); 909 gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]); 910 tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1); 911 } 912 gen_set_label(label); 913 } 914 915 static void gen_endloop01(DisasContext *ctx) 916 { 917 TCGv lpcfg = tcg_temp_new(); 918 TCGLabel *label1 = gen_new_label(); 919 TCGLabel *label2 = gen_new_label(); 920 TCGLabel *label3 = gen_new_label(); 921 TCGLabel *done = gen_new_label(); 922 923 GET_USR_FIELD(USR_LPCFG, lpcfg); 924 925 /* 926 * if (lpcfg == 1) { 927 * p3 = 0xff; 928 * } 929 */ 930 tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1); 931 { 932 gen_log_pred_write(ctx, 3, tcg_constant_tl(0xff)); 933 } 934 gen_set_label(label1); 935 936 /* 937 * if (lpcfg) { 938 * SET_USR_FIELD(USR_LPCFG, lpcfg - 1); 939 * } 940 */ 941 tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2); 942 { 943 tcg_gen_subi_tl(lpcfg, lpcfg, 1); 944 gen_set_usr_field(ctx, USR_LPCFG, lpcfg); 945 } 946 gen_set_label(label2); 947 948 /* 949 * if (LC0 > 1) { 950 * PC = SA0; 951 * LC0--; 952 * } else if (LC1 > 1) { 953 * PC = SA1; 954 * LC1--; 955 * } 956 */ 957 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3); 958 { 959 TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0); 960 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]); 961 tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1); 962 tcg_gen_br(done); 963 } 964 gen_set_label(label3); 965 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, done); 966 { 967 TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1); 968 gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]); 969 tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1); 970 } 971 gen_set_label(done); 972 } 973 974 static void gen_cmp_jumpnv(DisasContext *ctx, 975 TCGCond cond, TCGv val, TCGv src, int pc_off) 976 { 977 TCGv pred = tcg_temp_new(); 978 tcg_gen_setcond_tl(cond, pred, val, src); 979 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); 980 } 981 982 static void gen_cmpi_jumpnv(DisasContext *ctx, 983 TCGCond cond, TCGv val, int src, int pc_off) 984 { 985 TCGv pred = tcg_temp_new(); 986 tcg_gen_setcondi_tl(cond, pred, val, src); 987 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); 988 } 989 990 /* Shift left with saturation */ 991 static void gen_shl_sat(DisasContext *ctx, TCGv dst, TCGv src, TCGv shift_amt) 992 { 993 TCGv tmp = tcg_temp_new(); /* In case dst == src */ 994 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 995 TCGv sh32 = tcg_temp_new(); 996 TCGv dst_sar = tcg_temp_new(); 997 TCGv ovf = tcg_temp_new(); 998 TCGv satval = tcg_temp_new(); 999 TCGv min = tcg_constant_tl(0x80000000); 1000 TCGv max = tcg_constant_tl(0x7fffffff); 1001 1002 /* 1003 * Possible values for shift_amt are 0 .. 64 1004 * We need special handling for values above 31 1005 * 1006 * sh32 = shift & 31; 1007 * dst = sh32 == shift ? src : 0; 1008 * dst <<= sh32; 1009 * dst_sar = dst >> sh32; 1010 * satval = src < 0 ? min : max; 1011 * if (dst_asr != src) { 1012 * usr.OVF |= 1; 1013 * dst = satval; 1014 * } 1015 */ 1016 1017 tcg_gen_andi_tl(sh32, shift_amt, 31); 1018 tcg_gen_movcond_tl(TCG_COND_EQ, tmp, sh32, shift_amt, 1019 src, tcg_constant_tl(0)); 1020 tcg_gen_shl_tl(tmp, tmp, sh32); 1021 tcg_gen_sar_tl(dst_sar, tmp, sh32); 1022 tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max); 1023 1024 tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src); 1025 tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset); 1026 tcg_gen_or_tl(usr, usr, ovf); 1027 1028 tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, tmp, satval); 1029 } 1030 1031 static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt) 1032 { 1033 /* 1034 * Shift arithmetic right 1035 * Robust when shift_amt is >31 bits 1036 */ 1037 TCGv tmp = tcg_temp_new(); 1038 tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31)); 1039 tcg_gen_sar_tl(dst, src, tmp); 1040 } 1041 1042 /* Bidirectional shift right with saturation */ 1043 static void gen_asr_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV) 1044 { 1045 TCGv shift_amt = tcg_temp_new(); 1046 TCGLabel *positive = gen_new_label(); 1047 TCGLabel *done = gen_new_label(); 1048 1049 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); 1050 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); 1051 1052 /* Negative shift amount => shift left */ 1053 tcg_gen_neg_tl(shift_amt, shift_amt); 1054 gen_shl_sat(ctx, RdV, RsV, shift_amt); 1055 tcg_gen_br(done); 1056 1057 gen_set_label(positive); 1058 /* Positive shift amount => shift right */ 1059 gen_sar(RdV, RsV, shift_amt); 1060 1061 gen_set_label(done); 1062 } 1063 1064 /* Bidirectional shift left with saturation */ 1065 static void gen_asl_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV) 1066 { 1067 TCGv shift_amt = tcg_temp_new(); 1068 TCGLabel *positive = gen_new_label(); 1069 TCGLabel *done = gen_new_label(); 1070 1071 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); 1072 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); 1073 1074 /* Negative shift amount => shift right */ 1075 tcg_gen_neg_tl(shift_amt, shift_amt); 1076 gen_sar(RdV, RsV, shift_amt); 1077 tcg_gen_br(done); 1078 1079 gen_set_label(positive); 1080 /* Positive shift amount => shift left */ 1081 gen_shl_sat(ctx, RdV, RsV, shift_amt); 1082 1083 gen_set_label(done); 1084 } 1085 1086 static void gen_insert_rp(DisasContext *ctx, TCGv RxV, TCGv RsV, TCGv_i64 RttV) 1087 { 1088 /* 1089 * int width = fZXTN(6, 32, (fGETWORD(1, RttV))); 1090 * int offset = fSXTN(7, 32, (fGETWORD(0, RttV))); 1091 * size8u_t mask = ((fCONSTLL(1) << width) - 1); 1092 * if (offset < 0) { 1093 * RxV = 0; 1094 * } else { 1095 * RxV &= ~(mask << offset); 1096 * RxV |= ((RsV & mask) << offset); 1097 * } 1098 */ 1099 1100 TCGv width = tcg_temp_new(); 1101 TCGv offset = tcg_temp_new(); 1102 TCGv_i64 mask = tcg_temp_new_i64(); 1103 TCGv_i64 result = tcg_temp_new_i64(); 1104 TCGv_i64 tmp = tcg_temp_new_i64(); 1105 TCGv_i64 offset64 = tcg_temp_new_i64(); 1106 TCGLabel *label = gen_new_label(); 1107 TCGLabel *done = gen_new_label(); 1108 1109 tcg_gen_extrh_i64_i32(width, RttV); 1110 tcg_gen_extract_tl(width, width, 0, 6); 1111 tcg_gen_extrl_i64_i32(offset, RttV); 1112 tcg_gen_sextract_tl(offset, offset, 0, 7); 1113 /* Possible values for offset are -64 .. 63 */ 1114 tcg_gen_brcondi_tl(TCG_COND_GE, offset, 0, label); 1115 /* For negative offsets, zero out the result */ 1116 tcg_gen_movi_tl(RxV, 0); 1117 tcg_gen_br(done); 1118 gen_set_label(label); 1119 /* At this point, possible values of offset are 0 .. 63 */ 1120 tcg_gen_ext_i32_i64(mask, width); 1121 tcg_gen_shl_i64(mask, tcg_constant_i64(1), mask); 1122 tcg_gen_subi_i64(mask, mask, 1); 1123 tcg_gen_extu_i32_i64(result, RxV); 1124 tcg_gen_ext_i32_i64(tmp, offset); 1125 tcg_gen_shl_i64(tmp, mask, tmp); 1126 tcg_gen_andc_i64(result, result, tmp); 1127 tcg_gen_extu_i32_i64(tmp, RsV); 1128 tcg_gen_and_i64(tmp, tmp, mask); 1129 tcg_gen_extu_i32_i64(offset64, offset); 1130 tcg_gen_shl_i64(tmp, tmp, offset64); 1131 tcg_gen_or_i64(result, result, tmp); 1132 tcg_gen_extrl_i64_i32(RxV, result); 1133 gen_set_label(done); 1134 } 1135 1136 static void gen_asr_r_svw_trun(DisasContext *ctx, TCGv RdV, 1137 TCGv_i64 RssV, TCGv RtV) 1138 { 1139 /* 1140 * for (int i = 0; i < 2; i++) { 1141 * fSETHALF(i, RdV, fGETHALF(0, ((fSXTN(7, 32, RtV) > 0) ? 1142 * (fCAST4_8s(fGETWORD(i, RssV)) >> fSXTN(7, 32, RtV)) : 1143 * (fCAST4_8s(fGETWORD(i, RssV)) << -fSXTN(7, 32, RtV))))); 1144 * } 1145 */ 1146 TCGv shift_amt32 = tcg_temp_new(); 1147 TCGv_i64 shift_amt64 = tcg_temp_new_i64(); 1148 TCGv_i64 tmp64 = tcg_temp_new_i64(); 1149 TCGv tmp32 = tcg_temp_new(); 1150 TCGLabel *label = gen_new_label(); 1151 TCGLabel *zero = gen_new_label(); 1152 TCGLabel *done = gen_new_label(); 1153 1154 tcg_gen_sextract_tl(shift_amt32, RtV, 0, 7); 1155 /* Possible values of shift_amt32 are -64 .. 63 */ 1156 tcg_gen_brcondi_tl(TCG_COND_LE, shift_amt32, 0, label); 1157 /* After branch, possible values of shift_amt32 are 1 .. 63 */ 1158 tcg_gen_ext_i32_i64(shift_amt64, shift_amt32); 1159 for (int i = 0; i < 2; i++) { 1160 tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32); 1161 tcg_gen_sar_i64(tmp64, tmp64, shift_amt64); 1162 tcg_gen_extrl_i64_i32(tmp32, tmp64); 1163 tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16); 1164 } 1165 tcg_gen_br(done); 1166 gen_set_label(label); 1167 tcg_gen_neg_tl(shift_amt32, shift_amt32); 1168 /*At this point, possible values of shift_amt32 are 0 .. 64 */ 1169 tcg_gen_brcondi_tl(TCG_COND_GT, shift_amt32, 63, zero); 1170 /*At this point, possible values of shift_amt32 are 0 .. 63 */ 1171 tcg_gen_ext_i32_i64(shift_amt64, shift_amt32); 1172 for (int i = 0; i < 2; i++) { 1173 tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32); 1174 tcg_gen_shl_i64(tmp64, tmp64, shift_amt64); 1175 tcg_gen_extrl_i64_i32(tmp32, tmp64); 1176 tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16); 1177 } 1178 tcg_gen_br(done); 1179 gen_set_label(zero); 1180 /* When the shift_amt is 64, zero out the result */ 1181 tcg_gen_movi_tl(RdV, 0); 1182 gen_set_label(done); 1183 } 1184 1185 static intptr_t vreg_src_off(DisasContext *ctx, int num) 1186 { 1187 intptr_t offset = offsetof(CPUHexagonState, VRegs[num]); 1188 1189 if (test_bit(num, ctx->vregs_select)) { 1190 offset = ctx_future_vreg_off(ctx, num, 1, false); 1191 } 1192 if (test_bit(num, ctx->vregs_updated_tmp)) { 1193 offset = ctx_tmp_vreg_off(ctx, num, 1, false); 1194 } 1195 return offset; 1196 } 1197 1198 static void gen_log_vreg_write(DisasContext *ctx, intptr_t srcoff, int num, 1199 VRegWriteType type) 1200 { 1201 intptr_t dstoff; 1202 1203 if (type != EXT_TMP) { 1204 dstoff = ctx_future_vreg_off(ctx, num, 1, true); 1205 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, 1206 sizeof(MMVector), sizeof(MMVector)); 1207 } else { 1208 dstoff = ctx_tmp_vreg_off(ctx, num, 1, false); 1209 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, 1210 sizeof(MMVector), sizeof(MMVector)); 1211 } 1212 } 1213 1214 static void gen_log_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num, 1215 VRegWriteType type) 1216 { 1217 gen_log_vreg_write(ctx, srcoff, num ^ 0, type); 1218 srcoff += sizeof(MMVector); 1219 gen_log_vreg_write(ctx, srcoff, num ^ 1, type); 1220 } 1221 1222 static intptr_t get_result_qreg(DisasContext *ctx, int qnum) 1223 { 1224 if (ctx->need_commit) { 1225 return offsetof(CPUHexagonState, future_QRegs[qnum]); 1226 } else { 1227 return offsetof(CPUHexagonState, QRegs[qnum]); 1228 } 1229 } 1230 1231 static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src, 1232 bool aligned) 1233 { 1234 TCGv_i64 tmp = tcg_temp_new_i64(); 1235 if (aligned) { 1236 tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1)); 1237 } 1238 for (int i = 0; i < sizeof(MMVector) / 8; i++) { 1239 tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_TEUQ); 1240 tcg_gen_addi_tl(src, src, 8); 1241 tcg_gen_st_i64(tmp, cpu_env, dstoff + i * 8); 1242 } 1243 } 1244 1245 static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, 1246 int slot, bool aligned) 1247 { 1248 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); 1249 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); 1250 1251 if (is_gather_store_insn(ctx)) { 1252 TCGv sl = tcg_constant_tl(slot); 1253 gen_helper_gather_store(cpu_env, EA, sl); 1254 return; 1255 } 1256 1257 tcg_gen_movi_tl(hex_vstore_pending[slot], 1); 1258 if (aligned) { 1259 tcg_gen_andi_tl(hex_vstore_addr[slot], EA, 1260 ~((int32_t)sizeof(MMVector) - 1)); 1261 } else { 1262 tcg_gen_mov_tl(hex_vstore_addr[slot], EA); 1263 } 1264 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector)); 1265 1266 /* Copy the data to the vstore buffer */ 1267 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector)); 1268 /* Set the mask to all 1's */ 1269 tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL); 1270 } 1271 1272 static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, 1273 intptr_t bitsoff, int slot, bool invert) 1274 { 1275 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); 1276 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); 1277 1278 tcg_gen_movi_tl(hex_vstore_pending[slot], 1); 1279 tcg_gen_andi_tl(hex_vstore_addr[slot], EA, 1280 ~((int32_t)sizeof(MMVector) - 1)); 1281 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector)); 1282 1283 /* Copy the data to the vstore buffer */ 1284 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector)); 1285 /* Copy the mask */ 1286 tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg)); 1287 if (invert) { 1288 tcg_gen_gvec_not(MO_64, maskoff, maskoff, 1289 sizeof(MMQReg), sizeof(MMQReg)); 1290 } 1291 } 1292 1293 static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff) 1294 { 1295 TCGv_i64 tmp = tcg_temp_new_i64(); 1296 TCGv_i64 word = tcg_temp_new_i64(); 1297 TCGv_i64 bits = tcg_temp_new_i64(); 1298 TCGv_i64 mask = tcg_temp_new_i64(); 1299 TCGv_i64 zero = tcg_constant_i64(0); 1300 TCGv_i64 ones = tcg_constant_i64(~0); 1301 1302 for (int i = 0; i < sizeof(MMVector) / 8; i++) { 1303 tcg_gen_ld_i64(tmp, cpu_env, srcoff + i * 8); 1304 tcg_gen_movi_i64(mask, 0); 1305 1306 for (int j = 0; j < 8; j += size) { 1307 tcg_gen_extract_i64(word, tmp, j * 8, size * 8); 1308 tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero); 1309 tcg_gen_deposit_i64(mask, mask, bits, j, size); 1310 } 1311 1312 tcg_gen_st8_i64(mask, cpu_env, dstoff + i); 1313 } 1314 } 1315 1316 void probe_noshuf_load(TCGv va, int s, int mi) 1317 { 1318 TCGv size = tcg_constant_tl(s); 1319 TCGv mem_idx = tcg_constant_tl(mi); 1320 gen_helper_probe_noshuf_load(cpu_env, va, size, mem_idx); 1321 } 1322 1323 /* 1324 * Note: Since this function might branch, `val` is 1325 * required to be a `tcg_temp_local`. 1326 */ 1327 void gen_set_usr_field_if(DisasContext *ctx, int field, TCGv val) 1328 { 1329 /* Sets the USR field if `val` is non-zero */ 1330 if (reg_field_info[field].width == 1) { 1331 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 1332 TCGv tmp = tcg_temp_new(); 1333 tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width); 1334 tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset); 1335 tcg_gen_or_tl(usr, usr, tmp); 1336 } else { 1337 TCGLabel *skip_label = gen_new_label(); 1338 tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label); 1339 gen_set_usr_field(ctx, field, val); 1340 gen_set_label(skip_label); 1341 } 1342 } 1343 1344 void gen_sat_i32(TCGv dest, TCGv source, int width) 1345 { 1346 TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1); 1347 TCGv min_val = tcg_constant_tl(-(1 << (width - 1))); 1348 tcg_gen_smin_tl(dest, source, max_val); 1349 tcg_gen_smax_tl(dest, dest, min_val); 1350 } 1351 1352 void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) 1353 { 1354 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1355 gen_sat_i32(tmp, source, width); 1356 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp); 1357 tcg_gen_mov_tl(dest, tmp); 1358 } 1359 1360 void gen_satu_i32(TCGv dest, TCGv source, int width) 1361 { 1362 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1363 TCGv max_val = tcg_constant_tl((1 << width) - 1); 1364 TCGv zero = tcg_constant_tl(0); 1365 tcg_gen_movcond_tl(TCG_COND_GTU, tmp, source, max_val, max_val, source); 1366 tcg_gen_movcond_tl(TCG_COND_LT, tmp, source, zero, zero, tmp); 1367 tcg_gen_mov_tl(dest, tmp); 1368 } 1369 1370 void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) 1371 { 1372 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1373 gen_satu_i32(tmp, source, width); 1374 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp); 1375 tcg_gen_mov_tl(dest, tmp); 1376 } 1377 1378 void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width) 1379 { 1380 TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL); 1381 TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1))); 1382 tcg_gen_smin_i64(dest, source, max_val); 1383 tcg_gen_smax_i64(dest, dest, min_val); 1384 } 1385 1386 void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) 1387 { 1388 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1389 TCGv_i64 ovfl_64; 1390 gen_sat_i64(tmp, source, width); 1391 ovfl_64 = tcg_temp_new_i64(); 1392 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source); 1393 tcg_gen_mov_i64(dest, tmp); 1394 tcg_gen_trunc_i64_tl(ovfl, ovfl_64); 1395 } 1396 1397 void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width) 1398 { 1399 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1400 TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL); 1401 TCGv_i64 zero = tcg_constant_i64(0); 1402 tcg_gen_movcond_i64(TCG_COND_GTU, tmp, source, max_val, max_val, source); 1403 tcg_gen_movcond_i64(TCG_COND_LT, tmp, source, zero, zero, tmp); 1404 tcg_gen_mov_i64(dest, tmp); 1405 } 1406 1407 void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) 1408 { 1409 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1410 TCGv_i64 ovfl_64; 1411 gen_satu_i64(tmp, source, width); 1412 ovfl_64 = tcg_temp_new_i64(); 1413 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source); 1414 tcg_gen_mov_i64(dest, tmp); 1415 tcg_gen_trunc_i64_tl(ovfl, ovfl_64); 1416 } 1417 1418 /* Implements the fADDSAT64 macro in TCG */ 1419 void gen_add_sat_i64(DisasContext *ctx, TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 1420 { 1421 TCGv_i64 sum = tcg_temp_new_i64(); 1422 TCGv_i64 xor = tcg_temp_new_i64(); 1423 TCGv_i64 cond1 = tcg_temp_new_i64(); 1424 TCGv_i64 cond2 = tcg_temp_new_i64(); 1425 TCGv_i64 cond3 = tcg_temp_new_i64(); 1426 TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL); 1427 TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL); 1428 TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL); 1429 TCGv_i64 zero = tcg_constant_i64(0); 1430 TCGLabel *no_ovfl_label = gen_new_label(); 1431 TCGLabel *ovfl_label = gen_new_label(); 1432 TCGLabel *ret_label = gen_new_label(); 1433 1434 tcg_gen_add_i64(sum, a, b); 1435 tcg_gen_xor_i64(xor, a, b); 1436 1437 /* if (xor & mask) */ 1438 tcg_gen_and_i64(cond1, xor, mask); 1439 tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label); 1440 1441 /* else if ((a ^ sum) & mask) */ 1442 tcg_gen_xor_i64(cond2, a, sum); 1443 tcg_gen_and_i64(cond2, cond2, mask); 1444 tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label); 1445 /* fallthrough to no_ovfl_label branch */ 1446 1447 /* if branch */ 1448 gen_set_label(no_ovfl_label); 1449 tcg_gen_mov_i64(ret, sum); 1450 tcg_gen_br(ret_label); 1451 1452 /* else if branch */ 1453 gen_set_label(ovfl_label); 1454 tcg_gen_and_i64(cond3, sum, mask); 1455 tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg); 1456 gen_set_usr_fieldi(ctx, USR_OVF, 1); 1457 1458 gen_set_label(ret_label); 1459 } 1460 1461 #include "tcg_funcs_generated.c.inc" 1462 #include "tcg_func_table_generated.c.inc" 1463