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