master
inc 224 lines 4.96 KB
Raw
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * Copyright (c) 2021 Loongson Technology Corporation Limited
4 */
5
6 static const uint32_t fcsr_mask[4] = {
7 UINT32_MAX, FCSR0_M1, FCSR0_M2, FCSR0_M3
8 };
9
10 static bool trans_fsel(DisasContext *ctx, arg_fsel *a)
11 {
12 TCGv zero = tcg_constant_tl(0);
13 TCGv dest = get_fpr(ctx, a->fd);
14 TCGv src1 = get_fpr(ctx, a->fj);
15 TCGv src2 = get_fpr(ctx, a->fk);
16 TCGv cond;
17
18 if (!avail_FP(ctx)) {
19 return false;
20 }
21
22 CHECK_FPE;
23
24 cond = tcg_temp_new();
25 tcg_gen_ld8u_tl(cond, tcg_env, offsetof(CPULoongArchState, cf[a->ca]));
26 tcg_gen_movcond_tl(TCG_COND_EQ, dest, cond, zero, src1, src2);
27 set_fpr(a->fd, dest);
28
29 return true;
30 }
31
32 static bool gen_f2f(DisasContext *ctx, arg_ff *a,
33 void (*func)(TCGv, TCGv), bool nanbox)
34 {
35 TCGv dest = get_fpr(ctx, a->fd);
36 TCGv src = get_fpr(ctx, a->fj);
37
38 CHECK_FPE;
39
40 func(dest, src);
41 if (nanbox) {
42 gen_nanbox_s(dest, dest);
43 }
44 set_fpr(a->fd, dest);
45
46 return true;
47 }
48
49 static bool gen_r2f(DisasContext *ctx, arg_fr *a,
50 void (*func)(TCGv, TCGv))
51 {
52 TCGv src = gpr_src(ctx, a->rj, EXT_NONE);
53 TCGv dest = get_fpr(ctx, a->fd);
54
55 if (!avail_FP(ctx)) {
56 return false;
57 }
58
59 CHECK_FPE;
60
61 func(dest, src);
62 set_fpr(a->fd, dest);
63
64 return true;
65 }
66
67 static bool gen_f2r(DisasContext *ctx, arg_rf *a,
68 void (*func)(TCGv, TCGv))
69 {
70 TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
71 TCGv src = get_fpr(ctx, a->fj);
72
73 if (!avail_FP(ctx)) {
74 return false;
75 }
76
77 CHECK_FPE;
78
79 func(dest, src);
80 gen_set_gpr(a->rd, dest, EXT_NONE);
81
82 return true;
83 }
84
85 static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a)
86 {
87 uint32_t mask = fcsr_mask[a->fcsrd];
88 TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE);
89
90 if (!avail_FP(ctx)) {
91 return false;
92 }
93
94 CHECK_FPE;
95
96 if (mask == UINT32_MAX) {
97 tcg_gen_st32_i64(Rj, tcg_env, offsetof(CPULoongArchState, fcsr0));
98 } else {
99 TCGv_i32 fcsr0 = tcg_temp_new_i32();
100 TCGv_i32 temp = tcg_temp_new_i32();
101
102 tcg_gen_ld_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0));
103 tcg_gen_extrl_i64_i32(temp, Rj);
104 tcg_gen_andi_i32(temp, temp, mask);
105 tcg_gen_andi_i32(fcsr0, fcsr0, ~mask);
106 tcg_gen_or_i32(fcsr0, fcsr0, temp);
107 tcg_gen_st_i32(fcsr0, tcg_env, offsetof(CPULoongArchState, fcsr0));
108 }
109
110 /*
111 * Install the new rounding mode to fpu_status, if changed.
112 * Note that FCSR3 is exactly the rounding mode field.
113 */
114 if (mask & FCSR0_M3) {
115 gen_helper_set_rounding_mode(tcg_env);
116 }
117 return true;
118 }
119
120 static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a)
121 {
122 TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
123
124 if (!avail_FP(ctx)) {
125 return false;
126 }
127
128 CHECK_FPE;
129
130 tcg_gen_ld32u_i64(dest, tcg_env, offsetof(CPULoongArchState, fcsr0));
131 tcg_gen_andi_i64(dest, dest, fcsr_mask[a->fcsrs]);
132 gen_set_gpr(a->rd, dest, EXT_NONE);
133
134 return true;
135 }
136
137 static void gen_movgr2fr_w(TCGv dest, TCGv src)
138 {
139 tcg_gen_deposit_i64(dest, dest, src, 0, 32);
140 }
141
142 static void gen_movgr2frh_w(TCGv dest, TCGv src)
143 {
144 tcg_gen_deposit_i64(dest, dest, src, 32, 32);
145 }
146
147 static void gen_movfrh2gr_s(TCGv dest, TCGv src)
148 {
149 tcg_gen_sextract_tl(dest, src, 32, 32);
150 }
151
152 static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a)
153 {
154 TCGv t0;
155 TCGv src = get_fpr(ctx, a->fj);
156
157 if (!avail_FP(ctx)) {
158 return false;
159 }
160
161 CHECK_FPE;
162
163 t0 = tcg_temp_new();
164 tcg_gen_andi_tl(t0, src, 0x1);
165 tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7]));
166
167 return true;
168 }
169
170 static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a)
171 {
172 TCGv dest = get_fpr(ctx, a->fd);
173
174 if (!avail_FP(ctx)) {
175 return false;
176 }
177
178 CHECK_FPE;
179
180 tcg_gen_ld8u_tl(dest, tcg_env,
181 offsetof(CPULoongArchState, cf[a->cj & 0x7]));
182 set_fpr(a->fd, dest);
183
184 return true;
185 }
186
187 static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a)
188 {
189 TCGv t0;
190
191 if (!avail_FP(ctx)) {
192 return false;
193 }
194
195 CHECK_FPE;
196
197 t0 = tcg_temp_new();
198 tcg_gen_andi_tl(t0, gpr_src(ctx, a->rj, EXT_NONE), 0x1);
199 tcg_gen_st8_tl(t0, tcg_env, offsetof(CPULoongArchState, cf[a->cd & 0x7]));
200
201 return true;
202 }
203
204 static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a)
205 {
206 if (!avail_FP(ctx)) {
207 return false;
208 }
209
210 CHECK_FPE;
211
212 tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), tcg_env,
213 offsetof(CPULoongArchState, cf[a->cj & 0x7]));
214 return true;
215 }
216
217 TRANS(fmov_s, FP_SP, gen_f2f, tcg_gen_mov_tl, true)
218 TRANS(fmov_d, FP_DP, gen_f2f, tcg_gen_mov_tl, false)
219 TRANS(movgr2fr_w, FP_SP, gen_r2f, gen_movgr2fr_w)
220 TRANS(movgr2fr_d, 64, gen_r2f, tcg_gen_mov_tl)
221 TRANS(movgr2frh_w, FP_DP, gen_r2f, gen_movgr2frh_w)
222 TRANS(movfr2gr_s, FP_SP, gen_f2r, tcg_gen_ext32s_tl)
223 TRANS(movfr2gr_d, 64, gen_f2r, tcg_gen_mov_tl)
224 TRANS(movfrh2gr_s, FP_DP, gen_f2r, gen_movfrh2gr_s)