2 * RISC-V translation routines for the RVXI Base Integer Instruction Set.
4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
5 * Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
6 * Bastian Koppelmann, kbastian@mail.uni-paderborn.de
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2 or later, as published by the Free Software Foundation.
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
21 static bool trans_lui(DisasContext
*ctx
, arg_lui
*a
)
24 tcg_gen_movi_tl(cpu_gpr
[a
->rd
], a
->imm
);
29 static bool trans_auipc(DisasContext
*ctx
, arg_auipc
*a
)
32 tcg_gen_movi_tl(cpu_gpr
[a
->rd
], a
->imm
+ ctx
->base
.pc_next
);
37 static bool trans_jal(DisasContext
*ctx
, arg_jal
*a
)
39 gen_jal(ctx
, a
->rd
, a
->imm
);
43 static bool trans_jalr(DisasContext
*ctx
, arg_jalr
*a
)
45 /* no chaining with JALR */
46 TCGLabel
*misaligned
= NULL
;
47 TCGv t0
= tcg_temp_new();
50 gen_get_gpr(cpu_pc
, a
->rs1
);
51 tcg_gen_addi_tl(cpu_pc
, cpu_pc
, a
->imm
);
52 tcg_gen_andi_tl(cpu_pc
, cpu_pc
, (target_ulong
)-2);
54 if (!has_ext(ctx
, RVC
)) {
55 misaligned
= gen_new_label();
56 tcg_gen_andi_tl(t0
, cpu_pc
, 0x2);
57 tcg_gen_brcondi_tl(TCG_COND_NE
, t0
, 0x0, misaligned
);
61 tcg_gen_movi_tl(cpu_gpr
[a
->rd
], ctx
->pc_succ_insn
);
63 tcg_gen_lookup_and_goto_ptr();
66 gen_set_label(misaligned
);
67 gen_exception_inst_addr_mis(ctx
);
69 ctx
->base
.is_jmp
= DISAS_NORETURN
;
75 static bool gen_branch(DisasContext
*ctx
, arg_b
*a
, TCGCond cond
)
77 TCGLabel
*l
= gen_new_label();
78 TCGv source1
, source2
;
79 source1
= tcg_temp_new();
80 source2
= tcg_temp_new();
81 gen_get_gpr(source1
, a
->rs1
);
82 gen_get_gpr(source2
, a
->rs2
);
84 tcg_gen_brcond_tl(cond
, source1
, source2
, l
);
85 gen_goto_tb(ctx
, 1, ctx
->pc_succ_insn
);
86 gen_set_label(l
); /* branch taken */
88 if (!has_ext(ctx
, RVC
) && ((ctx
->base
.pc_next
+ a
->imm
) & 0x3)) {
90 gen_exception_inst_addr_mis(ctx
);
92 gen_goto_tb(ctx
, 0, ctx
->base
.pc_next
+ a
->imm
);
94 ctx
->base
.is_jmp
= DISAS_NORETURN
;
96 tcg_temp_free(source1
);
97 tcg_temp_free(source2
);
102 static bool trans_beq(DisasContext
*ctx
, arg_beq
*a
)
104 return gen_branch(ctx
, a
, TCG_COND_EQ
);
107 static bool trans_bne(DisasContext
*ctx
, arg_bne
*a
)
109 return gen_branch(ctx
, a
, TCG_COND_NE
);
112 static bool trans_blt(DisasContext
*ctx
, arg_blt
*a
)
114 return gen_branch(ctx
, a
, TCG_COND_LT
);
117 static bool trans_bge(DisasContext
*ctx
, arg_bge
*a
)
119 return gen_branch(ctx
, a
, TCG_COND_GE
);
122 static bool trans_bltu(DisasContext
*ctx
, arg_bltu
*a
)
124 return gen_branch(ctx
, a
, TCG_COND_LTU
);
127 static bool trans_bgeu(DisasContext
*ctx
, arg_bgeu
*a
)
129 return gen_branch(ctx
, a
, TCG_COND_GEU
);
132 static bool gen_load(DisasContext
*ctx
, arg_lb
*a
, TCGMemOp memop
)
134 TCGv t0
= tcg_temp_new();
135 TCGv t1
= tcg_temp_new();
136 gen_get_gpr(t0
, a
->rs1
);
137 tcg_gen_addi_tl(t0
, t0
, a
->imm
);
139 tcg_gen_qemu_ld_tl(t1
, t0
, ctx
->mem_idx
, memop
);
140 gen_set_gpr(a
->rd
, t1
);
146 static bool trans_lb(DisasContext
*ctx
, arg_lb
*a
)
148 return gen_load(ctx
, a
, MO_SB
);
151 static bool trans_lh(DisasContext
*ctx
, arg_lh
*a
)
153 return gen_load(ctx
, a
, MO_TESW
);
156 static bool trans_lw(DisasContext
*ctx
, arg_lw
*a
)
158 return gen_load(ctx
, a
, MO_TESL
);
161 static bool trans_lbu(DisasContext
*ctx
, arg_lbu
*a
)
163 return gen_load(ctx
, a
, MO_UB
);
166 static bool trans_lhu(DisasContext
*ctx
, arg_lhu
*a
)
168 return gen_load(ctx
, a
, MO_TEUW
);
171 static bool gen_store(DisasContext
*ctx
, arg_sb
*a
, TCGMemOp memop
)
173 TCGv t0
= tcg_temp_new();
174 TCGv dat
= tcg_temp_new();
175 gen_get_gpr(t0
, a
->rs1
);
176 tcg_gen_addi_tl(t0
, t0
, a
->imm
);
177 gen_get_gpr(dat
, a
->rs2
);
179 tcg_gen_qemu_st_tl(dat
, t0
, ctx
->mem_idx
, memop
);
186 static bool trans_sb(DisasContext
*ctx
, arg_sb
*a
)
188 return gen_store(ctx
, a
, MO_SB
);
191 static bool trans_sh(DisasContext
*ctx
, arg_sh
*a
)
193 return gen_store(ctx
, a
, MO_TESW
);
196 static bool trans_sw(DisasContext
*ctx
, arg_sw
*a
)
198 return gen_store(ctx
, a
, MO_TESL
);
201 #ifdef TARGET_RISCV64
202 static bool trans_lwu(DisasContext
*ctx
, arg_lwu
*a
)
204 return gen_load(ctx
, a
, MO_TEUL
);
207 static bool trans_ld(DisasContext
*ctx
, arg_ld
*a
)
209 return gen_load(ctx
, a
, MO_TEQ
);
212 static bool trans_sd(DisasContext
*ctx
, arg_sd
*a
)
214 return gen_store(ctx
, a
, MO_TEQ
);
218 static bool trans_addi(DisasContext
*ctx
, arg_addi
*a
)
220 return gen_arith_imm(ctx
, a
, &tcg_gen_add_tl
);
223 static void gen_slt(TCGv ret
, TCGv s1
, TCGv s2
)
225 tcg_gen_setcond_tl(TCG_COND_LT
, ret
, s1
, s2
);
228 static void gen_sltu(TCGv ret
, TCGv s1
, TCGv s2
)
230 tcg_gen_setcond_tl(TCG_COND_LTU
, ret
, s1
, s2
);
234 static bool trans_slti(DisasContext
*ctx
, arg_slti
*a
)
236 return gen_arith_imm(ctx
, a
, &gen_slt
);
239 static bool trans_sltiu(DisasContext
*ctx
, arg_sltiu
*a
)
241 return gen_arith_imm(ctx
, a
, &gen_sltu
);
244 static bool trans_xori(DisasContext
*ctx
, arg_xori
*a
)
246 return gen_arith_imm(ctx
, a
, &tcg_gen_xor_tl
);
248 static bool trans_ori(DisasContext
*ctx
, arg_ori
*a
)
250 return gen_arith_imm(ctx
, a
, &tcg_gen_or_tl
);
252 static bool trans_andi(DisasContext
*ctx
, arg_andi
*a
)
254 return gen_arith_imm(ctx
, a
, &tcg_gen_and_tl
);
256 static bool trans_slli(DisasContext
*ctx
, arg_slli
*a
)
258 if (a
->shamt
>= TARGET_LONG_BITS
) {
263 TCGv t
= tcg_temp_new();
264 gen_get_gpr(t
, a
->rs1
);
266 tcg_gen_shli_tl(t
, t
, a
->shamt
);
268 gen_set_gpr(a
->rd
, t
);
270 } /* NOP otherwise */
274 static bool trans_srli(DisasContext
*ctx
, arg_srli
*a
)
276 if (a
->shamt
>= TARGET_LONG_BITS
) {
281 TCGv t
= tcg_temp_new();
282 gen_get_gpr(t
, a
->rs1
);
284 tcg_gen_shri_tl(t
, t
, a
->shamt
);
285 gen_set_gpr(a
->rd
, t
);
287 } /* NOP otherwise */
291 static bool trans_srai(DisasContext
*ctx
, arg_srai
*a
)
293 if (a
->shamt
>= TARGET_LONG_BITS
) {
298 TCGv t
= tcg_temp_new();
299 gen_get_gpr(t
, a
->rs1
);
301 tcg_gen_sari_tl(t
, t
, a
->shamt
);
302 gen_set_gpr(a
->rd
, t
);
304 } /* NOP otherwise */
308 static bool trans_add(DisasContext
*ctx
, arg_add
*a
)
310 return gen_arith(ctx
, a
, &tcg_gen_add_tl
);
313 static bool trans_sub(DisasContext
*ctx
, arg_sub
*a
)
315 return gen_arith(ctx
, a
, &tcg_gen_sub_tl
);
318 static bool trans_sll(DisasContext
*ctx
, arg_sll
*a
)
320 return gen_shift(ctx
, a
, &tcg_gen_shl_tl
);
323 static bool trans_slt(DisasContext
*ctx
, arg_slt
*a
)
325 return gen_arith(ctx
, a
, &gen_slt
);
328 static bool trans_sltu(DisasContext
*ctx
, arg_sltu
*a
)
330 return gen_arith(ctx
, a
, &gen_sltu
);
333 static bool trans_xor(DisasContext
*ctx
, arg_xor
*a
)
335 return gen_arith(ctx
, a
, &tcg_gen_xor_tl
);
338 static bool trans_srl(DisasContext
*ctx
, arg_srl
*a
)
340 return gen_shift(ctx
, a
, &tcg_gen_shr_tl
);
343 static bool trans_sra(DisasContext
*ctx
, arg_sra
*a
)
345 return gen_shift(ctx
, a
, &tcg_gen_sar_tl
);
348 static bool trans_or(DisasContext
*ctx
, arg_or
*a
)
350 return gen_arith(ctx
, a
, &tcg_gen_or_tl
);
353 static bool trans_and(DisasContext
*ctx
, arg_and
*a
)
355 return gen_arith(ctx
, a
, &tcg_gen_and_tl
);
358 #ifdef TARGET_RISCV64
359 static bool trans_addiw(DisasContext
*ctx
, arg_addiw
*a
)
361 return gen_arith_imm(ctx
, a
, &gen_addw
);
364 static bool trans_slliw(DisasContext
*ctx
, arg_slliw
*a
)
367 source1
= tcg_temp_new();
368 gen_get_gpr(source1
, a
->rs1
);
370 tcg_gen_shli_tl(source1
, source1
, a
->shamt
);
371 tcg_gen_ext32s_tl(source1
, source1
);
372 gen_set_gpr(a
->rd
, source1
);
374 tcg_temp_free(source1
);
378 static bool trans_srliw(DisasContext
*ctx
, arg_srliw
*a
)
380 TCGv t
= tcg_temp_new();
381 gen_get_gpr(t
, a
->rs1
);
382 tcg_gen_extract_tl(t
, t
, a
->shamt
, 32 - a
->shamt
);
383 /* sign-extend for W instructions */
384 tcg_gen_ext32s_tl(t
, t
);
385 gen_set_gpr(a
->rd
, t
);
390 static bool trans_sraiw(DisasContext
*ctx
, arg_sraiw
*a
)
392 TCGv t
= tcg_temp_new();
393 gen_get_gpr(t
, a
->rs1
);
394 tcg_gen_sextract_tl(t
, t
, a
->shamt
, 32 - a
->shamt
);
395 gen_set_gpr(a
->rd
, t
);
400 static bool trans_addw(DisasContext
*ctx
, arg_addw
*a
)
402 return gen_arith(ctx
, a
, &gen_addw
);
405 static bool trans_subw(DisasContext
*ctx
, arg_subw
*a
)
407 return gen_arith(ctx
, a
, &gen_subw
);
410 static bool trans_sllw(DisasContext
*ctx
, arg_sllw
*a
)
412 TCGv source1
= tcg_temp_new();
413 TCGv source2
= tcg_temp_new();
415 gen_get_gpr(source1
, a
->rs1
);
416 gen_get_gpr(source2
, a
->rs2
);
418 tcg_gen_andi_tl(source2
, source2
, 0x1F);
419 tcg_gen_shl_tl(source1
, source1
, source2
);
421 tcg_gen_ext32s_tl(source1
, source1
);
422 gen_set_gpr(a
->rd
, source1
);
423 tcg_temp_free(source1
);
424 tcg_temp_free(source2
);
428 static bool trans_srlw(DisasContext
*ctx
, arg_srlw
*a
)
430 TCGv source1
= tcg_temp_new();
431 TCGv source2
= tcg_temp_new();
433 gen_get_gpr(source1
, a
->rs1
);
434 gen_get_gpr(source2
, a
->rs2
);
437 tcg_gen_ext32u_tl(source1
, source1
);
438 tcg_gen_andi_tl(source2
, source2
, 0x1F);
439 tcg_gen_shr_tl(source1
, source1
, source2
);
441 tcg_gen_ext32s_tl(source1
, source1
);
442 gen_set_gpr(a
->rd
, source1
);
443 tcg_temp_free(source1
);
444 tcg_temp_free(source2
);
448 static bool trans_sraw(DisasContext
*ctx
, arg_sraw
*a
)
450 TCGv source1
= tcg_temp_new();
451 TCGv source2
= tcg_temp_new();
453 gen_get_gpr(source1
, a
->rs1
);
454 gen_get_gpr(source2
, a
->rs2
);
457 * first, trick to get it to act like working on 32 bits (get rid of
458 * upper 32, sign extend to fill space)
460 tcg_gen_ext32s_tl(source1
, source1
);
461 tcg_gen_andi_tl(source2
, source2
, 0x1F);
462 tcg_gen_sar_tl(source1
, source1
, source2
);
464 gen_set_gpr(a
->rd
, source1
);
465 tcg_temp_free(source1
);
466 tcg_temp_free(source2
);
472 static bool trans_fence(DisasContext
*ctx
, arg_fence
*a
)
474 /* FENCE is a full memory barrier. */
475 tcg_gen_mb(TCG_MO_ALL
| TCG_BAR_SC
);
479 static bool trans_fence_i(DisasContext
*ctx
, arg_fence_i
*a
)
482 * FENCE_I is a no-op in QEMU,
483 * however we need to end the translation block
485 tcg_gen_movi_tl(cpu_pc
, ctx
->pc_succ_insn
);
486 tcg_gen_exit_tb(NULL
, 0);
487 ctx
->base
.is_jmp
= DISAS_NORETURN
;
491 #define RISCV_OP_CSR_PRE do {\
492 source1 = tcg_temp_new(); \
493 csr_store = tcg_temp_new(); \
494 dest = tcg_temp_new(); \
495 rs1_pass = tcg_temp_new(); \
496 gen_get_gpr(source1, a->rs1); \
497 tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \
498 tcg_gen_movi_tl(rs1_pass, a->rs1); \
499 tcg_gen_movi_tl(csr_store, a->csr); \
503 #define RISCV_OP_CSR_POST do {\
505 gen_set_gpr(a->rd, dest); \
506 tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \
507 tcg_gen_exit_tb(NULL, 0); \
508 ctx->base.is_jmp = DISAS_NORETURN; \
509 tcg_temp_free(source1); \
510 tcg_temp_free(csr_store); \
511 tcg_temp_free(dest); \
512 tcg_temp_free(rs1_pass); \
516 static bool trans_csrrw(DisasContext
*ctx
, arg_csrrw
*a
)
518 TCGv source1
, csr_store
, dest
, rs1_pass
;
520 gen_helper_csrrw(dest
, cpu_env
, source1
, csr_store
);
525 static bool trans_csrrs(DisasContext
*ctx
, arg_csrrs
*a
)
527 TCGv source1
, csr_store
, dest
, rs1_pass
;
529 gen_helper_csrrs(dest
, cpu_env
, source1
, csr_store
, rs1_pass
);
534 static bool trans_csrrc(DisasContext
*ctx
, arg_csrrc
*a
)
536 TCGv source1
, csr_store
, dest
, rs1_pass
;
538 gen_helper_csrrc(dest
, cpu_env
, source1
, csr_store
, rs1_pass
);
543 static bool trans_csrrwi(DisasContext
*ctx
, arg_csrrwi
*a
)
545 TCGv source1
, csr_store
, dest
, rs1_pass
;
547 gen_helper_csrrw(dest
, cpu_env
, rs1_pass
, csr_store
);
552 static bool trans_csrrsi(DisasContext
*ctx
, arg_csrrsi
*a
)
554 TCGv source1
, csr_store
, dest
, rs1_pass
;
556 gen_helper_csrrs(dest
, cpu_env
, rs1_pass
, csr_store
, rs1_pass
);
561 static bool trans_csrrci(DisasContext
*ctx
, arg_csrrci
*a
)
563 TCGv source1
, csr_store
, dest
, rs1_pass
;
565 gen_helper_csrrc(dest
, cpu_env
, rs1_pass
, csr_store
, rs1_pass
);