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 (hex_gpr[HEX_REG_LC0] > 1) { 882 * PC = hex_gpr[HEX_REG_SA0]; 883 * hex_new_value[HEX_REG_LC0] = hex_gpr[HEX_REG_LC0] - 1; 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 (hex_gpr[HEX_REG_LC1] > 1) { 901 * PC = hex_gpr[HEX_REG_SA1]; 902 * hex_new_value[HEX_REG_LC1] = hex_gpr[HEX_REG_LC1] - 1; 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 (hex_gpr[HEX_REG_LC0] > 1) { 950 * PC = hex_gpr[HEX_REG_SA0]; 951 * hex_new_value[HEX_REG_LC0] = hex_gpr[HEX_REG_LC0] - 1; 952 * } else { 953 * if (hex_gpr[HEX_REG_LC1] > 1) { 954 * hex_next_pc = hex_gpr[HEX_REG_SA1]; 955 * hex_new_value[HEX_REG_LC1] = hex_gpr[HEX_REG_LC1] - 1; 956 * } 957 * } 958 */ 959 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3); 960 { 961 TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0); 962 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]); 963 tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1); 964 tcg_gen_br(done); 965 } 966 gen_set_label(label3); 967 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, done); 968 { 969 TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1); 970 gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]); 971 tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1); 972 } 973 gen_set_label(done); 974 } 975 976 static void gen_cmp_jumpnv(DisasContext *ctx, 977 TCGCond cond, TCGv val, TCGv src, int pc_off) 978 { 979 TCGv pred = tcg_temp_new(); 980 tcg_gen_setcond_tl(cond, pred, val, src); 981 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); 982 } 983 984 static void gen_cmpi_jumpnv(DisasContext *ctx, 985 TCGCond cond, TCGv val, int src, int pc_off) 986 { 987 TCGv pred = tcg_temp_new(); 988 tcg_gen_setcondi_tl(cond, pred, val, src); 989 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); 990 } 991 992 /* Shift left with saturation */ 993 static void gen_shl_sat(DisasContext *ctx, TCGv dst, TCGv src, TCGv shift_amt) 994 { 995 TCGv tmp = tcg_temp_new(); /* In case dst == src */ 996 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 997 TCGv sh32 = tcg_temp_new(); 998 TCGv dst_sar = tcg_temp_new(); 999 TCGv ovf = tcg_temp_new(); 1000 TCGv satval = tcg_temp_new(); 1001 TCGv min = tcg_constant_tl(0x80000000); 1002 TCGv max = tcg_constant_tl(0x7fffffff); 1003 1004 /* 1005 * Possible values for shift_amt are 0 .. 64 1006 * We need special handling for values above 31 1007 * 1008 * sh32 = shift & 31; 1009 * dst = sh32 == shift ? src : 0; 1010 * dst <<= sh32; 1011 * dst_sar = dst >> sh32; 1012 * satval = src < 0 ? min : max; 1013 * if (dst_asr != src) { 1014 * usr.OVF |= 1; 1015 * dst = satval; 1016 * } 1017 */ 1018 1019 tcg_gen_andi_tl(sh32, shift_amt, 31); 1020 tcg_gen_movcond_tl(TCG_COND_EQ, tmp, sh32, shift_amt, 1021 src, tcg_constant_tl(0)); 1022 tcg_gen_shl_tl(tmp, tmp, sh32); 1023 tcg_gen_sar_tl(dst_sar, tmp, sh32); 1024 tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max); 1025 1026 tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src); 1027 tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset); 1028 tcg_gen_or_tl(usr, usr, ovf); 1029 1030 tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, tmp, satval); 1031 } 1032 1033 static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt) 1034 { 1035 /* 1036 * Shift arithmetic right 1037 * Robust when shift_amt is >31 bits 1038 */ 1039 TCGv tmp = tcg_temp_new(); 1040 tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31)); 1041 tcg_gen_sar_tl(dst, src, tmp); 1042 } 1043 1044 /* Bidirectional shift right with saturation */ 1045 static void gen_asr_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV) 1046 { 1047 TCGv shift_amt = tcg_temp_new(); 1048 TCGLabel *positive = gen_new_label(); 1049 TCGLabel *done = gen_new_label(); 1050 1051 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); 1052 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); 1053 1054 /* Negative shift amount => shift left */ 1055 tcg_gen_neg_tl(shift_amt, shift_amt); 1056 gen_shl_sat(ctx, RdV, RsV, shift_amt); 1057 tcg_gen_br(done); 1058 1059 gen_set_label(positive); 1060 /* Positive shift amount => shift right */ 1061 gen_sar(RdV, RsV, shift_amt); 1062 1063 gen_set_label(done); 1064 } 1065 1066 /* Bidirectional shift left with saturation */ 1067 static void gen_asl_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV) 1068 { 1069 TCGv shift_amt = tcg_temp_new(); 1070 TCGLabel *positive = gen_new_label(); 1071 TCGLabel *done = gen_new_label(); 1072 1073 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); 1074 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); 1075 1076 /* Negative shift amount => shift right */ 1077 tcg_gen_neg_tl(shift_amt, shift_amt); 1078 gen_sar(RdV, RsV, shift_amt); 1079 tcg_gen_br(done); 1080 1081 gen_set_label(positive); 1082 /* Positive shift amount => shift left */ 1083 gen_shl_sat(ctx, RdV, RsV, shift_amt); 1084 1085 gen_set_label(done); 1086 } 1087 1088 static void gen_insert_rp(DisasContext *ctx, TCGv RxV, TCGv RsV, TCGv_i64 RttV) 1089 { 1090 /* 1091 * int width = fZXTN(6, 32, (fGETWORD(1, RttV))); 1092 * int offset = fSXTN(7, 32, (fGETWORD(0, RttV))); 1093 * size8u_t mask = ((fCONSTLL(1) << width) - 1); 1094 * if (offset < 0) { 1095 * RxV = 0; 1096 * } else { 1097 * RxV &= ~(mask << offset); 1098 * RxV |= ((RsV & mask) << offset); 1099 * } 1100 */ 1101 1102 TCGv width = tcg_temp_new(); 1103 TCGv offset = tcg_temp_new(); 1104 TCGv_i64 mask = tcg_temp_new_i64(); 1105 TCGv_i64 result = tcg_temp_new_i64(); 1106 TCGv_i64 tmp = tcg_temp_new_i64(); 1107 TCGv_i64 offset64 = tcg_temp_new_i64(); 1108 TCGLabel *label = gen_new_label(); 1109 TCGLabel *done = gen_new_label(); 1110 1111 tcg_gen_extrh_i64_i32(width, RttV); 1112 tcg_gen_extract_tl(width, width, 0, 6); 1113 tcg_gen_extrl_i64_i32(offset, RttV); 1114 tcg_gen_sextract_tl(offset, offset, 0, 7); 1115 /* Possible values for offset are -64 .. 63 */ 1116 tcg_gen_brcondi_tl(TCG_COND_GE, offset, 0, label); 1117 /* For negative offsets, zero out the result */ 1118 tcg_gen_movi_tl(RxV, 0); 1119 tcg_gen_br(done); 1120 gen_set_label(label); 1121 /* At this point, possible values of offset are 0 .. 63 */ 1122 tcg_gen_ext_i32_i64(mask, width); 1123 tcg_gen_shl_i64(mask, tcg_constant_i64(1), mask); 1124 tcg_gen_subi_i64(mask, mask, 1); 1125 tcg_gen_extu_i32_i64(result, RxV); 1126 tcg_gen_ext_i32_i64(tmp, offset); 1127 tcg_gen_shl_i64(tmp, mask, tmp); 1128 tcg_gen_andc_i64(result, result, tmp); 1129 tcg_gen_extu_i32_i64(tmp, RsV); 1130 tcg_gen_and_i64(tmp, tmp, mask); 1131 tcg_gen_extu_i32_i64(offset64, offset); 1132 tcg_gen_shl_i64(tmp, tmp, offset64); 1133 tcg_gen_or_i64(result, result, tmp); 1134 tcg_gen_extrl_i64_i32(RxV, result); 1135 gen_set_label(done); 1136 } 1137 1138 static void gen_asr_r_svw_trun(DisasContext *ctx, TCGv RdV, 1139 TCGv_i64 RssV, TCGv RtV) 1140 { 1141 /* 1142 * for (int i = 0; i < 2; i++) { 1143 * fSETHALF(i, RdV, fGETHALF(0, ((fSXTN(7, 32, RtV) > 0) ? 1144 * (fCAST4_8s(fGETWORD(i, RssV)) >> fSXTN(7, 32, RtV)) : 1145 * (fCAST4_8s(fGETWORD(i, RssV)) << -fSXTN(7, 32, RtV))))); 1146 * } 1147 */ 1148 TCGv shift_amt32 = tcg_temp_new(); 1149 TCGv_i64 shift_amt64 = tcg_temp_new_i64(); 1150 TCGv_i64 tmp64 = tcg_temp_new_i64(); 1151 TCGv tmp32 = tcg_temp_new(); 1152 TCGLabel *label = gen_new_label(); 1153 TCGLabel *zero = gen_new_label(); 1154 TCGLabel *done = gen_new_label(); 1155 1156 tcg_gen_sextract_tl(shift_amt32, RtV, 0, 7); 1157 /* Possible values of shift_amt32 are -64 .. 63 */ 1158 tcg_gen_brcondi_tl(TCG_COND_LE, shift_amt32, 0, label); 1159 /* After branch, possible values of shift_amt32 are 1 .. 63 */ 1160 tcg_gen_ext_i32_i64(shift_amt64, shift_amt32); 1161 for (int i = 0; i < 2; i++) { 1162 tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32); 1163 tcg_gen_sar_i64(tmp64, tmp64, shift_amt64); 1164 tcg_gen_extrl_i64_i32(tmp32, tmp64); 1165 tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16); 1166 } 1167 tcg_gen_br(done); 1168 gen_set_label(label); 1169 tcg_gen_neg_tl(shift_amt32, shift_amt32); 1170 /*At this point, possible values of shift_amt32 are 0 .. 64 */ 1171 tcg_gen_brcondi_tl(TCG_COND_GT, shift_amt32, 63, zero); 1172 /*At this point, possible values of shift_amt32 are 0 .. 63 */ 1173 tcg_gen_ext_i32_i64(shift_amt64, shift_amt32); 1174 for (int i = 0; i < 2; i++) { 1175 tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32); 1176 tcg_gen_shl_i64(tmp64, tmp64, shift_amt64); 1177 tcg_gen_extrl_i64_i32(tmp32, tmp64); 1178 tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16); 1179 } 1180 tcg_gen_br(done); 1181 gen_set_label(zero); 1182 /* When the shift_amt is 64, zero out the result */ 1183 tcg_gen_movi_tl(RdV, 0); 1184 gen_set_label(done); 1185 } 1186 1187 static intptr_t vreg_src_off(DisasContext *ctx, int num) 1188 { 1189 intptr_t offset = offsetof(CPUHexagonState, VRegs[num]); 1190 1191 if (test_bit(num, ctx->vregs_select)) { 1192 offset = ctx_future_vreg_off(ctx, num, 1, false); 1193 } 1194 if (test_bit(num, ctx->vregs_updated_tmp)) { 1195 offset = ctx_tmp_vreg_off(ctx, num, 1, false); 1196 } 1197 return offset; 1198 } 1199 1200 static void gen_log_vreg_write(DisasContext *ctx, intptr_t srcoff, int num, 1201 VRegWriteType type) 1202 { 1203 intptr_t dstoff; 1204 1205 if (type != EXT_TMP) { 1206 dstoff = ctx_future_vreg_off(ctx, num, 1, true); 1207 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, 1208 sizeof(MMVector), sizeof(MMVector)); 1209 } else { 1210 dstoff = ctx_tmp_vreg_off(ctx, num, 1, false); 1211 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, 1212 sizeof(MMVector), sizeof(MMVector)); 1213 } 1214 } 1215 1216 static void gen_log_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num, 1217 VRegWriteType type) 1218 { 1219 gen_log_vreg_write(ctx, srcoff, num ^ 0, type); 1220 srcoff += sizeof(MMVector); 1221 gen_log_vreg_write(ctx, srcoff, num ^ 1, type); 1222 } 1223 1224 static intptr_t get_result_qreg(DisasContext *ctx, int qnum) 1225 { 1226 if (ctx->need_commit) { 1227 return offsetof(CPUHexagonState, future_QRegs[qnum]); 1228 } else { 1229 return offsetof(CPUHexagonState, QRegs[qnum]); 1230 } 1231 } 1232 1233 static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src, 1234 bool aligned) 1235 { 1236 TCGv_i64 tmp = tcg_temp_new_i64(); 1237 if (aligned) { 1238 tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1)); 1239 } 1240 for (int i = 0; i < sizeof(MMVector) / 8; i++) { 1241 tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_TEUQ); 1242 tcg_gen_addi_tl(src, src, 8); 1243 tcg_gen_st_i64(tmp, cpu_env, dstoff + i * 8); 1244 } 1245 } 1246 1247 static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, 1248 int slot, bool aligned) 1249 { 1250 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); 1251 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); 1252 1253 if (is_gather_store_insn(ctx)) { 1254 TCGv sl = tcg_constant_tl(slot); 1255 gen_helper_gather_store(cpu_env, EA, sl); 1256 return; 1257 } 1258 1259 tcg_gen_movi_tl(hex_vstore_pending[slot], 1); 1260 if (aligned) { 1261 tcg_gen_andi_tl(hex_vstore_addr[slot], EA, 1262 ~((int32_t)sizeof(MMVector) - 1)); 1263 } else { 1264 tcg_gen_mov_tl(hex_vstore_addr[slot], EA); 1265 } 1266 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector)); 1267 1268 /* Copy the data to the vstore buffer */ 1269 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector)); 1270 /* Set the mask to all 1's */ 1271 tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL); 1272 } 1273 1274 static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, 1275 intptr_t bitsoff, int slot, bool invert) 1276 { 1277 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); 1278 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); 1279 1280 tcg_gen_movi_tl(hex_vstore_pending[slot], 1); 1281 tcg_gen_andi_tl(hex_vstore_addr[slot], EA, 1282 ~((int32_t)sizeof(MMVector) - 1)); 1283 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector)); 1284 1285 /* Copy the data to the vstore buffer */ 1286 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector)); 1287 /* Copy the mask */ 1288 tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg)); 1289 if (invert) { 1290 tcg_gen_gvec_not(MO_64, maskoff, maskoff, 1291 sizeof(MMQReg), sizeof(MMQReg)); 1292 } 1293 } 1294 1295 static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff) 1296 { 1297 TCGv_i64 tmp = tcg_temp_new_i64(); 1298 TCGv_i64 word = tcg_temp_new_i64(); 1299 TCGv_i64 bits = tcg_temp_new_i64(); 1300 TCGv_i64 mask = tcg_temp_new_i64(); 1301 TCGv_i64 zero = tcg_constant_i64(0); 1302 TCGv_i64 ones = tcg_constant_i64(~0); 1303 1304 for (int i = 0; i < sizeof(MMVector) / 8; i++) { 1305 tcg_gen_ld_i64(tmp, cpu_env, srcoff + i * 8); 1306 tcg_gen_movi_i64(mask, 0); 1307 1308 for (int j = 0; j < 8; j += size) { 1309 tcg_gen_extract_i64(word, tmp, j * 8, size * 8); 1310 tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero); 1311 tcg_gen_deposit_i64(mask, mask, bits, j, size); 1312 } 1313 1314 tcg_gen_st8_i64(mask, cpu_env, dstoff + i); 1315 } 1316 } 1317 1318 void probe_noshuf_load(TCGv va, int s, int mi) 1319 { 1320 TCGv size = tcg_constant_tl(s); 1321 TCGv mem_idx = tcg_constant_tl(mi); 1322 gen_helper_probe_noshuf_load(cpu_env, va, size, mem_idx); 1323 } 1324 1325 /* 1326 * Note: Since this function might branch, `val` is 1327 * required to be a `tcg_temp_local`. 1328 */ 1329 void gen_set_usr_field_if(DisasContext *ctx, int field, TCGv val) 1330 { 1331 /* Sets the USR field if `val` is non-zero */ 1332 if (reg_field_info[field].width == 1) { 1333 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 1334 TCGv tmp = tcg_temp_new(); 1335 tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width); 1336 tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset); 1337 tcg_gen_or_tl(usr, usr, tmp); 1338 } else { 1339 TCGLabel *skip_label = gen_new_label(); 1340 tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label); 1341 gen_set_usr_field(ctx, field, val); 1342 gen_set_label(skip_label); 1343 } 1344 } 1345 1346 void gen_sat_i32(TCGv dest, TCGv source, int width) 1347 { 1348 TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1); 1349 TCGv min_val = tcg_constant_tl(-(1 << (width - 1))); 1350 tcg_gen_smin_tl(dest, source, max_val); 1351 tcg_gen_smax_tl(dest, dest, min_val); 1352 } 1353 1354 void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) 1355 { 1356 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1357 gen_sat_i32(tmp, source, width); 1358 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp); 1359 tcg_gen_mov_tl(dest, tmp); 1360 } 1361 1362 void gen_satu_i32(TCGv dest, TCGv source, int width) 1363 { 1364 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1365 TCGv max_val = tcg_constant_tl((1 << width) - 1); 1366 TCGv zero = tcg_constant_tl(0); 1367 tcg_gen_movcond_tl(TCG_COND_GTU, tmp, source, max_val, max_val, source); 1368 tcg_gen_movcond_tl(TCG_COND_LT, tmp, source, zero, zero, tmp); 1369 tcg_gen_mov_tl(dest, tmp); 1370 } 1371 1372 void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) 1373 { 1374 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1375 gen_satu_i32(tmp, source, width); 1376 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp); 1377 tcg_gen_mov_tl(dest, tmp); 1378 } 1379 1380 void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width) 1381 { 1382 TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL); 1383 TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1))); 1384 tcg_gen_smin_i64(dest, source, max_val); 1385 tcg_gen_smax_i64(dest, dest, min_val); 1386 } 1387 1388 void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) 1389 { 1390 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1391 TCGv_i64 ovfl_64; 1392 gen_sat_i64(tmp, source, width); 1393 ovfl_64 = tcg_temp_new_i64(); 1394 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source); 1395 tcg_gen_mov_i64(dest, tmp); 1396 tcg_gen_trunc_i64_tl(ovfl, ovfl_64); 1397 } 1398 1399 void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width) 1400 { 1401 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1402 TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL); 1403 TCGv_i64 zero = tcg_constant_i64(0); 1404 tcg_gen_movcond_i64(TCG_COND_GTU, tmp, source, max_val, max_val, source); 1405 tcg_gen_movcond_i64(TCG_COND_LT, tmp, source, zero, zero, tmp); 1406 tcg_gen_mov_i64(dest, tmp); 1407 } 1408 1409 void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) 1410 { 1411 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1412 TCGv_i64 ovfl_64; 1413 gen_satu_i64(tmp, source, width); 1414 ovfl_64 = tcg_temp_new_i64(); 1415 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source); 1416 tcg_gen_mov_i64(dest, tmp); 1417 tcg_gen_trunc_i64_tl(ovfl, ovfl_64); 1418 } 1419 1420 /* Implements the fADDSAT64 macro in TCG */ 1421 void gen_add_sat_i64(DisasContext *ctx, TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 1422 { 1423 TCGv_i64 sum = tcg_temp_new_i64(); 1424 TCGv_i64 xor = tcg_temp_new_i64(); 1425 TCGv_i64 cond1 = tcg_temp_new_i64(); 1426 TCGv_i64 cond2 = tcg_temp_new_i64(); 1427 TCGv_i64 cond3 = tcg_temp_new_i64(); 1428 TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL); 1429 TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL); 1430 TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL); 1431 TCGv_i64 zero = tcg_constant_i64(0); 1432 TCGLabel *no_ovfl_label = gen_new_label(); 1433 TCGLabel *ovfl_label = gen_new_label(); 1434 TCGLabel *ret_label = gen_new_label(); 1435 1436 tcg_gen_add_i64(sum, a, b); 1437 tcg_gen_xor_i64(xor, a, b); 1438 1439 /* if (xor & mask) */ 1440 tcg_gen_and_i64(cond1, xor, mask); 1441 tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label); 1442 1443 /* else if ((a ^ sum) & mask) */ 1444 tcg_gen_xor_i64(cond2, a, sum); 1445 tcg_gen_and_i64(cond2, cond2, mask); 1446 tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label); 1447 /* fallthrough to no_ovfl_label branch */ 1448 1449 /* if branch */ 1450 gen_set_label(no_ovfl_label); 1451 tcg_gen_mov_i64(ret, sum); 1452 tcg_gen_br(ret_label); 1453 1454 /* else if branch */ 1455 gen_set_label(ovfl_label); 1456 tcg_gen_and_i64(cond3, sum, mask); 1457 tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg); 1458 gen_set_usr_fieldi(ctx, USR_OVF, 1); 1459 1460 gen_set_label(ret_label); 1461 } 1462 1463 #include "tcg_funcs_generated.c.inc" 1464 #include "tcg_func_table_generated.c.inc" 1465