xref: /openbmc/qemu/target/hexagon/genptr.c (revision 2babbd93)
157acfcdeSTaylor Simpson /*
25ef5fdbaSTaylor Simpson  *  Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
357acfcdeSTaylor Simpson  *
457acfcdeSTaylor Simpson  *  This program is free software; you can redistribute it and/or modify
557acfcdeSTaylor Simpson  *  it under the terms of the GNU General Public License as published by
657acfcdeSTaylor Simpson  *  the Free Software Foundation; either version 2 of the License, or
757acfcdeSTaylor Simpson  *  (at your option) any later version.
857acfcdeSTaylor Simpson  *
957acfcdeSTaylor Simpson  *  This program is distributed in the hope that it will be useful,
1057acfcdeSTaylor Simpson  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1157acfcdeSTaylor Simpson  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1257acfcdeSTaylor Simpson  *  GNU General Public License for more details.
1357acfcdeSTaylor Simpson  *
1457acfcdeSTaylor Simpson  *  You should have received a copy of the GNU General Public License
1557acfcdeSTaylor Simpson  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1657acfcdeSTaylor Simpson  */
1757acfcdeSTaylor Simpson 
1857acfcdeSTaylor Simpson #include "qemu/osdep.h"
1957acfcdeSTaylor Simpson #include "cpu.h"
2057acfcdeSTaylor Simpson #include "internal.h"
2157acfcdeSTaylor Simpson #include "tcg/tcg-op.h"
22887d61b2STaylor Simpson #include "tcg/tcg-op-gvec.h"
2357acfcdeSTaylor Simpson #include "insn.h"
2457acfcdeSTaylor Simpson #include "opcodes.h"
2557acfcdeSTaylor Simpson #include "translate.h"
26a33872ebSTaylor Simpson #define QEMU_GENERATE       /* Used internally by macros.h */
2757acfcdeSTaylor Simpson #include "macros.h"
28887d61b2STaylor Simpson #include "mmvec/macros.h"
29a33872ebSTaylor Simpson #undef QEMU_GENERATE
3057acfcdeSTaylor Simpson #include "gen_tcg.h"
31d51bcabeSTaylor Simpson #include "gen_tcg_hvx.h"
327e8b3b39SPaolo Montesel #include "genptr.h"
337e8b3b39SPaolo Montesel 
3442659e04SNiccolò Izzo TCGv gen_read_reg(TCGv result, int num)
3542659e04SNiccolò Izzo {
3642659e04SNiccolò Izzo     tcg_gen_mov_tl(result, hex_gpr[num]);
3742659e04SNiccolò Izzo     return result;
3842659e04SNiccolò Izzo }
3942659e04SNiccolò Izzo 
407e8b3b39SPaolo Montesel TCGv gen_read_preg(TCGv pred, uint8_t num)
417e8b3b39SPaolo Montesel {
427e8b3b39SPaolo Montesel     tcg_gen_mov_tl(pred, hex_pred[num]);
437e8b3b39SPaolo Montesel     return pred;
447e8b3b39SPaolo Montesel }
4557acfcdeSTaylor Simpson 
46d63aeb3bSMarco Liebel #define IMMUTABLE (~0)
47d63aeb3bSMarco Liebel 
48d54c5615STaylor Simpson const target_ulong reg_immut_masks[TOTAL_PER_THREAD_REGS] = {
49d63aeb3bSMarco Liebel     [HEX_REG_USR] = 0xc13000c0,
50d63aeb3bSMarco Liebel     [HEX_REG_PC] = IMMUTABLE,
51d63aeb3bSMarco Liebel     [HEX_REG_GP] = 0x3f,
52d63aeb3bSMarco Liebel     [HEX_REG_UPCYCLELO] = IMMUTABLE,
53d63aeb3bSMarco Liebel     [HEX_REG_UPCYCLEHI] = IMMUTABLE,
54d63aeb3bSMarco Liebel     [HEX_REG_UTIMERLO] = IMMUTABLE,
55d63aeb3bSMarco Liebel     [HEX_REG_UTIMERHI] = IMMUTABLE,
56d63aeb3bSMarco Liebel };
57d63aeb3bSMarco Liebel 
58d63aeb3bSMarco Liebel static inline void gen_masked_reg_write(TCGv new_val, TCGv cur_val,
59d63aeb3bSMarco Liebel                                         target_ulong reg_mask)
60d63aeb3bSMarco Liebel {
61d63aeb3bSMarco Liebel     if (reg_mask) {
62d63aeb3bSMarco Liebel         TCGv tmp = tcg_temp_new();
63d63aeb3bSMarco Liebel 
64d63aeb3bSMarco Liebel         /* new_val = (new_val & ~reg_mask) | (cur_val & reg_mask) */
65d63aeb3bSMarco Liebel         tcg_gen_andi_tl(new_val, new_val, ~reg_mask);
66d63aeb3bSMarco Liebel         tcg_gen_andi_tl(tmp, cur_val, reg_mask);
67d63aeb3bSMarco Liebel         tcg_gen_or_tl(new_val, new_val, tmp);
68d63aeb3bSMarco Liebel     }
69d63aeb3bSMarco Liebel }
70d63aeb3bSMarco Liebel 
716aa4f1d1STaylor Simpson TCGv get_result_gpr(DisasContext *ctx, int rnum)
7257acfcdeSTaylor Simpson {
73d54c5615STaylor Simpson     if (ctx->need_commit) {
746aa4f1d1STaylor Simpson         if (rnum == HEX_REG_USR) {
756aa4f1d1STaylor Simpson             return hex_new_value_usr;
766aa4f1d1STaylor Simpson         } else {
774ff56764STaylor Simpson             if (ctx->new_value[rnum] == NULL) {
784ff56764STaylor Simpson                 ctx->new_value[rnum] = tcg_temp_new();
794ff56764STaylor Simpson                 tcg_gen_movi_tl(ctx->new_value[rnum], 0);
804ff56764STaylor Simpson             }
814ff56764STaylor Simpson             return ctx->new_value[rnum];
826aa4f1d1STaylor Simpson         }
83d54c5615STaylor Simpson     } else {
84d54c5615STaylor Simpson         return hex_gpr[rnum];
85d54c5615STaylor Simpson     }
8685580a65STaylor Simpson }
87e28b77a6STaylor Simpson 
88e28b77a6STaylor Simpson static TCGv_i64 get_result_gpr_pair(DisasContext *ctx, int rnum)
89e28b77a6STaylor Simpson {
90e28b77a6STaylor Simpson     TCGv_i64 result = tcg_temp_new_i64();
91d54c5615STaylor Simpson     tcg_gen_concat_i32_i64(result, get_result_gpr(ctx, rnum),
92d54c5615STaylor Simpson                                    get_result_gpr(ctx, rnum + 1));
93e28b77a6STaylor Simpson     return result;
9457acfcdeSTaylor Simpson }
9557acfcdeSTaylor Simpson 
9607540a28STaylor Simpson void gen_log_reg_write(DisasContext *ctx, int rnum, TCGv val)
9757acfcdeSTaylor Simpson {
98d63aeb3bSMarco Liebel     const target_ulong reg_mask = reg_immut_masks[rnum];
99d63aeb3bSMarco Liebel 
100d63aeb3bSMarco Liebel     gen_masked_reg_write(val, hex_gpr[rnum], reg_mask);
101d54c5615STaylor Simpson     tcg_gen_mov_tl(get_result_gpr(ctx, rnum), val);
10285580a65STaylor Simpson     if (HEX_DEBUG) {
10357acfcdeSTaylor Simpson         /* Do this so HELPER(debug_commit_end) will know */
10457acfcdeSTaylor Simpson         tcg_gen_movi_tl(hex_reg_written[rnum], 1);
10585580a65STaylor Simpson     }
10657acfcdeSTaylor Simpson }
10757acfcdeSTaylor Simpson 
10807540a28STaylor Simpson static void gen_log_reg_write_pair(DisasContext *ctx, int rnum, TCGv_i64 val)
10957acfcdeSTaylor Simpson {
110d63aeb3bSMarco Liebel     TCGv val32 = tcg_temp_new();
111d63aeb3bSMarco Liebel 
11257acfcdeSTaylor Simpson     /* Low word */
113d63aeb3bSMarco Liebel     tcg_gen_extrl_i64_i32(val32, val);
114d54c5615STaylor Simpson     gen_log_reg_write(ctx, rnum, val32);
11557acfcdeSTaylor Simpson 
11657acfcdeSTaylor Simpson     /* High word */
117d63aeb3bSMarco Liebel     tcg_gen_extrh_i64_i32(val32, val);
118d54c5615STaylor Simpson     gen_log_reg_write(ctx, rnum + 1, val32);
11957acfcdeSTaylor Simpson }
12057acfcdeSTaylor Simpson 
121455e169dSTaylor Simpson TCGv get_result_pred(DisasContext *ctx, int pnum)
122455e169dSTaylor Simpson {
123455e169dSTaylor Simpson     if (ctx->need_commit) {
124e22edc7cSTaylor Simpson         if (ctx->new_pred_value[pnum] == NULL) {
125e22edc7cSTaylor Simpson             ctx->new_pred_value[pnum] = tcg_temp_new();
126e22edc7cSTaylor Simpson             tcg_gen_movi_tl(ctx->new_pred_value[pnum], 0);
127e22edc7cSTaylor Simpson         }
128e22edc7cSTaylor Simpson         return ctx->new_pred_value[pnum];
129455e169dSTaylor Simpson     } else {
130455e169dSTaylor Simpson         return hex_pred[pnum];
131455e169dSTaylor Simpson     }
132455e169dSTaylor Simpson }
133455e169dSTaylor Simpson 
1347e8b3b39SPaolo Montesel void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val)
13557acfcdeSTaylor Simpson {
136455e169dSTaylor Simpson     TCGv pred = get_result_pred(ctx, pnum);
13757acfcdeSTaylor Simpson     TCGv base_val = tcg_temp_new();
13857acfcdeSTaylor Simpson 
13957acfcdeSTaylor Simpson     tcg_gen_andi_tl(base_val, val, 0xff);
1406c677c60STaylor Simpson 
1416c677c60STaylor Simpson     /*
1426c677c60STaylor Simpson      * Section 6.1.3 of the Hexagon V67 Programmer's Reference Manual
1436c677c60STaylor Simpson      *
1446c677c60STaylor Simpson      * Multiple writes to the same preg are and'ed together
1456c677c60STaylor Simpson      * If this is the first predicate write in the packet, do a
1466c677c60STaylor Simpson      * straight assignment.  Otherwise, do an and.
1476c677c60STaylor Simpson      */
1486c677c60STaylor Simpson     if (!test_bit(pnum, ctx->pregs_written)) {
149455e169dSTaylor Simpson         tcg_gen_mov_tl(pred, base_val);
1506c677c60STaylor Simpson     } else {
151455e169dSTaylor Simpson         tcg_gen_and_tl(pred, pred, base_val);
1526c677c60STaylor Simpson     }
15325e1d87dSTaylor Simpson     if (HEX_DEBUG) {
154842b206fSTaylor Simpson         tcg_gen_ori_tl(ctx->pred_written, ctx->pred_written, 1 << pnum);
15525e1d87dSTaylor Simpson     }
15610849c26STaylor Simpson     set_bit(pnum, ctx->pregs_written);
15757acfcdeSTaylor Simpson }
15857acfcdeSTaylor Simpson 
15957acfcdeSTaylor Simpson static inline void gen_read_p3_0(TCGv control_reg)
16057acfcdeSTaylor Simpson {
16157acfcdeSTaylor Simpson     tcg_gen_movi_tl(control_reg, 0);
16257acfcdeSTaylor Simpson     for (int i = 0; i < NUM_PREGS; i++) {
16357acfcdeSTaylor Simpson         tcg_gen_deposit_tl(control_reg, control_reg, hex_pred[i], i * 8, 8);
16457acfcdeSTaylor Simpson     }
16557acfcdeSTaylor Simpson }
16657acfcdeSTaylor Simpson 
16757acfcdeSTaylor Simpson /*
16857acfcdeSTaylor Simpson  * Certain control registers require special handling on read
16972895676SMukilan Thiyagarajan  *     HEX_REG_P3_0_ALIASED  aliased to the predicate registers
17057acfcdeSTaylor Simpson  *                           -> concat the 4 predicate registers together
17157acfcdeSTaylor Simpson  *     HEX_REG_PC            actual value stored in DisasContext
17257acfcdeSTaylor Simpson  *                           -> assign from ctx->base.pc_next
17357acfcdeSTaylor Simpson  *     HEX_REG_QEMU_*_CNT    changes in current TB in DisasContext
17457acfcdeSTaylor Simpson  *                           -> add current TB changes to existing reg value
17557acfcdeSTaylor Simpson  */
17657acfcdeSTaylor Simpson static inline void gen_read_ctrl_reg(DisasContext *ctx, const int reg_num,
17757acfcdeSTaylor Simpson                                      TCGv dest)
17857acfcdeSTaylor Simpson {
17972895676SMukilan Thiyagarajan     if (reg_num == HEX_REG_P3_0_ALIASED) {
18057acfcdeSTaylor Simpson         gen_read_p3_0(dest);
18157acfcdeSTaylor Simpson     } else if (reg_num == HEX_REG_PC) {
18257acfcdeSTaylor Simpson         tcg_gen_movi_tl(dest, ctx->base.pc_next);
18357acfcdeSTaylor Simpson     } else if (reg_num == HEX_REG_QEMU_PKT_CNT) {
18457acfcdeSTaylor Simpson         tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_PKT_CNT],
18557acfcdeSTaylor Simpson                         ctx->num_packets);
18657acfcdeSTaylor Simpson     } else if (reg_num == HEX_REG_QEMU_INSN_CNT) {
18757acfcdeSTaylor Simpson         tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_INSN_CNT],
18857acfcdeSTaylor Simpson                         ctx->num_insns);
189a82dd548STaylor Simpson     } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
190a82dd548STaylor Simpson         tcg_gen_addi_tl(dest, hex_gpr[HEX_REG_QEMU_HVX_CNT],
191a82dd548STaylor Simpson                         ctx->num_hvx_insns);
19257acfcdeSTaylor Simpson     } else {
19357acfcdeSTaylor Simpson         tcg_gen_mov_tl(dest, hex_gpr[reg_num]);
19457acfcdeSTaylor Simpson     }
19557acfcdeSTaylor Simpson }
19657acfcdeSTaylor Simpson 
19757acfcdeSTaylor Simpson static inline void gen_read_ctrl_reg_pair(DisasContext *ctx, const int reg_num,
19857acfcdeSTaylor Simpson                                           TCGv_i64 dest)
19957acfcdeSTaylor Simpson {
20072895676SMukilan Thiyagarajan     if (reg_num == HEX_REG_P3_0_ALIASED) {
20157acfcdeSTaylor Simpson         TCGv p3_0 = tcg_temp_new();
20257acfcdeSTaylor Simpson         gen_read_p3_0(p3_0);
20357acfcdeSTaylor Simpson         tcg_gen_concat_i32_i64(dest, p3_0, hex_gpr[reg_num + 1]);
20457acfcdeSTaylor Simpson     } else if (reg_num == HEX_REG_PC - 1) {
20523803bbeSPhilippe Mathieu-Daudé         TCGv pc = tcg_constant_tl(ctx->base.pc_next);
20657acfcdeSTaylor Simpson         tcg_gen_concat_i32_i64(dest, hex_gpr[reg_num], pc);
20757acfcdeSTaylor Simpson     } else if (reg_num == HEX_REG_QEMU_PKT_CNT) {
20857acfcdeSTaylor Simpson         TCGv pkt_cnt = tcg_temp_new();
20957acfcdeSTaylor Simpson         TCGv insn_cnt = tcg_temp_new();
21057acfcdeSTaylor Simpson         tcg_gen_addi_tl(pkt_cnt, hex_gpr[HEX_REG_QEMU_PKT_CNT],
21157acfcdeSTaylor Simpson                         ctx->num_packets);
21257acfcdeSTaylor Simpson         tcg_gen_addi_tl(insn_cnt, hex_gpr[HEX_REG_QEMU_INSN_CNT],
21357acfcdeSTaylor Simpson                         ctx->num_insns);
21457acfcdeSTaylor Simpson         tcg_gen_concat_i32_i64(dest, pkt_cnt, insn_cnt);
215a82dd548STaylor Simpson     } else if (reg_num == HEX_REG_QEMU_HVX_CNT) {
216a82dd548STaylor Simpson         TCGv hvx_cnt = tcg_temp_new();
217a82dd548STaylor Simpson         tcg_gen_addi_tl(hvx_cnt, hex_gpr[HEX_REG_QEMU_HVX_CNT],
218a82dd548STaylor Simpson                         ctx->num_hvx_insns);
219a82dd548STaylor Simpson         tcg_gen_concat_i32_i64(dest, hvx_cnt, hex_gpr[reg_num + 1]);
22057acfcdeSTaylor Simpson     } else {
22157acfcdeSTaylor Simpson         tcg_gen_concat_i32_i64(dest,
22257acfcdeSTaylor Simpson             hex_gpr[reg_num],
22357acfcdeSTaylor Simpson             hex_gpr[reg_num + 1]);
22457acfcdeSTaylor Simpson     }
22557acfcdeSTaylor Simpson }
22657acfcdeSTaylor Simpson 
227c0d86060STaylor Simpson static void gen_write_p3_0(DisasContext *ctx, TCGv control_reg)
22857acfcdeSTaylor Simpson {
229c0d86060STaylor Simpson     TCGv hex_p8 = tcg_temp_new();
23057acfcdeSTaylor Simpson     for (int i = 0; i < NUM_PREGS; i++) {
231c0d86060STaylor Simpson         tcg_gen_extract_tl(hex_p8, control_reg, i * 8, 8);
232c0d86060STaylor Simpson         gen_log_pred_write(ctx, i, hex_p8);
23357acfcdeSTaylor Simpson     }
23457acfcdeSTaylor Simpson }
23557acfcdeSTaylor Simpson 
23657acfcdeSTaylor Simpson /*
23757acfcdeSTaylor Simpson  * Certain control registers require special handling on write
23872895676SMukilan Thiyagarajan  *     HEX_REG_P3_0_ALIASED  aliased to the predicate registers
23957acfcdeSTaylor Simpson  *                           -> break the value across 4 predicate registers
24057acfcdeSTaylor Simpson  *     HEX_REG_QEMU_*_CNT    changes in current TB in DisasContext
24157acfcdeSTaylor Simpson  *                            -> clear the changes
24257acfcdeSTaylor Simpson  */
24357acfcdeSTaylor Simpson static inline void gen_write_ctrl_reg(DisasContext *ctx, int reg_num,
24457acfcdeSTaylor Simpson                                       TCGv val)
24557acfcdeSTaylor Simpson {
24672895676SMukilan Thiyagarajan     if (reg_num == HEX_REG_P3_0_ALIASED) {
247c0d86060STaylor Simpson         gen_write_p3_0(ctx, val);
24857acfcdeSTaylor Simpson     } else {
24907540a28STaylor Simpson         gen_log_reg_write(ctx, reg_num, val);
25057acfcdeSTaylor Simpson         if (reg_num == HEX_REG_QEMU_PKT_CNT) {
25157acfcdeSTaylor Simpson             ctx->num_packets = 0;
25257acfcdeSTaylor Simpson         }
25357acfcdeSTaylor Simpson         if (reg_num == HEX_REG_QEMU_INSN_CNT) {
25457acfcdeSTaylor Simpson             ctx->num_insns = 0;
25557acfcdeSTaylor Simpson         }
256a82dd548STaylor Simpson         if (reg_num == HEX_REG_QEMU_HVX_CNT) {
257a82dd548STaylor Simpson             ctx->num_hvx_insns = 0;
258a82dd548STaylor Simpson         }
25957acfcdeSTaylor Simpson     }
26057acfcdeSTaylor Simpson }
26157acfcdeSTaylor Simpson 
26257acfcdeSTaylor Simpson static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num,
26357acfcdeSTaylor Simpson                                            TCGv_i64 val)
26457acfcdeSTaylor Simpson {
26572895676SMukilan Thiyagarajan     if (reg_num == HEX_REG_P3_0_ALIASED) {
266e28b77a6STaylor Simpson         TCGv result = get_result_gpr(ctx, reg_num + 1);
26757acfcdeSTaylor Simpson         TCGv val32 = tcg_temp_new();
26857acfcdeSTaylor Simpson         tcg_gen_extrl_i64_i32(val32, val);
269c0d86060STaylor Simpson         gen_write_p3_0(ctx, val32);
27057acfcdeSTaylor Simpson         tcg_gen_extrh_i64_i32(val32, val);
271e28b77a6STaylor Simpson         tcg_gen_mov_tl(result, val32);
27257acfcdeSTaylor Simpson     } else {
27307540a28STaylor Simpson         gen_log_reg_write_pair(ctx, reg_num, val);
27457acfcdeSTaylor Simpson         if (reg_num == HEX_REG_QEMU_PKT_CNT) {
27557acfcdeSTaylor Simpson             ctx->num_packets = 0;
27657acfcdeSTaylor Simpson             ctx->num_insns = 0;
27757acfcdeSTaylor Simpson         }
278a82dd548STaylor Simpson         if (reg_num == HEX_REG_QEMU_HVX_CNT) {
279a82dd548STaylor Simpson             ctx->num_hvx_insns = 0;
280a82dd548STaylor Simpson         }
28157acfcdeSTaylor Simpson     }
28257acfcdeSTaylor Simpson }
28357acfcdeSTaylor Simpson 
2847e8b3b39SPaolo Montesel TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign)
28546ef47e2STaylor Simpson {
28646ef47e2STaylor Simpson     if (sign) {
28746ef47e2STaylor Simpson         tcg_gen_sextract_tl(result, src, N * 8, 8);
28846ef47e2STaylor Simpson     } else {
28946ef47e2STaylor Simpson         tcg_gen_extract_tl(result, src, N * 8, 8);
29046ef47e2STaylor Simpson     }
29146ef47e2STaylor Simpson     return result;
29246ef47e2STaylor Simpson }
29346ef47e2STaylor Simpson 
2947e8b3b39SPaolo Montesel TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign)
2950a65d286STaylor Simpson {
2960a65d286STaylor Simpson     TCGv_i64 res64 = tcg_temp_new_i64();
2970a65d286STaylor Simpson     if (sign) {
2980a65d286STaylor Simpson         tcg_gen_sextract_i64(res64, src, N * 8, 8);
2990a65d286STaylor Simpson     } else {
3000a65d286STaylor Simpson         tcg_gen_extract_i64(res64, src, N * 8, 8);
3010a65d286STaylor Simpson     }
3020a65d286STaylor Simpson     tcg_gen_extrl_i64_i32(result, res64);
3030a65d286STaylor Simpson 
3040a65d286STaylor Simpson     return result;
3050a65d286STaylor Simpson }
3060a65d286STaylor Simpson 
3077e8b3b39SPaolo Montesel TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign)
30846ef47e2STaylor Simpson {
30946ef47e2STaylor Simpson     if (sign) {
31046ef47e2STaylor Simpson         tcg_gen_sextract_tl(result, src, N * 16, 16);
31146ef47e2STaylor Simpson     } else {
31246ef47e2STaylor Simpson         tcg_gen_extract_tl(result, src, N * 16, 16);
31346ef47e2STaylor Simpson     }
31446ef47e2STaylor Simpson     return result;
31546ef47e2STaylor Simpson }
31646ef47e2STaylor Simpson 
3177e8b3b39SPaolo Montesel void gen_set_half(int N, TCGv result, TCGv src)
3180d0b91a8STaylor Simpson {
3190d0b91a8STaylor Simpson     tcg_gen_deposit_tl(result, result, src, N * 16, 16);
3200d0b91a8STaylor Simpson }
3210d0b91a8STaylor Simpson 
3227e8b3b39SPaolo Montesel void gen_set_half_i64(int N, TCGv_i64 result, TCGv src)
3230d0b91a8STaylor Simpson {
3240d0b91a8STaylor Simpson     TCGv_i64 src64 = tcg_temp_new_i64();
3250d0b91a8STaylor Simpson     tcg_gen_extu_i32_i64(src64, src);
3260d0b91a8STaylor Simpson     tcg_gen_deposit_i64(result, result, src64, N * 16, 16);
3270d0b91a8STaylor Simpson }
3280d0b91a8STaylor Simpson 
3297e8b3b39SPaolo Montesel void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src)
3300a65d286STaylor Simpson {
3310a65d286STaylor Simpson     TCGv_i64 src64 = tcg_temp_new_i64();
3320a65d286STaylor Simpson     tcg_gen_extu_i32_i64(src64, src);
3330a65d286STaylor Simpson     tcg_gen_deposit_i64(result, result, src64, N * 8, 8);
3340a65d286STaylor Simpson }
3350a65d286STaylor Simpson 
33657acfcdeSTaylor Simpson static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index)
33757acfcdeSTaylor Simpson {
33853b26d25SRichard Henderson     tcg_gen_qemu_ld_tl(dest, vaddr, mem_index, MO_TEUL);
33957acfcdeSTaylor Simpson     tcg_gen_mov_tl(hex_llsc_addr, vaddr);
34057acfcdeSTaylor Simpson     tcg_gen_mov_tl(hex_llsc_val, dest);
34157acfcdeSTaylor Simpson }
34257acfcdeSTaylor Simpson 
34357acfcdeSTaylor Simpson static inline void gen_load_locked8u(TCGv_i64 dest, TCGv vaddr, int mem_index)
34457acfcdeSTaylor Simpson {
34553b26d25SRichard Henderson     tcg_gen_qemu_ld_i64(dest, vaddr, mem_index, MO_TEUQ);
34657acfcdeSTaylor Simpson     tcg_gen_mov_tl(hex_llsc_addr, vaddr);
34757acfcdeSTaylor Simpson     tcg_gen_mov_i64(hex_llsc_val_i64, dest);
34857acfcdeSTaylor Simpson }
34957acfcdeSTaylor Simpson 
35088725336STaylor Simpson static inline void gen_store_conditional4(DisasContext *ctx,
35157acfcdeSTaylor Simpson                                           TCGv pred, TCGv vaddr, TCGv src)
35257acfcdeSTaylor Simpson {
35357acfcdeSTaylor Simpson     TCGLabel *fail = gen_new_label();
35457acfcdeSTaylor Simpson     TCGLabel *done = gen_new_label();
35557acfcdeSTaylor Simpson     TCGv one, zero, tmp;
35657acfcdeSTaylor Simpson 
35757acfcdeSTaylor Simpson     tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail);
35857acfcdeSTaylor Simpson 
35923803bbeSPhilippe Mathieu-Daudé     one = tcg_constant_tl(0xff);
36023803bbeSPhilippe Mathieu-Daudé     zero = tcg_constant_tl(0);
36157acfcdeSTaylor Simpson     tmp = tcg_temp_new();
36257acfcdeSTaylor Simpson     tcg_gen_atomic_cmpxchg_tl(tmp, hex_llsc_addr, hex_llsc_val, src,
36357acfcdeSTaylor Simpson                               ctx->mem_idx, MO_32);
36488725336STaylor Simpson     tcg_gen_movcond_tl(TCG_COND_EQ, pred, tmp, hex_llsc_val,
36557acfcdeSTaylor Simpson                        one, zero);
36657acfcdeSTaylor Simpson     tcg_gen_br(done);
36757acfcdeSTaylor Simpson 
36857acfcdeSTaylor Simpson     gen_set_label(fail);
36957acfcdeSTaylor Simpson     tcg_gen_movi_tl(pred, 0);
37057acfcdeSTaylor Simpson 
37157acfcdeSTaylor Simpson     gen_set_label(done);
37257acfcdeSTaylor Simpson     tcg_gen_movi_tl(hex_llsc_addr, ~0);
37357acfcdeSTaylor Simpson }
37457acfcdeSTaylor Simpson 
37588725336STaylor Simpson static inline void gen_store_conditional8(DisasContext *ctx,
37657acfcdeSTaylor Simpson                                           TCGv pred, TCGv vaddr, TCGv_i64 src)
37757acfcdeSTaylor Simpson {
37857acfcdeSTaylor Simpson     TCGLabel *fail = gen_new_label();
37957acfcdeSTaylor Simpson     TCGLabel *done = gen_new_label();
38057acfcdeSTaylor Simpson     TCGv_i64 one, zero, tmp;
38157acfcdeSTaylor Simpson 
38257acfcdeSTaylor Simpson     tcg_gen_brcond_tl(TCG_COND_NE, vaddr, hex_llsc_addr, fail);
38357acfcdeSTaylor Simpson 
38423803bbeSPhilippe Mathieu-Daudé     one = tcg_constant_i64(0xff);
38523803bbeSPhilippe Mathieu-Daudé     zero = tcg_constant_i64(0);
38657acfcdeSTaylor Simpson     tmp = tcg_temp_new_i64();
38757acfcdeSTaylor Simpson     tcg_gen_atomic_cmpxchg_i64(tmp, hex_llsc_addr, hex_llsc_val_i64, src,
38857acfcdeSTaylor Simpson                                ctx->mem_idx, MO_64);
38957acfcdeSTaylor Simpson     tcg_gen_movcond_i64(TCG_COND_EQ, tmp, tmp, hex_llsc_val_i64,
39057acfcdeSTaylor Simpson                         one, zero);
39188725336STaylor Simpson     tcg_gen_extrl_i64_i32(pred, tmp);
39257acfcdeSTaylor Simpson     tcg_gen_br(done);
39357acfcdeSTaylor Simpson 
39457acfcdeSTaylor Simpson     gen_set_label(fail);
39557acfcdeSTaylor Simpson     tcg_gen_movi_tl(pred, 0);
39657acfcdeSTaylor Simpson 
39757acfcdeSTaylor Simpson     gen_set_label(done);
39857acfcdeSTaylor Simpson     tcg_gen_movi_tl(hex_llsc_addr, ~0);
39957acfcdeSTaylor Simpson }
40057acfcdeSTaylor Simpson 
401e5d0d78dSTaylor Simpson #ifndef CONFIG_HEXAGON_IDEF_PARSER
402e5d0d78dSTaylor Simpson static TCGv gen_slotval(DisasContext *ctx)
403e5d0d78dSTaylor Simpson {
404e5d0d78dSTaylor Simpson     int slotval = (ctx->pkt->pkt_has_store_s1 & 1) | (ctx->insn->slot << 1);
405e5d0d78dSTaylor Simpson     return tcg_constant_tl(slotval);
406e5d0d78dSTaylor Simpson }
407e5d0d78dSTaylor Simpson #endif
408e5d0d78dSTaylor Simpson 
4097e8b3b39SPaolo Montesel void gen_store32(TCGv vaddr, TCGv src, int width, uint32_t slot)
41046ef47e2STaylor Simpson {
41146ef47e2STaylor Simpson     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
41246ef47e2STaylor Simpson     tcg_gen_movi_tl(hex_store_width[slot], width);
41346ef47e2STaylor Simpson     tcg_gen_mov_tl(hex_store_val32[slot], src);
41446ef47e2STaylor Simpson }
41546ef47e2STaylor Simpson 
4167e8b3b39SPaolo Montesel void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot)
41746ef47e2STaylor Simpson {
41846ef47e2STaylor Simpson     gen_store32(vaddr, src, 1, slot);
41946ef47e2STaylor Simpson }
42046ef47e2STaylor Simpson 
4217e8b3b39SPaolo Montesel void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot)
42246ef47e2STaylor Simpson {
42323803bbeSPhilippe Mathieu-Daudé     TCGv tmp = tcg_constant_tl(src);
424661ad999STaylor Simpson     gen_store1(cpu_env, vaddr, tmp, slot);
42546ef47e2STaylor Simpson }
42646ef47e2STaylor Simpson 
4277e8b3b39SPaolo Montesel void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot)
42846ef47e2STaylor Simpson {
42946ef47e2STaylor Simpson     gen_store32(vaddr, src, 2, slot);
43046ef47e2STaylor Simpson }
43146ef47e2STaylor Simpson 
4327e8b3b39SPaolo Montesel void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot)
43346ef47e2STaylor Simpson {
43423803bbeSPhilippe Mathieu-Daudé     TCGv tmp = tcg_constant_tl(src);
435661ad999STaylor Simpson     gen_store2(cpu_env, vaddr, tmp, slot);
43646ef47e2STaylor Simpson }
43746ef47e2STaylor Simpson 
4387e8b3b39SPaolo Montesel void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, uint32_t slot)
43946ef47e2STaylor Simpson {
44046ef47e2STaylor Simpson     gen_store32(vaddr, src, 4, slot);
44146ef47e2STaylor Simpson }
44246ef47e2STaylor Simpson 
4437e8b3b39SPaolo Montesel void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, uint32_t slot)
44446ef47e2STaylor Simpson {
44523803bbeSPhilippe Mathieu-Daudé     TCGv tmp = tcg_constant_tl(src);
446661ad999STaylor Simpson     gen_store4(cpu_env, vaddr, tmp, slot);
44746ef47e2STaylor Simpson }
44846ef47e2STaylor Simpson 
4497e8b3b39SPaolo Montesel void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, uint32_t slot)
45046ef47e2STaylor Simpson {
45146ef47e2STaylor Simpson     tcg_gen_mov_tl(hex_store_addr[slot], vaddr);
45246ef47e2STaylor Simpson     tcg_gen_movi_tl(hex_store_width[slot], 8);
45346ef47e2STaylor Simpson     tcg_gen_mov_i64(hex_store_val64[slot], src);
45446ef47e2STaylor Simpson }
45546ef47e2STaylor Simpson 
4567e8b3b39SPaolo Montesel void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot)
45746ef47e2STaylor Simpson {
45823803bbeSPhilippe Mathieu-Daudé     TCGv_i64 tmp = tcg_constant_i64(src);
459661ad999STaylor Simpson     gen_store8(cpu_env, vaddr, tmp, slot);
46046ef47e2STaylor Simpson }
46146ef47e2STaylor Simpson 
4627e8b3b39SPaolo Montesel TCGv gen_8bitsof(TCGv result, TCGv value)
46357d352acSTaylor Simpson {
46423803bbeSPhilippe Mathieu-Daudé     TCGv zero = tcg_constant_tl(0);
46523803bbeSPhilippe Mathieu-Daudé     TCGv ones = tcg_constant_tl(0xff);
46657d352acSTaylor Simpson     tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero);
46757d352acSTaylor Simpson 
46857d352acSTaylor Simpson     return result;
46957d352acSTaylor Simpson }
47057d352acSTaylor Simpson 
47161c6c06eSTaylor Simpson static void gen_write_new_pc_addr(DisasContext *ctx, TCGv addr,
47261c6c06eSTaylor Simpson                                   TCGCond cond, TCGv pred)
47361c6c06eSTaylor Simpson {
47461c6c06eSTaylor Simpson     TCGLabel *pred_false = NULL;
47561c6c06eSTaylor Simpson     if (cond != TCG_COND_ALWAYS) {
47661c6c06eSTaylor Simpson         pred_false = gen_new_label();
47761c6c06eSTaylor Simpson         tcg_gen_brcondi_tl(cond, pred, 0, pred_false);
47861c6c06eSTaylor Simpson     }
47961c6c06eSTaylor Simpson 
48061c6c06eSTaylor Simpson     if (ctx->pkt->pkt_has_multi_cof) {
48161c6c06eSTaylor Simpson         /* If there are multiple branches in a packet, ignore the second one */
48261c6c06eSTaylor Simpson         tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC],
4830fc56c43STaylor Simpson                            ctx->branch_taken, tcg_constant_tl(0),
48461c6c06eSTaylor Simpson                            hex_gpr[HEX_REG_PC], addr);
4850fc56c43STaylor Simpson         tcg_gen_movi_tl(ctx->branch_taken, 1);
48661c6c06eSTaylor Simpson     } else {
48761c6c06eSTaylor Simpson         tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr);
48861c6c06eSTaylor Simpson     }
48961c6c06eSTaylor Simpson 
49061c6c06eSTaylor Simpson     if (cond != TCG_COND_ALWAYS) {
49161c6c06eSTaylor Simpson         gen_set_label(pred_false);
49261c6c06eSTaylor Simpson     }
49361c6c06eSTaylor Simpson }
49461c6c06eSTaylor Simpson 
49561c6c06eSTaylor Simpson static void gen_write_new_pc_pcrel(DisasContext *ctx, int pc_off,
49661c6c06eSTaylor Simpson                                    TCGCond cond, TCGv pred)
49761c6c06eSTaylor Simpson {
49861c6c06eSTaylor Simpson     target_ulong dest = ctx->pkt->pc + pc_off;
4991b9a7f2aSTaylor Simpson     if (ctx->pkt->pkt_has_multi_cof) {
50061c6c06eSTaylor Simpson         gen_write_new_pc_addr(ctx, tcg_constant_tl(dest), cond, pred);
5011b9a7f2aSTaylor Simpson     } else {
5021b9a7f2aSTaylor Simpson         /* Defer this jump to the end of the TB */
5031b9a7f2aSTaylor Simpson         ctx->branch_cond = TCG_COND_ALWAYS;
5041b9a7f2aSTaylor Simpson         if (pred != NULL) {
5051b9a7f2aSTaylor Simpson             ctx->branch_cond = cond;
5060fc56c43STaylor Simpson             tcg_gen_mov_tl(ctx->branch_taken, pred);
5071b9a7f2aSTaylor Simpson         }
5081b9a7f2aSTaylor Simpson         ctx->branch_dest = dest;
5091b9a7f2aSTaylor Simpson     }
51061c6c06eSTaylor Simpson }
51161c6c06eSTaylor Simpson 
512148ef7fdSTaylor Simpson void gen_set_usr_field(DisasContext *ctx, int field, TCGv val)
513564b2040STaylor Simpson {
514148ef7fdSTaylor Simpson     TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
515148ef7fdSTaylor Simpson     tcg_gen_deposit_tl(usr, usr, val,
516564b2040STaylor Simpson                        reg_field_info[field].offset,
517564b2040STaylor Simpson                        reg_field_info[field].width);
518564b2040STaylor Simpson }
519564b2040STaylor Simpson 
520148ef7fdSTaylor Simpson void gen_set_usr_fieldi(DisasContext *ctx, int field, int x)
521564b2040STaylor Simpson {
522564b2040STaylor Simpson     if (reg_field_info[field].width == 1) {
523148ef7fdSTaylor Simpson         TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
524564b2040STaylor Simpson         target_ulong bit = 1 << reg_field_info[field].offset;
525564b2040STaylor Simpson         if ((x & 1) == 1) {
526148ef7fdSTaylor Simpson             tcg_gen_ori_tl(usr, usr, bit);
527564b2040STaylor Simpson         } else {
528148ef7fdSTaylor Simpson             tcg_gen_andi_tl(usr, usr, ~bit);
529564b2040STaylor Simpson         }
530564b2040STaylor Simpson     } else {
531564b2040STaylor Simpson         TCGv val = tcg_constant_tl(x);
532148ef7fdSTaylor Simpson         gen_set_usr_field(ctx, field, val);
533564b2040STaylor Simpson     }
534564b2040STaylor Simpson }
535564b2040STaylor Simpson 
53611b577ffSTaylor Simpson static void gen_compare(TCGCond cond, TCGv res, TCGv arg1, TCGv arg2)
53711b577ffSTaylor Simpson {
53811b577ffSTaylor Simpson     TCGv one = tcg_constant_tl(0xff);
53911b577ffSTaylor Simpson     TCGv zero = tcg_constant_tl(0);
54011b577ffSTaylor Simpson 
54111b577ffSTaylor Simpson     tcg_gen_movcond_tl(cond, res, arg1, arg2, one, zero);
54211b577ffSTaylor Simpson }
54311b577ffSTaylor Simpson 
54417fda3c2STaylor Simpson #ifndef CONFIG_HEXAGON_IDEF_PARSER
54517fda3c2STaylor Simpson static inline void gen_loop0r(DisasContext *ctx, TCGv RsV, int riV)
54617fda3c2STaylor Simpson {
54717fda3c2STaylor Simpson     fIMMEXT(riV);
54817fda3c2STaylor Simpson     fPCALIGN(riV);
54917fda3c2STaylor Simpson     gen_log_reg_write(ctx, HEX_REG_LC0, RsV);
55017fda3c2STaylor Simpson     gen_log_reg_write(ctx, HEX_REG_SA0, tcg_constant_tl(ctx->pkt->pc + riV));
55117fda3c2STaylor Simpson     gen_set_usr_fieldi(ctx, USR_LPCFG, 0);
55217fda3c2STaylor Simpson }
55317fda3c2STaylor Simpson 
55417fda3c2STaylor Simpson static void gen_loop0i(DisasContext *ctx, int count, int riV)
55517fda3c2STaylor Simpson {
55617fda3c2STaylor Simpson     gen_loop0r(ctx, tcg_constant_tl(count), riV);
55717fda3c2STaylor Simpson }
55817fda3c2STaylor Simpson 
55917fda3c2STaylor Simpson static inline void gen_loop1r(DisasContext *ctx, TCGv RsV, int riV)
56017fda3c2STaylor Simpson {
56117fda3c2STaylor Simpson     fIMMEXT(riV);
56217fda3c2STaylor Simpson     fPCALIGN(riV);
56317fda3c2STaylor Simpson     gen_log_reg_write(ctx, HEX_REG_LC1, RsV);
56417fda3c2STaylor Simpson     gen_log_reg_write(ctx, HEX_REG_SA1, tcg_constant_tl(ctx->pkt->pc + riV));
56517fda3c2STaylor Simpson }
56617fda3c2STaylor Simpson 
56717fda3c2STaylor Simpson static void gen_loop1i(DisasContext *ctx, int count, int riV)
56817fda3c2STaylor Simpson {
56917fda3c2STaylor Simpson     gen_loop1r(ctx, tcg_constant_tl(count), riV);
57017fda3c2STaylor Simpson }
57117fda3c2STaylor Simpson 
57217fda3c2STaylor Simpson static void gen_ploopNsr(DisasContext *ctx, int N, TCGv RsV, int riV)
57317fda3c2STaylor Simpson {
57417fda3c2STaylor Simpson     fIMMEXT(riV);
57517fda3c2STaylor Simpson     fPCALIGN(riV);
57617fda3c2STaylor Simpson     gen_log_reg_write(ctx, HEX_REG_LC0, RsV);
57717fda3c2STaylor Simpson     gen_log_reg_write(ctx, HEX_REG_SA0, tcg_constant_tl(ctx->pkt->pc + riV));
57817fda3c2STaylor Simpson     gen_set_usr_fieldi(ctx, USR_LPCFG, N);
57917fda3c2STaylor Simpson     gen_log_pred_write(ctx, 3, tcg_constant_tl(0));
58017fda3c2STaylor Simpson }
58117fda3c2STaylor Simpson 
58217fda3c2STaylor Simpson static void gen_ploopNsi(DisasContext *ctx, int N, int count, int riV)
58317fda3c2STaylor Simpson {
58417fda3c2STaylor Simpson     gen_ploopNsr(ctx, N, tcg_constant_tl(count), riV);
58517fda3c2STaylor Simpson }
586d24f0b2bSTaylor Simpson 
587d24f0b2bSTaylor Simpson static inline void gen_comparei(TCGCond cond, TCGv res, TCGv arg1, int arg2)
588d24f0b2bSTaylor Simpson {
589d24f0b2bSTaylor Simpson     gen_compare(cond, res, arg1, tcg_constant_tl(arg2));
590d24f0b2bSTaylor Simpson }
59117fda3c2STaylor Simpson #endif
59217fda3c2STaylor Simpson 
59397b16fafSTaylor Simpson static void gen_cond_jumpr(DisasContext *ctx, TCGv dst_pc,
59497b16fafSTaylor Simpson                            TCGCond cond, TCGv pred)
59597b16fafSTaylor Simpson {
59697b16fafSTaylor Simpson     gen_write_new_pc_addr(ctx, dst_pc, cond, pred);
59797b16fafSTaylor Simpson }
59897b16fafSTaylor Simpson 
5995ef5fdbaSTaylor Simpson static void gen_cond_jumpr31(DisasContext *ctx, TCGCond cond, TCGv pred)
6005ef5fdbaSTaylor Simpson {
6015ef5fdbaSTaylor Simpson     TCGv LSB = tcg_temp_new();
6025ef5fdbaSTaylor Simpson     tcg_gen_andi_tl(LSB, pred, 1);
6035ef5fdbaSTaylor Simpson     gen_cond_jumpr(ctx, hex_gpr[HEX_REG_LR], cond, LSB);
6045ef5fdbaSTaylor Simpson }
6055ef5fdbaSTaylor Simpson 
60611b577ffSTaylor Simpson static void gen_cond_jump(DisasContext *ctx, TCGCond cond, TCGv pred,
60711b577ffSTaylor Simpson                           int pc_off)
60811b577ffSTaylor Simpson {
60911b577ffSTaylor Simpson     gen_write_new_pc_pcrel(ctx, pc_off, cond, pred);
61011b577ffSTaylor Simpson }
61111b577ffSTaylor Simpson 
61211b577ffSTaylor Simpson static void gen_cmpnd_cmp_jmp(DisasContext *ctx,
61311b577ffSTaylor Simpson                               int pnum, TCGCond cond1, TCGv arg1, TCGv arg2,
61411b577ffSTaylor Simpson                               TCGCond cond2, int pc_off)
61511b577ffSTaylor Simpson {
61611b577ffSTaylor Simpson     if (ctx->insn->part1) {
61711b577ffSTaylor Simpson         TCGv pred = tcg_temp_new();
61811b577ffSTaylor Simpson         gen_compare(cond1, pred, arg1, arg2);
61911b577ffSTaylor Simpson         gen_log_pred_write(ctx, pnum, pred);
62011b577ffSTaylor Simpson     } else {
62111b577ffSTaylor Simpson         TCGv pred = tcg_temp_new();
622e22edc7cSTaylor Simpson         tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]);
62311b577ffSTaylor Simpson         gen_cond_jump(ctx, cond2, pred, pc_off);
62411b577ffSTaylor Simpson     }
62511b577ffSTaylor Simpson }
62611b577ffSTaylor Simpson 
62711b577ffSTaylor Simpson static void gen_cmpnd_cmp_jmp_t(DisasContext *ctx,
62811b577ffSTaylor Simpson                                 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
62911b577ffSTaylor Simpson                                 int pc_off)
63011b577ffSTaylor Simpson {
63111b577ffSTaylor Simpson     gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_EQ, pc_off);
63211b577ffSTaylor Simpson }
63311b577ffSTaylor Simpson 
63411b577ffSTaylor Simpson static void gen_cmpnd_cmp_jmp_f(DisasContext *ctx,
63511b577ffSTaylor Simpson                                 int pnum, TCGCond cond, TCGv arg1, TCGv arg2,
63611b577ffSTaylor Simpson                                 int pc_off)
63711b577ffSTaylor Simpson {
63811b577ffSTaylor Simpson     gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, arg2, TCG_COND_NE, pc_off);
63911b577ffSTaylor Simpson }
64011b577ffSTaylor Simpson 
64111b577ffSTaylor Simpson static void gen_cmpnd_cmpi_jmp_t(DisasContext *ctx,
64211b577ffSTaylor Simpson                                  int pnum, TCGCond cond, TCGv arg1, int arg2,
64311b577ffSTaylor Simpson                                  int pc_off)
64411b577ffSTaylor Simpson {
64511b577ffSTaylor Simpson     TCGv tmp = tcg_constant_tl(arg2);
64611b577ffSTaylor Simpson     gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_EQ, pc_off);
64711b577ffSTaylor Simpson }
64811b577ffSTaylor Simpson 
64911b577ffSTaylor Simpson static void gen_cmpnd_cmpi_jmp_f(DisasContext *ctx,
65011b577ffSTaylor Simpson                                  int pnum, TCGCond cond, TCGv arg1, int arg2,
65111b577ffSTaylor Simpson                                  int pc_off)
65211b577ffSTaylor Simpson {
65311b577ffSTaylor Simpson     TCGv tmp = tcg_constant_tl(arg2);
65411b577ffSTaylor Simpson     gen_cmpnd_cmp_jmp(ctx, pnum, cond, arg1, tmp, TCG_COND_NE, pc_off);
65511b577ffSTaylor Simpson }
65611b577ffSTaylor Simpson 
65711b577ffSTaylor Simpson static void gen_cmpnd_cmp_n1_jmp_t(DisasContext *ctx, int pnum, TCGCond cond,
65811b577ffSTaylor Simpson                                    TCGv arg, int pc_off)
65911b577ffSTaylor Simpson {
66011b577ffSTaylor Simpson     gen_cmpnd_cmpi_jmp_t(ctx, pnum, cond, arg, -1, pc_off);
66111b577ffSTaylor Simpson }
66211b577ffSTaylor Simpson 
66311b577ffSTaylor Simpson static void gen_cmpnd_cmp_n1_jmp_f(DisasContext *ctx, int pnum, TCGCond cond,
66411b577ffSTaylor Simpson                                    TCGv arg, int pc_off)
66511b577ffSTaylor Simpson {
66611b577ffSTaylor Simpson     gen_cmpnd_cmpi_jmp_f(ctx, pnum, cond, arg, -1, pc_off);
66711b577ffSTaylor Simpson }
66811b577ffSTaylor Simpson 
66911b577ffSTaylor Simpson static void gen_cmpnd_tstbit0_jmp(DisasContext *ctx,
67011b577ffSTaylor Simpson                                   int pnum, TCGv arg, TCGCond cond, int pc_off)
67111b577ffSTaylor Simpson {
67211b577ffSTaylor Simpson     if (ctx->insn->part1) {
67311b577ffSTaylor Simpson         TCGv pred = tcg_temp_new();
67411b577ffSTaylor Simpson         tcg_gen_andi_tl(pred, arg, 1);
67511b577ffSTaylor Simpson         gen_8bitsof(pred, pred);
67611b577ffSTaylor Simpson         gen_log_pred_write(ctx, pnum, pred);
67711b577ffSTaylor Simpson     } else {
67811b577ffSTaylor Simpson         TCGv pred = tcg_temp_new();
679e22edc7cSTaylor Simpson         tcg_gen_mov_tl(pred, ctx->new_pred_value[pnum]);
68011b577ffSTaylor Simpson         gen_cond_jump(ctx, cond, pred, pc_off);
68111b577ffSTaylor Simpson     }
68211b577ffSTaylor Simpson }
68311b577ffSTaylor Simpson 
68497b16fafSTaylor Simpson static void gen_testbit0_jumpnv(DisasContext *ctx,
68597b16fafSTaylor Simpson                                 TCGv arg, TCGCond cond, int pc_off)
68697b16fafSTaylor Simpson {
68797b16fafSTaylor Simpson     TCGv pred = tcg_temp_new();
68897b16fafSTaylor Simpson     tcg_gen_andi_tl(pred, arg, 1);
68997b16fafSTaylor Simpson     gen_cond_jump(ctx, cond, pred, pc_off);
69097b16fafSTaylor Simpson }
69197b16fafSTaylor Simpson 
69297b16fafSTaylor Simpson static void gen_jump(DisasContext *ctx, int pc_off)
69397b16fafSTaylor Simpson {
69497b16fafSTaylor Simpson     gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL);
69597b16fafSTaylor Simpson }
69697b16fafSTaylor Simpson 
69797b16fafSTaylor Simpson static void gen_jumpr(DisasContext *ctx, TCGv new_pc)
69897b16fafSTaylor Simpson {
69997b16fafSTaylor Simpson     gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL);
70097b16fafSTaylor Simpson }
70197b16fafSTaylor Simpson 
70261c6c06eSTaylor Simpson static void gen_call(DisasContext *ctx, int pc_off)
70361c6c06eSTaylor Simpson {
704e28b77a6STaylor Simpson     TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
705e28b77a6STaylor Simpson     tcg_gen_movi_tl(lr, ctx->next_PC);
70661c6c06eSTaylor Simpson     gen_write_new_pc_pcrel(ctx, pc_off, TCG_COND_ALWAYS, NULL);
70761c6c06eSTaylor Simpson }
70861c6c06eSTaylor Simpson 
709242af2c0STaylor Simpson static void gen_callr(DisasContext *ctx, TCGv new_pc)
710242af2c0STaylor Simpson {
711e28b77a6STaylor Simpson     TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
712e28b77a6STaylor Simpson     tcg_gen_movi_tl(lr, ctx->next_PC);
713242af2c0STaylor Simpson     gen_write_new_pc_addr(ctx, new_pc, TCG_COND_ALWAYS, NULL);
714242af2c0STaylor Simpson }
715242af2c0STaylor Simpson 
71661c6c06eSTaylor Simpson static void gen_cond_call(DisasContext *ctx, TCGv pred,
71761c6c06eSTaylor Simpson                           TCGCond cond, int pc_off)
71861c6c06eSTaylor Simpson {
719e28b77a6STaylor Simpson     TCGv lr = get_result_gpr(ctx, HEX_REG_LR);
7207a819de8SRichard Henderson     TCGv lsb = tcg_temp_new();
72161c6c06eSTaylor Simpson     TCGLabel *skip = gen_new_label();
72261c6c06eSTaylor Simpson     tcg_gen_andi_tl(lsb, pred, 1);
72361c6c06eSTaylor Simpson     gen_write_new_pc_pcrel(ctx, pc_off, cond, lsb);
72461c6c06eSTaylor Simpson     tcg_gen_brcondi_tl(cond, lsb, 0, skip);
725e28b77a6STaylor Simpson     tcg_gen_movi_tl(lr, ctx->next_PC);
72661c6c06eSTaylor Simpson     gen_set_label(skip);
72761c6c06eSTaylor Simpson }
72861c6c06eSTaylor Simpson 
729242af2c0STaylor Simpson static void gen_cond_callr(DisasContext *ctx,
730242af2c0STaylor Simpson                            TCGCond cond, TCGv pred, TCGv new_pc)
731242af2c0STaylor Simpson {
732242af2c0STaylor Simpson     TCGv lsb = tcg_temp_new();
733242af2c0STaylor Simpson     TCGLabel *skip = gen_new_label();
734242af2c0STaylor Simpson     tcg_gen_andi_tl(lsb, pred, 1);
735242af2c0STaylor Simpson     tcg_gen_brcondi_tl(cond, lsb, 0, skip);
736242af2c0STaylor Simpson     gen_callr(ctx, new_pc);
737242af2c0STaylor Simpson     gen_set_label(skip);
738242af2c0STaylor Simpson }
739242af2c0STaylor Simpson 
740085b6700STaylor Simpson #ifndef CONFIG_HEXAGON_IDEF_PARSER
741085b6700STaylor Simpson /* frame = ((LR << 32) | FP) ^ (FRAMEKEY << 32)) */
742085b6700STaylor Simpson static TCGv_i64 gen_frame_scramble(void)
743085b6700STaylor Simpson {
744085b6700STaylor Simpson     TCGv_i64 frame = tcg_temp_new_i64();
745085b6700STaylor Simpson     TCGv tmp = tcg_temp_new();
746085b6700STaylor Simpson     tcg_gen_xor_tl(tmp, hex_gpr[HEX_REG_LR], hex_gpr[HEX_REG_FRAMEKEY]);
747085b6700STaylor Simpson     tcg_gen_concat_i32_i64(frame, hex_gpr[HEX_REG_FP], tmp);
748085b6700STaylor Simpson     return frame;
749085b6700STaylor Simpson }
750085b6700STaylor Simpson #endif
751085b6700STaylor Simpson 
752dae386b8STaylor Simpson /* frame ^= (int64_t)FRAMEKEY << 32 */
753dae386b8STaylor Simpson static void gen_frame_unscramble(TCGv_i64 frame)
754dae386b8STaylor Simpson {
755dae386b8STaylor Simpson     TCGv_i64 framekey = tcg_temp_new_i64();
756dae386b8STaylor Simpson     tcg_gen_extu_i32_i64(framekey, hex_gpr[HEX_REG_FRAMEKEY]);
757dae386b8STaylor Simpson     tcg_gen_shli_i64(framekey, framekey, 32);
758dae386b8STaylor Simpson     tcg_gen_xor_i64(frame, frame, framekey);
759dae386b8STaylor Simpson }
760dae386b8STaylor Simpson 
761dae386b8STaylor Simpson static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA)
762dae386b8STaylor Simpson {
763dae386b8STaylor Simpson     Insn *insn = ctx->insn;  /* Needed for CHECK_NOSHUF */
764dae386b8STaylor Simpson     CHECK_NOSHUF(EA, 8);
76553b26d25SRichard Henderson     tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_TEUQ);
766dae386b8STaylor Simpson }
767dae386b8STaylor Simpson 
768085b6700STaylor Simpson #ifndef CONFIG_HEXAGON_IDEF_PARSER
769085b6700STaylor Simpson /* Stack overflow check */
770085b6700STaylor Simpson static void gen_framecheck(TCGv EA, int framesize)
771085b6700STaylor Simpson {
772085b6700STaylor Simpson     /* Not modelled in linux-user mode */
773085b6700STaylor Simpson     /* Placeholder for system mode */
774085b6700STaylor Simpson #ifndef CONFIG_USER_ONLY
775085b6700STaylor Simpson     g_assert_not_reached();
776085b6700STaylor Simpson #endif
777085b6700STaylor Simpson }
778085b6700STaylor Simpson 
779085b6700STaylor Simpson static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize)
780085b6700STaylor Simpson {
781085b6700STaylor Simpson     TCGv r30 = tcg_temp_new();
782085b6700STaylor Simpson     TCGv_i64 frame;
783085b6700STaylor Simpson     tcg_gen_addi_tl(r30, r29, -8);
784085b6700STaylor Simpson     frame = gen_frame_scramble();
785085b6700STaylor Simpson     gen_store8(cpu_env, r30, frame, ctx->insn->slot);
786085b6700STaylor Simpson     gen_log_reg_write(ctx, HEX_REG_FP, r30);
787085b6700STaylor Simpson     gen_framecheck(r30, framesize);
788085b6700STaylor Simpson     tcg_gen_subi_tl(r29, r30, framesize);
789085b6700STaylor Simpson }
790085b6700STaylor Simpson 
791085b6700STaylor Simpson static void gen_deallocframe(DisasContext *ctx, TCGv_i64 r31_30, TCGv r30)
792085b6700STaylor Simpson {
793085b6700STaylor Simpson     TCGv r29 = tcg_temp_new();
794085b6700STaylor Simpson     TCGv_i64 frame = tcg_temp_new_i64();
795085b6700STaylor Simpson     gen_load_frame(ctx, frame, r30);
796085b6700STaylor Simpson     gen_frame_unscramble(frame);
797085b6700STaylor Simpson     tcg_gen_mov_i64(r31_30, frame);
798085b6700STaylor Simpson     tcg_gen_addi_tl(r29, r30, 8);
799085b6700STaylor Simpson     gen_log_reg_write(ctx, HEX_REG_SP, r29);
800085b6700STaylor Simpson }
801085b6700STaylor Simpson #endif
802085b6700STaylor Simpson 
803e28b77a6STaylor Simpson static void gen_return(DisasContext *ctx, TCGv_i64 dst, TCGv src)
804dae386b8STaylor Simpson {
805dae386b8STaylor Simpson     /*
806dae386b8STaylor Simpson      * frame = *src
807dae386b8STaylor Simpson      * dst = frame_unscramble(frame)
808dae386b8STaylor Simpson      * SP = src + 8
809dae386b8STaylor Simpson      * PC = dst.w[1]
810dae386b8STaylor Simpson      */
811dae386b8STaylor Simpson     TCGv_i64 frame = tcg_temp_new_i64();
812dae386b8STaylor Simpson     TCGv r31 = tcg_temp_new();
813e28b77a6STaylor Simpson     TCGv r29 = get_result_gpr(ctx, HEX_REG_SP);
814dae386b8STaylor Simpson 
815dae386b8STaylor Simpson     gen_load_frame(ctx, frame, src);
816dae386b8STaylor Simpson     gen_frame_unscramble(frame);
817dae386b8STaylor Simpson     tcg_gen_mov_i64(dst, frame);
818dae386b8STaylor Simpson     tcg_gen_addi_tl(r29, src, 8);
819dae386b8STaylor Simpson     tcg_gen_extrh_i64_i32(r31, dst);
820dae386b8STaylor Simpson     gen_jumpr(ctx, r31);
821dae386b8STaylor Simpson }
822dae386b8STaylor Simpson 
823dae386b8STaylor Simpson /* if (pred) dst = dealloc_return(src):raw */
824dae386b8STaylor Simpson static void gen_cond_return(DisasContext *ctx, TCGv_i64 dst, TCGv src,
825dae386b8STaylor Simpson                             TCGv pred, TCGCond cond)
826dae386b8STaylor Simpson {
827dae386b8STaylor Simpson     TCGv LSB = tcg_temp_new();
828dae386b8STaylor Simpson     TCGLabel *skip = gen_new_label();
829dae386b8STaylor Simpson     tcg_gen_andi_tl(LSB, pred, 1);
830dae386b8STaylor Simpson 
831dae386b8STaylor Simpson     tcg_gen_brcondi_tl(cond, LSB, 0, skip);
832e28b77a6STaylor Simpson     gen_return(ctx, dst, src);
833dae386b8STaylor Simpson     gen_set_label(skip);
834dae386b8STaylor Simpson }
835dae386b8STaylor Simpson 
836dae386b8STaylor Simpson /* sub-instruction version (no RddV, so handle it manually) */
837dae386b8STaylor Simpson static void gen_cond_return_subinsn(DisasContext *ctx, TCGCond cond, TCGv pred)
838dae386b8STaylor Simpson {
839e28b77a6STaylor Simpson     TCGv_i64 RddV = get_result_gpr_pair(ctx, HEX_REG_FP);
840dae386b8STaylor Simpson     gen_cond_return(ctx, RddV, hex_gpr[HEX_REG_FP], pred, cond);
84107540a28STaylor Simpson     gen_log_reg_write_pair(ctx, HEX_REG_FP, RddV);
842dae386b8STaylor Simpson }
843dae386b8STaylor Simpson 
844564b2040STaylor Simpson static void gen_endloop0(DisasContext *ctx)
845564b2040STaylor Simpson {
8467a819de8SRichard Henderson     TCGv lpcfg = tcg_temp_new();
847564b2040STaylor Simpson 
848564b2040STaylor Simpson     GET_USR_FIELD(USR_LPCFG, lpcfg);
849564b2040STaylor Simpson 
850564b2040STaylor Simpson     /*
851564b2040STaylor Simpson      *    if (lpcfg == 1) {
85225e1d87dSTaylor Simpson      *        p3 = 0xff;
853564b2040STaylor Simpson      *    }
854564b2040STaylor Simpson      */
855564b2040STaylor Simpson     TCGLabel *label1 = gen_new_label();
856564b2040STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1);
857564b2040STaylor Simpson     {
85825e1d87dSTaylor Simpson         gen_log_pred_write(ctx, 3, tcg_constant_tl(0xff));
859564b2040STaylor Simpson     }
860564b2040STaylor Simpson     gen_set_label(label1);
861564b2040STaylor Simpson 
862564b2040STaylor Simpson     /*
863564b2040STaylor Simpson      *    if (lpcfg) {
864564b2040STaylor Simpson      *        SET_USR_FIELD(USR_LPCFG, lpcfg - 1);
865564b2040STaylor Simpson      *    }
866564b2040STaylor Simpson      */
867564b2040STaylor Simpson     TCGLabel *label2 = gen_new_label();
868564b2040STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2);
869564b2040STaylor Simpson     {
870564b2040STaylor Simpson         tcg_gen_subi_tl(lpcfg, lpcfg, 1);
871148ef7fdSTaylor Simpson         gen_set_usr_field(ctx, USR_LPCFG, lpcfg);
872564b2040STaylor Simpson     }
873564b2040STaylor Simpson     gen_set_label(label2);
874564b2040STaylor Simpson 
875564b2040STaylor Simpson     /*
876564b2040STaylor Simpson      * If we're in a tight loop, we'll do this at the end of the TB to take
877564b2040STaylor Simpson      * advantage of direct block chaining.
878564b2040STaylor Simpson      */
879564b2040STaylor Simpson     if (!ctx->is_tight_loop) {
880564b2040STaylor Simpson         /*
881*2babbd93SMatheus Tavares Bernardino          *    if (LC0 > 1) {
882*2babbd93SMatheus Tavares Bernardino          *        PC = SA0;
883*2babbd93SMatheus Tavares Bernardino          *        LC0--;
884564b2040STaylor Simpson          *    }
885564b2040STaylor Simpson          */
886564b2040STaylor Simpson         TCGLabel *label3 = gen_new_label();
887564b2040STaylor Simpson         tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3);
888564b2040STaylor Simpson         {
889e28b77a6STaylor Simpson             TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0);
890564b2040STaylor Simpson             gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]);
891e28b77a6STaylor Simpson             tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1);
892564b2040STaylor Simpson         }
893564b2040STaylor Simpson         gen_set_label(label3);
894564b2040STaylor Simpson     }
895564b2040STaylor Simpson }
896564b2040STaylor Simpson 
897b8552a78STaylor Simpson static void gen_endloop1(DisasContext *ctx)
898b8552a78STaylor Simpson {
899b8552a78STaylor Simpson     /*
900*2babbd93SMatheus Tavares Bernardino      *    if (LC1 > 1) {
901*2babbd93SMatheus Tavares Bernardino      *        PC = SA1;
902*2babbd93SMatheus Tavares Bernardino      *        LC1--;
903b8552a78STaylor Simpson      *    }
904b8552a78STaylor Simpson      */
905b8552a78STaylor Simpson     TCGLabel *label = gen_new_label();
906b8552a78STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, label);
907b8552a78STaylor Simpson     {
908e28b77a6STaylor Simpson         TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1);
909b8552a78STaylor Simpson         gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]);
910e28b77a6STaylor Simpson         tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1);
911b8552a78STaylor Simpson     }
912b8552a78STaylor Simpson     gen_set_label(label);
913b8552a78STaylor Simpson }
914b8552a78STaylor Simpson 
915b8552a78STaylor Simpson static void gen_endloop01(DisasContext *ctx)
916b8552a78STaylor Simpson {
917b8552a78STaylor Simpson     TCGv lpcfg = tcg_temp_new();
918b8552a78STaylor Simpson     TCGLabel *label1 = gen_new_label();
919b8552a78STaylor Simpson     TCGLabel *label2 = gen_new_label();
920b8552a78STaylor Simpson     TCGLabel *label3 = gen_new_label();
921b8552a78STaylor Simpson     TCGLabel *done = gen_new_label();
922b8552a78STaylor Simpson 
923b8552a78STaylor Simpson     GET_USR_FIELD(USR_LPCFG, lpcfg);
924b8552a78STaylor Simpson 
925b8552a78STaylor Simpson     /*
926b8552a78STaylor Simpson      *    if (lpcfg == 1) {
92725e1d87dSTaylor Simpson      *        p3 = 0xff;
928b8552a78STaylor Simpson      *    }
929b8552a78STaylor Simpson      */
930b8552a78STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_NE, lpcfg, 1, label1);
931b8552a78STaylor Simpson     {
93225e1d87dSTaylor Simpson         gen_log_pred_write(ctx, 3, tcg_constant_tl(0xff));
933b8552a78STaylor Simpson     }
934b8552a78STaylor Simpson     gen_set_label(label1);
935b8552a78STaylor Simpson 
936b8552a78STaylor Simpson     /*
937b8552a78STaylor Simpson      *    if (lpcfg) {
938b8552a78STaylor Simpson      *        SET_USR_FIELD(USR_LPCFG, lpcfg - 1);
939b8552a78STaylor Simpson      *    }
940b8552a78STaylor Simpson      */
941b8552a78STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_EQ, lpcfg, 0, label2);
942b8552a78STaylor Simpson     {
943b8552a78STaylor Simpson         tcg_gen_subi_tl(lpcfg, lpcfg, 1);
944148ef7fdSTaylor Simpson         gen_set_usr_field(ctx, USR_LPCFG, lpcfg);
945b8552a78STaylor Simpson     }
946b8552a78STaylor Simpson     gen_set_label(label2);
947b8552a78STaylor Simpson 
948b8552a78STaylor Simpson     /*
949*2babbd93SMatheus Tavares Bernardino      *    if (LC0 > 1) {
950*2babbd93SMatheus Tavares Bernardino      *        PC = SA0;
951*2babbd93SMatheus Tavares Bernardino      *        LC0--;
952*2babbd93SMatheus Tavares Bernardino      *    } else if (LC1 > 1) {
953*2babbd93SMatheus Tavares Bernardino      *        PC = SA1;
954*2babbd93SMatheus Tavares Bernardino      *        LC1--;
955b8552a78STaylor Simpson      *    }
956b8552a78STaylor Simpson      */
957b8552a78STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC0], 1, label3);
958b8552a78STaylor Simpson     {
959e28b77a6STaylor Simpson         TCGv lc0 = get_result_gpr(ctx, HEX_REG_LC0);
960b8552a78STaylor Simpson         gen_jumpr(ctx, hex_gpr[HEX_REG_SA0]);
961e28b77a6STaylor Simpson         tcg_gen_subi_tl(lc0, hex_gpr[HEX_REG_LC0], 1);
962b8552a78STaylor Simpson         tcg_gen_br(done);
963b8552a78STaylor Simpson     }
964b8552a78STaylor Simpson     gen_set_label(label3);
965b8552a78STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_LEU, hex_gpr[HEX_REG_LC1], 1, done);
966b8552a78STaylor Simpson     {
967e28b77a6STaylor Simpson         TCGv lc1 = get_result_gpr(ctx, HEX_REG_LC1);
968b8552a78STaylor Simpson         gen_jumpr(ctx, hex_gpr[HEX_REG_SA1]);
969e28b77a6STaylor Simpson         tcg_gen_subi_tl(lc1, hex_gpr[HEX_REG_LC1], 1);
970b8552a78STaylor Simpson     }
971b8552a78STaylor Simpson     gen_set_label(done);
972b8552a78STaylor Simpson }
973b8552a78STaylor Simpson 
97497b16fafSTaylor Simpson static void gen_cmp_jumpnv(DisasContext *ctx,
97597b16fafSTaylor Simpson                            TCGCond cond, TCGv val, TCGv src, int pc_off)
97697b16fafSTaylor Simpson {
97797b16fafSTaylor Simpson     TCGv pred = tcg_temp_new();
97897b16fafSTaylor Simpson     tcg_gen_setcond_tl(cond, pred, val, src);
97997b16fafSTaylor Simpson     gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off);
98097b16fafSTaylor Simpson }
98197b16fafSTaylor Simpson 
98297b16fafSTaylor Simpson static void gen_cmpi_jumpnv(DisasContext *ctx,
98397b16fafSTaylor Simpson                             TCGCond cond, TCGv val, int src, int pc_off)
98497b16fafSTaylor Simpson {
98597b16fafSTaylor Simpson     TCGv pred = tcg_temp_new();
98697b16fafSTaylor Simpson     tcg_gen_setcondi_tl(cond, pred, val, src);
98797b16fafSTaylor Simpson     gen_cond_jump(ctx, TCG_COND_EQ, pred, pc_off);
98897b16fafSTaylor Simpson }
98997b16fafSTaylor Simpson 
9908e8a85c1STaylor Simpson /* Shift left with saturation */
991148ef7fdSTaylor Simpson static void gen_shl_sat(DisasContext *ctx, TCGv dst, TCGv src, TCGv shift_amt)
9928e8a85c1STaylor Simpson {
99371ed3697STaylor Simpson     TCGv tmp = tcg_temp_new();    /* In case dst == src */
994148ef7fdSTaylor Simpson     TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
9958e8a85c1STaylor Simpson     TCGv sh32 = tcg_temp_new();
9968e8a85c1STaylor Simpson     TCGv dst_sar = tcg_temp_new();
9978e8a85c1STaylor Simpson     TCGv ovf = tcg_temp_new();
9988e8a85c1STaylor Simpson     TCGv satval = tcg_temp_new();
9998e8a85c1STaylor Simpson     TCGv min = tcg_constant_tl(0x80000000);
10008e8a85c1STaylor Simpson     TCGv max = tcg_constant_tl(0x7fffffff);
10018e8a85c1STaylor Simpson 
10028e8a85c1STaylor Simpson     /*
10038e8a85c1STaylor Simpson      *    Possible values for shift_amt are 0 .. 64
10048e8a85c1STaylor Simpson      *    We need special handling for values above 31
10058e8a85c1STaylor Simpson      *
10068e8a85c1STaylor Simpson      *    sh32 = shift & 31;
10078e8a85c1STaylor Simpson      *    dst = sh32 == shift ? src : 0;
10088e8a85c1STaylor Simpson      *    dst <<= sh32;
10098e8a85c1STaylor Simpson      *    dst_sar = dst >> sh32;
10108e8a85c1STaylor Simpson      *    satval = src < 0 ? min : max;
10118e8a85c1STaylor Simpson      *    if (dst_asr != src) {
10128e8a85c1STaylor Simpson      *        usr.OVF |= 1;
10138e8a85c1STaylor Simpson      *        dst = satval;
10148e8a85c1STaylor Simpson      *    }
10158e8a85c1STaylor Simpson      */
10168e8a85c1STaylor Simpson 
10178e8a85c1STaylor Simpson     tcg_gen_andi_tl(sh32, shift_amt, 31);
101871ed3697STaylor Simpson     tcg_gen_movcond_tl(TCG_COND_EQ, tmp, sh32, shift_amt,
10198e8a85c1STaylor Simpson                        src, tcg_constant_tl(0));
102071ed3697STaylor Simpson     tcg_gen_shl_tl(tmp, tmp, sh32);
102171ed3697STaylor Simpson     tcg_gen_sar_tl(dst_sar, tmp, sh32);
10228e8a85c1STaylor Simpson     tcg_gen_movcond_tl(TCG_COND_LT, satval, src, tcg_constant_tl(0), min, max);
10238e8a85c1STaylor Simpson 
10248e8a85c1STaylor Simpson     tcg_gen_setcond_tl(TCG_COND_NE, ovf, dst_sar, src);
10258e8a85c1STaylor Simpson     tcg_gen_shli_tl(ovf, ovf, reg_field_info[USR_OVF].offset);
1026148ef7fdSTaylor Simpson     tcg_gen_or_tl(usr, usr, ovf);
10278e8a85c1STaylor Simpson 
102871ed3697STaylor Simpson     tcg_gen_movcond_tl(TCG_COND_EQ, dst, dst_sar, src, tmp, satval);
10298e8a85c1STaylor Simpson }
10308e8a85c1STaylor Simpson 
10318e8a85c1STaylor Simpson static void gen_sar(TCGv dst, TCGv src, TCGv shift_amt)
10328e8a85c1STaylor Simpson {
10338e8a85c1STaylor Simpson     /*
10348e8a85c1STaylor Simpson      *  Shift arithmetic right
10358e8a85c1STaylor Simpson      *  Robust when shift_amt is >31 bits
10368e8a85c1STaylor Simpson      */
10378e8a85c1STaylor Simpson     TCGv tmp = tcg_temp_new();
10388e8a85c1STaylor Simpson     tcg_gen_umin_tl(tmp, shift_amt, tcg_constant_tl(31));
10398e8a85c1STaylor Simpson     tcg_gen_sar_tl(dst, src, tmp);
10408e8a85c1STaylor Simpson }
10418e8a85c1STaylor Simpson 
10428e8a85c1STaylor Simpson /* Bidirectional shift right with saturation */
1043148ef7fdSTaylor Simpson static void gen_asr_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV)
10448e8a85c1STaylor Simpson {
10457a819de8SRichard Henderson     TCGv shift_amt = tcg_temp_new();
10468e8a85c1STaylor Simpson     TCGLabel *positive = gen_new_label();
10478e8a85c1STaylor Simpson     TCGLabel *done = gen_new_label();
10488e8a85c1STaylor Simpson 
10498e8a85c1STaylor Simpson     tcg_gen_sextract_i32(shift_amt, RtV, 0, 7);
10508e8a85c1STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive);
10518e8a85c1STaylor Simpson 
10528e8a85c1STaylor Simpson     /* Negative shift amount => shift left */
10538e8a85c1STaylor Simpson     tcg_gen_neg_tl(shift_amt, shift_amt);
1054148ef7fdSTaylor Simpson     gen_shl_sat(ctx, RdV, RsV, shift_amt);
10558e8a85c1STaylor Simpson     tcg_gen_br(done);
10568e8a85c1STaylor Simpson 
10578e8a85c1STaylor Simpson     gen_set_label(positive);
10588e8a85c1STaylor Simpson     /* Positive shift amount => shift right */
10598e8a85c1STaylor Simpson     gen_sar(RdV, RsV, shift_amt);
10608e8a85c1STaylor Simpson 
10618e8a85c1STaylor Simpson     gen_set_label(done);
10628e8a85c1STaylor Simpson }
10638e8a85c1STaylor Simpson 
10648e8a85c1STaylor Simpson /* Bidirectional shift left with saturation */
1065148ef7fdSTaylor Simpson static void gen_asl_r_r_sat(DisasContext *ctx, TCGv RdV, TCGv RsV, TCGv RtV)
10668e8a85c1STaylor Simpson {
10677a819de8SRichard Henderson     TCGv shift_amt = tcg_temp_new();
10688e8a85c1STaylor Simpson     TCGLabel *positive = gen_new_label();
10698e8a85c1STaylor Simpson     TCGLabel *done = gen_new_label();
10708e8a85c1STaylor Simpson 
10718e8a85c1STaylor Simpson     tcg_gen_sextract_i32(shift_amt, RtV, 0, 7);
10728e8a85c1STaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_GE, shift_amt, 0, positive);
10738e8a85c1STaylor Simpson 
10748e8a85c1STaylor Simpson     /* Negative shift amount => shift right */
10758e8a85c1STaylor Simpson     tcg_gen_neg_tl(shift_amt, shift_amt);
10768e8a85c1STaylor Simpson     gen_sar(RdV, RsV, shift_amt);
10778e8a85c1STaylor Simpson     tcg_gen_br(done);
10788e8a85c1STaylor Simpson 
10798e8a85c1STaylor Simpson     gen_set_label(positive);
10808e8a85c1STaylor Simpson     /* Positive shift amount => shift left */
1081148ef7fdSTaylor Simpson     gen_shl_sat(ctx, RdV, RsV, shift_amt);
10828e8a85c1STaylor Simpson 
10838e8a85c1STaylor Simpson     gen_set_label(done);
10848e8a85c1STaylor Simpson }
10858e8a85c1STaylor Simpson 
108600e64fdaSTaylor Simpson static void gen_insert_rp(DisasContext *ctx, TCGv RxV, TCGv RsV, TCGv_i64 RttV)
108700e64fdaSTaylor Simpson {
108800e64fdaSTaylor Simpson     /*
108900e64fdaSTaylor Simpson      * int width = fZXTN(6, 32, (fGETWORD(1, RttV)));
109000e64fdaSTaylor Simpson      * int offset = fSXTN(7, 32, (fGETWORD(0, RttV)));
109100e64fdaSTaylor Simpson      * size8u_t mask = ((fCONSTLL(1) << width) - 1);
109200e64fdaSTaylor Simpson      * if (offset < 0) {
109300e64fdaSTaylor Simpson      *     RxV = 0;
109400e64fdaSTaylor Simpson      * } else {
109500e64fdaSTaylor Simpson      *     RxV &= ~(mask << offset);
109600e64fdaSTaylor Simpson      *     RxV |= ((RsV & mask) << offset);
109700e64fdaSTaylor Simpson      * }
109800e64fdaSTaylor Simpson      */
109900e64fdaSTaylor Simpson 
110000e64fdaSTaylor Simpson     TCGv width = tcg_temp_new();
110100e64fdaSTaylor Simpson     TCGv offset = tcg_temp_new();
110200e64fdaSTaylor Simpson     TCGv_i64 mask = tcg_temp_new_i64();
110300e64fdaSTaylor Simpson     TCGv_i64 result = tcg_temp_new_i64();
110400e64fdaSTaylor Simpson     TCGv_i64 tmp = tcg_temp_new_i64();
110500e64fdaSTaylor Simpson     TCGv_i64 offset64 = tcg_temp_new_i64();
110600e64fdaSTaylor Simpson     TCGLabel *label = gen_new_label();
110700e64fdaSTaylor Simpson     TCGLabel *done = gen_new_label();
110800e64fdaSTaylor Simpson 
110900e64fdaSTaylor Simpson     tcg_gen_extrh_i64_i32(width, RttV);
111000e64fdaSTaylor Simpson     tcg_gen_extract_tl(width, width, 0, 6);
111100e64fdaSTaylor Simpson     tcg_gen_extrl_i64_i32(offset, RttV);
111200e64fdaSTaylor Simpson     tcg_gen_sextract_tl(offset, offset, 0, 7);
111300e64fdaSTaylor Simpson     /* Possible values for offset are -64 .. 63 */
111400e64fdaSTaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_GE, offset, 0, label);
111500e64fdaSTaylor Simpson     /* For negative offsets, zero out the result */
111600e64fdaSTaylor Simpson     tcg_gen_movi_tl(RxV, 0);
111700e64fdaSTaylor Simpson     tcg_gen_br(done);
111800e64fdaSTaylor Simpson     gen_set_label(label);
111900e64fdaSTaylor Simpson     /* At this point, possible values of offset are 0 .. 63 */
112000e64fdaSTaylor Simpson     tcg_gen_ext_i32_i64(mask, width);
112100e64fdaSTaylor Simpson     tcg_gen_shl_i64(mask, tcg_constant_i64(1), mask);
112200e64fdaSTaylor Simpson     tcg_gen_subi_i64(mask, mask, 1);
112300e64fdaSTaylor Simpson     tcg_gen_extu_i32_i64(result, RxV);
112400e64fdaSTaylor Simpson     tcg_gen_ext_i32_i64(tmp, offset);
112500e64fdaSTaylor Simpson     tcg_gen_shl_i64(tmp, mask, tmp);
112600e64fdaSTaylor Simpson     tcg_gen_andc_i64(result, result, tmp);
112700e64fdaSTaylor Simpson     tcg_gen_extu_i32_i64(tmp, RsV);
112800e64fdaSTaylor Simpson     tcg_gen_and_i64(tmp, tmp, mask);
112900e64fdaSTaylor Simpson     tcg_gen_extu_i32_i64(offset64, offset);
113000e64fdaSTaylor Simpson     tcg_gen_shl_i64(tmp, tmp, offset64);
113100e64fdaSTaylor Simpson     tcg_gen_or_i64(result, result, tmp);
113200e64fdaSTaylor Simpson     tcg_gen_extrl_i64_i32(RxV, result);
113300e64fdaSTaylor Simpson     gen_set_label(done);
113400e64fdaSTaylor Simpson }
113500e64fdaSTaylor Simpson 
113600e64fdaSTaylor Simpson static void gen_asr_r_svw_trun(DisasContext *ctx, TCGv RdV,
113700e64fdaSTaylor Simpson                                TCGv_i64 RssV, TCGv RtV)
113800e64fdaSTaylor Simpson {
113900e64fdaSTaylor Simpson     /*
114000e64fdaSTaylor Simpson      * for (int i = 0; i < 2; i++) {
114100e64fdaSTaylor Simpson      *     fSETHALF(i, RdV, fGETHALF(0, ((fSXTN(7, 32, RtV) > 0) ?
114200e64fdaSTaylor Simpson      *         (fCAST4_8s(fGETWORD(i, RssV)) >> fSXTN(7, 32, RtV)) :
114300e64fdaSTaylor Simpson      *         (fCAST4_8s(fGETWORD(i, RssV)) << -fSXTN(7, 32, RtV)))));
114400e64fdaSTaylor Simpson      * }
114500e64fdaSTaylor Simpson      */
114600e64fdaSTaylor Simpson     TCGv shift_amt32 = tcg_temp_new();
114700e64fdaSTaylor Simpson     TCGv_i64 shift_amt64 = tcg_temp_new_i64();
114800e64fdaSTaylor Simpson     TCGv_i64 tmp64 = tcg_temp_new_i64();
114900e64fdaSTaylor Simpson     TCGv tmp32 = tcg_temp_new();
115000e64fdaSTaylor Simpson     TCGLabel *label = gen_new_label();
115100e64fdaSTaylor Simpson     TCGLabel *zero = gen_new_label();
115200e64fdaSTaylor Simpson     TCGLabel *done =  gen_new_label();
115300e64fdaSTaylor Simpson 
115400e64fdaSTaylor Simpson     tcg_gen_sextract_tl(shift_amt32, RtV, 0, 7);
115500e64fdaSTaylor Simpson     /* Possible values of shift_amt32 are -64 .. 63 */
115600e64fdaSTaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_LE, shift_amt32, 0, label);
115700e64fdaSTaylor Simpson     /* After branch, possible values of shift_amt32 are 1 .. 63 */
115800e64fdaSTaylor Simpson     tcg_gen_ext_i32_i64(shift_amt64, shift_amt32);
115900e64fdaSTaylor Simpson     for (int i = 0; i < 2; i++) {
116000e64fdaSTaylor Simpson         tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32);
116100e64fdaSTaylor Simpson         tcg_gen_sar_i64(tmp64, tmp64, shift_amt64);
116200e64fdaSTaylor Simpson         tcg_gen_extrl_i64_i32(tmp32, tmp64);
116300e64fdaSTaylor Simpson         tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16);
116400e64fdaSTaylor Simpson     }
116500e64fdaSTaylor Simpson     tcg_gen_br(done);
116600e64fdaSTaylor Simpson     gen_set_label(label);
116700e64fdaSTaylor Simpson     tcg_gen_neg_tl(shift_amt32, shift_amt32);
116800e64fdaSTaylor Simpson     /*At this point, possible values of shift_amt32 are 0 .. 64 */
116900e64fdaSTaylor Simpson     tcg_gen_brcondi_tl(TCG_COND_GT, shift_amt32, 63, zero);
117000e64fdaSTaylor Simpson     /*At this point, possible values of shift_amt32 are 0 .. 63 */
117100e64fdaSTaylor Simpson     tcg_gen_ext_i32_i64(shift_amt64, shift_amt32);
117200e64fdaSTaylor Simpson     for (int i = 0; i < 2; i++) {
117300e64fdaSTaylor Simpson         tcg_gen_sextract_i64(tmp64, RssV, i * 32, 32);
117400e64fdaSTaylor Simpson         tcg_gen_shl_i64(tmp64, tmp64, shift_amt64);
117500e64fdaSTaylor Simpson         tcg_gen_extrl_i64_i32(tmp32, tmp64);
117600e64fdaSTaylor Simpson         tcg_gen_deposit_tl(RdV, RdV, tmp32, i * 16, 16);
117700e64fdaSTaylor Simpson     }
117800e64fdaSTaylor Simpson     tcg_gen_br(done);
117900e64fdaSTaylor Simpson     gen_set_label(zero);
118000e64fdaSTaylor Simpson     /* When the shift_amt is 64, zero out the result */
118100e64fdaSTaylor Simpson     tcg_gen_movi_tl(RdV, 0);
118200e64fdaSTaylor Simpson     gen_set_label(done);
118300e64fdaSTaylor Simpson }
118400e64fdaSTaylor Simpson 
1185887d61b2STaylor Simpson static intptr_t vreg_src_off(DisasContext *ctx, int num)
1186887d61b2STaylor Simpson {
1187887d61b2STaylor Simpson     intptr_t offset = offsetof(CPUHexagonState, VRegs[num]);
1188887d61b2STaylor Simpson 
1189887d61b2STaylor Simpson     if (test_bit(num, ctx->vregs_select)) {
1190887d61b2STaylor Simpson         offset = ctx_future_vreg_off(ctx, num, 1, false);
1191887d61b2STaylor Simpson     }
1192887d61b2STaylor Simpson     if (test_bit(num, ctx->vregs_updated_tmp)) {
1193887d61b2STaylor Simpson         offset = ctx_tmp_vreg_off(ctx, num, 1, false);
1194887d61b2STaylor Simpson     }
1195887d61b2STaylor Simpson     return offset;
1196887d61b2STaylor Simpson }
1197887d61b2STaylor Simpson 
1198887d61b2STaylor Simpson static void gen_log_vreg_write(DisasContext *ctx, intptr_t srcoff, int num,
1199c2b33d0bSTaylor Simpson                                VRegWriteType type)
1200887d61b2STaylor Simpson {
1201887d61b2STaylor Simpson     intptr_t dstoff;
1202887d61b2STaylor Simpson 
1203887d61b2STaylor Simpson     if (type != EXT_TMP) {
1204887d61b2STaylor Simpson         dstoff = ctx_future_vreg_off(ctx, num, 1, true);
1205887d61b2STaylor Simpson         tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
1206887d61b2STaylor Simpson                          sizeof(MMVector), sizeof(MMVector));
1207887d61b2STaylor Simpson     } else {
1208887d61b2STaylor Simpson         dstoff = ctx_tmp_vreg_off(ctx, num, 1, false);
1209887d61b2STaylor Simpson         tcg_gen_gvec_mov(MO_64, dstoff, srcoff,
1210887d61b2STaylor Simpson                          sizeof(MMVector), sizeof(MMVector));
1211887d61b2STaylor Simpson     }
1212887d61b2STaylor Simpson }
1213887d61b2STaylor Simpson 
1214887d61b2STaylor Simpson static void gen_log_vreg_write_pair(DisasContext *ctx, intptr_t srcoff, int num,
1215c2b33d0bSTaylor Simpson                                     VRegWriteType type)
1216887d61b2STaylor Simpson {
1217c2b33d0bSTaylor Simpson     gen_log_vreg_write(ctx, srcoff, num ^ 0, type);
1218887d61b2STaylor Simpson     srcoff += sizeof(MMVector);
1219c2b33d0bSTaylor Simpson     gen_log_vreg_write(ctx, srcoff, num ^ 1, type);
1220887d61b2STaylor Simpson }
1221887d61b2STaylor Simpson 
1222c2b33d0bSTaylor Simpson static intptr_t get_result_qreg(DisasContext *ctx, int qnum)
1223887d61b2STaylor Simpson {
1224b8552985STaylor Simpson     if (ctx->need_commit) {
1225c2b33d0bSTaylor Simpson         return  offsetof(CPUHexagonState, future_QRegs[qnum]);
1226b8552985STaylor Simpson     } else {
1227b8552985STaylor Simpson         return  offsetof(CPUHexagonState, QRegs[qnum]);
1228b8552985STaylor Simpson     }
1229887d61b2STaylor Simpson }
1230887d61b2STaylor Simpson 
1231887d61b2STaylor Simpson static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src,
1232887d61b2STaylor Simpson                           bool aligned)
1233887d61b2STaylor Simpson {
1234887d61b2STaylor Simpson     TCGv_i64 tmp = tcg_temp_new_i64();
1235887d61b2STaylor Simpson     if (aligned) {
1236887d61b2STaylor Simpson         tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1));
1237887d61b2STaylor Simpson     }
1238887d61b2STaylor Simpson     for (int i = 0; i < sizeof(MMVector) / 8; i++) {
123953b26d25SRichard Henderson         tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_TEUQ);
1240887d61b2STaylor Simpson         tcg_gen_addi_tl(src, src, 8);
1241887d61b2STaylor Simpson         tcg_gen_st_i64(tmp, cpu_env, dstoff + i * 8);
1242887d61b2STaylor Simpson     }
1243887d61b2STaylor Simpson }
1244887d61b2STaylor Simpson 
12451e536334STaylor Simpson static void gen_vreg_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
12461e536334STaylor Simpson                            int slot, bool aligned)
1247887d61b2STaylor Simpson {
1248887d61b2STaylor Simpson     intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
1249887d61b2STaylor Simpson     intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
1250887d61b2STaylor Simpson 
12511e536334STaylor Simpson     if (is_gather_store_insn(ctx)) {
1252887d61b2STaylor Simpson         TCGv sl = tcg_constant_tl(slot);
1253887d61b2STaylor Simpson         gen_helper_gather_store(cpu_env, EA, sl);
1254887d61b2STaylor Simpson         return;
1255887d61b2STaylor Simpson     }
1256887d61b2STaylor Simpson 
1257887d61b2STaylor Simpson     tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
1258887d61b2STaylor Simpson     if (aligned) {
1259887d61b2STaylor Simpson         tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
1260887d61b2STaylor Simpson                         ~((int32_t)sizeof(MMVector) - 1));
1261887d61b2STaylor Simpson     } else {
1262887d61b2STaylor Simpson         tcg_gen_mov_tl(hex_vstore_addr[slot], EA);
1263887d61b2STaylor Simpson     }
1264887d61b2STaylor Simpson     tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
1265887d61b2STaylor Simpson 
1266887d61b2STaylor Simpson     /* Copy the data to the vstore buffer */
1267887d61b2STaylor Simpson     tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
1268887d61b2STaylor Simpson     /* Set the mask to all 1's */
1269887d61b2STaylor Simpson     tcg_gen_gvec_dup_imm(MO_64, maskoff, sizeof(MMQReg), sizeof(MMQReg), ~0LL);
1270887d61b2STaylor Simpson }
1271887d61b2STaylor Simpson 
1272887d61b2STaylor Simpson static void gen_vreg_masked_store(DisasContext *ctx, TCGv EA, intptr_t srcoff,
1273887d61b2STaylor Simpson                                   intptr_t bitsoff, int slot, bool invert)
1274887d61b2STaylor Simpson {
1275887d61b2STaylor Simpson     intptr_t dstoff = offsetof(CPUHexagonState, vstore[slot].data);
1276887d61b2STaylor Simpson     intptr_t maskoff = offsetof(CPUHexagonState, vstore[slot].mask);
1277887d61b2STaylor Simpson 
1278887d61b2STaylor Simpson     tcg_gen_movi_tl(hex_vstore_pending[slot], 1);
1279887d61b2STaylor Simpson     tcg_gen_andi_tl(hex_vstore_addr[slot], EA,
1280887d61b2STaylor Simpson                     ~((int32_t)sizeof(MMVector) - 1));
1281887d61b2STaylor Simpson     tcg_gen_movi_tl(hex_vstore_size[slot], sizeof(MMVector));
1282887d61b2STaylor Simpson 
1283887d61b2STaylor Simpson     /* Copy the data to the vstore buffer */
1284887d61b2STaylor Simpson     tcg_gen_gvec_mov(MO_64, dstoff, srcoff, sizeof(MMVector), sizeof(MMVector));
1285887d61b2STaylor Simpson     /* Copy the mask */
1286887d61b2STaylor Simpson     tcg_gen_gvec_mov(MO_64, maskoff, bitsoff, sizeof(MMQReg), sizeof(MMQReg));
1287887d61b2STaylor Simpson     if (invert) {
1288887d61b2STaylor Simpson         tcg_gen_gvec_not(MO_64, maskoff, maskoff,
1289887d61b2STaylor Simpson                          sizeof(MMQReg), sizeof(MMQReg));
1290887d61b2STaylor Simpson     }
1291887d61b2STaylor Simpson }
1292887d61b2STaylor Simpson 
1293887d61b2STaylor Simpson static void vec_to_qvec(size_t size, intptr_t dstoff, intptr_t srcoff)
1294887d61b2STaylor Simpson {
1295887d61b2STaylor Simpson     TCGv_i64 tmp = tcg_temp_new_i64();
1296887d61b2STaylor Simpson     TCGv_i64 word = tcg_temp_new_i64();
1297887d61b2STaylor Simpson     TCGv_i64 bits = tcg_temp_new_i64();
1298887d61b2STaylor Simpson     TCGv_i64 mask = tcg_temp_new_i64();
1299887d61b2STaylor Simpson     TCGv_i64 zero = tcg_constant_i64(0);
1300887d61b2STaylor Simpson     TCGv_i64 ones = tcg_constant_i64(~0);
1301887d61b2STaylor Simpson 
1302887d61b2STaylor Simpson     for (int i = 0; i < sizeof(MMVector) / 8; i++) {
1303887d61b2STaylor Simpson         tcg_gen_ld_i64(tmp, cpu_env, srcoff + i * 8);
1304887d61b2STaylor Simpson         tcg_gen_movi_i64(mask, 0);
1305887d61b2STaylor Simpson 
1306887d61b2STaylor Simpson         for (int j = 0; j < 8; j += size) {
1307887d61b2STaylor Simpson             tcg_gen_extract_i64(word, tmp, j * 8, size * 8);
1308887d61b2STaylor Simpson             tcg_gen_movcond_i64(TCG_COND_NE, bits, word, zero, ones, zero);
1309887d61b2STaylor Simpson             tcg_gen_deposit_i64(mask, mask, bits, j, size);
1310887d61b2STaylor Simpson         }
1311887d61b2STaylor Simpson 
1312887d61b2STaylor Simpson         tcg_gen_st8_i64(mask, cpu_env, dstoff + i);
1313887d61b2STaylor Simpson     }
1314887d61b2STaylor Simpson }
1315887d61b2STaylor Simpson 
13167e8b3b39SPaolo Montesel void probe_noshuf_load(TCGv va, int s, int mi)
131715fc6badSTaylor Simpson {
131815fc6badSTaylor Simpson     TCGv size = tcg_constant_tl(s);
131915fc6badSTaylor Simpson     TCGv mem_idx = tcg_constant_tl(mi);
132015fc6badSTaylor Simpson     gen_helper_probe_noshuf_load(cpu_env, va, size, mem_idx);
132115fc6badSTaylor Simpson }
132215fc6badSTaylor Simpson 
132342659e04SNiccolò Izzo /*
132442659e04SNiccolò Izzo  * Note: Since this function might branch, `val` is
132542659e04SNiccolò Izzo  * required to be a `tcg_temp_local`.
132642659e04SNiccolò Izzo  */
1327148ef7fdSTaylor Simpson void gen_set_usr_field_if(DisasContext *ctx, int field, TCGv val)
132842659e04SNiccolò Izzo {
132942659e04SNiccolò Izzo     /* Sets the USR field if `val` is non-zero */
133042659e04SNiccolò Izzo     if (reg_field_info[field].width == 1) {
1331148ef7fdSTaylor Simpson         TCGv usr = get_result_gpr(ctx, HEX_REG_USR);
133242659e04SNiccolò Izzo         TCGv tmp = tcg_temp_new();
133342659e04SNiccolò Izzo         tcg_gen_extract_tl(tmp, val, 0, reg_field_info[field].width);
133442659e04SNiccolò Izzo         tcg_gen_shli_tl(tmp, tmp, reg_field_info[field].offset);
1335148ef7fdSTaylor Simpson         tcg_gen_or_tl(usr, usr, tmp);
133642659e04SNiccolò Izzo     } else {
133742659e04SNiccolò Izzo         TCGLabel *skip_label = gen_new_label();
133842659e04SNiccolò Izzo         tcg_gen_brcondi_tl(TCG_COND_EQ, val, 0, skip_label);
1339148ef7fdSTaylor Simpson         gen_set_usr_field(ctx, field, val);
134042659e04SNiccolò Izzo         gen_set_label(skip_label);
134142659e04SNiccolò Izzo     }
134242659e04SNiccolò Izzo }
134342659e04SNiccolò Izzo 
134442659e04SNiccolò Izzo void gen_sat_i32(TCGv dest, TCGv source, int width)
134542659e04SNiccolò Izzo {
134642659e04SNiccolò Izzo     TCGv max_val = tcg_constant_tl((1 << (width - 1)) - 1);
134742659e04SNiccolò Izzo     TCGv min_val = tcg_constant_tl(-(1 << (width - 1)));
134842659e04SNiccolò Izzo     tcg_gen_smin_tl(dest, source, max_val);
134942659e04SNiccolò Izzo     tcg_gen_smax_tl(dest, dest, min_val);
135042659e04SNiccolò Izzo }
135142659e04SNiccolò Izzo 
135242659e04SNiccolò Izzo void gen_sat_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
135342659e04SNiccolò Izzo {
135471ed3697STaylor Simpson     TCGv tmp = tcg_temp_new();    /* In case dest == source */
135571ed3697STaylor Simpson     gen_sat_i32(tmp, source, width);
135671ed3697STaylor Simpson     tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp);
135771ed3697STaylor Simpson     tcg_gen_mov_tl(dest, tmp);
135842659e04SNiccolò Izzo }
135942659e04SNiccolò Izzo 
136042659e04SNiccolò Izzo void gen_satu_i32(TCGv dest, TCGv source, int width)
136142659e04SNiccolò Izzo {
136271ed3697STaylor Simpson     TCGv tmp = tcg_temp_new();    /* In case dest == source */
136342659e04SNiccolò Izzo     TCGv max_val = tcg_constant_tl((1 << width) - 1);
136442659e04SNiccolò Izzo     TCGv zero = tcg_constant_tl(0);
136571ed3697STaylor Simpson     tcg_gen_movcond_tl(TCG_COND_GTU, tmp, source, max_val, max_val, source);
136671ed3697STaylor Simpson     tcg_gen_movcond_tl(TCG_COND_LT, tmp, source, zero, zero, tmp);
136771ed3697STaylor Simpson     tcg_gen_mov_tl(dest, tmp);
136842659e04SNiccolò Izzo }
136942659e04SNiccolò Izzo 
137042659e04SNiccolò Izzo void gen_satu_i32_ovfl(TCGv ovfl, TCGv dest, TCGv source, int width)
137142659e04SNiccolò Izzo {
137271ed3697STaylor Simpson     TCGv tmp = tcg_temp_new();    /* In case dest == source */
137371ed3697STaylor Simpson     gen_satu_i32(tmp, source, width);
137471ed3697STaylor Simpson     tcg_gen_setcond_tl(TCG_COND_NE, ovfl, source, tmp);
137571ed3697STaylor Simpson     tcg_gen_mov_tl(dest, tmp);
137642659e04SNiccolò Izzo }
137742659e04SNiccolò Izzo 
137842659e04SNiccolò Izzo void gen_sat_i64(TCGv_i64 dest, TCGv_i64 source, int width)
137942659e04SNiccolò Izzo {
138042659e04SNiccolò Izzo     TCGv_i64 max_val = tcg_constant_i64((1LL << (width - 1)) - 1LL);
138142659e04SNiccolò Izzo     TCGv_i64 min_val = tcg_constant_i64(-(1LL << (width - 1)));
138242659e04SNiccolò Izzo     tcg_gen_smin_i64(dest, source, max_val);
138342659e04SNiccolò Izzo     tcg_gen_smax_i64(dest, dest, min_val);
138442659e04SNiccolò Izzo }
138542659e04SNiccolò Izzo 
138642659e04SNiccolò Izzo void gen_sat_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
138742659e04SNiccolò Izzo {
138871ed3697STaylor Simpson     TCGv_i64 tmp = tcg_temp_new_i64(); /* In case dest == source */
138942659e04SNiccolò Izzo     TCGv_i64 ovfl_64;
139071ed3697STaylor Simpson     gen_sat_i64(tmp, source, width);
139142659e04SNiccolò Izzo     ovfl_64 = tcg_temp_new_i64();
139271ed3697STaylor Simpson     tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source);
139371ed3697STaylor Simpson     tcg_gen_mov_i64(dest, tmp);
139442659e04SNiccolò Izzo     tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
139542659e04SNiccolò Izzo }
139642659e04SNiccolò Izzo 
139742659e04SNiccolò Izzo void gen_satu_i64(TCGv_i64 dest, TCGv_i64 source, int width)
139842659e04SNiccolò Izzo {
139971ed3697STaylor Simpson     TCGv_i64 tmp = tcg_temp_new_i64();    /* In case dest == source */
140042659e04SNiccolò Izzo     TCGv_i64 max_val = tcg_constant_i64((1LL << width) - 1LL);
140142659e04SNiccolò Izzo     TCGv_i64 zero = tcg_constant_i64(0);
140271ed3697STaylor Simpson     tcg_gen_movcond_i64(TCG_COND_GTU, tmp, source, max_val, max_val, source);
140371ed3697STaylor Simpson     tcg_gen_movcond_i64(TCG_COND_LT, tmp, source, zero, zero, tmp);
140471ed3697STaylor Simpson     tcg_gen_mov_i64(dest, tmp);
140542659e04SNiccolò Izzo }
140642659e04SNiccolò Izzo 
140742659e04SNiccolò Izzo void gen_satu_i64_ovfl(TCGv ovfl, TCGv_i64 dest, TCGv_i64 source, int width)
140842659e04SNiccolò Izzo {
140971ed3697STaylor Simpson     TCGv_i64 tmp = tcg_temp_new_i64();    /* In case dest == source */
141042659e04SNiccolò Izzo     TCGv_i64 ovfl_64;
141171ed3697STaylor Simpson     gen_satu_i64(tmp, source, width);
141242659e04SNiccolò Izzo     ovfl_64 = tcg_temp_new_i64();
141371ed3697STaylor Simpson     tcg_gen_setcond_i64(TCG_COND_NE, ovfl_64, tmp, source);
141471ed3697STaylor Simpson     tcg_gen_mov_i64(dest, tmp);
141542659e04SNiccolò Izzo     tcg_gen_trunc_i64_tl(ovfl, ovfl_64);
141642659e04SNiccolò Izzo }
141742659e04SNiccolò Izzo 
141842659e04SNiccolò Izzo /* Implements the fADDSAT64 macro in TCG */
1419148ef7fdSTaylor Simpson void gen_add_sat_i64(DisasContext *ctx, TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b)
142042659e04SNiccolò Izzo {
14217a819de8SRichard Henderson     TCGv_i64 sum = tcg_temp_new_i64();
142242659e04SNiccolò Izzo     TCGv_i64 xor = tcg_temp_new_i64();
142342659e04SNiccolò Izzo     TCGv_i64 cond1 = tcg_temp_new_i64();
14247a819de8SRichard Henderson     TCGv_i64 cond2 = tcg_temp_new_i64();
142542659e04SNiccolò Izzo     TCGv_i64 cond3 = tcg_temp_new_i64();
142642659e04SNiccolò Izzo     TCGv_i64 mask = tcg_constant_i64(0x8000000000000000ULL);
142742659e04SNiccolò Izzo     TCGv_i64 max_pos = tcg_constant_i64(0x7FFFFFFFFFFFFFFFLL);
142842659e04SNiccolò Izzo     TCGv_i64 max_neg = tcg_constant_i64(0x8000000000000000LL);
142942659e04SNiccolò Izzo     TCGv_i64 zero = tcg_constant_i64(0);
143042659e04SNiccolò Izzo     TCGLabel *no_ovfl_label = gen_new_label();
143142659e04SNiccolò Izzo     TCGLabel *ovfl_label = gen_new_label();
143242659e04SNiccolò Izzo     TCGLabel *ret_label = gen_new_label();
143342659e04SNiccolò Izzo 
143442659e04SNiccolò Izzo     tcg_gen_add_i64(sum, a, b);
143542659e04SNiccolò Izzo     tcg_gen_xor_i64(xor, a, b);
143642659e04SNiccolò Izzo 
143742659e04SNiccolò Izzo     /* if (xor & mask) */
143842659e04SNiccolò Izzo     tcg_gen_and_i64(cond1, xor, mask);
143942659e04SNiccolò Izzo     tcg_gen_brcondi_i64(TCG_COND_NE, cond1, 0, no_ovfl_label);
144042659e04SNiccolò Izzo 
144142659e04SNiccolò Izzo     /* else if ((a ^ sum) & mask) */
144242659e04SNiccolò Izzo     tcg_gen_xor_i64(cond2, a, sum);
144342659e04SNiccolò Izzo     tcg_gen_and_i64(cond2, cond2, mask);
144442659e04SNiccolò Izzo     tcg_gen_brcondi_i64(TCG_COND_NE, cond2, 0, ovfl_label);
144542659e04SNiccolò Izzo     /* fallthrough to no_ovfl_label branch */
144642659e04SNiccolò Izzo 
144742659e04SNiccolò Izzo     /* if branch */
144842659e04SNiccolò Izzo     gen_set_label(no_ovfl_label);
144942659e04SNiccolò Izzo     tcg_gen_mov_i64(ret, sum);
145042659e04SNiccolò Izzo     tcg_gen_br(ret_label);
145142659e04SNiccolò Izzo 
145242659e04SNiccolò Izzo     /* else if branch */
145342659e04SNiccolò Izzo     gen_set_label(ovfl_label);
145442659e04SNiccolò Izzo     tcg_gen_and_i64(cond3, sum, mask);
145542659e04SNiccolò Izzo     tcg_gen_movcond_i64(TCG_COND_NE, ret, cond3, zero, max_pos, max_neg);
1456148ef7fdSTaylor Simpson     gen_set_usr_fieldi(ctx, USR_OVF, 1);
145742659e04SNiccolò Izzo 
145842659e04SNiccolò Izzo     gen_set_label(ret_label);
145942659e04SNiccolò Izzo }
146042659e04SNiccolò Izzo 
146157acfcdeSTaylor Simpson #include "tcg_funcs_generated.c.inc"
146257acfcdeSTaylor Simpson #include "tcg_func_table_generated.c.inc"
1463