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