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_TEUL); 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_TEUQ); 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 = (ctx->pkt->pkt_has_store_s1 & 1) | (ctx->insn->slot << 1); 399 return tcg_constant_tl(slotval); 400 } 401 #endif 402 403 void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot) 404 { 405 tcg_gen_mov_tl(hex_store_addr[slot], vaddr); 406 tcg_gen_movi_tl(hex_store_width[slot], width); 407 tcg_gen_mov_tl(hex_store_val32[slot], src); 408 } 409 410 void gen_store1(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot) 411 { 412 gen_store32(vaddr, src, 1, slot); 413 } 414 415 void gen_store1i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot) 416 { 417 TCGv tmp = tcg_constant_tl(src); 418 gen_store1(tcg_env, vaddr, tmp, slot); 419 } 420 421 void gen_store2(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot) 422 { 423 gen_store32(vaddr, src, 2, slot); 424 } 425 426 void gen_store2i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot) 427 { 428 TCGv tmp = tcg_constant_tl(src); 429 gen_store2(tcg_env, vaddr, tmp, slot); 430 } 431 432 void gen_store4(TCGv_env tcg_env, TCGv vaddr, TCGv src, uint32_t slot) 433 { 434 gen_store32(vaddr, src, 4, slot); 435 } 436 437 void gen_store4i(TCGv_env tcg_env, TCGv vaddr, int32_t src, uint32_t slot) 438 { 439 TCGv tmp = tcg_constant_tl(src); 440 gen_store4(tcg_env, vaddr, tmp, slot); 441 } 442 443 void gen_store8(TCGv_env tcg_env, TCGv vaddr, TCGv_i64 src, uint32_t slot) 444 { 445 tcg_gen_mov_tl(hex_store_addr[slot], vaddr); 446 tcg_gen_movi_tl(hex_store_width[slot], 8); 447 tcg_gen_mov_i64(hex_store_val64[slot], src); 448 } 449 450 void gen_store8i(TCGv_env tcg_env, TCGv vaddr, int64_t src, uint32_t slot) 451 { 452 TCGv_i64 tmp = tcg_constant_i64(src); 453 gen_store8(tcg_env, vaddr, tmp, slot); 454 } 455 456 TCGv gen_8bitsof(TCGv result, TCGv value) 457 { 458 TCGv zero = tcg_constant_tl(0); 459 TCGv ones = tcg_constant_tl(0xff); 460 tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero); 461 462 return result; 463 } 464 465 static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr, 466 TCGCond cond, TCGv pred) 467 { 468 TCGLabel *pred_false = NULL; 469 if (cond != TCG_COND_ALWAYS) { 470 pred_false = gen_new_label(); 471 tcg_gen_brcondi_tl(cond, pred, 0, pred_false); 472 } 473 474 if (ctx->pkt->pkt_has_multi_cof) { 475 /* If there are multiple branches in a packet, ignore the second one */ 476 tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC], 477 ctx->branch_taken, tcg_constant_tl(0), 478 hex_gpr[HEX_REG_PC], addr); 479 tcg_gen_movi_tl(ctx->branch_taken, 1); 480 } else { 481 tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr); 482 } 483 484 if (cond != TCG_COND_ALWAYS) { 485 gen_set_label(pred_false); 486 } 487 } 488 489 static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off, 490 TCGCond cond, TCGv pred) 491 { 492 target_ulong dest = ctx->pkt->pc + pc_off; 493 if (ctx->pkt->pkt_has_multi_cof) { 494 gen_write_new_pc_addr(ctx, tcg_constant_tl(dest), cond, pred); 495 } else { 496 /* Defer this jump to the end of the TB */ 497 ctx->branch_cond = TCG_COND_ALWAYS; 498 if (pred != NULL) { 499 ctx->branch_cond = cond; 500 tcg_gen_mov_tl(ctx->branch_taken, pred); 501 } 502 ctx->branch_dest = dest; 503 } 504 } 505 506 void gen_set_usr_field(DisasContext *ctx, int field, TCGv val) 507 { 508 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 509 tcg_gen_deposit_tl(usr, usr, val, 510 reg_field_info[field].offset, 511 reg_field_info[field].width); 512 } 513 514 void gen_set_usr_fieldi(DisasContext *ctx, int field, int x) 515 { 516 if (reg_field_info[field].width == 1) { 517 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 518 target_ulong bit = 1 << reg_field_info[field].offset; 519 if ((x & 1) == 1) { 520 tcg_gen_ori_tl(usr, usr, bit); 521 } else { 522 tcg_gen_andi_tl(usr, usr, ~bit); 523 } 524 } else { 525 TCGv val = tcg_constant_tl(x); 526 gen_set_usr_field(ctx, field, val); 527 } 528 } 529 530 static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2) 531 { 532 TCGv one = tcg_constant_tl(0xff); 533 TCGv zero = tcg_constant_tl(0); 534 535 tcg_gen_movcond_tl(cond, res, arg1, arg2, one, zero); 536 } 537 538 #ifndef CONFIG_HEXAGON_IDEF_PARSER 539 static inline void gen_loop0r(DisasContext *ctx, TCGv RsV, int riV) 540 { 541 fIMMEXT(riV); 542 fPCALIGN(riV); 543 gen_log_reg_write(ctx, HEX_REG_LC0, RsV); 544 gen_log_reg_write(ctx, HEX_REG_SA0, tcg_constant_tl(ctx->pkt->pc + riV)); 545 gen_set_usr_fieldi(ctx, USR_LPCFG, 0); 546 } 547 548 static void gen_loop0i(DisasContext *ctx, int count, int riV) 549 { 550 gen_loop0r(ctx, tcg_constant_tl(count), riV); 551 } 552 553 static inline void gen_loop1r(DisasContext *ctx, TCGv RsV, int riV) 554 { 555 fIMMEXT(riV); 556 fPCALIGN(riV); 557 gen_log_reg_write(ctx, HEX_REG_LC1, RsV); 558 gen_log_reg_write(ctx, HEX_REG_SA1, tcg_constant_tl(ctx->pkt->pc + riV)); 559 } 560 561 static void gen_loop1i(DisasContext *ctx, int count, int riV) 562 { 563 gen_loop1r(ctx, tcg_constant_tl(count), riV); 564 } 565 566 static void gen_ploopNsr(DisasContext *ctx, int N, TCGv RsV, int riV) 567 { 568 fIMMEXT(riV); 569 fPCALIGN(riV); 570 gen_log_reg_write(ctx, HEX_REG_LC0, RsV); 571 gen_log_reg_write(ctx, HEX_REG_SA0, tcg_constant_tl(ctx->pkt->pc + riV)); 572 gen_set_usr_fieldi(ctx, USR_LPCFG, N); 573 gen_log_pred_write(ctx, 3, tcg_constant_tl(0)); 574 } 575 576 static void gen_ploopNsi(DisasContext *ctx, int N, int count, int riV) 577 { 578 gen_ploopNsr(ctx, N, tcg_constant_tl(count), riV); 579 } 580 581 static inline void gen_comparei(TCGCond cond, TCGv res, TCGv arg1, int arg2) 582 { 583 gen_compare(cond, res, arg1, tcg_constant_tl(arg2)); 584 } 585 #endif 586 587 static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc, 588 TCGCond cond, TCGv pred) 589 { 590 gen_write_new_pc_addr(ctx, dst_pc, cond, pred); 591 } 592 593 static void gen_cond_jumpr31(DisasContext *ctx, TCGCond cond, TCGv pred) 594 { 595 TCGv LSB = tcg_temp_new(); 596 tcg_gen_andi_tl(LSB, pred, 1); 597 gen_cond_jumpr(ctx, hex_gpr[HEX_REG_LR], cond, LSB); 598 } 599 600 static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred, 601 int pc_off) 602 { 603 gen_write_new_pc_pcrel(ctx, pc_off, cond, pred); 604 } 605 606 static void gen_cmpnd_cmp_jmp(DisasContext *ctx, 607 int pnum, TCGCond cond1, TCGv arg1, TCGv arg2, 608 TCGCond cond2, int pc_off) 609 { 610 if (ctx->insn->part1) { 611 TCGv pred = tcg_temp_new(); 612 gen_compare(cond1, pred, arg1, arg2); 613 gen_log_pred_write(ctx, pnum, pred); 614 } else { 615 TCGv pred = tcg_temp_new(); 616 tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]); 617 gen_cond_jump(ctx, cond2, pred, pc_off); 618 } 619 } 620 621 static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx, 622 int pnum, TCGCond cond, TCGv arg1, TCGv arg2, 623 int pc_off) 624 { 625 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_EQ, pc_off); 626 } 627 628 static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx, 629 int pnum, TCGCond cond, TCGv arg1, TCGv arg2, 630 int pc_off) 631 { 632 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_NE, pc_off); 633 } 634 635 static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx, 636 int pnum, TCGCond cond, TCGv arg1, int arg2, 637 int pc_off) 638 { 639 TCGv tmp = tcg_constant_tl(arg2); 640 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_EQ, pc_off); 641 } 642 643 static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx, 644 int pnum, TCGCond cond, TCGv arg1, int arg2, 645 int pc_off) 646 { 647 TCGv tmp = tcg_constant_tl(arg2); 648 gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_NE, pc_off); 649 } 650 651 static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond, 652 TCGv arg, int pc_off) 653 { 654 gen_cmpnd_cmpi_jmp_t(ctx, pnum, cond, arg, -1, pc_off); 655 } 656 657 static void gen_cmpnd_cmp_n1_jmp_f(DisasContext *ctx, int pnum, TCGCond cond, 658 TCGv arg, int pc_off) 659 { 660 gen_cmpnd_cmpi_jmp_f(ctx, pnum, cond, arg, -1, pc_off); 661 } 662 663 static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx, 664 int pnum, TCGv arg, TCGCond cond, int pc_off) 665 { 666 if (ctx->insn->part1) { 667 TCGv pred = tcg_temp_new(); 668 tcg_gen_andi_tl(pred, arg, 1); 669 gen_8bitsof(pred, pred); 670 gen_log_pred_write(ctx, pnum, pred); 671 } else { 672 TCGv pred = tcg_temp_new(); 673 tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]); 674 gen_cond_jump(ctx, cond, pred, pc_off); 675 } 676 } 677 678 static void gen_testbit0_jumpnv(DisasContext *ctx, 679 TCGv arg, TCGCond cond, int pc_off) 680 { 681 TCGv pred = tcg_temp_new(); 682 tcg_gen_andi_tl(pred, arg, 1); 683 gen_cond_jump(ctx, cond, pred, pc_off); 684 } 685 686 static void gen_jump(DisasContext *ctx, int pc_off) 687 { 688 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL); 689 } 690 691 static void gen_jumpr(DisasContext *ctx, TCGv new_pc) 692 { 693 gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL); 694 } 695 696 static void gen_call(DisasContext *ctx, int pc_off) 697 { 698 TCGv lr = get_result_gpr(ctx, HEX_REG_LR); 699 tcg_gen_movi_tl(lr, ctx->next_PC); 700 gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL); 701 } 702 703 static void gen_callr(DisasContext *ctx, TCGv new_pc) 704 { 705 TCGv lr = get_result_gpr(ctx, HEX_REG_LR); 706 tcg_gen_movi_tl(lr, ctx->next_PC); 707 gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL); 708 } 709 710 static void gen_cond_call(DisasContext *ctx, TCGv pred, 711 TCGCond cond, int pc_off) 712 { 713 TCGv lr = get_result_gpr(ctx, HEX_REG_LR); 714 TCGv lsb = tcg_temp_new(); 715 TCGLabel *skip = gen_new_label(); 716 tcg_gen_andi_tl(lsb, pred, 1); 717 gen_write_new_pc_pcrel(ctx, pc_off, cond, lsb); 718 tcg_gen_brcondi_tl(cond, lsb, 0, skip); 719 tcg_gen_movi_tl(lr, ctx->next_PC); 720 gen_set_label(skip); 721 } 722 723 static void gen_cond_callr(DisasContext *ctx, 724 TCGCond cond, TCGv pred, TCGv new_pc) 725 { 726 TCGv lsb = tcg_temp_new(); 727 TCGLabel *skip = gen_new_label(); 728 tcg_gen_andi_tl(lsb, pred, 1); 729 tcg_gen_brcondi_tl(cond, lsb, 0, skip); 730 gen_callr(ctx, new_pc); 731 gen_set_label(skip); 732 } 733 734 #ifndef CONFIG_HEXAGON_IDEF_PARSER 735 /* frame = ((LR << 32) | FP) ^ (FRAMEKEY << 32)) */ 736 static TCGv_i64 gen_frame_scramble(void) 737 { 738 TCGv_i64 frame = tcg_temp_new_i64(); 739 TCGv tmp = tcg_temp_new(); 740 tcg_gen_xor_tl(tmp, hex_gpr[HEX_REG_LR], hex_gpr[HEX_REG_FRAMEKEY]); 741 tcg_gen_concat_i32_i64(frame, hex_gpr[HEX_REG_FP], tmp); 742 return frame; 743 } 744 #endif 745 746 /* frame ^= (int64_t)FRAMEKEY << 32 */ 747 static void gen_frame_unscramble(TCGv_i64 frame) 748 { 749 TCGv_i64 framekey = tcg_temp_new_i64(); 750 tcg_gen_extu_i32_i64(framekey, hex_gpr[HEX_REG_FRAMEKEY]); 751 tcg_gen_shli_i64(framekey, framekey, 32); 752 tcg_gen_xor_i64(frame, frame, framekey); 753 } 754 755 static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA) 756 { 757 Insn *insn = ctx->insn; /* Needed for CHECK_NOSHUF */ 758 CHECK_NOSHUF(EA, 8); 759 tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_TEUQ); 760 } 761 762 #ifndef CONFIG_HEXAGON_IDEF_PARSER 763 /* Stack overflow check */ 764 static void gen_framecheck(TCGv EA, int framesize) 765 { 766 /* Not modelled in linux-user mode */ 767 /* Placeholder for system mode */ 768 #ifndef CONFIG_USER_ONLY 769 g_assert_not_reached(); 770 #endif 771 } 772 773 static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize) 774 { 775 TCGv r30 = tcg_temp_new(); 776 TCGv_i64 frame; 777 tcg_gen_addi_tl(r30, r29, -8); 778 frame = gen_frame_scramble(); 779 gen_store8(tcg_env, r30, frame, ctx->insn->slot); 780 gen_log_reg_write(ctx, HEX_REG_FP, r30); 781 gen_framecheck(r30, framesize); 782 tcg_gen_subi_tl(r29, r30, framesize); 783 } 784 785 static void gen_deallocframe(DisasContext *ctx, TCGv_i64 r31_30, TCGv r30) 786 { 787 TCGv r29 = tcg_temp_new(); 788 TCGv_i64 frame = tcg_temp_new_i64(); 789 gen_load_frame(ctx, frame, r30); 790 gen_frame_unscramble(frame); 791 tcg_gen_mov_i64(r31_30, frame); 792 tcg_gen_addi_tl(r29, r30, 8); 793 gen_log_reg_write(ctx, HEX_REG_SP, r29); 794 } 795 #endif 796 797 static void gen_return(DisasContext *ctx, TCGv_i64 dst, TCGv src) 798 { 799 /* 800 * frame = *src 801 * dst = frame_unscramble(frame) 802 * SP = src + 8 803 * PC = dst.w[1] 804 */ 805 TCGv_i64 frame = tcg_temp_new_i64(); 806 TCGv r31 = tcg_temp_new(); 807 TCGv r29 = get_result_gpr(ctx, HEX_REG_SP); 808 809 gen_load_frame(ctx, frame, src); 810 gen_frame_unscramble(frame); 811 tcg_gen_mov_i64(dst, frame); 812 tcg_gen_addi_tl(r29, src, 8); 813 tcg_gen_extrh_i64_i32(r31, dst); 814 gen_jumpr(ctx, r31); 815 } 816 817 /* if (pred) dst = dealloc_return(src):raw */ 818 static void gen_cond_return(DisasContext *ctx, TCGv_i64 dst, TCGv src, 819 TCGv pred, TCGCond cond) 820 { 821 TCGv LSB = tcg_temp_new(); 822 TCGLabel *skip = gen_new_label(); 823 tcg_gen_andi_tl(LSB, pred, 1); 824 825 tcg_gen_brcondi_tl(cond, LSB, 0, skip); 826 gen_return(ctx, dst, src); 827 gen_set_label(skip); 828 } 829 830 /* sub-instruction version (no RddV, so handle it manually) */ 831 static void gen_cond_return_subinsn(DisasContext *ctx, TCGCond cond, TCGv pred) 832 { 833 TCGv_i64 RddV = get_result_gpr_pair(ctx, HEX_REG_FP); 834 gen_cond_return(ctx, RddV, hex_gpr[HEX_REG_FP], pred, cond); 835 gen_log_reg_write_pair(ctx, HEX_REG_FP, RddV); 836 } 837 838 static void gen_endloop0(DisasContext *ctx) 839 { 840 TCGv lpcfg = tcg_temp_new(); 841 842 GET_USR_FIELD(USR_LPCFG, lpcfg); 843 844 /* 845 * if (lpcfg == 1) { 846 * p3 = 0xff; 847 * } 848 */ 849 TCGLabel *label1 = gen_new_label(); 850 tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1); 851 { 852 gen_log_pred_write(ctx, 3, tcg_constant_tl(0xff)); 853 } 854 gen_set_label(label1); 855 856 /* 857 * if (lpcfg) { 858 * SET_USR_FIELD(USR_LPCFG, lpcfg - 1); 859 * } 860 */ 861 TCGLabel *label2 = gen_new_label(); 862 tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2); 863 { 864 tcg_gen_subi_tl(lpcfg, lpcfg, 1); 865 gen_set_usr_field(ctx, USR_LPCFG, lpcfg); 866 } 867 gen_set_label(label2); 868 869 /* 870 * If we're in a tight loop, we'll do this at the end of the TB to take 871 * advantage of direct block chaining. 872 */ 873 if (!ctx->is_tight_loop) { 874 /* 875 * if (LC0 > 1) { 876 * PC = SA0; 877 * LC0--; 878 * } 879 */ 880 TCGLabel *label3 = gen_new_label(); 881 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3); 882 { 883 TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0); 884 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]); 885 tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1); 886 } 887 gen_set_label(label3); 888 } 889 } 890 891 static void gen_endloop1(DisasContext *ctx) 892 { 893 /* 894 * if (LC1 > 1) { 895 * PC = SA1; 896 * LC1--; 897 * } 898 */ 899 TCGLabel *label = gen_new_label(); 900 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, label); 901 { 902 TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1); 903 gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]); 904 tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1); 905 } 906 gen_set_label(label); 907 } 908 909 static void gen_endloop01(DisasContext *ctx) 910 { 911 TCGv lpcfg = tcg_temp_new(); 912 TCGLabel *label1 = gen_new_label(); 913 TCGLabel *label2 = gen_new_label(); 914 TCGLabel *label3 = gen_new_label(); 915 TCGLabel *done = gen_new_label(); 916 917 GET_USR_FIELD(USR_LPCFG, lpcfg); 918 919 /* 920 * if (lpcfg == 1) { 921 * p3 = 0xff; 922 * } 923 */ 924 tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1); 925 { 926 gen_log_pred_write(ctx, 3, tcg_constant_tl(0xff)); 927 } 928 gen_set_label(label1); 929 930 /* 931 * if (lpcfg) { 932 * SET_USR_FIELD(USR_LPCFG, lpcfg - 1); 933 * } 934 */ 935 tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2); 936 { 937 tcg_gen_subi_tl(lpcfg, lpcfg, 1); 938 gen_set_usr_field(ctx, USR_LPCFG, lpcfg); 939 } 940 gen_set_label(label2); 941 942 /* 943 * if (LC0 > 1) { 944 * PC = SA0; 945 * LC0--; 946 * } else if (LC1 > 1) { 947 * PC = SA1; 948 * LC1--; 949 * } 950 */ 951 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3); 952 { 953 TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0); 954 gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]); 955 tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1); 956 tcg_gen_br(done); 957 } 958 gen_set_label(label3); 959 tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, done); 960 { 961 TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1); 962 gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]); 963 tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1); 964 } 965 gen_set_label(done); 966 } 967 968 static void gen_cmp_jumpnv(DisasContext *ctx, 969 TCGCond cond, TCGv val, TCGv src, int pc_off) 970 { 971 TCGv pred = tcg_temp_new(); 972 tcg_gen_setcond_tl(cond, pred, val, src); 973 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); 974 } 975 976 static void gen_cmpi_jumpnv(DisasContext *ctx, 977 TCGCond cond, TCGv val, int src, int pc_off) 978 { 979 TCGv pred = tcg_temp_new(); 980 tcg_gen_setcondi_tl(cond, pred, val, src); 981 gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off); 982 } 983 984 /* Shift left with saturation */ 985 static void gen_shl_sat(DisasContext *ctx, TCGv dst, TCGv src, TCGv shift_amt) 986 { 987 TCGv tmp = tcg_temp_new(); /* In case dst == src */ 988 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 989 TCGv sh32 = tcg_temp_new(); 990 TCGv dst_sar = tcg_temp_new(); 991 TCGv ovf = tcg_temp_new(); 992 TCGv satval = tcg_temp_new(); 993 TCGv min = tcg_constant_tl(0x80000000); 994 TCGv max = tcg_constant_tl(0x7fffffff); 995 996 /* 997 * Possible values for shift_amt are 0 .. 64 998 * We need special handling for values above 31 999 * 1000 * sh32 = shift & 31; 1001 * dst = sh32 == shift ? src : 0; 1002 * dst <<= sh32; 1003 * dst_sar = dst >> sh32; 1004 * satval = src < 0 ? min : max; 1005 * if (dst_asr != src) { 1006 * usr.OVF |= 1; 1007 * dst = satval; 1008 * } 1009 */ 1010 1011 tcg_gen_andi_tl(sh32, shift_amt, 31); 1012 tcg_gen_movcond_tl(TCG_COND_EQ, tmp, sh32, shift_amt, 1013 src, tcg_constant_tl(0)); 1014 tcg_gen_shl_tl(tmp, tmp, sh32); 1015 tcg_gen_sar_tl(dst_sar, tmp, sh32); 1016 tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max); 1017 1018 tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src); 1019 tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset); 1020 tcg_gen_or_tl(usr, usr, ovf); 1021 1022 tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, tmp, satval); 1023 } 1024 1025 static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt) 1026 { 1027 /* 1028 * Shift arithmetic right 1029 * Robust when shift_amt is >31 bits 1030 */ 1031 TCGv tmp = tcg_temp_new(); 1032 tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31)); 1033 tcg_gen_sar_tl(dst, src, tmp); 1034 } 1035 1036 /* Bidirectional shift right with saturation */ 1037 static void gen_asr_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV) 1038 { 1039 TCGv shift_amt = tcg_temp_new(); 1040 TCGLabel *positive = gen_new_label(); 1041 TCGLabel *done = gen_new_label(); 1042 1043 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); 1044 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); 1045 1046 /* Negative shift amount => shift left */ 1047 tcg_gen_neg_tl(shift_amt, shift_amt); 1048 gen_shl_sat(ctx, RdV, RsV, shift_amt); 1049 tcg_gen_br(done); 1050 1051 gen_set_label(positive); 1052 /* Positive shift amount => shift right */ 1053 gen_sar(RdV, RsV, shift_amt); 1054 1055 gen_set_label(done); 1056 } 1057 1058 /* Bidirectional shift left with saturation */ 1059 static void gen_asl_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV) 1060 { 1061 TCGv shift_amt = tcg_temp_new(); 1062 TCGLabel *positive = gen_new_label(); 1063 TCGLabel *done = gen_new_label(); 1064 1065 tcg_gen_sextract_i32(shift_amt, RtV, 0, 7); 1066 tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive); 1067 1068 /* Negative shift amount => shift right */ 1069 tcg_gen_neg_tl(shift_amt, shift_amt); 1070 gen_sar(RdV, RsV, shift_amt); 1071 tcg_gen_br(done); 1072 1073 gen_set_label(positive); 1074 /* Positive shift amount => shift left */ 1075 gen_shl_sat(ctx, RdV, RsV, shift_amt); 1076 1077 gen_set_label(done); 1078 } 1079 1080 static void gen_insert_rp(DisasContext *ctx, TCGv RxV, TCGv RsV, TCGv_i64 RttV) 1081 { 1082 /* 1083 * int width = fZXTN(6, 32, (fGETWORD(1, RttV))); 1084 * int offset = fSXTN(7, 32, (fGETWORD(0, RttV))); 1085 * size8u_t mask = ((fCONSTLL(1) << width) - 1); 1086 * if (offset < 0) { 1087 * RxV = 0; 1088 * } else { 1089 * RxV &= ~(mask << offset); 1090 * RxV |= ((RsV & mask) << offset); 1091 * } 1092 */ 1093 1094 TCGv width = tcg_temp_new(); 1095 TCGv offset = tcg_temp_new(); 1096 TCGv_i64 mask = tcg_temp_new_i64(); 1097 TCGv_i64 result = tcg_temp_new_i64(); 1098 TCGv_i64 tmp = tcg_temp_new_i64(); 1099 TCGv_i64 offset64 = tcg_temp_new_i64(); 1100 TCGLabel *label = gen_new_label(); 1101 TCGLabel *done = gen_new_label(); 1102 1103 tcg_gen_extrh_i64_i32(width, RttV); 1104 tcg_gen_extract_tl(width, width, 0, 6); 1105 tcg_gen_extrl_i64_i32(offset, RttV); 1106 tcg_gen_sextract_tl(offset, offset, 0, 7); 1107 /* Possible values for offset are -64 .. 63 */ 1108 tcg_gen_brcondi_tl(TCG_COND_GE, offset, 0, label); 1109 /* For negative offsets, zero out the result */ 1110 tcg_gen_movi_tl(RxV, 0); 1111 tcg_gen_br(done); 1112 gen_set_label(label); 1113 /* At this point, possible values of offset are 0 .. 63 */ 1114 tcg_gen_ext_i32_i64(mask, width); 1115 tcg_gen_shl_i64(mask, tcg_constant_i64(1), mask); 1116 tcg_gen_subi_i64(mask, mask, 1); 1117 tcg_gen_extu_i32_i64(result, RxV); 1118 tcg_gen_ext_i32_i64(tmp, offset); 1119 tcg_gen_shl_i64(tmp, mask, tmp); 1120 tcg_gen_andc_i64(result, result, tmp); 1121 tcg_gen_extu_i32_i64(tmp, RsV); 1122 tcg_gen_and_i64(tmp, tmp, mask); 1123 tcg_gen_extu_i32_i64(offset64, offset); 1124 tcg_gen_shl_i64(tmp, tmp, offset64); 1125 tcg_gen_or_i64(result, result, tmp); 1126 tcg_gen_extrl_i64_i32(RxV, result); 1127 gen_set_label(done); 1128 } 1129 1130 static void gen_asr_r_svw_trun(DisasContext *ctx, TCGv RdV, 1131 TCGv_i64 RssV, TCGv RtV) 1132 { 1133 /* 1134 * for (int i = 0; i < 2; i++) { 1135 * fSETHALF(i, RdV, fGETHALF(0, ((fSXTN(7, 32, RtV) > 0) ? 1136 * (fCAST4_8s(fGETWORD(i, RssV)) >> fSXTN(7, 32, RtV)) : 1137 * (fCAST4_8s(fGETWORD(i, RssV)) << -fSXTN(7, 32, RtV))))); 1138 * } 1139 */ 1140 TCGv shift_amt32 = tcg_temp_new(); 1141 TCGv_i64 shift_amt64 = tcg_temp_new_i64(); 1142 TCGv_i64 tmp64 = tcg_temp_new_i64(); 1143 TCGv tmp32 = tcg_temp_new(); 1144 TCGLabel *label = gen_new_label(); 1145 TCGLabel *zero = gen_new_label(); 1146 TCGLabel *done = gen_new_label(); 1147 1148 tcg_gen_sextract_tl(shift_amt32, RtV, 0, 7); 1149 /* Possible values of shift_amt32 are -64 .. 63 */ 1150 tcg_gen_brcondi_tl(TCG_COND_LE, shift_amt32, 0, label); 1151 /* After branch, possible values of shift_amt32 are 1 .. 63 */ 1152 tcg_gen_ext_i32_i64(shift_amt64, shift_amt32); 1153 for (int i = 0; i < 2; i++) { 1154 tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32); 1155 tcg_gen_sar_i64(tmp64, tmp64, shift_amt64); 1156 tcg_gen_extrl_i64_i32(tmp32, tmp64); 1157 tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16); 1158 } 1159 tcg_gen_br(done); 1160 gen_set_label(label); 1161 tcg_gen_neg_tl(shift_amt32, shift_amt32); 1162 /*At this point, possible values of shift_amt32 are 0 .. 64 */ 1163 tcg_gen_brcondi_tl(TCG_COND_GT, shift_amt32, 63, zero); 1164 /*At this point, possible values of shift_amt32 are 0 .. 63 */ 1165 tcg_gen_ext_i32_i64(shift_amt64, shift_amt32); 1166 for (int i = 0; i < 2; i++) { 1167 tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32); 1168 tcg_gen_shl_i64(tmp64, tmp64, shift_amt64); 1169 tcg_gen_extrl_i64_i32(tmp32, tmp64); 1170 tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16); 1171 } 1172 tcg_gen_br(done); 1173 gen_set_label(zero); 1174 /* When the shift_amt is 64, zero out the result */ 1175 tcg_gen_movi_tl(RdV, 0); 1176 gen_set_label(done); 1177 } 1178 1179 static intptr_t vreg_src_off(DisasContext *ctx, int num) 1180 { 1181 intptr_t offset = offsetof(CPUHexagonState, VRegs[num]); 1182 1183 if (test_bit(num, ctx->vregs_select)) { 1184 offset = ctx_future_vreg_off(ctx, num, 1, false); 1185 } 1186 if (test_bit(num, ctx->vregs_updated_tmp)) { 1187 offset = ctx_tmp_vreg_off(ctx, num, 1, false); 1188 } 1189 return offset; 1190 } 1191 1192 static void gen_log_vreg_write(DisasContext *ctx, intptr_t srcoff, int num, 1193 VRegWriteType type) 1194 { 1195 intptr_t dstoff; 1196 1197 if (type != EXT_TMP) { 1198 dstoff = ctx_future_vreg_off(ctx, num, 1, true); 1199 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, 1200 sizeof(MMVector), sizeof(MMVector)); 1201 } else { 1202 dstoff = ctx_tmp_vreg_off(ctx, num, 1, false); 1203 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, 1204 sizeof(MMVector), sizeof(MMVector)); 1205 } 1206 } 1207 1208 static void gen_log_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num, 1209 VRegWriteType type) 1210 { 1211 gen_log_vreg_write(ctx, srcoff, num ^ 0, type); 1212 srcoff += sizeof(MMVector); 1213 gen_log_vreg_write(ctx, srcoff, num ^ 1, type); 1214 } 1215 1216 static intptr_t get_result_qreg(DisasContext *ctx, int qnum) 1217 { 1218 if (ctx->need_commit) { 1219 return offsetof(CPUHexagonState, future_QRegs[qnum]); 1220 } else { 1221 return offsetof(CPUHexagonState, QRegs[qnum]); 1222 } 1223 } 1224 1225 static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src, 1226 bool aligned) 1227 { 1228 TCGv_i64 tmp = tcg_temp_new_i64(); 1229 if (aligned) { 1230 tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1)); 1231 } 1232 for (int i = 0; i < sizeof(MMVector) / 8; i++) { 1233 tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_TEUQ); 1234 tcg_gen_addi_tl(src, src, 8); 1235 tcg_gen_st_i64(tmp, tcg_env, dstoff + i * 8); 1236 } 1237 } 1238 1239 static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, 1240 int slot, bool aligned) 1241 { 1242 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); 1243 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); 1244 1245 if (is_gather_store_insn(ctx)) { 1246 TCGv sl = tcg_constant_tl(slot); 1247 gen_helper_gather_store(tcg_env, EA, sl); 1248 return; 1249 } 1250 1251 tcg_gen_movi_tl(hex_vstore_pending[slot], 1); 1252 if (aligned) { 1253 tcg_gen_andi_tl(hex_vstore_addr[slot], EA, 1254 ~((int32_t)sizeof(MMVector) - 1)); 1255 } else { 1256 tcg_gen_mov_tl(hex_vstore_addr[slot], EA); 1257 } 1258 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector)); 1259 1260 /* Copy the data to the vstore buffer */ 1261 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector)); 1262 /* Set the mask to all 1's */ 1263 tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL); 1264 } 1265 1266 static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff, 1267 intptr_t bitsoff, int slot, bool invert) 1268 { 1269 intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data); 1270 intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask); 1271 1272 tcg_gen_movi_tl(hex_vstore_pending[slot], 1); 1273 tcg_gen_andi_tl(hex_vstore_addr[slot], EA, 1274 ~((int32_t)sizeof(MMVector) - 1)); 1275 tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector)); 1276 1277 /* Copy the data to the vstore buffer */ 1278 tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector)); 1279 /* Copy the mask */ 1280 tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg)); 1281 if (invert) { 1282 tcg_gen_gvec_not(MO_64, maskoff, maskoff, 1283 sizeof(MMQReg), sizeof(MMQReg)); 1284 } 1285 } 1286 1287 static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff) 1288 { 1289 TCGv_i64 tmp = tcg_temp_new_i64(); 1290 TCGv_i64 word = tcg_temp_new_i64(); 1291 TCGv_i64 bits = tcg_temp_new_i64(); 1292 TCGv_i64 mask = tcg_temp_new_i64(); 1293 TCGv_i64 zero = tcg_constant_i64(0); 1294 TCGv_i64 ones = tcg_constant_i64(~0); 1295 1296 for (int i = 0; i < sizeof(MMVector) / 8; i++) { 1297 tcg_gen_ld_i64(tmp, tcg_env, srcoff + i * 8); 1298 tcg_gen_movi_i64(mask, 0); 1299 1300 for (int j = 0; j < 8; j += size) { 1301 tcg_gen_extract_i64(word, tmp, j * 8, size * 8); 1302 tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero); 1303 tcg_gen_deposit_i64(mask, mask, bits, j, size); 1304 } 1305 1306 tcg_gen_st8_i64(mask, tcg_env, dstoff + i); 1307 } 1308 } 1309 1310 void probe_noshuf_load(TCGv va, int s, int mi) 1311 { 1312 TCGv size = tcg_constant_tl(s); 1313 TCGv mem_idx = tcg_constant_tl(mi); 1314 gen_helper_probe_noshuf_load(tcg_env, va, size, mem_idx); 1315 } 1316 1317 /* 1318 * Note: Since this function might branch, `val` is 1319 * required to be a `tcg_temp_local`. 1320 */ 1321 void gen_set_usr_field_if(DisasContext *ctx, int field, TCGv val) 1322 { 1323 /* Sets the USR field if `val` is non-zero */ 1324 if (reg_field_info[field].width == 1) { 1325 TCGv usr = get_result_gpr(ctx, HEX_REG_USR); 1326 TCGv tmp = tcg_temp_new(); 1327 tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width); 1328 tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset); 1329 tcg_gen_or_tl(usr, usr, tmp); 1330 } else { 1331 TCGLabel *skip_label = gen_new_label(); 1332 tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label); 1333 gen_set_usr_field(ctx, field, val); 1334 gen_set_label(skip_label); 1335 } 1336 } 1337 1338 void gen_sat_i32(TCGv dest, TCGv source, int width) 1339 { 1340 TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1); 1341 TCGv min_val = tcg_constant_tl(-(1 << (width - 1))); 1342 tcg_gen_smin_tl(dest, source, max_val); 1343 tcg_gen_smax_tl(dest, dest, min_val); 1344 } 1345 1346 void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) 1347 { 1348 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1349 gen_sat_i32(tmp, source, width); 1350 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp); 1351 tcg_gen_mov_tl(dest, tmp); 1352 } 1353 1354 void gen_satu_i32(TCGv dest, TCGv source, int width) 1355 { 1356 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1357 TCGv max_val = tcg_constant_tl((1 << width) - 1); 1358 TCGv zero = tcg_constant_tl(0); 1359 tcg_gen_movcond_tl(TCG_COND_GTU, tmp, source, max_val, max_val, source); 1360 tcg_gen_movcond_tl(TCG_COND_LT, tmp, source, zero, zero, tmp); 1361 tcg_gen_mov_tl(dest, tmp); 1362 } 1363 1364 void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width) 1365 { 1366 TCGv tmp = tcg_temp_new(); /* In case dest == source */ 1367 gen_satu_i32(tmp, source, width); 1368 tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp); 1369 tcg_gen_mov_tl(dest, tmp); 1370 } 1371 1372 void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width) 1373 { 1374 TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL); 1375 TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1))); 1376 tcg_gen_smin_i64(dest, source, max_val); 1377 tcg_gen_smax_i64(dest, dest, min_val); 1378 } 1379 1380 void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) 1381 { 1382 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1383 TCGv_i64 ovfl_64; 1384 gen_sat_i64(tmp, source, width); 1385 ovfl_64 = tcg_temp_new_i64(); 1386 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source); 1387 tcg_gen_mov_i64(dest, tmp); 1388 tcg_gen_trunc_i64_tl(ovfl, ovfl_64); 1389 } 1390 1391 void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width) 1392 { 1393 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1394 TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL); 1395 TCGv_i64 zero = tcg_constant_i64(0); 1396 tcg_gen_movcond_i64(TCG_COND_GTU, tmp, source, max_val, max_val, source); 1397 tcg_gen_movcond_i64(TCG_COND_LT, tmp, source, zero, zero, tmp); 1398 tcg_gen_mov_i64(dest, tmp); 1399 } 1400 1401 void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width) 1402 { 1403 TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */ 1404 TCGv_i64 ovfl_64; 1405 gen_satu_i64(tmp, source, width); 1406 ovfl_64 = tcg_temp_new_i64(); 1407 tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source); 1408 tcg_gen_mov_i64(dest, tmp); 1409 tcg_gen_trunc_i64_tl(ovfl, ovfl_64); 1410 } 1411 1412 /* Implements the fADDSAT64 macro in TCG */ 1413 void gen_add_sat_i64(DisasContext *ctx, TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) 1414 { 1415 TCGv_i64 sum = tcg_temp_new_i64(); 1416 TCGv_i64 xor = tcg_temp_new_i64(); 1417 TCGv_i64 cond1 = tcg_temp_new_i64(); 1418 TCGv_i64 cond2 = tcg_temp_new_i64(); 1419 TCGv_i64 cond3 = tcg_temp_new_i64(); 1420 TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL); 1421 TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL); 1422 TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL); 1423 TCGv_i64 zero = tcg_constant_i64(0); 1424 TCGLabel *no_ovfl_label = gen_new_label(); 1425 TCGLabel *ovfl_label = gen_new_label(); 1426 TCGLabel *ret_label = gen_new_label(); 1427 1428 tcg_gen_add_i64(sum, a, b); 1429 tcg_gen_xor_i64(xor, a, b); 1430 1431 /* if (xor & mask) */ 1432 tcg_gen_and_i64(cond1, xor, mask); 1433 tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label); 1434 1435 /* else if ((a ^ sum) & mask) */ 1436 tcg_gen_xor_i64(cond2, a, sum); 1437 tcg_gen_and_i64(cond2, cond2, mask); 1438 tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label); 1439 /* fallthrough to no_ovfl_label branch */ 1440 1441 /* if branch */ 1442 gen_set_label(no_ovfl_label); 1443 tcg_gen_mov_i64(ret, sum); 1444 tcg_gen_br(ret_label); 1445 1446 /* else if branch */ 1447 gen_set_label(ovfl_label); 1448 tcg_gen_and_i64(cond3, sum, mask); 1449 tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg); 1450 gen_set_usr_fieldi(ctx, USR_OVF, 1); 1451 1452 gen_set_label(ret_label); 1453 } 1454 1455 #include "tcg_funcs_generated.c.inc" 1456 #include "tcg_func_table_generated.c.inc" 1457