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_illegal(DisasContext
*ctx
, arg_empty
*a
)
23 gen_exception_illegal(ctx
);
27 static bool trans_lui(DisasContext
*ctx
, arg_lui
*a
)
30 tcg_gen_movi_tl(cpu_gpr
[a
->rd
], a
->imm
);
35 static bool trans_auipc(DisasContext
*ctx
, arg_auipc
*a
)
38 tcg_gen_movi_tl(cpu_gpr
[a
->rd
], a
->imm
+ ctx
->base
.pc_next
);
43 static bool trans_jal(DisasContext
*ctx
, arg_jal
*a
)
45 gen_jal(ctx
, a
->rd
, a
->imm
);
49 static bool trans_jalr(DisasContext
*ctx
, arg_jalr
*a
)
51 /* no chaining with JALR */
52 TCGLabel
*misaligned
= NULL
;
53 TCGv t0
= tcg_temp_new();
56 gen_get_gpr(cpu_pc
, a
->rs1
);
57 tcg_gen_addi_tl(cpu_pc
, cpu_pc
, a
->imm
);
58 tcg_gen_andi_tl(cpu_pc
, cpu_pc
, (target_ulong
)-2);
60 if (!has_ext(ctx
, RVC
)) {
61 misaligned
= gen_new_label();
62 tcg_gen_andi_tl(t0
, cpu_pc
, 0x2);
63 tcg_gen_brcondi_tl(TCG_COND_NE
, t0
, 0x0, misaligned
);
67 tcg_gen_movi_tl(cpu_gpr
[a
->rd
], ctx
->pc_succ_insn
);
69 lookup_and_goto_ptr(ctx
);
72 gen_set_label(misaligned
);
73 gen_exception_inst_addr_mis(ctx
);
75 ctx
->base
.is_jmp
= DISAS_NORETURN
;
81 static bool gen_branch(DisasContext
*ctx
, arg_b
*a
, TCGCond cond
)
83 TCGLabel
*l
= gen_new_label();
84 TCGv source1
, source2
;
85 source1
= tcg_temp_new();
86 source2
= tcg_temp_new();
87 gen_get_gpr(source1
, a
->rs1
);
88 gen_get_gpr(source2
, a
->rs2
);
90 tcg_gen_brcond_tl(cond
, source1
, source2
, l
);
91 gen_goto_tb(ctx
, 1, ctx
->pc_succ_insn
);
92 gen_set_label(l
); /* branch taken */
94 if (!has_ext(ctx
, RVC
) && ((ctx
->base
.pc_next
+ a
->imm
) & 0x3)) {
96 gen_exception_inst_addr_mis(ctx
);
98 gen_goto_tb(ctx
, 0, ctx
->base
.pc_next
+ a
->imm
);
100 ctx
->base
.is_jmp
= DISAS_NORETURN
;
102 tcg_temp_free(source1
);
103 tcg_temp_free(source2
);
108 static bool trans_beq(DisasContext
*ctx
, arg_beq
*a
)
110 return gen_branch(ctx
, a
, TCG_COND_EQ
);
113 static bool trans_bne(DisasContext
*ctx
, arg_bne
*a
)
115 return gen_branch(ctx
, a
, TCG_COND_NE
);
118 static bool trans_blt(DisasContext
*ctx
, arg_blt
*a
)
120 return gen_branch(ctx
, a
, TCG_COND_LT
);
123 static bool trans_bge(DisasContext
*ctx
, arg_bge
*a
)
125 return gen_branch(ctx
, a
, TCG_COND_GE
);
128 static bool trans_bltu(DisasContext
*ctx
, arg_bltu
*a
)
130 return gen_branch(ctx
, a
, TCG_COND_LTU
);
133 static bool trans_bgeu(DisasContext
*ctx
, arg_bgeu
*a
)
135 return gen_branch(ctx
, a
, TCG_COND_GEU
);
138 static bool gen_load(DisasContext
*ctx
, arg_lb
*a
, MemOp memop
)
140 TCGv t0
= tcg_temp_new();
141 TCGv t1
= tcg_temp_new();
142 gen_get_gpr(t0
, a
->rs1
);
143 tcg_gen_addi_tl(t0
, t0
, a
->imm
);
145 tcg_gen_qemu_ld_tl(t1
, t0
, ctx
->mem_idx
, memop
);
146 gen_set_gpr(a
->rd
, t1
);
152 static bool trans_lb(DisasContext
*ctx
, arg_lb
*a
)
154 return gen_load(ctx
, a
, MO_SB
);
157 static bool trans_lh(DisasContext
*ctx
, arg_lh
*a
)
159 return gen_load(ctx
, a
, MO_TESW
);
162 static bool trans_lw(DisasContext
*ctx
, arg_lw
*a
)
164 return gen_load(ctx
, a
, MO_TESL
);
167 static bool trans_lbu(DisasContext
*ctx
, arg_lbu
*a
)
169 return gen_load(ctx
, a
, MO_UB
);
172 static bool trans_lhu(DisasContext
*ctx
, arg_lhu
*a
)
174 return gen_load(ctx
, a
, MO_TEUW
);
177 static bool gen_store(DisasContext
*ctx
, arg_sb
*a
, MemOp memop
)
179 TCGv t0
= tcg_temp_new();
180 TCGv dat
= tcg_temp_new();
181 gen_get_gpr(t0
, a
->rs1
);
182 tcg_gen_addi_tl(t0
, t0
, a
->imm
);
183 gen_get_gpr(dat
, a
->rs2
);
185 tcg_gen_qemu_st_tl(dat
, t0
, ctx
->mem_idx
, memop
);
192 static bool trans_sb(DisasContext
*ctx
, arg_sb
*a
)
194 return gen_store(ctx
, a
, MO_SB
);
197 static bool trans_sh(DisasContext
*ctx
, arg_sh
*a
)
199 return gen_store(ctx
, a
, MO_TESW
);
202 static bool trans_sw(DisasContext
*ctx
, arg_sw
*a
)
204 return gen_store(ctx
, a
, MO_TESL
);
207 #ifdef TARGET_RISCV64
208 static bool trans_lwu(DisasContext
*ctx
, arg_lwu
*a
)
210 return gen_load(ctx
, a
, MO_TEUL
);
213 static bool trans_ld(DisasContext
*ctx
, arg_ld
*a
)
215 return gen_load(ctx
, a
, MO_TEQ
);
218 static bool trans_sd(DisasContext
*ctx
, arg_sd
*a
)
220 return gen_store(ctx
, a
, MO_TEQ
);
224 static bool trans_addi(DisasContext
*ctx
, arg_addi
*a
)
226 return gen_arith_imm_fn(ctx
, a
, &tcg_gen_addi_tl
);
229 static void gen_slt(TCGv ret
, TCGv s1
, TCGv s2
)
231 tcg_gen_setcond_tl(TCG_COND_LT
, ret
, s1
, s2
);
234 static void gen_sltu(TCGv ret
, TCGv s1
, TCGv s2
)
236 tcg_gen_setcond_tl(TCG_COND_LTU
, ret
, s1
, s2
);
240 static bool trans_slti(DisasContext
*ctx
, arg_slti
*a
)
242 return gen_arith_imm_tl(ctx
, a
, &gen_slt
);
245 static bool trans_sltiu(DisasContext
*ctx
, arg_sltiu
*a
)
247 return gen_arith_imm_tl(ctx
, a
, &gen_sltu
);
250 static bool trans_xori(DisasContext
*ctx
, arg_xori
*a
)
252 return gen_arith_imm_fn(ctx
, a
, &tcg_gen_xori_tl
);
254 static bool trans_ori(DisasContext
*ctx
, arg_ori
*a
)
256 return gen_arith_imm_fn(ctx
, a
, &tcg_gen_ori_tl
);
258 static bool trans_andi(DisasContext
*ctx
, arg_andi
*a
)
260 return gen_arith_imm_fn(ctx
, a
, &tcg_gen_andi_tl
);
262 static bool trans_slli(DisasContext
*ctx
, arg_slli
*a
)
264 if (a
->shamt
>= TARGET_LONG_BITS
) {
269 TCGv t
= tcg_temp_new();
270 gen_get_gpr(t
, a
->rs1
);
272 tcg_gen_shli_tl(t
, t
, a
->shamt
);
274 gen_set_gpr(a
->rd
, t
);
276 } /* NOP otherwise */
280 static bool trans_srli(DisasContext
*ctx
, arg_srli
*a
)
282 if (a
->shamt
>= TARGET_LONG_BITS
) {
287 TCGv t
= tcg_temp_new();
288 gen_get_gpr(t
, a
->rs1
);
290 tcg_gen_shri_tl(t
, t
, a
->shamt
);
291 gen_set_gpr(a
->rd
, t
);
293 } /* NOP otherwise */
297 static bool trans_srai(DisasContext
*ctx
, arg_srai
*a
)
299 if (a
->shamt
>= TARGET_LONG_BITS
) {
304 TCGv t
= tcg_temp_new();
305 gen_get_gpr(t
, a
->rs1
);
307 tcg_gen_sari_tl(t
, t
, a
->shamt
);
308 gen_set_gpr(a
->rd
, t
);
310 } /* NOP otherwise */
314 static bool trans_add(DisasContext
*ctx
, arg_add
*a
)
316 return gen_arith(ctx
, a
, &tcg_gen_add_tl
);
319 static bool trans_sub(DisasContext
*ctx
, arg_sub
*a
)
321 return gen_arith(ctx
, a
, &tcg_gen_sub_tl
);
324 static bool trans_sll(DisasContext
*ctx
, arg_sll
*a
)
326 return gen_shift(ctx
, a
, &tcg_gen_shl_tl
);
329 static bool trans_slt(DisasContext
*ctx
, arg_slt
*a
)
331 return gen_arith(ctx
, a
, &gen_slt
);
334 static bool trans_sltu(DisasContext
*ctx
, arg_sltu
*a
)
336 return gen_arith(ctx
, a
, &gen_sltu
);
339 static bool trans_xor(DisasContext
*ctx
, arg_xor
*a
)
341 return gen_arith(ctx
, a
, &tcg_gen_xor_tl
);
344 static bool trans_srl(DisasContext
*ctx
, arg_srl
*a
)
346 return gen_shift(ctx
, a
, &tcg_gen_shr_tl
);
349 static bool trans_sra(DisasContext
*ctx
, arg_sra
*a
)
351 return gen_shift(ctx
, a
, &tcg_gen_sar_tl
);
354 static bool trans_or(DisasContext
*ctx
, arg_or
*a
)
356 return gen_arith(ctx
, a
, &tcg_gen_or_tl
);
359 static bool trans_and(DisasContext
*ctx
, arg_and
*a
)
361 return gen_arith(ctx
, a
, &tcg_gen_and_tl
);
364 #ifdef TARGET_RISCV64
365 static bool trans_addiw(DisasContext
*ctx
, arg_addiw
*a
)
367 return gen_arith_imm_tl(ctx
, a
, &gen_addw
);
370 static bool trans_slliw(DisasContext
*ctx
, arg_slliw
*a
)
373 source1
= tcg_temp_new();
374 gen_get_gpr(source1
, a
->rs1
);
376 tcg_gen_shli_tl(source1
, source1
, a
->shamt
);
377 tcg_gen_ext32s_tl(source1
, source1
);
378 gen_set_gpr(a
->rd
, source1
);
380 tcg_temp_free(source1
);
384 static bool trans_srliw(DisasContext
*ctx
, arg_srliw
*a
)
386 TCGv t
= tcg_temp_new();
387 gen_get_gpr(t
, a
->rs1
);
388 tcg_gen_extract_tl(t
, t
, a
->shamt
, 32 - a
->shamt
);
389 /* sign-extend for W instructions */
390 tcg_gen_ext32s_tl(t
, t
);
391 gen_set_gpr(a
->rd
, t
);
396 static bool trans_sraiw(DisasContext
*ctx
, arg_sraiw
*a
)
398 TCGv t
= tcg_temp_new();
399 gen_get_gpr(t
, a
->rs1
);
400 tcg_gen_sextract_tl(t
, t
, a
->shamt
, 32 - a
->shamt
);
401 gen_set_gpr(a
->rd
, t
);
406 static bool trans_addw(DisasContext
*ctx
, arg_addw
*a
)
408 return gen_arith(ctx
, a
, &gen_addw
);
411 static bool trans_subw(DisasContext
*ctx
, arg_subw
*a
)
413 return gen_arith(ctx
, a
, &gen_subw
);
416 static bool trans_sllw(DisasContext
*ctx
, arg_sllw
*a
)
418 TCGv source1
= tcg_temp_new();
419 TCGv source2
= tcg_temp_new();
421 gen_get_gpr(source1
, a
->rs1
);
422 gen_get_gpr(source2
, a
->rs2
);
424 tcg_gen_andi_tl(source2
, source2
, 0x1F);
425 tcg_gen_shl_tl(source1
, source1
, source2
);
427 tcg_gen_ext32s_tl(source1
, source1
);
428 gen_set_gpr(a
->rd
, source1
);
429 tcg_temp_free(source1
);
430 tcg_temp_free(source2
);
434 static bool trans_srlw(DisasContext
*ctx
, arg_srlw
*a
)
436 TCGv source1
= tcg_temp_new();
437 TCGv source2
= tcg_temp_new();
439 gen_get_gpr(source1
, a
->rs1
);
440 gen_get_gpr(source2
, a
->rs2
);
443 tcg_gen_ext32u_tl(source1
, source1
);
444 tcg_gen_andi_tl(source2
, source2
, 0x1F);
445 tcg_gen_shr_tl(source1
, source1
, source2
);
447 tcg_gen_ext32s_tl(source1
, source1
);
448 gen_set_gpr(a
->rd
, source1
);
449 tcg_temp_free(source1
);
450 tcg_temp_free(source2
);
454 static bool trans_sraw(DisasContext
*ctx
, arg_sraw
*a
)
456 TCGv source1
= tcg_temp_new();
457 TCGv source2
= tcg_temp_new();
459 gen_get_gpr(source1
, a
->rs1
);
460 gen_get_gpr(source2
, a
->rs2
);
463 * first, trick to get it to act like working on 32 bits (get rid of
464 * upper 32, sign extend to fill space)
466 tcg_gen_ext32s_tl(source1
, source1
);
467 tcg_gen_andi_tl(source2
, source2
, 0x1F);
468 tcg_gen_sar_tl(source1
, source1
, source2
);
470 gen_set_gpr(a
->rd
, source1
);
471 tcg_temp_free(source1
);
472 tcg_temp_free(source2
);
478 static bool trans_fence(DisasContext
*ctx
, arg_fence
*a
)
480 /* FENCE is a full memory barrier. */
481 tcg_gen_mb(TCG_MO_ALL
| TCG_BAR_SC
);
485 static bool trans_fence_i(DisasContext
*ctx
, arg_fence_i
*a
)
487 if (!ctx
->ext_ifencei
) {
492 * FENCE_I is a no-op in QEMU,
493 * however we need to end the translation block
495 tcg_gen_movi_tl(cpu_pc
, ctx
->pc_succ_insn
);
497 ctx
->base
.is_jmp
= DISAS_NORETURN
;
501 #define RISCV_OP_CSR_PRE do {\
502 source1 = tcg_temp_new(); \
503 csr_store = tcg_temp_new(); \
504 dest = tcg_temp_new(); \
505 rs1_pass = tcg_temp_new(); \
506 gen_get_gpr(source1, a->rs1); \
507 tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \
508 tcg_gen_movi_tl(rs1_pass, a->rs1); \
509 tcg_gen_movi_tl(csr_store, a->csr); \
513 #define RISCV_OP_CSR_POST do {\
514 gen_set_gpr(a->rd, dest); \
515 tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \
517 ctx->base.is_jmp = DISAS_NORETURN; \
518 tcg_temp_free(source1); \
519 tcg_temp_free(csr_store); \
520 tcg_temp_free(dest); \
521 tcg_temp_free(rs1_pass); \
525 static bool trans_csrrw(DisasContext
*ctx
, arg_csrrw
*a
)
527 TCGv source1
, csr_store
, dest
, rs1_pass
;
529 gen_helper_csrrw(dest
, cpu_env
, source1
, csr_store
);
534 static bool trans_csrrs(DisasContext
*ctx
, arg_csrrs
*a
)
536 TCGv source1
, csr_store
, dest
, rs1_pass
;
538 gen_helper_csrrs(dest
, cpu_env
, source1
, csr_store
, rs1_pass
);
543 static bool trans_csrrc(DisasContext
*ctx
, arg_csrrc
*a
)
545 TCGv source1
, csr_store
, dest
, rs1_pass
;
547 gen_helper_csrrc(dest
, cpu_env
, source1
, csr_store
, rs1_pass
);
552 static bool trans_csrrwi(DisasContext
*ctx
, arg_csrrwi
*a
)
554 TCGv source1
, csr_store
, dest
, rs1_pass
;
556 gen_helper_csrrw(dest
, cpu_env
, rs1_pass
, csr_store
);
561 static bool trans_csrrsi(DisasContext
*ctx
, arg_csrrsi
*a
)
563 TCGv source1
, csr_store
, dest
, rs1_pass
;
565 gen_helper_csrrs(dest
, cpu_env
, rs1_pass
, csr_store
, rs1_pass
);
570 static bool trans_csrrci(DisasContext
*ctx
, arg_csrrci
*a
)
572 TCGv source1
, csr_store
, dest
, rs1_pass
;
574 gen_helper_csrrc(dest
, cpu_env
, rs1_pass
, csr_store
, rs1_pass
);