master
inc 340 lines 8.47 KB
Raw
1 /*
2 * RISC-V translation routines for the Zc[b,mp,mt] Standard Extensions.
3 *
4 * Copyright (c) 2021-2022 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_ZCB(ctx) do { \
20 if (!ctx->cfg_ptr->ext_zcb) \
21 return false; \
22 } while (0)
23
24 #define REQUIRE_ZCMP(ctx) do { \
25 if (!ctx->cfg_ptr->ext_zcmp) \
26 return false; \
27 } while (0)
28
29 #define REQUIRE_ZCMT(ctx) do { \
30 if (!ctx->cfg_ptr->ext_zcmt) \
31 return false; \
32 } while (0)
33
34 static bool trans_c_zext_b(DisasContext *ctx, arg_c_zext_b *a)
35 {
36 REQUIRE_ZCB(ctx);
37 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8u_tl);
38 }
39
40 static bool trans_c_zext_h(DisasContext *ctx, arg_c_zext_h *a)
41 {
42 REQUIRE_ZCB(ctx);
43 REQUIRE_ZBB(ctx);
44 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16u_tl);
45 }
46
47 static bool trans_c_sext_b(DisasContext *ctx, arg_c_sext_b *a)
48 {
49 REQUIRE_ZCB(ctx);
50 REQUIRE_ZBB(ctx);
51 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext8s_tl);
52 }
53
54 static bool trans_c_sext_h(DisasContext *ctx, arg_c_sext_h *a)
55 {
56 REQUIRE_ZCB(ctx);
57 REQUIRE_ZBB(ctx);
58 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16s_tl);
59 }
60
61 static bool trans_c_zext_w(DisasContext *ctx, arg_c_zext_w *a)
62 {
63 REQUIRE_64BIT(ctx);
64 REQUIRE_ZCB(ctx);
65 REQUIRE_ZBA(ctx);
66 return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext32u_tl);
67 }
68
69 static bool trans_c_not(DisasContext *ctx, arg_c_not *a)
70 {
71 REQUIRE_ZCB(ctx);
72 return gen_unary(ctx, a, EXT_NONE, tcg_gen_not_tl);
73 }
74
75 static bool trans_c_mul(DisasContext *ctx, arg_c_mul *a)
76 {
77 REQUIRE_ZCB(ctx);
78 REQUIRE_M_OR_ZMMUL(ctx);
79 return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl, NULL);
80 }
81
82 static bool trans_c_lbu(DisasContext *ctx, arg_c_lbu *a)
83 {
84 REQUIRE_ZCB(ctx);
85 return gen_load(ctx, a, MO_UB);
86 }
87
88 static bool trans_c_lhu(DisasContext *ctx, arg_c_lhu *a)
89 {
90 REQUIRE_ZCB(ctx);
91 return gen_load(ctx, a, MO_UW);
92 }
93
94 static bool trans_c_lh(DisasContext *ctx, arg_c_lh *a)
95 {
96 REQUIRE_ZCB(ctx);
97 return gen_load(ctx, a, MO_SW);
98 }
99
100 static bool trans_c_sb(DisasContext *ctx, arg_c_sb *a)
101 {
102 REQUIRE_ZCB(ctx);
103 return gen_store(ctx, a, MO_UB);
104 }
105
106 static bool trans_c_sh(DisasContext *ctx, arg_c_sh *a)
107 {
108 REQUIRE_ZCB(ctx);
109 return gen_store(ctx, a, MO_UW);
110 }
111
112 #define X_S0 8
113 #define X_S1 9
114 #define X_Sn 16
115
116 static uint32_t decode_push_pop_list(DisasContext *ctx, target_ulong rlist)
117 {
118 uint32_t reg_bitmap = 0;
119
120 if (has_ext(ctx, RVE) && rlist > 6) {
121 return 0;
122 }
123
124 switch (rlist) {
125 case 15:
126 reg_bitmap |= 1 << (X_Sn + 11) ;
127 reg_bitmap |= 1 << (X_Sn + 10) ;
128 /* FALL THROUGH */
129 case 14:
130 reg_bitmap |= 1 << (X_Sn + 9) ;
131 /* FALL THROUGH */
132 case 13:
133 reg_bitmap |= 1 << (X_Sn + 8) ;
134 /* FALL THROUGH */
135 case 12:
136 reg_bitmap |= 1 << (X_Sn + 7) ;
137 /* FALL THROUGH */
138 case 11:
139 reg_bitmap |= 1 << (X_Sn + 6) ;
140 /* FALL THROUGH */
141 case 10:
142 reg_bitmap |= 1 << (X_Sn + 5) ;
143 /* FALL THROUGH */
144 case 9:
145 reg_bitmap |= 1 << (X_Sn + 4) ;
146 /* FALL THROUGH */
147 case 8:
148 reg_bitmap |= 1 << (X_Sn + 3) ;
149 /* FALL THROUGH */
150 case 7:
151 reg_bitmap |= 1 << (X_Sn + 2) ;
152 /* FALL THROUGH */
153 case 6:
154 reg_bitmap |= 1 << X_S1 ;
155 /* FALL THROUGH */
156 case 5:
157 reg_bitmap |= 1 << X_S0;
158 /* FALL THROUGH */
159 case 4:
160 reg_bitmap |= 1 << xRA;
161 break;
162 default:
163 break;
164 }
165
166 return reg_bitmap;
167 }
168
169 static bool gen_pop(DisasContext *ctx, arg_cmpp *a, bool ret, bool ret_val)
170 {
171 REQUIRE_ZCMP(ctx);
172
173 uint32_t reg_bitmap = decode_push_pop_list(ctx, a->urlist);
174 if (reg_bitmap == 0) {
175 return false;
176 }
177
178 MemOp memop = get_ol(ctx) == MXL_RV32 ? MO_UL : MO_UQ;
179 int reg_size = memop_size(memop);
180 target_ulong stack_adj = ROUND_UP(ctpop32(reg_bitmap) * reg_size, 16) +
181 a->spimm;
182 TCGv sp = dest_gpr(ctx, xSP);
183 TCGv addr = tcg_temp_new();
184 int i;
185
186 tcg_gen_addi_tl(addr, sp, stack_adj - reg_size);
187
188 memop |= ctx->mo_endianness;
189 for (i = X_Sn + 11; i >= 0; i--) {
190 if (reg_bitmap & (1 << i)) {
191 TCGv dest = dest_gpr(ctx, i);
192 tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop);
193 gen_set_gpr(ctx, i, dest);
194 tcg_gen_subi_tl(addr, addr, reg_size);
195 }
196 }
197
198 tcg_gen_addi_tl(sp, sp, stack_adj);
199 gen_set_gpr(ctx, xSP, sp);
200
201 if (ret_val) {
202 gen_set_gpr(ctx, xA0, ctx->zero);
203 }
204
205 if (ret) {
206 TCGv ret_addr = get_gpr(ctx, xRA, EXT_SIGN);
207 #ifndef CONFIG_USER_ONLY
208 if (ctx->cfg_ptr->ext_smctr || ctx->cfg_ptr->ext_ssctr) {
209 TCGv type = tcg_constant_tl(CTRDATA_TYPE_RETURN);
210 TCGv src = tcg_temp_new();
211 gen_pc_plus_diff(src, ctx, 0);
212 gen_helper_ctr_add_entry(tcg_env, src, ret_addr, type);
213 }
214 #endif
215 tcg_gen_mov_tl(cpu_pc, ret_addr);
216 tcg_gen_lookup_and_goto_ptr();
217 ctx->base.is_jmp = DISAS_NORETURN;
218 }
219
220 return true;
221 }
222
223 static bool trans_cm_push(DisasContext *ctx, arg_cm_push *a)
224 {
225 REQUIRE_ZCMP(ctx);
226
227 uint32_t reg_bitmap = decode_push_pop_list(ctx, a->urlist);
228 if (reg_bitmap == 0) {
229 return false;
230 }
231
232 MemOp memop = get_ol(ctx) == MXL_RV32 ? MO_UL : MO_UQ;
233 int reg_size = memop_size(memop);
234 target_ulong stack_adj = ROUND_UP(ctpop32(reg_bitmap) * reg_size, 16) +
235 a->spimm;
236 TCGv sp = dest_gpr(ctx, xSP);
237 TCGv addr = tcg_temp_new();
238 int i;
239
240 tcg_gen_subi_tl(addr, sp, reg_size);
241
242 memop |= ctx->mo_endianness;
243 for (i = X_Sn + 11; i >= 0; i--) {
244 if (reg_bitmap & (1 << i)) {
245 TCGv val = get_gpr(ctx, i, EXT_NONE);
246 tcg_gen_qemu_st_tl(val, addr, ctx->mem_idx, memop);
247 tcg_gen_subi_tl(addr, addr, reg_size);
248 }
249 }
250
251 tcg_gen_subi_tl(sp, sp, stack_adj);
252 gen_set_gpr(ctx, xSP, sp);
253
254 return true;
255 }
256
257 static bool trans_cm_pop(DisasContext *ctx, arg_cm_pop *a)
258 {
259 return gen_pop(ctx, a, false, false);
260 }
261
262 static bool trans_cm_popret(DisasContext *ctx, arg_cm_popret *a)
263 {
264 return gen_pop(ctx, a, true, false);
265 }
266
267 static bool trans_cm_popretz(DisasContext *ctx, arg_cm_popret *a)
268 {
269 return gen_pop(ctx, a, true, true);
270 }
271
272 static bool trans_cm_mva01s(DisasContext *ctx, arg_cm_mva01s *a)
273 {
274 REQUIRE_ZCMP(ctx);
275
276 TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
277 TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
278
279 gen_set_gpr(ctx, xA0, src1);
280 gen_set_gpr(ctx, xA1, src2);
281
282 return true;
283 }
284
285 static bool trans_cm_mvsa01(DisasContext *ctx, arg_cm_mvsa01 *a)
286 {
287 REQUIRE_ZCMP(ctx);
288
289 if (a->rs1 == a->rs2) {
290 return false;
291 }
292
293 TCGv a0 = get_gpr(ctx, xA0, EXT_NONE);
294 TCGv a1 = get_gpr(ctx, xA1, EXT_NONE);
295
296 gen_set_gpr(ctx, a->rs1, a0);
297 gen_set_gpr(ctx, a->rs2, a1);
298
299 return true;
300 }
301
302 static bool trans_cm_jalt(DisasContext *ctx, arg_cm_jalt *a)
303 {
304 REQUIRE_ZCMT(ctx);
305
306 TCGv addr = tcg_temp_new();
307
308 /*
309 * Update pc to current for the non-unwinding exception
310 * that might come from cpu_ld*_code() in the helper.
311 */
312 gen_update_pc(ctx, 0);
313 gen_helper_cm_jalt(addr, tcg_env, tcg_constant_i32(a->index));
314
315 /* c.jt vs c.jalt depends on the index. */
316 if (a->index >= 32) {
317 TCGv succ_pc = dest_gpr(ctx, xRA);
318 gen_pc_plus_diff(succ_pc, ctx, ctx->cur_insn_len);
319 gen_set_gpr(ctx, xRA, succ_pc);
320 }
321
322 #ifndef CONFIG_USER_ONLY
323 if (ctx->cfg_ptr->ext_smctr || ctx->cfg_ptr->ext_ssctr) {
324 if (a->index >= 32) {
325 TCGv type = tcg_constant_tl(CTRDATA_TYPE_DIRECT_CALL);
326 gen_helper_ctr_add_entry(tcg_env, cpu_pc, addr, type);
327 } else {
328 TCGv type = tcg_constant_tl(CTRDATA_TYPE_DIRECT_JUMP);
329 gen_helper_ctr_add_entry(tcg_env, cpu_pc, addr, type);
330 }
331 }
332 #endif
333
334
335 tcg_gen_mov_tl(cpu_pc, addr);
336
337 tcg_gen_lookup_and_goto_ptr();
338 ctx->base.is_jmp = DISAS_NORETURN;
339 return true;
340 }