1/*
2 * RISC-V translation routines for the BF16 Standard Extensions.
3 *
4 * Copyright (c) 2020-2023 PLCT Lab
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#define REQUIRE_ZFBFMIN(ctx) do { \
20    if (!ctx->cfg_ptr->ext_zfbfmin) { \
21        return false; \
22    } \
23} while (0)
24
25#define REQUIRE_ZVFBFMIN(ctx) do { \
26    if (!ctx->cfg_ptr->ext_zvfbfmin) { \
27        return false; \
28    } \
29} while (0)
30
31#define REQUIRE_ZVFBFWMA(ctx) do { \
32    if (!ctx->cfg_ptr->ext_zvfbfwma) { \
33        return false; \
34    } \
35} while (0)
36
37static bool trans_fcvt_bf16_s(DisasContext *ctx, arg_fcvt_bf16_s *a)
38{
39    REQUIRE_FPU;
40    REQUIRE_ZFBFMIN(ctx);
41
42    TCGv_i64 dest = dest_fpr(ctx, a->rd);
43    TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1);
44
45    gen_set_rm(ctx, a->rm);
46    gen_helper_fcvt_bf16_s(dest, tcg_env, src1);
47    gen_set_fpr_hs(ctx, a->rd, dest);
48    mark_fs_dirty(ctx);
49    return true;
50}
51
52static bool trans_fcvt_s_bf16(DisasContext *ctx, arg_fcvt_s_bf16 *a)
53{
54    REQUIRE_FPU;
55    REQUIRE_ZFBFMIN(ctx);
56
57    TCGv_i64 dest = dest_fpr(ctx, a->rd);
58    TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1);
59
60    gen_set_rm(ctx, a->rm);
61    gen_helper_fcvt_s_bf16(dest, tcg_env, src1);
62    gen_set_fpr_hs(ctx, a->rd, dest);
63    mark_fs_dirty(ctx);
64    return true;
65}
66
67static bool trans_vfncvtbf16_f_f_w(DisasContext *ctx, arg_vfncvtbf16_f_f_w *a)
68{
69    REQUIRE_FPU;
70    REQUIRE_ZVFBFMIN(ctx);
71
72    if (opfv_narrow_check(ctx, a) && (ctx->sew == MO_16)) {
73        uint32_t data = 0;
74
75        gen_set_rm_chkfrm(ctx, RISCV_FRM_DYN);
76
77        data = FIELD_DP32(data, VDATA, VM, a->vm);
78        data = FIELD_DP32(data, VDATA, LMUL, ctx->lmul);
79        data = FIELD_DP32(data, VDATA, VTA, ctx->vta);
80        data = FIELD_DP32(data, VDATA, VMA, ctx->vma);
81        tcg_gen_gvec_3_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0),
82                           vreg_ofs(ctx, a->rs2), tcg_env,
83                           ctx->cfg_ptr->vlenb,
84                           ctx->cfg_ptr->vlenb, data,
85                           gen_helper_vfncvtbf16_f_f_w);
86        finalize_rvv_inst(ctx);
87        return true;
88    }
89    return false;
90}
91
92static bool trans_vfwcvtbf16_f_f_v(DisasContext *ctx, arg_vfwcvtbf16_f_f_v *a)
93{
94    REQUIRE_FPU;
95    REQUIRE_ZVFBFMIN(ctx);
96
97    if (opfv_widen_check(ctx, a) && (ctx->sew == MO_16)) {
98        uint32_t data = 0;
99
100        gen_set_rm_chkfrm(ctx, RISCV_FRM_DYN);
101
102        data = FIELD_DP32(data, VDATA, VM, a->vm);
103        data = FIELD_DP32(data, VDATA, LMUL, ctx->lmul);
104        data = FIELD_DP32(data, VDATA, VTA, ctx->vta);
105        data = FIELD_DP32(data, VDATA, VMA, ctx->vma);
106        tcg_gen_gvec_3_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0),
107                           vreg_ofs(ctx, a->rs2), tcg_env,
108                           ctx->cfg_ptr->vlenb,
109                           ctx->cfg_ptr->vlenb, data,
110                           gen_helper_vfwcvtbf16_f_f_v);
111        finalize_rvv_inst(ctx);
112        return true;
113    }
114    return false;
115}
116
117static bool trans_vfwmaccbf16_vv(DisasContext *ctx, arg_vfwmaccbf16_vv *a)
118{
119    REQUIRE_FPU;
120    REQUIRE_ZVFBFWMA(ctx);
121
122    if (require_rvv(ctx) && vext_check_isa_ill(ctx) && (ctx->sew == MO_16) &&
123        vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm)) {
124        uint32_t data = 0;
125
126        gen_set_rm_chkfrm(ctx, RISCV_FRM_DYN);
127
128        data = FIELD_DP32(data, VDATA, VM, a->vm);
129        data = FIELD_DP32(data, VDATA, LMUL, ctx->lmul);
130        data = FIELD_DP32(data, VDATA, VTA, ctx->vta);
131        data = FIELD_DP32(data, VDATA, VMA, ctx->vma);
132        tcg_gen_gvec_4_ptr(vreg_ofs(ctx, a->rd), vreg_ofs(ctx, 0),
133                           vreg_ofs(ctx, a->rs1),
134                           vreg_ofs(ctx, a->rs2), tcg_env,
135                           ctx->cfg_ptr->vlenb,
136                           ctx->cfg_ptr->vlenb, data,
137                           gen_helper_vfwmaccbf16_vv);
138        finalize_rvv_inst(ctx);
139        return true;
140    }
141    return false;
142}
143
144static bool trans_vfwmaccbf16_vf(DisasContext *ctx, arg_vfwmaccbf16_vf *a)
145{
146    REQUIRE_FPU;
147    REQUIRE_ZVFBFWMA(ctx);
148
149    if (require_rvv(ctx) && (ctx->sew == MO_16) && vext_check_isa_ill(ctx) &&
150        vext_check_ds(ctx, a->rd, a->rs2, a->vm)) {
151        uint32_t data = 0;
152
153        gen_set_rm(ctx, RISCV_FRM_DYN);
154        data = FIELD_DP32(data, VDATA, VM, a->vm);
155        data = FIELD_DP32(data, VDATA, LMUL, ctx->lmul);
156        data = FIELD_DP32(data, VDATA, VTA, ctx->vta);
157        data = FIELD_DP32(data, VDATA, VMA, ctx->vma);
158        return opfvf_trans(a->rd, a->rs1, a->rs2, data,
159                           gen_helper_vfwmaccbf16_vf, ctx);
160    }
161
162    return false;
163}
164