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