target/riscv: Convert to decodetree
Bastian: this patchset converts the RISC-V decoder to decodetree in four major steps: 1) Convert 32-bit instructions to decodetree [Patch 1-15]: Many of the gen_* functions are called by the decode functions for 16-bit and 32-bit functions. If we move translation code from the gen_* functions to the generated trans_* functions of decode-tree, we get a lot of duplication. Therefore, we mostly generate calls to the old gen_* function which are properly replaced after step 2). Each of the trans_ functions are grouped into files corresponding to their ISA extension, e.g. addi which is in RV32I is translated in the file 'trans_rvi.inc.c'. 2) Convert 16-bit instructions to decodetree [Patch 16-18]: All 16 bit instructions have a direct mapping to a 32 bit instruction. Thus, we convert the arguments in the 16 bit trans_ function to the arguments of the corresponding 32 bit instruction and call the 32 bit trans_ function. 3) Remove old manual decoding in gen_* function [Patch 19-29]: this move all manual translation code into the trans_* instructions of decode tree, such that we can remove the old decode_* functions. Palmer: This, with some additional cleanup patches, passed Alistar's testing on rv32 and rv64 as well as my testing on rv64, so I think it's good to go. I've run my standard test against this exact tag. I still don't have a Mac to try this on, sorry! -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEAM520YNJYN/OiG3470yhUCzLq0EFAlyJCVETHHBhbG1lckBk YWJiZWx0LmNvbQAKCRDvTKFQLMurQeF6D/0UPlrbX7Gq8aPjs/Obca39SzNuQRqc BsFjy6sKm62iSCsawYRtdclqb0UT+5DaiR9TypoguG+FUrU4aiFTqVUCHkcBuFql 53gk3PGc/neODu9SZxWmDDv5qf7iZaDgngNFOy2zczHiL7+Cw0v0+iLBxNQmDWNI pGrmLUgYBMLHQl6GouDLrVW0jzVOqPXlgFcRagnmvozFrYE56ArZqTnN/urxVvAM FhXgNKpbYcAVnDE+ruVqeKcQFgjuGSooBO6wx2dWEhoqlpPKpE0ONZjxNKLjuv1a MyCUoBowukGENceNAts1wCkIAjRP+rGNgC9c26MH4ZYvnj3ThBsX73iQ56goHnQp Pc8BbSrftdQYayaG+Ba+rATLOBqvAZekmozzSV6EyqGyJLcnMZYDg+wBH2nhb9dD wlyYYoKPJFLrhYwn2nYhRplFTMTZ+vAmLxehG6BzRgddfmnaOKAkUP4OiMeQ/PG/ n8dXZUqev+mwPRA0ddxQYxeoxnw11zNJPfvnfXg879SutFdLHb/D3ZfBiTXT8SBp rMT8pnD0Pyi58MwdBFNas9woS/m8L6/lrMBfJ9VvMDKusPzjpgpdgw2Nf1/EUqQe cdrsJpTAKhTeXXax/kSSOHWqtXxbKhbOA+GU/BkWr8dCCeZUM9+M20rfWjkj7oyM FTQH3dfRT36FMw== =t7se -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-4.0-sf4' into staging target/riscv: Convert to decodetree Bastian: this patchset converts the RISC-V decoder to decodetree in four major steps: 1) Convert 32-bit instructions to decodetree [Patch 1-15]: Many of the gen_* functions are called by the decode functions for 16-bit and 32-bit functions. If we move translation code from the gen_* functions to the generated trans_* functions of decode-tree, we get a lot of duplication. Therefore, we mostly generate calls to the old gen_* function which are properly replaced after step 2). Each of the trans_ functions are grouped into files corresponding to their ISA extension, e.g. addi which is in RV32I is translated in the file 'trans_rvi.inc.c'. 2) Convert 16-bit instructions to decodetree [Patch 16-18]: All 16 bit instructions have a direct mapping to a 32 bit instruction. Thus, we convert the arguments in the 16 bit trans_ function to the arguments of the corresponding 32 bit instruction and call the 32 bit trans_ function. 3) Remove old manual decoding in gen_* function [Patch 19-29]: this move all manual translation code into the trans_* instructions of decode tree, such that we can remove the old decode_* functions. Palmer: This, with some additional cleanup patches, passed Alistar's testing on rv32 and rv64 as well as my testing on rv64, so I think it's good to go. I've run my standard test against this exact tag. I still don't have a Mac to try this on, sorry! # gpg: Signature made Wed 13 Mar 2019 13:44:49 GMT # gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41 # gpg: issuer "palmer@dabbelt.com" # gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown] # gpg: aka "Palmer Dabbelt <palmer@sifive.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41 * remotes/palmer/tags/riscv-for-master-4.0-sf4: (29 commits) target/riscv: Remove decode_RV32_64G() target/riscv: Remove gen_system() target/riscv: Rename trans_arith to gen_arith target/riscv: Remove manual decoding of RV32/64M insn target/riscv: Remove shift and slt insn manual decoding target/riscv: make ADD/SUB/OR/XOR/AND insn use arg lists target/riscv: Move gen_arith_imm() decoding into trans_* functions target/riscv: Remove manual decoding from gen_store() target/riscv: Remove manual decoding from gen_load() target/riscv: Remove manual decoding from gen_branch() target/riscv: Remove gen_jalr() target/riscv: Convert quadrant 2 of RVXC insns to decodetree target/riscv: Convert quadrant 1 of RVXC insns to decodetree target/riscv: Convert quadrant 0 of RVXC insns to decodetree target/riscv: Convert RV priv insns to decodetree target/riscv: Convert RV64D insns to decodetree target/riscv: Convert RV32D insns to decodetree target/riscv: Convert RV64F insns to decodetree target/riscv: Convert RV32F insns to decodetree target/riscv: Convert RV64A insns to decodetree ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
1fa87eb56e
@ -1 +1,20 @@
|
||||
obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o pmp.o
|
||||
|
||||
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
|
||||
|
||||
decode32-y = $(SRC_PATH)/target/riscv/insn32.decode
|
||||
decode32-$(TARGET_RISCV64) += $(SRC_PATH)/target/riscv/insn32-64.decode
|
||||
|
||||
target/riscv/decode_insn32.inc.c: $(decode32-y) $(DECODETREE)
|
||||
$(call quiet-command, \
|
||||
$(PYTHON) $(DECODETREE) -o $@ --decode decode_insn32 $(decode32-y), \
|
||||
"GEN", $(TARGET_DIR)$@)
|
||||
|
||||
target/riscv/decode_insn16.inc.c: \
|
||||
$(SRC_PATH)/target/riscv/insn16.decode $(DECODETREE)
|
||||
$(call quiet-command, \
|
||||
$(PYTHON) $(DECODETREE) -o $@ --decode decode_insn16 --insnwidth 16 $<, \
|
||||
"GEN", $(TARGET_DIR)$@)
|
||||
|
||||
target/riscv/translate.o: target/riscv/decode_insn32.inc.c \
|
||||
target/riscv/decode_insn16.inc.c
|
||||
|
129
target/riscv/insn16.decode
Normal file
129
target/riscv/insn16.decode
Normal file
@ -0,0 +1,129 @@
|
||||
#
|
||||
# RISC-V translation routines for the RVXI Base Integer Instruction Set.
|
||||
#
|
||||
# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms and conditions of the GNU General Public License,
|
||||
# version 2 or later, as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Fields:
|
||||
%rd 7:5
|
||||
%rs1_3 7:3 !function=ex_rvc_register
|
||||
%rs2_3 2:3 !function=ex_rvc_register
|
||||
%rs2_5 2:5
|
||||
|
||||
# Immediates:
|
||||
%imm_ci 12:s1 2:5
|
||||
%nzuimm_ciw 7:4 11:2 5:1 6:1 !function=ex_shift_2
|
||||
%uimm_cl_d 5:2 10:3 !function=ex_shift_3
|
||||
%uimm_cl_w 5:1 10:3 6:1 !function=ex_shift_2
|
||||
%imm_cb 12:s1 5:2 2:1 10:2 3:2 !function=ex_shift_1
|
||||
%imm_cj 12:s1 8:1 9:2 6:1 7:1 2:1 11:1 3:3 !function=ex_shift_1
|
||||
|
||||
%nzuimm_6bit 12:1 2:5
|
||||
%uimm_6bit_ld 2:3 12:1 5:2 !function=ex_shift_3
|
||||
%uimm_6bit_lw 2:2 12:1 4:3 !function=ex_shift_2
|
||||
%uimm_6bit_sd 7:3 10:3 !function=ex_shift_3
|
||||
%uimm_6bit_sw 7:2 9:4 !function=ex_shift_2
|
||||
|
||||
%imm_addi16sp 12:s1 3:2 5:1 2:1 6:1 !function=ex_shift_4
|
||||
%imm_lui 12:s1 2:5 !function=ex_shift_12
|
||||
|
||||
|
||||
|
||||
# Argument sets:
|
||||
&cl rs1 rd
|
||||
&cl_dw uimm rs1 rd
|
||||
&ci imm rd
|
||||
&ciw nzuimm rd
|
||||
&cs rs1 rs2
|
||||
&cs_dw uimm rs1 rs2
|
||||
&cb imm rs1
|
||||
&cr rd rs2
|
||||
&cj imm
|
||||
&c_shift shamt rd
|
||||
|
||||
&c_ld uimm rd
|
||||
&c_sd uimm rs2
|
||||
|
||||
&caddi16sp_lui imm_lui imm_addi16sp rd
|
||||
&cflwsp_ldsp uimm_flwsp uimm_ldsp rd
|
||||
&cfswsp_sdsp uimm_fswsp uimm_sdsp rs2
|
||||
|
||||
# Formats 16:
|
||||
@cr .... ..... ..... .. &cr rs2=%rs2_5 %rd
|
||||
@ci ... . ..... ..... .. &ci imm=%imm_ci %rd
|
||||
@ciw ... ........ ... .. &ciw nzuimm=%nzuimm_ciw rd=%rs2_3
|
||||
@cl_d ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
|
||||
@cl_w ... ... ... .. ... .. &cl_dw uimm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
|
||||
@cl ... ... ... .. ... .. &cl rs1=%rs1_3 rd=%rs2_3
|
||||
@cs ... ... ... .. ... .. &cs rs1=%rs1_3 rs2=%rs2_3
|
||||
@cs_2 ... ... ... .. ... .. &cr rd=%rs1_3 rs2=%rs2_3
|
||||
@cs_d ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3
|
||||
@cs_w ... ... ... .. ... .. &cs_dw uimm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3
|
||||
@cb ... ... ... .. ... .. &cb imm=%imm_cb rs1=%rs1_3
|
||||
@cj ... ........... .. &cj imm=%imm_cj
|
||||
|
||||
@c_ld ... . ..... ..... .. &c_ld uimm=%uimm_6bit_ld %rd
|
||||
@c_lw ... . ..... ..... .. &c_ld uimm=%uimm_6bit_lw %rd
|
||||
@c_sd ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sd rs2=%rs2_5
|
||||
@c_sw ... . ..... ..... .. &c_sd uimm=%uimm_6bit_sw rs2=%rs2_5
|
||||
|
||||
@c_addi16sp_lui ... . ..... ..... .. &caddi16sp_lui %imm_lui %imm_addi16sp %rd
|
||||
@c_flwsp_ldsp ... . ..... ..... .. &cflwsp_ldsp uimm_flwsp=%uimm_6bit_lw \
|
||||
uimm_ldsp=%uimm_6bit_ld %rd
|
||||
@c_fswsp_sdsp ... . ..... ..... .. &cfswsp_sdsp uimm_fswsp=%uimm_6bit_sw \
|
||||
uimm_sdsp=%uimm_6bit_sd rs2=%rs2_5
|
||||
|
||||
@c_shift ... . .. ... ..... .. &c_shift rd=%rs1_3 shamt=%nzuimm_6bit
|
||||
@c_shift2 ... . .. ... ..... .. &c_shift rd=%rd shamt=%nzuimm_6bit
|
||||
|
||||
@c_andi ... . .. ... ..... .. &ci imm=%imm_ci rd=%rs1_3
|
||||
|
||||
# *** RV64C Standard Extension (Quadrant 0) ***
|
||||
c_addi4spn 000 ........ ... 00 @ciw
|
||||
c_fld 001 ... ... .. ... 00 @cl_d
|
||||
c_lw 010 ... ... .. ... 00 @cl_w
|
||||
c_flw_ld 011 --- ... -- ... 00 @cl #Note: Must parse uimm manually
|
||||
c_fsd 101 ... ... .. ... 00 @cs_d
|
||||
c_sw 110 ... ... .. ... 00 @cs_w
|
||||
c_fsw_sd 111 --- ... -- ... 00 @cs #Note: Must parse uimm manually
|
||||
|
||||
# *** RV64C Standard Extension (Quadrant 1) ***
|
||||
c_addi 000 . ..... ..... 01 @ci
|
||||
c_jal_addiw 001 . ..... ..... 01 @ci #Note: parse rd and/or imm manually
|
||||
c_li 010 . ..... ..... 01 @ci
|
||||
c_addi16sp_lui 011 . ..... ..... 01 @c_addi16sp_lui # shares opc with C.LUI
|
||||
c_srli 100 . 00 ... ..... 01 @c_shift
|
||||
c_srai 100 . 01 ... ..... 01 @c_shift
|
||||
c_andi 100 . 10 ... ..... 01 @c_andi
|
||||
c_sub 100 0 11 ... 00 ... 01 @cs_2
|
||||
c_xor 100 0 11 ... 01 ... 01 @cs_2
|
||||
c_or 100 0 11 ... 10 ... 01 @cs_2
|
||||
c_and 100 0 11 ... 11 ... 01 @cs_2
|
||||
c_subw 100 1 11 ... 00 ... 01 @cs_2
|
||||
c_addw 100 1 11 ... 01 ... 01 @cs_2
|
||||
c_j 101 ........... 01 @cj
|
||||
c_beqz 110 ... ... ..... 01 @cb
|
||||
c_bnez 111 ... ... ..... 01 @cb
|
||||
|
||||
# *** RV64C Standard Extension (Quadrant 2) ***
|
||||
c_slli 000 . ..... ..... 10 @c_shift2
|
||||
c_fldsp 001 . ..... ..... 10 @c_ld
|
||||
c_lwsp 010 . ..... ..... 10 @c_lw
|
||||
c_flwsp_ldsp 011 . ..... ..... 10 @c_flwsp_ldsp #C.LDSP:RV64;C.FLWSP:RV32
|
||||
c_jr_mv 100 0 ..... ..... 10 @cr
|
||||
c_ebreak_jalr_add 100 1 ..... ..... 10 @cr
|
||||
c_fsdsp 101 ...... ..... 10 @c_sd
|
||||
c_swsp 110 . ..... ..... 10 @c_sw
|
||||
c_fswsp_sdsp 111 . ..... ..... 10 @c_fswsp_sdsp #C.SDSP:RV64;C.FSWSP:RV32
|
72
target/riscv/insn32-64.decode
Normal file
72
target/riscv/insn32-64.decode
Normal file
@ -0,0 +1,72 @@
|
||||
#
|
||||
# RISC-V translation routines for the RV Instruction Set.
|
||||
#
|
||||
# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms and conditions of the GNU General Public License,
|
||||
# version 2 or later, as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This is concatenated with insn32.decode for risc64 targets.
|
||||
# Most of the fields and formats are there.
|
||||
|
||||
%sh5 20:5
|
||||
|
||||
@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
|
||||
|
||||
# *** RV64I Base Instruction Set (in addition to RV32I) ***
|
||||
lwu ............ ..... 110 ..... 0000011 @i
|
||||
ld ............ ..... 011 ..... 0000011 @i
|
||||
sd ....... ..... ..... 011 ..... 0100011 @s
|
||||
addiw ............ ..... 000 ..... 0011011 @i
|
||||
slliw 0000000 ..... ..... 001 ..... 0011011 @sh5
|
||||
srliw 0000000 ..... ..... 101 ..... 0011011 @sh5
|
||||
sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5
|
||||
addw 0000000 ..... ..... 000 ..... 0111011 @r
|
||||
subw 0100000 ..... ..... 000 ..... 0111011 @r
|
||||
sllw 0000000 ..... ..... 001 ..... 0111011 @r
|
||||
srlw 0000000 ..... ..... 101 ..... 0111011 @r
|
||||
sraw 0100000 ..... ..... 101 ..... 0111011 @r
|
||||
|
||||
# *** RV64M Standard Extension (in addition to RV32M) ***
|
||||
mulw 0000001 ..... ..... 000 ..... 0111011 @r
|
||||
divw 0000001 ..... ..... 100 ..... 0111011 @r
|
||||
divuw 0000001 ..... ..... 101 ..... 0111011 @r
|
||||
remw 0000001 ..... ..... 110 ..... 0111011 @r
|
||||
remuw 0000001 ..... ..... 111 ..... 0111011 @r
|
||||
|
||||
# *** RV64A Standard Extension (in addition to RV32A) ***
|
||||
lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld
|
||||
sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st
|
||||
|
||||
# *** RV64F Standard Extension (in addition to RV32F) ***
|
||||
fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm
|
||||
|
||||
# *** RV64D Standard Extension (in addition to RV32D) ***
|
||||
fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm
|
||||
fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2
|
||||
fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm
|
||||
fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2
|
201
target/riscv/insn32.decode
Normal file
201
target/riscv/insn32.decode
Normal file
@ -0,0 +1,201 @@
|
||||
#
|
||||
# RISC-V translation routines for the RVXI Base Integer Instruction Set.
|
||||
#
|
||||
# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms and conditions of the GNU General Public License,
|
||||
# version 2 or later, as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Fields:
|
||||
%rs3 27:5
|
||||
%rs2 20:5
|
||||
%rs1 15:5
|
||||
%rd 7:5
|
||||
|
||||
%sh10 20:10
|
||||
%csr 20:12
|
||||
%rm 12:3
|
||||
|
||||
# immediates:
|
||||
%imm_i 20:s12
|
||||
%imm_s 25:s7 7:5
|
||||
%imm_b 31:s1 7:1 25:6 8:4 !function=ex_shift_1
|
||||
%imm_j 31:s1 12:8 20:1 21:10 !function=ex_shift_1
|
||||
%imm_u 12:s20 !function=ex_shift_12
|
||||
|
||||
# Argument sets:
|
||||
&b imm rs2 rs1
|
||||
&i imm rs1 rd
|
||||
&r rd rs1 rs2
|
||||
&shift shamt rs1 rd
|
||||
&atomic aq rl rs2 rs1 rd
|
||||
|
||||
# Formats 32:
|
||||
@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
|
||||
@i ............ ..... ... ..... ....... &i imm=%imm_i %rs1 %rd
|
||||
@b ....... ..... ..... ... ..... ....... &b imm=%imm_b %rs2 %rs1
|
||||
@s ....... ..... ..... ... ..... ....... imm=%imm_s %rs2 %rs1
|
||||
@u .................... ..... ....... imm=%imm_u %rd
|
||||
@j .................... ..... ....... imm=%imm_j %rd
|
||||
|
||||
@sh ...... ...... ..... ... ..... ....... &shift shamt=%sh10 %rs1 %rd
|
||||
@csr ............ ..... ... ..... ....... %csr %rs1 %rd
|
||||
|
||||
@atom_ld ..... aq:1 rl:1 ..... ........ ..... ....... &atomic rs2=0 %rs1 %rd
|
||||
@atom_st ..... aq:1 rl:1 ..... ........ ..... ....... &atomic %rs2 %rs1 %rd
|
||||
|
||||
@r4_rm ..... .. ..... ..... ... ..... ....... %rs3 %rs2 %rs1 %rm %rd
|
||||
@r_rm ....... ..... ..... ... ..... ....... %rs2 %rs1 %rm %rd
|
||||
@r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd
|
||||
@r2 ....... ..... ..... ... ..... ....... %rs1 %rd
|
||||
|
||||
@sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1
|
||||
@sfence_vm ....... ..... ..... ... ..... ....... %rs1
|
||||
|
||||
|
||||
# *** Privileged Instructions ***
|
||||
ecall 000000000000 00000 000 00000 1110011
|
||||
ebreak 000000000001 00000 000 00000 1110011
|
||||
uret 0000000 00010 00000 000 00000 1110011
|
||||
sret 0001000 00010 00000 000 00000 1110011
|
||||
hret 0010000 00010 00000 000 00000 1110011
|
||||
mret 0011000 00010 00000 000 00000 1110011
|
||||
wfi 0001000 00101 00000 000 00000 1110011
|
||||
sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma
|
||||
sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm
|
||||
|
||||
# *** RV32I Base Instruction Set ***
|
||||
lui .................... ..... 0110111 @u
|
||||
auipc .................... ..... 0010111 @u
|
||||
jal .................... ..... 1101111 @j
|
||||
jalr ............ ..... 000 ..... 1100111 @i
|
||||
beq ....... ..... ..... 000 ..... 1100011 @b
|
||||
bne ....... ..... ..... 001 ..... 1100011 @b
|
||||
blt ....... ..... ..... 100 ..... 1100011 @b
|
||||
bge ....... ..... ..... 101 ..... 1100011 @b
|
||||
bltu ....... ..... ..... 110 ..... 1100011 @b
|
||||
bgeu ....... ..... ..... 111 ..... 1100011 @b
|
||||
lb ............ ..... 000 ..... 0000011 @i
|
||||
lh ............ ..... 001 ..... 0000011 @i
|
||||
lw ............ ..... 010 ..... 0000011 @i
|
||||
lbu ............ ..... 100 ..... 0000011 @i
|
||||
lhu ............ ..... 101 ..... 0000011 @i
|
||||
sb ....... ..... ..... 000 ..... 0100011 @s
|
||||
sh ....... ..... ..... 001 ..... 0100011 @s
|
||||
sw ....... ..... ..... 010 ..... 0100011 @s
|
||||
addi ............ ..... 000 ..... 0010011 @i
|
||||
slti ............ ..... 010 ..... 0010011 @i
|
||||
sltiu ............ ..... 011 ..... 0010011 @i
|
||||
xori ............ ..... 100 ..... 0010011 @i
|
||||
ori ............ ..... 110 ..... 0010011 @i
|
||||
andi ............ ..... 111 ..... 0010011 @i
|
||||
slli 00.... ...... ..... 001 ..... 0010011 @sh
|
||||
srli 00.... ...... ..... 101 ..... 0010011 @sh
|
||||
srai 01.... ...... ..... 101 ..... 0010011 @sh
|
||||
add 0000000 ..... ..... 000 ..... 0110011 @r
|
||||
sub 0100000 ..... ..... 000 ..... 0110011 @r
|
||||
sll 0000000 ..... ..... 001 ..... 0110011 @r
|
||||
slt 0000000 ..... ..... 010 ..... 0110011 @r
|
||||
sltu 0000000 ..... ..... 011 ..... 0110011 @r
|
||||
xor 0000000 ..... ..... 100 ..... 0110011 @r
|
||||
srl 0000000 ..... ..... 101 ..... 0110011 @r
|
||||
sra 0100000 ..... ..... 101 ..... 0110011 @r
|
||||
or 0000000 ..... ..... 110 ..... 0110011 @r
|
||||
and 0000000 ..... ..... 111 ..... 0110011 @r
|
||||
fence ---- pred:4 succ:4 ----- 000 ----- 0001111
|
||||
fence_i ---- ---- ---- ----- 001 ----- 0001111
|
||||
csrrw ............ ..... 001 ..... 1110011 @csr
|
||||
csrrs ............ ..... 010 ..... 1110011 @csr
|
||||
csrrc ............ ..... 011 ..... 1110011 @csr
|
||||
csrrwi ............ ..... 101 ..... 1110011 @csr
|
||||
csrrsi ............ ..... 110 ..... 1110011 @csr
|
||||
csrrci ............ ..... 111 ..... 1110011 @csr
|
||||
|
||||
# *** RV32M Standard Extension ***
|
||||
mul 0000001 ..... ..... 000 ..... 0110011 @r
|
||||
mulh 0000001 ..... ..... 001 ..... 0110011 @r
|
||||
mulhsu 0000001 ..... ..... 010 ..... 0110011 @r
|
||||
mulhu 0000001 ..... ..... 011 ..... 0110011 @r
|
||||
div 0000001 ..... ..... 100 ..... 0110011 @r
|
||||
divu 0000001 ..... ..... 101 ..... 0110011 @r
|
||||
rem 0000001 ..... ..... 110 ..... 0110011 @r
|
||||
remu 0000001 ..... ..... 111 ..... 0110011 @r
|
||||
|
||||
# *** RV32A Standard Extension ***
|
||||
lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld
|
||||
sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amoswap_w 00001 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amoadd_w 00000 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amoxor_w 00100 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amoand_w 01100 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amoor_w 01000 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amomin_w 10000 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amomax_w 10100 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amominu_w 11000 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st
|
||||
|
||||
# *** RV32F Standard Extension ***
|
||||
flw ............ ..... 010 ..... 0000111 @i
|
||||
fsw ....... ..... ..... 010 ..... 0100111 @s
|
||||
fmadd_s ..... 00 ..... ..... ... ..... 1000011 @r4_rm
|
||||
fmsub_s ..... 00 ..... ..... ... ..... 1000111 @r4_rm
|
||||
fnmsub_s ..... 00 ..... ..... ... ..... 1001011 @r4_rm
|
||||
fnmadd_s ..... 00 ..... ..... ... ..... 1001111 @r4_rm
|
||||
fadd_s 0000000 ..... ..... ... ..... 1010011 @r_rm
|
||||
fsub_s 0000100 ..... ..... ... ..... 1010011 @r_rm
|
||||
fmul_s 0001000 ..... ..... ... ..... 1010011 @r_rm
|
||||
fdiv_s 0001100 ..... ..... ... ..... 1010011 @r_rm
|
||||
fsqrt_s 0101100 00000 ..... ... ..... 1010011 @r2_rm
|
||||
fsgnj_s 0010000 ..... ..... 000 ..... 1010011 @r
|
||||
fsgnjn_s 0010000 ..... ..... 001 ..... 1010011 @r
|
||||
fsgnjx_s 0010000 ..... ..... 010 ..... 1010011 @r
|
||||
fmin_s 0010100 ..... ..... 000 ..... 1010011 @r
|
||||
fmax_s 0010100 ..... ..... 001 ..... 1010011 @r
|
||||
fcvt_w_s 1100000 00000 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_wu_s 1100000 00001 ..... ... ..... 1010011 @r2_rm
|
||||
fmv_x_w 1110000 00000 ..... 000 ..... 1010011 @r2
|
||||
feq_s 1010000 ..... ..... 010 ..... 1010011 @r
|
||||
flt_s 1010000 ..... ..... 001 ..... 1010011 @r
|
||||
fle_s 1010000 ..... ..... 000 ..... 1010011 @r
|
||||
fclass_s 1110000 00000 ..... 001 ..... 1010011 @r2
|
||||
fcvt_s_w 1101000 00000 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_s_wu 1101000 00001 ..... ... ..... 1010011 @r2_rm
|
||||
fmv_w_x 1111000 00000 ..... 000 ..... 1010011 @r2
|
||||
|
||||
# *** RV32D Standard Extension ***
|
||||
fld ............ ..... 011 ..... 0000111 @i
|
||||
fsd ....... ..... ..... 011 ..... 0100111 @s
|
||||
fmadd_d ..... 01 ..... ..... ... ..... 1000011 @r4_rm
|
||||
fmsub_d ..... 01 ..... ..... ... ..... 1000111 @r4_rm
|
||||
fnmsub_d ..... 01 ..... ..... ... ..... 1001011 @r4_rm
|
||||
fnmadd_d ..... 01 ..... ..... ... ..... 1001111 @r4_rm
|
||||
fadd_d 0000001 ..... ..... ... ..... 1010011 @r_rm
|
||||
fsub_d 0000101 ..... ..... ... ..... 1010011 @r_rm
|
||||
fmul_d 0001001 ..... ..... ... ..... 1010011 @r_rm
|
||||
fdiv_d 0001101 ..... ..... ... ..... 1010011 @r_rm
|
||||
fsqrt_d 0101101 00000 ..... ... ..... 1010011 @r2_rm
|
||||
fsgnj_d 0010001 ..... ..... 000 ..... 1010011 @r
|
||||
fsgnjn_d 0010001 ..... ..... 001 ..... 1010011 @r
|
||||
fsgnjx_d 0010001 ..... ..... 010 ..... 1010011 @r
|
||||
fmin_d 0010101 ..... ..... 000 ..... 1010011 @r
|
||||
fmax_d 0010101 ..... ..... 001 ..... 1010011 @r
|
||||
fcvt_s_d 0100000 00001 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_d_s 0100001 00000 ..... ... ..... 1010011 @r2_rm
|
||||
feq_d 1010001 ..... ..... 010 ..... 1010011 @r
|
||||
flt_d 1010001 ..... ..... 001 ..... 1010011 @r
|
||||
fle_d 1010001 ..... ..... 000 ..... 1010011 @r
|
||||
fclass_d 1110001 00000 ..... 001 ..... 1010011 @r2
|
||||
fcvt_w_d 1100001 00000 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm
|
||||
fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm
|
110
target/riscv/insn_trans/trans_privileged.inc.c
Normal file
110
target/riscv/insn_trans/trans_privileged.inc.c
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RISC-V privileged instructions.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
* Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static bool trans_ecall(DisasContext *ctx, arg_ecall *a)
|
||||
{
|
||||
/* always generates U-level ECALL, fixed in do_interrupt handler */
|
||||
generate_exception(ctx, RISCV_EXCP_U_ECALL);
|
||||
tcg_gen_exit_tb(NULL, 0); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
|
||||
{
|
||||
generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
|
||||
tcg_gen_exit_tb(NULL, 0); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_uret(DisasContext *ctx, arg_uret *a)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_sret(DisasContext *ctx, arg_sret *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
|
||||
|
||||
if (has_ext(ctx, RVS)) {
|
||||
gen_helper_sret(cpu_pc, cpu_env, cpu_pc);
|
||||
tcg_gen_exit_tb(NULL, 0); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_hret(DisasContext *ctx, arg_hret *a)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_mret(DisasContext *ctx, arg_mret *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
|
||||
gen_helper_mret(cpu_pc, cpu_env, cpu_pc);
|
||||
tcg_gen_exit_tb(NULL, 0); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
|
||||
gen_helper_wfi(cpu_env);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (ctx->priv_ver == PRIV_VERSION_1_10_0) {
|
||||
gen_helper_tlb_flush(cpu_env);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (ctx->priv_ver <= PRIV_VERSION_1_09_1) {
|
||||
gen_helper_tlb_flush(cpu_env);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
218
target/riscv/insn_trans/trans_rva.inc.c
Normal file
218
target/riscv/insn_trans/trans_rva.inc.c
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RV64A Standard Extension.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
* Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static inline bool gen_lr(DisasContext *ctx, arg_atomic *a, TCGMemOp mop)
|
||||
{
|
||||
TCGv src1 = tcg_temp_new();
|
||||
/* Put addr in load_res, data in load_val. */
|
||||
gen_get_gpr(src1, a->rs1);
|
||||
if (a->rl) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
|
||||
}
|
||||
tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop);
|
||||
if (a->aq) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
|
||||
}
|
||||
tcg_gen_mov_tl(load_res, src1);
|
||||
gen_set_gpr(a->rd, load_val);
|
||||
|
||||
tcg_temp_free(src1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool gen_sc(DisasContext *ctx, arg_atomic *a, TCGMemOp mop)
|
||||
{
|
||||
TCGv src1 = tcg_temp_new();
|
||||
TCGv src2 = tcg_temp_new();
|
||||
TCGv dat = tcg_temp_new();
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
|
||||
gen_get_gpr(src1, a->rs1);
|
||||
tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1);
|
||||
|
||||
gen_get_gpr(src2, a->rs2);
|
||||
/*
|
||||
* Note that the TCG atomic primitives are SC,
|
||||
* so we can ignore AQ/RL along this path.
|
||||
*/
|
||||
tcg_gen_atomic_cmpxchg_tl(src1, load_res, load_val, src2,
|
||||
ctx->mem_idx, mop);
|
||||
tcg_gen_setcond_tl(TCG_COND_NE, dat, src1, load_val);
|
||||
gen_set_gpr(a->rd, dat);
|
||||
tcg_gen_br(l2);
|
||||
|
||||
gen_set_label(l1);
|
||||
/*
|
||||
* Address comparion failure. However, we still need to
|
||||
* provide the memory barrier implied by AQ/RL.
|
||||
*/
|
||||
tcg_gen_mb(TCG_MO_ALL + a->aq * TCG_BAR_LDAQ + a->rl * TCG_BAR_STRL);
|
||||
tcg_gen_movi_tl(dat, 1);
|
||||
gen_set_gpr(a->rd, dat);
|
||||
|
||||
gen_set_label(l2);
|
||||
tcg_temp_free(dat);
|
||||
tcg_temp_free(src1);
|
||||
tcg_temp_free(src2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_amo(DisasContext *ctx, arg_atomic *a,
|
||||
void(*func)(TCGv, TCGv, TCGv, TCGArg, TCGMemOp),
|
||||
TCGMemOp mop)
|
||||
{
|
||||
TCGv src1 = tcg_temp_new();
|
||||
TCGv src2 = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(src1, a->rs1);
|
||||
gen_get_gpr(src2, a->rs2);
|
||||
|
||||
(*func)(src2, src1, src2, ctx->mem_idx, mop);
|
||||
|
||||
gen_set_gpr(a->rd, src2);
|
||||
tcg_temp_free(src1);
|
||||
tcg_temp_free(src2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_lr(ctx, a, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_sc(ctx, a, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVA);
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL));
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
|
||||
static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a)
|
||||
{
|
||||
return gen_lr(ctx, a, MO_ALIGN | MO_TEQ);
|
||||
}
|
||||
|
||||
static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a)
|
||||
{
|
||||
return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
|
||||
static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a)
|
||||
{
|
||||
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ));
|
||||
}
|
||||
#endif
|
327
target/riscv/insn_trans/trans_rvc.inc.c
Normal file
327
target/riscv/insn_trans/trans_rvc.inc.c
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RVC Compressed Instruction Set.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
* Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static bool trans_c_addi4spn(DisasContext *ctx, arg_c_addi4spn *a)
|
||||
{
|
||||
if (a->nzuimm == 0) {
|
||||
/* Reserved in ISA */
|
||||
return false;
|
||||
}
|
||||
arg_addi arg = { .rd = a->rd, .rs1 = 2, .imm = a->nzuimm };
|
||||
return trans_addi(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_fld(DisasContext *ctx, arg_c_fld *a)
|
||||
{
|
||||
arg_fld arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm };
|
||||
return trans_fld(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_lw(DisasContext *ctx, arg_c_lw *a)
|
||||
{
|
||||
arg_lw arg = { .rd = a->rd, .rs1 = a->rs1, .imm = a->uimm };
|
||||
return trans_lw(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_flw_ld(DisasContext *ctx, arg_c_flw_ld *a)
|
||||
{
|
||||
#ifdef TARGET_RISCV32
|
||||
/* C.FLW ( RV32FC-only ) */
|
||||
return false;
|
||||
#else
|
||||
/* C.LD ( RV64C/RV128C-only ) */
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_c_fsd(DisasContext *ctx, arg_c_fsd *a)
|
||||
{
|
||||
arg_fsd arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm };
|
||||
return trans_fsd(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_sw(DisasContext *ctx, arg_c_sw *a)
|
||||
{
|
||||
arg_sw arg = { .rs1 = a->rs1, .rs2 = a->rs2, .imm = a->uimm };
|
||||
return trans_sw(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_fsw_sd(DisasContext *ctx, arg_c_fsw_sd *a)
|
||||
{
|
||||
#ifdef TARGET_RISCV32
|
||||
/* C.FSW ( RV32FC-only ) */
|
||||
return false;
|
||||
#else
|
||||
/* C.SD ( RV64C/RV128C-only ) */
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_c_addi(DisasContext *ctx, arg_c_addi *a)
|
||||
{
|
||||
if (a->imm == 0) {
|
||||
/* Hint: insn is valid but does not affect state */
|
||||
return true;
|
||||
}
|
||||
arg_addi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
|
||||
return trans_addi(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_jal_addiw(DisasContext *ctx, arg_c_jal_addiw *a)
|
||||
{
|
||||
#ifdef TARGET_RISCV32
|
||||
/* C.JAL */
|
||||
arg_jal arg = { .rd = 1, .imm = a->imm };
|
||||
return trans_jal(ctx, &arg);
|
||||
#else
|
||||
/* C.ADDIW */
|
||||
arg_addiw arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
|
||||
return trans_addiw(ctx, &arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_c_li(DisasContext *ctx, arg_c_li *a)
|
||||
{
|
||||
if (a->rd == 0) {
|
||||
/* Hint: insn is valid but does not affect state */
|
||||
return true;
|
||||
}
|
||||
arg_addi arg = { .rd = a->rd, .rs1 = 0, .imm = a->imm };
|
||||
return trans_addi(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_addi16sp_lui(DisasContext *ctx, arg_c_addi16sp_lui *a)
|
||||
{
|
||||
if (a->rd == 2) {
|
||||
/* C.ADDI16SP */
|
||||
arg_addi arg = { .rd = 2, .rs1 = 2, .imm = a->imm_addi16sp };
|
||||
return trans_addi(ctx, &arg);
|
||||
} else if (a->imm_lui != 0) {
|
||||
/* C.LUI */
|
||||
if (a->rd == 0) {
|
||||
/* Hint: insn is valid but does not affect state */
|
||||
return true;
|
||||
}
|
||||
arg_lui arg = { .rd = a->rd, .imm = a->imm_lui };
|
||||
return trans_lui(ctx, &arg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_c_srli(DisasContext *ctx, arg_c_srli *a)
|
||||
{
|
||||
int shamt = a->shamt;
|
||||
if (shamt == 0) {
|
||||
/* For RV128 a shamt of 0 means a shift by 64 */
|
||||
shamt = 64;
|
||||
}
|
||||
/* Ensure, that shamt[5] is zero for RV32 */
|
||||
if (shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
arg_srli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
|
||||
return trans_srli(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_srai(DisasContext *ctx, arg_c_srai *a)
|
||||
{
|
||||
int shamt = a->shamt;
|
||||
if (shamt == 0) {
|
||||
/* For RV128 a shamt of 0 means a shift by 64 */
|
||||
shamt = 64;
|
||||
}
|
||||
/* Ensure, that shamt[5] is zero for RV32 */
|
||||
if (shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
arg_srai arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
|
||||
return trans_srai(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_andi(DisasContext *ctx, arg_c_andi *a)
|
||||
{
|
||||
arg_andi arg = { .rd = a->rd, .rs1 = a->rd, .imm = a->imm };
|
||||
return trans_andi(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_sub(DisasContext *ctx, arg_c_sub *a)
|
||||
{
|
||||
arg_sub arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
|
||||
return trans_sub(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_xor(DisasContext *ctx, arg_c_xor *a)
|
||||
{
|
||||
arg_xor arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
|
||||
return trans_xor(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_or(DisasContext *ctx, arg_c_or *a)
|
||||
{
|
||||
arg_or arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
|
||||
return trans_or(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_and(DisasContext *ctx, arg_c_and *a)
|
||||
{
|
||||
arg_and arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
|
||||
return trans_and(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_subw(DisasContext *ctx, arg_c_subw *a)
|
||||
{
|
||||
#ifdef TARGET_RISCV64
|
||||
arg_subw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
|
||||
return trans_subw(ctx, &arg);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_c_addw(DisasContext *ctx, arg_c_addw *a)
|
||||
{
|
||||
#ifdef TARGET_RISCV64
|
||||
arg_addw arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
|
||||
return trans_addw(ctx, &arg);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool trans_c_j(DisasContext *ctx, arg_c_j *a)
|
||||
{
|
||||
arg_jal arg = { .rd = 0, .imm = a->imm };
|
||||
return trans_jal(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_beqz(DisasContext *ctx, arg_c_beqz *a)
|
||||
{
|
||||
arg_beq arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm };
|
||||
return trans_beq(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_bnez(DisasContext *ctx, arg_c_bnez *a)
|
||||
{
|
||||
arg_bne arg = { .rs1 = a->rs1, .rs2 = 0, .imm = a->imm };
|
||||
return trans_bne(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_slli(DisasContext *ctx, arg_c_slli *a)
|
||||
{
|
||||
int shamt = a->shamt;
|
||||
if (shamt == 0) {
|
||||
/* For RV128 a shamt of 0 means a shift by 64 */
|
||||
shamt = 64;
|
||||
}
|
||||
/* Ensure, that shamt[5] is zero for RV32 */
|
||||
if (shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
arg_slli arg = { .rd = a->rd, .rs1 = a->rd, .shamt = a->shamt };
|
||||
return trans_slli(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_fldsp(DisasContext *ctx, arg_c_fldsp *a)
|
||||
{
|
||||
arg_fld arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm };
|
||||
return trans_fld(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_lwsp(DisasContext *ctx, arg_c_lwsp *a)
|
||||
{
|
||||
arg_lw arg = { .rd = a->rd, .rs1 = 2, .imm = a->uimm };
|
||||
return trans_lw(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_flwsp_ldsp(DisasContext *ctx, arg_c_flwsp_ldsp *a)
|
||||
{
|
||||
#ifdef TARGET_RISCV32
|
||||
/* C.FLWSP */
|
||||
arg_flw arg_flw = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_flwsp };
|
||||
return trans_flw(ctx, &arg_flw);
|
||||
#else
|
||||
/* C.LDSP */
|
||||
arg_ld arg_ld = { .rd = a->rd, .rs1 = 2, .imm = a->uimm_ldsp };
|
||||
return trans_ld(ctx, &arg_ld);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_c_jr_mv(DisasContext *ctx, arg_c_jr_mv *a)
|
||||
{
|
||||
if (a->rd != 0 && a->rs2 == 0) {
|
||||
/* C.JR */
|
||||
arg_jalr arg = { .rd = 0, .rs1 = a->rd, .imm = 0 };
|
||||
return trans_jalr(ctx, &arg);
|
||||
} else if (a->rd != 0 && a->rs2 != 0) {
|
||||
/* C.MV */
|
||||
arg_add arg = { .rd = a->rd, .rs1 = 0, .rs2 = a->rs2 };
|
||||
return trans_add(ctx, &arg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_c_ebreak_jalr_add(DisasContext *ctx, arg_c_ebreak_jalr_add *a)
|
||||
{
|
||||
if (a->rd == 0 && a->rs2 == 0) {
|
||||
/* C.EBREAK */
|
||||
arg_ebreak arg = { };
|
||||
return trans_ebreak(ctx, &arg);
|
||||
} else if (a->rd != 0) {
|
||||
if (a->rs2 == 0) {
|
||||
/* C.JALR */
|
||||
arg_jalr arg = { .rd = 1, .rs1 = a->rd, .imm = 0 };
|
||||
return trans_jalr(ctx, &arg);
|
||||
} else {
|
||||
/* C.ADD */
|
||||
arg_add arg = { .rd = a->rd, .rs1 = a->rd, .rs2 = a->rs2 };
|
||||
return trans_add(ctx, &arg);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trans_c_fsdsp(DisasContext *ctx, arg_c_fsdsp *a)
|
||||
{
|
||||
arg_fsd arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm };
|
||||
return trans_fsd(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_swsp(DisasContext *ctx, arg_c_swsp *a)
|
||||
{
|
||||
arg_sw arg = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm };
|
||||
return trans_sw(ctx, &arg);
|
||||
}
|
||||
|
||||
static bool trans_c_fswsp_sdsp(DisasContext *ctx, arg_c_fswsp_sdsp *a)
|
||||
{
|
||||
#ifdef TARGET_RISCV32
|
||||
/* C.FSWSP */
|
||||
arg_fsw a_fsw = { .rs1 = a->rs2, .rs2 = 2, .imm = a->uimm_fswsp };
|
||||
return trans_fsw(ctx, &a_fsw);
|
||||
#else
|
||||
/* C.SDSP */
|
||||
arg_sd a_sd = { .rs1 = 2, .rs2 = a->rs2, .imm = a->uimm_sdsp };
|
||||
return trans_sd(ctx, &a_sd);
|
||||
#endif
|
||||
}
|
442
target/riscv/insn_trans/trans_rvd.inc.c
Normal file
442
target/riscv/insn_trans/trans_rvd.inc.c
Normal file
@ -0,0 +1,442 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RV64D Standard Extension.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
* Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static bool trans_fld(DisasContext *ctx, arg_fld *a)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEQ);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEQ);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fnmsub_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fnmadd_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fadd_d(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fsub_d(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmul_d(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fdiv_d(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fsqrt_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnj_d(DisasContext *ctx, arg_fsgnj_d *a)
|
||||
{
|
||||
if (a->rs1 == a->rs2) { /* FMOV */
|
||||
tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
|
||||
} else {
|
||||
tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2],
|
||||
cpu_fpr[a->rs1], 0, 63);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnjn_d(DisasContext *ctx, arg_fsgnjn_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
if (a->rs1 == a->rs2) { /* FNEG */
|
||||
tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT64_MIN);
|
||||
} else {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
tcg_gen_not_i64(t0, cpu_fpr[a->rs2]);
|
||||
tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 63);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnjx_d(DisasContext *ctx, arg_fsgnjx_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
if (a->rs1 == a->rs2) { /* FABS */
|
||||
tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT64_MIN);
|
||||
} else {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT64_MIN);
|
||||
tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_helper_fmin_d(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_helper_fmax_d(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_d(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_feq_d(DisasContext *ctx, arg_feq_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_feq_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_flt_d(DisasContext *ctx, arg_flt_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_flt_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fle_d(DisasContext *ctx, arg_fle_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_fle_d(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_fclass_d(t0, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_w_d(DisasContext *ctx, arg_fcvt_w_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_w_d(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_wu_d(DisasContext *ctx, arg_fcvt_wu_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_wu_d(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_w(DisasContext *ctx, arg_fcvt_d_w *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_w(cpu_fpr[a->rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_wu(cpu_fpr[a->rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
|
||||
static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_l_d(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_lu_d(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
gen_set_gpr(a->rd, cpu_fpr[a->rs1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_l(cpu_fpr[a->rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_d_lu(cpu_fpr[a->rd], cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
tcg_gen_mov_tl(cpu_fpr[a->rd], t0);
|
||||
tcg_temp_free(t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
#endif
|
439
target/riscv/insn_trans/trans_rvf.inc.c
Normal file
439
target/riscv/insn_trans/trans_rvf.inc.c
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RV64F Standard Extension.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
* Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define REQUIRE_FPU do {\
|
||||
if (ctx->mstatus_fs == 0) \
|
||||
return false; \
|
||||
} while (0)
|
||||
|
||||
static bool trans_flw(DisasContext *ctx, arg_flw *a)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL);
|
||||
/* RISC-V requires NaN-boxing of narrower width floating point values */
|
||||
tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 0xffffffff00000000ULL);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], t0, ctx->mem_idx, MO_TEUL);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fnmsub_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fnmadd_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2], cpu_fpr[a->rs3]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fadd_s(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fsub_s(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fmul_s(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fdiv_s(cpu_fpr[a->rd], cpu_env,
|
||||
cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fsqrt_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnj_s(DisasContext *ctx, arg_fsgnj_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
if (a->rs1 == a->rs2) { /* FMOV */
|
||||
tcg_gen_mov_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1]);
|
||||
} else { /* FSGNJ */
|
||||
tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rs2], cpu_fpr[a->rs1],
|
||||
0, 31);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnjn_s(DisasContext *ctx, arg_fsgnjn_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
if (a->rs1 == a->rs2) { /* FNEG */
|
||||
tcg_gen_xori_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], INT32_MIN);
|
||||
} else {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
tcg_gen_not_i64(t0, cpu_fpr[a->rs2]);
|
||||
tcg_gen_deposit_i64(cpu_fpr[a->rd], t0, cpu_fpr[a->rs1], 0, 31);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fsgnjx_s(DisasContext *ctx, arg_fsgnjx_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
if (a->rs1 == a->rs2) { /* FABS */
|
||||
tcg_gen_andi_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], ~INT32_MIN);
|
||||
} else {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
tcg_gen_andi_i64(t0, cpu_fpr[a->rs2], INT32_MIN);
|
||||
tcg_gen_xor_i64(cpu_fpr[a->rd], cpu_fpr[a->rs1], t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
gen_helper_fmin_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
gen_helper_fmax_s(cpu_fpr[a->rd], cpu_env, cpu_fpr[a->rs1],
|
||||
cpu_fpr[a->rs2]);
|
||||
mark_fs_dirty(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_w_s(DisasContext *ctx, arg_fcvt_w_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_w_s(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_wu_s(DisasContext *ctx, arg_fcvt_wu_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_wu_s(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a)
|
||||
{
|
||||
/* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
#if defined(TARGET_RISCV64)
|
||||
tcg_gen_ext32s_tl(t0, cpu_fpr[a->rs1]);
|
||||
#else
|
||||
tcg_gen_extrl_i64_i32(t0, cpu_fpr[a->rs1]);
|
||||
#endif
|
||||
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_feq_s(DisasContext *ctx, arg_feq_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_feq_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_flt_s(DisasContext *ctx, arg_flt_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_flt_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fle_s(DisasContext *ctx, arg_fle_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_helper_fle_s(t0, cpu_env, cpu_fpr[a->rs1], cpu_fpr[a->rs2]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
gen_helper_fclass_s(t0, cpu_fpr[a->rs1]);
|
||||
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_w(DisasContext *ctx, arg_fcvt_s_w *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_w(cpu_fpr[a->rd], cpu_env, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_wu(DisasContext *ctx, arg_fcvt_s_wu *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_wu(cpu_fpr[a->rd], cpu_env, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a)
|
||||
{
|
||||
/* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
#if defined(TARGET_RISCV64)
|
||||
tcg_gen_mov_i64(cpu_fpr[a->rd], t0);
|
||||
#else
|
||||
tcg_gen_extu_i32_i64(cpu_fpr[a->rd], t0);
|
||||
#endif
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_l_s(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_lu_s(t0, cpu_env, cpu_fpr[a->rs1]);
|
||||
gen_set_gpr(a->rd, t0);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_l(cpu_fpr[a->rd], cpu_env, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
|
||||
{
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
TCGv t0 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
|
||||
gen_set_rm(ctx, a->rm);
|
||||
gen_helper_fcvt_s_lu(cpu_fpr[a->rd], cpu_env, t0);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
#endif
|
568
target/riscv/insn_trans/trans_rvi.inc.c
Normal file
568
target/riscv/insn_trans/trans_rvi.inc.c
Normal file
@ -0,0 +1,568 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RVXI Base Integer Instruction Set.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
* Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static bool trans_lui(DisasContext *ctx, arg_lui *a)
|
||||
{
|
||||
if (a->rd != 0) {
|
||||
tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
|
||||
{
|
||||
if (a->rd != 0) {
|
||||
tcg_gen_movi_tl(cpu_gpr[a->rd], a->imm + ctx->base.pc_next);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_jal(DisasContext *ctx, arg_jal *a)
|
||||
{
|
||||
gen_jal(ctx, a->rd, a->imm);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
|
||||
{
|
||||
/* no chaining with JALR */
|
||||
TCGLabel *misaligned = NULL;
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
|
||||
gen_get_gpr(cpu_pc, a->rs1);
|
||||
tcg_gen_addi_tl(cpu_pc, cpu_pc, a->imm);
|
||||
tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2);
|
||||
|
||||
if (!has_ext(ctx, RVC)) {
|
||||
misaligned = gen_new_label();
|
||||
tcg_gen_andi_tl(t0, cpu_pc, 0x2);
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn);
|
||||
}
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
|
||||
if (misaligned) {
|
||||
gen_set_label(misaligned);
|
||||
gen_exception_inst_addr_mis(ctx);
|
||||
}
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
tcg_temp_free(t0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
|
||||
{
|
||||
TCGLabel *l = gen_new_label();
|
||||
TCGv source1, source2;
|
||||
source1 = tcg_temp_new();
|
||||
source2 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
tcg_gen_brcond_tl(cond, source1, source2, l);
|
||||
gen_goto_tb(ctx, 1, ctx->pc_succ_insn);
|
||||
gen_set_label(l); /* branch taken */
|
||||
|
||||
if (!has_ext(ctx, RVC) && ((ctx->base.pc_next + a->imm) & 0x3)) {
|
||||
/* misaligned */
|
||||
gen_exception_inst_addr_mis(ctx);
|
||||
} else {
|
||||
gen_goto_tb(ctx, 0, ctx->base.pc_next + a->imm);
|
||||
}
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_beq(DisasContext *ctx, arg_beq *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_EQ);
|
||||
}
|
||||
|
||||
static bool trans_bne(DisasContext *ctx, arg_bne *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_NE);
|
||||
}
|
||||
|
||||
static bool trans_blt(DisasContext *ctx, arg_blt *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_LT);
|
||||
}
|
||||
|
||||
static bool trans_bge(DisasContext *ctx, arg_bge *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_GE);
|
||||
}
|
||||
|
||||
static bool trans_bltu(DisasContext *ctx, arg_bltu *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_LTU);
|
||||
}
|
||||
|
||||
static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
|
||||
{
|
||||
return gen_branch(ctx, a, TCG_COND_GEU);
|
||||
}
|
||||
|
||||
static bool gen_load(DisasContext *ctx, arg_lb *a, TCGMemOp memop)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop);
|
||||
gen_set_gpr(a->rd, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_lb(DisasContext *ctx, arg_lb *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_SB);
|
||||
}
|
||||
|
||||
static bool trans_lh(DisasContext *ctx, arg_lh *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TESW);
|
||||
}
|
||||
|
||||
static bool trans_lw(DisasContext *ctx, arg_lw *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TESL);
|
||||
}
|
||||
|
||||
static bool trans_lbu(DisasContext *ctx, arg_lbu *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_UB);
|
||||
}
|
||||
|
||||
static bool trans_lhu(DisasContext *ctx, arg_lhu *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TEUW);
|
||||
}
|
||||
|
||||
static bool gen_store(DisasContext *ctx, arg_sb *a, TCGMemOp memop)
|
||||
{
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv dat = tcg_temp_new();
|
||||
gen_get_gpr(t0, a->rs1);
|
||||
tcg_gen_addi_tl(t0, t0, a->imm);
|
||||
gen_get_gpr(dat, a->rs2);
|
||||
|
||||
tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx, memop);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(dat);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool trans_sb(DisasContext *ctx, arg_sb *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_SB);
|
||||
}
|
||||
|
||||
static bool trans_sh(DisasContext *ctx, arg_sh *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_TESW);
|
||||
}
|
||||
|
||||
static bool trans_sw(DisasContext *ctx, arg_sw *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_TESL);
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
static bool trans_lwu(DisasContext *ctx, arg_lwu *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TEUL);
|
||||
}
|
||||
|
||||
static bool trans_ld(DisasContext *ctx, arg_ld *a)
|
||||
{
|
||||
return gen_load(ctx, a, MO_TEQ);
|
||||
}
|
||||
|
||||
static bool trans_sd(DisasContext *ctx, arg_sd *a)
|
||||
{
|
||||
return gen_store(ctx, a, MO_TEQ);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool trans_addi(DisasContext *ctx, arg_addi *a)
|
||||
{
|
||||
return gen_arith_imm(ctx, a, &tcg_gen_add_tl);
|
||||
}
|
||||
|
||||
static void gen_slt(TCGv ret, TCGv s1, TCGv s2)
|
||||
{
|
||||
tcg_gen_setcond_tl(TCG_COND_LT, ret, s1, s2);
|
||||
}
|
||||
|
||||
static void gen_sltu(TCGv ret, TCGv s1, TCGv s2)
|
||||
{
|
||||
tcg_gen_setcond_tl(TCG_COND_LTU, ret, s1, s2);
|
||||
}
|
||||
|
||||
|
||||
static bool trans_slti(DisasContext *ctx, arg_slti *a)
|
||||
{
|
||||
return gen_arith_imm(ctx, a, &gen_slt);
|
||||
}
|
||||
|
||||
static bool trans_sltiu(DisasContext *ctx, arg_sltiu *a)
|
||||
{
|
||||
return gen_arith_imm(ctx, a, &gen_sltu);
|
||||
}
|
||||
|
||||
static bool trans_xori(DisasContext *ctx, arg_xori *a)
|
||||
{
|
||||
return gen_arith_imm(ctx, a, &tcg_gen_xor_tl);
|
||||
}
|
||||
static bool trans_ori(DisasContext *ctx, arg_ori *a)
|
||||
{
|
||||
return gen_arith_imm(ctx, a, &tcg_gen_or_tl);
|
||||
}
|
||||
static bool trans_andi(DisasContext *ctx, arg_andi *a)
|
||||
{
|
||||
return gen_arith_imm(ctx, a, &tcg_gen_and_tl);
|
||||
}
|
||||
static bool trans_slli(DisasContext *ctx, arg_slli *a)
|
||||
{
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new();
|
||||
gen_get_gpr(t, a->rs1);
|
||||
|
||||
tcg_gen_shli_tl(t, t, a->shamt);
|
||||
|
||||
gen_set_gpr(a->rd, t);
|
||||
tcg_temp_free(t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_srli(DisasContext *ctx, arg_srli *a)
|
||||
{
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new();
|
||||
gen_get_gpr(t, a->rs1);
|
||||
|
||||
tcg_gen_shri_tl(t, t, a->shamt);
|
||||
gen_set_gpr(a->rd, t);
|
||||
tcg_temp_free(t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_srai(DisasContext *ctx, arg_srai *a)
|
||||
{
|
||||
if (a->shamt >= TARGET_LONG_BITS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
TCGv t = tcg_temp_new();
|
||||
gen_get_gpr(t, a->rs1);
|
||||
|
||||
tcg_gen_sari_tl(t, t, a->shamt);
|
||||
gen_set_gpr(a->rd, t);
|
||||
tcg_temp_free(t);
|
||||
} /* NOP otherwise */
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_add(DisasContext *ctx, arg_add *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &tcg_gen_add_tl);
|
||||
}
|
||||
|
||||
static bool trans_sub(DisasContext *ctx, arg_sub *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &tcg_gen_sub_tl);
|
||||
}
|
||||
|
||||
static bool trans_sll(DisasContext *ctx, arg_sll *a)
|
||||
{
|
||||
return gen_shift(ctx, a, &tcg_gen_shl_tl);
|
||||
}
|
||||
|
||||
static bool trans_slt(DisasContext *ctx, arg_slt *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &gen_slt);
|
||||
}
|
||||
|
||||
static bool trans_sltu(DisasContext *ctx, arg_sltu *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &gen_sltu);
|
||||
}
|
||||
|
||||
static bool trans_xor(DisasContext *ctx, arg_xor *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &tcg_gen_xor_tl);
|
||||
}
|
||||
|
||||
static bool trans_srl(DisasContext *ctx, arg_srl *a)
|
||||
{
|
||||
return gen_shift(ctx, a, &tcg_gen_shr_tl);
|
||||
}
|
||||
|
||||
static bool trans_sra(DisasContext *ctx, arg_sra *a)
|
||||
{
|
||||
return gen_shift(ctx, a, &tcg_gen_sar_tl);
|
||||
}
|
||||
|
||||
static bool trans_or(DisasContext *ctx, arg_or *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &tcg_gen_or_tl);
|
||||
}
|
||||
|
||||
static bool trans_and(DisasContext *ctx, arg_and *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &tcg_gen_and_tl);
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
|
||||
{
|
||||
return gen_arith_imm(ctx, a, &gen_addw);
|
||||
}
|
||||
|
||||
static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
|
||||
{
|
||||
TCGv source1;
|
||||
source1 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
|
||||
tcg_gen_shli_tl(source1, source1, a->shamt);
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
gen_set_gpr(a->rd, source1);
|
||||
|
||||
tcg_temp_free(source1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
gen_get_gpr(t, a->rs1);
|
||||
tcg_gen_extract_tl(t, t, a->shamt, 32 - a->shamt);
|
||||
/* sign-extend for W instructions */
|
||||
tcg_gen_ext32s_tl(t, t);
|
||||
gen_set_gpr(a->rd, t);
|
||||
tcg_temp_free(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
gen_get_gpr(t, a->rs1);
|
||||
tcg_gen_sextract_tl(t, t, a->shamt, 32 - a->shamt);
|
||||
gen_set_gpr(a->rd, t);
|
||||
tcg_temp_free(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_addw(DisasContext *ctx, arg_addw *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &gen_addw);
|
||||
}
|
||||
|
||||
static bool trans_subw(DisasContext *ctx, arg_subw *a)
|
||||
{
|
||||
return gen_arith(ctx, a, &gen_subw);
|
||||
}
|
||||
|
||||
static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
|
||||
{
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
tcg_gen_andi_tl(source2, source2, 0x1F);
|
||||
tcg_gen_shl_tl(source1, source1, source2);
|
||||
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
|
||||
{
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
/* clear upper 32 */
|
||||
tcg_gen_ext32u_tl(source1, source1);
|
||||
tcg_gen_andi_tl(source2, source2, 0x1F);
|
||||
tcg_gen_shr_tl(source1, source1, source2);
|
||||
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
|
||||
{
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
/*
|
||||
* first, trick to get it to act like working on 32 bits (get rid of
|
||||
* upper 32, sign extend to fill space)
|
||||
*/
|
||||
tcg_gen_ext32s_tl(source1, source1);
|
||||
tcg_gen_andi_tl(source2, source2, 0x1F);
|
||||
tcg_gen_sar_tl(source1, source1, source2);
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool trans_fence(DisasContext *ctx, arg_fence *a)
|
||||
{
|
||||
/* FENCE is a full memory barrier. */
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
|
||||
{
|
||||
/*
|
||||
* FENCE_I is a no-op in QEMU,
|
||||
* however we need to end the translation block
|
||||
*/
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define RISCV_OP_CSR_PRE do {\
|
||||
source1 = tcg_temp_new(); \
|
||||
csr_store = tcg_temp_new(); \
|
||||
dest = tcg_temp_new(); \
|
||||
rs1_pass = tcg_temp_new(); \
|
||||
gen_get_gpr(source1, a->rs1); \
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); \
|
||||
tcg_gen_movi_tl(rs1_pass, a->rs1); \
|
||||
tcg_gen_movi_tl(csr_store, a->csr); \
|
||||
gen_io_start();\
|
||||
} while (0)
|
||||
|
||||
#define RISCV_OP_CSR_POST do {\
|
||||
gen_io_end(); \
|
||||
gen_set_gpr(a->rd, dest); \
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); \
|
||||
tcg_gen_exit_tb(NULL, 0); \
|
||||
ctx->base.is_jmp = DISAS_NORETURN; \
|
||||
tcg_temp_free(source1); \
|
||||
tcg_temp_free(csr_store); \
|
||||
tcg_temp_free(dest); \
|
||||
tcg_temp_free(rs1_pass); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
|
||||
{
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrw(dest, cpu_env, source1, csr_store);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrs(DisasContext *ctx, arg_csrrs *a)
|
||||
{
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrs(dest, cpu_env, source1, csr_store, rs1_pass);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
|
||||
{
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrc(dest, cpu_env, source1, csr_store, rs1_pass);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
|
||||
{
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrw(dest, cpu_env, rs1_pass, csr_store);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrsi(DisasContext *ctx, arg_csrrsi *a)
|
||||
{
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrs(dest, cpu_env, rs1_pass, csr_store, rs1_pass);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_csrrci(DisasContext *ctx, arg_csrrci *a)
|
||||
{
|
||||
TCGv source1, csr_store, dest, rs1_pass;
|
||||
RISCV_OP_CSR_PRE;
|
||||
gen_helper_csrrc(dest, cpu_env, rs1_pass, csr_store, rs1_pass);
|
||||
RISCV_OP_CSR_POST;
|
||||
return true;
|
||||
}
|
120
target/riscv/insn_trans/trans_rvm.inc.c
Normal file
120
target/riscv/insn_trans/trans_rvm.inc.c
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* RISC-V translation routines for the RV64M Standard Extension.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
|
||||
* Bastian Koppelmann, kbastian@mail.uni-paderborn.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
static bool trans_mul(DisasContext *ctx, arg_mul *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &tcg_gen_mul_tl);
|
||||
}
|
||||
|
||||
static bool trans_mulh(DisasContext *ctx, arg_mulh *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
tcg_gen_muls2_tl(source2, source1, source1, source2);
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_mulhsu);
|
||||
}
|
||||
|
||||
static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
TCGv source1 = tcg_temp_new();
|
||||
TCGv source2 = tcg_temp_new();
|
||||
gen_get_gpr(source1, a->rs1);
|
||||
gen_get_gpr(source2, a->rs2);
|
||||
|
||||
tcg_gen_mulu2_tl(source2, source1, source1, source2);
|
||||
|
||||
gen_set_gpr(a->rd, source1);
|
||||
tcg_temp_free(source1);
|
||||
tcg_temp_free(source2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_div(DisasContext *ctx, arg_div *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_div);
|
||||
}
|
||||
|
||||
static bool trans_divu(DisasContext *ctx, arg_divu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_divu);
|
||||
}
|
||||
|
||||
static bool trans_rem(DisasContext *ctx, arg_rem *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_rem);
|
||||
}
|
||||
|
||||
static bool trans_remu(DisasContext *ctx, arg_remu *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_remu);
|
||||
}
|
||||
|
||||
#ifdef TARGET_RISCV64
|
||||
static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith(ctx, a, &gen_mulw);
|
||||
}
|
||||
|
||||
static bool trans_divw(DisasContext *ctx, arg_divw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith_div_w(ctx, a, &gen_div);
|
||||
}
|
||||
|
||||
static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith_div_w(ctx, a, &gen_divu);
|
||||
}
|
||||
|
||||
static bool trans_remw(DisasContext *ctx, arg_remw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith_div_w(ctx, a, &gen_rem);
|
||||
}
|
||||
|
||||
static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
|
||||
{
|
||||
REQUIRE_EXT(ctx, RVM);
|
||||
return gen_arith_div_w(ctx, a, &gen_remu);
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user