diff --git a/CMakeLists.txt b/CMakeLists.txt index b92435a804..3d050503c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ option(BUILD_SHARED_LIBS "Build shared instead of static library" ${PROJECT_IS_T option(UNICORN_FUZZ "Enable fuzzing" OFF) option(UNICORN_BUILD_TESTS "Build unicorn tests" ${PROJECT_IS_TOP_LEVEL}) option(UNICORN_INSTALL "Enable unicorn installation" ${PROJECT_IS_TOP_LEVEL}) -set(UNICORN_ARCH "x86;arm;aarch64;riscv;mips;sparc;m68k;ppc;s390x;tricore" CACHE STRING "Enabled unicorn architectures") +set(UNICORN_ARCH "x86;arm;aarch64;riscv;mips;sparc;m68k;ppc;rh850;s390x;tricore" CACHE STRING "Enabled unicorn architectures") option(UNICORN_TRACER "Trace unicorn execution" OFF) foreach(ARCH_LOOP ${UNICORN_ARCH}) @@ -268,6 +268,9 @@ else() if(UNICORN_HAS_PPC) set(EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_PPC ") endif() + if(UNICORN_HAS_RH850) + set(EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_RH850 ") + endif() if(UNICORN_HAS_RISCV) set(EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_RISCV ") endif() @@ -315,6 +318,9 @@ else() if(UNICORN_HAS_PPC) set(TARGET_LIST "${TARGET_LIST}ppc-softmmu, ppc64-softmmu, ") endif() + if(UNICORN_HAS_RH850) + set(TARGET_LIST "${TARGET_LIST}rh850-softmmu, ") + endif() if(UNICORN_HAS_RISCV) set(TARGET_LIST "${TARGET_LIST}riscv32-softmmu, riscv64-softmmu, ") endif() @@ -399,6 +405,12 @@ else() OUTPUT_FILE ${CMAKE_BINARY_DIR}/ppc64-softmmu/config-target.h ) endif() + if(UNICORN_HAS_RH850) + execute_process(COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/qemu/scripts/create_config + INPUT_FILE ${CMAKE_BINARY_DIR}/rh850-softmmu/config-target.mak + OUTPUT_FILE ${CMAKE_BINARY_DIR}/rh850-softmmu/config-target.h + ) + endif() if(UNICORN_HAS_RISCV) execute_process(COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/qemu/scripts/create_config INPUT_FILE ${CMAKE_BINARY_DIR}/riscv32-softmmu/config-target.mak @@ -1119,6 +1131,36 @@ endif() endif() +if (UNICORN_HAS_RH850) +add_library(rh850-softmmu STATIC + ${UNICORN_ARCH_COMMON} + + qemu/target/rh850/cpu.c + qemu/target/rh850/fpu_helper.c + qemu/target/rh850/helper.c + qemu/target/rh850/op_helper.c + qemu/target/rh850/translate.c + qemu/target/rh850/fpu_translate.c + qemu/target/rh850/unicorn.c +) + +if(MSVC) + target_compile_options(rh850-softmmu PRIVATE + -DNEED_CPU_H + /FIrh850.h + /I${CMAKE_CURRENT_SOURCE_DIR}/msvc/rh850-softmmu + /I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/rh850 + ) +else() + target_compile_options(rh850-softmmu PRIVATE + -DNEED_CPU_H + -include rh850.h + -I${CMAKE_BINARY_DIR}/rh850-softmmu + -I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/rh850 + ) +endif() +endif() + set(UNICORN_SRCS uc.c @@ -1266,6 +1308,13 @@ if(UNICORN_HAS_PPC) target_link_libraries(ppc64-softmmu PRIVATE unicorn-common) set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_ppc) endif() +if(UNICORN_HAS_RH850) + set(UNICORN_COMPILE_OPTIONS ${UNICORN_COMPILE_OPTIONS} -DUNICORN_HAS_RH850) + set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} rh850-softmmu rh850-softmmu) + set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_rh850) + target_link_libraries(rh850-softmmu PRIVATE unicorn-common) + set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_rh850) +endif() if(UNICORN_HAS_RISCV) set(UNICORN_COMPILE_OPTIONS ${UNICORN_COMPILE_OPTIONS} -DUNICORN_HAS_RISCV) set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} riscv32-softmmu riscv64-softmmu) diff --git a/Cargo.toml b/Cargo.toml index 64ab69b2c3..942ce1f304 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ pkg-config = { version = "0.3" } [features] default = ["arch_all"] dynamic_linkage = [] -arch_all = ["arch_x86", "arch_arm", "arch_aarch64", "arch_riscv", "arch_mips", "arch_sparc", "arch_m68k", "arch_ppc", "arch_s390x", "arch_tricore"] +arch_all = ["arch_x86", "arch_arm", "arch_aarch64", "arch_riscv", "arch_mips", "arch_sparc", "arch_m68k", "arch_ppc", "arch_s390x", "arch_tricore", "arch_rh850"] arch_x86 = [] arch_arm = [] arch_aarch64 = [] @@ -53,3 +53,4 @@ arch_m68k = [] arch_ppc = [] arch_s390x = [] arch_tricore = [] +arch_rh850 = [] diff --git a/bindings/const_generator.py b/bindings/const_generator.py index 982b48f4cb..259254a9bd 100644 --- a/bindings/const_generator.py +++ b/bindings/const_generator.py @@ -6,7 +6,7 @@ INCL_DIR = os.path.join('..', 'include', 'unicorn') -include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'ppc.h', 'riscv.h', 's390x.h', 'tricore.h', 'unicorn.h' ] +include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'ppc.h', 'rh850.h', 'riscv.h', 's390x.h', 'tricore.h', 'unicorn.h' ] template = { 'python': { @@ -22,6 +22,7 @@ 'sparc.h': 'sparc', 'm68k.h': 'm68k', 'ppc.h': 'ppc', + 'rh850.h': 'rh850', 'riscv.h': 'riscv', 's390x.h' : 's390x', 'tricore.h' : 'tricore', @@ -43,6 +44,7 @@ 'm68k.h': 'm68k', 'ppc.h': 'ppc', 'riscv.h': 'riscv', + 'rh850.h': 'rh850', 's390x.h' : 's390x', 'tricore.h' : 'tricore', 'unicorn.h': 'unicorn', @@ -62,6 +64,7 @@ 'sparc.h': 'sparc', 'm68k.h': 'm68k', 'ppc.h': 'ppc', + 'rh850.h': 'rh850', 'riscv.h': 'riscv', 's390x.h' : 's390x', 'tricore.h' : 'tricore', @@ -82,6 +85,7 @@ 'sparc.h': 'Sparc', 'm68k.h': 'M68k', 'ppc.h': 'Ppc', + 'rh850.h': 'Rh850', 'riscv.h': 'Riscv', 's390x.h' : 'S390x', 'tricore.h' : 'TriCore', @@ -102,6 +106,7 @@ 'sparc.h': 'Sparc', 'm68k.h': 'M68k', 'ppc.h': 'Ppc', + 'rh850.h': 'Rh850', 'riscv.h': 'Riscv', 's390x.h' : 'S390x', 'tricore.h' : 'TriCore', @@ -122,6 +127,7 @@ 'sparc.h': 'Sparc', 'm68k.h': 'M68k', 'ppc.h': 'Ppc', + 'rh850.h': 'Rh850', 'riscv.h': 'Riscv', 's390x.h' : 'S390x', 'tricore.h' : 'TriCore', @@ -143,6 +149,7 @@ 'm68k.h': 'm68k', 'ppc.h': 'ppc', 'riscv.h': 'riscv', + 'rh850.h': 'rh850', 's390x.h' : 's390x', 'tricore.h' : 'tricore', 'unicorn.h': 'unicorn', diff --git a/bindings/dotnet/UnicornEngine/Const/Common.fs b/bindings/dotnet/UnicornEngine/Const/Common.fs index f44d114903..02c813d177 100644 --- a/bindings/dotnet/UnicornEngine/Const/Common.fs +++ b/bindings/dotnet/UnicornEngine/Const/Common.fs @@ -28,7 +28,8 @@ module Common = let UC_ARCH_RISCV = 8 let UC_ARCH_S390X = 9 let UC_ARCH_TRICORE = 10 - let UC_ARCH_MAX = 11 + let UC_ARCH_RH850 = 11 + let UC_ARCH_MAX = 12 let UC_MODE_LITTLE_ENDIAN = 0 let UC_MODE_BIG_ENDIAN = 1073741824 @@ -55,6 +56,7 @@ module Common = let UC_MODE_SPARC32 = 4 let UC_MODE_SPARC64 = 8 let UC_MODE_V9 = 16 + let UC_MODE_RH850 = 4 let UC_MODE_RISCV32 = 4 let UC_MODE_RISCV64 = 8 diff --git a/bindings/dotnet/UnicornEngine/Const/Rh850.fs b/bindings/dotnet/UnicornEngine/Const/Rh850.fs new file mode 100644 index 0000000000..073f10416f --- /dev/null +++ b/bindings/dotnet/UnicornEngine/Const/Rh850.fs @@ -0,0 +1,99 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +namespace UnicornManaged.Const + +open System + +[<AutoOpen>] +module Rh850 = + let UC_RH850_SYSREG_SELID0 = 32 + let UC_RH850_SYSREG_SELID1 = 64 + let UC_RH850_SYSREG_SELID2 = 96 + let UC_RH850_SYSREG_SELID3 = 128 + let UC_RH850_SYSREG_SELID4 = 160 + let UC_RH850_SYSREG_SELID5 = 192 + let UC_RH850_SYSREG_SELID6 = 224 + let UC_RH850_SYSREG_SELID7 = 256 + + // RH850 global purpose registers + + let UC_RH850_REG_R0 = 0 + let UC_RH850_REG_R1 = 1 + let UC_RH850_REG_R2 = 2 + let UC_RH850_REG_R3 = 3 + let UC_RH850_REG_R4 = 4 + let UC_RH850_REG_R5 = 5 + let UC_RH850_REG_R6 = 6 + let UC_RH850_REG_R7 = 7 + let UC_RH850_REG_R8 = 8 + let UC_RH850_REG_R9 = 9 + let UC_RH850_REG_R10 = 10 + let UC_RH850_REG_R11 = 11 + let UC_RH850_REG_R12 = 12 + let UC_RH850_REG_R13 = 13 + let UC_RH850_REG_R14 = 14 + let UC_RH850_REG_R15 = 15 + let UC_RH850_REG_R16 = 16 + let UC_RH850_REG_R17 = 17 + let UC_RH850_REG_R18 = 18 + let UC_RH850_REG_R19 = 19 + let UC_RH850_REG_R20 = 20 + let UC_RH850_REG_R21 = 21 + let UC_RH850_REG_R22 = 22 + let UC_RH850_REG_R23 = 23 + let UC_RH850_REG_R24 = 24 + let UC_RH850_REG_R25 = 25 + let UC_RH850_REG_R26 = 26 + let UC_RH850_REG_R27 = 27 + let UC_RH850_REG_R28 = 28 + let UC_RH850_REG_R29 = 29 + let UC_RH850_REG_R30 = 30 + let UC_RH850_REG_R31 = 31 + + // RH850 system registers, selection ID 0 + let UC_RH850_REG_EIPC = 32 + let UC_RH850_REG_EIPSW = 33 + let UC_RH850_REG_FEPC = 34 + let UC_RH850_REG_FEPSW = 35 + let UC_RH850_REG_ECR = 36 + let UC_RH850_REG_PSW = 37 + let UC_RH850_REG_FPSR = 38 + let UC_RH850_REG_FPEPC = 39 + let UC_RH850_REG_FPST = 40 + let UC_RH850_REG_FPCC = 41 + let UC_RH850_REG_FPCFG = 42 + let UC_RH850_REG_FPEC = 43 + let UC_RH850_REG_EIIC = 45 + let UC_RH850_REG_FEIC = 46 + let UC_RH850_REG_CTPC = 48 + let UC_RH850_REG_CTPSW = 49 + let UC_RH850_REG_CTBP = 52 + let UC_RH850_REG_EIWR = 60 + let UC_RH850_REG_FEWR = 61 + let UC_RH850_REG_BSEL = 63 + + // RH850 system regusters, selection ID 1 + let UC_RH850_REG_MCFG0 = 64 + let UC_RH850_REG_RBASE = 65 + let UC_RH850_REG_EBASE = 66 + let UC_RH850_REG_INTBP = 67 + let UC_RH850_REG_MCTL = 68 + let UC_RH850_REG_PID = 69 + let UC_RH850_REG_SCCFG = 75 + let UC_RH850_REG_SCBP = 76 + + // RH850 system registers, selection ID 2 + let UC_RH850_REG_HTCFG0 = 96 + let UC_RH850_REG_MEA = 102 + let UC_RH850_REG_ASID = 103 + let UC_RH850_REG_MEI = 104 + let UC_RH850_REG_PC = 288 + let UC_RH850_REG_ENDING = 289 + + // RH8509 Registers aliases. + + let UC_RH850_REG_ZERO = 0 + let UC_RH850_REG_SP = 3 + let UC_RH850_REG_EP = 30 + let UC_RH850_REG_LP = 31 + diff --git a/bindings/go/unicorn/rh850_const.go b/bindings/go/unicorn/rh850_const.go new file mode 100644 index 0000000000..72ad301628 --- /dev/null +++ b/bindings/go/unicorn/rh850_const.go @@ -0,0 +1,94 @@ +package unicorn +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [rh850_const.go] +const ( + RH850_SYSREG_SELID0 = 32 + RH850_SYSREG_SELID1 = 64 + RH850_SYSREG_SELID2 = 96 + RH850_SYSREG_SELID3 = 128 + RH850_SYSREG_SELID4 = 160 + RH850_SYSREG_SELID5 = 192 + RH850_SYSREG_SELID6 = 224 + RH850_SYSREG_SELID7 = 256 + +// RH850 global purpose registers + + RH850_REG_R0 = 0 + RH850_REG_R1 = 1 + RH850_REG_R2 = 2 + RH850_REG_R3 = 3 + RH850_REG_R4 = 4 + RH850_REG_R5 = 5 + RH850_REG_R6 = 6 + RH850_REG_R7 = 7 + RH850_REG_R8 = 8 + RH850_REG_R9 = 9 + RH850_REG_R10 = 10 + RH850_REG_R11 = 11 + RH850_REG_R12 = 12 + RH850_REG_R13 = 13 + RH850_REG_R14 = 14 + RH850_REG_R15 = 15 + RH850_REG_R16 = 16 + RH850_REG_R17 = 17 + RH850_REG_R18 = 18 + RH850_REG_R19 = 19 + RH850_REG_R20 = 20 + RH850_REG_R21 = 21 + RH850_REG_R22 = 22 + RH850_REG_R23 = 23 + RH850_REG_R24 = 24 + RH850_REG_R25 = 25 + RH850_REG_R26 = 26 + RH850_REG_R27 = 27 + RH850_REG_R28 = 28 + RH850_REG_R29 = 29 + RH850_REG_R30 = 30 + RH850_REG_R31 = 31 + +// RH850 system registers, selection ID 0 + RH850_REG_EIPC = 32 + RH850_REG_EIPSW = 33 + RH850_REG_FEPC = 34 + RH850_REG_FEPSW = 35 + RH850_REG_ECR = 36 + RH850_REG_PSW = 37 + RH850_REG_FPSR = 38 + RH850_REG_FPEPC = 39 + RH850_REG_FPST = 40 + RH850_REG_FPCC = 41 + RH850_REG_FPCFG = 42 + RH850_REG_FPEC = 43 + RH850_REG_EIIC = 45 + RH850_REG_FEIC = 46 + RH850_REG_CTPC = 48 + RH850_REG_CTPSW = 49 + RH850_REG_CTBP = 52 + RH850_REG_EIWR = 60 + RH850_REG_FEWR = 61 + RH850_REG_BSEL = 63 + +// RH850 system regusters, selection ID 1 + RH850_REG_MCFG0 = 64 + RH850_REG_RBASE = 65 + RH850_REG_EBASE = 66 + RH850_REG_INTBP = 67 + RH850_REG_MCTL = 68 + RH850_REG_PID = 69 + RH850_REG_SCCFG = 75 + RH850_REG_SCBP = 76 + +// RH850 system registers, selection ID 2 + RH850_REG_HTCFG0 = 96 + RH850_REG_MEA = 102 + RH850_REG_ASID = 103 + RH850_REG_MEI = 104 + RH850_REG_PC = 288 + RH850_REG_ENDING = 289 + +// RH8509 Registers aliases. + + RH850_REG_ZERO = 0 + RH850_REG_SP = 3 + RH850_REG_EP = 30 + RH850_REG_LP = 31 +) \ No newline at end of file diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index f82cf91667..7a036992ff 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -23,7 +23,8 @@ const ( ARCH_RISCV = 8 ARCH_S390X = 9 ARCH_TRICORE = 10 - ARCH_MAX = 11 + ARCH_RH850 = 11 + ARCH_MAX = 12 MODE_LITTLE_ENDIAN = 0 MODE_BIG_ENDIAN = 1073741824 @@ -50,6 +51,7 @@ const ( MODE_SPARC32 = 4 MODE_SPARC64 = 8 MODE_V9 = 16 + MODE_RH850 = 4 MODE_RISCV32 = 4 MODE_RISCV64 = 8 diff --git a/bindings/java/src/main/java/unicorn/Rh850Const.java b/bindings/java/src/main/java/unicorn/Rh850Const.java new file mode 100644 index 0000000000..098eea41b5 --- /dev/null +++ b/bindings/java/src/main/java/unicorn/Rh850Const.java @@ -0,0 +1,97 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +package unicorn; + +public interface Rh850Const { + public static final int UC_RH850_SYSREG_SELID0 = 32; + public static final int UC_RH850_SYSREG_SELID1 = 64; + public static final int UC_RH850_SYSREG_SELID2 = 96; + public static final int UC_RH850_SYSREG_SELID3 = 128; + public static final int UC_RH850_SYSREG_SELID4 = 160; + public static final int UC_RH850_SYSREG_SELID5 = 192; + public static final int UC_RH850_SYSREG_SELID6 = 224; + public static final int UC_RH850_SYSREG_SELID7 = 256; + +// RH850 global purpose registers + + public static final int UC_RH850_REG_R0 = 0; + public static final int UC_RH850_REG_R1 = 1; + public static final int UC_RH850_REG_R2 = 2; + public static final int UC_RH850_REG_R3 = 3; + public static final int UC_RH850_REG_R4 = 4; + public static final int UC_RH850_REG_R5 = 5; + public static final int UC_RH850_REG_R6 = 6; + public static final int UC_RH850_REG_R7 = 7; + public static final int UC_RH850_REG_R8 = 8; + public static final int UC_RH850_REG_R9 = 9; + public static final int UC_RH850_REG_R10 = 10; + public static final int UC_RH850_REG_R11 = 11; + public static final int UC_RH850_REG_R12 = 12; + public static final int UC_RH850_REG_R13 = 13; + public static final int UC_RH850_REG_R14 = 14; + public static final int UC_RH850_REG_R15 = 15; + public static final int UC_RH850_REG_R16 = 16; + public static final int UC_RH850_REG_R17 = 17; + public static final int UC_RH850_REG_R18 = 18; + public static final int UC_RH850_REG_R19 = 19; + public static final int UC_RH850_REG_R20 = 20; + public static final int UC_RH850_REG_R21 = 21; + public static final int UC_RH850_REG_R22 = 22; + public static final int UC_RH850_REG_R23 = 23; + public static final int UC_RH850_REG_R24 = 24; + public static final int UC_RH850_REG_R25 = 25; + public static final int UC_RH850_REG_R26 = 26; + public static final int UC_RH850_REG_R27 = 27; + public static final int UC_RH850_REG_R28 = 28; + public static final int UC_RH850_REG_R29 = 29; + public static final int UC_RH850_REG_R30 = 30; + public static final int UC_RH850_REG_R31 = 31; + +// RH850 system registers, selection ID 0 + public static final int UC_RH850_REG_EIPC = 32; + public static final int UC_RH850_REG_EIPSW = 33; + public static final int UC_RH850_REG_FEPC = 34; + public static final int UC_RH850_REG_FEPSW = 35; + public static final int UC_RH850_REG_ECR = 36; + public static final int UC_RH850_REG_PSW = 37; + public static final int UC_RH850_REG_FPSR = 38; + public static final int UC_RH850_REG_FPEPC = 39; + public static final int UC_RH850_REG_FPST = 40; + public static final int UC_RH850_REG_FPCC = 41; + public static final int UC_RH850_REG_FPCFG = 42; + public static final int UC_RH850_REG_FPEC = 43; + public static final int UC_RH850_REG_EIIC = 45; + public static final int UC_RH850_REG_FEIC = 46; + public static final int UC_RH850_REG_CTPC = 48; + public static final int UC_RH850_REG_CTPSW = 49; + public static final int UC_RH850_REG_CTBP = 52; + public static final int UC_RH850_REG_EIWR = 60; + public static final int UC_RH850_REG_FEWR = 61; + public static final int UC_RH850_REG_BSEL = 63; + +// RH850 system regusters, selection ID 1 + public static final int UC_RH850_REG_MCFG0 = 64; + public static final int UC_RH850_REG_RBASE = 65; + public static final int UC_RH850_REG_EBASE = 66; + public static final int UC_RH850_REG_INTBP = 67; + public static final int UC_RH850_REG_MCTL = 68; + public static final int UC_RH850_REG_PID = 69; + public static final int UC_RH850_REG_SCCFG = 75; + public static final int UC_RH850_REG_SCBP = 76; + +// RH850 system registers, selection ID 2 + public static final int UC_RH850_REG_HTCFG0 = 96; + public static final int UC_RH850_REG_MEA = 102; + public static final int UC_RH850_REG_ASID = 103; + public static final int UC_RH850_REG_MEI = 104; + public static final int UC_RH850_REG_PC = 288; + public static final int UC_RH850_REG_ENDING = 289; + +// RH8509 Registers aliases. + + public static final int UC_RH850_REG_ZERO = 0; + public static final int UC_RH850_REG_SP = 3; + public static final int UC_RH850_REG_EP = 30; + public static final int UC_RH850_REG_LP = 31; + +} diff --git a/bindings/java/src/main/java/unicorn/UnicornConst.java b/bindings/java/src/main/java/unicorn/UnicornConst.java index 8ab6fdb174..ac91590da1 100644 --- a/bindings/java/src/main/java/unicorn/UnicornConst.java +++ b/bindings/java/src/main/java/unicorn/UnicornConst.java @@ -25,7 +25,8 @@ public interface UnicornConst { public static final int UC_ARCH_RISCV = 8; public static final int UC_ARCH_S390X = 9; public static final int UC_ARCH_TRICORE = 10; - public static final int UC_ARCH_MAX = 11; + public static final int UC_ARCH_RH850 = 11; + public static final int UC_ARCH_MAX = 12; public static final int UC_MODE_LITTLE_ENDIAN = 0; public static final int UC_MODE_BIG_ENDIAN = 1073741824; @@ -52,6 +53,7 @@ public interface UnicornConst { public static final int UC_MODE_SPARC32 = 4; public static final int UC_MODE_SPARC64 = 8; public static final int UC_MODE_V9 = 16; + public static final int UC_MODE_RH850 = 4; public static final int UC_MODE_RISCV32 = 4; public static final int UC_MODE_RISCV64 = 8; diff --git a/bindings/pascal/unicorn/Rh850Const.pas b/bindings/pascal/unicorn/Rh850Const.pas new file mode 100644 index 0000000000..c405b3c464 --- /dev/null +++ b/bindings/pascal/unicorn/Rh850Const.pas @@ -0,0 +1,99 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit Rh850Const; + +interface + +const UC_RH850_SYSREG_SELID0 = 32; + UC_RH850_SYSREG_SELID1 = 64; + UC_RH850_SYSREG_SELID2 = 96; + UC_RH850_SYSREG_SELID3 = 128; + UC_RH850_SYSREG_SELID4 = 160; + UC_RH850_SYSREG_SELID5 = 192; + UC_RH850_SYSREG_SELID6 = 224; + UC_RH850_SYSREG_SELID7 = 256; + +// RH850 global purpose registers + + UC_RH850_REG_R0 = 0; + UC_RH850_REG_R1 = 1; + UC_RH850_REG_R2 = 2; + UC_RH850_REG_R3 = 3; + UC_RH850_REG_R4 = 4; + UC_RH850_REG_R5 = 5; + UC_RH850_REG_R6 = 6; + UC_RH850_REG_R7 = 7; + UC_RH850_REG_R8 = 8; + UC_RH850_REG_R9 = 9; + UC_RH850_REG_R10 = 10; + UC_RH850_REG_R11 = 11; + UC_RH850_REG_R12 = 12; + UC_RH850_REG_R13 = 13; + UC_RH850_REG_R14 = 14; + UC_RH850_REG_R15 = 15; + UC_RH850_REG_R16 = 16; + UC_RH850_REG_R17 = 17; + UC_RH850_REG_R18 = 18; + UC_RH850_REG_R19 = 19; + UC_RH850_REG_R20 = 20; + UC_RH850_REG_R21 = 21; + UC_RH850_REG_R22 = 22; + UC_RH850_REG_R23 = 23; + UC_RH850_REG_R24 = 24; + UC_RH850_REG_R25 = 25; + UC_RH850_REG_R26 = 26; + UC_RH850_REG_R27 = 27; + UC_RH850_REG_R28 = 28; + UC_RH850_REG_R29 = 29; + UC_RH850_REG_R30 = 30; + UC_RH850_REG_R31 = 31; + +// RH850 system registers, selection ID 0 + UC_RH850_REG_EIPC = 32; + UC_RH850_REG_EIPSW = 33; + UC_RH850_REG_FEPC = 34; + UC_RH850_REG_FEPSW = 35; + UC_RH850_REG_ECR = 36; + UC_RH850_REG_PSW = 37; + UC_RH850_REG_FPSR = 38; + UC_RH850_REG_FPEPC = 39; + UC_RH850_REG_FPST = 40; + UC_RH850_REG_FPCC = 41; + UC_RH850_REG_FPCFG = 42; + UC_RH850_REG_FPEC = 43; + UC_RH850_REG_EIIC = 45; + UC_RH850_REG_FEIC = 46; + UC_RH850_REG_CTPC = 48; + UC_RH850_REG_CTPSW = 49; + UC_RH850_REG_CTBP = 52; + UC_RH850_REG_EIWR = 60; + UC_RH850_REG_FEWR = 61; + UC_RH850_REG_BSEL = 63; + +// RH850 system regusters, selection ID 1 + UC_RH850_REG_MCFG0 = 64; + UC_RH850_REG_RBASE = 65; + UC_RH850_REG_EBASE = 66; + UC_RH850_REG_INTBP = 67; + UC_RH850_REG_MCTL = 68; + UC_RH850_REG_PID = 69; + UC_RH850_REG_SCCFG = 75; + UC_RH850_REG_SCBP = 76; + +// RH850 system registers, selection ID 2 + UC_RH850_REG_HTCFG0 = 96; + UC_RH850_REG_MEA = 102; + UC_RH850_REG_ASID = 103; + UC_RH850_REG_MEI = 104; + UC_RH850_REG_PC = 288; + UC_RH850_REG_ENDING = 289; + +// RH8509 Registers aliases. + + UC_RH850_REG_ZERO = 0; + UC_RH850_REG_SP = 3; + UC_RH850_REG_EP = 30; + UC_RH850_REG_LP = 31; + +implementation +end. \ No newline at end of file diff --git a/bindings/pascal/unicorn/UnicornConst.pas b/bindings/pascal/unicorn/UnicornConst.pas index 8b38e8e034..a959c25703 100644 --- a/bindings/pascal/unicorn/UnicornConst.pas +++ b/bindings/pascal/unicorn/UnicornConst.pas @@ -26,7 +26,8 @@ interface UC_ARCH_RISCV = 8; UC_ARCH_S390X = 9; UC_ARCH_TRICORE = 10; - UC_ARCH_MAX = 11; + UC_ARCH_RH850 = 11; + UC_ARCH_MAX = 12; UC_MODE_LITTLE_ENDIAN = 0; UC_MODE_BIG_ENDIAN = 1073741824; @@ -53,6 +54,7 @@ interface UC_MODE_SPARC32 = 4; UC_MODE_SPARC64 = 8; UC_MODE_V9 = 16; + UC_MODE_RH850 = 4; UC_MODE_RISCV32 = 4; UC_MODE_RISCV64 = 8; diff --git a/bindings/python/sample_rh850.py b/bindings/python/sample_rh850.py new file mode 100644 index 0000000000..294d76ff2b --- /dev/null +++ b/bindings/python/sample_rh850.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# Sample code for RH850 of Unicorn. Damien Cauquil <dcauquil@quarkslab.com> +# + +from __future__ import print_function +from unicorn import * +from unicorn.rh850_const import * + + +''' + 0 01 0e 06 addi 6, r1, r1 + 4 00 c1 11 add r1, r2 +''' +RH850_CODE = b"\x01\x0e\x06\x00\xc1\x11" + +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +def hook_block(uc, address, size, user_data): + print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size)) + + +# callback for tracing instructions +def hook_code(uc, address, size, user_data): + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) + + +# Test RH850 +def test_rh850(): + print("Emulate RH850 code") + try: + # Initialize emulator in RISCV32 mode + mu = Uc(UC_ARCH_RH850, 0) + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, RH850_CODE) + + # initialize machine registers + mu.reg_write(UC_RH850_REG_R1, 0x1234) + mu.reg_write(UC_RH850_REG_R2, 0x7890) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + len(RH850_CODE)) + + # now print out some registers + print(">>> Emulation done. Below is the CPU context") + + r1 = mu.reg_read(UC_RH850_REG_R1) + r2 = mu.reg_read(UC_RH850_REG_R2) + print(">>> R1 = 0x%x" % r1) + print(">>> R2 = 0x%x" % r2) + + except UcError as e: + print("ERROR: %s" % e) + + +if __name__ == '__main__': + test_rh850() + diff --git a/bindings/python/unicorn/rh850_const.py b/bindings/python/unicorn/rh850_const.py new file mode 100644 index 0000000000..6985d85e4f --- /dev/null +++ b/bindings/python/unicorn/rh850_const.py @@ -0,0 +1,91 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [rh850_const.py] +UC_RH850_SYSREG_SELID0 = 32 +UC_RH850_SYSREG_SELID1 = 64 +UC_RH850_SYSREG_SELID2 = 96 +UC_RH850_SYSREG_SELID3 = 128 +UC_RH850_SYSREG_SELID4 = 160 +UC_RH850_SYSREG_SELID5 = 192 +UC_RH850_SYSREG_SELID6 = 224 +UC_RH850_SYSREG_SELID7 = 256 + +# RH850 global purpose registers + +UC_RH850_REG_R0 = 0 +UC_RH850_REG_R1 = 1 +UC_RH850_REG_R2 = 2 +UC_RH850_REG_R3 = 3 +UC_RH850_REG_R4 = 4 +UC_RH850_REG_R5 = 5 +UC_RH850_REG_R6 = 6 +UC_RH850_REG_R7 = 7 +UC_RH850_REG_R8 = 8 +UC_RH850_REG_R9 = 9 +UC_RH850_REG_R10 = 10 +UC_RH850_REG_R11 = 11 +UC_RH850_REG_R12 = 12 +UC_RH850_REG_R13 = 13 +UC_RH850_REG_R14 = 14 +UC_RH850_REG_R15 = 15 +UC_RH850_REG_R16 = 16 +UC_RH850_REG_R17 = 17 +UC_RH850_REG_R18 = 18 +UC_RH850_REG_R19 = 19 +UC_RH850_REG_R20 = 20 +UC_RH850_REG_R21 = 21 +UC_RH850_REG_R22 = 22 +UC_RH850_REG_R23 = 23 +UC_RH850_REG_R24 = 24 +UC_RH850_REG_R25 = 25 +UC_RH850_REG_R26 = 26 +UC_RH850_REG_R27 = 27 +UC_RH850_REG_R28 = 28 +UC_RH850_REG_R29 = 29 +UC_RH850_REG_R30 = 30 +UC_RH850_REG_R31 = 31 + +# RH850 system registers, selection ID 0 +UC_RH850_REG_EIPC = 32 +UC_RH850_REG_EIPSW = 33 +UC_RH850_REG_FEPC = 34 +UC_RH850_REG_FEPSW = 35 +UC_RH850_REG_ECR = 36 +UC_RH850_REG_PSW = 37 +UC_RH850_REG_FPSR = 38 +UC_RH850_REG_FPEPC = 39 +UC_RH850_REG_FPST = 40 +UC_RH850_REG_FPCC = 41 +UC_RH850_REG_FPCFG = 42 +UC_RH850_REG_FPEC = 43 +UC_RH850_REG_EIIC = 45 +UC_RH850_REG_FEIC = 46 +UC_RH850_REG_CTPC = 48 +UC_RH850_REG_CTPSW = 49 +UC_RH850_REG_CTBP = 52 +UC_RH850_REG_EIWR = 60 +UC_RH850_REG_FEWR = 61 +UC_RH850_REG_BSEL = 63 + +# RH850 system regusters, selection ID 1 +UC_RH850_REG_MCFG0 = 64 +UC_RH850_REG_RBASE = 65 +UC_RH850_REG_EBASE = 66 +UC_RH850_REG_INTBP = 67 +UC_RH850_REG_MCTL = 68 +UC_RH850_REG_PID = 69 +UC_RH850_REG_SCCFG = 75 +UC_RH850_REG_SCBP = 76 + +# RH850 system registers, selection ID 2 +UC_RH850_REG_HTCFG0 = 96 +UC_RH850_REG_MEA = 102 +UC_RH850_REG_ASID = 103 +UC_RH850_REG_MEI = 104 +UC_RH850_REG_PC = 288 +UC_RH850_REG_ENDING = 289 + +# RH8509 Registers aliases. + +UC_RH850_REG_ZERO = 0 +UC_RH850_REG_SP = 3 +UC_RH850_REG_EP = 30 +UC_RH850_REG_LP = 31 diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 64247899e6..885a5eb910 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -21,7 +21,8 @@ UC_ARCH_RISCV = 8 UC_ARCH_S390X = 9 UC_ARCH_TRICORE = 10 -UC_ARCH_MAX = 11 +UC_ARCH_RH850 = 11 +UC_ARCH_MAX = 12 UC_MODE_LITTLE_ENDIAN = 0 UC_MODE_BIG_ENDIAN = 1073741824 @@ -48,6 +49,7 @@ UC_MODE_SPARC32 = 4 UC_MODE_SPARC64 = 8 UC_MODE_V9 = 16 +UC_MODE_RH850 = 4 UC_MODE_RISCV32 = 4 UC_MODE_RISCV64 = 8 diff --git a/bindings/ruby/unicorn_gem/lib/unicorn_engine/rh850_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn_engine/rh850_const.rb new file mode 100644 index 0000000000..40629b9883 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn_engine/rh850_const.rb @@ -0,0 +1,94 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [rh850_const.rb] + +module UnicornEngine + UC_RH850_SYSREG_SELID0 = 32 + UC_RH850_SYSREG_SELID1 = 64 + UC_RH850_SYSREG_SELID2 = 96 + UC_RH850_SYSREG_SELID3 = 128 + UC_RH850_SYSREG_SELID4 = 160 + UC_RH850_SYSREG_SELID5 = 192 + UC_RH850_SYSREG_SELID6 = 224 + UC_RH850_SYSREG_SELID7 = 256 + +# RH850 global purpose registers + + UC_RH850_REG_R0 = 0 + UC_RH850_REG_R1 = 1 + UC_RH850_REG_R2 = 2 + UC_RH850_REG_R3 = 3 + UC_RH850_REG_R4 = 4 + UC_RH850_REG_R5 = 5 + UC_RH850_REG_R6 = 6 + UC_RH850_REG_R7 = 7 + UC_RH850_REG_R8 = 8 + UC_RH850_REG_R9 = 9 + UC_RH850_REG_R10 = 10 + UC_RH850_REG_R11 = 11 + UC_RH850_REG_R12 = 12 + UC_RH850_REG_R13 = 13 + UC_RH850_REG_R14 = 14 + UC_RH850_REG_R15 = 15 + UC_RH850_REG_R16 = 16 + UC_RH850_REG_R17 = 17 + UC_RH850_REG_R18 = 18 + UC_RH850_REG_R19 = 19 + UC_RH850_REG_R20 = 20 + UC_RH850_REG_R21 = 21 + UC_RH850_REG_R22 = 22 + UC_RH850_REG_R23 = 23 + UC_RH850_REG_R24 = 24 + UC_RH850_REG_R25 = 25 + UC_RH850_REG_R26 = 26 + UC_RH850_REG_R27 = 27 + UC_RH850_REG_R28 = 28 + UC_RH850_REG_R29 = 29 + UC_RH850_REG_R30 = 30 + UC_RH850_REG_R31 = 31 + +# RH850 system registers, selection ID 0 + UC_RH850_REG_EIPC = 32 + UC_RH850_REG_EIPSW = 33 + UC_RH850_REG_FEPC = 34 + UC_RH850_REG_FEPSW = 35 + UC_RH850_REG_ECR = 36 + UC_RH850_REG_PSW = 37 + UC_RH850_REG_FPSR = 38 + UC_RH850_REG_FPEPC = 39 + UC_RH850_REG_FPST = 40 + UC_RH850_REG_FPCC = 41 + UC_RH850_REG_FPCFG = 42 + UC_RH850_REG_FPEC = 43 + UC_RH850_REG_EIIC = 45 + UC_RH850_REG_FEIC = 46 + UC_RH850_REG_CTPC = 48 + UC_RH850_REG_CTPSW = 49 + UC_RH850_REG_CTBP = 52 + UC_RH850_REG_EIWR = 60 + UC_RH850_REG_FEWR = 61 + UC_RH850_REG_BSEL = 63 + +# RH850 system regusters, selection ID 1 + UC_RH850_REG_MCFG0 = 64 + UC_RH850_REG_RBASE = 65 + UC_RH850_REG_EBASE = 66 + UC_RH850_REG_INTBP = 67 + UC_RH850_REG_MCTL = 68 + UC_RH850_REG_PID = 69 + UC_RH850_REG_SCCFG = 75 + UC_RH850_REG_SCBP = 76 + +# RH850 system registers, selection ID 2 + UC_RH850_REG_HTCFG0 = 96 + UC_RH850_REG_MEA = 102 + UC_RH850_REG_ASID = 103 + UC_RH850_REG_MEI = 104 + UC_RH850_REG_PC = 288 + UC_RH850_REG_ENDING = 289 + +# RH8509 Registers aliases. + + UC_RH850_REG_ZERO = 0 + UC_RH850_REG_SP = 3 + UC_RH850_REG_EP = 30 + UC_RH850_REG_LP = 31 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb index 8eaf2c3633..f022e70c81 100644 --- a/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb +++ b/bindings/ruby/unicorn_gem/lib/unicorn_engine/unicorn_const.rb @@ -23,7 +23,8 @@ module UnicornEngine UC_ARCH_RISCV = 8 UC_ARCH_S390X = 9 UC_ARCH_TRICORE = 10 - UC_ARCH_MAX = 11 + UC_ARCH_RH850 = 11 + UC_ARCH_MAX = 12 UC_MODE_LITTLE_ENDIAN = 0 UC_MODE_BIG_ENDIAN = 1073741824 @@ -50,6 +51,7 @@ module UnicornEngine UC_MODE_SPARC32 = 4 UC_MODE_SPARC64 = 8 UC_MODE_V9 = 16 + UC_MODE_RH850 = 4 UC_MODE_RISCV32 = 4 UC_MODE_RISCV64 = 8 diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 04f5431a90..f1ea169b54 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -116,6 +116,9 @@ fn build_with_cmake() { if std::env::var("CARGO_FEATURE_ARCH_TRICORE").is_ok() { archs.push_str("tricore;"); } + if std::env::var("CARGO_FEATURE_ARCH_RH850").is_ok() { + archs.push_str("rh850;"); + } if !archs.is_empty() { archs.pop(); diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 45962acf04..0828edf851 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -51,6 +51,7 @@ pub use crate::riscv::*; pub use crate::s390x::*; pub use crate::sparc::*; pub use crate::tricore::*; +pub use crate::rh850::*; pub use crate::unicorn_const::*; pub use crate::x86::*; @@ -67,6 +68,7 @@ mod riscv; mod s390x; mod sparc; mod tricore; +mod rh850; mod x86; #[derive(Debug)] @@ -999,6 +1001,7 @@ impl<'a, D> Unicorn<'a, D> { Arch::RISCV => RegisterRISCV::PC as i32, Arch::S390X => RegisterS390X::PC as i32, Arch::TRICORE => RegisterTRICORE::PC as i32, + Arch::RH850 => RegisterRH850::PC as i32, Arch::MAX => panic!("Illegal Arch specified"), }; self.reg_read(reg) @@ -1022,6 +1025,7 @@ impl<'a, D> Unicorn<'a, D> { Arch::RISCV => RegisterRISCV::PC as i32, Arch::S390X => RegisterS390X::PC as i32, Arch::TRICORE => RegisterTRICORE::PC as i32, + Arch::RH850 => RegisterRH850::PC as i32, Arch::MAX => panic!("Illegal Arch specified"), }; self.reg_write(reg, value) diff --git a/bindings/rust/src/rh850.rs b/bindings/rust/src/rh850.rs new file mode 100644 index 0000000000..92e8a16a4a --- /dev/null +++ b/bindings/rust/src/rh850.rs @@ -0,0 +1,119 @@ +#![allow(non_camel_case_types)] + +// RH850 registers +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum RegisterRH850 { + INVALID = -1, + + // General purpose registers + R0 = 0, + R1 = 1, + R2 = 2, + R3 = 3, + R4 = 4, + R5 = 5, + R6 = 6, + R7 = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15, + R16 = 16, + R17 = 17, + R18 = 18, + R19 = 19, + R20 = 20, + R21 = 21, + R22 = 22, + R23 = 23, + R24 = 24, + R25 = 25, + R26 = 26, + R27 = 27, + R28 = 28, + R29 = 29, + R30 = 30, + R31 = 31, + + // System registers + EIPC = 32, + EIPSW = 33, + FEPC = 34, + FEPSW = 35, + ECR = 36, + PSW = 37, + FPSR = 38, + FPEPC = 39, + FPST = 40, + FPCC = 41, + FPCFG = 42, + FPEC = 43, + EIIC = 45, + FEIC = 46, + CTPC = 48, + CTPSW = 49, + CTBP = 52, + EIWR = 60, + FEWR = 61, + BSEL = 63, + + // system registers, selection ID 1 + MCFG0 = 64, + RBASE = 65, + EBASE = 66, + INTBP = 67, + MCTL = 68, + PID = 69, + SCCFG = 75, + SCBP = 76, + + // system registers, selection ID 2 + HTCFG0 = 96, + MEA = 102, + ASID = 103, + MEI = 104, + PC = 288, + + ENDING = 289, +} + +impl RegisterRH850 { + // Alias registers + // (assoc) ZERO = 0, + // (assoc) SP = 3, + // (assoc) EP = 30, + // (assoc) LP = 31, + pub const ZERO: RegisterRH850 = RegisterRH850::R0; + pub const SP: RegisterRH850 = RegisterRH850::R3; + pub const EP: RegisterRH850 = RegisterRH850::R30; + pub const LP: RegisterRH850 = RegisterRH850::R31; +} + +impl From<RegisterRH850> for i32 { + fn from(r: RegisterRH850) -> Self { + r as i32 + } +} + +#[repr(i32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum RH850CpuModel { + UC_CPU_RH850_ANY = 0, +} + +impl From<RH850CpuModel> for i32 { + fn from(value: RH850CpuModel) -> Self { + value as i32 + } +} + +impl From<&RH850CpuModel> for i32 { + fn from(value: &RH850CpuModel) -> Self { + (*value) as i32 + } +} \ No newline at end of file diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index 5f8c80fd4a..59f38a6b7f 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -181,7 +181,8 @@ pub enum Arch { RISCV = 8, S390X = 9, TRICORE = 10, - MAX = 11, + RH850 = 11, + MAX = 12, } impl TryFrom<usize> for Arch { @@ -199,6 +200,7 @@ impl TryFrom<usize> for Arch { x if x == Self::RISCV as usize => Ok(Self::RISCV), x if x == Self::S390X as usize => Ok(Self::S390X), x if x == Self::TRICORE as usize => Ok(Self::TRICORE), + x if x == Self::RH850 as usize => Ok(Self::RH850), x if x == Self::MAX as usize => Ok(Self::MAX), _ => Err(uc_error::ARCH), } @@ -234,6 +236,7 @@ bitflags! { const SPARC32 = Self::MIPS32.bits(); const SPARC64 = Self::MIPS64.bits(); const V9 = Self::THUMB.bits(); + const RH850 = 4; const RISCV32 = Self::MIPS32.bits(); const RISCV64 = Self::MIPS64.bits(); } diff --git a/bindings/zig/unicorn/rh850_const.zig b/bindings/zig/unicorn/rh850_const.zig new file mode 100644 index 0000000000..3b965c6333 --- /dev/null +++ b/bindings/zig/unicorn/rh850_const.zig @@ -0,0 +1,95 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +pub const rh850Const = enum(c_int) { + RH850_SYSREG_SELID0 = 32, + RH850_SYSREG_SELID1 = 64, + RH850_SYSREG_SELID2 = 96, + RH850_SYSREG_SELID3 = 128, + RH850_SYSREG_SELID4 = 160, + RH850_SYSREG_SELID5 = 192, + RH850_SYSREG_SELID6 = 224, + RH850_SYSREG_SELID7 = 256, + +// RH850 global purpose registers + + RH850_REG_R0 = 0, + RH850_REG_R1 = 1, + RH850_REG_R2 = 2, + RH850_REG_R3 = 3, + RH850_REG_R4 = 4, + RH850_REG_R5 = 5, + RH850_REG_R6 = 6, + RH850_REG_R7 = 7, + RH850_REG_R8 = 8, + RH850_REG_R9 = 9, + RH850_REG_R10 = 10, + RH850_REG_R11 = 11, + RH850_REG_R12 = 12, + RH850_REG_R13 = 13, + RH850_REG_R14 = 14, + RH850_REG_R15 = 15, + RH850_REG_R16 = 16, + RH850_REG_R17 = 17, + RH850_REG_R18 = 18, + RH850_REG_R19 = 19, + RH850_REG_R20 = 20, + RH850_REG_R21 = 21, + RH850_REG_R22 = 22, + RH850_REG_R23 = 23, + RH850_REG_R24 = 24, + RH850_REG_R25 = 25, + RH850_REG_R26 = 26, + RH850_REG_R27 = 27, + RH850_REG_R28 = 28, + RH850_REG_R29 = 29, + RH850_REG_R30 = 30, + RH850_REG_R31 = 31, + +// RH850 system registers, selection ID 0 + RH850_REG_EIPC = 32, + RH850_REG_EIPSW = 33, + RH850_REG_FEPC = 34, + RH850_REG_FEPSW = 35, + RH850_REG_ECR = 36, + RH850_REG_PSW = 37, + RH850_REG_FPSR = 38, + RH850_REG_FPEPC = 39, + RH850_REG_FPST = 40, + RH850_REG_FPCC = 41, + RH850_REG_FPCFG = 42, + RH850_REG_FPEC = 43, + RH850_REG_EIIC = 45, + RH850_REG_FEIC = 46, + RH850_REG_CTPC = 48, + RH850_REG_CTPSW = 49, + RH850_REG_CTBP = 52, + RH850_REG_EIWR = 60, + RH850_REG_FEWR = 61, + RH850_REG_BSEL = 63, + +// RH850 system regusters, selection ID 1 + RH850_REG_MCFG0 = 64, + RH850_REG_RBASE = 65, + RH850_REG_EBASE = 66, + RH850_REG_INTBP = 67, + RH850_REG_MCTL = 68, + RH850_REG_PID = 69, + RH850_REG_SCCFG = 75, + RH850_REG_SCBP = 76, + +// RH850 system registers, selection ID 2 + RH850_REG_HTCFG0 = 96, + RH850_REG_MEA = 102, + RH850_REG_ASID = 103, + RH850_REG_MEI = 104, + RH850_REG_PC = 288, + RH850_REG_ENDING = 289, + +// RH8509 Registers aliases. + + RH850_REG_ZERO = 0, + RH850_REG_SP = 3, + RH850_REG_EP = 30, + RH850_REG_LP = 31, + +}; diff --git a/bindings/zig/unicorn/unicorn_const.zig b/bindings/zig/unicorn/unicorn_const.zig index afebcd76c3..fb2ee6add8 100644 --- a/bindings/zig/unicorn/unicorn_const.zig +++ b/bindings/zig/unicorn/unicorn_const.zig @@ -23,7 +23,8 @@ pub const unicornConst = enum(c_int) { ARCH_RISCV = 8, ARCH_S390X = 9, ARCH_TRICORE = 10, - ARCH_MAX = 11, + ARCH_RH850 = 11, + ARCH_MAX = 12, MODE_LITTLE_ENDIAN = 0, MODE_BIG_ENDIAN = 1073741824, @@ -50,6 +51,7 @@ pub const unicornConst = enum(c_int) { MODE_SPARC32 = 4, MODE_SPARC64 = 8, MODE_V9 = 16, + MODE_RH850 = 4, MODE_RISCV32 = 4, MODE_RISCV64 = 8, @@ -75,6 +77,7 @@ pub const unicornConst = enum(c_int) { ERR_HOOK_EXIST = 19, ERR_RESOURCE = 20, ERR_EXCEPTION = 21, + ERR_OVERFLOW = 22, MEM_READ = 16, MEM_WRITE = 17, MEM_FETCH = 18, @@ -140,11 +143,15 @@ pub const unicornConst = enum(c_int) { CTL_TB_FLUSH = 10, CTL_TLB_FLUSH = 11, CTL_TLB_TYPE = 12, + CTL_TCG_BUFFER_SIZE = 13, + CTL_CONTEXT_MODE = 14, PROT_NONE = 0, PROT_READ = 1, PROT_WRITE = 2, PROT_EXEC = 4, PROT_ALL = 7, + CTL_CONTEXT_CPU = 1, + CTL_CONTEXT_MEMORY = 2, }; diff --git a/include/unicorn/rh850.h b/include/unicorn/rh850.h new file mode 100644 index 0000000000..963e0bc042 --- /dev/null +++ b/include/unicorn/rh850.h @@ -0,0 +1,111 @@ +/* Unicorn Engine */ +/* By Damien Cauquil <dcauquil@quarkslab.com>, 2023 */ + +#ifndef UNICORN_RH850_H +#define UNICORN_RH850_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#pragma warning(disable : 4201) +#endif + +#define UC_RH850_SYSREG_SELID0 32 +#define UC_RH850_SYSREG_SELID1 64 +#define UC_RH850_SYSREG_SELID2 96 +#define UC_RH850_SYSREG_SELID3 128 +#define UC_RH850_SYSREG_SELID4 160 +#define UC_RH850_SYSREG_SELID5 192 +#define UC_RH850_SYSREG_SELID6 224 +#define UC_RH850_SYSREG_SELID7 256 + +//> RH850 global purpose registers +typedef enum uc_rh850_reg { + UC_RH850_REG_R0 = 0, + UC_RH850_REG_R1, + UC_RH850_REG_R2, + UC_RH850_REG_R3, + UC_RH850_REG_R4, + UC_RH850_REG_R5, + UC_RH850_REG_R6, + UC_RH850_REG_R7, + UC_RH850_REG_R8, + UC_RH850_REG_R9, + UC_RH850_REG_R10, + UC_RH850_REG_R11, + UC_RH850_REG_R12, + UC_RH850_REG_R13, + UC_RH850_REG_R14, + UC_RH850_REG_R15, + UC_RH850_REG_R16, + UC_RH850_REG_R17, + UC_RH850_REG_R18, + UC_RH850_REG_R19, + UC_RH850_REG_R20, + UC_RH850_REG_R21, + UC_RH850_REG_R22, + UC_RH850_REG_R23, + UC_RH850_REG_R24, + UC_RH850_REG_R25, + UC_RH850_REG_R26, + UC_RH850_REG_R27, + UC_RH850_REG_R28, + UC_RH850_REG_R29, + UC_RH850_REG_R30, + UC_RH850_REG_R31, + + //> RH850 system registers, selection ID 0 + UC_RH850_REG_EIPC = UC_RH850_SYSREG_SELID0, + UC_RH850_REG_EIPSW, + UC_RH850_REG_FEPC, + UC_RH850_REG_FEPSW, + UC_RH850_REG_ECR, + UC_RH850_REG_PSW, + UC_RH850_REG_FPSR, + UC_RH850_REG_FPEPC, + UC_RH850_REG_FPST, + UC_RH850_REG_FPCC, + UC_RH850_REG_FPCFG, + UC_RH850_REG_FPEC, + UC_RH850_REG_EIIC = UC_RH850_SYSREG_SELID0 + 13, + UC_RH850_REG_FEIC, + UC_RH850_REG_CTPC = UC_RH850_SYSREG_SELID0 + 16, + UC_RH850_REG_CTPSW, + UC_RH850_REG_CTBP = UC_RH850_SYSREG_SELID0 + 20, + UC_RH850_REG_EIWR = UC_RH850_SYSREG_SELID0 + 28, + UC_RH850_REG_FEWR = UC_RH850_SYSREG_SELID0 + 29, + UC_RH850_REG_BSEL = UC_RH850_SYSREG_SELID0 + 31, + + //> RH850 system regusters, selection ID 1 + UC_RH850_REG_MCFG0 = UC_RH850_SYSREG_SELID1, + UC_RH850_REG_RBASE, + UC_RH850_REG_EBASE, + UC_RH850_REG_INTBP, + UC_RH850_REG_MCTL, + UC_RH850_REG_PID, + UC_RH850_REG_SCCFG = UC_RH850_SYSREG_SELID1 + 11, + UC_RH850_REG_SCBP, + + //> RH850 system registers, selection ID 2 + UC_RH850_REG_HTCFG0 = UC_RH850_SYSREG_SELID2, + UC_RH850_REG_MEA = UC_RH850_SYSREG_SELID2 + 6, + UC_RH850_REG_ASID, + UC_RH850_REG_MEI, + + UC_RH850_REG_PC = UC_RH850_SYSREG_SELID7 + 32, + UC_RH850_REG_ENDING +} uc_cpu_rh850; + +//> RH8509 Registers aliases. +#define UC_RH850_REG_ZERO UC_RH850_REG_R0 +#define UC_RH850_REG_SP UC_RH850_REG_R3 +#define UC_RH850_REG_EP UC_RH850_REG_R30 +#define UC_RH850_REG_LP UC_RH850_REG_R31 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 91b0019cca..0946e2afea 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -33,6 +33,7 @@ typedef size_t uc_hook; #include "mips.h" #include "sparc.h" #include "ppc.h" +#include "rh850.h" #include "riscv.h" #include "s390x.h" #include "tricore.h" @@ -106,6 +107,7 @@ typedef enum uc_arch { UC_ARCH_RISCV, // RISCV architecture UC_ARCH_S390X, // S390X architecture UC_ARCH_TRICORE, // TriCore architecture + UC_ARCH_RH850, // Renesas RH850 architecture (V850e3v2) UC_ARCH_MAX, } uc_arch; @@ -152,6 +154,9 @@ typedef enum uc_mode { UC_MODE_SPARC64 = 1 << 3, // 64-bit mode UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported) + // rh850 + UC_MODE_RH850 = 1 << 2, // 32-bit mode + // riscv UC_MODE_RISCV32 = 1 << 2, // 32-bit mode UC_MODE_RISCV64 = 1 << 3, // 64-bit mode diff --git a/msvc/rh850-softmmu/config-target.h b/msvc/rh850-softmmu/config-target.h new file mode 100644 index 0000000000..69d3c14d97 --- /dev/null +++ b/msvc/rh850-softmmu/config-target.h @@ -0,0 +1,6 @@ +/* Automatically generated by create_config - do not modify */ +#define TARGET_RH850 1 +#define TARGET_NAME "rh850" +#define TARGET_RH850 1 +#define TARGET_SYSTBL_ABI common,nospu,64 +#define CONFIG_SOFTMMU 1 diff --git a/qemu/configure b/qemu/configure index 80080d0d1d..73ffc653cc 100755 --- a/qemu/configure +++ b/qemu/configure @@ -858,7 +858,7 @@ QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS" default_target_list="aarch64-softmmu \ arm-softmmu m68k-softmmu mips64el-softmmu mips64-softmmu mipsel-softmmu \ mips-softmmu ppc64-softmmu ppc-softmmu sparc64-softmmu sparc-softmmu \ - x86_64-softmmu riscv32-softmmu riscv64-softmmu s390x-softmmu \ + x86_64-softmmu rh850-softmmu riscv32-softmmu riscv64-softmmu s390x-softmmu \ tricore-softmmu" if test x"$show_help" = x"yes" ; then @@ -2599,7 +2599,7 @@ config_target_mak=$target_dir/config-target.mak target_name=$(echo $target | cut -d '-' -f 1) target_aligned_only="no" case "$target_name" in - alpha|hppa|mips64el|mips64|mipsel|mips|mipsn32|mipsn32el|sh4|sh4eb|sparc|sparc64|sparc32plus|xtensa|xtensaeb) + alpha|hppa|mips64el|mips64|mipsel|mips|mipsn32|mipsn32el|rh850|sh4|sh4eb|sparc|sparc64|sparc32plus|xtensa|xtensaeb) target_aligned_only="yes" ;; esac @@ -2715,6 +2715,11 @@ case "$target_name" in TARGET_SYSTBL_ABI=common,nospu,32 echo "TARGET_ABI32=y" >> $config_target_mak ;; + rh850) + TARGET_ARCH=rh850 + TARGET_ABI_DIR=rh850 + mttcg=no # system emulation is not supported for RH850 + ;; riscv32) TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv diff --git a/qemu/rh850.h b/qemu/rh850.h new file mode 100644 index 0000000000..071393cb7c --- /dev/null +++ b/qemu/rh850.h @@ -0,0 +1,1294 @@ +/* Autogen header for Unicorn Engine - DONOT MODIFY */ +#ifndef UNICORN_AUTOGEN_rh850_H +#define UNICORN_AUTOGEN_rh850_H +#ifndef UNICORN_ARCH_POSTFIX +#define UNICORN_ARCH_POSTFIX _rh850 +#endif +#define unicorn_fill_tlb unicorn_fill_tlb_rh850 +#define reg_read reg_read_rh850 +#define reg_write reg_write_rh850 +#define uc_init uc_init_rh850 +#define uc_add_inline_hook uc_add_inline_hook_rh850 +#define uc_del_inline_hook uc_del_inline_hook_rh850 +#define tb_invalidate_phys_range tb_invalidate_phys_range_rh850 +#define use_idiv_instructions use_idiv_instructions_rh850 +#define arm_arch arm_arch_rh850 +#define tb_target_set_jmp_target tb_target_set_jmp_target_rh850 +#define have_bmi1 have_bmi1_rh850 +#define have_popcnt have_popcnt_rh850 +#define have_avx1 have_avx1_rh850 +#define have_avx2 have_avx2_rh850 +#define have_isa have_isa_rh850 +#define have_altivec have_altivec_rh850 +#define have_vsx have_vsx_rh850 +#define flush_icache_range flush_icache_range_rh850 +#define s390_facilities s390_facilities_rh850 +#define tcg_dump_op tcg_dump_op_rh850 +#define tcg_dump_ops tcg_dump_ops_rh850 +#define tcg_gen_and_i64 tcg_gen_and_i64_rh850 +#define tcg_gen_discard_i64 tcg_gen_discard_i64_rh850 +#define tcg_gen_ld16s_i64 tcg_gen_ld16s_i64_rh850 +#define tcg_gen_ld16u_i64 tcg_gen_ld16u_i64_rh850 +#define tcg_gen_ld32s_i64 tcg_gen_ld32s_i64_rh850 +#define tcg_gen_ld32u_i64 tcg_gen_ld32u_i64_rh850 +#define tcg_gen_ld8s_i64 tcg_gen_ld8s_i64_rh850 +#define tcg_gen_ld8u_i64 tcg_gen_ld8u_i64_rh850 +#define tcg_gen_ld_i64 tcg_gen_ld_i64_rh850 +#define tcg_gen_mov_i64 tcg_gen_mov_i64_rh850 +#define tcg_gen_movi_i64 tcg_gen_movi_i64_rh850 +#define tcg_gen_mul_i64 tcg_gen_mul_i64_rh850 +#define tcg_gen_or_i64 tcg_gen_or_i64_rh850 +#define tcg_gen_sar_i64 tcg_gen_sar_i64_rh850 +#define tcg_gen_shl_i64 tcg_gen_shl_i64_rh850 +#define tcg_gen_shr_i64 tcg_gen_shr_i64_rh850 +#define tcg_gen_st_i64 tcg_gen_st_i64_rh850 +#define tcg_gen_xor_i64 tcg_gen_xor_i64_rh850 +#define cpu_icount_to_ns cpu_icount_to_ns_rh850 +#define cpu_is_stopped cpu_is_stopped_rh850 +#define cpu_get_ticks cpu_get_ticks_rh850 +#define cpu_get_clock cpu_get_clock_rh850 +#define cpu_resume cpu_resume_rh850 +#define qemu_init_vcpu qemu_init_vcpu_rh850 +#define cpu_stop_current cpu_stop_current_rh850 +#define resume_all_vcpus resume_all_vcpus_rh850 +#define vm_start vm_start_rh850 +#define address_space_dispatch_compact address_space_dispatch_compact_rh850 +#define flatview_translate flatview_translate_rh850 +#define address_space_translate_for_iotlb address_space_translate_for_iotlb_rh850 +#define qemu_get_cpu qemu_get_cpu_rh850 +#define cpu_address_space_init cpu_address_space_init_rh850 +#define cpu_get_address_space cpu_get_address_space_rh850 +#define cpu_exec_unrealizefn cpu_exec_unrealizefn_rh850 +#define cpu_exec_initfn cpu_exec_initfn_rh850 +#define cpu_exec_realizefn cpu_exec_realizefn_rh850 +#define tb_invalidate_phys_addr tb_invalidate_phys_addr_rh850 +#define cpu_watchpoint_insert cpu_watchpoint_insert_rh850 +#define cpu_watchpoint_remove_by_ref cpu_watchpoint_remove_by_ref_rh850 +#define cpu_watchpoint_remove_all cpu_watchpoint_remove_all_rh850 +#define cpu_watchpoint_address_matches cpu_watchpoint_address_matches_rh850 +#define cpu_breakpoint_insert cpu_breakpoint_insert_rh850 +#define cpu_breakpoint_remove cpu_breakpoint_remove_rh850 +#define cpu_breakpoint_remove_by_ref cpu_breakpoint_remove_by_ref_rh850 +#define cpu_breakpoint_remove_all cpu_breakpoint_remove_all_rh850 +#define cpu_abort cpu_abort_rh850 +#define cpu_physical_memory_test_and_clear_dirty cpu_physical_memory_test_and_clear_dirty_rh850 +#define memory_region_section_get_iotlb memory_region_section_get_iotlb_rh850 +#define flatview_add_to_dispatch flatview_add_to_dispatch_rh850 +#define qemu_ram_get_host_addr qemu_ram_get_host_addr_rh850 +#define qemu_ram_get_offset qemu_ram_get_offset_rh850 +#define qemu_ram_get_used_length qemu_ram_get_used_length_rh850 +#define qemu_ram_is_shared qemu_ram_is_shared_rh850 +#define qemu_ram_pagesize qemu_ram_pagesize_rh850 +#define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_rh850 +#define qemu_ram_alloc qemu_ram_alloc_rh850 +#define qemu_ram_free qemu_ram_free_rh850 +#define qemu_map_ram_ptr qemu_map_ram_ptr_rh850 +#define qemu_ram_block_host_offset qemu_ram_block_host_offset_rh850 +#define qemu_ram_block_from_host qemu_ram_block_from_host_rh850 +#define qemu_ram_addr_from_host qemu_ram_addr_from_host_rh850 +#define cpu_check_watchpoint cpu_check_watchpoint_rh850 +#define iotlb_to_section iotlb_to_section_rh850 +#define address_space_dispatch_new address_space_dispatch_new_rh850 +#define address_space_dispatch_free address_space_dispatch_free_rh850 +#define flatview_read_continue flatview_read_continue_rh850 +#define address_space_read_full address_space_read_full_rh850 +#define address_space_write address_space_write_rh850 +#define address_space_rw address_space_rw_rh850 +#define cpu_physical_memory_rw cpu_physical_memory_rw_rh850 +#define address_space_write_rom address_space_write_rom_rh850 +#define cpu_flush_icache_range cpu_flush_icache_range_rh850 +#define cpu_exec_init_all cpu_exec_init_all_rh850 +#define address_space_access_valid address_space_access_valid_rh850 +#define address_space_map address_space_map_rh850 +#define address_space_unmap address_space_unmap_rh850 +#define cpu_physical_memory_map cpu_physical_memory_map_rh850 +#define cpu_physical_memory_unmap cpu_physical_memory_unmap_rh850 +#define cpu_memory_rw_debug cpu_memory_rw_debug_rh850 +#define qemu_target_page_size qemu_target_page_size_rh850 +#define qemu_target_page_bits qemu_target_page_bits_rh850 +#define qemu_target_page_bits_min qemu_target_page_bits_min_rh850 +#define target_words_bigendian target_words_bigendian_rh850 +#define cpu_physical_memory_is_io cpu_physical_memory_is_io_rh850 +#define ram_block_discard_range ram_block_discard_range_rh850 +#define ramblock_is_pmem ramblock_is_pmem_rh850 +#define page_size_init page_size_init_rh850 +#define set_preferred_target_page_bits set_preferred_target_page_bits_rh850 +#define finalize_target_page_bits finalize_target_page_bits_rh850 +#define cpu_outb cpu_outb_rh850 +#define cpu_outw cpu_outw_rh850 +#define cpu_outl cpu_outl_rh850 +#define cpu_inb cpu_inb_rh850 +#define cpu_inw cpu_inw_rh850 +#define cpu_inl cpu_inl_rh850 +#define memory_map memory_map_rh850 +#define memory_map_io memory_map_io_rh850 +#define memory_map_ptr memory_map_ptr_rh850 +#define memory_cow memory_cow_rh850 +#define memory_unmap memory_unmap_rh850 +#define memory_moveout memory_moveout_rh850 +#define memory_movein memory_movein_rh850 +#define memory_free memory_free_rh850 +#define flatview_unref flatview_unref_rh850 +#define address_space_get_flatview address_space_get_flatview_rh850 +#define memory_region_transaction_begin memory_region_transaction_begin_rh850 +#define memory_region_transaction_commit memory_region_transaction_commit_rh850 +#define memory_region_init memory_region_init_rh850 +#define memory_region_access_valid memory_region_access_valid_rh850 +#define memory_region_dispatch_read memory_region_dispatch_read_rh850 +#define memory_region_dispatch_write memory_region_dispatch_write_rh850 +#define memory_region_init_io memory_region_init_io_rh850 +#define memory_region_init_ram_ptr memory_region_init_ram_ptr_rh850 +#define memory_region_size memory_region_size_rh850 +#define memory_region_set_readonly memory_region_set_readonly_rh850 +#define memory_region_get_ram_ptr memory_region_get_ram_ptr_rh850 +#define memory_region_from_host memory_region_from_host_rh850 +#define memory_region_get_ram_addr memory_region_get_ram_addr_rh850 +#define memory_region_add_subregion memory_region_add_subregion_rh850 +#define memory_region_del_subregion memory_region_del_subregion_rh850 +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_rh850 +#define memory_region_find memory_region_find_rh850 +#define memory_region_filter_subregions memory_region_filter_subregions_rh850 +#define memory_listener_register memory_listener_register_rh850 +#define memory_listener_unregister memory_listener_unregister_rh850 +#define address_space_remove_listeners address_space_remove_listeners_rh850 +#define address_space_init address_space_init_rh850 +#define address_space_destroy address_space_destroy_rh850 +#define memory_region_init_ram memory_region_init_ram_rh850 +#define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_rh850 +#define find_memory_mapping find_memory_mapping_rh850 +#define exec_inline_op exec_inline_op_rh850 +#define floatx80_default_nan floatx80_default_nan_rh850 +#define float_raise float_raise_rh850 +#define float16_is_quiet_nan float16_is_quiet_nan_rh850 +#define float16_is_signaling_nan float16_is_signaling_nan_rh850 +#define float32_is_quiet_nan float32_is_quiet_nan_rh850 +#define float32_is_signaling_nan float32_is_signaling_nan_rh850 +#define float64_is_quiet_nan float64_is_quiet_nan_rh850 +#define float64_is_signaling_nan float64_is_signaling_nan_rh850 +#define floatx80_is_quiet_nan floatx80_is_quiet_nan_rh850 +#define floatx80_is_signaling_nan floatx80_is_signaling_nan_rh850 +#define floatx80_silence_nan floatx80_silence_nan_rh850 +#define propagateFloatx80NaN propagateFloatx80NaN_rh850 +#define float128_is_quiet_nan float128_is_quiet_nan_rh850 +#define float128_is_signaling_nan float128_is_signaling_nan_rh850 +#define float128_silence_nan float128_silence_nan_rh850 +#define float16_add float16_add_rh850 +#define float16_sub float16_sub_rh850 +#define float32_add float32_add_rh850 +#define float32_sub float32_sub_rh850 +#define float64_add float64_add_rh850 +#define float64_sub float64_sub_rh850 +#define float16_mul float16_mul_rh850 +#define float32_mul float32_mul_rh850 +#define float64_mul float64_mul_rh850 +#define float16_muladd float16_muladd_rh850 +#define float32_muladd float32_muladd_rh850 +#define float64_muladd float64_muladd_rh850 +#define float16_div float16_div_rh850 +#define float32_div float32_div_rh850 +#define float64_div float64_div_rh850 +#define float16_to_float32 float16_to_float32_rh850 +#define float16_to_float64 float16_to_float64_rh850 +#define float32_to_float16 float32_to_float16_rh850 +#define float32_to_float64 float32_to_float64_rh850 +#define float64_to_float16 float64_to_float16_rh850 +#define float64_to_float32 float64_to_float32_rh850 +#define float16_round_to_int float16_round_to_int_rh850 +#define float32_round_to_int float32_round_to_int_rh850 +#define float64_round_to_int float64_round_to_int_rh850 +#define float16_to_int16_scalbn float16_to_int16_scalbn_rh850 +#define float16_to_int32_scalbn float16_to_int32_scalbn_rh850 +#define float16_to_int64_scalbn float16_to_int64_scalbn_rh850 +#define float32_to_int16_scalbn float32_to_int16_scalbn_rh850 +#define float32_to_int32_scalbn float32_to_int32_scalbn_rh850 +#define float32_to_int64_scalbn float32_to_int64_scalbn_rh850 +#define float64_to_int16_scalbn float64_to_int16_scalbn_rh850 +#define float64_to_int32_scalbn float64_to_int32_scalbn_rh850 +#define float64_to_int64_scalbn float64_to_int64_scalbn_rh850 +#define float16_to_int16 float16_to_int16_rh850 +#define float16_to_int32 float16_to_int32_rh850 +#define float16_to_int64 float16_to_int64_rh850 +#define float32_to_int16 float32_to_int16_rh850 +#define float32_to_int32 float32_to_int32_rh850 +#define float32_to_int64 float32_to_int64_rh850 +#define float64_to_int16 float64_to_int16_rh850 +#define float64_to_int32 float64_to_int32_rh850 +#define float64_to_int64 float64_to_int64_rh850 +#define float16_to_int16_round_to_zero float16_to_int16_round_to_zero_rh850 +#define float16_to_int32_round_to_zero float16_to_int32_round_to_zero_rh850 +#define float16_to_int64_round_to_zero float16_to_int64_round_to_zero_rh850 +#define float32_to_int16_round_to_zero float32_to_int16_round_to_zero_rh850 +#define float32_to_int32_round_to_zero float32_to_int32_round_to_zero_rh850 +#define float32_to_int64_round_to_zero float32_to_int64_round_to_zero_rh850 +#define float64_to_int16_round_to_zero float64_to_int16_round_to_zero_rh850 +#define float64_to_int32_round_to_zero float64_to_int32_round_to_zero_rh850 +#define float64_to_int64_round_to_zero float64_to_int64_round_to_zero_rh850 +#define float16_to_uint16_scalbn float16_to_uint16_scalbn_rh850 +#define float16_to_uint32_scalbn float16_to_uint32_scalbn_rh850 +#define float16_to_uint64_scalbn float16_to_uint64_scalbn_rh850 +#define float32_to_uint16_scalbn float32_to_uint16_scalbn_rh850 +#define float32_to_uint32_scalbn float32_to_uint32_scalbn_rh850 +#define float32_to_uint64_scalbn float32_to_uint64_scalbn_rh850 +#define float64_to_uint16_scalbn float64_to_uint16_scalbn_rh850 +#define float64_to_uint32_scalbn float64_to_uint32_scalbn_rh850 +#define float64_to_uint64_scalbn float64_to_uint64_scalbn_rh850 +#define float16_to_uint16 float16_to_uint16_rh850 +#define float16_to_uint32 float16_to_uint32_rh850 +#define float16_to_uint64 float16_to_uint64_rh850 +#define float32_to_uint16 float32_to_uint16_rh850 +#define float32_to_uint32 float32_to_uint32_rh850 +#define float32_to_uint64 float32_to_uint64_rh850 +#define float64_to_uint16 float64_to_uint16_rh850 +#define float64_to_uint32 float64_to_uint32_rh850 +#define float64_to_uint64 float64_to_uint64_rh850 +#define float16_to_uint16_round_to_zero float16_to_uint16_round_to_zero_rh850 +#define float16_to_uint32_round_to_zero float16_to_uint32_round_to_zero_rh850 +#define float16_to_uint64_round_to_zero float16_to_uint64_round_to_zero_rh850 +#define float32_to_uint16_round_to_zero float32_to_uint16_round_to_zero_rh850 +#define float32_to_uint32_round_to_zero float32_to_uint32_round_to_zero_rh850 +#define float32_to_uint64_round_to_zero float32_to_uint64_round_to_zero_rh850 +#define float64_to_uint16_round_to_zero float64_to_uint16_round_to_zero_rh850 +#define float64_to_uint32_round_to_zero float64_to_uint32_round_to_zero_rh850 +#define float64_to_uint64_round_to_zero float64_to_uint64_round_to_zero_rh850 +#define int64_to_float16_scalbn int64_to_float16_scalbn_rh850 +#define int32_to_float16_scalbn int32_to_float16_scalbn_rh850 +#define int16_to_float16_scalbn int16_to_float16_scalbn_rh850 +#define int64_to_float16 int64_to_float16_rh850 +#define int32_to_float16 int32_to_float16_rh850 +#define int16_to_float16 int16_to_float16_rh850 +#define int64_to_float32_scalbn int64_to_float32_scalbn_rh850 +#define int32_to_float32_scalbn int32_to_float32_scalbn_rh850 +#define int16_to_float32_scalbn int16_to_float32_scalbn_rh850 +#define int64_to_float32 int64_to_float32_rh850 +#define int32_to_float32 int32_to_float32_rh850 +#define int16_to_float32 int16_to_float32_rh850 +#define int64_to_float64_scalbn int64_to_float64_scalbn_rh850 +#define int32_to_float64_scalbn int32_to_float64_scalbn_rh850 +#define int16_to_float64_scalbn int16_to_float64_scalbn_rh850 +#define int64_to_float64 int64_to_float64_rh850 +#define int32_to_float64 int32_to_float64_rh850 +#define int16_to_float64 int16_to_float64_rh850 +#define uint64_to_float16_scalbn uint64_to_float16_scalbn_rh850 +#define uint32_to_float16_scalbn uint32_to_float16_scalbn_rh850 +#define uint16_to_float16_scalbn uint16_to_float16_scalbn_rh850 +#define uint64_to_float16 uint64_to_float16_rh850 +#define uint32_to_float16 uint32_to_float16_rh850 +#define uint16_to_float16 uint16_to_float16_rh850 +#define uint64_to_float32_scalbn uint64_to_float32_scalbn_rh850 +#define uint32_to_float32_scalbn uint32_to_float32_scalbn_rh850 +#define uint16_to_float32_scalbn uint16_to_float32_scalbn_rh850 +#define uint64_to_float32 uint64_to_float32_rh850 +#define uint32_to_float32 uint32_to_float32_rh850 +#define uint16_to_float32 uint16_to_float32_rh850 +#define uint64_to_float64_scalbn uint64_to_float64_scalbn_rh850 +#define uint32_to_float64_scalbn uint32_to_float64_scalbn_rh850 +#define uint16_to_float64_scalbn uint16_to_float64_scalbn_rh850 +#define uint64_to_float64 uint64_to_float64_rh850 +#define uint32_to_float64 uint32_to_float64_rh850 +#define uint16_to_float64 uint16_to_float64_rh850 +#define float16_min float16_min_rh850 +#define float16_minnum float16_minnum_rh850 +#define float16_minnummag float16_minnummag_rh850 +#define float16_max float16_max_rh850 +#define float16_maxnum float16_maxnum_rh850 +#define float16_maxnummag float16_maxnummag_rh850 +#define float32_min float32_min_rh850 +#define float32_minnum float32_minnum_rh850 +#define float32_minnummag float32_minnummag_rh850 +#define float32_max float32_max_rh850 +#define float32_maxnum float32_maxnum_rh850 +#define float32_maxnummag float32_maxnummag_rh850 +#define float64_min float64_min_rh850 +#define float64_minnum float64_minnum_rh850 +#define float64_minnummag float64_minnummag_rh850 +#define float64_max float64_max_rh850 +#define float64_maxnum float64_maxnum_rh850 +#define float64_maxnummag float64_maxnummag_rh850 +#define float16_compare float16_compare_rh850 +#define float16_compare_quiet float16_compare_quiet_rh850 +#define float32_compare float32_compare_rh850 +#define float32_compare_quiet float32_compare_quiet_rh850 +#define float64_compare float64_compare_rh850 +#define float64_compare_quiet float64_compare_quiet_rh850 +#define float16_scalbn float16_scalbn_rh850 +#define float32_scalbn float32_scalbn_rh850 +#define float64_scalbn float64_scalbn_rh850 +#define float16_sqrt float16_sqrt_rh850 +#define float32_sqrt float32_sqrt_rh850 +#define float64_sqrt float64_sqrt_rh850 +#define float16_default_nan float16_default_nan_rh850 +#define float32_default_nan float32_default_nan_rh850 +#define float64_default_nan float64_default_nan_rh850 +#define float128_default_nan float128_default_nan_rh850 +#define float16_silence_nan float16_silence_nan_rh850 +#define float32_silence_nan float32_silence_nan_rh850 +#define float64_silence_nan float64_silence_nan_rh850 +#define float16_squash_input_denormal float16_squash_input_denormal_rh850 +#define float32_squash_input_denormal float32_squash_input_denormal_rh850 +#define float64_squash_input_denormal float64_squash_input_denormal_rh850 +#define normalizeFloatx80Subnormal normalizeFloatx80Subnormal_rh850 +#define roundAndPackFloatx80 roundAndPackFloatx80_rh850 +#define normalizeRoundAndPackFloatx80 normalizeRoundAndPackFloatx80_rh850 +#define int32_to_floatx80 int32_to_floatx80_rh850 +#define int32_to_float128 int32_to_float128_rh850 +#define int64_to_floatx80 int64_to_floatx80_rh850 +#define int64_to_float128 int64_to_float128_rh850 +#define uint64_to_float128 uint64_to_float128_rh850 +#define float32_to_floatx80 float32_to_floatx80_rh850 +#define float32_to_float128 float32_to_float128_rh850 +#define float32_rem float32_rem_rh850 +#define float32_exp2 float32_exp2_rh850 +#define float32_log2 float32_log2_rh850 +#define float32_eq float32_eq_rh850 +#define float32_le float32_le_rh850 +#define float32_lt float32_lt_rh850 +#define float32_unordered float32_unordered_rh850 +#define float32_eq_quiet float32_eq_quiet_rh850 +#define float32_le_quiet float32_le_quiet_rh850 +#define float32_lt_quiet float32_lt_quiet_rh850 +#define float32_unordered_quiet float32_unordered_quiet_rh850 +#define float64_to_floatx80 float64_to_floatx80_rh850 +#define float64_to_float128 float64_to_float128_rh850 +#define float64_rem float64_rem_rh850 +#define float64_log2 float64_log2_rh850 +#define float64_eq float64_eq_rh850 +#define float64_le float64_le_rh850 +#define float64_lt float64_lt_rh850 +#define float64_unordered float64_unordered_rh850 +#define float64_eq_quiet float64_eq_quiet_rh850 +#define float64_le_quiet float64_le_quiet_rh850 +#define float64_lt_quiet float64_lt_quiet_rh850 +#define float64_unordered_quiet float64_unordered_quiet_rh850 +#define floatx80_to_int32 floatx80_to_int32_rh850 +#define floatx80_to_int32_round_to_zero floatx80_to_int32_round_to_zero_rh850 +#define floatx80_to_int64 floatx80_to_int64_rh850 +#define floatx80_to_int64_round_to_zero floatx80_to_int64_round_to_zero_rh850 +#define floatx80_to_float32 floatx80_to_float32_rh850 +#define floatx80_to_float64 floatx80_to_float64_rh850 +#define floatx80_to_float128 floatx80_to_float128_rh850 +#define floatx80_round floatx80_round_rh850 +#define floatx80_round_to_int floatx80_round_to_int_rh850 +#define floatx80_add floatx80_add_rh850 +#define floatx80_sub floatx80_sub_rh850 +#define floatx80_mul floatx80_mul_rh850 +#define floatx80_div floatx80_div_rh850 +#define floatx80_rem floatx80_rem_rh850 +#define floatx80_sqrt floatx80_sqrt_rh850 +#define floatx80_eq floatx80_eq_rh850 +#define floatx80_le floatx80_le_rh850 +#define floatx80_lt floatx80_lt_rh850 +#define floatx80_unordered floatx80_unordered_rh850 +#define floatx80_eq_quiet floatx80_eq_quiet_rh850 +#define floatx80_le_quiet floatx80_le_quiet_rh850 +#define floatx80_lt_quiet floatx80_lt_quiet_rh850 +#define floatx80_unordered_quiet floatx80_unordered_quiet_rh850 +#define float128_to_int32 float128_to_int32_rh850 +#define float128_to_int32_round_to_zero float128_to_int32_round_to_zero_rh850 +#define float128_to_int64 float128_to_int64_rh850 +#define float128_to_int64_round_to_zero float128_to_int64_round_to_zero_rh850 +#define float128_to_uint64 float128_to_uint64_rh850 +#define float128_to_uint64_round_to_zero float128_to_uint64_round_to_zero_rh850 +#define float128_to_uint32_round_to_zero float128_to_uint32_round_to_zero_rh850 +#define float128_to_uint32 float128_to_uint32_rh850 +#define float128_to_float32 float128_to_float32_rh850 +#define float128_to_float64 float128_to_float64_rh850 +#define float128_to_floatx80 float128_to_floatx80_rh850 +#define float128_round_to_int float128_round_to_int_rh850 +#define float128_add float128_add_rh850 +#define float128_sub float128_sub_rh850 +#define float128_mul float128_mul_rh850 +#define float128_div float128_div_rh850 +#define float128_rem float128_rem_rh850 +#define float128_sqrt float128_sqrt_rh850 +#define float128_eq float128_eq_rh850 +#define float128_le float128_le_rh850 +#define float128_lt float128_lt_rh850 +#define float128_unordered float128_unordered_rh850 +#define float128_eq_quiet float128_eq_quiet_rh850 +#define float128_le_quiet float128_le_quiet_rh850 +#define float128_lt_quiet float128_lt_quiet_rh850 +#define float128_unordered_quiet float128_unordered_quiet_rh850 +#define floatx80_compare floatx80_compare_rh850 +#define floatx80_compare_quiet floatx80_compare_quiet_rh850 +#define float128_compare float128_compare_rh850 +#define float128_compare_quiet float128_compare_quiet_rh850 +#define floatx80_scalbn floatx80_scalbn_rh850 +#define float128_scalbn float128_scalbn_rh850 +#define softfloat_init softfloat_init_rh850 +#define tcg_optimize tcg_optimize_rh850 +#define gen_new_label gen_new_label_rh850 +#define tcg_can_emit_vec_op tcg_can_emit_vec_op_rh850 +#define tcg_expand_vec_op tcg_expand_vec_op_rh850 +#define tcg_register_jit tcg_register_jit_rh850 +#define tcg_tb_insert tcg_tb_insert_rh850 +#define tcg_tb_remove tcg_tb_remove_rh850 +#define tcg_tb_lookup tcg_tb_lookup_rh850 +#define tcg_tb_foreach tcg_tb_foreach_rh850 +#define tcg_nb_tbs tcg_nb_tbs_rh850 +#define tcg_region_reset_all tcg_region_reset_all_rh850 +#define tcg_region_init tcg_region_init_rh850 +#define tcg_code_size tcg_code_size_rh850 +#define tcg_code_capacity tcg_code_capacity_rh850 +#define tcg_tb_phys_invalidate_count tcg_tb_phys_invalidate_count_rh850 +#define tcg_malloc_internal tcg_malloc_internal_rh850 +#define tcg_pool_reset tcg_pool_reset_rh850 +#define tcg_context_init tcg_context_init_rh850 +#define tcg_tb_alloc tcg_tb_alloc_rh850 +#define tcg_prologue_init tcg_prologue_init_rh850 +#define tcg_func_start tcg_func_start_rh850 +#define tcg_set_frame tcg_set_frame_rh850 +#define tcg_global_mem_new_internal tcg_global_mem_new_internal_rh850 +#define tcg_temp_new_internal tcg_temp_new_internal_rh850 +#define tcg_temp_new_vec tcg_temp_new_vec_rh850 +#define tcg_temp_new_vec_matching tcg_temp_new_vec_matching_rh850 +#define tcg_temp_free_internal tcg_temp_free_internal_rh850 +#define tcg_const_i32 tcg_const_i32_rh850 +#define tcg_const_i64 tcg_const_i64_rh850 +#define tcg_const_local_i32 tcg_const_local_i32_rh850 +#define tcg_const_local_i64 tcg_const_local_i64_rh850 +#define tcg_op_supported tcg_op_supported_rh850 +#define tcg_gen_callN tcg_gen_callN_rh850 +#define tcg_op_remove tcg_op_remove_rh850 +#define tcg_emit_op tcg_emit_op_rh850 +#define tcg_op_insert_before tcg_op_insert_before_rh850 +#define tcg_op_insert_after tcg_op_insert_after_rh850 +#define tcg_cpu_exec_time tcg_cpu_exec_time_rh850 +#define tcg_gen_code tcg_gen_code_rh850 +#define tcg_gen_op1 tcg_gen_op1_rh850 +#define tcg_gen_op2 tcg_gen_op2_rh850 +#define tcg_gen_op3 tcg_gen_op3_rh850 +#define tcg_gen_op4 tcg_gen_op4_rh850 +#define tcg_gen_op5 tcg_gen_op5_rh850 +#define tcg_gen_op6 tcg_gen_op6_rh850 +#define tcg_gen_mb tcg_gen_mb_rh850 +#define tcg_gen_addi_i32 tcg_gen_addi_i32_rh850 +#define tcg_gen_subfi_i32 tcg_gen_subfi_i32_rh850 +#define tcg_gen_subi_i32 tcg_gen_subi_i32_rh850 +#define tcg_gen_andi_i32 tcg_gen_andi_i32_rh850 +#define tcg_gen_ori_i32 tcg_gen_ori_i32_rh850 +#define tcg_gen_xori_i32 tcg_gen_xori_i32_rh850 +#define tcg_gen_shli_i32 tcg_gen_shli_i32_rh850 +#define tcg_gen_shri_i32 tcg_gen_shri_i32_rh850 +#define tcg_gen_sari_i32 tcg_gen_sari_i32_rh850 +#define tcg_gen_brcond_i32 tcg_gen_brcond_i32_rh850 +#define tcg_gen_brcondi_i32 tcg_gen_brcondi_i32_rh850 +#define tcg_gen_setcond_i32 tcg_gen_setcond_i32_rh850 +#define tcg_gen_setcondi_i32 tcg_gen_setcondi_i32_rh850 +#define tcg_gen_muli_i32 tcg_gen_muli_i32_rh850 +#define tcg_gen_div_i32 tcg_gen_div_i32_rh850 +#define tcg_gen_rem_i32 tcg_gen_rem_i32_rh850 +#define tcg_gen_divu_i32 tcg_gen_divu_i32_rh850 +#define tcg_gen_remu_i32 tcg_gen_remu_i32_rh850 +#define tcg_gen_andc_i32 tcg_gen_andc_i32_rh850 +#define tcg_gen_eqv_i32 tcg_gen_eqv_i32_rh850 +#define tcg_gen_nand_i32 tcg_gen_nand_i32_rh850 +#define tcg_gen_nor_i32 tcg_gen_nor_i32_rh850 +#define tcg_gen_orc_i32 tcg_gen_orc_i32_rh850 +#define tcg_gen_clz_i32 tcg_gen_clz_i32_rh850 +#define tcg_gen_clzi_i32 tcg_gen_clzi_i32_rh850 +#define tcg_gen_ctz_i32 tcg_gen_ctz_i32_rh850 +#define tcg_gen_ctzi_i32 tcg_gen_ctzi_i32_rh850 +#define tcg_gen_clrsb_i32 tcg_gen_clrsb_i32_rh850 +#define tcg_gen_ctpop_i32 tcg_gen_ctpop_i32_rh850 +#define tcg_gen_rotl_i32 tcg_gen_rotl_i32_rh850 +#define tcg_gen_rotli_i32 tcg_gen_rotli_i32_rh850 +#define tcg_gen_rotr_i32 tcg_gen_rotr_i32_rh850 +#define tcg_gen_rotri_i32 tcg_gen_rotri_i32_rh850 +#define tcg_gen_deposit_i32 tcg_gen_deposit_i32_rh850 +#define tcg_gen_deposit_z_i32 tcg_gen_deposit_z_i32_rh850 +#define tcg_gen_extract_i32 tcg_gen_extract_i32_rh850 +#define tcg_gen_sextract_i32 tcg_gen_sextract_i32_rh850 +#define tcg_gen_extract2_i32 tcg_gen_extract2_i32_rh850 +#define tcg_gen_movcond_i32 tcg_gen_movcond_i32_rh850 +#define tcg_gen_add2_i32 tcg_gen_add2_i32_rh850 +#define tcg_gen_sub2_i32 tcg_gen_sub2_i32_rh850 +#define tcg_gen_mulu2_i32 tcg_gen_mulu2_i32_rh850 +#define tcg_gen_muls2_i32 tcg_gen_muls2_i32_rh850 +#define tcg_gen_mulsu2_i32 tcg_gen_mulsu2_i32_rh850 +#define tcg_gen_ext8s_i32 tcg_gen_ext8s_i32_rh850 +#define tcg_gen_ext16s_i32 tcg_gen_ext16s_i32_rh850 +#define tcg_gen_ext8u_i32 tcg_gen_ext8u_i32_rh850 +#define tcg_gen_ext16u_i32 tcg_gen_ext16u_i32_rh850 +#define tcg_gen_bswap16_i32 tcg_gen_bswap16_i32_rh850 +#define tcg_gen_bswap32_i32 tcg_gen_bswap32_i32_rh850 +#define tcg_gen_smin_i32 tcg_gen_smin_i32_rh850 +#define tcg_gen_umin_i32 tcg_gen_umin_i32_rh850 +#define tcg_gen_smax_i32 tcg_gen_smax_i32_rh850 +#define tcg_gen_umax_i32 tcg_gen_umax_i32_rh850 +#define tcg_gen_abs_i32 tcg_gen_abs_i32_rh850 +#define tcg_gen_addi_i64 tcg_gen_addi_i64_rh850 +#define tcg_gen_subfi_i64 tcg_gen_subfi_i64_rh850 +#define tcg_gen_subi_i64 tcg_gen_subi_i64_rh850 +#define tcg_gen_andi_i64 tcg_gen_andi_i64_rh850 +#define tcg_gen_ori_i64 tcg_gen_ori_i64_rh850 +#define tcg_gen_xori_i64 tcg_gen_xori_i64_rh850 +#define tcg_gen_shli_i64 tcg_gen_shli_i64_rh850 +#define tcg_gen_shri_i64 tcg_gen_shri_i64_rh850 +#define tcg_gen_sari_i64 tcg_gen_sari_i64_rh850 +#define tcg_gen_brcond_i64 tcg_gen_brcond_i64_rh850 +#define tcg_gen_brcondi_i64 tcg_gen_brcondi_i64_rh850 +#define tcg_gen_setcond_i64 tcg_gen_setcond_i64_rh850 +#define tcg_gen_setcondi_i64 tcg_gen_setcondi_i64_rh850 +#define tcg_gen_muli_i64 tcg_gen_muli_i64_rh850 +#define tcg_gen_div_i64 tcg_gen_div_i64_rh850 +#define tcg_gen_rem_i64 tcg_gen_rem_i64_rh850 +#define tcg_gen_divu_i64 tcg_gen_divu_i64_rh850 +#define tcg_gen_remu_i64 tcg_gen_remu_i64_rh850 +#define tcg_gen_ext8s_i64 tcg_gen_ext8s_i64_rh850 +#define tcg_gen_ext16s_i64 tcg_gen_ext16s_i64_rh850 +#define tcg_gen_ext32s_i64 tcg_gen_ext32s_i64_rh850 +#define tcg_gen_ext8u_i64 tcg_gen_ext8u_i64_rh850 +#define tcg_gen_ext16u_i64 tcg_gen_ext16u_i64_rh850 +#define tcg_gen_ext32u_i64 tcg_gen_ext32u_i64_rh850 +#define tcg_gen_bswap16_i64 tcg_gen_bswap16_i64_rh850 +#define tcg_gen_bswap32_i64 tcg_gen_bswap32_i64_rh850 +#define tcg_gen_bswap64_i64 tcg_gen_bswap64_i64_rh850 +#define tcg_gen_not_i64 tcg_gen_not_i64_rh850 +#define tcg_gen_andc_i64 tcg_gen_andc_i64_rh850 +#define tcg_gen_eqv_i64 tcg_gen_eqv_i64_rh850 +#define tcg_gen_nand_i64 tcg_gen_nand_i64_rh850 +#define tcg_gen_nor_i64 tcg_gen_nor_i64_rh850 +#define tcg_gen_orc_i64 tcg_gen_orc_i64_rh850 +#define tcg_gen_clz_i64 tcg_gen_clz_i64_rh850 +#define tcg_gen_clzi_i64 tcg_gen_clzi_i64_rh850 +#define tcg_gen_ctz_i64 tcg_gen_ctz_i64_rh850 +#define tcg_gen_ctzi_i64 tcg_gen_ctzi_i64_rh850 +#define tcg_gen_clrsb_i64 tcg_gen_clrsb_i64_rh850 +#define tcg_gen_ctpop_i64 tcg_gen_ctpop_i64_rh850 +#define tcg_gen_rotl_i64 tcg_gen_rotl_i64_rh850 +#define tcg_gen_rotli_i64 tcg_gen_rotli_i64_rh850 +#define tcg_gen_rotr_i64 tcg_gen_rotr_i64_rh850 +#define tcg_gen_rotri_i64 tcg_gen_rotri_i64_rh850 +#define tcg_gen_deposit_i64 tcg_gen_deposit_i64_rh850 +#define tcg_gen_deposit_z_i64 tcg_gen_deposit_z_i64_rh850 +#define tcg_gen_extract_i64 tcg_gen_extract_i64_rh850 +#define tcg_gen_sextract_i64 tcg_gen_sextract_i64_rh850 +#define tcg_gen_extract2_i64 tcg_gen_extract2_i64_rh850 +#define tcg_gen_movcond_i64 tcg_gen_movcond_i64_rh850 +#define tcg_gen_add2_i64 tcg_gen_add2_i64_rh850 +#define tcg_gen_sub2_i64 tcg_gen_sub2_i64_rh850 +#define tcg_gen_mulu2_i64 tcg_gen_mulu2_i64_rh850 +#define tcg_gen_muls2_i64 tcg_gen_muls2_i64_rh850 +#define tcg_gen_mulsu2_i64 tcg_gen_mulsu2_i64_rh850 +#define tcg_gen_smin_i64 tcg_gen_smin_i64_rh850 +#define tcg_gen_umin_i64 tcg_gen_umin_i64_rh850 +#define tcg_gen_smax_i64 tcg_gen_smax_i64_rh850 +#define tcg_gen_umax_i64 tcg_gen_umax_i64_rh850 +#define tcg_gen_abs_i64 tcg_gen_abs_i64_rh850 +#define tcg_gen_extrl_i64_i32 tcg_gen_extrl_i64_i32_rh850 +#define tcg_gen_extrh_i64_i32 tcg_gen_extrh_i64_i32_rh850 +#define tcg_gen_extu_i32_i64 tcg_gen_extu_i32_i64_rh850 +#define tcg_gen_ext_i32_i64 tcg_gen_ext_i32_i64_rh850 +#define tcg_gen_concat_i32_i64 tcg_gen_concat_i32_i64_rh850 +#define tcg_gen_extr_i64_i32 tcg_gen_extr_i64_i32_rh850 +#define tcg_gen_extr32_i64 tcg_gen_extr32_i64_rh850 +#define tcg_gen_exit_tb tcg_gen_exit_tb_rh850 +#define tcg_gen_goto_tb tcg_gen_goto_tb_rh850 +#define tcg_gen_lookup_and_goto_ptr tcg_gen_lookup_and_goto_ptr_rh850 +#define check_exit_request check_exit_request_rh850 +#define tcg_gen_qemu_ld_i32 tcg_gen_qemu_ld_i32_rh850 +#define tcg_gen_qemu_st_i32 tcg_gen_qemu_st_i32_rh850 +#define tcg_gen_qemu_ld_i64 tcg_gen_qemu_ld_i64_rh850 +#define tcg_gen_qemu_st_i64 tcg_gen_qemu_st_i64_rh850 +#define tcg_gen_atomic_cmpxchg_i32 tcg_gen_atomic_cmpxchg_i32_rh850 +#define tcg_gen_atomic_cmpxchg_i64 tcg_gen_atomic_cmpxchg_i64_rh850 +#define tcg_gen_atomic_fetch_add_i32 tcg_gen_atomic_fetch_add_i32_rh850 +#define tcg_gen_atomic_fetch_add_i64 tcg_gen_atomic_fetch_add_i64_rh850 +#define tcg_gen_atomic_fetch_and_i32 tcg_gen_atomic_fetch_and_i32_rh850 +#define tcg_gen_atomic_fetch_and_i64 tcg_gen_atomic_fetch_and_i64_rh850 +#define tcg_gen_atomic_fetch_or_i32 tcg_gen_atomic_fetch_or_i32_rh850 +#define tcg_gen_atomic_fetch_or_i64 tcg_gen_atomic_fetch_or_i64_rh850 +#define tcg_gen_atomic_fetch_xor_i32 tcg_gen_atomic_fetch_xor_i32_rh850 +#define tcg_gen_atomic_fetch_xor_i64 tcg_gen_atomic_fetch_xor_i64_rh850 +#define tcg_gen_atomic_fetch_smin_i32 tcg_gen_atomic_fetch_smin_i32_rh850 +#define tcg_gen_atomic_fetch_smin_i64 tcg_gen_atomic_fetch_smin_i64_rh850 +#define tcg_gen_atomic_fetch_umin_i32 tcg_gen_atomic_fetch_umin_i32_rh850 +#define tcg_gen_atomic_fetch_umin_i64 tcg_gen_atomic_fetch_umin_i64_rh850 +#define tcg_gen_atomic_fetch_smax_i32 tcg_gen_atomic_fetch_smax_i32_rh850 +#define tcg_gen_atomic_fetch_smax_i64 tcg_gen_atomic_fetch_smax_i64_rh850 +#define tcg_gen_atomic_fetch_umax_i32 tcg_gen_atomic_fetch_umax_i32_rh850 +#define tcg_gen_atomic_fetch_umax_i64 tcg_gen_atomic_fetch_umax_i64_rh850 +#define tcg_gen_atomic_add_fetch_i32 tcg_gen_atomic_add_fetch_i32_rh850 +#define tcg_gen_atomic_add_fetch_i64 tcg_gen_atomic_add_fetch_i64_rh850 +#define tcg_gen_atomic_and_fetch_i32 tcg_gen_atomic_and_fetch_i32_rh850 +#define tcg_gen_atomic_and_fetch_i64 tcg_gen_atomic_and_fetch_i64_rh850 +#define tcg_gen_atomic_or_fetch_i32 tcg_gen_atomic_or_fetch_i32_rh850 +#define tcg_gen_atomic_or_fetch_i64 tcg_gen_atomic_or_fetch_i64_rh850 +#define tcg_gen_atomic_xor_fetch_i32 tcg_gen_atomic_xor_fetch_i32_rh850 +#define tcg_gen_atomic_xor_fetch_i64 tcg_gen_atomic_xor_fetch_i64_rh850 +#define tcg_gen_atomic_smin_fetch_i32 tcg_gen_atomic_smin_fetch_i32_rh850 +#define tcg_gen_atomic_smin_fetch_i64 tcg_gen_atomic_smin_fetch_i64_rh850 +#define tcg_gen_atomic_umin_fetch_i32 tcg_gen_atomic_umin_fetch_i32_rh850 +#define tcg_gen_atomic_umin_fetch_i64 tcg_gen_atomic_umin_fetch_i64_rh850 +#define tcg_gen_atomic_smax_fetch_i32 tcg_gen_atomic_smax_fetch_i32_rh850 +#define tcg_gen_atomic_smax_fetch_i64 tcg_gen_atomic_smax_fetch_i64_rh850 +#define tcg_gen_atomic_umax_fetch_i32 tcg_gen_atomic_umax_fetch_i32_rh850 +#define tcg_gen_atomic_umax_fetch_i64 tcg_gen_atomic_umax_fetch_i64_rh850 +#define tcg_gen_atomic_xchg_i32 tcg_gen_atomic_xchg_i32_rh850 +#define tcg_gen_atomic_xchg_i64 tcg_gen_atomic_xchg_i64_rh850 +#define simd_desc simd_desc_rh850 +#define tcg_gen_gvec_2_ool tcg_gen_gvec_2_ool_rh850 +#define tcg_gen_gvec_2i_ool tcg_gen_gvec_2i_ool_rh850 +#define tcg_gen_gvec_3_ool tcg_gen_gvec_3_ool_rh850 +#define tcg_gen_gvec_4_ool tcg_gen_gvec_4_ool_rh850 +#define tcg_gen_gvec_5_ool tcg_gen_gvec_5_ool_rh850 +#define tcg_gen_gvec_2_ptr tcg_gen_gvec_2_ptr_rh850 +#define tcg_gen_gvec_3_ptr tcg_gen_gvec_3_ptr_rh850 +#define tcg_gen_gvec_4_ptr tcg_gen_gvec_4_ptr_rh850 +#define tcg_gen_gvec_5_ptr tcg_gen_gvec_5_ptr_rh850 +#define tcg_gen_gvec_2 tcg_gen_gvec_2_rh850 +#define tcg_gen_gvec_2i tcg_gen_gvec_2i_rh850 +#define tcg_gen_gvec_2s tcg_gen_gvec_2s_rh850 +#define tcg_gen_gvec_3 tcg_gen_gvec_3_rh850 +#define tcg_gen_gvec_3i tcg_gen_gvec_3i_rh850 +#define tcg_gen_gvec_4 tcg_gen_gvec_4_rh850 +#define tcg_gen_gvec_mov tcg_gen_gvec_mov_rh850 +#define tcg_gen_gvec_dup_i32 tcg_gen_gvec_dup_i32_rh850 +#define tcg_gen_gvec_dup_i64 tcg_gen_gvec_dup_i64_rh850 +#define tcg_gen_gvec_dup_mem tcg_gen_gvec_dup_mem_rh850 +#define tcg_gen_gvec_dup64i tcg_gen_gvec_dup64i_rh850 +#define tcg_gen_gvec_dup32i tcg_gen_gvec_dup32i_rh850 +#define tcg_gen_gvec_dup16i tcg_gen_gvec_dup16i_rh850 +#define tcg_gen_gvec_dup8i tcg_gen_gvec_dup8i_rh850 +#define tcg_gen_gvec_not tcg_gen_gvec_not_rh850 +#define tcg_gen_vec_add8_i64 tcg_gen_vec_add8_i64_rh850 +#define tcg_gen_vec_add16_i64 tcg_gen_vec_add16_i64_rh850 +#define tcg_gen_vec_add32_i64 tcg_gen_vec_add32_i64_rh850 +#define tcg_gen_gvec_add tcg_gen_gvec_add_rh850 +#define tcg_gen_gvec_adds tcg_gen_gvec_adds_rh850 +#define tcg_gen_gvec_addi tcg_gen_gvec_addi_rh850 +#define tcg_gen_gvec_subs tcg_gen_gvec_subs_rh850 +#define tcg_gen_vec_sub8_i64 tcg_gen_vec_sub8_i64_rh850 +#define tcg_gen_vec_sub16_i64 tcg_gen_vec_sub16_i64_rh850 +#define tcg_gen_vec_sub32_i64 tcg_gen_vec_sub32_i64_rh850 +#define tcg_gen_gvec_sub tcg_gen_gvec_sub_rh850 +#define tcg_gen_gvec_mul tcg_gen_gvec_mul_rh850 +#define tcg_gen_gvec_muls tcg_gen_gvec_muls_rh850 +#define tcg_gen_gvec_muli tcg_gen_gvec_muli_rh850 +#define tcg_gen_gvec_ssadd tcg_gen_gvec_ssadd_rh850 +#define tcg_gen_gvec_sssub tcg_gen_gvec_sssub_rh850 +#define tcg_gen_gvec_usadd tcg_gen_gvec_usadd_rh850 +#define tcg_gen_gvec_ussub tcg_gen_gvec_ussub_rh850 +#define tcg_gen_gvec_smin tcg_gen_gvec_smin_rh850 +#define tcg_gen_gvec_umin tcg_gen_gvec_umin_rh850 +#define tcg_gen_gvec_smax tcg_gen_gvec_smax_rh850 +#define tcg_gen_gvec_umax tcg_gen_gvec_umax_rh850 +#define tcg_gen_vec_neg8_i64 tcg_gen_vec_neg8_i64_rh850 +#define tcg_gen_vec_neg16_i64 tcg_gen_vec_neg16_i64_rh850 +#define tcg_gen_vec_neg32_i64 tcg_gen_vec_neg32_i64_rh850 +#define tcg_gen_gvec_neg tcg_gen_gvec_neg_rh850 +#define tcg_gen_gvec_abs tcg_gen_gvec_abs_rh850 +#define tcg_gen_gvec_and tcg_gen_gvec_and_rh850 +#define tcg_gen_gvec_or tcg_gen_gvec_or_rh850 +#define tcg_gen_gvec_xor tcg_gen_gvec_xor_rh850 +#define tcg_gen_gvec_andc tcg_gen_gvec_andc_rh850 +#define tcg_gen_gvec_orc tcg_gen_gvec_orc_rh850 +#define tcg_gen_gvec_nand tcg_gen_gvec_nand_rh850 +#define tcg_gen_gvec_nor tcg_gen_gvec_nor_rh850 +#define tcg_gen_gvec_eqv tcg_gen_gvec_eqv_rh850 +#define tcg_gen_gvec_ands tcg_gen_gvec_ands_rh850 +#define tcg_gen_gvec_andi tcg_gen_gvec_andi_rh850 +#define tcg_gen_gvec_xors tcg_gen_gvec_xors_rh850 +#define tcg_gen_gvec_xori tcg_gen_gvec_xori_rh850 +#define tcg_gen_gvec_ors tcg_gen_gvec_ors_rh850 +#define tcg_gen_gvec_ori tcg_gen_gvec_ori_rh850 +#define tcg_gen_vec_shl8i_i64 tcg_gen_vec_shl8i_i64_rh850 +#define tcg_gen_vec_shl16i_i64 tcg_gen_vec_shl16i_i64_rh850 +#define tcg_gen_gvec_shli tcg_gen_gvec_shli_rh850 +#define tcg_gen_vec_shr8i_i64 tcg_gen_vec_shr8i_i64_rh850 +#define tcg_gen_vec_shr16i_i64 tcg_gen_vec_shr16i_i64_rh850 +#define tcg_gen_gvec_shri tcg_gen_gvec_shri_rh850 +#define tcg_gen_vec_sar8i_i64 tcg_gen_vec_sar8i_i64_rh850 +#define tcg_gen_vec_sar16i_i64 tcg_gen_vec_sar16i_i64_rh850 +#define tcg_gen_gvec_sari tcg_gen_gvec_sari_rh850 +#define tcg_gen_gvec_shls tcg_gen_gvec_shls_rh850 +#define tcg_gen_gvec_shrs tcg_gen_gvec_shrs_rh850 +#define tcg_gen_gvec_sars tcg_gen_gvec_sars_rh850 +#define tcg_gen_gvec_shlv tcg_gen_gvec_shlv_rh850 +#define tcg_gen_gvec_shrv tcg_gen_gvec_shrv_rh850 +#define tcg_gen_gvec_sarv tcg_gen_gvec_sarv_rh850 +#define tcg_gen_gvec_cmp tcg_gen_gvec_cmp_rh850 +#define tcg_gen_gvec_bitsel tcg_gen_gvec_bitsel_rh850 +#define tcg_can_emit_vecop_list tcg_can_emit_vecop_list_rh850 +#define vec_gen_2 vec_gen_2_rh850 +#define vec_gen_3 vec_gen_3_rh850 +#define vec_gen_4 vec_gen_4_rh850 +#define tcg_gen_mov_vec tcg_gen_mov_vec_rh850 +#define tcg_const_zeros_vec tcg_const_zeros_vec_rh850 +#define tcg_const_ones_vec tcg_const_ones_vec_rh850 +#define tcg_const_zeros_vec_matching tcg_const_zeros_vec_matching_rh850 +#define tcg_const_ones_vec_matching tcg_const_ones_vec_matching_rh850 +#define tcg_gen_dup64i_vec tcg_gen_dup64i_vec_rh850 +#define tcg_gen_dup32i_vec tcg_gen_dup32i_vec_rh850 +#define tcg_gen_dup16i_vec tcg_gen_dup16i_vec_rh850 +#define tcg_gen_dup8i_vec tcg_gen_dup8i_vec_rh850 +#define tcg_gen_dupi_vec tcg_gen_dupi_vec_rh850 +#define tcg_gen_dup_i64_vec tcg_gen_dup_i64_vec_rh850 +#define tcg_gen_dup_i32_vec tcg_gen_dup_i32_vec_rh850 +#define tcg_gen_dup_mem_vec tcg_gen_dup_mem_vec_rh850 +#define tcg_gen_ld_vec tcg_gen_ld_vec_rh850 +#define tcg_gen_st_vec tcg_gen_st_vec_rh850 +#define tcg_gen_stl_vec tcg_gen_stl_vec_rh850 +#define tcg_gen_and_vec tcg_gen_and_vec_rh850 +#define tcg_gen_or_vec tcg_gen_or_vec_rh850 +#define tcg_gen_xor_vec tcg_gen_xor_vec_rh850 +#define tcg_gen_andc_vec tcg_gen_andc_vec_rh850 +#define tcg_gen_orc_vec tcg_gen_orc_vec_rh850 +#define tcg_gen_nand_vec tcg_gen_nand_vec_rh850 +#define tcg_gen_nor_vec tcg_gen_nor_vec_rh850 +#define tcg_gen_eqv_vec tcg_gen_eqv_vec_rh850 +#define tcg_gen_not_vec tcg_gen_not_vec_rh850 +#define tcg_gen_neg_vec tcg_gen_neg_vec_rh850 +#define tcg_gen_abs_vec tcg_gen_abs_vec_rh850 +#define tcg_gen_shli_vec tcg_gen_shli_vec_rh850 +#define tcg_gen_shri_vec tcg_gen_shri_vec_rh850 +#define tcg_gen_sari_vec tcg_gen_sari_vec_rh850 +#define tcg_gen_cmp_vec tcg_gen_cmp_vec_rh850 +#define tcg_gen_add_vec tcg_gen_add_vec_rh850 +#define tcg_gen_sub_vec tcg_gen_sub_vec_rh850 +#define tcg_gen_mul_vec tcg_gen_mul_vec_rh850 +#define tcg_gen_ssadd_vec tcg_gen_ssadd_vec_rh850 +#define tcg_gen_usadd_vec tcg_gen_usadd_vec_rh850 +#define tcg_gen_sssub_vec tcg_gen_sssub_vec_rh850 +#define tcg_gen_ussub_vec tcg_gen_ussub_vec_rh850 +#define tcg_gen_smin_vec tcg_gen_smin_vec_rh850 +#define tcg_gen_umin_vec tcg_gen_umin_vec_rh850 +#define tcg_gen_smax_vec tcg_gen_smax_vec_rh850 +#define tcg_gen_umax_vec tcg_gen_umax_vec_rh850 +#define tcg_gen_shlv_vec tcg_gen_shlv_vec_rh850 +#define tcg_gen_shrv_vec tcg_gen_shrv_vec_rh850 +#define tcg_gen_sarv_vec tcg_gen_sarv_vec_rh850 +#define tcg_gen_shls_vec tcg_gen_shls_vec_rh850 +#define tcg_gen_shrs_vec tcg_gen_shrs_vec_rh850 +#define tcg_gen_sars_vec tcg_gen_sars_vec_rh850 +#define tcg_gen_bitsel_vec tcg_gen_bitsel_vec_rh850 +#define tcg_gen_cmpsel_vec tcg_gen_cmpsel_vec_rh850 +#define tb_htable_lookup tb_htable_lookup_rh850 +#define tb_set_jmp_target tb_set_jmp_target_rh850 +#define cpu_exec cpu_exec_rh850 +#define cpu_loop_exit_noexc cpu_loop_exit_noexc_rh850 +#define cpu_reloading_memory_map cpu_reloading_memory_map_rh850 +#define cpu_loop_exit cpu_loop_exit_rh850 +#define cpu_loop_exit_restore cpu_loop_exit_restore_rh850 +#define cpu_loop_exit_atomic cpu_loop_exit_atomic_rh850 +#define tlb_init tlb_init_rh850 +#define tlb_flush_by_mmuidx tlb_flush_by_mmuidx_rh850 +#define tlb_flush tlb_flush_rh850 +#define tlb_flush_by_mmuidx_all_cpus tlb_flush_by_mmuidx_all_cpus_rh850 +#define tlb_flush_all_cpus tlb_flush_all_cpus_rh850 +#define tlb_flush_by_mmuidx_all_cpus_synced tlb_flush_by_mmuidx_all_cpus_synced_rh850 +#define tlb_flush_all_cpus_synced tlb_flush_all_cpus_synced_rh850 +#define tlb_flush_page_by_mmuidx tlb_flush_page_by_mmuidx_rh850 +#define tlb_flush_page tlb_flush_page_rh850 +#define tlb_flush_page_by_mmuidx_all_cpus tlb_flush_page_by_mmuidx_all_cpus_rh850 +#define tlb_flush_page_all_cpus tlb_flush_page_all_cpus_rh850 +#define tlb_flush_page_by_mmuidx_all_cpus_synced tlb_flush_page_by_mmuidx_all_cpus_synced_rh850 +#define tlb_flush_page_all_cpus_synced tlb_flush_page_all_cpus_synced_rh850 +#define tlb_protect_code tlb_protect_code_rh850 +#define tlb_unprotect_code tlb_unprotect_code_rh850 +#define tlb_reset_dirty tlb_reset_dirty_rh850 +#define tlb_set_dirty tlb_set_dirty_rh850 +#define tlb_set_page_with_attrs tlb_set_page_with_attrs_rh850 +#define tlb_set_page tlb_set_page_rh850 +#define get_page_addr_code_hostp get_page_addr_code_hostp_rh850 +#define get_page_addr_code get_page_addr_code_rh850 +#define probe_access probe_access_rh850 +#define tlb_vaddr_to_host tlb_vaddr_to_host_rh850 +#define helper_ret_ldub_mmu helper_ret_ldub_mmu_rh850 +#define helper_le_lduw_mmu helper_le_lduw_mmu_rh850 +#define helper_be_lduw_mmu helper_be_lduw_mmu_rh850 +#define helper_le_ldul_mmu helper_le_ldul_mmu_rh850 +#define helper_be_ldul_mmu helper_be_ldul_mmu_rh850 +#define helper_le_ldq_mmu helper_le_ldq_mmu_rh850 +#define helper_be_ldq_mmu helper_be_ldq_mmu_rh850 +#define helper_ret_ldsb_mmu helper_ret_ldsb_mmu_rh850 +#define helper_le_ldsw_mmu helper_le_ldsw_mmu_rh850 +#define helper_be_ldsw_mmu helper_be_ldsw_mmu_rh850 +#define helper_le_ldsl_mmu helper_le_ldsl_mmu_rh850 +#define helper_be_ldsl_mmu helper_be_ldsl_mmu_rh850 +#define cpu_ldub_mmuidx_ra cpu_ldub_mmuidx_ra_rh850 +#define cpu_ldsb_mmuidx_ra cpu_ldsb_mmuidx_ra_rh850 +#define cpu_lduw_mmuidx_ra cpu_lduw_mmuidx_ra_rh850 +#define cpu_ldsw_mmuidx_ra cpu_ldsw_mmuidx_ra_rh850 +#define cpu_ldl_mmuidx_ra cpu_ldl_mmuidx_ra_rh850 +#define cpu_ldq_mmuidx_ra cpu_ldq_mmuidx_ra_rh850 +#define cpu_ldub_data_ra cpu_ldub_data_ra_rh850 +#define cpu_ldsb_data_ra cpu_ldsb_data_ra_rh850 +#define cpu_lduw_data_ra cpu_lduw_data_ra_rh850 +#define cpu_ldsw_data_ra cpu_ldsw_data_ra_rh850 +#define cpu_ldl_data_ra cpu_ldl_data_ra_rh850 +#define cpu_ldq_data_ra cpu_ldq_data_ra_rh850 +#define cpu_ldub_data cpu_ldub_data_rh850 +#define cpu_ldsb_data cpu_ldsb_data_rh850 +#define cpu_lduw_data cpu_lduw_data_rh850 +#define cpu_ldsw_data cpu_ldsw_data_rh850 +#define cpu_ldl_data cpu_ldl_data_rh850 +#define cpu_ldq_data cpu_ldq_data_rh850 +#define helper_ret_stb_mmu helper_ret_stb_mmu_rh850 +#define helper_le_stw_mmu helper_le_stw_mmu_rh850 +#define helper_be_stw_mmu helper_be_stw_mmu_rh850 +#define helper_le_stl_mmu helper_le_stl_mmu_rh850 +#define helper_be_stl_mmu helper_be_stl_mmu_rh850 +#define helper_le_stq_mmu helper_le_stq_mmu_rh850 +#define helper_be_stq_mmu helper_be_stq_mmu_rh850 +#define cpu_stb_mmuidx_ra cpu_stb_mmuidx_ra_rh850 +#define cpu_stw_mmuidx_ra cpu_stw_mmuidx_ra_rh850 +#define cpu_stl_mmuidx_ra cpu_stl_mmuidx_ra_rh850 +#define cpu_stq_mmuidx_ra cpu_stq_mmuidx_ra_rh850 +#define cpu_stb_data_ra cpu_stb_data_ra_rh850 +#define cpu_stw_data_ra cpu_stw_data_ra_rh850 +#define cpu_stl_data_ra cpu_stl_data_ra_rh850 +#define cpu_stq_data_ra cpu_stq_data_ra_rh850 +#define cpu_stb_data cpu_stb_data_rh850 +#define cpu_stw_data cpu_stw_data_rh850 +#define cpu_stl_data cpu_stl_data_rh850 +#define cpu_stq_data cpu_stq_data_rh850 +#define helper_atomic_cmpxchgb_mmu helper_atomic_cmpxchgb_mmu_rh850 +#define helper_atomic_xchgb_mmu helper_atomic_xchgb_mmu_rh850 +#define helper_atomic_fetch_addb_mmu helper_atomic_fetch_addb_mmu_rh850 +#define helper_atomic_fetch_andb_mmu helper_atomic_fetch_andb_mmu_rh850 +#define helper_atomic_fetch_orb_mmu helper_atomic_fetch_orb_mmu_rh850 +#define helper_atomic_fetch_xorb_mmu helper_atomic_fetch_xorb_mmu_rh850 +#define helper_atomic_add_fetchb_mmu helper_atomic_add_fetchb_mmu_rh850 +#define helper_atomic_and_fetchb_mmu helper_atomic_and_fetchb_mmu_rh850 +#define helper_atomic_or_fetchb_mmu helper_atomic_or_fetchb_mmu_rh850 +#define helper_atomic_xor_fetchb_mmu helper_atomic_xor_fetchb_mmu_rh850 +#define helper_atomic_fetch_sminb_mmu helper_atomic_fetch_sminb_mmu_rh850 +#define helper_atomic_fetch_uminb_mmu helper_atomic_fetch_uminb_mmu_rh850 +#define helper_atomic_fetch_smaxb_mmu helper_atomic_fetch_smaxb_mmu_rh850 +#define helper_atomic_fetch_umaxb_mmu helper_atomic_fetch_umaxb_mmu_rh850 +#define helper_atomic_smin_fetchb_mmu helper_atomic_smin_fetchb_mmu_rh850 +#define helper_atomic_umin_fetchb_mmu helper_atomic_umin_fetchb_mmu_rh850 +#define helper_atomic_smax_fetchb_mmu helper_atomic_smax_fetchb_mmu_rh850 +#define helper_atomic_umax_fetchb_mmu helper_atomic_umax_fetchb_mmu_rh850 +#define helper_atomic_cmpxchgw_le_mmu helper_atomic_cmpxchgw_le_mmu_rh850 +#define helper_atomic_xchgw_le_mmu helper_atomic_xchgw_le_mmu_rh850 +#define helper_atomic_fetch_addw_le_mmu helper_atomic_fetch_addw_le_mmu_rh850 +#define helper_atomic_fetch_andw_le_mmu helper_atomic_fetch_andw_le_mmu_rh850 +#define helper_atomic_fetch_orw_le_mmu helper_atomic_fetch_orw_le_mmu_rh850 +#define helper_atomic_fetch_xorw_le_mmu helper_atomic_fetch_xorw_le_mmu_rh850 +#define helper_atomic_add_fetchw_le_mmu helper_atomic_add_fetchw_le_mmu_rh850 +#define helper_atomic_and_fetchw_le_mmu helper_atomic_and_fetchw_le_mmu_rh850 +#define helper_atomic_or_fetchw_le_mmu helper_atomic_or_fetchw_le_mmu_rh850 +#define helper_atomic_xor_fetchw_le_mmu helper_atomic_xor_fetchw_le_mmu_rh850 +#define helper_atomic_fetch_sminw_le_mmu helper_atomic_fetch_sminw_le_mmu_rh850 +#define helper_atomic_fetch_uminw_le_mmu helper_atomic_fetch_uminw_le_mmu_rh850 +#define helper_atomic_fetch_smaxw_le_mmu helper_atomic_fetch_smaxw_le_mmu_rh850 +#define helper_atomic_fetch_umaxw_le_mmu helper_atomic_fetch_umaxw_le_mmu_rh850 +#define helper_atomic_smin_fetchw_le_mmu helper_atomic_smin_fetchw_le_mmu_rh850 +#define helper_atomic_umin_fetchw_le_mmu helper_atomic_umin_fetchw_le_mmu_rh850 +#define helper_atomic_smax_fetchw_le_mmu helper_atomic_smax_fetchw_le_mmu_rh850 +#define helper_atomic_umax_fetchw_le_mmu helper_atomic_umax_fetchw_le_mmu_rh850 +#define helper_atomic_cmpxchgw_be_mmu helper_atomic_cmpxchgw_be_mmu_rh850 +#define helper_atomic_xchgw_be_mmu helper_atomic_xchgw_be_mmu_rh850 +#define helper_atomic_fetch_andw_be_mmu helper_atomic_fetch_andw_be_mmu_rh850 +#define helper_atomic_fetch_orw_be_mmu helper_atomic_fetch_orw_be_mmu_rh850 +#define helper_atomic_fetch_xorw_be_mmu helper_atomic_fetch_xorw_be_mmu_rh850 +#define helper_atomic_and_fetchw_be_mmu helper_atomic_and_fetchw_be_mmu_rh850 +#define helper_atomic_or_fetchw_be_mmu helper_atomic_or_fetchw_be_mmu_rh850 +#define helper_atomic_xor_fetchw_be_mmu helper_atomic_xor_fetchw_be_mmu_rh850 +#define helper_atomic_fetch_sminw_be_mmu helper_atomic_fetch_sminw_be_mmu_rh850 +#define helper_atomic_fetch_uminw_be_mmu helper_atomic_fetch_uminw_be_mmu_rh850 +#define helper_atomic_fetch_smaxw_be_mmu helper_atomic_fetch_smaxw_be_mmu_rh850 +#define helper_atomic_fetch_umaxw_be_mmu helper_atomic_fetch_umaxw_be_mmu_rh850 +#define helper_atomic_smin_fetchw_be_mmu helper_atomic_smin_fetchw_be_mmu_rh850 +#define helper_atomic_umin_fetchw_be_mmu helper_atomic_umin_fetchw_be_mmu_rh850 +#define helper_atomic_smax_fetchw_be_mmu helper_atomic_smax_fetchw_be_mmu_rh850 +#define helper_atomic_umax_fetchw_be_mmu helper_atomic_umax_fetchw_be_mmu_rh850 +#define helper_atomic_fetch_addw_be_mmu helper_atomic_fetch_addw_be_mmu_rh850 +#define helper_atomic_add_fetchw_be_mmu helper_atomic_add_fetchw_be_mmu_rh850 +#define helper_atomic_cmpxchgl_le_mmu helper_atomic_cmpxchgl_le_mmu_rh850 +#define helper_atomic_xchgl_le_mmu helper_atomic_xchgl_le_mmu_rh850 +#define helper_atomic_fetch_addl_le_mmu helper_atomic_fetch_addl_le_mmu_rh850 +#define helper_atomic_fetch_andl_le_mmu helper_atomic_fetch_andl_le_mmu_rh850 +#define helper_atomic_fetch_orl_le_mmu helper_atomic_fetch_orl_le_mmu_rh850 +#define helper_atomic_fetch_xorl_le_mmu helper_atomic_fetch_xorl_le_mmu_rh850 +#define helper_atomic_add_fetchl_le_mmu helper_atomic_add_fetchl_le_mmu_rh850 +#define helper_atomic_and_fetchl_le_mmu helper_atomic_and_fetchl_le_mmu_rh850 +#define helper_atomic_or_fetchl_le_mmu helper_atomic_or_fetchl_le_mmu_rh850 +#define helper_atomic_xor_fetchl_le_mmu helper_atomic_xor_fetchl_le_mmu_rh850 +#define helper_atomic_fetch_sminl_le_mmu helper_atomic_fetch_sminl_le_mmu_rh850 +#define helper_atomic_fetch_uminl_le_mmu helper_atomic_fetch_uminl_le_mmu_rh850 +#define helper_atomic_fetch_smaxl_le_mmu helper_atomic_fetch_smaxl_le_mmu_rh850 +#define helper_atomic_fetch_umaxl_le_mmu helper_atomic_fetch_umaxl_le_mmu_rh850 +#define helper_atomic_smin_fetchl_le_mmu helper_atomic_smin_fetchl_le_mmu_rh850 +#define helper_atomic_umin_fetchl_le_mmu helper_atomic_umin_fetchl_le_mmu_rh850 +#define helper_atomic_smax_fetchl_le_mmu helper_atomic_smax_fetchl_le_mmu_rh850 +#define helper_atomic_umax_fetchl_le_mmu helper_atomic_umax_fetchl_le_mmu_rh850 +#define helper_atomic_cmpxchgl_be_mmu helper_atomic_cmpxchgl_be_mmu_rh850 +#define helper_atomic_xchgl_be_mmu helper_atomic_xchgl_be_mmu_rh850 +#define helper_atomic_fetch_andl_be_mmu helper_atomic_fetch_andl_be_mmu_rh850 +#define helper_atomic_fetch_orl_be_mmu helper_atomic_fetch_orl_be_mmu_rh850 +#define helper_atomic_fetch_xorl_be_mmu helper_atomic_fetch_xorl_be_mmu_rh850 +#define helper_atomic_and_fetchl_be_mmu helper_atomic_and_fetchl_be_mmu_rh850 +#define helper_atomic_or_fetchl_be_mmu helper_atomic_or_fetchl_be_mmu_rh850 +#define helper_atomic_xor_fetchl_be_mmu helper_atomic_xor_fetchl_be_mmu_rh850 +#define helper_atomic_fetch_sminl_be_mmu helper_atomic_fetch_sminl_be_mmu_rh850 +#define helper_atomic_fetch_uminl_be_mmu helper_atomic_fetch_uminl_be_mmu_rh850 +#define helper_atomic_fetch_smaxl_be_mmu helper_atomic_fetch_smaxl_be_mmu_rh850 +#define helper_atomic_fetch_umaxl_be_mmu helper_atomic_fetch_umaxl_be_mmu_rh850 +#define helper_atomic_smin_fetchl_be_mmu helper_atomic_smin_fetchl_be_mmu_rh850 +#define helper_atomic_umin_fetchl_be_mmu helper_atomic_umin_fetchl_be_mmu_rh850 +#define helper_atomic_smax_fetchl_be_mmu helper_atomic_smax_fetchl_be_mmu_rh850 +#define helper_atomic_umax_fetchl_be_mmu helper_atomic_umax_fetchl_be_mmu_rh850 +#define helper_atomic_fetch_addl_be_mmu helper_atomic_fetch_addl_be_mmu_rh850 +#define helper_atomic_add_fetchl_be_mmu helper_atomic_add_fetchl_be_mmu_rh850 +#define helper_atomic_cmpxchgq_le_mmu helper_atomic_cmpxchgq_le_mmu_rh850 +#define helper_atomic_xchgq_le_mmu helper_atomic_xchgq_le_mmu_rh850 +#define helper_atomic_fetch_addq_le_mmu helper_atomic_fetch_addq_le_mmu_rh850 +#define helper_atomic_fetch_andq_le_mmu helper_atomic_fetch_andq_le_mmu_rh850 +#define helper_atomic_fetch_orq_le_mmu helper_atomic_fetch_orq_le_mmu_rh850 +#define helper_atomic_fetch_xorq_le_mmu helper_atomic_fetch_xorq_le_mmu_rh850 +#define helper_atomic_add_fetchq_le_mmu helper_atomic_add_fetchq_le_mmu_rh850 +#define helper_atomic_and_fetchq_le_mmu helper_atomic_and_fetchq_le_mmu_rh850 +#define helper_atomic_or_fetchq_le_mmu helper_atomic_or_fetchq_le_mmu_rh850 +#define helper_atomic_xor_fetchq_le_mmu helper_atomic_xor_fetchq_le_mmu_rh850 +#define helper_atomic_fetch_sminq_le_mmu helper_atomic_fetch_sminq_le_mmu_rh850 +#define helper_atomic_fetch_uminq_le_mmu helper_atomic_fetch_uminq_le_mmu_rh850 +#define helper_atomic_fetch_smaxq_le_mmu helper_atomic_fetch_smaxq_le_mmu_rh850 +#define helper_atomic_fetch_umaxq_le_mmu helper_atomic_fetch_umaxq_le_mmu_rh850 +#define helper_atomic_smin_fetchq_le_mmu helper_atomic_smin_fetchq_le_mmu_rh850 +#define helper_atomic_umin_fetchq_le_mmu helper_atomic_umin_fetchq_le_mmu_rh850 +#define helper_atomic_smax_fetchq_le_mmu helper_atomic_smax_fetchq_le_mmu_rh850 +#define helper_atomic_umax_fetchq_le_mmu helper_atomic_umax_fetchq_le_mmu_rh850 +#define helper_atomic_cmpxchgq_be_mmu helper_atomic_cmpxchgq_be_mmu_rh850 +#define helper_atomic_xchgq_be_mmu helper_atomic_xchgq_be_mmu_rh850 +#define helper_atomic_fetch_andq_be_mmu helper_atomic_fetch_andq_be_mmu_rh850 +#define helper_atomic_fetch_orq_be_mmu helper_atomic_fetch_orq_be_mmu_rh850 +#define helper_atomic_fetch_xorq_be_mmu helper_atomic_fetch_xorq_be_mmu_rh850 +#define helper_atomic_and_fetchq_be_mmu helper_atomic_and_fetchq_be_mmu_rh850 +#define helper_atomic_or_fetchq_be_mmu helper_atomic_or_fetchq_be_mmu_rh850 +#define helper_atomic_xor_fetchq_be_mmu helper_atomic_xor_fetchq_be_mmu_rh850 +#define helper_atomic_fetch_sminq_be_mmu helper_atomic_fetch_sminq_be_mmu_rh850 +#define helper_atomic_fetch_uminq_be_mmu helper_atomic_fetch_uminq_be_mmu_rh850 +#define helper_atomic_fetch_smaxq_be_mmu helper_atomic_fetch_smaxq_be_mmu_rh850 +#define helper_atomic_fetch_umaxq_be_mmu helper_atomic_fetch_umaxq_be_mmu_rh850 +#define helper_atomic_smin_fetchq_be_mmu helper_atomic_smin_fetchq_be_mmu_rh850 +#define helper_atomic_umin_fetchq_be_mmu helper_atomic_umin_fetchq_be_mmu_rh850 +#define helper_atomic_smax_fetchq_be_mmu helper_atomic_smax_fetchq_be_mmu_rh850 +#define helper_atomic_umax_fetchq_be_mmu helper_atomic_umax_fetchq_be_mmu_rh850 +#define helper_atomic_fetch_addq_be_mmu helper_atomic_fetch_addq_be_mmu_rh850 +#define helper_atomic_add_fetchq_be_mmu helper_atomic_add_fetchq_be_mmu_rh850 +#define helper_atomic_cmpxchgb helper_atomic_cmpxchgb_rh850 +#define helper_atomic_xchgb helper_atomic_xchgb_rh850 +#define helper_atomic_fetch_addb helper_atomic_fetch_addb_rh850 +#define helper_atomic_fetch_andb helper_atomic_fetch_andb_rh850 +#define helper_atomic_fetch_orb helper_atomic_fetch_orb_rh850 +#define helper_atomic_fetch_xorb helper_atomic_fetch_xorb_rh850 +#define helper_atomic_add_fetchb helper_atomic_add_fetchb_rh850 +#define helper_atomic_and_fetchb helper_atomic_and_fetchb_rh850 +#define helper_atomic_or_fetchb helper_atomic_or_fetchb_rh850 +#define helper_atomic_xor_fetchb helper_atomic_xor_fetchb_rh850 +#define helper_atomic_fetch_sminb helper_atomic_fetch_sminb_rh850 +#define helper_atomic_fetch_uminb helper_atomic_fetch_uminb_rh850 +#define helper_atomic_fetch_smaxb helper_atomic_fetch_smaxb_rh850 +#define helper_atomic_fetch_umaxb helper_atomic_fetch_umaxb_rh850 +#define helper_atomic_smin_fetchb helper_atomic_smin_fetchb_rh850 +#define helper_atomic_umin_fetchb helper_atomic_umin_fetchb_rh850 +#define helper_atomic_smax_fetchb helper_atomic_smax_fetchb_rh850 +#define helper_atomic_umax_fetchb helper_atomic_umax_fetchb_rh850 +#define helper_atomic_cmpxchgw_le helper_atomic_cmpxchgw_le_rh850 +#define helper_atomic_xchgw_le helper_atomic_xchgw_le_rh850 +#define helper_atomic_fetch_addw_le helper_atomic_fetch_addw_le_rh850 +#define helper_atomic_fetch_andw_le helper_atomic_fetch_andw_le_rh850 +#define helper_atomic_fetch_orw_le helper_atomic_fetch_orw_le_rh850 +#define helper_atomic_fetch_xorw_le helper_atomic_fetch_xorw_le_rh850 +#define helper_atomic_add_fetchw_le helper_atomic_add_fetchw_le_rh850 +#define helper_atomic_and_fetchw_le helper_atomic_and_fetchw_le_rh850 +#define helper_atomic_or_fetchw_le helper_atomic_or_fetchw_le_rh850 +#define helper_atomic_xor_fetchw_le helper_atomic_xor_fetchw_le_rh850 +#define helper_atomic_fetch_sminw_le helper_atomic_fetch_sminw_le_rh850 +#define helper_atomic_fetch_uminw_le helper_atomic_fetch_uminw_le_rh850 +#define helper_atomic_fetch_smaxw_le helper_atomic_fetch_smaxw_le_rh850 +#define helper_atomic_fetch_umaxw_le helper_atomic_fetch_umaxw_le_rh850 +#define helper_atomic_smin_fetchw_le helper_atomic_smin_fetchw_le_rh850 +#define helper_atomic_umin_fetchw_le helper_atomic_umin_fetchw_le_rh850 +#define helper_atomic_smax_fetchw_le helper_atomic_smax_fetchw_le_rh850 +#define helper_atomic_umax_fetchw_le helper_atomic_umax_fetchw_le_rh850 +#define helper_atomic_cmpxchgw_be helper_atomic_cmpxchgw_be_rh850 +#define helper_atomic_xchgw_be helper_atomic_xchgw_be_rh850 +#define helper_atomic_fetch_andw_be helper_atomic_fetch_andw_be_rh850 +#define helper_atomic_fetch_orw_be helper_atomic_fetch_orw_be_rh850 +#define helper_atomic_fetch_xorw_be helper_atomic_fetch_xorw_be_rh850 +#define helper_atomic_and_fetchw_be helper_atomic_and_fetchw_be_rh850 +#define helper_atomic_or_fetchw_be helper_atomic_or_fetchw_be_rh850 +#define helper_atomic_xor_fetchw_be helper_atomic_xor_fetchw_be_rh850 +#define helper_atomic_fetch_sminw_be helper_atomic_fetch_sminw_be_rh850 +#define helper_atomic_fetch_uminw_be helper_atomic_fetch_uminw_be_rh850 +#define helper_atomic_fetch_smaxw_be helper_atomic_fetch_smaxw_be_rh850 +#define helper_atomic_fetch_umaxw_be helper_atomic_fetch_umaxw_be_rh850 +#define helper_atomic_smin_fetchw_be helper_atomic_smin_fetchw_be_rh850 +#define helper_atomic_umin_fetchw_be helper_atomic_umin_fetchw_be_rh850 +#define helper_atomic_smax_fetchw_be helper_atomic_smax_fetchw_be_rh850 +#define helper_atomic_umax_fetchw_be helper_atomic_umax_fetchw_be_rh850 +#define helper_atomic_fetch_addw_be helper_atomic_fetch_addw_be_rh850 +#define helper_atomic_add_fetchw_be helper_atomic_add_fetchw_be_rh850 +#define helper_atomic_cmpxchgl_le helper_atomic_cmpxchgl_le_rh850 +#define helper_atomic_xchgl_le helper_atomic_xchgl_le_rh850 +#define helper_atomic_fetch_addl_le helper_atomic_fetch_addl_le_rh850 +#define helper_atomic_fetch_andl_le helper_atomic_fetch_andl_le_rh850 +#define helper_atomic_fetch_orl_le helper_atomic_fetch_orl_le_rh850 +#define helper_atomic_fetch_xorl_le helper_atomic_fetch_xorl_le_rh850 +#define helper_atomic_add_fetchl_le helper_atomic_add_fetchl_le_rh850 +#define helper_atomic_and_fetchl_le helper_atomic_and_fetchl_le_rh850 +#define helper_atomic_or_fetchl_le helper_atomic_or_fetchl_le_rh850 +#define helper_atomic_xor_fetchl_le helper_atomic_xor_fetchl_le_rh850 +#define helper_atomic_fetch_sminl_le helper_atomic_fetch_sminl_le_rh850 +#define helper_atomic_fetch_uminl_le helper_atomic_fetch_uminl_le_rh850 +#define helper_atomic_fetch_smaxl_le helper_atomic_fetch_smaxl_le_rh850 +#define helper_atomic_fetch_umaxl_le helper_atomic_fetch_umaxl_le_rh850 +#define helper_atomic_smin_fetchl_le helper_atomic_smin_fetchl_le_rh850 +#define helper_atomic_umin_fetchl_le helper_atomic_umin_fetchl_le_rh850 +#define helper_atomic_smax_fetchl_le helper_atomic_smax_fetchl_le_rh850 +#define helper_atomic_umax_fetchl_le helper_atomic_umax_fetchl_le_rh850 +#define helper_atomic_cmpxchgl_be helper_atomic_cmpxchgl_be_rh850 +#define helper_atomic_xchgl_be helper_atomic_xchgl_be_rh850 +#define helper_atomic_fetch_andl_be helper_atomic_fetch_andl_be_rh850 +#define helper_atomic_fetch_orl_be helper_atomic_fetch_orl_be_rh850 +#define helper_atomic_fetch_xorl_be helper_atomic_fetch_xorl_be_rh850 +#define helper_atomic_and_fetchl_be helper_atomic_and_fetchl_be_rh850 +#define helper_atomic_or_fetchl_be helper_atomic_or_fetchl_be_rh850 +#define helper_atomic_xor_fetchl_be helper_atomic_xor_fetchl_be_rh850 +#define helper_atomic_fetch_sminl_be helper_atomic_fetch_sminl_be_rh850 +#define helper_atomic_fetch_uminl_be helper_atomic_fetch_uminl_be_rh850 +#define helper_atomic_fetch_smaxl_be helper_atomic_fetch_smaxl_be_rh850 +#define helper_atomic_fetch_umaxl_be helper_atomic_fetch_umaxl_be_rh850 +#define helper_atomic_smin_fetchl_be helper_atomic_smin_fetchl_be_rh850 +#define helper_atomic_umin_fetchl_be helper_atomic_umin_fetchl_be_rh850 +#define helper_atomic_smax_fetchl_be helper_atomic_smax_fetchl_be_rh850 +#define helper_atomic_umax_fetchl_be helper_atomic_umax_fetchl_be_rh850 +#define helper_atomic_fetch_addl_be helper_atomic_fetch_addl_be_rh850 +#define helper_atomic_add_fetchl_be helper_atomic_add_fetchl_be_rh850 +#define helper_atomic_cmpxchgq_le helper_atomic_cmpxchgq_le_rh850 +#define helper_atomic_xchgq_le helper_atomic_xchgq_le_rh850 +#define helper_atomic_fetch_addq_le helper_atomic_fetch_addq_le_rh850 +#define helper_atomic_fetch_andq_le helper_atomic_fetch_andq_le_rh850 +#define helper_atomic_fetch_orq_le helper_atomic_fetch_orq_le_rh850 +#define helper_atomic_fetch_xorq_le helper_atomic_fetch_xorq_le_rh850 +#define helper_atomic_add_fetchq_le helper_atomic_add_fetchq_le_rh850 +#define helper_atomic_and_fetchq_le helper_atomic_and_fetchq_le_rh850 +#define helper_atomic_or_fetchq_le helper_atomic_or_fetchq_le_rh850 +#define helper_atomic_xor_fetchq_le helper_atomic_xor_fetchq_le_rh850 +#define helper_atomic_fetch_sminq_le helper_atomic_fetch_sminq_le_rh850 +#define helper_atomic_fetch_uminq_le helper_atomic_fetch_uminq_le_rh850 +#define helper_atomic_fetch_smaxq_le helper_atomic_fetch_smaxq_le_rh850 +#define helper_atomic_fetch_umaxq_le helper_atomic_fetch_umaxq_le_rh850 +#define helper_atomic_smin_fetchq_le helper_atomic_smin_fetchq_le_rh850 +#define helper_atomic_umin_fetchq_le helper_atomic_umin_fetchq_le_rh850 +#define helper_atomic_smax_fetchq_le helper_atomic_smax_fetchq_le_rh850 +#define helper_atomic_umax_fetchq_le helper_atomic_umax_fetchq_le_rh850 +#define helper_atomic_cmpxchgq_be helper_atomic_cmpxchgq_be_rh850 +#define helper_atomic_xchgq_be helper_atomic_xchgq_be_rh850 +#define helper_atomic_fetch_andq_be helper_atomic_fetch_andq_be_rh850 +#define helper_atomic_fetch_orq_be helper_atomic_fetch_orq_be_rh850 +#define helper_atomic_fetch_xorq_be helper_atomic_fetch_xorq_be_rh850 +#define helper_atomic_and_fetchq_be helper_atomic_and_fetchq_be_rh850 +#define helper_atomic_or_fetchq_be helper_atomic_or_fetchq_be_rh850 +#define helper_atomic_xor_fetchq_be helper_atomic_xor_fetchq_be_rh850 +#define helper_atomic_fetch_sminq_be helper_atomic_fetch_sminq_be_rh850 +#define helper_atomic_fetch_uminq_be helper_atomic_fetch_uminq_be_rh850 +#define helper_atomic_fetch_smaxq_be helper_atomic_fetch_smaxq_be_rh850 +#define helper_atomic_fetch_umaxq_be helper_atomic_fetch_umaxq_be_rh850 +#define helper_atomic_smin_fetchq_be helper_atomic_smin_fetchq_be_rh850 +#define helper_atomic_umin_fetchq_be helper_atomic_umin_fetchq_be_rh850 +#define helper_atomic_smax_fetchq_be helper_atomic_smax_fetchq_be_rh850 +#define helper_atomic_umax_fetchq_be helper_atomic_umax_fetchq_be_rh850 +#define helper_atomic_fetch_addq_be helper_atomic_fetch_addq_be_rh850 +#define helper_atomic_add_fetchq_be helper_atomic_add_fetchq_be_rh850 +#define cpu_ldub_code cpu_ldub_code_rh850 +#define cpu_lduw_code cpu_lduw_code_rh850 +#define cpu_ldl_code cpu_ldl_code_rh850 +#define cpu_ldq_code cpu_ldq_code_rh850 +#define helper_div_i32 helper_div_i32_rh850 +#define helper_rem_i32 helper_rem_i32_rh850 +#define helper_divu_i32 helper_divu_i32_rh850 +#define helper_remu_i32 helper_remu_i32_rh850 +#define helper_shl_i64 helper_shl_i64_rh850 +#define helper_shr_i64 helper_shr_i64_rh850 +#define helper_sar_i64 helper_sar_i64_rh850 +#define helper_div_i64 helper_div_i64_rh850 +#define helper_rem_i64 helper_rem_i64_rh850 +#define helper_divu_i64 helper_divu_i64_rh850 +#define helper_remu_i64 helper_remu_i64_rh850 +#define helper_muluh_i64 helper_muluh_i64_rh850 +#define helper_mulsh_i64 helper_mulsh_i64_rh850 +#define helper_clz_i32 helper_clz_i32_rh850 +#define helper_ctz_i32 helper_ctz_i32_rh850 +#define helper_clz_i64 helper_clz_i64_rh850 +#define helper_ctz_i64 helper_ctz_i64_rh850 +#define helper_clrsb_i32 helper_clrsb_i32_rh850 +#define helper_clrsb_i64 helper_clrsb_i64_rh850 +#define helper_ctpop_i32 helper_ctpop_i32_rh850 +#define helper_ctpop_i64 helper_ctpop_i64_rh850 +#define helper_lookup_tb_ptr helper_lookup_tb_ptr_rh850 +#define helper_exit_atomic helper_exit_atomic_rh850 +#define helper_gvec_add8 helper_gvec_add8_rh850 +#define helper_gvec_add16 helper_gvec_add16_rh850 +#define helper_gvec_add32 helper_gvec_add32_rh850 +#define helper_gvec_add64 helper_gvec_add64_rh850 +#define helper_gvec_adds8 helper_gvec_adds8_rh850 +#define helper_gvec_adds16 helper_gvec_adds16_rh850 +#define helper_gvec_adds32 helper_gvec_adds32_rh850 +#define helper_gvec_adds64 helper_gvec_adds64_rh850 +#define helper_gvec_sub8 helper_gvec_sub8_rh850 +#define helper_gvec_sub16 helper_gvec_sub16_rh850 +#define helper_gvec_sub32 helper_gvec_sub32_rh850 +#define helper_gvec_sub64 helper_gvec_sub64_rh850 +#define helper_gvec_subs8 helper_gvec_subs8_rh850 +#define helper_gvec_subs16 helper_gvec_subs16_rh850 +#define helper_gvec_subs32 helper_gvec_subs32_rh850 +#define helper_gvec_subs64 helper_gvec_subs64_rh850 +#define helper_gvec_mul8 helper_gvec_mul8_rh850 +#define helper_gvec_mul16 helper_gvec_mul16_rh850 +#define helper_gvec_mul32 helper_gvec_mul32_rh850 +#define helper_gvec_mul64 helper_gvec_mul64_rh850 +#define helper_gvec_muls8 helper_gvec_muls8_rh850 +#define helper_gvec_muls16 helper_gvec_muls16_rh850 +#define helper_gvec_muls32 helper_gvec_muls32_rh850 +#define helper_gvec_muls64 helper_gvec_muls64_rh850 +#define helper_gvec_neg8 helper_gvec_neg8_rh850 +#define helper_gvec_neg16 helper_gvec_neg16_rh850 +#define helper_gvec_neg32 helper_gvec_neg32_rh850 +#define helper_gvec_neg64 helper_gvec_neg64_rh850 +#define helper_gvec_abs8 helper_gvec_abs8_rh850 +#define helper_gvec_abs16 helper_gvec_abs16_rh850 +#define helper_gvec_abs32 helper_gvec_abs32_rh850 +#define helper_gvec_abs64 helper_gvec_abs64_rh850 +#define helper_gvec_mov helper_gvec_mov_rh850 +#define helper_gvec_dup64 helper_gvec_dup64_rh850 +#define helper_gvec_dup32 helper_gvec_dup32_rh850 +#define helper_gvec_dup16 helper_gvec_dup16_rh850 +#define helper_gvec_dup8 helper_gvec_dup8_rh850 +#define helper_gvec_not helper_gvec_not_rh850 +#define helper_gvec_and helper_gvec_and_rh850 +#define helper_gvec_or helper_gvec_or_rh850 +#define helper_gvec_xor helper_gvec_xor_rh850 +#define helper_gvec_andc helper_gvec_andc_rh850 +#define helper_gvec_orc helper_gvec_orc_rh850 +#define helper_gvec_nand helper_gvec_nand_rh850 +#define helper_gvec_nor helper_gvec_nor_rh850 +#define helper_gvec_eqv helper_gvec_eqv_rh850 +#define helper_gvec_ands helper_gvec_ands_rh850 +#define helper_gvec_xors helper_gvec_xors_rh850 +#define helper_gvec_ors helper_gvec_ors_rh850 +#define helper_gvec_shl8i helper_gvec_shl8i_rh850 +#define helper_gvec_shl16i helper_gvec_shl16i_rh850 +#define helper_gvec_shl32i helper_gvec_shl32i_rh850 +#define helper_gvec_shl64i helper_gvec_shl64i_rh850 +#define helper_gvec_shr8i helper_gvec_shr8i_rh850 +#define helper_gvec_shr16i helper_gvec_shr16i_rh850 +#define helper_gvec_shr32i helper_gvec_shr32i_rh850 +#define helper_gvec_shr64i helper_gvec_shr64i_rh850 +#define helper_gvec_sar8i helper_gvec_sar8i_rh850 +#define helper_gvec_sar16i helper_gvec_sar16i_rh850 +#define helper_gvec_sar32i helper_gvec_sar32i_rh850 +#define helper_gvec_sar64i helper_gvec_sar64i_rh850 +#define helper_gvec_shl8v helper_gvec_shl8v_rh850 +#define helper_gvec_shl16v helper_gvec_shl16v_rh850 +#define helper_gvec_shl32v helper_gvec_shl32v_rh850 +#define helper_gvec_shl64v helper_gvec_shl64v_rh850 +#define helper_gvec_shr8v helper_gvec_shr8v_rh850 +#define helper_gvec_shr16v helper_gvec_shr16v_rh850 +#define helper_gvec_shr32v helper_gvec_shr32v_rh850 +#define helper_gvec_shr64v helper_gvec_shr64v_rh850 +#define helper_gvec_sar8v helper_gvec_sar8v_rh850 +#define helper_gvec_sar16v helper_gvec_sar16v_rh850 +#define helper_gvec_sar32v helper_gvec_sar32v_rh850 +#define helper_gvec_sar64v helper_gvec_sar64v_rh850 +#define helper_gvec_eq8 helper_gvec_eq8_rh850 +#define helper_gvec_ne8 helper_gvec_ne8_rh850 +#define helper_gvec_lt8 helper_gvec_lt8_rh850 +#define helper_gvec_le8 helper_gvec_le8_rh850 +#define helper_gvec_ltu8 helper_gvec_ltu8_rh850 +#define helper_gvec_leu8 helper_gvec_leu8_rh850 +#define helper_gvec_eq16 helper_gvec_eq16_rh850 +#define helper_gvec_ne16 helper_gvec_ne16_rh850 +#define helper_gvec_lt16 helper_gvec_lt16_rh850 +#define helper_gvec_le16 helper_gvec_le16_rh850 +#define helper_gvec_ltu16 helper_gvec_ltu16_rh850 +#define helper_gvec_leu16 helper_gvec_leu16_rh850 +#define helper_gvec_eq32 helper_gvec_eq32_rh850 +#define helper_gvec_ne32 helper_gvec_ne32_rh850 +#define helper_gvec_lt32 helper_gvec_lt32_rh850 +#define helper_gvec_le32 helper_gvec_le32_rh850 +#define helper_gvec_ltu32 helper_gvec_ltu32_rh850 +#define helper_gvec_leu32 helper_gvec_leu32_rh850 +#define helper_gvec_eq64 helper_gvec_eq64_rh850 +#define helper_gvec_ne64 helper_gvec_ne64_rh850 +#define helper_gvec_lt64 helper_gvec_lt64_rh850 +#define helper_gvec_le64 helper_gvec_le64_rh850 +#define helper_gvec_ltu64 helper_gvec_ltu64_rh850 +#define helper_gvec_leu64 helper_gvec_leu64_rh850 +#define helper_gvec_ssadd8 helper_gvec_ssadd8_rh850 +#define helper_gvec_ssadd16 helper_gvec_ssadd16_rh850 +#define helper_gvec_ssadd32 helper_gvec_ssadd32_rh850 +#define helper_gvec_ssadd64 helper_gvec_ssadd64_rh850 +#define helper_gvec_sssub8 helper_gvec_sssub8_rh850 +#define helper_gvec_sssub16 helper_gvec_sssub16_rh850 +#define helper_gvec_sssub32 helper_gvec_sssub32_rh850 +#define helper_gvec_sssub64 helper_gvec_sssub64_rh850 +#define helper_gvec_usadd8 helper_gvec_usadd8_rh850 +#define helper_gvec_usadd16 helper_gvec_usadd16_rh850 +#define helper_gvec_usadd32 helper_gvec_usadd32_rh850 +#define helper_gvec_usadd64 helper_gvec_usadd64_rh850 +#define helper_gvec_ussub8 helper_gvec_ussub8_rh850 +#define helper_gvec_ussub16 helper_gvec_ussub16_rh850 +#define helper_gvec_ussub32 helper_gvec_ussub32_rh850 +#define helper_gvec_ussub64 helper_gvec_ussub64_rh850 +#define helper_gvec_smin8 helper_gvec_smin8_rh850 +#define helper_gvec_smin16 helper_gvec_smin16_rh850 +#define helper_gvec_smin32 helper_gvec_smin32_rh850 +#define helper_gvec_smin64 helper_gvec_smin64_rh850 +#define helper_gvec_smax8 helper_gvec_smax8_rh850 +#define helper_gvec_smax16 helper_gvec_smax16_rh850 +#define helper_gvec_smax32 helper_gvec_smax32_rh850 +#define helper_gvec_smax64 helper_gvec_smax64_rh850 +#define helper_gvec_umin8 helper_gvec_umin8_rh850 +#define helper_gvec_umin16 helper_gvec_umin16_rh850 +#define helper_gvec_umin32 helper_gvec_umin32_rh850 +#define helper_gvec_umin64 helper_gvec_umin64_rh850 +#define helper_gvec_umax8 helper_gvec_umax8_rh850 +#define helper_gvec_umax16 helper_gvec_umax16_rh850 +#define helper_gvec_umax32 helper_gvec_umax32_rh850 +#define helper_gvec_umax64 helper_gvec_umax64_rh850 +#define helper_gvec_bitsel helper_gvec_bitsel_rh850 +#define cpu_restore_state cpu_restore_state_rh850 +#define page_collection_lock page_collection_lock_rh850 +#define page_collection_unlock page_collection_unlock_rh850 +#define free_code_gen_buffer free_code_gen_buffer_rh850 +#define tcg_exec_init tcg_exec_init_rh850 +#define tb_cleanup tb_cleanup_rh850 +#define tb_flush tb_flush_rh850 +#define tb_phys_invalidate tb_phys_invalidate_rh850 +#define tb_gen_code tb_gen_code_rh850 +#define tb_exec_lock tb_exec_lock_rh850 +#define tb_exec_unlock tb_exec_unlock_rh850 +#define tb_invalidate_phys_page_range tb_invalidate_phys_page_range_rh850 +#define tb_invalidate_phys_range tb_invalidate_phys_range_rh850 +#define tb_invalidate_phys_page_fast tb_invalidate_phys_page_fast_rh850 +#define tb_check_watchpoint tb_check_watchpoint_rh850 +#define cpu_io_recompile cpu_io_recompile_rh850 +#define tb_flush_jmp_cache tb_flush_jmp_cache_rh850 +#define tcg_flush_softmmu_tlb tcg_flush_softmmu_tlb_rh850 +#define translator_loop_temp_check translator_loop_temp_check_rh850 +#define translator_loop translator_loop_rh850 +#define helper_atomic_cmpxchgo_le_mmu helper_atomic_cmpxchgo_le_mmu_rh850 +#define helper_atomic_cmpxchgo_be_mmu helper_atomic_cmpxchgo_be_mmu_rh850 +#define helper_atomic_ldo_le_mmu helper_atomic_ldo_le_mmu_rh850 +#define helper_atomic_ldo_be_mmu helper_atomic_ldo_be_mmu_rh850 +#define helper_atomic_sto_le_mmu helper_atomic_sto_le_mmu_rh850 +#define helper_atomic_sto_be_mmu helper_atomic_sto_be_mmu_rh850 +#define unassigned_mem_ops unassigned_mem_ops_rh850 +#define floatx80_infinity floatx80_infinity_rh850 +#define dup_const_func dup_const_func_rh850 +#define gen_helper_raise_exception gen_helper_raise_exception_rh850 +#define gen_helper_raise_interrupt gen_helper_raise_interrupt_rh850 +#define gen_helper_vfp_get_fpscr gen_helper_vfp_get_fpscr_rh850 +#define gen_helper_vfp_set_fpscr gen_helper_vfp_set_fpscr_rh850 +#define gen_helper_cpsr_read gen_helper_cpsr_read_rh850 +#define gen_helper_cpsr_write gen_helper_cpsr_write_rh850 +#define restore_state_to_opc restore_state_to_opc_rh850 +#define helper_tlb_flush helper_tlb_flush_rh850 +#define helper_uc_rh850_exit helper_uc_rh850_exit_rh850 +#define gen_intermediate_code gen_intermediate_code_rh850 +#endif diff --git a/qemu/target/rh850/Makefile.objs b/qemu/target/rh850/Makefile.objs new file mode 100644 index 0000000000..aaa7c0cc64 --- /dev/null +++ b/qemu/target/rh850/Makefile.objs @@ -0,0 +1 @@ +obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o gdbstub.o fpu_translate.o diff --git a/qemu/target/rh850/cpu-param.h b/qemu/target/rh850/cpu-param.h new file mode 100644 index 0000000000..24231873c3 --- /dev/null +++ b/qemu/target/rh850/cpu-param.h @@ -0,0 +1,11 @@ +#pragma once + +/* QEMU addressing/paging config */ +#define TARGET_PAGE_BITS 12 /* 4 KiB Pages */ + +#define TARGET_LONG_BITS 32 +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 + +#define NB_MMU_MODES 4 + diff --git a/qemu/target/rh850/cpu.c b/qemu/target/rh850/cpu.c new file mode 100644 index 0000000000..b6b44b28d2 --- /dev/null +++ b/qemu/target/rh850/cpu.c @@ -0,0 +1,473 @@ +/* + * QEMU RH850 CPU + * + * Copyright (c) 2018-2019 iSYSTEM Labs d.o.o. + * Copyright (c) 2023 Quarkslab + * + * 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/>. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/ctype.h" +#include "cpu.h" +#include "exec/exec-all.h" + +/* RH850 CPU definitions */ + +/* Program registers (rh850_prog_regnames): + * r0 - zero + * r1 - assembler reserved register + * r2 - real-time OS register / address and data variable register + * r3 - stack pointer + * r4 - global pointer + * r5 - text pointer + * r6-r29 - address and data variable registers + * r30 - element pointer + * r31 - link pointer + */ + +const char * const rh850_gp_regnames[] = { + "r0-zero", "r1", "r2", "r3-sp", "r4", "r5", "r6", "r7", + "r8", "r9", "r10 ", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r2 ", + "r24", "r25", "r26", "r27", "r28", "r29", "r30-ep", "r31-lp" +}; + +// Basic system registers +const char * const rh850_sys_regnames[][MAX_SYS_REGS_IN_BANK] = { + +{ // SELECTION ID 0 [5] used to be psw, but now it is stored in flags only + "eipc", "eipsw", "fepc", "fepsw", NULL, NULL, "fpsr", "fpepc", "fpst", "fpcc", + "fpcfg", "fpec", NULL, "eiic", "feic", NULL, "ctpc", "ctpsw", NULL, NULL, + "ctbp", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "eiwr", "fewr", + NULL, "bsel"}, +{ // SELECTION ID 1 + "mcfg0", NULL, "rbase", "ebase", "intbp", "mctl", "pid", "fpipr", NULL, NULL, + NULL, "sccfg", "scbp", +}, +{ // SELECTION ID 2 + "htcfg0",NULL, NULL, NULL, NULL, NULL, "mea", "asid", "mei", NULL, + "ispr", "pmr", "icsr", "intcfg" +}, +{ // SELECTION ID 3 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}, +{ // SELECTION ID 4 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, "ictagl", "ictagh","icdatl","icdath", + NULL, NULL, NULL, NULL, "icctrl",NULL, "iccfg", NULL, "icerr", NULL +}, +{ // SELECTION ID 5 + "mpm", "mprc", NULL, NULL, "mpbrgn","mptrgn",NULL, NULL, "mca", "mcs" + "mcc", "mcr" +}, +{ // SELECTION ID 6 + "mpla0", "mpua0", "mpat0", NULL, "mpla1", "mpua1", "mpat1", NULL, "mpla2", "mpua2", + "mpat2", NULL, "mpla3", "mpua3", "mpat3", NULL, "mpla4", "mpua4", "mpat4", NULL, + "mpla5", "mpua5", "mpat5", NULL, "mpla6", "mpua6", "mpat6", NULL, "mpla7", "mpua7", + "mpat7", NULL +}, +{ // SELECTION ID 7 + /* MPU function system registers */ + "mpla8", "mpua8", "mpat8", NULL, "mpla9", "mpua9", "mpat9", NULL, "mpla10","mpua10", + "mpat10",NULL, "mpla11", "mpua11", "mpat11",NULL, "mpla12","mpua12","mpat12",NULL, + "mpla13","mpua13","mpat13", NULL, "mpla14","mpua14","mpat14",NULL, "mpla15","mpua15", + "mpat15",NULL +} +}; + +// Where bits are read only, mask is set to 0 +const uint32_t rh850_sys_reg_read_only_masks[][MAX_SYS_REGS_IN_BANK] = { + +{ //SELECTION ID 0 PSW - implemented as registers for each used bit, see cpu_ZF, ... + 0xFFFFFFFF, 0x40078EFF, 0xFFFFFFFF, 0x40078EFF, 0x0, /*0x40018EFF*/ 0, 0xFFEEFFFF, 0xFFFFFFFE, 0x00003F3F, 0x000000FF, + 0x0000031F, 0x00000001, 0x0, 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0xFFFFFFFF, 0x0000001F, 0x0, 0x0, + 0xFFFFFFFE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFFFFFFFF, 0xFFFFFFFF, + 0x0, 0x0 +}, +{ //SELECTION ID 1 + // for MCFG (idx = 0), byte 3 seems to not be writable, at least on devicee used for testing + 0x00000000, 0x0, 0x00000000, 0xFFFFFE01, 0xFFFFFE00, 0x00000003, 0x00000000, 0x0000001F, 0x0, 0x0, + 0x0, 0x000000FF, 0xFFFFFFFC +}, +{ //SELECTION ID 2 + 0x00000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFFFFFFFF, 0x000003FF, 0x001F073F, 0x0, + 0x00000000, 0x0000FFFF, 0x00000000, 0x00000001 +}, +{ //SELECTION ID 3 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}, +{ //SELECTION ID 4 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFFFFFA35, 0xF0FFFF00, 0xFFFFFFFF, 0xFFFFFFFF, + 0x0, 0x0, 0x0, 0x0, 0x00020107, 0x0, 0x00000000, 0x0, 0xBF3F7FFD, 0x0 +}, +{ //SELECTION ID 5 + 0x00000003, 0x0000FFFF, 0x0, 0x0, 0x00000000, 0x00000000, 0x0, 0x0, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0x0000013F +}, +{ //SELECTION ID 6 + 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFF, + 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, + 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, + 0x03FF00FF, 0x0 +}, +{ //SELECTION ID 7 + 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFF, + 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, + 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, 0x03FF00FF, 0x0, 0xFFFFFFFC, 0xFFFFFFFC, + 0x03FF00FF, 0x0 +} +}; + + +const uint32_t rh850_sys_reg_read_only_values[][MAX_SYS_REGS_IN_BANK] = { +{ //SELECTION ID 0 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0 +}, +{ //SELECTION ID 1 + 0x4, 0x0, 0x0, 0x0, 0x0, 0x80000000, 0x12345678, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0 +}, +{ //SELECTION ID 2 + 0x00008000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0 +}, +{ //SELECTION ID 3 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}, +{ //SELECTION ID 4 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x00010000, 0x0, 0x00010000, 0x0, 0x0, 0x0 +}, +{ //SELECTION ID 5 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0 +}, +{ //SELECTION ID 6 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0 +}, +{ //SELECTION ID 7 + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0 +} +}; + + + +/*Data Buffer Operation Registers (rh850_sys_databuff_regnames): + * sr24, 13 - cbdcr */ +const char * const rh850_sys_databuff_regnames[] = { /* Data buffer operation registers */ + "cbdcr" +}; + +const char * const rh850_excp_names[] = { + "misaligned_fetch", + "fault_fetch", + "illegal_instruction", + "breakpoint", + "misaligned_load", + "fault_load", + "misaligned_store", + "fault_store", + "user_ecall", + "supervisor_ecall", + "hypervisor_ecall", + "machine_ecall", + "exec_page_fault", + "load_page_fault", + "reserved", + "store_page_fault" +}; + +const char * const rh850_intr_names[] = { + "u_software", + "s_software", + "h_software", + "m_software", + "u_timer", + "s_timer", + "h_timer", + "m_timer", + "u_external", + "s_external", + "h_external", + "m_external", + "coprocessor", + "host" +}; + + +void rh850_cpu_set_pc(CPUState *cs, vaddr value) +{ + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + env->pc = value; +} + +vaddr rh850_cpu_get_pc(CPUState *cs) +{ + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + return env->pc; +} + +AddressSpace *cpu_addressspace(CPUState *cs, MemTxAttrs attrs) +{ + return cpu_get_address_space(cs, cpu_asidx_from_attrs(cs, attrs)); +} + + +/* called by qemu's softmmu to fill the qemu tlb */ +static bool rh850_tlb_fill(CPUState *cs, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + int ret; + ret = rh850_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx); + if (ret == TRANSLATE_FAIL) { + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + do_raise_exception_err(env, cs->exception_index, retaddr); + } + return true; +} + + +static void rh850_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) +{ + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + env->pc = tb->pc; +} + +static bool rh850_cpu_has_work(CPUState *cs) +{ +#ifndef CONFIG_USER_ONLY + return true; +#else + return true; +#endif +} + +void restore_state_to_opc(CPURH850State *env, TranslationBlock *tb, + target_ulong *data) +{ + env->pc = data[0]; +} + + +static void rh850_raise_exception(CPURH850State *env, uint32_t excp, + uint32_t syndrome, uint32_t target_el) +{ + CPUState *cs = CPU(rh850_env_get_cpu(env)); + + cs->exception_index = excp; + cpu_loop_exit(cs); +} + + +static void rh850_debug_excp_handler(CPUState *cs) +{ + /* Called by core code when a watchpoint or breakpoint fires; + * need to check which one and raise the appropriate exception. + */ + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + CPUWatchpoint *wp_hit = cs->watchpoint_hit; + + if (wp_hit) { + if (wp_hit->flags & BP_CPU) { + // bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0; + // bool same_el = true; + + cs->watchpoint_hit = NULL; + + // env->exception.fsr = arm_debug_exception_fsr(env); + // env->exception.vaddress = wp_hit->hitaddr; + rh850_raise_exception(env, 0, 0, 0); + } + } else { + uint64_t pc = env->pc; + // bool same_el = true; + + /* (1) GDB breakpoints should be handled first. + * (2) Do not raise a CPU exception if no CPU breakpoint has fired, + * since singlestep is also done by generating a debug internal + * exception. + */ + if (!cpu_breakpoint_test(cs, pc, BP_GDB) && + cpu_breakpoint_test(cs, pc, BP_CPU)) { + + rh850_raise_exception(env, 0, 0, 0); + } + } +} + +static bool check_watchpoints(RH850CPU *cpu) +{ + return true; +} + + +static bool rh850_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) +{ + /* Called by core code when a CPU watchpoint fires; need to check if this + * is also an architectural watchpoint match. + */ + RH850CPU *cpu = RH850_CPU(cs); + + return check_watchpoints(cpu); +} + + +static void rh850_cpu_reset(CPUState *cs) +{ + + RH850CPU *cpu = RH850_CPU(cs); + RH850CPUClass *mcc = RH850_CPU_GET_CLASS(cpu); + CPURH850State *env = &cpu->env; + + mcc->parent_reset(cs); + cs->exception_index = EXCP_NONE; + set_default_nan_mode(1, &env->fp_status); + env->pc = 0; // move to direct vector ? (always 0?) + env->ID_flag = 1; // interrupts are disable on reset + env->systemRegs[BANK_ID_BASIC_0][EIPSW_IDX] = 0x20; + env->systemRegs[BANK_ID_BASIC_0][FEPSW_IDX] = 0x20; + env->systemRegs[BANK_ID_BASIC_0][EIIC_IDX] = 0x0; + env->systemRegs[BANK_ID_BASIC_0][FEIC_IDX] = 0x0; + env->systemRegs[BANK_ID_BASIC_0][PSW_IDX] = 0x20; // reset value of PSW + env->systemRegs[BANK_ID_BASIC_0][CTPSW_IDX] = 0; + env->systemRegs[BANK_ID_BASIC_0][CTBP_IDX] = 0; // only bit 0 must be set to 0 + env->systemRegs[BANK_ID_BASIC_2][ASID_IDX2] = 0; // only bits 31-10 must be set to 0 + env->systemRegs[BANK_ID_BASIC_2][HTCFG0_IDX2] = 0x00018000; // const value + env->systemRegs[BANK_ID_BASIC_2][MEI_IDX2] = 0; // only some bits must be 0 + env->systemRegs[BANK_ID_BASIC_1][RBASE_IDX1] = 0; + env->systemRegs[BANK_ID_BASIC_1][EBASE_IDX1] = 0; // only bits 8-1 must be 0 + env->systemRegs[BANK_ID_BASIC_1][INTBP_IDX1] = 0; // only bits 8-0 must be 0 + env->systemRegs[BANK_ID_BASIC_1][PID_IDX1] = 0x05000120; // const + env->systemRegs[BANK_ID_BASIC_1][SCCFG_IDX1] = 0; // bits 31-8 must be 0 + env->systemRegs[BANK_ID_BASIC_1][SCBP_IDX1] = 0; // bits 1-0 must be 0 + env->systemRegs[BANK_ID_BASIC_1][MCFG0_IDX1] = 0x4; // bits 31-8 must be 0 + env->systemRegs[BANK_ID_BASIC_1][MCTL_IDX1] = 0x80000000; // bits 31-8 must be 0 + + env->systemRegs[BANK_ID_BASIC_2][FPIPR_IDX1] = 0; + env->systemRegs[BANK_ID_BASIC_2][ISPR_IDX2] = 0; + env->systemRegs[BANK_ID_BASIC_2][PMR_IDX2] = 0; + env->systemRegs[BANK_ID_BASIC_2][ICSR_IDX2] = 0; + env->systemRegs[BANK_ID_BASIC_2][INTCFG_IDX2] = 0; +} + +static void rh850_cpu_realize(struct uc_struct *uc, CPUState *dev) +{ + CPUState *cs = CPU(dev); + + cpu_exec_realizefn(cs); + + qemu_init_vcpu(cs); + + cpu_reset(cs); +} + +static void rh850_cpu_init(struct uc_struct *uc, CPUState *obj) +{ + CPUState *cs = CPU(obj); + RH850CPU *cpu = RH850_CPU(obj); + + /* Set CPU pointers. */ + cpu_set_cpustate_pointers(cpu); + + cs->env_ptr = &cpu->env; + cpu->env.uc = uc; +} + +static void rh850_cpu_class_init(struct uc_struct *uc, CPUClass *c) +{ + RH850CPUClass *mcc = RH850_CPU_CLASS(c); + CPUClass *cc = CPU_CLASS(c); + + mcc->parent_reset = cc->reset; + cc->reset = rh850_cpu_reset; + + cc->has_work = rh850_cpu_has_work; + cc->do_interrupt = rh850_cpu_do_interrupt; + cc->cpu_exec_interrupt = rh850_cpu_exec_interrupt; + cc->set_pc = rh850_cpu_set_pc; + cc->tlb_fill = rh850_tlb_fill; + cc->synchronize_from_tb = rh850_cpu_synchronize_from_tb; + cc->debug_excp_handler = rh850_debug_excp_handler; + cc->debug_check_watchpoint = rh850_debug_check_watchpoint; + +#ifdef CONFIG_USER_ONLY + cc->handle_mmu_fault = rh850_cpu_handle_mmu_fault; +#else + cc->do_unaligned_access = rh850_cpu_do_unaligned_access; + cc->get_phys_page_debug = rh850_cpu_get_phys_page_debug; +#endif +#ifdef CONFIG_TCG + cc->tcg_initialize = rh850_translate_init; +#endif +} + +RH850CPU *cpu_rh850_init(struct uc_struct *uc, const char *cpu_model) +{ + RH850CPU *cpu; + CPUState *cs; + CPUClass *cc; + + cpu = calloc(1, sizeof(*cpu)); + if (cpu == NULL) { + return NULL; + } + + cs = (CPUState *)cpu; + cc = (CPUClass *)&cpu->cc; + cs->cc = cc; + cs->uc = uc; + uc->cpu = (CPUState *)cpu; + + /* init CPUClass */ + cpu_class_init(uc, cc); + + /* init CPUClass */ + rh850_cpu_class_init(uc, cc); + + /* init CPUState */ + cpu_common_initfn(uc, cs); + + /* init CPU */ + rh850_cpu_init(uc, cs); + + /* realize CPU */ + rh850_cpu_realize(uc, cs); + + // init addresss space + cpu_address_space_init(cs, 0, cs->memory); + + return cpu; +} + + + + diff --git a/qemu/target/rh850/cpu.h b/qemu/target/rh850/cpu.h new file mode 100644 index 0000000000..c54ad11599 --- /dev/null +++ b/qemu/target/rh850/cpu.h @@ -0,0 +1,276 @@ +/* + * QEMU RH850 CPU + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2017-2018 SiFive, Inc. + * Copyright (c) 2023 Quarkslab + * + * 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/>. + */ + +#ifndef RH850_CPU_H +#define RH850_CPU_H + +#define TCG_GUEST_DEFAULT_MO 0 + +//#define TARGET_INSN_START_EXTRA_WORDS 2 + +#define ELF_MACHINE EM_RH850 +#define CPUArchState struct CPURH850State + +#include "qemu-common.h" +#include "hw/core/cpu.h" +#include "exec/cpu-defs.h" +#include "fpu/softfloat.h" + +#define TYPE_RH850_CPU "rh850-cpu" + +#define RH850_CPU_TYPE_SUFFIX "-" TYPE_RH850_CPU +#define RH850_CPU_TYPE_NAME(name) (name RH850_CPU_TYPE_SUFFIX) +#define CPU_RESOLVING_TYPE TYPE_RH850_CPU +#define TYPE_RH850_CPU_ANY RH850_CPU_TYPE_NAME("any") + +#define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2)) +#define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2)) + +#if defined(TARGET_RH850) +#define RVXLEN RV32 +#elif defined(TARGET_RH85064) +#define RVXLEN RV64 +#endif + +#define RV(x) ((target_ulong)1 << (x - 'A')) + +#define RVI RV('I') +#define RVM RV('M') +#define RVA RV('A') +#define RVF RV('F') +#define RVD RV('D') +#define RVC RV('C') +#define RVS RV('S') +#define RVU RV('U') + +/* S extension denotes that Supervisor mode exists, however it is possible + to have a core that support S mode but does not have an MMU and there + is currently no bit in misa to indicate whether an MMU exists or not + so a cpu features bitfield is required */ +enum { + RH850_FEATURE_MMU +}; + +#define USER_VERSION_2_02_0 0x00020200 +#define PRIV_VERSION_1_09_1 0x00010901 +#define PRIV_VERSION_1_10_0 0x00011000 + +#define TRANSLATE_FAIL 1 +#define TRANSLATE_SUCCESS 0 +#define MMU_USER_IDX 3 + +#define MAX_RH850_PMPS (16) + +typedef struct CPURH850State CPURH850State; + +#include "pmp.h" + +#include "register_indices.h" + +#define NUM_GP_REGS 32 +#define NUM_SYS_REG_BANKS 7 +#define MAX_SYS_REGS_IN_BANK 32 +#define BANK_ID_BASIC_0 0 +#define BANK_ID_BASIC_1 1 +#define BANK_ID_BASIC_2 2 + +struct CPURH850State { + + + target_ulong gpRegs[NUM_GP_REGS]; + target_ulong pc; + target_ulong sysDatabuffRegs[1]; + target_ulong systemRegs[NUM_SYS_REG_BANKS][MAX_SYS_REGS_IN_BANK]; + //target_ulong sysBasicRegs[31]; + //target_ulong sysInterruptRegs[5]; + //uint64_t sysFpuRegs[6]; //using rh850 basic system registers(sr6-sr11), 32-bit or 64-bit precision + //target_ulong sysMpuRegs[56]; + //target_ulong sysCacheRegs[7]; + + // flags contained in PSW register + uint32_t Z_flag; + uint32_t S_flag; + uint32_t OV_flag; + uint32_t CY_flag; + uint32_t SAT_flag; + uint32_t ID_flag; + uint32_t EP_flag; + uint32_t NP_flag; + uint32_t EBV_flag; + uint32_t CU0_flag; + uint32_t CU1_flag; + uint32_t CU2_flag; + uint32_t UM_flag; + + uint32_t features; + uint32_t badaddr; + + target_ulong cpu_LLbit; // register for mutual exclusion (LDL.W, STC.W) + target_ulong cpu_LLAddress; // register for mutual exclusion (LDL.W, STC.W) + + target_ulong load_res; // inst addr for TCG + target_ulong load_val; // inst val for TCG + + float_status fp_status; // not used yet in rh850, left for floating-point support. + + target_ulong fpsr; /* floating-point configuration/status register. */ + + uint32_t exception_cause; + int exception_priority; + bool exception_dv; + + // Unicorn engine + struct uc_struct *uc; +}; + +#define RH850_CPU(obj) ((RH850CPU *)obj) +#define RH850_CPU_CLASS(klass) ((RH850CPUClass *)klass) +#define RH850_CPU_GET_CLASS(obj) (&((RH850CPU *)obj)->cc) + + +/** + * RH850CPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * + * A RH850 CPU model. + */ +typedef struct RH850CPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + void (*parent_reset)(CPUState *cpu); +} RH850CPUClass; + +/** + * RH850CPU: + * @env: #CPURH850State + * + * A RH850 CPU. + */ +typedef struct RH850CPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + CPUNegativeOffsetState neg; + CPURH850State env; + + RH850CPUClass cc; +} RH850CPU; + +typedef RH850CPU ArchCPU; + +static inline RH850CPU *rh850_env_get_cpu(CPURH850State *env) +{ + return container_of(env, RH850CPU, env); +} + +static inline int rh850_has_ext(CPURH850State *env, target_ulong ext) +{ // TODO: what does value 'ext' represent?? + //return (env->misa & ext) != 0; + return true; +} + +static inline bool rh850_feature(CPURH850State *env, int feature) +{ + return env->features & (1ULL << feature); +} + +#include "cpu_user.h" +#include "cpu_bits.h" + +extern const char * const rh850_gp_regnames[]; +extern const char * const rh850_sys_regnames[][MAX_SYS_REGS_IN_BANK]; +extern const char * const rh850_sys_databuff_regnames[]; + +extern const char * const rh850_excp_names[]; +extern const char * const rh850_intr_names[]; +extern const uint32_t rh850_sys_reg_read_only_values[][MAX_SYS_REGS_IN_BANK]; +extern const uint32_t rh850_sys_reg_read_only_masks[][MAX_SYS_REGS_IN_BANK]; + +#define ENV_GET_CPU(e) CPU(rh850_env_get_cpu(e)) +#define ENV_OFFSET offsetof(RH850CPU, env) + +void rh850_cpu_do_interrupt(CPUState *cpu); +int rh850_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int rh850_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +bool rh850_cpu_exec_interrupt(CPUState *cs, int interrupt_request); +int rh850_cpu_mmu_index(CPURH850State *env, bool ifetch); +hwaddr rh850_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +void rh850_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr); +int rh850_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, + int rw, int mmu_idx); + +char *rh850_isa_string(RH850CPU *cpu); +void rh850_cpu_list(void); + +#define cpu_init(cpu_model) cpu_generic_init(TYPE_RH850_CPU, cpu_model) +#define cpu_signal_handler cpu_rh850_signal_handler +#define cpu_list rh850_cpu_list +#define cpu_mmu_index rh850_cpu_mmu_index + +void rh850_set_mode(CPURH850State *env, target_ulong newpriv); + +void rh850_translate_init(struct uc_struct *uc); +RH850CPU *cpu_rh850_init(struct uc_struct *uc, const char *cpu_model); +int cpu_rh850_signal_handler(int host_signum, void *pinfo, void *puc); +void QEMU_NORETURN do_raise_exception_err(CPURH850State *env, + uint32_t exception, uintptr_t pc); + +target_ulong cpu_rh850_get_fflags(CPURH850State *env); +void cpu_rh850_set_fflags(CPURH850State *env, target_ulong); +void rh850_cpu_set_pc(CPUState *cs, vaddr value); +vaddr rh850_cpu_get_pc(CPUState *cs); +AddressSpace *cpu_addressspace(CPUState *cs, MemTxAttrs attrs); + +#define TB_FLAGS_MMU_MASK 3 +#define TB_FLAGS_FP_ENABLE MSTATUS_FS + +/* + * This f. is called from tcg_gen_lookup_and_goto_ptr() to obtain PC + * which is then used for TB lookup. + */ +static inline void cpu_get_tb_cpu_state(CPURH850State *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; +#ifdef CONFIG_USER_ONLY + *flags = TB_FLAGS_FP_ENABLE; +#else + *flags = cpu_mmu_index(env, 0); +#endif +} + +void csr_write_helper(CPURH850State *env, target_ulong val_to_write, + target_ulong csrno); +target_ulong csr_read_helper(CPURH850State *env, target_ulong csrno); + +#ifndef CONFIG_USER_ONLY +void rh850_set_local_interrupt(RH850CPU *cpu, target_ulong mask, int value); +#endif + +extern const int NUM_GDB_REGS; + +#include "exec/cpu-all.h" + +#endif /* RH850_CPU_H */ diff --git a/qemu/target/rh850/cpu_bits.h b/qemu/target/rh850/cpu_bits.h new file mode 100644 index 0000000000..a3b90298a6 --- /dev/null +++ b/qemu/target/rh850/cpu_bits.h @@ -0,0 +1,431 @@ +/* RH850 PSW constants */ + +#define PSW_Z 0x00000001 +#define PSW_S 0x00000002 +#define PSW_OV 0x00000004 +#define PSW_CY 0x00000008 +#define PSW_SAT 0x00000010 +#define PSW_ID 0x00000020 +#define PSW_EP 0x00000040 +#define PSW_NP 0x00000080 +#define PSW_EBV 0x00008000 +#define PSW_CU0 0x00010000 +#define PSW_UM 0x40000000 + +/* */ + +/* RH850 ISA constants */ + +#define get_field(reg, mask) (((reg) & \ + (target_ulong)(mask)) / ((mask) & ~((mask) << 1))) +#define set_field(reg, mask, val) (((reg) & ~(target_ulong)(mask)) | \ + (((target_ulong)(val) * ((mask) & ~((mask) << 1))) & \ + (target_ulong)(mask))) + +#define PGSHIFT 12 + +#define FSR_RD_SHIFT 5 +#define FSR_RD (0x7 << FSR_RD_SHIFT) + +#define FPEXC_NX 0x01 +#define FPEXC_UF 0x02 +#define FPEXC_OF 0x04 +#define FPEXC_DZ 0x08 +#define FPEXC_NV 0x10 + +#define FSR_AEXC_SHIFT 0 +#define FSR_NVA (FPEXC_NV << FSR_AEXC_SHIFT) +#define FSR_OFA (FPEXC_OF << FSR_AEXC_SHIFT) +#define FSR_UFA (FPEXC_UF << FSR_AEXC_SHIFT) +#define FSR_DZA (FPEXC_DZ << FSR_AEXC_SHIFT) +#define FSR_NXA (FPEXC_NX << FSR_AEXC_SHIFT) +#define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA) + +/* CSR numbers */ +#define CSR_FFLAGS 0x1 +#define CSR_FRM 0x2 +#define CSR_FCSR 0x3 +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_SBADADDR 0x143 +#define CSR_SIP 0x144 +#define CSR_SPTBR 0x180 +#define CSR_SATP 0x180 +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MCOUNTEREN 0x306 +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MBADADDR 0x343 +#define CSR_MIP 0x344 +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPCFG1 0x3a1 +#define CSR_PMPCFG2 0x3a2 +#define CSR_PMPCFG3 0x3a3 +#define CSR_PMPADDR0 0x3b0 +#define CSR_PMPADDR1 0x3b1 +#define CSR_PMPADDR2 0x3b2 +#define CSR_PMPADDR3 0x3b3 +#define CSR_PMPADDR4 0x3b4 +#define CSR_PMPADDR5 0x3b5 +#define CSR_PMPADDR6 0x3b6 +#define CSR_PMPADDR7 0x3b7 +#define CSR_PMPADDR8 0x3b8 +#define CSR_PMPADDR9 0x3b9 +#define CSR_PMPADDR10 0x3ba +#define CSR_PMPADDR11 0x3bb +#define CSR_PMPADDR12 0x3bc +#define CSR_PMPADDR13 0x3bd +#define CSR_PMPADDR14 0x3be +#define CSR_PMPADDR15 0x3bf +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH 0x7b2 +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MUCOUNTEREN 0x320 +#define CSR_MSCOUNTEREN 0x321 +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f + +/* mstatus bits */ +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_PUM 0x00040000 /* until: priv-1.9.1 */ +#define MSTATUS_SUM 0x00040000 /* since: priv-1.10 */ +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_VM 0x1F000000 /* until: priv-1.9.1 */ +#define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */ +#define MSTATUS_TW 0x20000000 /* since: priv-1.10 */ +#define MSTATUS_TSR 0x40000000 /* since: priv-1.10 */ + +#define MSTATUS64_UXL 0x0000000300000000ULL +#define MSTATUS64_SXL 0x0000000C00000000ULL + +#define MSTATUS32_SD 0x80000000 +#define MSTATUS64_SD 0x8000000000000000ULL + +#if defined(TARGET_RH850) +#define MSTATUS_SD MSTATUS32_SD +#endif + +/* sstatus bits */ +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_PUM 0x00040000 /* until: priv-1.9.1 */ +#define SSTATUS_SUM 0x00040000 /* since: priv-1.10 */ +#define SSTATUS_MXR 0x00080000 + +#define SSTATUS32_SD 0x80000000 +#define SSTATUS64_SD 0x8000000000000000ULL + +#if defined(TARGET_RH850) +#define SSTATUS_SD SSTATUS32_SD +#endif + +/* irqs */ +#define MIP_SSIP (1 << IRQ_S_SOFT) +#define MIP_HSIP (1 << IRQ_H_SOFT) +#define MIP_MSIP (1 << IRQ_M_SOFT) +#define MIP_STIP (1 << IRQ_S_TIMER) +#define MIP_HTIP (1 << IRQ_H_TIMER) +#define MIP_MTIP (1 << IRQ_M_TIMER) +#define MIP_SEIP (1 << IRQ_S_EXT) +#define MIP_HEIP (1 << IRQ_H_EXT) +#define MIP_MEIP (1 << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP +#define SIP_SEIP MIP_SEIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +/* privileged ISA 1.9.1 VM modes (mstatus.vm) */ +#define VM_1_09_MBARE 0 +#define VM_1_09_MBB 1 +#define VM_1_09_MBBID 2 +#define VM_1_09_SV32 8 +#define VM_1_09_SV39 9 +#define VM_1_09_SV48 10 + +/* privileged ISA 1.10.0 VM modes (satp.mode) */ +#define VM_1_10_MBARE 0 +#define VM_1_10_SV32 1 +#define VM_1_10_SV39 8 +#define VM_1_10_SV48 9 +#define VM_1_10_SV57 10 +#define VM_1_10_SV64 11 + +/* privileged ISA interrupt causes */ +#define IRQ_U_SOFT 0 /* since: priv-1.10 */ +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 /* until: priv-1.9.1 */ +#define IRQ_M_SOFT 3 /* until: priv-1.9.1 */ +#define IRQ_U_TIMER 4 /* since: priv-1.10 */ +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 /* until: priv-1.9.1 */ +#define IRQ_M_TIMER 7 /* until: priv-1.9.1 */ +#define IRQ_U_EXT 8 /* since: priv-1.10 */ +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 /* until: priv-1.9.1 */ +#define IRQ_M_EXT 11 /* until: priv-1.9.1 */ +#define IRQ_X_COP 12 /* non-standard */ + +/* Default addresses */ +#define DEFAULT_RSTVEC 0x00000000 + +/* RV32 satp field masks */ +#define SATP32_MODE 0x80000000 +#define SATP32_ASID 0x7fc00000 +#define SATP32_PPN 0x003fffff + +/* RV64 satp field masks */ +#define SATP64_MODE 0xF000000000000000ULL +#define SATP64_ASID 0x0FFFF00000000000ULL +#define SATP64_PPN 0x00000FFFFFFFFFFFULL + +#if defined(TARGET_RH850) +#define SATP_MODE SATP32_MODE +#define SATP_ASID SATP32_ASID +#define SATP_PPN SATP32_PPN +#endif + +/* RH850 Exception Codes */ +#define EXCP_NONE -1 /* not a real RH850 exception code */ +#define RH850_EXCP_INST_ADDR_MIS 0x0 +#define RH850_EXCP_INST_ACCESS_FAULT 0x1 +#define RH850_EXCP_ILLEGAL_INST 0x2 +#define RH850_EXCP_BREAKPOINT 0x3 +#define RH850_EXCP_LOAD_ADDR_MIS 0x4 +#define RH850_EXCP_LOAD_ACCESS_FAULT 0x5 +#define RH850_EXCP_STORE_AMO_ADDR_MIS 0x6 +#define RH850_EXCP_STORE_AMO_ACCESS_FAULT 0x7 +#define RH850_EXCP_U_ECALL 0x8 /* for convenience, report all + ECALLs as this, handler + fixes */ +#define RH850_EXCP_S_ECALL 0x9 +#define RH850_EXCP_H_ECALL 0xa +#define RH850_EXCP_M_ECALL 0xb +#define RH850_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */ +#define RH850_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */ +#define RH850_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */ +#define RH850_EXCP_FETRAP 0x10 +#define RH850_EXCP_TRAP 0x11 +#define RH850_EXCP_RIE 0x12 +#define RH850_EXCP_SYSCALL 0x13 +#define RH850_EXCP_EIINT 0x14 +#define RH850_EXCP_FEINT 0x15 +#define RH850_EXCP_FENMI 0x16 + +/* Specific interrupts (FENMI, FEINT, EIINT). */ +#define RH850_INT_FENMI CPU_INTERRUPT_TGT_EXT_0 /* Exception handler address is table-based */ +#define RH850_INT_FEINT CPU_INTERRUPT_TGT_EXT_1 /* Defines a non-maskable FE interrupt */ +#define RH850_INT_EIINT CPU_INTERRUPT_TGT_EXT_2 /* Defines a maskable FE interrupt */ + +#define RH850_EXCP_INT_FLAG 0x80000000 +#define RH850_EXCP_INT_MASK 0x7fffffff + + +/* page table entry (PTE) fields */ +#define PTE_V 0x001 /* Valid */ +#define PTE_R 0x002 /* Read */ +#define PTE_W 0x004 /* Write */ +#define PTE_X 0x008 /* Execute */ +#define PTE_U 0x010 /* User */ +#define PTE_G 0x020 /* Global */ +#define PTE_A 0x040 /* Accessed */ +#define PTE_D 0x080 /* Dirty */ +#define PTE_SOFT 0x300 /* Reserved for Software */ + +#define PTE_PPN_SHIFT 10 + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) diff --git a/qemu/target/rh850/cpu_user.h b/qemu/target/rh850/cpu_user.h new file mode 100644 index 0000000000..c2199610ab --- /dev/null +++ b/qemu/target/rh850/cpu_user.h @@ -0,0 +1,13 @@ +#define xRA 1 /* return address (aka link register) */ +#define xSP 2 /* stack pointer */ +#define xGP 3 /* global pointer */ +#define xTP 4 /* thread pointer */ + +#define xA0 10 /* gpr[10-17] are syscall arguments */ +#define xA1 11 +#define xA2 12 +#define xA3 13 +#define xA4 14 +#define xA5 15 +#define xA6 16 +#define xA7 17 /* syscall number goes here */ diff --git a/qemu/target/rh850/fpu_helper.c b/qemu/target/rh850/fpu_helper.c new file mode 100644 index 0000000000..d99c8613dd --- /dev/null +++ b/qemu/target/rh850/fpu_helper.c @@ -0,0 +1,823 @@ +/* + * RH850 FPU Emulation Helpers for QEMU. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * + * 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/>. + */ + +#include "qemu/osdep.h" +#include <stdlib.h> +#include "cpu.h" +#include "qemu/host-utils.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" + +target_ulong cpu_rh850_get_fflags(CPURH850State *env) +{ + int soft = get_float_exception_flags(&env->fp_status); + target_ulong hard = 0; + + hard |= (soft & float_flag_inexact) ? FPEXC_NX : 0; + hard |= (soft & float_flag_underflow) ? FPEXC_UF : 0; + hard |= (soft & float_flag_overflow) ? FPEXC_OF : 0; + hard |= (soft & float_flag_divbyzero) ? FPEXC_DZ : 0; + hard |= (soft & float_flag_invalid) ? FPEXC_NV : 0; + + return hard; +} + +void cpu_rh850_set_fflags(CPURH850State *env, target_ulong hard) +{ + int soft = 0; + + soft |= (hard & FPEXC_NX) ? float_flag_inexact : 0; + soft |= (hard & FPEXC_UF) ? float_flag_underflow : 0; + soft |= (hard & FPEXC_OF) ? float_flag_overflow : 0; + soft |= (hard & FPEXC_DZ) ? float_flag_divbyzero : 0; + soft |= (hard & FPEXC_NV) ? float_flag_invalid : 0; + + set_float_exception_flags(soft, &env->fp_status); +} + +void helper_set_rounding_mode(CPURH850State *env, uint32_t rm) +{ + int softrm; + + if (rm == 7) { + rm = 0; //env->frm; + } + switch (rm) { + case 0: + softrm = float_round_nearest_even; + break; + case 1: + softrm = float_round_to_zero; + break; + case 2: + softrm = float_round_down; + break; + case 3: + softrm = float_round_up; + break; + case 4: + softrm = float_round_ties_away; + break; + default: + qemu_log_mask(CPU_LOG_INT, "%s\n", __func__); + do_raise_exception_err(env, RH850_EXCP_ILLEGAL_INST, GETPC()); + } + + set_float_rounding_mode(softrm, &env->fp_status); +} + +/* Propagate softfloat flags into FPSR. */ +void helper_f_sync_fflags(CPURH850State *env) +{ + target_ulong flags; + + /* Retrieve softfloat flags. */ + flags = cpu_rh850_get_fflags(env); + + /* Handle inexact flag. */ + if (flags & FPEXC_NX) + { + if (env->fpsr & (1 << 5)) + { + /* Inexact exception allowed, set cause bit. */ + env->fpsr |= (1 << 10); + } + else + { + /* Set preservation bit. */ + flags |= 1 << 0; + } + } + + /* Handle underflow flag. */ + if (flags & FPEXC_UF) + { + if (env->fpsr & (1 << 6)) + { + /* Underflow exception allowed, set cause bit. */ + env->fpsr |= (1 << 11); + } + else + { + /* Set preservation bit. */ + env->fpsr |= 1 << 1; + } + } + + /* Handle overflow flag. */ + if (flags & FPEXC_OF) + { + if (env->fpsr & (1 << 7)) + { + /* Overflow exception allowed, set cause bit. */ + env->fpsr |= (1 << 12); + } + else + { + /* Set preservation bit. */ + env->fpsr |= 1 << 2; + } + } + + /* Handle div-by-zero flag. */ + if (flags & FPEXC_DZ) + { + if (env->fpsr & (1 << 8)) + { + /* Div-by-zero exception allowed, set cause bit. */ + env->fpsr |= (1 << 13); + } + else + { + /* Set preservation bit. */ + env->fpsr |= 1 << 3; + } + } + + /* Handle invalid flag. */ + if (flags & FPEXC_NV) + { + if (env->fpsr & (1 << 9)) + { + /* Div-by-zero exception allowed, set cause bit. */ + env->fpsr |= (1 << 14); + } + else + { + /* Set preservation bit. */ + env->fpsr |= 1 << 4; + } + } +} + +/** + * FPU flags checks + **/ + +uint32_t HELPER(f32_is_normal)(CPURH850State *env, uint32_t frs1) +{ + return (uint32_t)float32_is_normal(frs1); +} + +uint32_t HELPER(f32_is_zero_or_normal)(CPURH850State *env, uint32_t frs1) +{ + return (uint32_t)float32_is_zero_or_normal(frs1); +} + +uint32_t HELPER(f32_is_infinity)(CPURH850State *env, uint32_t frs1) +{ + return (uint32_t)float32_is_infinity(frs1); +} + + + +uint64_t helper_fmadd_s(CPURH850State *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3) +{ + return float32_muladd(frs1, frs2, frs3, 0, &env->fp_status); +} + +uint64_t helper_fmadd_d(CPURH850State *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3) +{ + return float64_muladd(frs1, frs2, frs3, 0, &env->fp_status); +} + +uint64_t helper_fmsub_s(CPURH850State *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3) +{ + return float32_muladd(frs1, frs2, frs3, float_muladd_negate_c, + &env->fp_status); +} + +uint64_t helper_fmsub_d(CPURH850State *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3) +{ + return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c, + &env->fp_status); +} + +uint64_t helper_fnmsub_s(CPURH850State *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3) +{ + return float32_muladd(frs1, frs2, frs3, float_muladd_negate_product, + &env->fp_status); +} + +uint64_t helper_fnmsub_d(CPURH850State *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3) +{ + return float64_muladd(frs1, frs2, frs3, float_muladd_negate_product, + &env->fp_status); +} + +uint64_t helper_fnmadd_s(CPURH850State *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3) +{ + return float32_muladd(frs1, frs2, frs3, float_muladd_negate_c | + float_muladd_negate_product, &env->fp_status); +} + +uint64_t helper_fnmadd_d(CPURH850State *env, uint64_t frs1, uint64_t frs2, + uint64_t frs3) +{ + return float64_muladd(frs1, frs2, frs3, float_muladd_negate_c | + float_muladd_negate_product, &env->fp_status); +} + + +/** + * Floating-point simple precision helpers. + **/ + +uint32_t HELPER(fadd_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_add(frs1, frs2, &env->fp_status); +} + +uint32_t HELPER(fsub_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_sub(frs1, frs2, &env->fp_status); +} + +uint32_t HELPER(fmul_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_mul(frs1, frs2, &env->fp_status); +} + +uint32_t HELPER(fmax_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_maxnum(frs1, frs2, &env->fp_status); +} + +uint32_t HELPER(fmin_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_minnum(frs1, frs2, &env->fp_status); +} + +uint32_t HELPER(fdiv_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_div(frs1, frs2, &env->fp_status); +} + +uint32_t HELPER(fabs_s)(CPURH850State *env, uint32_t frs1) +{ + return float32_abs(frs1); +} + +uint32_t HELPER(fneg_s)(CPURH850State *env, uint32_t frs1) +{ + return (frs1^0x80000000); +} + +uint32_t HELPER(ftrnc_sw)(CPURH850State *env, uint32_t frs1) +{ + return float32_to_int32_round_to_zero(frs1, &env->fp_status); +} + +uint32_t HELPER(fceil_sw)(CPURH850State *env, uint32_t frs1) +{ + /* Convert to int32 and round to positive. */ + return float32_to_int32_scalbn(frs1, float_round_up, 0, &env->fp_status); +} + +uint32_t HELPER(ffloor_sw)(CPURH850State *env, uint32_t frs1) +{ + /* Convert to int32 and round to positive. */ + return float32_to_int32_scalbn(frs1, float_round_down, 0, &env->fp_status); +} + +uint32_t HELPER(fcvt_sw)(CPURH850State *env, uint32_t frs1) +{ + /* Convert to int32 and round based on fp_status. */ + return float32_to_int32(frs1, &env->fp_status); +} + +uint32_t HELPER(fcvt_ls)(CPURH850State *env, uint64_t frs1) +{ + /* Convert int64 to float32 and round based on fp_status. */ + return int64_to_float32(frs1, &env->fp_status); +} + +uint32_t HELPER(fcvt_hs)(CPURH850State *env, uint32_t frs1) +{ + /* Convert lower half of frs1 into float32. */ + return int16_to_float32((int16_t)(frs1&0xffff), &env->fp_status); +} + +uint32_t HELPER(fcvt_sh)(CPURH850State *env, uint32_t frs1) +{ + /* Convert float32 to int16_t, zero-extended. */ + return float32_to_int16(frs1, &env->fp_status) & 0xffff; +} + +uint32_t HELPER(fcvt_ws)(CPURH850State *env, uint32_t frs1) +{ + /* Convert to float32 and round based on fp_status. */ + return int32_to_float32(frs1, &env->fp_status); +} + +uint32_t HELPER(ftrnc_suw)(CPURH850State *env, uint32_t frs1) +{ + return float32_to_uint32_round_to_zero(frs1, &env->fp_status); +} + +uint32_t HELPER(fceil_suw)(CPURH850State *env, uint32_t frs1) +{ + /* Convert to int32 and round to positive. */ + return float32_to_uint32_scalbn(frs1, float_round_up, 0, &env->fp_status); +} + +uint32_t HELPER(ffloor_suw)(CPURH850State *env, uint32_t frs1) +{ + /* Convert to int32 and round to positive. */ + return float32_to_uint32_scalbn(frs1, float_round_down, 0, &env->fp_status); +} + +uint32_t HELPER(fcvt_suw)(CPURH850State *env, uint32_t frs1) +{ + /* Convert to int32 and round based on fp_status. */ + return float32_to_uint32(frs1, &env->fp_status); +} + +uint32_t HELPER(fcvt_uws)(CPURH850State *env, uint32_t frs1) +{ + /* Convert from uint32 to float32 and round based on fp_status. */ + return uint32_to_float32(frs1, &env->fp_status); +} + +uint32_t HELPER(fcvt_uls)(CPURH850State *env, uint64_t frs1) +{ + /* Convert uint64 to float32 and round based on fp_status. */ + return uint64_to_float32(frs1, &env->fp_status); +} + +uint64_t HELPER(ftrnc_sl)(CPURH850State *env, uint32_t frs1) +{ + return float32_to_int64_round_to_zero(frs1, &env->fp_status); +} + +uint64_t HELPER(fceil_sl)(CPURH850State *env, uint32_t frs1) +{ + /* Convert float32 to int64 and round to upper value. */ + return float32_to_int64_scalbn(frs1, float_round_up, 0, &env->fp_status); +} + +uint64_t HELPER(ffloor_sl)(CPURH850State *env, uint32_t frs1) +{ + /* Convert float32 to int64 and round to lower value. */ + return float32_to_int64_scalbn(frs1, float_round_down, 0, &env->fp_status); +} + +uint64_t HELPER(fcvt_sl)(CPURH850State *env, uint32_t frs1) +{ + /* Convert float32 to int64. */ + return float32_to_int64(frs1, &env->fp_status); +} + +uint64_t HELPER(ftrnc_sul)(CPURH850State *env, uint32_t frs1) +{ + return float32_to_uint64_round_to_zero(frs1, &env->fp_status); +} + +uint64_t HELPER(fceil_sul)(CPURH850State *env, uint32_t frs1) +{ + /* Convert float32 to uint64 and round to upper value. */ + return float32_to_uint64_scalbn(frs1, float_round_up, 0, &env->fp_status); +} + +uint64_t HELPER(ffloor_sul)(CPURH850State *env, uint32_t frs1) +{ + /* Convert float32 to uint64 and round to lower value. */ + return float32_to_uint64_scalbn(frs1, float_round_down, 0, &env->fp_status); +} + +uint64_t HELPER(fcvt_sul)(CPURH850State *env, uint32_t frs1) +{ + /* Convert float32 to uint64. */ + return float32_to_uint64(frs1, &env->fp_status); +} + +uint32_t HELPER(fsqrt_s)(CPURH850State *env, uint32_t frs1) +{ + return float32_sqrt(frs1, &env->fp_status); +} + +uint32_t HELPER(frecip_s)(CPURH850State *env, uint32_t frs1) +{ + /* Compute 1/x (0x3f800000 = float32(1.1)). */ + return float32_div(0x3f800000, frs1, &env->fp_status); +} + +uint32_t HELPER(frsqrt_s)(CPURH850State *env, uint32_t frs1) +{ + /* Compute 1/sqrt(x). */ + return HELPER(frecip_s)(env, float32_sqrt(frs1, &env->fp_status)); +} + +uint32_t HELPER(f_is_nan_s)(CPURH850State *env, uint32_t frs1) +{ + /* Check if float32 is NaN. */ + return float32_is_any_nan(frs1); +} + +uint32_t helper_fle_s(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_le(frs1, frs2, &env->fp_status); +} + +uint32_t helper_flt_s(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_lt(frs1, frs2, &env->fp_status); +} + +uint32_t helper_feq_s(CPURH850State *env, uint32_t frs1, uint32_t frs2) +{ + return float32_eq_quiet(frs1, frs2, &env->fp_status); +} + + +uint32_t HELPER(fmaf_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2, uint32_t frs3) +{ + /* Compute (frs1 * frs2) + frs3 */ + return float32_muladd(frs1, frs2, frs3, 0, &env->fp_status); +} + +uint32_t HELPER(fmsf_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2, uint32_t frs3) +{ + /* Compute (frs1 * frs2) - frs3 */ + return float32_muladd(frs1, frs2, frs3, float_muladd_negate_c, &env->fp_status); +} + +uint32_t HELPER(fnmaf_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2, uint32_t frs3) +{ + /* Compute (frs1 * frs2) + frs3 */ + return float32_muladd(frs1, frs2, frs3, float_muladd_negate_result, &env->fp_status); +} + +uint32_t HELPER(fnmsf_s)(CPURH850State *env, uint32_t frs1, uint32_t frs2, uint32_t frs3) +{ + /* Compute (frs1 * frs2) - frs3 */ + return float32_muladd(frs1, frs2, frs3, float_muladd_negate_c | float_muladd_negate_result, &env->fp_status); +} + + + +target_ulong helper_fcvt_w_s(CPURH850State *env, uint64_t frs1) +{ + return float32_to_int32(frs1, &env->fp_status); +} + +target_ulong helper_fcvt_wu_s(CPURH850State *env, uint64_t frs1) +{ + return (int32_t)float32_to_uint32(frs1, &env->fp_status); +} + +#if defined(TARGET_RH85064) +uint64_t helper_fcvt_l_s(CPURH850State *env, uint64_t frs1) +{ + return float32_to_int64(frs1, &env->fp_status); +} + +uint64_t helper_fcvt_lu_s(CPURH850State *env, uint64_t frs1) +{ + return float32_to_uint64(frs1, &env->fp_status); +} +#endif + +uint64_t helper_fcvt_s_w(CPURH850State *env, target_ulong rs1) +{ + return int32_to_float32((int32_t)rs1, &env->fp_status); +} + +uint64_t helper_fcvt_s_wu(CPURH850State *env, target_ulong rs1) +{ + return uint32_to_float32((uint32_t)rs1, &env->fp_status); +} + +#if defined(TARGET_RH85064) +uint64_t helper_fcvt_s_l(CPURH850State *env, uint64_t rs1) +{ + return int64_to_float32(rs1, &env->fp_status); +} + +uint64_t helper_fcvt_s_lu(CPURH850State *env, uint64_t rs1) +{ + return uint64_to_float32(rs1, &env->fp_status); +} +#endif + +target_ulong helper_fclass_s(uint64_t frs1) +{ + float32 f = frs1; + bool sign = float32_is_neg(f); + + if (float32_is_infinity(f)) { + return sign ? 1 << 0 : 1 << 7; + } else if (float32_is_zero(f)) { + return sign ? 1 << 3 : 1 << 4; + } else if (float32_is_zero_or_denormal(f)) { + return sign ? 1 << 2 : 1 << 5; + } else if (float32_is_any_nan(f)) { + float_status s = { 0 }; /* for snan_bit_is_one */ + return float32_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; + } else { + return sign ? 1 << 1 : 1 << 6; + } +} + +/** + * Floating-point double precision helpers. + **/ + +uint64_t HELPER(fadd_d)(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_add(frs1, frs2, &env->fp_status); +} + +uint64_t HELPER(fsub_d)(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_sub(frs1, frs2, &env->fp_status); +} + +uint64_t HELPER(fmul_d)(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_mul(frs1, frs2, &env->fp_status); +} + +uint64_t HELPER(fmax_d)(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_maxnum(frs1, frs2, &env->fp_status); +} + +uint64_t HELPER(fmin_d)(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_minnum(frs1, frs2, &env->fp_status); +} + +uint64_t HELPER(fdiv_d)(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_div(frs1, frs2, &env->fp_status); +} + +uint64_t HELPER(fabs_d)(CPURH850State *env, uint64_t frs1) +{ + return float64_abs(frs1); +} + +uint64_t HELPER(fneg_d)(CPURH850State *env, uint64_t frs1) +{ + return (frs1 ^ 0x8000000000000000); +} + +uint32_t HELPER(ftrnc_dw)(CPURH850State *env, uint64_t frs1) +{ + return float64_to_int32_round_to_zero(frs1, &env->fp_status); +} + +uint32_t HELPER(fceil_dw)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to int32 and round to upper value. */ + return float64_to_int32_scalbn(frs1, float_round_up, 0, &env->fp_status); +} + +uint32_t HELPER(ffloor_dw)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to int32 and round to lower value. */ + return float64_to_int32_scalbn(frs1, float_round_down, 0, &env->fp_status); +} + +uint32_t HELPER(fcvt_dw)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to int32. */ + return float64_to_int32(frs1, &env->fp_status); +} + +uint32_t HELPER(ftrnc_duw)(CPURH850State *env, uint64_t frs1) +{ + return float64_to_uint32_round_to_zero(frs1, &env->fp_status); +} + +uint32_t HELPER(fceil_duw)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to uint32 and round to upper value. */ + return float64_to_uint32_scalbn(frs1, float_round_up, 0, &env->fp_status); +} + +uint32_t HELPER(ffloor_duw)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to uint32 and round to lower value. */ + return float64_to_uint32_scalbn(frs1, float_round_down, 0, &env->fp_status); +} + +uint32_t HELPER(fcvt_duw)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to uint32. */ + return float64_to_uint32(frs1, &env->fp_status); +} + +uint64_t HELPER(fcvt_wd)(CPURH850State *env, uint32_t frs1) +{ + /* Convert int32 to float64. */ + return int32_to_float64(frs1, &env->fp_status); +} + +uint64_t HELPER(fcvt_ld)(CPURH850State *env, uint64_t frs1) +{ + /* Convert int32 to float64. */ + return int64_to_float64(frs1, &env->fp_status); +} + +uint64_t HELPER(fcvt_sd)(CPURH850State *env, uint32_t frs1) +{ + /* Convert float32 to float64. */ + return float32_to_float64(frs1, &env->fp_status); +} + +uint64_t HELPER(fcvt_uwd)(CPURH850State *env, uint32_t frs1) +{ + /* Convert int32 to float64. */ + return uint32_to_float64(frs1, &env->fp_status); +} + +uint64_t HELPER(fcvt_uld)(CPURH850State *env, uint64_t frs1) +{ + /* Convert int32 to float64. */ + return uint64_to_float64(frs1, &env->fp_status); +} + + + +uint64_t HELPER(ftrnc_dl)(CPURH850State *env, uint64_t frs1) +{ + return float64_to_int64_round_to_zero(frs1, &env->fp_status); +} + +uint64_t HELPER(fceil_dl)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to int64 and round to upper value. */ + return float64_to_int64_scalbn(frs1, float_round_up, 0, &env->fp_status); +} + +uint64_t HELPER(ffloor_dl)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to int64 and round to lower value. */ + return float64_to_int64_scalbn(frs1, float_round_down, 0, &env->fp_status); +} + +uint64_t HELPER(fcvt_dl)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to int64. */ + return float64_to_int64(frs1, &env->fp_status); +} + +uint64_t HELPER(ftrnc_dul)(CPURH850State *env, uint64_t frs1) +{ + return float64_to_uint64_round_to_zero(frs1, &env->fp_status); +} + +uint64_t HELPER(fceil_dul)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to uint64 and round to upper value. */ + return float64_to_uint64_scalbn(frs1, float_round_up, 0, &env->fp_status); +} + +uint64_t HELPER(ffloor_dul)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to uint64 and round to lower value. */ + return float64_to_uint64_scalbn(frs1, float_round_down, 0, &env->fp_status); +} + +uint64_t HELPER(fcvt_dul)(CPURH850State *env, uint64_t frs1) +{ + /* Convert float64 to uint64. */ + return float64_to_uint64(frs1, &env->fp_status); +} + +uint64_t HELPER(fsqrt_d)(CPURH850State *env, uint64_t frs1) +{ + return float64_sqrt(frs1, &env->fp_status); +} + +uint64_t HELPER(frecip_d)(CPURH850State *env, uint64_t frs1) +{ + /* Compute 1/x (0x3ff0000000000000 = float64(1.1)). */ + return float64_div(0x3ff0000000000000, frs1, &env->fp_status); +} + +uint64_t HELPER(frsqrt_d)(CPURH850State *env, uint64_t frs1) +{ + /* Compute 1/sqrt(x). */ + return HELPER(frecip_d)(env, float64_sqrt(frs1, &env->fp_status)); +} + +uint32_t HELPER(f_is_nan_d)(CPURH850State *env, uint64_t frs1) +{ + /* Check if float64 is NaN. */ + return float64_is_any_nan(frs1); +} + + + +uint64_t helper_fcvt_s_d(CPURH850State *env, uint64_t rs1) +{ + return float64_to_float32(rs1, &env->fp_status); +} + +uint64_t helper_fcvt_d_s(CPURH850State *env, uint64_t rs1) +{ + return float32_to_float64(rs1, &env->fp_status); +} + +uint32_t helper_fle_d(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_le(frs1, frs2, &env->fp_status); +} + +uint32_t helper_flt_d(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_lt(frs1, frs2, &env->fp_status); +} + +uint32_t helper_feq_d(CPURH850State *env, uint64_t frs1, uint64_t frs2) +{ + return float64_eq_quiet(frs1, frs2, &env->fp_status); +} + +target_ulong helper_fcvt_w_d(CPURH850State *env, uint64_t frs1) +{ + return float64_to_int32(frs1, &env->fp_status); +} + +target_ulong helper_fcvt_wu_d(CPURH850State *env, uint64_t frs1) +{ + return (int32_t)float64_to_uint32(frs1, &env->fp_status); +} + +#if defined(TARGET_RH85064) +uint64_t helper_fcvt_l_d(CPURH850State *env, uint64_t frs1) +{ + return float64_to_int64(frs1, &env->fp_status); +} + +uint64_t helper_fcvt_lu_d(CPURH850State *env, uint64_t frs1) +{ + return float64_to_uint64(frs1, &env->fp_status); +} +#endif + +uint64_t helper_fcvt_d_w(CPURH850State *env, target_ulong rs1) +{ + return int32_to_float64((int32_t)rs1, &env->fp_status); +} + +uint64_t helper_fcvt_d_wu(CPURH850State *env, target_ulong rs1) +{ + return uint32_to_float64((uint32_t)rs1, &env->fp_status); +} + +#if defined(TARGET_RH85064) +uint64_t helper_fcvt_d_l(CPURH850State *env, uint64_t rs1) +{ + return int64_to_float64(rs1, &env->fp_status); +} + +uint64_t helper_fcvt_d_lu(CPURH850State *env, uint64_t rs1) +{ + return uint64_to_float64(rs1, &env->fp_status); +} +#endif + +target_ulong helper_fclass_d(uint64_t frs1) +{ + float64 f = frs1; + bool sign = float64_is_neg(f); + + if (float64_is_infinity(f)) { + return sign ? 1 << 0 : 1 << 7; + } else if (float64_is_zero(f)) { + return sign ? 1 << 3 : 1 << 4; + } else if (float64_is_zero_or_denormal(f)) { + return sign ? 1 << 2 : 1 << 5; + } else if (float64_is_any_nan(f)) { + float_status s = { 0 }; /* for snan_bit_is_one */ + return float64_is_quiet_nan(f, &s) ? 1 << 9 : 1 << 8; + } else { + return sign ? 1 << 1 : 1 << 6; + } +} diff --git a/qemu/target/rh850/fpu_translate.c b/qemu/target/rh850/fpu_translate.c new file mode 100644 index 0000000000..2fd008177b --- /dev/null +++ b/qemu/target/rh850/fpu_translate.c @@ -0,0 +1,1557 @@ +#include "fpu_translate.h" +#include "instmap.h" + +extern TCGv_i32 cpu_ZF; + +/* Helpers */ +void fpu_load_i64(TCGContext *tcg_ctx, TCGv_i64 dst, int reg_n); +void fpu_load_i64_2(TCGContext *tcg_ctx, TCGv_i64 dst0, TCGv_i64 dst1, int reg_n0, int reg_n1); +void fpu_store_i64(TCGContext *tcg_ctx, int reg_n, TCGv_i64 src); + +/* Single-precision */ +void fpu_gen_sp_ir_3(CPURH850State *env, DisasContext *ctx, int operands, int op, int rs1, int rs2, int rs3); +void fpu_gen_sp_ir_2(CPURH850State *env, DisasContext *ctx, int operands, int op, int rs2, int rs3); +void fpu_gen_cmpf_s(CPURH850State *env, DisasContext *ctx, int rs1, int rs2, int fcond, int fcbit); +void fpu_gen_cmov_s(CPURH850State *env, DisasContext *ctx, int rs1, int rs2, int rs3, int fcbit); +void fpu_gen_trfsr(CPURH850State *env, DisasContext *ctx, int fcbit); +void fpu_gen_cat1_ir(CPURH850State *env, DisasContext *ctx, int op, int frs1, int frs2, int frs3); + + +/* Double precision */ +void fpu_gen_cmpf_d(CPURH850State *env, DisasContext *ctx, int rs1, int rs2, int fcond, int fcbit); +void fpu_gen_cmov_d(CPURH850State *env, DisasContext *ctx, int rs1, int rs2, int rs3, int fcbit); +void fpu_gen_dp_ir_3(CPURH850State *env, DisasContext *ctx, int operands, int op, int rs1, int rs2, int rs3); +void fpu_gen_dp_ir_2(CPURH850State *env, DisasContext *ctx, int operands, int op, int rs2, int rs3); + + +/** + * Helpers for 64-bit register load/store + **/ + +void fpu_load_i64(TCGContext *tcg_ctx, TCGv_i64 dst, int reg_n) +{ + TCGv_i32 rl = tcg_temp_local_new_i32(tcg_ctx); + TCGv_i32 rh = tcg_temp_local_new_i32(tcg_ctx); + + /* Read float64 from (reg_n/reg_n+1). */ + gen_get_gpr(tcg_ctx, rl, reg_n); + gen_get_gpr(tcg_ctx, rh, reg_n+1); + tcg_gen_concat_i32_i64(tcg_ctx, dst, rl, rh); + + /* Free temporary variables. */ + tcg_temp_free_i32(tcg_ctx, rl); + tcg_temp_free_i32(tcg_ctx, rh); +} + +void fpu_store_i64(TCGContext *tcg_ctx, int reg_n, TCGv_i64 src) +{ + TCGv_i32 rl = tcg_temp_local_new_i32(tcg_ctx); + TCGv_i32 rh = tcg_temp_local_new_i32(tcg_ctx); + TCGv_i64 shift = tcg_temp_local_new_i64(tcg_ctx); + + tcg_gen_movi_i64(tcg_ctx, shift, 32); + tcg_gen_extrl_i64_i32(tcg_ctx, rl, src); + tcg_gen_shr_i64(tcg_ctx, src, src, shift); + tcg_gen_extrl_i64_i32(tcg_ctx, rh, src); + gen_set_gpr(tcg_ctx, reg_n, rl); + gen_set_gpr(tcg_ctx, reg_n + 1, rh); + + /* Free temporary variables. */ + tcg_temp_free_i32(tcg_ctx, rl); + tcg_temp_free_i32(tcg_ctx, rh); +} + +void fpu_load_i64_2(TCGContext *tcg_ctx, TCGv_i64 dst0, TCGv_i64 dst1, int reg_n0, int reg_n1) +{ + TCGv_i32 rl = tcg_temp_local_new_i32(tcg_ctx); + TCGv_i32 rh = tcg_temp_local_new_i32(tcg_ctx); + + /* Read float64 from (reg_n0/reg_n0 + 1). */ + gen_get_gpr(tcg_ctx, rl, reg_n0); + gen_get_gpr(tcg_ctx, rh, reg_n0 + 1); + tcg_gen_concat_i32_i64(tcg_ctx, dst0, rl, rh); + + /* Read float64 from (reg_n1/reg_n1 + 1). */ + gen_get_gpr(tcg_ctx, rl, reg_n1); + gen_get_gpr(tcg_ctx, rh, reg_n1 + 1); + tcg_gen_concat_i32_i64(tcg_ctx, dst1, rl, rh); + + /* Free temporary variables. */ + tcg_temp_free_i32(tcg_ctx, rl); + tcg_temp_free_i32(tcg_ctx, rh); +} + +/** + * Floating-point simple-precision IR generators. + **/ + +void fpu_gen_cat1_ir(CPURH850State *env, DisasContext *ctx, int op, int frs1, int frs2, int frs3) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv r1 = tcg_temp_local_new(tcg_ctx); + TCGv r2 = tcg_temp_local_new(tcg_ctx); + TCGv r3 = tcg_temp_local_new(tcg_ctx); + + /* Load register content from frs1, frs2 and frs3. */ + gen_get_gpr(tcg_ctx, r1, frs1); + gen_get_gpr(tcg_ctx, r2, frs2); + gen_get_gpr(tcg_ctx, r3, frs3); + + switch(op) + { + case OPC_RH850_FPU_FMAF_S: + gen_helper_fmaf_s(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2, r3); + break; + + case OPC_RH850_FPU_FMSF_S: + gen_helper_fmsf_s(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2, r3); + break; + + case OPC_RH850_FPU_FNMAF_S: + gen_helper_fnmaf_s(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2, r3); + break; + + case OPC_RH850_FPU_FNMSF_S: + gen_helper_fnmsf_s(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2, r3); + break; + + default: + /* Unknown instruction. */ + break; + } + + /* Store r3 register into frs3. */ + gen_set_gpr(tcg_ctx, frs3, r3); + + /* Free locals. */ + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, r3); +} + + +void fpu_gen_sp_ir_2(CPURH850State *env, DisasContext *ctx, int operands, int op, int rs2, int rs3) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + /* rs1, rs2 and rs3 for TCG */ + TCGv r2 = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3 = tcg_temp_local_new_i32(tcg_ctx); + TCGv_i64 r3_64 = tcg_temp_local_new_i64(tcg_ctx); + + /* Load contents from registers. */ + switch(operands) + { + case FPU_TYPE_S: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_ABS: + gen_helper_fabs_s(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_NEG: + gen_helper_fneg_s(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_SQRT: + gen_helper_fsqrt_s(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_RECIP: + gen_helper_frecip_s(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_RSQRT: + gen_helper_frsqrt_s(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + } + + /* Store result. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_SL: + { + /* Load simple-precision float. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_TRNC: + gen_helper_ftrnc_sl(tcg_ctx, r3_64, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CEIL: + gen_helper_fceil_sl(tcg_ctx, r3_64, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_FLOOR: + gen_helper_ffloor_sl(tcg_ctx, r3_64, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CVT: + gen_helper_fcvt_sl(tcg_ctx, r3_64, tcg_ctx->cpu_env, r2); + break; + } + + /* Store result as long. */ + fpu_store_i64(tcg_ctx, rs3, r3_64); + } + break; + + case FPU_TYPE_SUL: + { + /* Load simple-precision float. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_TRNC: + gen_helper_ftrnc_sul(tcg_ctx, r3_64, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CEIL: + gen_helper_fceil_sul(tcg_ctx, r3_64, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_FLOOR: + gen_helper_ffloor_sul(tcg_ctx, r3_64, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CVT: + gen_helper_fcvt_sul(tcg_ctx, r3_64, tcg_ctx->cpu_env, r2); + break; + } + + /* Store result as long. */ + fpu_store_i64(tcg_ctx, rs3, r3_64); + } + break; + + + case FPU_TYPE_SW: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_TRNC: + gen_helper_ftrnc_sw(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CEIL: + gen_helper_fceil_sw(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_FLOOR: + gen_helper_ffloor_sw(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CVT: + gen_helper_fcvt_sw(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + } + + /* Store result. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_SUW: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_TRNC: + gen_helper_ftrnc_suw(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CEIL: + gen_helper_fceil_suw(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_FLOOR: + gen_helper_ffloor_suw(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CVT: + gen_helper_fcvt_suw(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + } + + /* Store result. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_LS: + { + /* Load content from register. */ + fpu_load_i64(tcg_ctx, r3_64, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_ls(tcg_ctx, r3, tcg_ctx->cpu_env, r3_64); + } + else + { + /* Unsupported operation. */ + } + + /* Store result into rs3. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_HS: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_hs(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + } + else + { + /* Unsupported operation. */ + } + + /* Store result into rs3. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_WS: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_ws(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + } + else + { + /* Unsupported operation. */ + } + + /* Store result into rs3. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + + case FPU_TYPE_SH: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_sh(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + } + else + { + /* Unsupported operation. */ + } + + /* Store result into rs3. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_ULS: + { + /* Load content from register. */ + fpu_load_i64(tcg_ctx, r3_64, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_uls(tcg_ctx, r3, tcg_ctx->cpu_env, r3_64); + } + else + { + /* Unsupported operation. */ + } + + /* Store result into rs3. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_UWS: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_uws(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + } + else + { + /* Unsupported operation. */ + } + + /* Store result into rs3. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + + } + + /* Mov softfloat flags into our register. */ + gen_helper_f_sync_fflags(tcg_ctx, tcg_ctx->cpu_env); + + /* Free temp. */ + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, r3); + tcg_temp_free_i64(tcg_ctx, r3_64); +} + +/** + * refactored + **/ + +void fpu_gen_sp_ir_3(CPURH850State *env, DisasContext *ctx, int operands, int op, int rs1, int rs2, int rs3) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + /* rs1, rs2 and rs3 for TCG */ + TCGv r1 = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2 = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3 = tcg_temp_local_new_i32(tcg_ctx); + + /* Load contents from registers. */ + switch(operands) + { + case FPU_TYPE_S: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + } + break; + } + + /* Apply operation. */ + switch(op) + { + case FPU_OP_ADD: + gen_helper_fadd_s(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2); + break; + + case FPU_OP_DIV: + gen_helper_fdiv_s(tcg_ctx, r3, tcg_ctx->cpu_env, r2, r1); + break; + + case FPU_OP_SUB: + gen_helper_fsub_s(tcg_ctx, r3, tcg_ctx->cpu_env, r2, r1); + break; + + case FPU_OP_MAX: + gen_helper_fmax_s(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2); + break; + + case FPU_OP_MIN: + gen_helper_fmin_s(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2); + break; + + case FPU_OP_MUL: + gen_helper_fmul_s(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2); + break; + } + + /* Store result. */ + switch(operands) + { + case FPU_TYPE_S: + { + /* Set reg3. */ + gen_set_gpr(tcg_ctx, rs3, r3); + } + break; + } + + /* Mov softfloat flags into our register. */ + gen_helper_f_sync_fflags(tcg_ctx, tcg_ctx->cpu_env); + + /* Free temp. */ + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, r3); +} + + +void fpu_gen_trfsr(CPURH850State *env, DisasContext *ctx, int fcbit) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv fpsr = tcg_temp_local_new(tcg_ctx); + TCGv mask = tcg_temp_local_new(tcg_ctx); + TCGv shift = tcg_temp_local_new(tcg_ctx); + TCGv one = tcg_const_i32(tcg_ctx, 1); + TCGv value = tcg_temp_local_new(tcg_ctx); + + /* Load fpsr and compute mask. */ + gen_get_spr(tcg_ctx, BANK_ID_BASIC_0, FPSR_IDX, fpsr); + tcg_gen_movi_i32(tcg_ctx, shift, 24 + fcbit); + tcg_gen_shl_i32(tcg_ctx, mask, one, shift); + + /* Extract CCn bit. */ + tcg_gen_and_i32(tcg_ctx, value, fpsr, mask); + tcg_gen_shr_i32(tcg_ctx, value, value, shift); + + /* Set Z flag. */ + tcg_gen_mov_i32(tcg_ctx, cpu_ZF, value); + gen_set_gpr(tcg_ctx, 1, value); + + /* Free locals. */ + tcg_temp_free(tcg_ctx, fpsr); + tcg_temp_free(tcg_ctx, mask); + tcg_temp_free(tcg_ctx, shift); + tcg_temp_free(tcg_ctx, one); + tcg_temp_free(tcg_ctx, value); +} + +void fpu_gen_cmov_s(CPURH850State *env, DisasContext *ctx, int rs1, int rs2, int rs3, int fcbit) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGLabel *end, *otherwise; + TCGv r1 = tcg_temp_local_new(tcg_ctx); + TCGv r2 = tcg_temp_local_new(tcg_ctx); + TCGv final_shift = tcg_temp_local_new(tcg_ctx); + TCGv res = tcg_temp_local_new(tcg_ctx); + TCGv fpsr = tcg_temp_local_new(tcg_ctx); + + end = gen_new_label(tcg_ctx); + otherwise = gen_new_label(tcg_ctx); + + + /* Load register contents. */ + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + + /* Check if FPSR.CCn is set (with n=fcbit). */ + gen_get_spr(tcg_ctx, BANK_ID_BASIC_0, FPSR_IDX, fpsr); + tcg_gen_movi_i32(tcg_ctx, res, 1); + tcg_gen_movi_i32(tcg_ctx, final_shift, 24 + fcbit); + tcg_gen_shl_i32(tcg_ctx, res, res, final_shift); + tcg_gen_and_i32(tcg_ctx, res, fpsr, res); + + /* If not set, r2 -> r3. */ + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, res, 0, otherwise); + + /* If set, do the move ! */ + gen_set_gpr(tcg_ctx, rs3, r1); + + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, otherwise); + + gen_set_gpr(tcg_ctx, rs3, r2); + + /* End. */ + gen_set_label(tcg_ctx, end); + + /* Free variables. */ + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, final_shift); + tcg_temp_free(tcg_ctx, res); + tcg_temp_free(tcg_ctx, fpsr); +} + +void fpu_gen_cmpf_s(CPURH850State *env, DisasContext *ctx, int rs1, int rs2, int fcond, int fcbit) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGLabel *handle_nan; + TCGLabel *end; + + end = gen_new_label(tcg_ctx); + handle_nan = gen_new_label(tcg_ctx); + + TCGv r1 = tcg_temp_local_new(tcg_ctx); + TCGv r2 = tcg_temp_local_new(tcg_ctx); + TCGv nan1 = tcg_temp_local_new(tcg_ctx); + TCGv nan2 = tcg_temp_local_new(tcg_ctx); + TCGv less = tcg_temp_local_new(tcg_ctx); + TCGv equal = tcg_temp_local_new(tcg_ctx); + TCGv unordered = tcg_temp_local_new(tcg_ctx); + TCGv res = tcg_temp_local_new(tcg_ctx); + TCGv final_shift = tcg_temp_local_new(tcg_ctx); + TCGv one = tcg_temp_local_new(tcg_ctx); + TCGv mask = tcg_temp_local_new(tcg_ctx); + + tcg_gen_movi_i32(tcg_ctx, one, 1); + + /* Load rs1 and rs2 registers. */ + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + + /* If r1 or r2 is a Nan, then error. */ + gen_helper_f_is_nan_s(tcg_ctx, nan1, tcg_ctx->cpu_env, r1); + gen_helper_f_is_nan_s(tcg_ctx, nan2, tcg_ctx->cpu_env, r2); + tcg_gen_brcond_i32(tcg_ctx, TCG_COND_EQ, nan1, one, handle_nan); + tcg_gen_brcond_i32(tcg_ctx, TCG_COND_EQ, nan2, one, handle_nan); + + gen_helper_flt_s(tcg_ctx, less, tcg_ctx->cpu_env, r2, r1); + gen_helper_feq_s(tcg_ctx, equal, tcg_ctx->cpu_env, r2, r1); + tcg_gen_movi_i32(tcg_ctx, unordered, 0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, handle_nan); + + tcg_gen_movi_i32(tcg_ctx, less, 0); + tcg_gen_movi_i32(tcg_ctx, equal, 0); + tcg_gen_movi_i32(tcg_ctx, unordered, 1); + if (fcond & 0x8) + { + /* Invalid operation detected. */ + /* TODO: raise exception ? */ + } + + /* This is the end =) */ + gen_set_label(tcg_ctx, end); + + /* Compute logical result. */ + tcg_gen_movi_i32(tcg_ctx, res, 0); + if (fcond & 1) + tcg_gen_or_i32(tcg_ctx, res, res, unordered); + if (fcond & 2) + tcg_gen_or_i32(tcg_ctx, res, res, equal); + if (fcond & 4) + tcg_gen_or_i32(tcg_ctx, res, res, less); + + /** + * Set CCn bit into FPSR (with n=fcbit). + * 1. Load FPSR into r1 + * 2. AND r1 with NOT bitmask for CCn + * 3. OR bitmask if res == 1 + * 4. Store r1 into FPSR + **/ + gen_get_spr(tcg_ctx, BANK_ID_BASIC_0, FPSR_IDX, r1); + tcg_gen_movi_i32(tcg_ctx, final_shift, 24 + fcbit); + tcg_gen_shl_i32(tcg_ctx, mask, one, final_shift); + tcg_gen_andc_tl(tcg_ctx, r1, r1, mask); + tcg_gen_shl_i32(tcg_ctx, res, res, final_shift); + tcg_gen_or_i32(tcg_ctx, r1, r1, res); + gen_set_spr(tcg_ctx, BANK_ID_BASIC_0, FPSR_IDX, r1); + + /* Free variables. */ + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, nan1); + tcg_temp_free(tcg_ctx, nan2); + tcg_temp_free(tcg_ctx, less); + tcg_temp_free(tcg_ctx, equal); + tcg_temp_free(tcg_ctx, unordered); + tcg_temp_free(tcg_ctx, final_shift); + tcg_temp_free(tcg_ctx, one); + tcg_temp_free(tcg_ctx, res); +} + + +/** + * Floating-point double-precision IR generators. + **/ + +void fpu_gen_dp_ir_2(CPURH850State *env, DisasContext *ctx, int operands, int op, int rs2, int rs3) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + /* rs1, rs2 and rs3 for TCG */ + TCGv_i64 r2 = tcg_temp_local_new_i64(tcg_ctx); + TCGv_i64 r3 = tcg_temp_local_new_i64(tcg_ctx); + TCGv r3_32 = tcg_temp_local_new_i32(tcg_ctx); + + /* Load contents from registers. */ + switch(operands) + { + case FPU_TYPE_D: + { + /* Extract value from register rs2. */ + fpu_load_i64(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_ABS: + gen_helper_fabs_d(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_NEG: + gen_helper_fneg_d(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_SQRT: + gen_helper_fsqrt_d(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_RECIP: + gen_helper_frecip_d(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_RSQRT: + gen_helper_frsqrt_d(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + } + + /* Store result. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_DL: + { + /* Extract value from register rs2. */ + fpu_load_i64(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_TRNC: + gen_helper_ftrnc_dl(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CEIL: + gen_helper_fceil_dl(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_FLOOR: + gen_helper_ffloor_dl(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CVT: + gen_helper_fcvt_dl(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + } + + /* Store result. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_DUL: + { + /* Extract value from register rs2. */ + fpu_load_i64(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_TRNC: + gen_helper_ftrnc_dul(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CEIL: + gen_helper_fceil_dul(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_FLOOR: + gen_helper_ffloor_dul(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CVT: + gen_helper_fcvt_dul(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + break; + + } + + /* Store result. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + + + case FPU_TYPE_DW: + { + /* Extract value from register rs2. */ + fpu_load_i64(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_TRNC: + gen_helper_ftrnc_dw(tcg_ctx, r3_32, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CEIL: + gen_helper_fceil_dw(tcg_ctx, r3_32, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_FLOOR: + gen_helper_ffloor_dw(tcg_ctx, r3_32, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CVT: + gen_helper_fcvt_dw(tcg_ctx, r3_32, tcg_ctx->cpu_env, r2); + break; + + } + + /* Store result. */ + gen_set_gpr(tcg_ctx, rs3, r3_32); + } + break; + + case FPU_TYPE_DUW: + { + /* Extract value from register rs2. */ + fpu_load_i64(tcg_ctx, r2, rs2); + + /* Apply operation. */ + switch(op) + { + case FPU_OP_TRNC: + gen_helper_ftrnc_duw(tcg_ctx, r3_32, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CEIL: + gen_helper_fceil_duw(tcg_ctx, r3_32, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_FLOOR: + gen_helper_ffloor_duw(tcg_ctx, r3_32, tcg_ctx->cpu_env, r2); + break; + + case FPU_OP_CVT: + gen_helper_fcvt_duw(tcg_ctx, r3_32, tcg_ctx->cpu_env, r2); + break; + + } + + /* Store result. */ + gen_set_gpr(tcg_ctx, rs3, r3_32); + } + break; + + + case FPU_TYPE_LD: + { + /* Load content from register. */ + fpu_load_i64(tcg_ctx, r2, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_ld(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + } + else + { + /* Unsupported operation. */ + } + + /* Store result. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + + + case FPU_TYPE_WD: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r3_32, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_wd(tcg_ctx, r3, tcg_ctx->cpu_env, r3_32); + } + else + { + /* Unsupported operation. */ + } + + /* Store result. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + + + case FPU_TYPE_SD: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r3_32, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_sd(tcg_ctx, r3, tcg_ctx->cpu_env, r3_32); + } + else + { + /* Unsupported operation. */ + } + + /* Store result. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_UWD: + { + /* Extract value of reg1 and reg2. */ + gen_get_gpr(tcg_ctx, r3_32, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_uwd(tcg_ctx, r3, tcg_ctx->cpu_env, r3_32); + } + else + { + /* Unsupported operation. */ + } + + /* Store result. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + + case FPU_TYPE_ULD: + { + /* Load content from register. */ + fpu_load_i64(tcg_ctx, r2, rs2); + + /* Apply operation. */ + if (op == FPU_OP_CVT) + { + gen_helper_fcvt_uld(tcg_ctx, r3, tcg_ctx->cpu_env, r2); + } + else + { + /* Unsupported operation. */ + } + + /* Store result. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + + } + + /* Mov softfloat flags into our register. */ + gen_helper_f_sync_fflags(tcg_ctx, tcg_ctx->cpu_env); + + /* Free temp. */ + tcg_temp_free_i64(tcg_ctx, r2); + tcg_temp_free_i64(tcg_ctx, r3); + tcg_temp_free_i32(tcg_ctx, r3_32); +} + + +void fpu_gen_dp_ir_3(CPURH850State *env, DisasContext *ctx, int operands, int op, int rs1, int rs2, int rs3) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + /* rs1, rs2 and rs3 for TCG */ + TCGv_i64 r1 = tcg_temp_local_new_i64(tcg_ctx); + TCGv_i64 r2 = tcg_temp_local_new_i64(tcg_ctx); + TCGv_i64 r3 = tcg_temp_local_new_i64(tcg_ctx); + + /* Load contents from registers. */ + switch(operands) + { + case FPU_TYPE_D: + { + /* Load float64 values from regpairs designed by rs1 and rs2. */ + fpu_load_i64_2(tcg_ctx, r1, r2, rs1, rs2); + } + break; + } + + switch(op) + { + case FPU_OP_ADD: + gen_helper_fadd_d(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2); + break; + + case FPU_OP_DIV: + gen_helper_fdiv_d(tcg_ctx, r3, tcg_ctx->cpu_env, r2, r1); + break; + + case FPU_OP_SUB: + gen_helper_fsub_d(tcg_ctx, r3, tcg_ctx->cpu_env, r2, r1); + break; + + case FPU_OP_MAX: + gen_helper_fmax_d(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2); + break; + + case FPU_OP_MIN: + gen_helper_fmin_d(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2); + break; + + case FPU_OP_MUL: + gen_helper_fmul_d(tcg_ctx, r3, tcg_ctx->cpu_env, r1, r2); + break; + } + + switch(operands) + { + case FPU_TYPE_D: + { + /* Store result as float64 in regpair designed by rs3. */ + fpu_store_i64(tcg_ctx, rs3, r3); + } + break; + } + + /* Mov softfloat flags into our register. */ + gen_helper_f_sync_fflags(tcg_ctx, tcg_ctx->cpu_env); + + /* Free temp. */ + tcg_temp_free_i64(tcg_ctx, r1); + tcg_temp_free_i64(tcg_ctx, r2); + tcg_temp_free_i64(tcg_ctx, r3); +} + + +void fpu_gen_cmpf_d(CPURH850State *env, DisasContext *ctx, int rs1, int rs2, int fcond, int fcbit) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGLabel *handle_nan; + TCGLabel *end; + + end = gen_new_label(tcg_ctx); + handle_nan = gen_new_label(tcg_ctx); + + TCGv_i64 r1 = tcg_temp_local_new_i64(tcg_ctx); + TCGv_i64 r2 = tcg_temp_local_new_i64(tcg_ctx); + TCGv nan1 = tcg_temp_local_new(tcg_ctx); + TCGv nan2 = tcg_temp_local_new(tcg_ctx); + TCGv less = tcg_temp_local_new(tcg_ctx); + TCGv equal = tcg_temp_local_new(tcg_ctx); + TCGv unordered = tcg_temp_local_new(tcg_ctx); + TCGv res = tcg_temp_local_new(tcg_ctx); + TCGv final_shift = tcg_temp_local_new(tcg_ctx); + TCGv one = tcg_temp_local_new(tcg_ctx); + TCGv mask = tcg_temp_local_new(tcg_ctx); + + tcg_gen_movi_i32(tcg_ctx, one, 1); + + /* Load rs1 and rs2 registers. */ + fpu_load_i64(tcg_ctx, r1, rs1); + fpu_load_i64(tcg_ctx, r2, rs2); + + /* If r1 or r2 is a Nan, then error. */ + gen_helper_f_is_nan_d(tcg_ctx, nan1, tcg_ctx->cpu_env, r1); + gen_helper_f_is_nan_d(tcg_ctx, nan2, tcg_ctx->cpu_env, r2); + tcg_gen_or_i32(tcg_ctx, nan1, nan1, nan2); + tcg_gen_brcond_i32(tcg_ctx, TCG_COND_EQ, nan1, one, handle_nan); + tcg_gen_brcond_i32(tcg_ctx, TCG_COND_EQ, nan2, one, handle_nan); + + gen_helper_flt_d(tcg_ctx, less, tcg_ctx->cpu_env, r2, r1); + gen_helper_feq_d(tcg_ctx, equal, tcg_ctx->cpu_env, r2, r1); + tcg_gen_movi_i32(tcg_ctx, unordered, 0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, handle_nan); + + tcg_gen_movi_i32(tcg_ctx, less, 0); + tcg_gen_movi_i32(tcg_ctx, equal, 0); + tcg_gen_movi_i32(tcg_ctx, unordered, 1); + if (fcond & 0x8) + { + /* Invalid operation detected. */ + /* TODO: raise exception ? */ + } + + /* This is the end =) */ + gen_set_label(tcg_ctx, end); + + /* Set FPSR.CCn */ + tcg_gen_movi_i32(tcg_ctx, res, 0); + if (fcond & 1) + tcg_gen_or_i32(tcg_ctx, res, res, unordered); + if (fcond & 2) + tcg_gen_or_i32(tcg_ctx, res, res, equal); + if (fcond & 4) + tcg_gen_or_i32(tcg_ctx, res, res, less); + + /** + * Set CCn bit into FPSR (with n=fcbit). + * 1. Load FPSR into r1 + * 2. AND r1 with NOT bitmask for CCn + * 3. OR bitmask if res == 1 + * 4. Store r1 into FPSR + **/ + gen_get_spr(tcg_ctx, BANK_ID_BASIC_0, FPSR_IDX, nan1); + tcg_gen_movi_i32(tcg_ctx, final_shift, 24 + fcbit); + tcg_gen_shl_i32(tcg_ctx, mask, one, final_shift); + tcg_gen_andc_tl(tcg_ctx, nan1, nan1, mask); + tcg_gen_shl_i32(tcg_ctx, res, res, final_shift); + tcg_gen_or_i32(tcg_ctx, nan1, nan1, res); + gen_set_spr(tcg_ctx, BANK_ID_BASIC_0, FPSR_IDX, nan1); + + /* Free variables. */ + tcg_temp_free_i64(tcg_ctx, r1); + tcg_temp_free_i64(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, nan1); + tcg_temp_free(tcg_ctx, nan2); + tcg_temp_free(tcg_ctx, less); + tcg_temp_free(tcg_ctx, equal); + tcg_temp_free(tcg_ctx, unordered); + tcg_temp_free(tcg_ctx, final_shift); + tcg_temp_free(tcg_ctx, one); + tcg_temp_free(tcg_ctx, mask); +} + +void fpu_gen_cmov_d(CPURH850State *env, DisasContext *ctx, int rs1, int rs2, int rs3, int fcbit) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGLabel *end, *otherwise; + TCGv_i64 r1 = tcg_temp_local_new_i64(tcg_ctx); + TCGv_i64 r2 = tcg_temp_local_new_i64(tcg_ctx); + TCGv final_shift = tcg_temp_local_new(tcg_ctx); + TCGv res = tcg_temp_local_new(tcg_ctx); + TCGv fpsr = tcg_temp_local_new(tcg_ctx); + + end = gen_new_label(tcg_ctx); + otherwise = gen_new_label(tcg_ctx); + + + /* Load register contents. */ + fpu_load_i64(tcg_ctx, r1, rs1); + fpu_load_i64(tcg_ctx, r2, rs2); + + /* Check if FPSR.CCn is set (with n=fcbit). */ + gen_get_spr(tcg_ctx, BANK_ID_BASIC_0, FPSR_IDX, fpsr); + tcg_gen_movi_i32(tcg_ctx, res, 1); + tcg_gen_movi_i32(tcg_ctx, final_shift, 24 + fcbit); + tcg_gen_shl_i32(tcg_ctx, res, res, final_shift); + tcg_gen_and_i32(tcg_ctx, res, fpsr, res); + + /* If not set, r2 -> r3. */ + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, res, 0, otherwise); + + /* If set, do the move ! */ + fpu_store_i64(tcg_ctx, rs3, r1); + + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, otherwise); + + fpu_store_i64(tcg_ctx, rs3, r2); + + /* End. */ + gen_set_label(tcg_ctx, end); + + /* Free variables. */ + tcg_temp_free_i64(tcg_ctx, r1); + tcg_temp_free_i64(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, final_shift); + tcg_temp_free(tcg_ctx, res); + tcg_temp_free(tcg_ctx, fpsr); +} + + +/** + * Instruction decoding and IR generation. + **/ + +void fpu_decode_cat0_instn(CPURH850State *env, DisasContext *ctx) +{ + int rs1 = GET_RS1(ctx->opcode); + int rs2 = GET_RS2(ctx->opcode); + int rs3 = GET_RS3(ctx->opcode); + + switch(MASK_OP_FORMAT_FI(ctx->opcode)) + { + case OPC_RH850_FPU_GROUP_SW: + switch(rs1) + { + case OPC_RH850_FPU_TRNCF_SW: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SW, FPU_OP_TRNC, rs2, rs3); + break; + + case OPC_RH850_FPU_CEILF_SW: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SW, FPU_OP_CEIL, rs2, rs3); + break; + + case OPC_RH850_FPU_FLOORF_SW: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SW, FPU_OP_FLOOR, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_SW: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SW, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_TRNCF_SUW: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SUW, FPU_OP_TRNC, rs2, rs3); + break; + + case OPC_RH850_FPU_CEILF_SUW: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SUW, FPU_OP_CEIL, rs2, rs3); + break; + + case OPC_RH850_FPU_FLOORF_SUW: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SW, FPU_OP_FLOOR, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_SUW: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SUW, FPU_OP_CVT, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_DS: + switch(rs1) + { + case OPC_RH850_FPU_CVTF_WS: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_WS, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_LS: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_LS, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_HS: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_HS, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_SH: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SH, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_UWS: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_UWS, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_ULS: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_ULS, FPU_OP_CVT, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_SL: + switch(rs1) + { + case OPC_RH850_FPU_TRNCF_SL: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SL, FPU_OP_TRNC, rs2, rs3); + break; + + case OPC_RH850_FPU_CEILF_SL: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SL, FPU_OP_CEIL, rs2, rs3); + break; + + case OPC_RH850_FPU_FLOORF_SL: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SL, FPU_OP_FLOOR, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_SL: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SL, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_TRNCF_SUL: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SUL, FPU_OP_TRNC, rs2, rs3); + break; + + case OPC_RH850_FPU_CEILF_SUL: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SUL, FPU_OP_CEIL, rs2, rs3); + break; + + case OPC_RH850_FPU_FLOORF_SUL: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SUL, FPU_OP_FLOOR, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_SUL: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_SUL, FPU_OP_CVT, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_ABSS: + switch(rs1) + { + case OPC_RH850_FPU_ABSF_S: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_S, FPU_OP_ABS, rs2, rs3); + break; + + case OPC_RH850_FPU_NEGF_S: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_S, FPU_OP_NEG, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_S: + switch(rs1) + { + case OPC_RH850_FPU_SQRTF_S: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_S, FPU_OP_SQRT, rs2, rs3); + break; + + case OPC_RH850_FPU_RECIPF_S: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_S, FPU_OP_RECIP, rs2, rs3); + break; + + case OPC_RH850_FPU_RSQRTF_S: + fpu_gen_sp_ir_2(env, ctx, FPU_TYPE_S, FPU_OP_RSQRT, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_DW: + switch(rs1) + { + case OPC_RH850_FPU_TRNCF_DW: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DW, FPU_OP_TRNC, rs2, rs3); + break; + + case OPC_RH850_FPU_CEILF_DW: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DW, FPU_OP_CEIL, rs2, rs3); + break; + + case OPC_RH850_FPU_FLOORF_DW: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DW, FPU_OP_FLOOR, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_DW: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DW, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_TRNCF_DUW: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DUW, FPU_OP_TRNC, rs2, rs3); + break; + + case OPC_RH850_FPU_CEILF_DUW: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DUW, FPU_OP_CEIL, rs2, rs3); + break; + + case OPC_RH850_FPU_FLOORF_DUW: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DUW, FPU_OP_FLOOR, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_DUW: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DUW, FPU_OP_CVT, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_DD: + switch(rs1) + { + case OPC_RH850_FPU_CVTF_WD: + //fpu_gen_cvtf_wd(env, ctx, rs2, rs3); + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_WD, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_LD: + //fpu_gen_cvtf_ld(env, ctx, rs2, rs3); + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_LD, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_SD: + //fpu_gen_cvtf_sd(env, ctx, rs2, rs3); + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_SD, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_UWD: + //fpu_gen_cvtf_uwd(env, ctx, rs2, rs3); + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_UWD, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_ULD: + //fpu_gen_cvtf_uld(env, ctx, rs2, rs3); + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_ULD, FPU_OP_CVT, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_DL: + switch(rs1) + { + case OPC_RH850_FPU_TRNCF_DL: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DL, FPU_OP_TRNC, rs2, rs3); + break; + + case OPC_RH850_FPU_CEILF_DL: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DL, FPU_OP_CEIL, rs2, rs3); + break; + + case OPC_RH850_FPU_FLOORF_DL: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DL, FPU_OP_FLOOR, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_DL: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DL, FPU_OP_CVT, rs2, rs3); + break; + + case OPC_RH850_FPU_TRNCF_DUL: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DUL, FPU_OP_TRNC, rs2, rs3); + break; + + case OPC_RH850_FPU_CEILF_DUL: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DUL, FPU_OP_CEIL, rs2, rs3); + break; + + case OPC_RH850_FPU_FLOORF_DUL: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DUL, FPU_OP_FLOOR, rs2, rs3); + break; + + case OPC_RH850_FPU_CVTF_DUL: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_DUL, FPU_OP_CVT, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_ABSD: + switch(rs1) + { + case OPC_RH850_FPU_ABSF_D: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_D, FPU_OP_ABS, rs2, rs3); + break; + + case OPC_RH850_FPU_NEGF_D: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_D, FPU_OP_NEG, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_GROUP_D: + switch(rs1) + { + case OPC_RH850_FPU_SQRTF_D: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_D, FPU_OP_SQRT, rs2, rs3); + break; + + case OPC_RH850_FPU_RECIPF_D: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_D, FPU_OP_RECIP, rs2, rs3); + break; + + case OPC_RH850_FPU_RSQRTF_D: + fpu_gen_dp_ir_2(env, ctx, FPU_TYPE_D, FPU_OP_RSQRT, rs2, rs3); + break; + } + break; + + case OPC_RH850_FPU_ADDF_S: + fpu_gen_sp_ir_3(env, ctx, FPU_TYPE_S, FPU_OP_ADD, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_ADDF_D: + /* rs1, rs2 and rs3 must have bit 0 set to 0. */ + if ((rs1 & 1) || (rs2 & 1) || (rs3 & 1)) + { + /* TODO: Invalid instruction, must trigger exception. */ + } + else + fpu_gen_dp_ir_3(env, ctx, FPU_TYPE_D, FPU_OP_ADD, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_SUBF_S: + fpu_gen_sp_ir_3(env, ctx, FPU_TYPE_S, FPU_OP_SUB, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_SUBF_D: + fpu_gen_dp_ir_3(env, ctx, FPU_TYPE_D, FPU_OP_SUB, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_MULF_S: + fpu_gen_sp_ir_3(env, ctx, FPU_TYPE_S, FPU_OP_MUL, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_MULF_D: + fpu_gen_dp_ir_3(env, ctx, FPU_TYPE_D, FPU_OP_MUL, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_MAXF_S: + fpu_gen_sp_ir_3(env, ctx, FPU_TYPE_S, FPU_OP_MAX, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_MAXF_D: + fpu_gen_dp_ir_3(env, ctx, FPU_TYPE_D, FPU_OP_MAX, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_MINF_S: + fpu_gen_sp_ir_3(env, ctx, FPU_TYPE_S, FPU_OP_MIN, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_MINF_D: + fpu_gen_dp_ir_3(env, ctx, FPU_TYPE_D, FPU_OP_MIN, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_DIVF_S: + fpu_gen_sp_ir_3(env, ctx, FPU_TYPE_S, FPU_OP_DIV, rs1, rs2, rs3); + break; + + case OPC_RH850_FPU_DIVF_D: + fpu_gen_dp_ir_3(env, ctx, FPU_TYPE_D, FPU_OP_DIV, rs1, rs2, rs3); + break; + + + default: + switch(ctx->opcode & (0x70 << 16)) + { + case OPC_RH850_FPU_CMOV_S_OR_TRFSR: + + /* If reg1==reg2==reg3==0, then it is a TRSFR instruction. */ + if ((rs1 == 0) && (rs2 == 0) && (rs3 == 0)) + { + fpu_gen_trfsr(env, ctx, (ctx->opcode & (0xe << 16))>>17 ); + } + else + { + /* Call generator with fcbit. */ + fpu_gen_cmov_s(env, ctx, rs1, rs2, rs3, (ctx->opcode & (0xe << 16))>>17 ); + } + break; + + case OPC_RH850_FPU_CMOV_D: + /* Call generator with fcbit. */ + fpu_gen_cmov_d(env, ctx, rs1, rs2, rs3, (ctx->opcode & (0xe << 16))>>17 ); + break; + + case OPC_RH850_FPU_CMP_S: + /* Call generator with fcond (rs3) and fcbit. */ + fpu_gen_cmpf_s(env, ctx, rs1, rs2, rs3, (ctx->opcode & (0xe << 16))>>17 ); + break; + + case OPC_RH850_FPU_CMP_D: + /* Call generator with fcond (rs3) and fcbit. */ + fpu_gen_cmpf_d(env, ctx, rs1, rs2, rs3, (ctx->opcode & (0xe << 16))>>17 ); + break; + + default: + /* Unknown inst. */ + break; + } + break; + } +} + +void fpu_decode_cat1_instn(CPURH850State *env, DisasContext *ctx) +{ + int rs1 = GET_RS1(ctx->opcode); + int rs2 = GET_RS2(ctx->opcode); + int rs3 = GET_RS3(ctx->opcode); + + fpu_gen_cat1_ir(env, ctx, MASK_OP_FORMAT_FI(ctx->opcode), rs1, rs2, rs3); +} + +/** + * Initialize FPU. + **/ + +void rh850_fpu_translate_init(void) +{ +} \ No newline at end of file diff --git a/qemu/target/rh850/fpu_translate.h b/qemu/target/rh850/fpu_translate.h new file mode 100644 index 0000000000..b21af6759f --- /dev/null +++ b/qemu/target/rh850/fpu_translate.h @@ -0,0 +1,41 @@ +/* + * QEMU RH850 CPU + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2017-2018 SiFive, Inc. + * + * 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/>. + */ + +#ifndef RH850_FPU_H +#define RH850_FPU_H + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "tcg/tcg-op.h" +#include "translate.h" +#include "fpu_translate.h" +#include "exec/cpu_ldst.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "exec/translator.h" +#include "translate.h" + +void fpu_decode_cat0_instn(CPURH850State *env, DisasContext *ctx); +void fpu_decode_cat1_instn(CPURH850State *env, DisasContext *ctx); +void fpu_init(CPURH850State *env); +void rh850_fpu_translate_init(void); + +#endif /* RH850_FPU_H */ \ No newline at end of file diff --git a/qemu/target/rh850/gdbstub.c b/qemu/target/rh850/gdbstub.c new file mode 100644 index 0000000000..2abc97fb64 --- /dev/null +++ b/qemu/target/rh850/gdbstub.c @@ -0,0 +1,169 @@ +/* + * RH850 GDB Server Stub + * + * Copyright (c) 2019-2020 Marko Klopcic, iSYSTEM Labs + * + * 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/>. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" +#include "cpu.h" + +/* Mapping of winIDEA register index to env->sysBasicRegs() index. (see mail + * from Matic 2019-05-06 and isystem/doc/v850-tdep.c) + QEMU idx wI idx + 32, // eipc 0 + 33, // eipsw 1 + 34, // fepc 2 + 35, // fepsw 3 + 37, // psw 4 + 128, // fpsr 5 + 129, // fpepc 6 + 130, // fpst 7 + 131, // fpcc 8 + 132, // fpcfg 9 + 133, // fpec 10 + 44, // SESR N/A + 45, // EIIC 11 + 46, // FEIC 12 + 48, // CTPC 13 + 49, // CTPSW 14 + 52, // CTBP 15 + 60, // EIWR 16 + 61, // FEWR 17 + 63, // BSEL 18 + 150, // mcfg0 19 + 152, // RBASE 20 + 153, // EBASE 21 + 154, // intbp 22 + 155, // mctl 23 + 156, // pid 24 + 161, // sccfg 25 + 162, // scbp 26 + 182, // htcfg0 27 + 188, // mea 28 + 189, // asid 29 + 190 // mei 30 +*/ +#define BANK_MASK 0xf0000 +#define BANK_SHIFT 16 +#define SRI(selID, regID) (((selID) << BANK_SHIFT) | (regID)) +#define SRI0(regID) (regID) +#define SRI1(regID) SRI(1, (regID)) +#define SRI2(regID) SRI(2, (regID)) + +typedef int IdxType; +const IdxType winIdeaRegIdx2qemuSysRegIdx[] = { +// 0 1 2 3 4 5 6 7 8 9 +// --------------------------------------------- +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0 +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1 +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2 + +-1, -1, SRI0(EIPC_IDX), SRI0(EIPSW_IDX),SRI0(FEPC_IDX),SRI0(FEPSW_IDX),-1, SRI0(PSW_IDX), -1, -1, // 3 +-1, -1, -1, -1, -1, SRI0(EIIC_IDX),SRI0(FEIC_IDX),-1,SRI0(CTPC_IDX),SRI0(CTPSW_IDX), // 4 +-1, -1, SRI0(CTBP_IDX), -1, -1, -1, -1, -1, -1, -1, // 5 + +SRI0(EIWR_IDX),SRI0(FEWR_IDX),-1,SRI0(BSEL_IDX), -1, -1, -1, -1, -1, -1, // 6 +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7 +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 8 + +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 9 +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10 +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 11 + +-1, -1, -1, -1, -1, -1, -1, -1, SRI0(FPSR_IDX), SRI0(FEPC_IDX), // 12 +SRI0(FPST_IDX),SRI0(FPCC_IDX),SRI0(FPCFG_IDX),SRI0(FPEC_IDX), -1,-1, -1, -1, -1, -1, // 13 +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 14 + +SRI1(MCFG0_IDX1),-1,SRI1(RBASE_IDX1),SRI1(EBASE_IDX1),SRI1(INTBP_IDX1),SRI1(MCTL_IDX1),SRI1(PID_IDX1),-1,-1, -1, // 15 +-1, SRI1(SCCFG_IDX1), SRI1(SCBP_IDX1), -1, -1, -1, -1, -1, -1, -1, // 16 +-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 17 + +-1, -1,SRI2(HTCFG0_IDX2), -1, -1, -1, -1, -1,SRI2(MEA_IDX2),SRI2(ASID_IDX2), // 18 +SRI2(MEI_IDX2), -1, -1, -1, -1, -1, -1, -1, -1, -1, // 19 +}; + +const int NUM_GDB_REGS = sizeof(winIdeaRegIdx2qemuSysRegIdx) / sizeof(IdxType); + +int rh850_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + + if (n < 32) { + return gdb_get_regl(mem_buf, env->gpRegs[n]); //gpr is now supposed to be progRegs + } else if (n == 64) { + return gdb_get_regl(mem_buf, env->pc); + } else if (n < NUM_GDB_REGS) { + int sysRegIdx = winIdeaRegIdx2qemuSysRegIdx[n]; + if (sysRegIdx >= 0) { + int selID = sysRegIdx >> BANK_SHIFT; + int regID = sysRegIdx & ~BANK_MASK; + if (selID == BANK_ID_BASIC_0 && regID == PSW_IDX) { + int psw = env->Z_flag | (env->S_flag << 1) | (env->OV_flag << 2) | (env->CY_flag << 3); + psw |= (env->SAT_flag << 4) | (env->ID_flag << 5) | (env->EP_flag << 6); + psw |= (env->NP_flag << 7) | (env->EBV_flag << 15) | (env->CU0_flag << 16); + psw |= (env->CU1_flag << 17) | (env->CU2_flag << 18) | (env->UM_flag << 30); + return gdb_get_regl(mem_buf, psw); + } else { + return gdb_get_regl(mem_buf, env->systemRegs[selID][regID]); // eipc, eipsw, fepc, fepsw, psw, ... + } + } + } + + *((uint32_t *)mem_buf) = 0xBAD0BAD0; + return 4; // registers in slots not set above are ignored +} + +int rh850_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + // at the moment our GDB server has different indices for writing single register + // will fix this if batch write will have to be supported or interfacing + // to other GDB servers for RH850 will be needed. + if (n > 0 && n < 32) { // skip R0, because it is always 0 + env->gpRegs[n] = ldtul_p(mem_buf); + } else if (n == 64) { + env->pc = ldtul_p(mem_buf); + } else if (n < NUM_GDB_REGS) { + int sysRegIdx = winIdeaRegIdx2qemuSysRegIdx[n]; + if (sysRegIdx >= 0) { + int selID = sysRegIdx >> BANK_SHIFT; + int regID = sysRegIdx & ~BANK_MASK; + if (selID == BANK_ID_BASIC_0 && regID == PSW_IDX) { + int psw = ldtul_p(mem_buf); + env->Z_flag = psw & 1; + env->S_flag = (psw >> 1) & 1; + env->OV_flag = (psw >> 2) & 1; + env->CY_flag = (psw >> 3) & 1; + env->SAT_flag = (psw >> 4) & 1; + env->ID_flag = (psw >> 5) & 1; + env->EP_flag = (psw >> 6) & 1; + env->NP_flag = (psw >> 7) & 1; + env->EBV_flag = (psw >> 15) & 1; + env->CU0_flag = (psw >> 16) & 1; + env->CU1_flag = (psw >> 17) & 1; + env->CU2_flag = (psw >> 18) & 1; + env->UM_flag = (psw >> 30) & 1; + } else { + env->systemRegs[selID][regID] = ldtul_p(mem_buf); // eipc, eipsw, fepc, fepsw, psw, ... + } + } + } + + return sizeof(target_ulong); +} diff --git a/qemu/target/rh850/helper.c b/qemu/target/rh850/helper.c new file mode 100644 index 0000000000..ee171f0dbb --- /dev/null +++ b/qemu/target/rh850/helper.c @@ -0,0 +1,539 @@ +/* + * RH850 emulation helpers for qemu. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2017-2018 SiFive, Inc. + * Copyright (c) 2018-2019 iSYSTEM Labs d.o.o. + * + * 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/>. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "exec/exec-all.h" + +#define RH850_DEBUG_INTERRUPT 0 + +int rh850_cpu_mmu_index(CPURH850State *env, bool ifetch) +{ + return 0; +} + +#ifndef CONFIG_USER_ONLY +/* + * Return RH850 IRQ number if an interrupt should be taken, else -1. + * Used in cpu-exec.c + * + * Adapted from Spike's processor_t::take_interrupt() + */ + +#if 0 /* Not used */ +static int rh850_cpu_hw_interrupts_pending(CPURH850State *env) +{ + + return EXCP_NONE; +} +#endif +#endif + +uint32_t psw2int(CPURH850State * env); +uint32_t mem_deref_4(CPUState * cs, uint32_t addr); + + +uint32_t psw2int(CPURH850State * env) +{ + uint32_t ret = 0; + ret |= env->UM_flag<<30; + ret |= env->CU0_flag<<16; + ret |= env->CU1_flag<<17; + ret |= env->CU2_flag<<18; + ret |= env->EBV_flag<<15; + ret |= env->NP_flag<<7; + ret |= env->EP_flag<<6; + ret |= env->ID_flag<<5; + ret |= env->SAT_flag<<4; + ret |= env->CY_flag<<3; + ret |= env->OV_flag<<2; + ret |= env->S_flag<<1; + ret |= env->Z_flag; + + return ret; +} + +/* + * RH850 interrupt handler. + **/ + +bool rh850_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ +#if !defined(CONFIG_USER_ONLY) + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + + //qemu_log("[cpu] exec_interrupt: got interrupt_req=%08x\n", interrupt_request); + + /* Handle FENMI interrupt. */ + if (interrupt_request == RH850_INT_FENMI) + { + /* Set exception info. */ + cs->exception_index = RH850_EXCP_FENMI; + env->exception_cause = 0xE0; + env->exception_priority = 1; + + /* Acknowledge interrupt. */ + rh850_cpu_do_interrupt(cs); + } + else if (interrupt_request == RH850_INT_FEINT) + { + if (!(env->systemRegs[BANK_ID_BASIC_2][PMR_IDX2] & (1<<env->exception_priority))) + { + /* Set exception info. */ + cs->exception_index = RH850_EXCP_FEINT; + env->exception_cause = 0xF0; + env->exception_priority = 3; + + /* Acknowledge interrupt. */ + rh850_cpu_do_interrupt(cs); + } + } + else if (interrupt_request == RH850_EXCP_EIINT) + { + //qemu_log("exec_interrupt got RH850_EXCP_EIINT\n"); + + /* Get interrupt request number. */ + //int intn = env->exception_cause & 0xfff; + int priority = 4; + + //qemu_log("[cpu] exec_interrupt: got interrupt_req=%08x\n", interrupt_request); + + /* Check if interrupt priority is not masked (through PMR). */ + if (!(env->systemRegs[BANK_ID_BASIC_2][PMR_IDX2] & (1<<priority))) + { + /** + * Interrupt is not masked, process it. + * We set the exception index to RH850_EXCP_EIINT to notify an EIINT interrupt, + * and we set the exception cause to indicate the channel. + **/ + + /* Set exception info. */ + cs->exception_index = RH850_EXCP_EIINT; + //env->exception_cause = 0x1000 | (intn); + //env->exception_dv = !(interrupt_request & RH850_INT_TAB_REF); + env->exception_priority = priority; + + /* Acknowledge interrupt. */ + rh850_cpu_do_interrupt(cs); + } + else + { + //qemu_log("[cpu] interrupt priority is masked\n"); + } + } +#endif + + /* Interrupt request has been processed. */ + cs->interrupt_request = 0; + return false; +} + +#if !defined(CONFIG_USER_ONLY) + + +static int get_physical_address(CPURH850State *env, hwaddr *physical, + int *prot, target_ulong addr, + int access_type, int mmu_idx) +{ + + /* + * There is no memory virtualization in RH850 (at least for the targeted SoC) + * Address resolution is straightforward + */ + *physical = addr; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return TRANSLATE_SUCCESS; + +} + +static void raise_mmu_exception(CPURH850State *env, target_ulong address, + MMUAccessType access_type) +{ + CPUState *cs = CPU(rh850_env_get_cpu(env)); + int page_fault_exceptions = RH850_EXCP_INST_PAGE_FAULT; + switch (access_type) { + case MMU_INST_FETCH: + cs->exception_index = page_fault_exceptions ? + RH850_EXCP_INST_PAGE_FAULT : RH850_EXCP_INST_ACCESS_FAULT; + break; + case MMU_DATA_LOAD: + cs->exception_index = page_fault_exceptions ? + RH850_EXCP_LOAD_PAGE_FAULT : RH850_EXCP_LOAD_ACCESS_FAULT; + break; + case MMU_DATA_STORE: + cs->exception_index = page_fault_exceptions ? + RH850_EXCP_STORE_PAGE_FAULT : RH850_EXCP_STORE_AMO_ACCESS_FAULT; + break; + default: + g_assert_not_reached(); + } + env->badaddr = address; +} + +hwaddr rh850_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + RH850CPU *cpu = RH850_CPU(cs); + hwaddr phys_addr; + int prot; + int mmu_idx = cpu_mmu_index(&cpu->env, false); + + if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) { + return -1; + } + return phys_addr; +} + +void rh850_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, int mmu_idx, + uintptr_t retaddr) +{ + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + switch (access_type) { + case MMU_INST_FETCH: + cs->exception_index = RH850_EXCP_INST_ADDR_MIS; + break; + case MMU_DATA_LOAD: + cs->exception_index = RH850_EXCP_LOAD_ADDR_MIS; + break; + case MMU_DATA_STORE: + cs->exception_index = RH850_EXCP_STORE_AMO_ADDR_MIS; + break; + default: + g_assert_not_reached(); + } + env->badaddr = addr; + //qemu_log_mask(CPU_LOG_INT, "%s\n", __func__); + do_raise_exception_err(env, cs->exception_index, retaddr); +} + +#endif + +int rh850_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, + int rw, int mmu_idx) +{ + + + /* + * TODO: Add check to system register concerning MPU configuratuon MPLA, MPUA + * + */ + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; +#if !defined(CONFIG_USER_ONLY) + hwaddr pa = 0; + int prot; +#endif + int ret = TRANSLATE_FAIL; + qemu_log_mask(CPU_LOG_MMU, + "%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx \ + %d\n", __func__, env->pc, address, rw, mmu_idx); + +#if !defined(CONFIG_USER_ONLY) + + ret = get_physical_address(env, &pa, &prot, address, rw, mmu_idx); + qemu_log_mask(CPU_LOG_MMU, + "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx + " prot %d\n", __func__, address, ret, pa, prot); + if (ret == TRANSLATE_SUCCESS) { + tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK, + prot, mmu_idx, TARGET_PAGE_SIZE); + } else if (ret == TRANSLATE_FAIL) { + raise_mmu_exception(env, address, rw); + } +#else + switch (rw) { + case MMU_INST_FETCH: + cs->exception_index = RH850_EXCP_INST_PAGE_FAULT; + break; + case MMU_DATA_LOAD: + cs->exception_index = RH850_EXCP_LOAD_PAGE_FAULT; + break; + case MMU_DATA_STORE: + cs->exception_index = RH850_EXCP_STORE_PAGE_FAULT; + break; + } +#endif + return ret; +} + + +uint32_t mem_deref_4(CPUState * cs, uint32_t addr){ + uint8_t * buf = g_malloc(4); + uint32_t ret_dword = 0; + cpu_memory_rw_debug(cs, addr, buf, 4, false); + + ret_dword |= buf[3] << 24; + ret_dword |= buf[2] << 16; + ret_dword |= buf[1] << 8; + ret_dword |= buf[0]; + g_free(buf); + return ret_dword; +} + + +void rh850_cpu_do_interrupt(CPUState *cs) +{ + + //qemu_log("[cpu] rh850_cpu_do_interrupt()\n"); + //qemu_log_mask(CPU_LOG_INT, "%s\n", __func__); +#if !defined(CONFIG_USER_ONLY) + uint32_t intbp; + RH850CPU *cpu = RH850_CPU(cs); + CPURH850State *env = &cpu->env; + + uint32_t direct_vector_ba; + qemu_log_mask(CPU_LOG_INT, "%s: entering switch\n", __func__); + switch (cs->exception_index) { + case RH850_EXCP_FETRAP: + + qemu_log_mask(CPU_LOG_INT, "%s: entering FETRAP handler\n", __func__); + // store PSW to FEPSW (and update env->EBV_flag) + env->systemRegs[BANK_ID_BASIC_0][FEPSW_IDX] = psw2int(env); + // store PC to FEPC + env->systemRegs[BANK_ID_BASIC_0][FEPC_IDX] = env->pc+2; + // Set Exception Cause + env->systemRegs[BANK_ID_BASIC_0][FEIC_IDX] = env->exception_cause; + + qemu_log_mask(CPU_LOG_INT, "%s, saved pc : %x\n", __func__,env->pc); + + // update PSW + env->UM_flag = 0; + env->NP_flag = 1; + env->EP_flag = 1; + env->ID_flag = 1; + + // modify PC, keep RBASE or EBASE bits 9 to 31 (discard bits 0 to 8) + if (env->EBV_flag) + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][EBASE_IDX1] & 0xFFFFFE00; + else + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][RBASE_IDX1] & 0xFFFFFE00; + + qemu_log_mask(CPU_LOG_INT, "%s: direct vector addr : %x \n", __func__,direct_vector_ba); + env->pc = direct_vector_ba + 0x30; + break; + + case RH850_EXCP_TRAP: + qemu_log_mask(CPU_LOG_INT, "%s: entering TRAP handler\n", __func__); + // store PSW to EIPSW + env->systemRegs[BANK_ID_BASIC_0][EIPSW_IDX] = psw2int(env); + // store PC to EIPC + env->systemRegs[BANK_ID_BASIC_0][EIPC_IDX] = env->pc+4; + // Set Exception Cause + env->systemRegs[BANK_ID_BASIC_0][EIIC_IDX] = env->exception_cause; + + env->UM_flag = 0; + env->EP_flag = 1; + env->ID_flag = 1; + + // modify PC, keep RBASE or EBASE bits 9 to 31 (discard bits 0 to 8) + if (env->EBV_flag) + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][EBASE_IDX1] & 0xFFFFFE00; + else + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][RBASE_IDX1] & 0xFFFFFE00; + + if (env->exception_cause < 0x50) { + env->pc = direct_vector_ba + 0x40; + } else { + env->pc = direct_vector_ba + 0x50; + } + break; + + case RH850_EXCP_RIE: + //qemu_log("%s: entering RIE handler\n", __func__); + // store PSW to FEPSW + env->systemRegs[BANK_ID_BASIC_0][FEPSW_IDX] = psw2int(env); + // store PC to FEPC + env->systemRegs[BANK_ID_BASIC_0][FEPC_IDX] = env->pc; + // Set Exception Cause + env->systemRegs[BANK_ID_BASIC_0][FEIC_IDX] = env->exception_cause; + //qemu_log("%s, saved pc : %x\n", __func__,env->pc); + // update PSW + + env->UM_flag = 0; + env->NP_flag = 1; + env->EP_flag = 1; + env->ID_flag = 1; + + // modify PC, keep RBASE or EBASE bits 9 to 31 (discard bits 0 to 8) + if (env->EBV_flag) + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][EBASE_IDX1] & 0xFFFFFE00; + else + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][RBASE_IDX1] & 0xFFFFFE00; + + //qemu_log("%s: direct vector addr : %x \n", __func__,direct_vector_ba); + env->pc = direct_vector_ba + 0x60; + //qemu_log("%s: pc : 0x%08x \n", __func__, direct_vector_ba+0x60); + break; + + case RH850_EXCP_SYSCALL: + qemu_log_mask(CPU_LOG_INT, "%s: entering SYSCALL handler\n", __func__); + uint32_t syscall_cfg = env->systemRegs[BANK_ID_BASIC_1][SCCFG_IDX1] & 0xff; + uint32_t syscall_number = env->exception_cause - 0x8000; + uint32_t syscall_bp = env->systemRegs[BANK_ID_BASIC_1][SCBP_IDX1]; + uint32_t handler_offset=0, deref_addr=0; + + if (syscall_number <= syscall_cfg) { + deref_addr = syscall_bp + (syscall_number<<2); + } else { + + deref_addr = syscall_bp; + } + + qemu_log_mask(CPU_LOG_INT, "%s syscall_cfg_size = %d\n", __func__,syscall_cfg); + qemu_log_mask(CPU_LOG_INT, "%s syscall_bp = %d\n", __func__,syscall_bp); + qemu_log_mask(CPU_LOG_INT, "%s syscall_num = %d\n", __func__,syscall_number); + qemu_log_mask(CPU_LOG_INT, "%s deref_addr = 0x%x\n", __func__,deref_addr); + handler_offset = mem_deref_4(cs,deref_addr); + qemu_log_mask(CPU_LOG_INT, "%s handler offset = %x\n", __func__,handler_offset); + + // store PSW to EIPSW + env->systemRegs[BANK_ID_BASIC_0][EIPSW_IDX] = psw2int(env); + // store PC to EIPC + env->systemRegs[BANK_ID_BASIC_0][EIPC_IDX] = env->pc+4; + // Set Exception Cause + env->systemRegs[BANK_ID_BASIC_0][EIIC_IDX] = env->exception_cause; + + env->UM_flag = 0; + env->EP_flag = 1; + env->ID_flag = 1; + + // modify PC + env->pc = syscall_bp + handler_offset; + qemu_log_mask(CPU_LOG_INT, "%s: moving pc to = 0x%x\n", __func__,env->pc); + + break; + + case RH850_EXCP_FEINT: + //qemu_log("[cpu] entering FEINT handler\n"); + // store PSW to FEPSW + env->systemRegs[BANK_ID_BASIC_0][FEPSW_IDX] = psw2int(env); + // store PC to FEPC + env->systemRegs[BANK_ID_BASIC_0][FEPC_IDX] = env->pc; + // Set Exception Cause + env->systemRegs[BANK_ID_BASIC_0][FEIC_IDX] = env->exception_cause; + + /* Update PSW. */ + env->UM_flag = 0; + env->ID_flag = 1; + env->NP_flag = 1; + env->EP_flag = 0; + + /* Direct vector. */ + if (env->EBV_flag) + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][EBASE_IDX1]; + else + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][RBASE_IDX1]; + + /* Redirect to FEINT exception handler. */ + env->pc = (direct_vector_ba & 0xFFFFFF00) + 0xF0; + //qemu_log("%s: moving pc to = 0x%x\n", __func__,env->pc); + break; + + case RH850_EXCP_FENMI: + //qemu_log("[cpu] entering FENMI handler\n"); + // store PSW to FEPSW + env->systemRegs[BANK_ID_BASIC_0][FEPSW_IDX] = psw2int(env); + // store PC to FEPC + env->systemRegs[BANK_ID_BASIC_0][FEPC_IDX] = env->pc; + // Set Exception Cause + env->systemRegs[BANK_ID_BASIC_0][FEIC_IDX] = env->exception_cause; + + /* Update PSW. */ + env->UM_flag = 0; + env->ID_flag = 1; + env->NP_flag = 1; + env->EP_flag = 0; + + /* Direct vector. */ + if (env->EBV_flag) + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][EBASE_IDX1]; + else + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][RBASE_IDX1]; + + /* Redirect to FENMI exception handler. */ + env->pc = (direct_vector_ba & 0xFFFFFF00) + 0xE0; + break; + + case RH850_EXCP_EIINT: + //qemu_log("[cpu] entering EIINT handler\n"); + //qemu_log_mask(CPU_LOG_INT, "%s: entering EIINT handler\n", __func__); + + // store PSW to EIPSW + env->systemRegs[BANK_ID_BASIC_0][EIPSW_IDX] = psw2int(env); + // store PC to EIPC + env->systemRegs[BANK_ID_BASIC_0][EIPC_IDX] = env->pc; + // Set Exception Cause + env->systemRegs[BANK_ID_BASIC_0][EIIC_IDX] = env->exception_cause; + // Set priority to ISPR + env->systemRegs[BANK_ID_BASIC_2][ISPR_IDX2] |= (1 << env->exception_priority); + + /* Set PSW.ID (disable further EI exceptions). */ + env->ID_flag = 1; + + /* Clear PSW.EP (we are processing an interrupt). */ + env->EP_flag = 0; + + /* Modify PC based on dispatch method (direct vector or table reference). */ + if (!env->exception_dv) + { + //qemu_log("[cpu] dispatch EIINT (table reference) for IRQ %d\n", env->exception_cause&0x1ff); + /* Table reference, first read INTBP value. */ + intbp = env->systemRegs[BANK_ID_BASIC_1][INTBP_IDX1]; + //qemu_log("[cpu] INTBP=0x%08x\n", intbp); + + /* Compute address of interrupt handler (based on channel). */ + env->pc = mem_deref_4(cs, intbp + 4*(env->exception_cause & 0x1ff)); + //qemu_log("[cpu] PC=0x%08x\n", env->pc); + } + else + { + //qemu_log("[cpu] dispatch EIINT (direct vector) for IRQ %d\n", env->exception_cause&0x1ff); + //qemu_log("[cpu] exception priority=%d\n", env->exception_priority); + /* Direct vector. */ + if (env->EBV_flag) + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][EBASE_IDX1]; + else + direct_vector_ba = env->systemRegs[BANK_ID_BASIC_1][RBASE_IDX1]; + //qemu_log("[cpu] Direct vector Base Address = 0x%08x\n", direct_vector_ba); + + /* Is RINT bit set ? */ + if (direct_vector_ba & 1) + { + //qemu_log("[cpu] RINT bit set\n"); + /* Reduced vector (one handler for any priority). */ + env->pc = (direct_vector_ba & 0xFFFFFF00) + 0x100; + } + else + { + //qemu_log("[cpu] RINT bit NOT set\n"); + /* One handler per priority level. */ + env->pc = (direct_vector_ba & 0xFFFFFF00) + 0x100 + (env->exception_priority<<4); + } + //qemu_log("[cpu] PC=0x%08x\n", env->pc); + } + break; + } + +#endif + cs->exception_index = EXCP_NONE; /* mark handled to qemu */ +} diff --git a/qemu/target/rh850/helper.h b/qemu/target/rh850/helper.h new file mode 100644 index 0000000000..24c9fa5865 --- /dev/null +++ b/qemu/target/rh850/helper.h @@ -0,0 +1,157 @@ +DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64) +DEF_HELPER_6(uc_traceopcode, void, ptr, i64, i64, i32, ptr, i64) +DEF_HELPER_1(uc_rh850_exit, void, env) + +/* Exceptions */ +DEF_HELPER_2(raise_exception, noreturn, env, i32) +DEF_HELPER_3(raise_exception_with_cause, noreturn, env, i32, i32) + + +/* Floating Point - rounding mode */ +DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_WG, void, env, i32) + +/* Floating Point - fused */ +DEF_HELPER_FLAGS_4(fmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fnmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fnmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fnmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(fnmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) + +/* Floating Point - Single Precision */ +DEF_HELPER_FLAGS_2(f32_is_normal, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(f32_is_zero_or_normal, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(f32_is_infinity, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_1(f_sync_fflags, TCG_CALL_NO_RWG, void, env) + +DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fmul_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_2(fabs_s, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fneg_s, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(ftrnc_sw, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fceil_sw, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(ffloor_sw, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fcvt_sw, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(ftrnc_suw, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fceil_suw, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(ffloor_suw, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fcvt_suw, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fcvt_ws, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fcvt_ls, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(fcvt_hs, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fcvt_sh, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fcvt_uws, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(fcvt_uls, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(ftrnc_sl, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fceil_sl, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(ffloor_sl, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fcvt_sl, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(ftrnc_sul, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fceil_sul, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(ffloor_sul, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fcvt_sul, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(frecip_s, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(frsqrt_s, TCG_CALL_NO_RWG, i32, env, i32) + +DEF_HELPER_FLAGS_2(f_is_nan_s, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_3(fle_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_2(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64) +DEF_HELPER_FLAGS_2(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64) + +DEF_HELPER_FLAGS_4(fmaf_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32) +DEF_HELPER_FLAGS_4(fmsf_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32) +DEF_HELPER_FLAGS_4(fnmaf_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32) +DEF_HELPER_FLAGS_4(fnmsf_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32) + + + + +#if defined(TARGET_RH85064) +DEF_HELPER_FLAGS_2(fcvt_l_s, TCG_CALL_NO_RWG, tl, env, i64) +DEF_HELPER_FLAGS_2(fcvt_lu_s, TCG_CALL_NO_RWG, tl, env, i64) +#endif +DEF_HELPER_FLAGS_2(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl) +DEF_HELPER_FLAGS_2(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl) +#if defined(TARGET_RH85064) +DEF_HELPER_FLAGS_2(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, tl) +DEF_HELPER_FLAGS_2(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, tl) +#endif +DEF_HELPER_FLAGS_1(fclass_s, TCG_CALL_NO_RWG_SE, tl, i64) + +/* Floating Point - Double Precision */ +DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmul_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(fabs_d, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fneg_d, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_2(ftrnc_dw, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(fceil_dw, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(ffloor_dw, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(fcvt_dw, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(ftrnc_duw, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(fceil_duw, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(ffloor_duw, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(fcvt_duw, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_2(fcvt_wd, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fcvt_ld, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_sd, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fcvt_uwd, TCG_CALL_NO_RWG, i64, env, i32) +DEF_HELPER_FLAGS_2(fcvt_uld, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(ftrnc_dl, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fceil_dl, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(ffloor_dl, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_dl, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(ftrnc_dul, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fceil_dul, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(ffloor_dul, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_dul, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(frecip_d, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(frsqrt_d, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_FLAGS_2(f_is_nan_d, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_FLAGS_3(fle_d, TCG_CALL_NO_RWG, i32, env, i64, i64) +DEF_HELPER_FLAGS_3(flt_d, TCG_CALL_NO_RWG, i32, env, i64, i64) +DEF_HELPER_FLAGS_3(feq_d, TCG_CALL_NO_RWG, i32, env, i64, i64) + + + +DEF_HELPER_FLAGS_2(fcvt_s_d, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_d_s, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_w_d, TCG_CALL_NO_RWG, tl, env, i64) +DEF_HELPER_FLAGS_2(fcvt_wu_d, TCG_CALL_NO_RWG, tl, env, i64) +#if defined(TARGET_RH85064) +DEF_HELPER_FLAGS_2(fcvt_l_d, TCG_CALL_NO_RWG, tl, env, i64) +DEF_HELPER_FLAGS_2(fcvt_lu_d, TCG_CALL_NO_RWG, tl, env, i64) +#endif +DEF_HELPER_FLAGS_2(fcvt_d_w, TCG_CALL_NO_RWG, i64, env, tl) +DEF_HELPER_FLAGS_2(fcvt_d_wu, TCG_CALL_NO_RWG, i64, env, tl) +#if defined(TARGET_RH85064) +DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, tl) +DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, tl) +#endif +DEF_HELPER_FLAGS_1(fclass_d, TCG_CALL_NO_RWG_SE, tl, i64) + +/* Special functions */ +//DEF_HELPER_3(csrrw, tl, env, tl, tl) +//DEF_HELPER_4(csrrs, tl, env, tl, tl, tl) +//DEF_HELPER_4(csrrc, tl, env, tl, tl, tl) +#ifndef CONFIG_USER_ONLY +//DEF_HELPER_2(sret, tl, env, tl) +//DEF_HELPER_2(mret, tl, env, tl) +//DEF_HELPER_1(wfi, void, env) +DEF_HELPER_1(tlb_flush, void, env) +#endif diff --git a/qemu/target/rh850/instmap.h b/qemu/target/rh850/instmap.h new file mode 100644 index 0000000000..2cbf2aed2f --- /dev/null +++ b/qemu/target/rh850/instmap.h @@ -0,0 +1,624 @@ +/* + * RH850 emulation for qemu: Instruction decode helpers + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * + * 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/>. + */ + +#ifndef _RH850_INSTMAP_H +#define _RH850_INSTMAP_H + +enum{ + /*SIGNED INT*/ + COND_RH850_BGE = 1110, + COND_RH850_BGT = 1111, + COND_RH850_BLE = 0111, + COND_RH850_BLT = 0110, + /*UNSIGNED INT*/ + COND_RH850_BH = 1011, + COND_RH850_BL = 0001, + COND_RH850_BNH = 0011, + COND_RH850_BNL = 1001, + /*COMMON*/ + COND_RH850_BE = 0010, + COND_RH850_BNE = 1010, + /*OTHERS*/ + COND_RH850_BC = 0001, + COND_RH850_BF = 1010, + COND_RH850_BN = 0100, + COND_RH850_BNC = 1001, + COND_RH850_BNV = 1000, + COND_RH850_BNZ = 1010, + COND_RH850_BP = 1100, + COND_RH850_BR = 0101, + COND_RH850_BSA = 1101, + COND_RH850_BT = 0010, + COND_RH850_BV = 0000, + COND_RH850_BZ = 0010, +}; + +#define MASK_OP_MAJOR(op) (op & (0x3F << 5)) // the major opcode in rh850 is at bits 10-5 +enum { + /* FORMAT I */ // unique opcodes and grouped instructions + OPC_RH850_16bit_0 = (0x0 << 5), // group with opcode 0x0 (nop, synci, synce, syncm, syncp, mov) + OPC_RH850_NOT_reg1_reg2 = (0x1 << 5), + OPC_RH850_16bit_2 = (0x2 << 5), // group with opcode 0x2 (rie, switch, divh, fetrap) + OPC_RH850_16bit_3 = (0x3 << 5), // group with opcode 0x3 (jmp,sld.bu,sld.hu) + OPC_RH850_16bit_4 = (0x4 << 5), // group with opcode 0x4 (zyb, satsub) + OPC_RH850_16bit_5 = (0x5 << 5), // group with opcode 0x5 (sxb, satsub) + OPC_RH850_16bit_6 = (0x6 << 5), // group with opcode 0x6 (zyh, satadd) + OPC_RH850_16bit_7 = (0x7 << 5), // group with opcode 0x7 (sxh, mulh) + OPC_RH850_OR_reg1_reg2 = (0x8 << 5), + OPC_RH850_XOR_reg1_reg2 = (0x9 << 5), + OPC_RH850_AND_reg1_reg2 = (0xA << 5), + OPC_RH850_TST_reg1_reg2 = (0xB << 5), + OPC_RH850_SUBR_reg1_reg2 = (0xC << 5), + OPC_RH850_SUB_reg1_reg2 = (0xD << 5), + OPC_RH850_ADD_reg1_reg2 = (0xE << 5), + OPC_RH850_CMP_reg1_reg2 = (0xF << 5), + + /* FORMAT II */ + OPC_RH850_16bit_16 = (0x10 << 5), // group with opcode 0x10 (mov,callt) + OPC_RH850_16bit_17 = (0x11 << 5), // group with opcode 0x11 (callt, satadd) + OPC_RH850_ADD_imm5_reg2= (0x12 << 5), // group with opcode 0x12 (add) + OPC_RH850_CMP_imm5_reg2 = (0x13 << 5), // group with opcode 0x13 (cmp) + OPC_RH850_SHR_imm5_reg2 = (0x14 << 5), + OPC_RH850_SAR_imm5_reg2 = (0x15 << 5), + OPC_RH850_SHL_imm5_reg2 = (0x16 << 5), + OPC_RH850_MULH_imm5_reg2 = (0x17 << 5), + + /*FORMAT III */ + OPC_RH850_BCOND = (0xB << 7), // different mask! (bits 10-7) + + /* FORMAT IV */ // different mask! (bits 10-7) + OPC_RH850_16bit_SLDB = (0x6 << 5), + OPC_RH850_16bit_SLDH = (0x8 << 5), + OPC_RH850_16bit_IV10 = (0xA << 5), // group with opcode 0xA (sld.w,sst.w) + OPC_RH850_16bit_SSTB = (0x7 << 5), + OPC_RH850_16bit_SSTH = (0x9 << 5), + + /* FORMAT VI */ + OPC_RH850_ADDI_imm16_reg1_reg2 = (0x30 << 5), + OPC_RH850_ANDI_imm16_reg1_reg2 = (0x36 << 5), + OPC_RH850_MOVEA = (0x31 << 5), // this is also MOV 3, which is 48 bit + OPC_RH850_MOVHI_imm16_reg1_reg2 = (0x32 << 5), + OPC_RH850_ORI_imm16_reg1_reg2 = (0x34 << 5), + OPC_RH850_SATSUBI_imm16_reg1_reg2= (0x33 << 5), + OPC_RH850_XORI_imm16_reg1_reg2 = (0x35 << 5), + + + /* FORMAT VII */ + + OPC_RH850_LOOP = (0x37 << 5), //same as MULHI in format VI !!!! + + OPC_RH850_LDB = (0x38 << 5), + OPC_RH850_LDH_LDW = (0x39 << 5), + OPC_RH850_STB = (0x3A << 5), + OPC_RH850_STH_STW = (0x3B << 5), //the store halfword and store word instructions differ on LSB displacement bit 16 (0=ST.H, 1=ST.W) (format VII) + + OPC_RH850_ST_LD_0 = (0x3C << 5), //5 instructions share this opcode, sub-op bits 11-15 are 0, inst. differ in sub-op bits 16-19 (ST.B2=D, ST.W2=F) (format XIV) + OPC_RH850_ST_LD_1 = (0x3D << 5), //5 instructions share this opcode, sub-op bits 11-15 are 0, inst. differ in sub-op bits 16-19 (ST.DW=F, ST.H2=D) (format XIV) + //OPC_RH850_LDHU = (0x3F << 5), //bits 11-15 are not all 0 + + OPC_RH850_32bit_1 = (0x3F << 5), // 111111 + + + + + OPC_RH850_BIT_MANIPULATION_2 = (0x3E << 5), + + OPC_RH850_FORMAT_V_XIII = (0x1E << 6), + + + OPC_RH850_MULH1 = (0x7 << 5), + OPC_RH850_MULH2 = (0x17 << 5), + + +}; + +enum{ + OPC_RH850_SET1_reg2_reg1 = 0, + OPC_RH850_NOT1_reg2_reg1 = 2, + OPC_RH850_CLR1_reg2_reg1 = 4, + OPC_RH850_TST1_reg2_reg1 = 6, +}; + +enum{ + OPC_RH850_SET1_bit3_disp16_reg1 = 1, + OPC_RH850_NOT1_bit3_disp16_reg1 = 3, + OPC_RH850_CLR1_bit3_disp16_reg1 = 5, + OPC_RH850_TST1_bit3_disp16_reg1 = 7, +}; + +enum{ + OPC_RH850_MOV_reg1_reg2 = 1, + OPC_RH850_MOV_imm5_reg2 = 2, + OPC_RH850_MOV_imm32_reg1 = 3, + OPC_RH850_MOVEA_imm16_reg1_reg2 = 4, +}; + +enum{ + OPC_RH850_SATADD_reg1_reg2 = 1, + OPC_RH850_SATADD_imm5_reg2 = 2, + OPC_RH850_SATADD_reg1_reg2_reg3 = 3, + OPC_RH850_SATSUB_reg1_reg2 = 4, + OPC_RH850_SATSUB_reg1_reg2_reg3 = 5, + OPC_RH850_SATSUBR_reg1_reg2 = 6, +}; + +enum{ + OPC_RH850_MUL_reg1_reg2_reg3 = 1, + OPC_RH850_MUL_imm9_reg2_reg3 = 2, + OPC_RH850_MULH_reg1_reg2 = 3, + //OPC_RH850_MULH_imm5_reg2 = 4, + OPC_RH850_MULHI_imm16_reg1_reg2 = 5, + OPC_RH850_MULU_reg1_reg2_reg3 = 8, + OPC_RH850_MULU_imm9_reg2_reg3 = 9, +}; + +enum{ + OPC_RH850_ADF_cccc_reg1_reg2_reg3 = 10, + OPC_RH850_SBF_cccc_reg1_reg2_reg3 = 11, + OPC_RH850_DIVH_reg1_reg2 = 12, +}; + +enum{ //enum for gen_data_manipulation cases + OPC_RH850_SHR_reg1_reg2 = 111, + OPC_RH850_SHR_reg1_reg2_reg3 = 222, + OPC_RH850_CMOV_cccc_reg1_reg2_reg3 = 333, + OPC_RH850_CMOV_cccc_imm5_reg2_reg3 = 444, + OPC_RH850_ROTL_reg1_reg2_reg3 = 445, + OPC_RH850_ROTL_imm5_reg2_reg3 = 446, + OPC_RH850_SAR_reg1_reg2 = 447, + OPC_RH850_SAR_reg1_reg2_reg3 = 448, + OPC_RH850_SASF_cccc_reg2 = 449, + OPC_RH850_SETF_cccc_reg2 = 450, + OPC_RH850_SHL_reg1_reg2 = 451, + OPC_RH850_SHL_reg1_reg2_reg3 = 453, + OPC_RH850_SXB_reg1 = 454, + OPC_RH850_SXH_reg1 = 455, + OPC_RH850_ZXB_reg1 = 456, + OPC_RH850_ZXH_reg1 = 457, + + + +}; + +enum{ + OPC_RH850_LDSR_reg2_regID_selID = 1, + OPC_RH850_STSR_regID_reg2_selID = 2, + //check for unintentional matching + OPC_RH850_PREPARE_list12_imm5 = 12, + OPC_RH850_PREPARE_list12_imm5_sp = 13, + OPC_RH850_RIE = 3, + OPC_RH850_CALLT_imm6 = 4, + OPC_RH850_CAXI_reg1_reg2_reg3 = 5, + OPC_RH850_DISPOSE_imm5_list12 = 7, + OPC_RH850_DISPOSE_imm5_list12_reg1 = 8, + OPC_RH850_FETRAP_vector4 = 15, + OPC_RH850_SWITCH_reg1 = 10, +}; + +enum{ // magic numbers for branch opcodes + OPC_RH850_JR_imm22 = 0, + OPC_RH850_JR_imm32 = 1, + OPC_RH850_JARL_disp22_reg2 = 2, + OPC_RH850_JARL_disp32_reg1 = 3, //48-bit + OPC_RH850_JARL_reg1_reg3 = 4, + OPC_RH850_JMP_reg1 = 5, + OPC_RH850_JMP_disp32_reg1 = 6, + +}; + + +#define MASK_OP_FORMAT_I_0(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 11)) | (op & (0x1F << 0))) +enum { + OPC_RH850_NOP = OPC_RH850_16bit_0 | (0x0 << 11) | (0x0 << 0), + OPC_RH850_SYNCI = OPC_RH850_16bit_0 | (0x0 << 11) | (0x1C << 0), + OPC_RH850_SYNCE = OPC_RH850_16bit_0 | (0x0 << 11) | (0x1D << 0), + OPC_RH850_SYNCM = OPC_RH850_16bit_0 | (0x0 << 11) | (0x1E << 0), + OPC_RH850_SYNCP = OPC_RH850_16bit_0 | (0x0 << 11) | (0x1F << 0) +}; + + + +#define MASK_OP_ST_LD0(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 11)) | (op & (0xF << 16))) +enum { + + OPC_RH850_LDB2 = OPC_RH850_ST_LD_0 | (0x00 << 11 ) | (0x5 << 16), + OPC_RH850_LDH2 = OPC_RH850_ST_LD_0 | (0x00 << 11 ) | (0x7 << 16), + OPC_RH850_LDW2 = OPC_RH850_ST_LD_0 | (0x00 << 11 ) | (0x9 << 16), + OPC_RH850_STB2 = OPC_RH850_ST_LD_0 | (0x00 << 11 ) | (0xD << 16), //sub-op bits 11-15 are 0, inst. differ in sub-op bits 16-19 (ST.B2=D, ST.W2=F) (format XIV) + OPC_RH850_STW2 = OPC_RH850_ST_LD_0 | (0x00 << 11 ) | (0xF << 16), + +}; +#define MASK_OP_ST_LD1(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 11)) | (op & (0xF << 16))) +enum { + + OPC_RH850_LDBU2 = OPC_RH850_ST_LD_1 | (0x00 << 11 ) | (0x5 << 16), + OPC_RH850_LDHU2 = OPC_RH850_ST_LD_1 | (0x00 << 11 ) | (0x7 << 16), + OPC_RH850_LDDW = OPC_RH850_ST_LD_1 | (0x00 << 11 ) | (0x9 << 16), + OPC_RH850_STDW = OPC_RH850_ST_LD_1 | (0x00 << 11 ) | (0xF << 16), + OPC_RH850_STH2 = OPC_RH850_ST_LD_1 | (0x00 << 11 ) | (0xD << 16), +}; + +#define MASK_OP_32BIT_SUB(op) (op & (0xF << 23)) +enum { + OPC_RH850_LDSR_RIE_SETF_STSR = (0x0 << 23), + OPC_RH850_FORMAT_IX = (0x1 << 23), // 0001 + OPC_RH850_FORMAT_X = (0x2 << 23), // 0010 + OPC_RH850_MUL_INSTS = (0x4 << 23), // 0100 this is also for SASF + OPC_RH850_FORMAT_XI = (0x5 << 23), // 0101 + OPC_RH850_FORMAT_XII = (0x6 << 23), // 0110 + OPC_RH850_ADDIT_ARITH = (0x7 << 23), // 0111 + OPC_RH850_FORMAT_FI_CAT0 = (0x8 << 23), // 1000 used for floating-point instructions + OPC_RH850_FORMAT_FI_CAT1 = (0x9 << 23) // 1001 used for specific FPU instructions +}; + +#define MASK_OP_FORMAT_IX(op) (op & (0x3 << 21)) //0001 on b26-b23 +enum { + OPC_RH850_BINS_0 = (0x0 << 21), //BINS0,SHR, SHR2 + OPC_RH850_BINS_1 = (0x1 << 21), //BINS1,SAR,SAR2 + OPC_RH850_BINS_2 = (0x2 << 21), //BINS2,SHL, SHL2, ROTL, ROTL2 + OPC_RH850_BIT_MANIPULATION = (0x3 << 21), //clr1, set, tst1, not1, caxi in format IX +}; + +#define MASK_OP_FORMAT_X(op) (op & (0xFFF << 11)) //0010 on b26-b23 +enum { + OPC_RH850_CTRET = (0x880 << 11), + OPC_RH850_DI = (0xC00 << 11), + OPC_RH850_EI = (0XC10 << 11), + OPC_RH850_EIRET = (0X900 << 11), + OPC_RH850_FERET = (0X940 << 11), + OPC_RH850_HALT = (0X400 << 11), + OPC_RH850_JARL3 = (0XC18 << 11), + OPC_RH850_SNOOZE = (0x401 << 11), + OPC_RH850_SYSCALL = (0xC1A << 11), + OPC_RH850_TRAP = (0x000 << 11), + OPC_RH850_PREF = (0xC1B << 11), + OPC_RH850_POPSP_rh_rt = (0xC0C << 11), + OPC_RH850_PUSHSP_rh_rt = (0xC08 << 11), + //don't forget CACHE + OPC_RH850_CLL = (0xC1F << 11), + +}; + +#define MASK_OP_FORMAT_XI(op) (op & (0x7F << 16)) +enum { + OPC_RH850_DIVH_reg1_reg2_reg3 = 0x0, + OPC_RH850_DIVHU_reg1_reg2_reg3 = 0x2, + OPC_RH850_DIV_reg1_reg2_reg3 = 0x40, + OPC_RH850_DIVQ = 0x7C, + OPC_RH850_DIVQU = 0x7E, + OPC_RH850_DIVU_reg1_reg2_reg3 = 0x42 +}; + +#define MASK_OP_FORMAT_XII(op) (op & (0x3 << 17)) +enum { + OPC_RH850_BSW_reg2_reg3 = (0x0 << 0), + OPC_RH850_BSH_reg2_reg3 = (0x1 << 0), + OPC_RH850_HSW_reg2_reg3 = (0x2 << 0), + OPC_RH850_HSH_reg2_reg3 = (0x3 << 0), + // SCHOL, SCHOR, SCH1L, SCH1R + OPC_RH850_SCH0R_reg2_reg3 = (0x0 << 0), + OPC_RH850_SCH1R_reg2_reg3 = (0x1 << 0), //this is also STCW + OPC_RH850_SCH0L_reg2_reg3 = (0x2 << 0), + OPC_RH850_SCH1L_reg2_reg3 = (0x3 << 0), + + +}; + +#define MASK_ADDIT_ARITH_OP(op) (op & (0x3 << 21)) +enum { + OPC_RH850_SBF_SATSUB = 0x0, + OPC_RH850_ADF_SATADD3 = 0x1, + OPC_RH850_MAC_reg1_reg2_reg3_reg4 = 0x2, + OPC_RH850_MACU_reg1_reg2_reg3_reg4 = 0x3, +}; + +/* + * FPU instruction format (F:I) + */ + +enum { + FPU_TYPE_S, + FPU_TYPE_D, + FPU_TYPE_LS, + FPU_TYPE_LD, + FPU_TYPE_DL, + FPU_TYPE_SD, + FPU_TYPE_SL, + FPU_TYPE_DW, + FPU_TYPE_WD, + FPU_TYPE_HS, + FPU_TYPE_SH, + FPU_TYPE_SW, + FPU_TYPE_WS, + FPU_TYPE_DUW, + FPU_TYPE_SUW, + FPU_TYPE_UWD, + FPU_TYPE_UWS, + FPU_TYPE_ULD, + FPU_TYPE_ULS, + FPU_TYPE_SUL, + FPU_TYPE_DUL +}; + +enum { + FPU_OP_ABS, + FPU_OP_ADD, + FPU_OP_CEIL, + FPU_OP_CVT, + FPU_OP_DIV, + FPU_OP_FLOOR, + FPU_OP_CMOV, + FPU_OP_CMP, + FPU_OP_MAX, + FPU_OP_MIN, + FPU_OP_MUL, + FPU_OP_NEG, + FPU_OP_RECIP, + FPU_OP_RSQRT, + FPU_OP_SQRT, + FPU_OP_SUB, + FPU_OP_TRNC +}; + +#define MASK_OP_FORMAT_FI(op) (op & (0x7F << 16)) +enum { + OPC_RH850_FPU_CMOV_S_OR_TRFSR = 0x00 << 16, + OPC_RH850_FPU_CMOV_D = 0x10 << 16, + OPC_RH850_FPU_CMP_S = 0x20 << 16, + OPC_RH850_FPU_CMP_D = 0x30 << 16, + OPC_RH850_FPU_GROUP_CMPD= 0x30 << 16, + OPC_RH850_FPU_GROUP_SW = 0x40 << 16, + OPC_RH850_FPU_GROUP_DS = 0x42 << 16, + OPC_RH850_FPU_GROUP_SL = 0x44 << 16, + OPC_RH850_FPU_GROUP_ABSS = 0x48 << 16, + OPC_RH850_FPU_GROUP_S = 0x4E << 16, + OPC_RH850_FPU_GROUP_DW = 0x50 << 16, + OPC_RH850_FPU_GROUP_DD = 0x52 << 16, + OPC_RH850_FPU_GROUP_DL = 0x54 << 16, + OPC_RH850_FPU_GROUP_ABSD = 0x58 << 16, + OPC_RH850_FPU_GROUP_D = 0x5E << 16, + OPC_RH850_FPU_ADDF_S = 0x60 << 16, + OPC_RH850_FPU_SUBF_S = 0x62 << 16, + OPC_RH850_FPU_MULF_S = 0x64 << 16, + OPC_RH850_FPU_MAXF_S = 0x68 << 16, + OPC_RH850_FPU_MINF_S = 0x6A << 16, + OPC_RH850_FPU_DIVF_S = 0x6E << 16, + OPC_RH850_FPU_ADDF_D = 0x70 << 16, + OPC_RH850_FPU_SUBF_D = 0x72 << 16, + OPC_RH850_FPU_MULF_D = 0x74 << 16, + OPC_RH850_FPU_MAXF_D = 0x78 << 16, + OPC_RH850_FPU_MINF_D = 0x7A << 16, + OPC_RH850_FPU_DIVF_D = 0x7E << 16 +}; + +/* OPC_RH850_FPU_GROUP_CMPS/D, variant defined by cond reg3. */ +enum { + OPC_RH850_FPU_CMPS_F = 0x20, + OPC_RH850_FPU_CMPS_UN, + OPC_RH850_FPU_CMPS_EQ, + OPC_RH850_FPU_CMPS_UEQ, + OPC_RH850_FPU_CMPS_OLT, + OPC_RH850_FPU_CMPS_ULT, + OPC_RH850_FPU_CMPS_OLE, + OPC_RH850_FPU_CMPS_ULE, + OPC_RH850_FPU_CMPS_SF, + OPC_RH850_FPU_CMPS_NGLE, + OPC_RH850_FPU_CMPS_SEQ, + OPC_RH850_FPU_CMPS_NGL, + OPC_RH850_FPU_CMPS_LT, + OPC_RH850_FPU_CMPS_NGE, + OPC_RH850_FPU_CMPS_LE, + OPC_RH850_FPU_CMPS_NGT +}; + +/* OPC_RH850_FPU_GROUP_SW, variant defined by reg1 */ +enum { + OPC_RH850_FPU_TRNCF_SW=0x1, + OPC_RH850_FPU_CEILF_SW, + OPC_RH850_FPU_FLOORF_SW, + OPC_RH850_FPU_CVTF_SW, + OPC_RH850_FPU_TRNCF_SUW=0x11, + OPC_RH850_FPU_CEILF_SUW, + OPC_RH850_FPU_FLOORF_SUW, + OPC_RH850_FPU_CVTF_SUW=0x14 +}; + +/* OPC_RH850_FPU_GROUP_DS, variant defined by reg1 */ +enum { + OPC_RH850_FPU_CVTF_WS=0x0, + OPC_RH850_FPU_CVTF_LS, + OPC_RH850_FPU_CVTF_HS, + OPC_RH850_FPU_CVTF_SH, + OPC_RH850_FPU_CVTF_UWS=0x10, + OPC_RH850_FPU_CVTF_ULS +}; + +/* OPC_RH850_FPU_GROUP_SL, variant defined by reg1 */ +enum { + OPC_RH850_FPU_TRNCF_SL = 0x1, + OPC_RH850_FPU_CEILF_SL, + OPC_RH850_FPU_FLOORF_SL, + OPC_RH850_FPU_CVTF_SL, + OPC_RH850_FPU_TRNCF_SUL = 0x11, + OPC_RH850_FPU_CEILF_SUL, + OPC_RH850_FPU_FLOORF_SUL, + OPC_RH850_FPU_CVTF_SUL +}; + +/* OPC_RH850_FPU_GROUP_ABSS, variant defined by reg1 */ +enum { + OPC_RH850_FPU_ABSF_S = 0x0, + OPC_RH850_FPU_NEGF_S, +}; + +/* OPC_RH850_FPU_GROUP_S, variant defined by reg1 */ +enum { + OPC_RH850_FPU_SQRTF_S = 0x0, + OPC_RH850_FPU_RECIPF_S, + OPC_RH850_FPU_RSQRTF_S +}; + + +/* OPC_RH850_FPU_GROUP_DW, variant defined by reg1 */ +enum { + OPC_RH850_FPU_TRNCF_DW = 0x1, + OPC_RH850_FPU_CEILF_DW, + OPC_RH850_FPU_FLOORF_DW, + OPC_RH850_FPU_CVTF_DW, + OPC_RH850_FPU_TRNCF_DUW = 0x11, + OPC_RH850_FPU_CEILF_DUW, + OPC_RH850_FPU_FLOORF_DUW, + OPC_RH850_FPU_CVTF_DUW +}; + +/* OPC_RH850_FPU_GROUP_DD, variant defined by reg1 */ +enum { + OPC_RH850_FPU_CVTF_WD = 0x00, + OPC_RH850_FPU_CVTF_LD, + OPC_RH850_FPU_CVTF_SD, + OPC_RH850_FPU_CVTF_UWD = 0x10, + OPC_RH850_FPU_CVTF_ULD +}; + +/* OPC_RH850_FPU_GROUP_DL, variant defined by reg1 */ +enum { + OPC_RH850_FPU_TRNCF_DL = 0x1, + OPC_RH850_FPU_CEILF_DL, + OPC_RH850_FPU_FLOORF_DL, + OPC_RH850_FPU_CVTF_DL, + OPC_RH850_FPU_TRNCF_DUL = 0x11, + OPC_RH850_FPU_CEILF_DUL, + OPC_RH850_FPU_FLOORF_DUL, + OPC_RH850_FPU_CVTF_DUL +}; + +/* OPC_RH850_FPU_GROUP_ABSD, variant defined by reg1 */ +enum { + OPC_RH850_FPU_ABSF_D = 0x0, + OPC_RH850_FPU_NEGF_D, +}; + +/* OPC_RH850_FPU_GROUP_D, variant defined by reg1 */ +enum { + OPC_RH850_FPU_SQRTF_D = 0x0, + OPC_RH850_FPU_RECIPF_D, + OPC_RH850_FPU_RSQRTF_D +}; + +/* Format F:I with category=1 */ +enum { + OPC_RH850_FPU_FMAF_S = 0x60 << 16, + OPC_RH850_FPU_FMSF_S = 0x62 << 16, + OPC_RH850_FPU_FNMAF_S = 0x64 << 16, + OPC_RH850_FPU_FNMSF_S = 0x66 << 16 +}; + +#define MASK_OP_FORMAT_V_FORMAT_XIII(op) (op & (0x1F << 6)) + + +enum { + operation_LDL_W = 0, + operation_STC_W = 1, + operation_CLL = 2, +}; + + + +////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////// + + +#define GET_B_IMM(inst) ((extract32(inst, 8, 4) << 1) \ + | (extract32(inst, 25, 6) << 5) \ + | (extract32(inst, 7, 1) << 11) \ + | (sextract64(inst, 31, 1) << 12)) + +#define GET_STORE_IMM(inst) ((extract32(inst, 7, 5)) \ + | (sextract64(inst, 25, 7) << 5)) + +#define GET_JAL_IMM(inst) ((extract32(inst, 21, 10) << 1) \ + | (extract32(inst, 20, 1) << 11) \ + | (extract32(inst, 12, 8) << 12) \ + | (sextract64(inst, 31, 1) << 20)) + + +#define GET_RS1(inst) extract32(inst, 0, 5) //appropriate for RH850 +#define GET_RS2(inst) extract32(inst, 11, 5) //appropriate for RH850 +#define GET_RS3(inst) extract32(inst, 27, 5) //appropriate for RH850 +#define GET_DISP(inst) (extract32(inst, 20, 7) | (sextract32(inst, 32, 16) << 7 ) ) //b47-b32 + b26-b20 + + +#define GET_RM(inst) extract32(inst, 12, 3) +#define GET_RD(inst) extract32(inst, 7, 5) +#define GET_IMM(inst) sextract64(inst, 20, 12) +#define GET_IMM_32(inst) sextract64(inst, 16, 32) + +/* RVC decoding macros */ +#define GET_C_IMM(inst) (extract32(inst, 2, 5) \ + | (sextract64(inst, 12, 1) << 5)) +#define GET_C_ZIMM(inst) (extract32(inst, 2, 5) \ + | (extract32(inst, 12, 1) << 5)) +#define GET_C_ADDI4SPN_IMM(inst) ((extract32(inst, 6, 1) << 2) \ + | (extract32(inst, 5, 1) << 3) \ + | (extract32(inst, 11, 2) << 4) \ + | (extract32(inst, 7, 4) << 6)) +#define GET_C_ADDI16SP_IMM(inst) ((extract32(inst, 6, 1) << 4) \ + | (extract32(inst, 2, 1) << 5) \ + | (extract32(inst, 5, 1) << 6) \ + | (extract32(inst, 3, 2) << 7) \ + | (sextract64(inst, 12, 1) << 9)) +#define GET_C_LWSP_IMM(inst) ((extract32(inst, 4, 3) << 2) \ + | (extract32(inst, 12, 1) << 5) \ + | (extract32(inst, 2, 2) << 6)) +#define GET_C_LDSP_IMM(inst) ((extract32(inst, 5, 2) << 3) \ + | (extract32(inst, 12, 1) << 5) \ + | (extract32(inst, 2, 3) << 6)) +#define GET_C_SWSP_IMM(inst) ((extract32(inst, 9, 4) << 2) \ + | (extract32(inst, 7, 2) << 6)) +#define GET_C_SDSP_IMM(inst) ((extract32(inst, 10, 3) << 3) \ + | (extract32(inst, 7, 3) << 6)) +#define GET_C_LW_IMM(inst) ((extract32(inst, 6, 1) << 2) \ + | (extract32(inst, 10, 3) << 3) \ + | (extract32(inst, 5, 1) << 6)) +#define GET_C_LD_IMM(inst) ((extract32(inst, 10, 3) << 3) \ + | (extract32(inst, 5, 2) << 6)) +#define GET_C_J_IMM(inst) ((extract32(inst, 3, 3) << 1) \ + | (extract32(inst, 11, 1) << 4) \ + | (extract32(inst, 2, 1) << 5) \ + | (extract32(inst, 7, 1) << 6) \ + | (extract32(inst, 6, 1) << 7) \ + | (extract32(inst, 9, 2) << 8) \ + | (extract32(inst, 8, 1) << 10) \ + | (sextract64(inst, 12, 1) << 11)) +#define GET_C_B_IMM(inst) ((extract32(inst, 3, 2) << 1) \ + | (extract32(inst, 10, 2) << 3) \ + | (extract32(inst, 2, 1) << 5) \ + | (extract32(inst, 5, 2) << 6) \ + | (sextract64(inst, 12, 1) << 8)) +#define GET_C_SIMM3(inst) extract32(inst, 10, 3) +#define GET_C_RD(inst) GET_RD(inst) +#define GET_C_RS1(inst) GET_RD(inst) +#define GET_C_RS2(inst) extract32(inst, 2, 5) +#define GET_C_RS1S(inst) (8 + extract32(inst, 7, 3)) +#define GET_C_RS2S(inst) (8 + extract32(inst, 2, 3)) + +#endif /* _RH850_INSTMAP_H */ \ No newline at end of file diff --git a/qemu/target/rh850/op_helper.c b/qemu/target/rh850/op_helper.c new file mode 100644 index 0000000000..36e272e7a0 --- /dev/null +++ b/qemu/target/rh850/op_helper.c @@ -0,0 +1,89 @@ +/* + * RH850 Emulation Helpers for QEMU. + * + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu + * Copyright (c) 2017-2018 SiFive, Inc. + * + * 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/>. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" + +/* Exceptions processing helpers */ +void QEMU_NORETURN do_raise_exception_err(CPURH850State *env, + uint32_t exception, uintptr_t pc) +{ + CPUState *cs = CPU(rh850_env_get_cpu(env)); + qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); + cs->exception_index = exception; + cpu_loop_exit_restore(cs, pc); +} + +void QEMU_NORETURN do_raise_exception_err_with_cause(CPURH850State *env, + uint32_t exception, uint32_t cause, uintptr_t pc) +{ + CPUState *cs = CPU(rh850_env_get_cpu(env)); + //qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); + cs->exception_index = exception; + env->exception_cause = cause; + cpu_loop_exit_restore(cs, pc); +} + + +void helper_raise_exception(CPURH850State *env, uint32_t exception) +{ + do_raise_exception_err(env, exception, 0); +} + +void helper_raise_exception_with_cause(CPURH850State *env, uint32_t exception, uint32_t cause) +{ + do_raise_exception_err_with_cause(env, exception, cause, 0); +} + +target_ulong csr_read_helper(CPURH850State *env, target_ulong csrno) +{ + return 0; +} + +#ifndef CONFIG_USER_ONLY + +/* iothread_mutex must be held */ +void rh850_set_local_interrupt(RH850CPU *cpu, target_ulong mask, int value) +{ +} + +void rh850_set_mode(CPURH850State *env, target_ulong newpriv) +{ +} + +void helper_tlb_flush(CPURH850State *env) +{ + RH850CPU *cpu = rh850_env_get_cpu(env); + CPUState *cs = CPU(cpu); + tlb_flush(cs); +} + +void helper_uc_rh850_exit(CPURH850State *env) +{ + CPUState *cs = CPU(env); + + cs->exception_index = EXCP_HLT; + cs->halted = 1; + cpu_loop_exit(cs); +} + +#endif /* !CONFIG_USER_ONLY */ diff --git a/qemu/target/rh850/pmp.c b/qemu/target/rh850/pmp.c new file mode 100644 index 0000000000..8f98659d3a --- /dev/null +++ b/qemu/target/rh850/pmp.c @@ -0,0 +1,379 @@ +/* + * QEMU RH850 PMP (Physical Memory Protection) + * + * Author: Daire McNamara, daire.mcnamara@emdalo.com + * Ivan Griffin, ivan.griffin@emdalo.com + * + * This provides a RH850 Physical Memory Protection implementation + * + * 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/>. + */ + +/* + * PMP (Physical Memory Protection) is as-of-yet unused and needs testing. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "qemu-common.h" + +#ifndef CONFIG_USER_ONLY + +#define RH850_DEBUG_PMP 0 +#define PMP_DEBUG(fmt, ...) \ + do { \ + if (RH850_DEBUG_PMP) { \ + qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\ + } \ + } while (0) + +static void pmp_write_cfg(CPURH850State *env, uint32_t addr_index, + uint8_t val); +static uint8_t pmp_read_cfg(CPURH850State *env, uint32_t addr_index); +static void pmp_update_rule(CPURH850State *env, uint32_t pmp_index); + +/* + * Accessor method to extract address matching type 'a field' from cfg reg + */ +static inline uint8_t pmp_get_a_field(uint8_t cfg) +{ + uint8_t a = cfg >> 3; + return a & 0x3; +} + +/* + * Check whether a PMP is locked or not. + */ +static inline int pmp_is_locked(CPURH850State *env, uint32_t pmp_index) +{ + + if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) { + return 1; + } + + /* Top PMP has no 'next' to check */ + if ((pmp_index + 1u) >= MAX_RH850_PMPS) { + return 0; + } + + /* In TOR mode, need to check the lock bit of the next pmp + * (if there is a next) + */ + const uint8_t a_field = + pmp_get_a_field(env->pmp_state.pmp[pmp_index + 1].cfg_reg); + if ((env->pmp_state.pmp[pmp_index + 1u].cfg_reg & PMP_LOCK) && + (PMP_AMATCH_TOR == a_field)) { + return 1; + } + + return 0; +} + +/* + * Count the number of active rules. + */ +static inline uint32_t pmp_get_num_rules(CPURH850State *env) +{ + return env->pmp_state.num_rules; +} + +/* + * Accessor to get the cfg reg for a specific PMP/HART + */ +static inline uint8_t pmp_read_cfg(CPURH850State *env, uint32_t pmp_index) +{ + if (pmp_index < MAX_RH850_PMPS) { + return env->pmp_state.pmp[pmp_index].cfg_reg; + } + + return 0; +} + + +/* + * Accessor to set the cfg reg for a specific PMP/HART + * Bounds checks and relevant lock bit. + */ +static void pmp_write_cfg(CPURH850State *env, uint32_t pmp_index, uint8_t val) +{ + if (pmp_index < MAX_RH850_PMPS) { + if (!pmp_is_locked(env, pmp_index)) { + env->pmp_state.pmp[pmp_index].cfg_reg = val; + pmp_update_rule(env, pmp_index); + } else { + PMP_DEBUG("ignoring write - locked"); + } + } else { + PMP_DEBUG("ignoring write - out of bounds"); + } +} + +static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea) +{ + /* + aaaa...aaa0 8-byte NAPOT range + aaaa...aa01 16-byte NAPOT range + aaaa...a011 32-byte NAPOT range + ... + aa01...1111 2^XLEN-byte NAPOT range + a011...1111 2^(XLEN+1)-byte NAPOT range + 0111...1111 2^(XLEN+2)-byte NAPOT range + 1111...1111 Reserved + */ + if (a == -1) { + *sa = 0u; + *ea = -1; + return; + } else { + target_ulong t1 = ctz64(~a); + target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 3; + target_ulong range = ((target_ulong)1 << (t1 + 3)) - 1; + *sa = base; + *ea = base + range; + } +} + + +/* Convert cfg/addr reg values here into simple 'sa' --> start address and 'ea' + * end address values. + * This function is called relatively infrequently whereas the check that + * an address is within a pmp rule is called often, so optimise that one + */ +static void pmp_update_rule(CPURH850State *env, uint32_t pmp_index) +{ + int i; + + env->pmp_state.num_rules = 0; + + uint8_t this_cfg = env->pmp_state.pmp[pmp_index].cfg_reg; + target_ulong this_addr = env->pmp_state.pmp[pmp_index].addr_reg; + target_ulong prev_addr = 0u; + target_ulong sa = 0u; + target_ulong ea = 0u; + + if (pmp_index >= 1u) { + prev_addr = env->pmp_state.pmp[pmp_index - 1].addr_reg; + } + + switch (pmp_get_a_field(this_cfg)) { + case PMP_AMATCH_OFF: + sa = 0u; + ea = -1; + break; + + case PMP_AMATCH_TOR: + sa = prev_addr << 2; /* shift up from [xx:0] to [xx+2:2] */ + ea = (this_addr << 2) - 1u; + break; + + case PMP_AMATCH_NA4: + sa = this_addr << 2; /* shift up from [xx:0] to [xx+2:2] */ + ea = (this_addr + 4u) - 1u; + break; + + case PMP_AMATCH_NAPOT: + pmp_decode_napot(this_addr, &sa, &ea); + break; + + default: + sa = 0u; + ea = 0u; + break; + } + + env->pmp_state.addr[pmp_index].sa = sa; + env->pmp_state.addr[pmp_index].ea = ea; + + for (i = 0; i < MAX_RH850_PMPS; i++) { + const uint8_t a_field = + pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); + if (PMP_AMATCH_OFF != a_field) { + env->pmp_state.num_rules++; + } + } +} + +static int pmp_is_in_range(CPURH850State *env, int pmp_index, target_ulong addr) +{ + int result = 0; + + if ((addr >= env->pmp_state.addr[pmp_index].sa) + && (addr <= env->pmp_state.addr[pmp_index].ea)) { + result = 1; + } else { + result = 0; + } + + return result; +} + + +/* + * Public Interface + */ + +/* + * Check if the address has required RWX privs to complete desired operation + */ +bool pmp_hart_has_privs(CPURH850State *env, target_ulong addr, + target_ulong size, pmp_priv_t privs) +{ + int i = 0; + int ret = -1; + target_ulong s = 0; + target_ulong e = 0; + pmp_priv_t allowed_privs = 0; + + /* Short cut if no rules */ + if (0 == pmp_get_num_rules(env)) { + return true; + } + + /* 1.10 draft priv spec states there is an implicit order + from low to high */ + for (i = 0; i < MAX_RH850_PMPS; i++) { + s = pmp_is_in_range(env, i, addr); + e = pmp_is_in_range(env, i, addr + size); + + /* partially inside */ + if ((s + e) == 1) { + PMP_DEBUG("pmp violation - access is partially inside"); + ret = 0; + break; + } + + /* fully inside */ + const uint8_t a_field = + pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); + if ((s + e) == 2) { + if (PMP_AMATCH_OFF == a_field) { + return 1; + } + + allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; + if ((env->priv != PRV_M) || pmp_is_locked(env, i)) { + allowed_privs &= env->pmp_state.pmp[i].cfg_reg; + } + + if ((privs & allowed_privs) == privs) { + ret = 1; + break; + } else { + ret = 0; + break; + } + } + } + + /* No rule matched */ + if (ret == -1) { + if (env->priv == PRV_M) { + ret = 1; /* Privileged spec v1.10 states if no PMP entry matches an + * M-Mode access, the access succeeds */ + } else { + ret = 0; /* Other modes are not allowed to succeed if they don't + * match a rule, but there are rules. We've checked for + * no rule earlier in this function. */ + } + } + + return ret == 1 ? true : false; +} + + +/* + * Handle a write to a pmpcfg CSP + */ +void pmpcfg_csr_write(CPURH850State *env, uint32_t reg_index, + target_ulong val) +{ + int i; + uint8_t cfg_val; + + PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx, + env->mhartid, reg_index, val); + + if ((reg_index & 1) && (sizeof(target_ulong) == 8)) { + PMP_DEBUG("ignoring write - incorrect address"); + return; + } + + for (i = 0; i < sizeof(target_ulong); i++) { + cfg_val = (val >> 8 * i) & 0xff; + pmp_write_cfg(env, (reg_index * sizeof(target_ulong)) + i, + cfg_val); + } +} + + +/* + * Handle a read from a pmpcfg CSP + */ +target_ulong pmpcfg_csr_read(CPURH850State *env, uint32_t reg_index) +{ + int i; + target_ulong cfg_val = 0; + uint8_t val = 0; + + for (i = 0; i < sizeof(target_ulong); i++) { + val = pmp_read_cfg(env, (reg_index * sizeof(target_ulong)) + i); + cfg_val |= (val << (i * 8)); + } + + PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx, + env->mhartid, reg_index, cfg_val); + + return cfg_val; +} + + +/* + * Handle a write to a pmpaddr CSP + */ +void pmpaddr_csr_write(CPURH850State *env, uint32_t addr_index, + target_ulong val) +{ + PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx, + env->mhartid, addr_index, val); + + if (addr_index < MAX_RH850_PMPS) { + if (!pmp_is_locked(env, addr_index)) { + env->pmp_state.pmp[addr_index].addr_reg = val; + pmp_update_rule(env, addr_index); + } else { + PMP_DEBUG("ignoring write - locked"); + } + } else { + PMP_DEBUG("ignoring write - out of bounds"); + } +} + + +/* + * Handle a read from a pmpaddr CSP + */ +target_ulong pmpaddr_csr_read(CPURH850State *env, uint32_t addr_index) +{ + PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx, + env->mhartid, addr_index, + env->pmp_state.pmp[addr_index].addr_reg); + if (addr_index < MAX_RH850_PMPS) { + return env->pmp_state.pmp[addr_index].addr_reg; + } else { + PMP_DEBUG("ignoring read - out of bounds"); + return 0; + } +} + +#endif diff --git a/qemu/target/rh850/pmp.h b/qemu/target/rh850/pmp.h new file mode 100644 index 0000000000..e6e43e8241 --- /dev/null +++ b/qemu/target/rh850/pmp.h @@ -0,0 +1,64 @@ +/* + * QEMU RH850 PMP (Physical Memory Protection) + * + * Author: Daire McNamara, daire.mcnamara@emdalo.com + * Ivan Griffin, ivan.griffin@emdalo.com + * + * This provides a RH850 Physical Memory Protection interface + * + * 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/>. + */ + +#ifndef _RH850_PMP_H_ +#define _RH850_PMP_H_ + +typedef enum { + PMP_READ = 1 << 0, + PMP_WRITE = 1 << 1, + PMP_EXEC = 1 << 2, + PMP_LOCK = 1 << 7 +} pmp_priv_t; + +typedef enum { + PMP_AMATCH_OFF, /* Null (off) */ + PMP_AMATCH_TOR, /* Top of Range */ + PMP_AMATCH_NA4, /* Naturally aligned four-byte region */ + PMP_AMATCH_NAPOT /* Naturally aligned power-of-two region */ +} pmp_am_t; + +typedef struct { + target_ulong addr_reg; + uint8_t cfg_reg; +} pmp_entry_t; + +typedef struct { + target_ulong sa; + target_ulong ea; +} pmp_addr_t; + +typedef struct { + pmp_entry_t pmp[MAX_RH850_PMPS]; + pmp_addr_t addr[MAX_RH850_PMPS]; + uint32_t num_rules; +} pmp_table_t; + +void pmpcfg_csr_write(CPURH850State *env, uint32_t reg_index, + target_ulong val); +target_ulong pmpcfg_csr_read(CPURH850State *env, uint32_t reg_index); +void pmpaddr_csr_write(CPURH850State *env, uint32_t addr_index, + target_ulong val); +target_ulong pmpaddr_csr_read(CPURH850State *env, uint32_t addr_index); +bool pmp_hart_has_privs(CPURH850State *env, target_ulong addr, + target_ulong size, pmp_priv_t priv); + +#endif diff --git a/qemu/target/rh850/register_indices.h b/qemu/target/rh850/register_indices.h new file mode 100644 index 0000000000..20fcea8cae --- /dev/null +++ b/qemu/target/rh850/register_indices.h @@ -0,0 +1,63 @@ +/* + * register_indices.h + * + * Created on: Jun 18, 2018 + * + */ + +#ifndef TARGET_RH850_REGISTER_INDICES_H_ +#define TARGET_RH850_REGISTER_INDICES_H_ + + +// BANK ID 0, sys basic regs +#define EIPC_IDX 0 +#define EIPSW_IDX 1 +#define FEPC_IDX 2 +#define FEPSW_IDX 3 +#define PSW_IDX 5 //program status word +// sysFpuRegs indices +#define FPSR_IDX 6 //floating-point configuration/status <---write the bit defines +#define FPEPC_IDX 7 //floating point exception PC +#define FPST_IDX 8 +#define FPCC_IDX 9 +#define FPCFG_IDX 10 +#define FPEC_IDX 11 + +#define EIIC_IDX 13 //EI level exception cause +#define FEIC_IDX 14 //FI level exception cause +#define CTPC_IDX 16 +#define CTPSW_IDX 17 +#define CTBP_IDX 20 +#define EIWR_IDX 28 +#define FEWR_IDX 29 +#define BSEL_IDX 31 + +// BANK ID 1, sys basic regs +#define MCFG0_IDX1 0 //machine configuration +#define RBASE_IDX1 2 //reset vector base address (if psw.ebv==0, this is also exception vector) +#define EBASE_IDX1 3 //exception handler vector address +#define INTBP_IDX1 4 +#define MCTL_IDX1 5 //CPU control +#define PID_IDX1 6 //processor ID +#define SCCFG_IDX1 11 // SYSCALL config +#define SCBP_IDX1 12 // SYSCALL base pointer + +// BANK ID 2, sys basic regs +#define HTCFG0_IDX2 0 //thread configuration +#define MEA_IDX2 6 //memory error address (when misaligned or MPU) +#define ASID_IDX2 7 //memory error address (when misaligned or MPU) +#define MEI_IDX2 8 //memory error info (info about instruction that caused exception) + +// BANK ID 1, 2 sysInterruptRegs indices +#define FPIPR_IDX1 7 +#define ISPR_IDX2 10 +#define PMR_IDX2 11 +#define ICSR_IDX2 12 //interrupt control status register +#define INTCFG_IDX2 13 //interrupt function setting + + +// BANK ID 5, 6, 7 system MPU regs indices +#define MPM_IDX5 0 //memory protection operation mode + + +#endif /* TARGET_RH850_REGISTER_INDICES_H_ */ diff --git a/qemu/target/rh850/translate.c b/qemu/target/rh850/translate.c new file mode 100644 index 0000000000..7081656c95 --- /dev/null +++ b/qemu/target/rh850/translate.c @@ -0,0 +1,5190 @@ +/* + * RH850 emulation for qemu: main translation routines. + * + * Copyright (c) 2018 iSYSTEM Labs d.o.o. + * Copyright (c) 2023 Quarkslab + * + * 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/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "qemu/log.h" +#include "qemu/host-utils.h" +#include "exec/cpu_ldst.h" +#include "exec/gen-icount.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "exec/translator.h" + +#include "instmap.h" + +#include "unicorn/platform.h" +#include "uc_priv.h" +#include "translate.h" +#include "fpu_translate.h" + +/* + * Unicorn: Special disas state for exiting in the middle of tb. + */ + +/* We are not using a goto_tb (for whatever reason), but have updated + the PC (for whatever reason), so there's no need to do it again on + exiting the TB. */ +#define DISAS_PC_UPDATED DISAS_TARGET_0 + +/* We have emitted one or more goto_tb. No fixup required. */ +#define DISAS_GOTO_TB DISAS_TARGET_1 + +/* We have updated the PC and CC values. */ +#define DISAS_PC_CC_UPDATED DISAS_TARGET_2 + +/* We are exiting the TB, but have neither emitted a goto_tb, nor + updated the PC for the next instruction to be executed. */ +#define DISAS_PC_STALE DISAS_TARGET_3 + +/* We are exiting the TB to the main loop. */ +#define DISAS_PC_STALE_NOCHAIN DISAS_TARGET_4 + +#define DISAS_UNICORN_HALT DISAS_TARGET_11 + +/* global register indices */ +static TCGv cpu_gpr[NUM_GP_REGS]; +static TCGv cpu_pc; +static TCGv cpu_sysRegs[NUM_SYS_REG_BANKS][MAX_SYS_REGS_IN_BANK]; +// static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */ +static TCGv cpu_sysDatabuffRegs[1], cpu_LLbit, cpu_LLAddress; +static TCGv load_res; +static TCGv load_val; + +// PSW register flags. These are for temporary use only during +// calculations. Before usage they should be set from PSW and +// stored back to PSW after changes. +// TODO: since PSW as a register is rarely used - only when ld/str sys reg and +// on some branches (TRAP, ...) it makes sense to compose/decompose PSW +// on these occcasions and not have PSW stored in registers below. +TCGv_i32 cpu_ZF, cpu_SF, cpu_OVF, cpu_CYF, cpu_SATF, cpu_ID, cpu_EP, cpu_NP, + cpu_EBV, cpu_CU0, cpu_CU1, cpu_CU2, cpu_UM; + + +/** Const, RH850 does not have MMU. */ +const int MEM_IDX = 0; + +/* is_jmp field values */ +#define DISAS_INDIRECT_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ +#define DISAS_EXIT_TB DISAS_TARGET_1 /* cpu state was modified dynamically */ +#define DISAS_TB_EXIT_ALREADY_GENERATED DISAS_TARGET_2 +#define CASE_OP_32_64(X) case X + +/* Possible conditions for tests. */ +enum { + V_COND = 0, /* OV = 1 */ + C_COND = 1, /* CY = 1 */ + Z_COND = 2, /* Z = 1 */ + NH_COND = 3, /* (CY or Z) = 1 */ + S_COND = 4, /* S = 1 */ + T_COND = 5, /* Always */ + LT_COND = 6, /* (S xor OV) = 1 */ + LE_COND = 7, /* ((S xor OV) or Z) = 1 */ + + NV_COND = 8, /* OV = 0 */ + NC_COND = 9, /* CY = 0 */ + NZ_COND = 10, /* Z = 0 */ + H_COND = 11, /* (CY or Z) = 0 */ + NS_COND = 12, /* S = 0 */ + SA_COND = 13, /* SAT = 1 */ + GE_COND = 14, /* (S xor OV) = 0 */ + GT_COND = 15, /* ((S xor OV) or Z) = 0 */ +}; + +// Enumeration for Cache operations. +enum { + CHBII = 0x0, + CIBII = 0x20, + CFALI = 0x40, + CISTI = 0x60, + CILDI = 0x61, + CLL = 0x7e, +}; + +enum { + OPC_RH850_BINS = 123456, +}; + + +static void gen_exception_debug(DisasContext *dc) +{ + TCGContext *tcg_ctx = dc->uc->tcg_ctx; + + TCGv_i32 helper_tmp = tcg_const_i32(tcg_ctx, EXCP_DEBUG); + gen_helper_raise_exception(tcg_ctx, tcg_ctx->cpu_env, helper_tmp); + tcg_temp_free_i32(tcg_ctx, helper_tmp); + + dc->base.is_jmp = DISAS_TB_EXIT_ALREADY_GENERATED; +} + +static void gen_exception_halt(DisasContext *dc) +{ + TCGContext *tcg_ctx = dc->uc->tcg_ctx; + + TCGv_i32 helper_tmp = tcg_const_i32(tcg_ctx, EXCP_HLT); + gen_helper_raise_exception(tcg_ctx, tcg_ctx->cpu_env, helper_tmp); + tcg_temp_free_i32(tcg_ctx, helper_tmp); + + dc->base.is_jmp = DISAS_TB_EXIT_ALREADY_GENERATED; +} + + +static void gen_goto_tb_imm(DisasContext *ctx, int n, target_ulong dest) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + if (unlikely(ctx->base.singlestep_enabled)) { + tcg_gen_movi_tl(tcg_ctx, cpu_pc, dest); + gen_exception_debug(ctx); + } else { + tcg_gen_goto_tb(tcg_ctx, n); + tcg_gen_movi_tl(tcg_ctx, cpu_pc, dest); + tcg_gen_exit_tb(tcg_ctx, ctx->base.tb, n); + } +} + + +/* Wrapper for getting reg values - need to check of reg is zero since + * cpu_gpr[0] is not actually allocated + */ +void gen_get_gpr(TCGContext *tcg_ctx, TCGv t, int reg_num) +{ + if (reg_num == 0) { + tcg_gen_movi_tl(tcg_ctx, t, 0); + } else { + tcg_gen_mov_tl(tcg_ctx, t, cpu_gpr[reg_num]); + } + +} + + +/* Wrapper for setting system register values. */ + +void gen_set_spr(TCGContext *tcg_ctx, int bank_id, int reg_id, TCGv t) +{ + tcg_gen_mov_tl(tcg_ctx, cpu_sysRegs[bank_id][reg_id], t); +} + +/* Wrapper for gettint sysreg values. */ +void gen_get_spr(TCGContext *tcg_ctx, int bank_id, int reg_id, TCGv t) +{ + tcg_gen_mov_tl(tcg_ctx, t, cpu_sysRegs[bank_id][reg_id]); +} + +/* Wrapper for setting reg values - need to check of reg is zero since + * cpu_gpr[0] is not actually allocated. this is more for safety purposes, + * since we usually avoid calling the OP_TYPE_gen function if we see a write to + * $zero + */ +void gen_set_gpr(TCGContext *tcg_ctx, int reg_num_dst, TCGv t) +{ + if (reg_num_dst != 0) { + tcg_gen_mov_tl(tcg_ctx, cpu_gpr[reg_num_dst], t); + } +} + + +/** + * gen_goto_tb_rl() is a customized version of gen_goto_tb() that is able to + * move PC into a specified register before updating PC. V850e3 JARL/JR insts. + * work this way :). + **/ + +static void gen_goto_tb_rl(DisasContext *ctx, int n, int reg, int insn_size, uint32_t dest) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv reg_value = tcg_temp_new_i32(tcg_ctx); + + if (unlikely(ctx->base.singlestep_enabled)) + { + + /* GR[reg] <- PC + insn_size */ + tcg_gen_movi_i32(tcg_ctx, reg_value, ctx->pc); + tcg_gen_addi_i32(tcg_ctx, reg_value, reg_value, insn_size); + gen_set_gpr(tcg_ctx, reg, reg_value); + + /* PC <- dest */ + tcg_gen_movi_i32(tcg_ctx, cpu_pc, dest); + + tcg_temp_free_i32(tcg_ctx, reg_value); + + /* Generate exception. */ + gen_exception_debug(ctx); + } + else + { + tcg_gen_goto_tb(tcg_ctx, n); + + /* GR[reg] <- PC + insn_size */ + tcg_gen_movi_i32(tcg_ctx, reg_value, ctx->pc); + tcg_gen_addi_i32(tcg_ctx, reg_value, reg_value, insn_size); + gen_set_gpr(tcg_ctx, reg, reg_value); + + /* PC <- dest */ + tcg_gen_movi_i32(tcg_ctx, cpu_pc, dest); + + tcg_temp_free_i32(tcg_ctx, reg_value); + + tcg_gen_exit_tb(tcg_ctx, ctx->base.tb, n); + } +} + + +static inline void tcgv_to_flags(TCGContext *tcg_ctx, TCGv reg) +{ + TCGv temp = tcg_temp_new_i32(tcg_ctx); + tcg_gen_mov_i32(tcg_ctx, temp, reg); + tcg_gen_andi_i32(tcg_ctx, cpu_ZF, temp, 0x1); + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_SF, temp, 0x1); + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_OVF, temp, 0x1); + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, temp, 0x1); + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_SATF, temp, 0x1); + + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_ID, temp, 0x1); + + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_EP, temp, 0x1); + + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_NP, temp, 0x1); + + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x8); + tcg_gen_andi_i32(tcg_ctx, cpu_EBV, temp, 0x1); + + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_CU0, temp, 0x1); + + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_CU1, temp, 0x1); + + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_CU2, temp, 0x1); + + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x12); + tcg_gen_andi_i32(tcg_ctx, cpu_UM, temp, 0x1); + + tcg_temp_free(tcg_ctx, temp); +} + + +static void tcgv_to_flags_z_cy_ov_s_sat(TCGContext *tcg_ctx, TCGv reg) +{ + TCGv temp = tcg_temp_new_i32(tcg_ctx); + tcg_gen_mov_i32(tcg_ctx, temp, reg); + tcg_gen_andi_i32(tcg_ctx, cpu_ZF, temp, 0x1); + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_SF, temp, 0x1); + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_OVF, temp, 0x1); + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, temp, 0x1); + tcg_gen_shri_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_andi_i32(tcg_ctx, cpu_SATF, temp, 0x1); + tcg_temp_free(tcg_ctx, temp); +} + + +static void flags_to_tcgv_id_ep_np_ebv_cu_um(TCGContext *tcg_ctx, TCGv reg) +{ + // Set flags in PSW to 0 so we can OR with new state + tcg_gen_andi_i32(tcg_ctx, reg, reg, 0xbff87f1f); + + TCGv temp = tcg_temp_new_i32(tcg_ctx); + + tcg_gen_shli_i32(tcg_ctx, temp, cpu_ID, 0x5); + tcg_gen_or_i32(tcg_ctx, reg, reg,temp); + + tcg_gen_shli_i32(tcg_ctx, temp, cpu_EP, 0x6); + tcg_gen_or_i32(tcg_ctx, reg, reg,temp); + + tcg_gen_shli_i32(tcg_ctx, temp, cpu_NP, 0x7); + tcg_gen_or_i32(tcg_ctx, reg, reg,temp); + + tcg_gen_shli_i32(tcg_ctx, temp, cpu_EBV, 0xF); + tcg_gen_or_i32(tcg_ctx, reg, reg,temp); + + tcg_gen_shli_i32(tcg_ctx, temp, cpu_CU0, 0x10); + tcg_gen_or_i32(tcg_ctx, reg, reg,temp); + + tcg_gen_shli_i32(tcg_ctx, temp, cpu_CU1, 0x11); + tcg_gen_or_i32(tcg_ctx, reg, reg,temp); + + tcg_gen_shli_i32(tcg_ctx, temp, cpu_CU2, 0x12); + tcg_gen_or_i32(tcg_ctx, reg, reg,temp); + + tcg_gen_shli_i32(tcg_ctx, temp, cpu_UM, 0x1E); + tcg_gen_or_i32(tcg_ctx, reg, reg,temp); + + tcg_temp_free(tcg_ctx, temp); +} + + +static void flags_to_tcgv_z_cy_ov_s_sat(TCGContext *tcg_ctx, TCGv reg) +{ + // update psw register, first reset flags before ORing new values + tcg_gen_andi_i32(tcg_ctx, reg, reg, 0xffffffe0); + TCGv temp = tcg_temp_new_i32(tcg_ctx); + tcg_gen_or_i32(tcg_ctx, reg, reg, cpu_ZF); + tcg_gen_shli_i32(tcg_ctx, temp, cpu_SF, 0x1); + tcg_gen_or_i32(tcg_ctx, reg,reg,temp); + tcg_gen_shli_i32(tcg_ctx, temp, cpu_OVF, 0x2); + tcg_gen_or_i32(tcg_ctx, reg,reg,temp); + tcg_gen_shli_i32(tcg_ctx, temp, cpu_CYF, 0x3); + tcg_gen_or_i32(tcg_ctx, reg,reg,temp); + tcg_gen_shli_i32(tcg_ctx, temp, cpu_SATF, 0x4); + tcg_gen_or_i32(tcg_ctx, reg,reg,temp); + tcg_temp_free(tcg_ctx, temp); +} + + +static void flags_to_tcgv(TCGContext *tcg_ctx, TCGv reg) +{ + flags_to_tcgv_z_cy_ov_s_sat(tcg_ctx, reg); + flags_to_tcgv_id_ep_np_ebv_cu_um(tcg_ctx, reg); +} + + +static TCGv condition_satisfied(TCGContext *tcg_ctx, int cond) +{ + TCGv condResult = tcg_temp_new_i32(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, condResult, 0x0); + + switch(cond) { + case GE_COND: + tcg_gen_xor_i32(tcg_ctx, condResult, cpu_SF, cpu_OVF); + tcg_gen_not_i32(tcg_ctx, condResult, condResult); + tcg_gen_andi_i32(tcg_ctx, condResult, condResult, 0x1); + break; + case GT_COND: + tcg_gen_xor_i32(tcg_ctx, condResult, cpu_SF, cpu_OVF); + tcg_gen_or_i32(tcg_ctx, condResult, condResult, cpu_ZF); + tcg_gen_not_i32(tcg_ctx, condResult, condResult); + tcg_gen_andi_i32(tcg_ctx, condResult, condResult, 0x1); + break; + case LE_COND: + tcg_gen_xor_i32(tcg_ctx, condResult, cpu_SF, cpu_OVF); + tcg_gen_or_i32(tcg_ctx, condResult, condResult, cpu_ZF); + break; + case LT_COND: + tcg_gen_xor_i32(tcg_ctx, condResult, cpu_SF, cpu_OVF); + break; + + case H_COND: + tcg_gen_or_i32(tcg_ctx, condResult, cpu_CYF, cpu_ZF); + tcg_gen_not_i32(tcg_ctx, condResult, condResult); + tcg_gen_andi_i32(tcg_ctx, condResult, condResult, 0x1); + break; + case NH_COND: + tcg_gen_or_i32(tcg_ctx, condResult, cpu_CYF, cpu_ZF); + break; + + case NS_COND: + tcg_gen_not_i32(tcg_ctx, condResult, cpu_SF); + tcg_gen_andi_i32(tcg_ctx, condResult, condResult, 0x1); + break; + + case S_COND: + tcg_gen_mov_i32(tcg_ctx, condResult, cpu_SF); + break; + + case C_COND: + tcg_gen_mov_i32(tcg_ctx, condResult, cpu_CYF); + break; + + case NC_COND: + tcg_gen_not_i32(tcg_ctx, condResult, cpu_CYF); + tcg_gen_andi_i32(tcg_ctx, condResult, condResult, 0x1); + break; + case NV_COND: + tcg_gen_not_i32(tcg_ctx, condResult, cpu_OVF); + tcg_gen_andi_i32(tcg_ctx, condResult, condResult, 0x1); + break; + case NZ_COND: + tcg_gen_not_i32(tcg_ctx, condResult, cpu_ZF); + tcg_gen_andi_i32(tcg_ctx, condResult, condResult, 0x1); + break; + + case SA_COND: + tcg_gen_mov_i32(tcg_ctx, condResult, cpu_SATF); + break; + case T_COND: + tcg_gen_movi_i32(tcg_ctx, condResult, 0x1); + break; + case V_COND: + tcg_gen_mov_i32(tcg_ctx, condResult, cpu_OVF); + break; + case Z_COND: + tcg_gen_mov_i32(tcg_ctx, condResult, cpu_ZF); + break; + } + + return condResult; +} + +static void gen_flags_on_add(TCGContext *tcg_ctx, TCGv_i32 t0, TCGv_i32 t1) +{ + TCGLabel *cont; + TCGLabel *end; + + TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, tmp, 0); + // 'add2(rl, rh, al, ah, bl, bh) creates 64-bit values and adds them: + // [CYF : SF] = [tmp : t0] + [tmp : t1] + // While CYF is 0 or 1, SF bit 15 contains sign, so it + // must be shifted 31 bits to the right later. + tcg_gen_add2_i32(tcg_ctx, cpu_SF, cpu_CYF, t0, tmp, t1, tmp); + tcg_gen_mov_i32(tcg_ctx, cpu_ZF, cpu_SF); + + tcg_gen_xor_i32(tcg_ctx, cpu_OVF, cpu_SF, t0); + tcg_gen_xor_i32(tcg_ctx, tmp, t0, t1); + tcg_gen_andc_i32(tcg_ctx, cpu_OVF, cpu_OVF, tmp); + + tcg_gen_shri_i32(tcg_ctx, cpu_SF, cpu_SF, 0x1f); + tcg_gen_shri_i32(tcg_ctx, cpu_OVF, cpu_OVF, 0x1f); + + tcg_temp_free_i32(tcg_ctx, tmp); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, 0x0, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_ZF, 0x1); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_ZF, 0x0); + + gen_set_label(tcg_ctx, end); +} + + +static void gen_satadd_CC(TCGContext *tcg_ctx, TCGv_i32 t0, TCGv_i32 t1, TCGv_i32 result) +{ + TCGLabel *cont; + TCGLabel *end; + + TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, tmp, 0); + tcg_gen_add2_i32(tcg_ctx, cpu_SF, cpu_CYF, t0, tmp, t1, tmp); + tcg_gen_mov_i32(tcg_ctx, cpu_ZF, cpu_SF); + tcg_gen_xor_i32(tcg_ctx, cpu_OVF, cpu_SF, t0); + tcg_gen_xor_i32(tcg_ctx, tmp, t0, t1); + tcg_gen_andc_i32(tcg_ctx, cpu_OVF, cpu_OVF, tmp); + + tcg_gen_shri_i32(tcg_ctx, cpu_SF, result, 0x1f); + tcg_gen_shri_i32(tcg_ctx, cpu_OVF, cpu_OVF, 0x1f); + tcg_temp_free_i32(tcg_ctx, tmp); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, 0x0, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_ZF, 0x1); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_ZF, 0x0); + + gen_set_label(tcg_ctx, end); +} + +static void gen_flags_on_sub(TCGContext *tcg_ctx, TCGv_i32 t0, TCGv_i32 t1) +{ + tcg_gen_sub_tl(tcg_ctx, cpu_SF, t0, t1); + tcg_gen_setcond_i32(tcg_ctx, TCG_COND_GTU, cpu_CYF, t1, t0); + tcg_gen_setcond_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, t0, t1); + tcg_gen_xor_i32(tcg_ctx, cpu_OVF, cpu_SF, t0); + TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx); + tcg_gen_xor_i32(tcg_ctx, tmp, t0, t1); + tcg_gen_and_i32(tcg_ctx, cpu_OVF, cpu_OVF, tmp); + + tcg_gen_shri_i32(tcg_ctx, cpu_SF, cpu_SF, 0x1f); + tcg_gen_shri_i32(tcg_ctx, cpu_OVF, cpu_OVF, 0x1f); + tcg_temp_free_i32(tcg_ctx, tmp); +} + +static void gen_satsub_CC(TCGContext *tcg_ctx, TCGv_i32 t0, TCGv_i32 t1, TCGv_i32 result) +{ + TCGLabel *cont; + TCGLabel *end; + + TCGv_i32 tmp; + tcg_gen_sub_tl(tcg_ctx, cpu_SF, t0, t1); + + tcg_gen_mov_i32(tcg_ctx, cpu_ZF, cpu_SF); + tcg_gen_setcond_i32(tcg_ctx, TCG_COND_GTU, cpu_CYF, t1, t0); + tcg_gen_xor_i32(tcg_ctx, cpu_OVF, cpu_SF, t0); + tmp = tcg_temp_new_i32(tcg_ctx); + tcg_gen_xor_i32(tcg_ctx, tmp, t0, t1); + tcg_gen_and_i32(tcg_ctx, cpu_OVF, cpu_OVF, tmp); + + tcg_gen_shri_i32(tcg_ctx, cpu_SF, result, 0x1f); + tcg_gen_shri_i32(tcg_ctx, cpu_OVF, cpu_OVF, 0x1f); + tcg_temp_free_i32(tcg_ctx, tmp); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, 0x0, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_ZF, 0x1); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_ZF, 0x0); + + gen_set_label(tcg_ctx, end); +} + +static void gen_logic_CC(TCGContext *tcg_ctx, TCGv_i32 result){ + + TCGLabel *cont; + TCGLabel *end; + + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, result, 0x1f); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, result, 0x0, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_ZF, 0x1); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_ZF, 0x0); + + gen_set_label(tcg_ctx, end); +} + + +static void gen_load(DisasContext *ctx, int memop, int rd, int rs1, + target_long imm, unsigned is_disp23) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv t0 = tcg_temp_new(tcg_ctx); + TCGv t1 = tcg_temp_new(tcg_ctx); + TCGv tcg_imm = tcg_temp_new(tcg_ctx); + TCGv_i64 t1_64 = tcg_temp_new_i64(tcg_ctx); + TCGv t1_high = tcg_temp_new(tcg_ctx); + + gen_get_gpr(tcg_ctx, t0, rs1); + tcg_gen_movi_i32(tcg_ctx, tcg_imm, imm); + + if (!is_disp23) + tcg_gen_ext16s_i32(tcg_ctx, tcg_imm, tcg_imm); + else { + tcg_gen_shli_i32(tcg_ctx, tcg_imm, tcg_imm, 9); + tcg_gen_sari_i32(tcg_ctx, tcg_imm, tcg_imm, 9); + } + + tcg_gen_add_tl(tcg_ctx, t0, t0, tcg_imm); + + if (memop == MO_TEQ) { + tcg_gen_qemu_ld_i64(tcg_ctx, t1_64, t0, MEM_IDX, memop); + tcg_gen_extrl_i64_i32(tcg_ctx, t1, t1_64); + tcg_gen_extrh_i64_i32(tcg_ctx, t1_high, t1_64); + gen_set_gpr(tcg_ctx, rd, t1); + gen_set_gpr(tcg_ctx, rd+1, t1_high); + } + else { + tcg_gen_qemu_ld_tl(tcg_ctx, t1, t0, MEM_IDX, memop); + gen_set_gpr(tcg_ctx, rd, t1); + } + + tcg_temp_free(tcg_ctx, t0); + tcg_temp_free(tcg_ctx, t1); + tcg_temp_free(tcg_ctx, tcg_imm); + tcg_temp_free_i64(tcg_ctx, t1_64); + tcg_temp_free(tcg_ctx, t1_high); +} + +static void gen_store(DisasContext *ctx, int memop, int rs1, int rs2, + target_long imm, unsigned is_disp23) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv t0 = tcg_temp_new(tcg_ctx); + TCGv dat = tcg_temp_new(tcg_ctx); + TCGv tcg_imm = tcg_temp_new(tcg_ctx); + TCGv dat_high = tcg_temp_new(tcg_ctx); + TCGv_i64 dat64 = tcg_temp_new_i64(tcg_ctx); + + gen_get_gpr(tcg_ctx, t0, rs1); // loading rs1 to t0 + tcg_gen_movi_i32(tcg_ctx, tcg_imm, imm); + + if (!is_disp23) + tcg_gen_ext16s_i32(tcg_ctx, tcg_imm, tcg_imm); + else { + tcg_gen_shli_i32(tcg_ctx, tcg_imm, tcg_imm, 9); + tcg_gen_sari_i32(tcg_ctx, tcg_imm, tcg_imm, 9); + } + + tcg_gen_add_tl(tcg_ctx, t0, t0, tcg_imm); // adding displacement to t0 + + gen_get_gpr(tcg_ctx, dat, rs2); // getting data from rs2 + + if (memop == MO_TEQ) { + gen_get_gpr(tcg_ctx, dat_high, rs2+1); + tcg_gen_concat_i32_i64(tcg_ctx, dat64, dat, dat_high); + tcg_gen_qemu_st_i64(tcg_ctx, dat64, t0, MEM_IDX, memop); + } + else { + tcg_gen_qemu_st_tl(tcg_ctx, dat, t0, MEM_IDX, memop); + } + + // clear possible mutex + TCGLabel *l = gen_new_label(tcg_ctx); + tcg_gen_brcond_i32(tcg_ctx, TCG_COND_NE, t0, cpu_LLAddress, l); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_LLbit, 0x1, l); + tcg_gen_movi_i32(tcg_ctx, cpu_LLbit, 0); + gen_set_label(tcg_ctx, l); + + tcg_temp_free(tcg_ctx, t0); + tcg_temp_free(tcg_ctx, dat); + tcg_temp_free(tcg_ctx, tcg_imm); + tcg_temp_free_i64(tcg_ctx, dat64); + tcg_temp_free(tcg_ctx, dat_high); +} + +static void gen_mutual_exclusion(DisasContext *ctx, int rs3, int rs1, int operation) +{ + /* LDL.W, STC.W, CLL: Implement as described. + Add two additional global CPU registers called LLBit and LLAddress. + Set them with LDL.W, and reset them with STC.W. + If LLBit is not set or LLAddress does not match STC.W address, make STC.W fail. + CLL clears LLBit. + Since we do not implement multicore CPU emulation, this implementation should be OK. */ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + if (operation == operation_LDL_W) + { + TCGv adr = tcg_temp_new(tcg_ctx); + TCGv dat = tcg_temp_new(tcg_ctx); + + gen_get_gpr(tcg_ctx, adr, rs1); + tcg_gen_qemu_ld_tl(tcg_ctx, dat, adr, MEM_IDX, MO_TESL); + gen_set_gpr(tcg_ctx, rs3, dat); + + tcg_temp_free(tcg_ctx, adr); + tcg_temp_free(tcg_ctx, dat); + + tcg_gen_movi_i32(tcg_ctx, cpu_LLbit, 1); + tcg_gen_mov_i32(tcg_ctx, cpu_LLAddress, adr); + } + else if (operation == operation_STC_W) + { + TCGv adr = tcg_temp_local_new(tcg_ctx); + TCGv dat = tcg_temp_local_new(tcg_ctx); + TCGv token = tcg_temp_local_new(tcg_ctx); + TCGLabel *l_fail = gen_new_label(tcg_ctx); + TCGLabel *l_ok = gen_new_label(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, token, cpu_LLbit); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, token, 0x1, l_fail); + gen_get_gpr(tcg_ctx, adr, rs1); + gen_get_gpr(tcg_ctx, dat, rs3); + tcg_gen_brcond_i32(tcg_ctx, TCG_COND_NE, adr, cpu_LLAddress, l_fail); + tcg_gen_qemu_st_tl(tcg_ctx, dat, adr, MEM_IDX, MO_TESL); + tcg_gen_movi_i32(tcg_ctx, dat, 1); + tcg_gen_br(tcg_ctx, l_ok); + + gen_set_label(tcg_ctx, l_fail); + tcg_gen_movi_i32(tcg_ctx, dat, 0); + gen_set_label(tcg_ctx, l_ok); + gen_set_gpr(tcg_ctx, rs3, dat); + + tcg_gen_movi_tl(tcg_ctx, cpu_LLbit, 0); + + tcg_temp_free(tcg_ctx, adr); + tcg_temp_free(tcg_ctx, dat); + tcg_temp_free(tcg_ctx, token); + } + else if (operation == operation_CLL) + { + tcg_gen_movi_i32(tcg_ctx, cpu_LLbit, 0); + } + else + printf("ERROR gen_mutual_exclusion \n"); +} + + +static void gen_multiply(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv r1 = tcg_temp_new(tcg_ctx); //temp + TCGv r2 = tcg_temp_new(tcg_ctx); //temp + + gen_get_gpr(tcg_ctx, r1, rs1); //loading rs1 to t0 + gen_get_gpr(tcg_ctx, r2, rs2); //loading rs2 to t1 + int imm = rs1; + int imm_32; + int int_rs3; + + TCGv tcg_imm = tcg_temp_new(tcg_ctx); + TCGv tcg_imm32 = tcg_temp_new(tcg_ctx); + TCGv tcg_r3 = tcg_temp_new(tcg_ctx); + TCGv tcg_temp = tcg_temp_new(tcg_ctx); + + switch(operation){ + case OPC_RH850_MUL_reg1_reg2_reg3: + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3,int_rs3); + + tcg_gen_muls2_i32(tcg_ctx, r2, tcg_r3, r1, r2); + if(rs2!=int_rs3){ + gen_set_gpr(tcg_ctx, rs2, r2); + } + gen_set_gpr(tcg_ctx, int_rs3,tcg_r3); + break; + + case OPC_RH850_MUL_imm9_reg2_reg3: + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3,int_rs3); + + imm_32 = extract32(ctx->opcode, 18, 4); + imm_32 = imm | (imm_32 << 5); + + // sign extension + if((imm_32 & 0x100) == 0x100){ + imm_32 = imm_32 | (0x7f << 9); + } + tcg_gen_movi_tl(tcg_ctx, tcg_imm32, imm_32); + tcg_gen_ext16s_tl(tcg_ctx, tcg_imm32, tcg_imm32); + + tcg_gen_muls2_i32(tcg_ctx, r2, tcg_r3, tcg_imm32, r2); + + if(rs2!=int_rs3){ + gen_set_gpr(tcg_ctx, rs2, r2); + } + gen_set_gpr(tcg_ctx, int_rs3, tcg_r3); + break; + + case OPC_RH850_MULH_reg1_reg2: + + tcg_gen_andi_tl(tcg_ctx, r1, r1,0x0000FFFF); + tcg_gen_andi_tl(tcg_ctx, r2, r2,0x0000FFFF); + tcg_gen_ext16s_i32(tcg_ctx, r1, r1); + tcg_gen_ext16s_i32(tcg_ctx, r2, r2); + + tcg_gen_mul_tl(tcg_ctx, r2, r2, r1); + gen_set_gpr(tcg_ctx, rs2, r2); + break; + + case OPC_RH850_MULH_imm5_reg2: + + if ((imm & 0x10) == 0x10){ + imm = imm | (0x7 << 5); + } + tcg_gen_andi_tl(tcg_ctx, r2, r2,0x0000FFFF); + tcg_gen_ext16s_i32(tcg_ctx, r2, r2); + + tcg_gen_movi_tl(tcg_ctx, tcg_imm, imm); + tcg_gen_ext8s_i32(tcg_ctx, tcg_imm, tcg_imm); + tcg_gen_mul_tl(tcg_ctx, r2, r2, tcg_imm); + gen_set_gpr(tcg_ctx, rs2, r2); + break; + + case OPC_RH850_MULHI_imm16_reg1_reg2: + + imm_32 = extract32(ctx->opcode, 16, 16); + tcg_gen_movi_tl(tcg_ctx, tcg_imm32, imm_32); + tcg_gen_ext16s_i32(tcg_ctx, tcg_imm32, tcg_imm32); + + tcg_gen_andi_tl(tcg_ctx, r1, r1, 0x0000FFFF); + tcg_gen_ext16s_i32(tcg_ctx, r1, r1); + + tcg_gen_mul_tl(tcg_ctx, r2, r1, tcg_imm32); + + gen_set_gpr(tcg_ctx, rs2, r2); + break; + + case OPC_RH850_MULU_reg1_reg2_reg3: + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3,int_rs3); + + tcg_gen_mulu2_i32(tcg_ctx, r2, tcg_r3, r2, r1); + + if(rs2!=int_rs3){ + gen_set_gpr(tcg_ctx, rs2, r2); + } + gen_set_gpr(tcg_ctx, int_rs3,tcg_r3); + break; + + case OPC_RH850_MULU_imm9_reg2_reg3: + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3,int_rs3); + + imm_32 = extract32(ctx->opcode, 18, 4); + imm_32 = imm | (imm_32 << 5); + tcg_gen_movi_tl(tcg_ctx, tcg_imm32, imm_32); + + tcg_gen_ext16u_tl(tcg_ctx, tcg_imm32, tcg_imm32); + + tcg_gen_mulu2_i32(tcg_ctx, r2, tcg_r3, tcg_imm32, r2); + + if(rs2!=int_rs3){ + gen_set_gpr(tcg_ctx, rs2, r2); + } + gen_set_gpr(tcg_ctx, int_rs3,tcg_r3); + break; + } + + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, tcg_r3); + tcg_temp_free(tcg_ctx, tcg_temp); + tcg_temp_free(tcg_ctx, tcg_imm); + tcg_temp_free(tcg_ctx, tcg_imm32); +} + +static void gen_mul_accumulate(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv r1 = tcg_temp_new(tcg_ctx); + TCGv r2 = tcg_temp_new(tcg_ctx); + TCGv addLo = tcg_temp_new(tcg_ctx); + TCGv addHi = tcg_temp_new(tcg_ctx); + TCGv resLo = tcg_temp_new(tcg_ctx); + TCGv resHi = tcg_temp_new(tcg_ctx); + TCGv destLo = tcg_temp_new(tcg_ctx); + TCGv destHi = tcg_temp_new(tcg_ctx); + + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + + int rs3; + int rs4; + + rs3 = extract32(ctx->opcode, 28, 4) << 1; + rs4 = extract32(ctx->opcode, 17, 4) << 1; + + gen_get_gpr(tcg_ctx, addLo, rs3); + gen_get_gpr(tcg_ctx, addHi, rs3+1); + + switch(operation){ + case OPC_RH850_MAC_reg1_reg2_reg3_reg4: + + tcg_gen_muls2_i32(tcg_ctx, resLo, resHi, r1, r2); + tcg_gen_add2_i32(tcg_ctx, destLo, destHi, resLo, resHi, addLo, addHi); + + gen_set_gpr(tcg_ctx, rs4, destLo); + gen_set_gpr(tcg_ctx, rs4+1, destHi); + break; + + case OPC_RH850_MACU_reg1_reg2_reg3_reg4: + tcg_gen_mulu2_i32(tcg_ctx, resLo, resHi, r1, r2); + tcg_gen_add2_i32(tcg_ctx, destLo, destHi, resLo, resHi, addLo, addHi); + + gen_set_gpr(tcg_ctx, rs4, destLo); + gen_set_gpr(tcg_ctx, (rs4+1), destHi); + break; + } + + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, addLo); + tcg_temp_free(tcg_ctx, addHi); + tcg_temp_free(tcg_ctx, resLo); + tcg_temp_free(tcg_ctx, resHi); + tcg_temp_free(tcg_ctx, destLo); + tcg_temp_free(tcg_ctx, destHi); + +} + +static void gen_arithmetic(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv r1 = tcg_temp_new(tcg_ctx); + TCGv r2 = tcg_temp_new(tcg_ctx); + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + + int imm = rs1; + int imm_32; + uint64_t opcode48; + + TCGv tcg_imm = tcg_temp_new(tcg_ctx); + TCGv tcg_r3 = tcg_temp_new(tcg_ctx); + TCGv tcg_result = tcg_temp_new(tcg_ctx); + + switch(operation) { + + case OPC_RH850_ADD_reg1_reg2: { + + tcg_gen_add_tl(tcg_ctx, tcg_result, r2, r1); + gen_set_gpr(tcg_ctx, rs2, tcg_result); + + gen_flags_on_add(tcg_ctx, r1, r2); + + } break; + + case OPC_RH850_ADD_imm5_reg2: + if((imm & 0x10) == 0x10){ + imm = imm | (0x7 << 5); + } + tcg_gen_movi_i32(tcg_ctx, tcg_imm, imm); + tcg_gen_ext8s_i32(tcg_ctx, tcg_imm, tcg_imm); + tcg_gen_add_tl(tcg_ctx, tcg_result, r2, tcg_imm); + gen_set_gpr(tcg_ctx, rs2, tcg_result); + + gen_flags_on_add(tcg_ctx, r2, tcg_imm); + + break; + + case OPC_RH850_ADDI_imm16_reg1_reg2: + imm_32 = extract32(ctx->opcode, 16, 16); + tcg_gen_movi_tl(tcg_ctx, tcg_imm, imm_32); + tcg_gen_ext16s_tl(tcg_ctx, tcg_imm, tcg_imm); + tcg_gen_add_tl(tcg_ctx, r2,r1, tcg_imm); + gen_set_gpr(tcg_ctx, rs2, r2); + + gen_flags_on_add(tcg_ctx, r1, tcg_imm); + + break; + + case OPC_RH850_CMP_reg1_reg2: { + gen_flags_on_sub(tcg_ctx, r2, r1); + } break; + + case OPC_RH850_CMP_imm5_reg2: { + + if ((imm & 0x10) == 0x10){ + imm = imm | (0x7 << 5); + } + tcg_gen_movi_tl(tcg_ctx, tcg_imm, imm); + tcg_gen_ext8s_i32(tcg_ctx, tcg_imm, tcg_imm); + + gen_flags_on_sub(tcg_ctx, r2, tcg_imm); + + } break; + + case OPC_RH850_MOV_reg1_reg2: + tcg_gen_mov_tl(tcg_ctx, r2, r1); + gen_set_gpr(tcg_ctx, rs2, r2); + break; + + case OPC_RH850_MOV_imm5_reg2: + if ((imm & 0x10) == 0x10){ + imm = imm | (0x7 << 5); + } + tcg_gen_movi_tl(tcg_ctx, r2, imm); + tcg_gen_ext8s_i32(tcg_ctx, r2, r2); + + gen_set_gpr(tcg_ctx, rs2, r2); + break; + + case OPC_RH850_MOV_imm32_reg1: // 48bit instruction + opcode48 = (ctx->opcode1); + opcode48 = (ctx->opcode) | (opcode48 << 0x20); + imm_32 = extract64(opcode48, 16, 32) & 0xffffffff; + tcg_gen_movi_i32(tcg_ctx, r2, imm_32); + gen_set_gpr(tcg_ctx, rs2, r2); + break; + + case OPC_RH850_MOVEA_imm16_reg1_reg2: + imm_32 = extract32(ctx->opcode, 16, 16); + tcg_gen_movi_i32(tcg_ctx, tcg_imm, imm_32); + tcg_gen_ext16s_i32(tcg_ctx, tcg_imm, tcg_imm); + + tcg_gen_add_i32(tcg_ctx, r2, tcg_imm, r1); + gen_set_gpr(tcg_ctx, rs2, r2); + break; + + case OPC_RH850_MOVHI_imm16_reg1_reg2: + imm_32 = extract32(ctx->opcode, 16, 16); + tcg_gen_movi_i32(tcg_ctx, tcg_imm, imm_32); + tcg_gen_shli_i32(tcg_ctx, tcg_imm, tcg_imm, 0x10); + + tcg_gen_add_i32(tcg_ctx, r2, tcg_imm, r1); + gen_set_gpr(tcg_ctx, rs2, r2); + break; + + case OPC_RH850_SUB_reg1_reg2: + + tcg_gen_sub_tl(tcg_ctx, tcg_result, r2, r1); + gen_set_gpr(tcg_ctx, rs2, tcg_result); + gen_flags_on_sub(tcg_ctx, r2, r1); + break; + + case OPC_RH850_SUBR_reg1_reg2: + tcg_gen_sub_tl(tcg_ctx, tcg_result, r1, r2); + gen_set_gpr(tcg_ctx, rs2, tcg_result); + gen_flags_on_sub(tcg_ctx, r1, r2); + break; + } + + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, tcg_imm); + tcg_temp_free(tcg_ctx, tcg_r3); + tcg_temp_free(tcg_ctx, tcg_result); +} + +static void gen_cond_arith(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv r1 = tcg_temp_local_new(tcg_ctx); + TCGv r2 = tcg_temp_local_new(tcg_ctx); + + TCGLabel *cont; + + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + + int int_rs3; + int int_cond; + + switch(operation){ + + case OPC_RH850_ADF_cccc_reg1_reg2_reg3:{ + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv addIfCond = tcg_temp_local_new_i32(tcg_ctx); + TCGv carry = tcg_temp_local_new_i32(tcg_ctx); + TCGv overflow = tcg_temp_local_new_i32(tcg_ctx); + + tcg_gen_movi_tl(tcg_ctx, carry, 0); + tcg_gen_movi_tl(tcg_ctx, overflow, 0); + + int_rs3 = extract32(ctx->opcode, 27, 5); + int_cond = extract32(ctx->opcode, 17, 4); + if(int_cond == 0xd){ + //throw exception/warning for inappropriate condition (SA) + break; + } + + tcg_gen_mov_i32(tcg_ctx, r1_local, r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, r2); + gen_get_gpr(tcg_ctx, r3_local,int_rs3); + tcg_gen_movi_i32(tcg_ctx, addIfCond, 0x1); + + TCGv condResult = condition_satisfied(tcg_ctx, int_cond); + cont = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, condResult, 0x1, cont); + // calc and store CY and OV flags to be used to obtain final values + gen_flags_on_add(tcg_ctx, r2_local, addIfCond); + tcg_gen_mov_tl(tcg_ctx, carry, cpu_CYF); + tcg_gen_mov_tl(tcg_ctx, overflow, cpu_OVF); + // on cond true, add 1 + tcg_gen_add_tl(tcg_ctx, r2_local, r2_local, addIfCond); + + gen_set_label(tcg_ctx, cont); + tcg_gen_add_tl(tcg_ctx, r3_local, r1_local, r2_local); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + + gen_flags_on_add(tcg_ctx, r1_local, r2_local); + tcg_gen_or_tl(tcg_ctx, cpu_CYF, cpu_CYF, carry); + tcg_gen_or_tl(tcg_ctx, cpu_OVF, cpu_OVF, overflow); + + tcg_temp_free(tcg_ctx, condResult); + tcg_temp_free_i32(tcg_ctx, r1_local); + tcg_temp_free_i32(tcg_ctx, r2_local); + tcg_temp_free_i32(tcg_ctx, r3_local); + tcg_temp_free_i32(tcg_ctx, addIfCond); + } + break; + + case OPC_RH850_SBF_cccc_reg1_reg2_reg3:{ + + int_rs3 = extract32(ctx->opcode, 27, 5); + int_cond = extract32(ctx->opcode, 17, 4); + if(int_cond == 0xd){ + //throw exception/warning for inappropriate condition (SA) + break; + } + + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + TCGv tmpReg = tcg_temp_local_new(tcg_ctx); + TCGv carry = tcg_temp_local_new(tcg_ctx); + TCGv overflow = tcg_temp_local_new(tcg_ctx); + cont = gen_new_label(tcg_ctx); + + tcg_gen_movi_tl(tcg_ctx, carry, 0); + tcg_gen_movi_tl(tcg_ctx, overflow, 0); + + tcg_gen_mov_i32(tcg_ctx, r3_local, r2); + + TCGv condResult = condition_satisfied(tcg_ctx, int_cond); + // store to local temp, because condResult is valid only until branch in gen_flags_on_sub + tcg_gen_mov_tl(tcg_ctx, tmpReg, condResult); + + gen_flags_on_sub(tcg_ctx, r3_local, r1); + tcg_gen_mov_tl(tcg_ctx, carry, cpu_CYF); + tcg_gen_mov_tl(tcg_ctx, overflow, cpu_OVF); + tcg_gen_sub_tl(tcg_ctx, r3_local, r3_local, r1); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, tmpReg, 0x1, cont); + tcg_gen_movi_i32(tcg_ctx, tmpReg, 0x1); + gen_flags_on_sub(tcg_ctx, r3_local, tmpReg); + tcg_gen_subi_tl(tcg_ctx, r3_local, r3_local, 1); + tcg_gen_or_tl(tcg_ctx, cpu_CYF, cpu_CYF, carry); + // overflow twice means no overflow + tcg_gen_xor_tl(tcg_ctx, cpu_OVF, cpu_OVF, overflow); + + gen_set_label(tcg_ctx, cont); + + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + + tcg_temp_free(tcg_ctx, condResult); + tcg_temp_free_i32(tcg_ctx, r3_local); + tcg_temp_free_i32(tcg_ctx, tmpReg); + tcg_temp_free_i32(tcg_ctx, overflow); + tcg_temp_free_i32(tcg_ctx, carry); + } + break; + } + + tcg_temp_free_i32(tcg_ctx, r1); + tcg_temp_free_i32(tcg_ctx, r2); +} + +static void gen_sat_op(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv r1 = tcg_temp_new(tcg_ctx); + TCGv r2 = tcg_temp_new(tcg_ctx); + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + + int imm = rs1; + int int_rs3; + + TCGLabel *end; + TCGLabel *cont; + TCGLabel *cont2; + TCGLabel *setMax; + TCGLabel *dontChange; + + switch(operation){ + + case OPC_RH850_SATADD_reg1_reg2: { + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv min = tcg_temp_local_new(tcg_ctx); + TCGv max = tcg_temp_local_new(tcg_ctx); + TCGv zero = tcg_temp_local_new(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, min, 0x80000000); + tcg_gen_movi_i32(tcg_ctx, max, 0x7fffffff); + tcg_gen_mov_i32(tcg_ctx, r1_local, r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, r2); + tcg_gen_movi_i32(tcg_ctx, zero, 0x0); + end = gen_new_label(tcg_ctx); + cont = gen_new_label(tcg_ctx); + cont2 = gen_new_label(tcg_ctx); + + + tcg_gen_add_i32(tcg_ctx, result, r1_local, r2_local); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LT, r1_local, zero, cont); + + tcg_gen_sub_i32(tcg_ctx, check, max, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LE, r2_local, check, end); + tcg_gen_mov_i32(tcg_ctx, result, max); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + tcg_gen_br(tcg_ctx, end); + + //--------------------------------------------------------------------------------- + gen_set_label(tcg_ctx, cont); + tcg_gen_sub_i32(tcg_ctx, check, min, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_GE, r2_local, check, cont2); + tcg_gen_mov_i32(tcg_ctx, result, min); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + + gen_set_label(tcg_ctx, cont2); + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, result); + + gen_satadd_CC(tcg_ctx, r1_local, r2_local, result); // moves also SET flag to psw + + tcg_temp_free(tcg_ctx, result); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, min); + tcg_temp_free(tcg_ctx, max); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, zero); + + } break; + + case OPC_RH850_SATADD_imm5_reg2: { + + TCGv imm_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv min = tcg_temp_local_new(tcg_ctx); + TCGv max = tcg_temp_local_new(tcg_ctx); + TCGv zero = tcg_temp_local_new(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, min, 0x80000000); + tcg_gen_movi_i32(tcg_ctx, max, 0x7fffffff); + tcg_gen_mov_i32(tcg_ctx, r2_local, r2); + tcg_gen_movi_i32(tcg_ctx, zero, 0x0); + end = gen_new_label(tcg_ctx); + cont = gen_new_label(tcg_ctx); + cont2 = gen_new_label(tcg_ctx); + + if ((imm & 0x10) == 0x10){ + imm = imm | (0x7 << 5); + } + + tcg_gen_movi_tl(tcg_ctx, imm_local, imm); + tcg_gen_ext8s_tl(tcg_ctx, imm_local, imm_local); + + tcg_gen_add_i32(tcg_ctx, result, imm_local, r2_local); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LT, imm_local, zero, cont); + + tcg_gen_sub_i32(tcg_ctx, check, max, imm_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LE, r2_local, check, end); + tcg_gen_mov_i32(tcg_ctx, result, max); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + tcg_gen_br(tcg_ctx, end); + + //--------------------------------------------------------------------------------- + gen_set_label(tcg_ctx, cont); + tcg_gen_sub_i32(tcg_ctx, check, min, imm_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_GE, r2_local, check, cont2); + tcg_gen_mov_i32(tcg_ctx, result, min); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + + gen_set_label(tcg_ctx, cont2); + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, result); + + gen_satadd_CC(tcg_ctx, r2_local, imm_local, result); + + tcg_temp_free(tcg_ctx, result); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, min); + tcg_temp_free(tcg_ctx, max); + tcg_temp_free(tcg_ctx, imm_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, zero); + + } break; + + case OPC_RH850_SATADD_reg1_reg2_reg3: { + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv min = tcg_temp_local_new(tcg_ctx); + TCGv max = tcg_temp_local_new(tcg_ctx); + TCGv zero = tcg_temp_local_new(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, min, 0x80000000); + tcg_gen_movi_i32(tcg_ctx, max, 0x7fffffff); + tcg_gen_mov_i32(tcg_ctx, r1_local, r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, r2); + tcg_gen_movi_i32(tcg_ctx, zero, 0x0); + end = gen_new_label(tcg_ctx); + cont = gen_new_label(tcg_ctx); + cont2 = gen_new_label(tcg_ctx); + + int_rs3 = extract32(ctx->opcode, 27, 5); + tcg_gen_add_i32(tcg_ctx, result, r1_local, r2_local); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LT, r1_local, zero, cont); //if (r1 > 0) + + tcg_gen_sub_i32(tcg_ctx, check, max, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LE, r2_local, check, end); //if (r2 > MAX-r1) + tcg_gen_mov_i32(tcg_ctx, result, max); //return MAX; + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + tcg_gen_br(tcg_ctx, end); + + //--------------------------------------------------------------------------------- + gen_set_label(tcg_ctx, cont); //else + tcg_gen_sub_i32(tcg_ctx, check, min, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_GE, r2_local, check, cont2); //if (r2 < MIN-r1) + tcg_gen_mov_i32(tcg_ctx, result, min); //return MIN; + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + + gen_set_label(tcg_ctx, cont2); + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, int_rs3, result); + + gen_satadd_CC(tcg_ctx, r1_local, r2_local, result); + + tcg_temp_free(tcg_ctx, result); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, min); + tcg_temp_free(tcg_ctx, max); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, zero); + + } break; + + case OPC_RH850_SATSUB_reg1_reg2: { + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv min = tcg_temp_local_new(tcg_ctx); + TCGv max = tcg_temp_local_new(tcg_ctx); + TCGv zero = tcg_temp_local_new(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, min, 0x80000000); + tcg_gen_movi_i32(tcg_ctx, max, 0x7fffffff); + tcg_gen_mov_i32(tcg_ctx, r1_local, r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, r2); + tcg_gen_movi_i32(tcg_ctx, zero, 0x0); + end = gen_new_label(tcg_ctx); + cont = gen_new_label(tcg_ctx); + cont2 = gen_new_label(tcg_ctx); + setMax = gen_new_label(tcg_ctx); + dontChange = gen_new_label(tcg_ctx); + + /* + * Negating second operand and using satadd code. When negating an operand + * with value 0x80000000, the result overflows positive numbers and is not + * negated. If this happens, the operand is first incremented, and then negated. + * The second operand is as well incremented, if it's value is less than 0x7fffffff. + * Otherwise, the result is set to MAX and SATF is set. + * This was done in all following saturated subtraction functions. + */ + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, r1_local, 0x80000000, dontChange); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r2_local, 0x7fffffff, setMax); + + tcg_gen_addi_i32(tcg_ctx, r1_local, r1_local, 0x1); + tcg_gen_addi_i32(tcg_ctx, r2_local, r2_local, 0x1); + gen_set_label(tcg_ctx, dontChange); + + tcg_gen_neg_i32(tcg_ctx, r1_local, r1_local); + tcg_gen_add_i32(tcg_ctx, result, r1_local, r2_local); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LT, r1_local, zero, cont); + + tcg_gen_sub_i32(tcg_ctx, check, max, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LE, r2_local, check, end); + gen_set_label(tcg_ctx, setMax); + tcg_gen_mov_i32(tcg_ctx, result, max); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + tcg_gen_br(tcg_ctx, end); + + //--------------------------------------------------------------------------------- + gen_set_label(tcg_ctx, cont); + tcg_gen_sub_i32(tcg_ctx, check, min, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_GE, r2_local, check, cont2); + tcg_gen_mov_i32(tcg_ctx, result, min); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + + gen_set_label(tcg_ctx, cont2); + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, result); + + // second negation is needed for appropriate flag calculation + tcg_gen_neg_i32(tcg_ctx, r1_local, r1_local); + gen_satsub_CC(tcg_ctx, r2_local, r1_local, result); + + tcg_temp_free(tcg_ctx, result); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, min); + tcg_temp_free(tcg_ctx, max); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, zero); + + } break; + + case OPC_RH850_SATSUB_reg1_reg2_reg3: { + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv min = tcg_temp_local_new(tcg_ctx); + TCGv max = tcg_temp_local_new(tcg_ctx); + TCGv zero = tcg_temp_local_new(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, min, 0x80000000); + tcg_gen_movi_i32(tcg_ctx, max, 0x7fffffff); + tcg_gen_mov_i32(tcg_ctx, r1_local, r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, r2); + tcg_gen_movi_i32(tcg_ctx, zero, 0x0); + end = gen_new_label(tcg_ctx); + cont = gen_new_label(tcg_ctx); + cont2 = gen_new_label(tcg_ctx); + setMax = gen_new_label(tcg_ctx); + dontChange = gen_new_label(tcg_ctx); + int_rs3 = extract32(ctx->opcode, 27, 5); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, r1_local, 0x80000000, dontChange); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r2_local, 0x7fffffff, setMax); + + tcg_gen_addi_i32(tcg_ctx, r1_local, r1_local, 0x1); + tcg_gen_addi_i32(tcg_ctx, r2_local, r2_local, 0x1); + gen_set_label(tcg_ctx, dontChange); + + tcg_gen_neg_i32(tcg_ctx, r1_local, r1_local); + tcg_gen_add_i32(tcg_ctx, result, r1_local, r2_local); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LT, r1_local, zero, cont); + + tcg_gen_sub_i32(tcg_ctx, check, max, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LE, r2_local, check, end); + gen_set_label(tcg_ctx, setMax); + tcg_gen_mov_i32(tcg_ctx, result, max); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + tcg_gen_br(tcg_ctx, end); + + //--------------------------------------------------------------------------------- + gen_set_label(tcg_ctx, cont); + tcg_gen_sub_i32(tcg_ctx, check, min, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_GE, r2_local, check, cont2); + tcg_gen_mov_i32(tcg_ctx, result, min); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + + gen_set_label(tcg_ctx, cont2); + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, int_rs3, result); + + tcg_gen_neg_i32(tcg_ctx, r1_local, r1_local); + gen_satsub_CC(tcg_ctx, r2_local, r1_local, result); + + tcg_temp_free(tcg_ctx, result); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, min); + tcg_temp_free(tcg_ctx, max); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, zero); + + } break; + + case OPC_RH850_SATSUBI_imm16_reg1_reg2: { + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv imm_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv min = tcg_temp_local_new(tcg_ctx); + TCGv max = tcg_temp_local_new(tcg_ctx); + TCGv zero = tcg_temp_local_new(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, min, 0x80000000); + tcg_gen_movi_i32(tcg_ctx, max, 0x7fffffff); + tcg_gen_mov_i32(tcg_ctx, r1_local, r1); + imm = extract32(ctx->opcode, 16, 16); + tcg_gen_movi_i32(tcg_ctx, imm_local, imm); + tcg_gen_ext16s_i32(tcg_ctx, imm_local, imm_local); + tcg_gen_movi_i32(tcg_ctx, zero, 0x0); + end = gen_new_label(tcg_ctx); + cont = gen_new_label(tcg_ctx); + cont2 = gen_new_label(tcg_ctx); + setMax = gen_new_label(tcg_ctx); + dontChange = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, r1_local, 0x80000000, dontChange); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, imm_local, 0x7fffffff, setMax); + + tcg_gen_addi_i32(tcg_ctx, r1_local, r1_local, 0x1); + tcg_gen_addi_i32(tcg_ctx, imm_local, imm_local, 0x1); + gen_set_label(tcg_ctx, dontChange); + + + tcg_gen_neg_i32(tcg_ctx, imm_local, imm_local); + + tcg_gen_add_i32(tcg_ctx, result, r1_local, imm_local); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LT, r1_local, zero, cont); + + tcg_gen_sub_i32(tcg_ctx, check, max, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LE, imm_local, check, end); + gen_set_label(tcg_ctx, setMax); + tcg_gen_mov_i32(tcg_ctx, result, max); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + tcg_gen_br(tcg_ctx, end); + + //--------------------------------------------------------------------------------- + gen_set_label(tcg_ctx, cont); + tcg_gen_sub_i32(tcg_ctx, check, min, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_GE, imm_local, check, cont2); + tcg_gen_mov_i32(tcg_ctx, result, min); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + + gen_set_label(tcg_ctx, cont2); + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, result); + + tcg_gen_neg_i32(tcg_ctx, imm_local, imm_local); + gen_satsub_CC(tcg_ctx, r1_local, imm_local, result); + + tcg_temp_free(tcg_ctx, result); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, min); + tcg_temp_free(tcg_ctx, max); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, imm_local); + tcg_temp_free(tcg_ctx, zero); + + } break; + + case OPC_RH850_SATSUBR_reg1_reg2: { + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv min = tcg_temp_local_new(tcg_ctx); + TCGv max = tcg_temp_local_new(tcg_ctx); + TCGv zero = tcg_temp_local_new(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, min, 0x80000000); + tcg_gen_movi_i32(tcg_ctx, max, 0x7fffffff); + tcg_gen_mov_i32(tcg_ctx, r1_local, r2); + tcg_gen_mov_i32(tcg_ctx, r2_local, r1); + tcg_gen_movi_i32(tcg_ctx, zero, 0x0); + end = gen_new_label(tcg_ctx); + cont = gen_new_label(tcg_ctx); + cont2 = gen_new_label(tcg_ctx); + setMax = gen_new_label(tcg_ctx); + dontChange = gen_new_label(tcg_ctx); + + /* + * Negating second operand and using satadd code. When negating an operand + * with value 0x80000000, the result overflows positive numbers and is not + * negated. If this happens, the operand is first incremented, and then negated. + * The second operand is as well incremented, if it's value is less than 0x7fffffff. + * Otherwise, the result is set to MAX and SATF is set. + * This was done in all following saturated subtraction functions. + */ + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, r1_local, 0x80000000, dontChange); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r2_local, 0x7fffffff, setMax); + + tcg_gen_addi_i32(tcg_ctx, r1_local, r1_local, 0x1); + tcg_gen_addi_i32(tcg_ctx, r2_local, r2_local, 0x1); + gen_set_label(tcg_ctx, dontChange); + + tcg_gen_neg_i32(tcg_ctx, r1_local, r1_local); + tcg_gen_add_i32(tcg_ctx, result, r1_local, r2_local); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LT, r1_local, zero, cont); + + tcg_gen_sub_i32(tcg_ctx, check, max, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_LE, r2_local, check, end); + gen_set_label(tcg_ctx, setMax); + tcg_gen_mov_i32(tcg_ctx, result, max); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + tcg_gen_br(tcg_ctx, end); + + //--------------------------------------------------------------------------------- + gen_set_label(tcg_ctx, cont); + tcg_gen_sub_i32(tcg_ctx, check, min, r1_local); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_GE, r2_local, check, cont2); + tcg_gen_mov_i32(tcg_ctx, result, min); + tcg_gen_movi_i32(tcg_ctx, cpu_SATF, 0x1); + + gen_set_label(tcg_ctx, cont2); + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, result); + + tcg_gen_neg_i32(tcg_ctx, r1_local, r1_local); + gen_satsub_CC(tcg_ctx, r2_local, r1_local, result); + + tcg_temp_free(tcg_ctx, result); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, min); + tcg_temp_free(tcg_ctx, max); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, zero); + + } break; + } + + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); +} + +static void gen_logical(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv r1 = tcg_temp_new(tcg_ctx); + TCGv r2 = tcg_temp_new(tcg_ctx); + TCGv result = tcg_temp_new(tcg_ctx); + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + + int imm_32; + TCGv tcg_imm = tcg_temp_new(tcg_ctx); + + switch(operation){ + + case OPC_RH850_AND_reg1_reg2: + tcg_gen_and_tl(tcg_ctx, r2, r2, r1); + gen_set_gpr(tcg_ctx, rs2, r2); + gen_logic_CC(tcg_ctx, r2); + break; + + case OPC_RH850_ANDI_imm16_reg1_reg2: + imm_32 = extract32(ctx->opcode, 16, 16); + tcg_gen_movi_tl(tcg_ctx, tcg_imm, imm_32); + tcg_gen_ext16u_i32(tcg_ctx, tcg_imm, tcg_imm); + tcg_gen_and_i32(tcg_ctx, r2, r1, tcg_imm); + gen_set_gpr(tcg_ctx, rs2, r2); + gen_logic_CC(tcg_ctx, r2); + break; + + case OPC_RH850_NOT_reg1_reg2: + tcg_gen_not_i32(tcg_ctx, r2, r1); + gen_set_gpr(tcg_ctx, rs2, r2); + gen_logic_CC(tcg_ctx, r2); + break; + + case OPC_RH850_OR_reg1_reg2: + tcg_gen_or_tl(tcg_ctx, r2, r2, r1); + gen_set_gpr(tcg_ctx, rs2, r2); + gen_logic_CC(tcg_ctx, r2); + break; + + case OPC_RH850_ORI_imm16_reg1_reg2: + imm_32 = extract32(ctx->opcode, 16, 16); + tcg_gen_movi_i32(tcg_ctx, tcg_imm, imm_32); + tcg_gen_ext16u_i32(tcg_ctx, tcg_imm,tcg_imm); + + tcg_gen_or_i32(tcg_ctx, r2, r1, tcg_imm); + gen_set_gpr(tcg_ctx, rs2, r2); + gen_logic_CC(tcg_ctx, r2); + break; + + case OPC_RH850_TST_reg1_reg2: + tcg_gen_and_i32(tcg_ctx, result, r1, r2); + gen_logic_CC(tcg_ctx, result); + break; + + case OPC_RH850_XOR_reg1_reg2: + tcg_gen_xor_i32(tcg_ctx, result, r2, r1); + gen_set_gpr(tcg_ctx, rs2, result); + gen_logic_CC(tcg_ctx, result); + break; + + case OPC_RH850_XORI_imm16_reg1_reg2: + imm_32 = extract32(ctx->opcode, 16, 16); + tcg_gen_movi_i32(tcg_ctx, tcg_imm, imm_32); + tcg_gen_ext16u_i32(tcg_ctx, tcg_imm,tcg_imm); + + tcg_gen_xor_i32(tcg_ctx, result, r1, tcg_imm); + gen_set_gpr(tcg_ctx, rs2, result); + gen_logic_CC(tcg_ctx, result); + break; + } + + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, tcg_imm); + tcg_temp_free(tcg_ctx, result); +} + +static void gen_data_manipulation(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv tcg_r1 = tcg_temp_new(tcg_ctx); + TCGv tcg_r2 = tcg_temp_new(tcg_ctx); + TCGv tcg_r3 = tcg_temp_new(tcg_ctx); + TCGv tcg_imm = tcg_temp_new(tcg_ctx); + TCGv tcg_temp = tcg_temp_new(tcg_ctx); + TCGv tcg_temp2 = tcg_temp_new(tcg_ctx); + TCGv insert = tcg_temp_new(tcg_ctx); + + TCGLabel *cont; + TCGLabel *end; + TCGLabel *set; + + int int_imm = rs1; + int int_rs3; + int int_cond; + int pos; + int lsb; + int msb; + int width; + int mask; + int group; + + gen_get_gpr(tcg_ctx, tcg_r1, rs1); + gen_get_gpr(tcg_ctx, tcg_r2, rs2); + + switch(operation) { + + case OPC_RH850_BINS: + + group = extract32(ctx->opcode, 21, 2); + + mask = 0; + pos = extract32(ctx->opcode, 17, 3) | (extract32(ctx->opcode, 27, 1) << 3); + lsb = pos; + + msb = extract32(ctx->opcode, 28, 4); + width = extract32(ctx->opcode, 28, 4) - pos + 1; + + switch(group){ + case 0: //bins0 + pos += 16; + break; + case 1: //bins1 + width += 16; + msb+=16; + break; + case 2: //bins2 + break; + } + + if(msb<lsb){ + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, tcg_r2, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, tcg_r2, 0x0); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + break; + } + + for(int i = 0; i < width; i++){ + mask = mask | (0x1 << i); + } + + tcg_gen_andi_i32(tcg_ctx, insert, tcg_r1, mask); //insert has the bits from reg1 + + tcg_gen_movi_i32(tcg_ctx, tcg_temp, mask); + tcg_gen_shli_i32(tcg_ctx, tcg_temp, tcg_temp, pos); //inverting and shifting the mask + tcg_gen_not_i32(tcg_ctx, tcg_temp, tcg_temp); //for deletion of bits in reg2 + + tcg_gen_and_i32(tcg_ctx, tcg_r2, tcg_r2, tcg_temp); //deleting bits that will be replaced + tcg_gen_shli_i32(tcg_ctx, insert, insert, pos); //shifting bits to right position + tcg_gen_or_i32(tcg_ctx, tcg_r2, tcg_r2, insert); //placing bits into reg2 + + gen_set_gpr(tcg_ctx, rs2, tcg_r2); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, tcg_r2, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, tcg_r2, 0x0); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + break; + + case OPC_RH850_BSH_reg2_reg3: { + + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv count_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + + + int_rs3 = extract32(ctx->opcode, 27, 5); + tcg_gen_mov_tl(tcg_ctx, tcg_temp2, tcg_r2); + tcg_gen_movi_i32(tcg_ctx, tcg_r3, 0x0); + + tcg_gen_andi_tl(tcg_ctx, tcg_temp, tcg_temp2, 0xff000000); + tcg_gen_shri_tl(tcg_ctx, tcg_temp, tcg_temp, 0x8); + tcg_gen_or_tl(tcg_ctx, tcg_r3, tcg_r3, tcg_temp); + + tcg_gen_andi_tl(tcg_ctx, tcg_temp, tcg_temp2, 0x00ff0000); + tcg_gen_shli_tl(tcg_ctx, tcg_temp, tcg_temp, 0x8); + tcg_gen_or_tl(tcg_ctx, tcg_r3, tcg_r3, tcg_temp); + + tcg_gen_andi_tl(tcg_ctx, tcg_temp, tcg_temp2, 0x0000ff00); + tcg_gen_shri_tl(tcg_ctx, tcg_temp, tcg_temp, 0x8); + tcg_gen_or_tl(tcg_ctx, tcg_r3, tcg_r3, tcg_temp); + + tcg_gen_andi_tl(tcg_ctx, tcg_temp, tcg_temp2, 0x000000ff); + tcg_gen_shli_tl(tcg_ctx, tcg_temp, tcg_temp, 0x8); + tcg_gen_or_tl(tcg_ctx, tcg_r3, tcg_r3, tcg_temp); + + gen_set_gpr(tcg_ctx, int_rs3, tcg_r3); + + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + set = gen_new_label(tcg_ctx); + tcg_gen_andi_i32(tcg_ctx, temp_local, r3_local, 0x0000ffff); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, temp_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r3_local, 0x1f); + + tcg_gen_movi_i32(tcg_ctx, count_local, 0x0); + + tcg_gen_andi_i32(tcg_ctx, temp_local, r3_local, 0x000000ff); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, temp_local, 0x0, set); + tcg_gen_andi_i32(tcg_ctx, temp_local, r3_local, 0x0000ff00); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, temp_local, 0x0, set); + + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, set);//// + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x1); + + gen_set_label(tcg_ctx, end);//// + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, count_local); + tcg_temp_free(tcg_ctx, temp_local); + } break; + + case OPC_RH850_BSW_reg2_reg3: { + + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv count_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + set = gen_new_label(tcg_ctx); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3,int_rs3); + tcg_gen_bswap32_i32(tcg_ctx, tcg_r3, tcg_r2); + gen_set_gpr(tcg_ctx, int_rs3, tcg_r3); + + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r3_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r3_local, 0x1f); + + tcg_gen_movi_i32(tcg_ctx, count_local, 0x0); + + gen_set_label(tcg_ctx, cont);//// + + tcg_gen_andi_i32(tcg_ctx, temp_local, r3_local, 0x000000ff); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, temp_local, 0x0, set);//// + tcg_gen_addi_i32(tcg_ctx, count_local, count_local, 0x1); + tcg_gen_shri_i32(tcg_ctx, r3_local, r3_local, 0x8); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, count_local, 0x4, cont);//// + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, set); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x1); + + gen_set_label(tcg_ctx, end); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, count_local); + tcg_temp_free(tcg_ctx, temp_local); + } + break; + + case OPC_RH850_CMOV_cccc_reg1_reg2_reg3: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + + int_rs3 = extract32(ctx->opcode, 27, 5); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + int_cond = extract32(ctx->opcode, 17, 4); + TCGv condResult = condition_satisfied(tcg_ctx, int_cond); + cont = gen_new_label(tcg_ctx); + + tcg_gen_mov_tl(tcg_ctx, r3_local, r2_local); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, condResult, 0x1, cont); + tcg_gen_mov_tl(tcg_ctx, r3_local, r1_local); + gen_set_label(tcg_ctx, cont); + + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + + tcg_temp_free(tcg_ctx, condResult); + tcg_temp_free_i32(tcg_ctx, r1_local); + tcg_temp_free_i32(tcg_ctx, r2_local); + tcg_temp_free_i32(tcg_ctx, r3_local); + } + break; + + case OPC_RH850_CMOV_cccc_imm5_reg2_reg3: { + + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + + if (int_imm & 0x10) { // if is sign bit in imm5 set + int_imm = int_imm | 0xffffffe0; + } + + int_cond = extract32(ctx->opcode, 17, 4); + TCGv condResult = condition_satisfied(tcg_ctx, int_cond); + cont = gen_new_label(tcg_ctx); + + tcg_gen_mov_tl(tcg_ctx, r3_local, tcg_r2); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, condResult, 0x1, cont); + tcg_gen_movi_tl(tcg_ctx, r3_local, int_imm); + + gen_set_label(tcg_ctx, cont); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + + tcg_temp_free(tcg_ctx, condResult); + tcg_temp_free_i32(tcg_ctx, r3_local); + } + break; + + case OPC_RH850_HSH_reg2_reg3: + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_set_gpr(tcg_ctx, int_rs3, tcg_r2); + + tcg_gen_shri_i32(tcg_ctx, cpu_SF, tcg_r2, 0x1f); + tcg_gen_andi_i32(tcg_ctx, tcg_temp, tcg_r2, 0x0000ffff); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, tcg_temp, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_CYF, tcg_temp, 0x0); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + break; + + case OPC_RH850_HSW_reg2_reg3: { + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv count_local = tcg_temp_local_new_i32(tcg_ctx); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + set = gen_new_label(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, r3_local,int_rs3); + + tcg_gen_andi_tl(tcg_ctx, temp_local, r2_local, 0xffff); + tcg_gen_shli_tl(tcg_ctx, temp_local, temp_local, 0x10); + tcg_gen_andi_tl(tcg_ctx, temp2_local, r2_local, 0xffff0000); + tcg_gen_shri_tl(tcg_ctx, temp2_local, temp2_local, 0x10); + + tcg_gen_or_tl(tcg_ctx, r3_local, temp2_local, temp_local); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r3_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r3_local, 0x1f); + + tcg_gen_movi_i32(tcg_ctx, count_local, 0x0); + + gen_set_label(tcg_ctx, cont); + + tcg_gen_andi_i32(tcg_ctx, temp3_local, r3_local, 0x0000ffff); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, temp3_local, 0x0, set); + tcg_gen_andi_i32(tcg_ctx, temp3_local, r3_local, 0xffff0000); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, temp3_local, 0x0, set); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, set);//// + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x1); + + gen_set_label(tcg_ctx, end);//// + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, count_local); + tcg_temp_free(tcg_ctx, temp_local); + tcg_temp_free(tcg_ctx, temp2_local); + tcg_temp_free(tcg_ctx, temp3_local); + } + break; + + case OPC_RH850_ROTL_imm5_reg2_reg3: + { + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv imm_local = tcg_temp_local_new_i32(tcg_ctx); + cont = gen_new_label(tcg_ctx); + + tcg_gen_movi_tl(tcg_ctx, tcg_imm, int_imm); + tcg_gen_ext8u_tl(tcg_ctx, tcg_imm, tcg_imm); + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3,int_rs3); + tcg_gen_rotl_tl(tcg_ctx, tcg_r3, tcg_r2, tcg_imm); + gen_set_gpr(tcg_ctx, int_rs3, tcg_r3); + + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, tcg_r3, 0x1); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, tcg_r3, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, tcg_r3, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + tcg_gen_mov_i32(tcg_ctx, imm_local, tcg_imm); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, tcg_imm, 0x0, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + gen_set_label(tcg_ctx, cont); + + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, imm_local); + } break; + + case OPC_RH850_ROTL_reg1_reg2_reg3: + { + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + cont = gen_new_label(tcg_ctx); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3,int_rs3); + tcg_gen_rotl_tl(tcg_ctx, tcg_r3, tcg_r2, tcg_r1); + gen_set_gpr(tcg_ctx, int_rs3, tcg_r3); + + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, tcg_r3, 0x1); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, tcg_r3, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, tcg_r3, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, tcg_r1, 0x0, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + gen_set_label(tcg_ctx, cont); + + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, r1_local); + } break; + + case OPC_RH850_SAR_reg1_reg2: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_andi_i32(tcg_ctx, r1_local, r1_local, 0x1f); //shift by value of lower 5 bits of reg1 + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, r1_local, 0x0, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + + tcg_gen_subi_i32(tcg_ctx, r1_local, r1_local, 0x1); //shift by r1-1 + + tcg_gen_sar_i32(tcg_ctx, r2_local, r2_local, r1_local); + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, r2_local, 0x1); //LSB here is the last bit to be shifted + tcg_gen_sari_i32(tcg_ctx, r2_local, r2_local, 0x1); + + gen_set_label(tcg_ctx, end); + + gen_set_gpr(tcg_ctx, rs2, r2_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r2_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r1_local); + } + break; + + case OPC_RH850_SAR_imm5_reg2: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_movi_tl(tcg_ctx, r1_local, int_imm); + tcg_gen_ext8u_i32(tcg_ctx, r1_local, r1_local); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, r1_local, 0x0, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + + tcg_gen_subi_i32(tcg_ctx, r1_local, r1_local, 0x1); //shift by one less + tcg_gen_sar_i32(tcg_ctx, r2_local, r2_local, r1_local); + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, r2_local, 0x1); //LSB here is the last bit to be shifted + tcg_gen_sari_i32(tcg_ctx, r2_local, r2_local, 0x1); + + gen_set_label(tcg_ctx, end); + + gen_set_gpr(tcg_ctx, rs2, r2_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r2_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r1_local); + } + break; + + case OPC_RH850_SAR_reg1_reg2_reg3: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_andi_i32(tcg_ctx, r1_local, r1_local, 0x1f); //shift by only lower 5 bits of reg1 + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, r3_local, int_rs3); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, r1_local, 0x0, cont); //is non-shift? + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + tcg_gen_mov_i32(tcg_ctx, r3_local, r2_local); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + + + tcg_gen_subi_i32(tcg_ctx, r1_local, r1_local, 0x1); //shift by one less + tcg_gen_sar_i32(tcg_ctx, r3_local, r2_local, r1_local); + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, r3_local, 0x1); //LSB here is the last bit to be shifted + tcg_gen_sari_i32(tcg_ctx, r3_local, r3_local, 0x1); + + gen_set_label(tcg_ctx, end); + + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r3_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r3_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r1_local); + } + break; + + case OPC_RH850_SASF_cccc_reg2: { + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv operand_local = tcg_temp_local_new_i32(tcg_ctx); + + int_cond = extract32(ctx->opcode,0,4); + TCGv condResult = condition_satisfied(tcg_ctx, int_cond); + cont = gen_new_label(tcg_ctx); + + tcg_gen_shli_tl(tcg_ctx, r2_local, tcg_r2, 0x1); + + tcg_gen_movi_i32(tcg_ctx, operand_local, 0x00000000); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, condResult, 0x1, cont); + tcg_gen_movi_i32(tcg_ctx, operand_local, 0x00000001); + + gen_set_label(tcg_ctx, cont); + tcg_gen_or_tl(tcg_ctx, r2_local, r2_local, operand_local); + + gen_set_gpr(tcg_ctx, rs2, r2_local); + + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, operand_local); + tcg_temp_free(tcg_ctx, condResult); + } + break; + + case OPC_RH850_SETF_cccc_reg2:{ + + TCGv operand_local = tcg_temp_local_new_i32(tcg_ctx); + int_cond = extract32(ctx->opcode,0,4); + TCGv condResult = condition_satisfied(tcg_ctx, int_cond); + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, condResult, 0x1, cont); + tcg_gen_movi_i32(tcg_ctx, operand_local, 0x00000001); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, operand_local, 0x00000000); + + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, operand_local); + + tcg_temp_free(tcg_ctx, condResult); + tcg_temp_free(tcg_ctx, operand_local); + } + break; + + case OPC_RH850_SHL_reg1_reg2: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_andi_i32(tcg_ctx, r1_local, r1_local, 0x1f); //get only lower 5 bits + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r1_local, 0x0, cont); + + tcg_gen_subi_i32(tcg_ctx, temp_local, r1_local, 0x1); // shifting for [r1]-1 + tcg_gen_shl_tl(tcg_ctx, r2_local, r2_local, temp_local); + + tcg_gen_shri_i32(tcg_ctx, cpu_CYF, r2_local, 0x1f); // checking the last bit to shift + tcg_gen_shli_i32(tcg_ctx, r2_local, r2_local, 0x1); // shifting for that remaining 1 + + gen_set_gpr(tcg_ctx, rs2, r2_local); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + + gen_set_label(tcg_ctx, end); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r2_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, temp_local); + } + break; + + case OPC_RH850_SHL_imm5_reg2: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + tcg_gen_movi_tl(tcg_ctx, r1_local, int_imm); + tcg_gen_ext8u_tl(tcg_ctx, r1_local, r1_local); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r1_local, 0x0, cont); + + tcg_gen_subi_i32(tcg_ctx, temp_local, r1_local, 0x1); + tcg_gen_shl_tl(tcg_ctx, r2_local, r2_local, temp_local); + tcg_gen_shri_i32(tcg_ctx, cpu_CYF, r2_local, 0x1f); + tcg_gen_shli_tl(tcg_ctx, r2_local, r2_local, 0x1); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, r2_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r2_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, temp_local); + } + break; + + case OPC_RH850_SHL_reg1_reg2_reg3: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_andi_i32(tcg_ctx, r1_local, r1_local, 0x1f); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, r3_local,int_rs3); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r1_local, 0x0, cont); // when reg1 = 0, do not shift + + tcg_gen_subi_i32(tcg_ctx, temp_local, r1_local, 0x1); + tcg_gen_shl_tl(tcg_ctx, r3_local, r2_local, temp_local); + + tcg_gen_shri_i32(tcg_ctx, cpu_CYF, r3_local, 0x1f); + tcg_gen_shli_tl(tcg_ctx, r3_local, r3_local, 0x1); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_mov_i32(tcg_ctx, r3_local, r2_local); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r3_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r3_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, temp_local); + } + break; + + case OPC_RH850_SHR_reg1_reg2: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_andi_i32(tcg_ctx, r1_local, r1_local, 0x1f); // + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r1_local, 0x0, cont); //checking for non-shift + + tcg_gen_subi_i32(tcg_ctx, temp_local, r1_local, 0x1); // shifting for [r1]-1 + tcg_gen_shr_tl(tcg_ctx, r2_local, r2_local, temp_local); + + + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, r2_local, 0x1); // checking the last bit to shift (LSB) + tcg_gen_shri_i32(tcg_ctx, r2_local, r2_local, 0x1); + + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, r2_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r2_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, temp_local); + } + break; + + case OPC_RH850_SHR_imm5_reg2: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + tcg_gen_movi_tl(tcg_ctx, r1_local, int_imm); + tcg_gen_ext8u_tl(tcg_ctx, r1_local, r1_local); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r1_local, 0x0, cont); //checking for non-shift + + tcg_gen_subi_i32(tcg_ctx, temp_local, r1_local, 0x1); // shifting for [r1]-1 + tcg_gen_shr_tl(tcg_ctx, r2_local, r2_local, temp_local); + + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, r2_local, 0x1); // checking the last bit to shift (LSB) + tcg_gen_shri_i32(tcg_ctx, r2_local, r2_local, 0x1); + + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, rs2, r2_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r2_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, temp_local); + } + break; + + case OPC_RH850_SHR_reg1_reg2_reg3: { + + TCGv r1_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r2_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv r3_local = tcg_temp_local_new_i32(tcg_ctx); + TCGv temp_local = tcg_temp_local_new_i32(tcg_ctx); + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_andi_i32(tcg_ctx, r1_local, r1_local, 0x1f); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, r3_local, int_rs3); + + + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, r1_local, 0x0, cont); //checking for non-shift + + tcg_gen_subi_i32(tcg_ctx, temp_local, r1_local, 0x1); // shifting for [r1]-1 + tcg_gen_shr_tl(tcg_ctx, r3_local, r2_local, temp_local); + + tcg_gen_andi_i32(tcg_ctx, cpu_CYF, r3_local, 0x1); // checking the last bit to shift (LSB) + tcg_gen_shri_i32(tcg_ctx, r3_local, r3_local, 0x1); + + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, cont); + tcg_gen_movi_i32(tcg_ctx, cpu_CYF, 0x0); + tcg_gen_mov_i32(tcg_ctx, r3_local, r2_local); + + gen_set_label(tcg_ctx, end); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r3_local, 0x0); + tcg_gen_shri_i32(tcg_ctx, cpu_SF, r3_local, 0x1f); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, temp_local); + } + break; + + case OPC_RH850_SXB_reg1: + tcg_gen_andi_tl(tcg_ctx, tcg_r1, tcg_r1,0xFF); + tcg_gen_ext8s_tl(tcg_ctx, tcg_r1, tcg_r1); + gen_set_gpr(tcg_ctx, rs1, tcg_r1); + break; + + case OPC_RH850_SXH_reg1: + tcg_gen_andi_tl(tcg_ctx, tcg_r1, tcg_r1,0xFFFF); + tcg_gen_ext16s_tl(tcg_ctx, tcg_r1, tcg_r1); + gen_set_gpr(tcg_ctx, rs1, tcg_r1); + break; + + case OPC_RH850_ZXH_reg1: + tcg_gen_andi_tl(tcg_ctx, tcg_r1, tcg_r1,0xFFFF); + tcg_gen_ext16u_tl(tcg_ctx, tcg_r1, tcg_r1); + gen_set_gpr(tcg_ctx, rs1, tcg_r1); + break; + + case OPC_RH850_ZXB_reg1: + tcg_gen_andi_tl(tcg_ctx, tcg_r1, tcg_r1,0xFF); + tcg_gen_ext8u_tl(tcg_ctx, tcg_r1, tcg_r1); + gen_set_gpr(tcg_ctx, rs1, tcg_r1); + break; + } + + tcg_temp_free(tcg_ctx, tcg_r1); + tcg_temp_free(tcg_ctx, tcg_r2); + tcg_temp_free(tcg_ctx, tcg_r3); + tcg_temp_free(tcg_ctx, tcg_imm); + tcg_temp_free(tcg_ctx, tcg_temp); + tcg_temp_free(tcg_ctx, tcg_temp2); + tcg_temp_free(tcg_ctx, insert); +} + +static void gen_bit_search(DisasContext *ctx, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv tcg_r2 = tcg_temp_new(tcg_ctx); + TCGv tcg_r3 = tcg_temp_new(tcg_ctx); + int int_rs3; + int_rs3 = extract32(ctx->opcode, 27, 5); + + gen_get_gpr(tcg_ctx, tcg_r2, rs2); + gen_get_gpr(tcg_ctx, tcg_r3, int_rs3); + + TCGLabel *end; + TCGLabel *found; + TCGLabel *loop; + + switch(operation){ + case OPC_RH850_SCH0L_reg2_reg3: { + + TCGv foundFlag = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv count = tcg_temp_local_new(tcg_ctx); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + tcg_gen_movi_i32(tcg_ctx, count, 0x0); + + end = gen_new_label(tcg_ctx); + found = gen_new_label(tcg_ctx); + loop = gen_new_label(tcg_ctx); + + gen_set_label(tcg_ctx, loop);//--------------------------------------------------- + + tcg_gen_shl_i32(tcg_ctx, check, r2_local, count); + tcg_gen_ori_i32(tcg_ctx, check, check, 0x7fffffff); // check MSB bit + tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_EQ, check, 0x7fffffff, found); + + tcg_gen_addi_i32(tcg_ctx, count, count, 0x1); + tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_NE, count, 0x20, loop);//-------------------- + + tcg_gen_movi_i32(tcg_ctx, result, 0x0); + tcg_gen_movi_i32(tcg_ctx, foundFlag, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, found); + tcg_gen_movi_i32(tcg_ctx, foundFlag, 0x1); + tcg_gen_addi_i32(tcg_ctx, result, count, 0x1); + + gen_set_label(tcg_ctx, end); + + gen_set_gpr(tcg_ctx, int_rs3, result); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, foundFlag, 0x1); //setting Z if not found + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + tcg_gen_movi_i32(tcg_ctx, cpu_SF, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_CYF, r2_local, 0xfffffffe); //setting CY if found at the end + + tcg_temp_free(tcg_ctx, foundFlag); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, count); + tcg_temp_free(tcg_ctx, result); + } break; + + case OPC_RH850_SCH0R_reg2_reg3: { + + TCGv foundFlag = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv count = tcg_temp_local_new(tcg_ctx); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + tcg_gen_movi_i32(tcg_ctx, count, 0x0); + + end = gen_new_label(tcg_ctx); + found = gen_new_label(tcg_ctx); + loop = gen_new_label(tcg_ctx); + + gen_set_label(tcg_ctx, loop);//--------------------------------------------------- + + tcg_gen_shr_i32(tcg_ctx, check, r2_local, count); + tcg_gen_ori_i32(tcg_ctx, check, check, 0xfffffffe); // check MSB bit + tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_EQ, check, 0xfffffffe, found); + + tcg_gen_addi_i32(tcg_ctx, count, count, 0x1); + tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_NE, count, 0x20, loop);//-------------------- + + tcg_gen_movi_i32(tcg_ctx, result, 0x0); + tcg_gen_movi_i32(tcg_ctx, foundFlag, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, found); + tcg_gen_movi_i32(tcg_ctx, foundFlag, 0x1); + tcg_gen_addi_i32(tcg_ctx, result, count, 0x1); + + gen_set_label(tcg_ctx, end); + + gen_set_gpr(tcg_ctx, int_rs3, result); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, foundFlag, 0x1); //setting Z if not found + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + tcg_gen_movi_i32(tcg_ctx, cpu_SF, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_CYF, r2_local, 0x7fffffff); + + tcg_temp_free(tcg_ctx, foundFlag); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, count); + tcg_temp_free(tcg_ctx, result); + } break; + + case OPC_RH850_SCH1L_reg2_reg3: { + + TCGv foundFlag = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv count = tcg_temp_local_new(tcg_ctx); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + tcg_gen_movi_i32(tcg_ctx, count, 0x0); + + end = gen_new_label(tcg_ctx); + found = gen_new_label(tcg_ctx); + loop = gen_new_label(tcg_ctx); + + gen_set_label(tcg_ctx, loop);//--------------------------------------------------- + + tcg_gen_shl_i32(tcg_ctx, check, r2_local, count); + tcg_gen_andi_i32(tcg_ctx, check, check, 0x80000000); // check MSB bit + tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_EQ, check, 0x80000000, found); + + tcg_gen_addi_i32(tcg_ctx, count, count, 0x1); + tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_NE, count, 0x20, loop);//-------------------- + + tcg_gen_movi_i32(tcg_ctx, result, 0x0); + tcg_gen_movi_i32(tcg_ctx, foundFlag, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, found); + tcg_gen_movi_i32(tcg_ctx, foundFlag, 0x1); + tcg_gen_addi_i32(tcg_ctx, result, count, 0x1); + + gen_set_label(tcg_ctx, end); + + gen_set_gpr(tcg_ctx, int_rs3, result); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, foundFlag, 0x1); //setting Z if not found + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + tcg_gen_movi_i32(tcg_ctx, cpu_SF, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_CYF, r2_local, 0x1); + + tcg_temp_free(tcg_ctx, foundFlag); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, count); + tcg_temp_free(tcg_ctx, result); + } break; + + case OPC_RH850_SCH1R_reg2_reg3: { + + TCGv foundFlag = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + TCGv result = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + TCGv count = tcg_temp_local_new(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + tcg_gen_movi_i32(tcg_ctx, count, 0x0); + + end = gen_new_label(tcg_ctx); + found = gen_new_label(tcg_ctx); + loop = gen_new_label(tcg_ctx); + + gen_set_label(tcg_ctx, loop);//--------------------------------------------------- + + tcg_gen_shr_i32(tcg_ctx, check, r2_local, count); + tcg_gen_andi_i32(tcg_ctx, check, check, 0x1); // check MSB bit + tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_EQ, check, 0x1, found); + + tcg_gen_addi_i32(tcg_ctx, count, count, 0x1); + tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_NE, count, 0x20, loop);//-------------------- + + tcg_gen_movi_i32(tcg_ctx, result, 0x0); + tcg_gen_movi_i32(tcg_ctx, foundFlag, 0x0); + tcg_gen_br(tcg_ctx, end); + + gen_set_label(tcg_ctx, found); + tcg_gen_movi_i32(tcg_ctx, foundFlag, 0x1); + tcg_gen_addi_i32(tcg_ctx, result, count, 0x1); + + gen_set_label(tcg_ctx, end); + + gen_set_gpr(tcg_ctx, int_rs3, result); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, foundFlag, 0x1); //setting Z if not found + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x0); + tcg_gen_movi_i32(tcg_ctx, cpu_SF, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_CYF, r2_local, 0x80000000); + + tcg_temp_free(tcg_ctx, foundFlag); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, check); + tcg_temp_free(tcg_ctx, count); + tcg_temp_free(tcg_ctx, result); + } break; + } + + tcg_temp_free(tcg_ctx, tcg_r2); + tcg_temp_free(tcg_ctx, tcg_r3); +} + +static void gen_divide(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv tcg_r1 = tcg_temp_new(tcg_ctx); + TCGv tcg_r2 = tcg_temp_new(tcg_ctx); + + gen_get_gpr(tcg_ctx, tcg_r1, rs1); + gen_get_gpr(tcg_ctx, tcg_r2, rs2); + + int int_rs3; + + TCGv tcg_r3 = tcg_temp_new(tcg_ctx); + + switch(operation){ + + case OPC_RH850_DIV_reg1_reg2_reg3:{ + + TCGLabel *cont; + TCGLabel *end; + TCGLabel *fin; + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3, int_rs3); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + TCGv overflowed = tcg_temp_local_new(tcg_ctx); + TCGv overflowed2 = tcg_temp_local_new(tcg_ctx); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + fin = gen_new_label(tcg_ctx); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_OVF, r1_local, 0x0); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_OVF, 0x1, cont); //if r1=0 jump to end + + tcg_gen_movi_i32(tcg_ctx, r2_local, 0x80000000); + tcg_gen_br(tcg_ctx, fin); + + gen_set_label(tcg_ctx, cont); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, overflowed, r2_local, 0x80000000); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, overflowed2, r1_local, 0xffffffff); + tcg_gen_and_i32(tcg_ctx, overflowed, overflowed, overflowed2); //if both + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_OVF, overflowed, 0x1); //are 1 + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_OVF, 0x1, end); + tcg_gen_movi_i32(tcg_ctx, r2_local, 0x80000000); //DO THIS + tcg_gen_movi_i32(tcg_ctx, r3_local, 0x0000); + gen_set_gpr(tcg_ctx, rs2, r2_local); //write zeros if undefined + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, r2_local, 0x0); + tcg_gen_br(tcg_ctx, fin); + + gen_set_label(tcg_ctx, end); + + tcg_gen_rem_i32(tcg_ctx, r3_local, r2_local, r1_local); + tcg_gen_div_i32(tcg_ctx, r2_local, r2_local, r1_local); + + if(rs2==int_rs3){ + gen_set_gpr(tcg_ctx, rs2, r3_local); + } else { + gen_set_gpr(tcg_ctx, rs2, r2_local); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + } + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, r2_local, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + + gen_set_label(tcg_ctx, fin); + + tcg_temp_free(tcg_ctx, overflowed); + tcg_temp_free(tcg_ctx, overflowed2); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + } break; + + case OPC_RH850_DIVH_reg1_reg2:{ + + TCGLabel *cont; + TCGLabel *end; + TCGLabel *fin; + + tcg_gen_andi_i32(tcg_ctx, tcg_r1, tcg_r1, 0x0000FFFF); + tcg_gen_ext16s_i32(tcg_ctx, tcg_r1, tcg_r1); + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv overflowed = tcg_temp_local_new(tcg_ctx); + TCGv overflowed2 = tcg_temp_local_new(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + fin = gen_new_label(tcg_ctx); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_OVF, r1_local, 0x0); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_OVF, 0x1, cont); //if r1=0 jump to cont + tcg_gen_br(tcg_ctx, fin); + + gen_set_label(tcg_ctx, cont); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, overflowed, r2_local, 0x80000000); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, overflowed2, r1_local, 0xffffffff); + tcg_gen_and_i32(tcg_ctx, overflowed, overflowed, overflowed2); //if both + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_OVF, overflowed, 0x1); //are 1 + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_OVF, 0x1, end); + tcg_gen_movi_i32(tcg_ctx, r2_local, 0x80000000); //DO THIS + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x1); + gen_set_gpr(tcg_ctx, rs2, r2_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, r2_local, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_br(tcg_ctx, fin); + + gen_set_label(tcg_ctx, end); + + tcg_gen_div_i32(tcg_ctx, r2_local, r2_local, r1_local); + gen_set_gpr(tcg_ctx, rs2, r2_local); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, r2_local, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + + gen_set_label(tcg_ctx, fin); + + tcg_temp_free(tcg_ctx, overflowed); + tcg_temp_free(tcg_ctx, overflowed2); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + } break; + + case OPC_RH850_DIVH_reg1_reg2_reg3: { + // 0x80000000/0xffffffff=0x80000000; cpu_OVF=1, cpu_Z=1? + // reg2/0x0000=undefined; cpu_OVF=1 + // if reg2==reg3; reg2=remainder + + TCGLabel *cont; + TCGLabel *end; + TCGLabel *fin; + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + + tcg_gen_andi_i32(tcg_ctx, tcg_r1, tcg_r1, 0x0000FFFF); + tcg_gen_ext16s_i32(tcg_ctx, tcg_r1, tcg_r1); + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3, int_rs3); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + TCGv overflowed = tcg_temp_local_new(tcg_ctx); + TCGv overflowed2 = tcg_temp_local_new(tcg_ctx); + + cont = gen_new_label(tcg_ctx); + end = gen_new_label(tcg_ctx); + fin = gen_new_label(tcg_ctx); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_OVF, r1_local, 0x0); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_OVF, 0x1, cont); + tcg_gen_br(tcg_ctx, fin); + + gen_set_label(tcg_ctx, cont); ///// + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, overflowed, r2_local, 0x80000000); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, overflowed2, r1_local, 0xffffffff); + tcg_gen_and_i32(tcg_ctx, overflowed, overflowed, overflowed2); // if result is 1, cpu_OVF = 1 + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_OVF, overflowed, 0x1); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_OVF, 0x1, end); + tcg_gen_movi_i32(tcg_ctx, r2_local, 0x80000000); + tcg_gen_movi_i32(tcg_ctx, r3_local, 0x0000); + tcg_gen_movi_i32(tcg_ctx, cpu_OVF, 0x1); + gen_set_gpr(tcg_ctx, rs2, r2_local); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, r2_local, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_br(tcg_ctx, fin); + + gen_set_label(tcg_ctx, end); ///// + + tcg_gen_rem_i32(tcg_ctx, r3_local, r2_local, r1_local); + tcg_gen_div_i32(tcg_ctx, r2_local, r2_local, r1_local); + + if(rs2==int_rs3){ + gen_set_gpr(tcg_ctx, rs2, r3_local); + } else { + gen_set_gpr(tcg_ctx, rs2, r2_local); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + } + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, r2_local, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + + gen_set_label(tcg_ctx, fin); ///// + + tcg_temp_free(tcg_ctx, overflowed); + tcg_temp_free(tcg_ctx, overflowed2); + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + } break; + + case OPC_RH850_DIVHU_reg1_reg2_reg3:{ + + TCGLabel *cont; + TCGLabel *fin; + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + + tcg_gen_andi_i32(tcg_ctx, tcg_r1, tcg_r1, 0x0000FFFF); + tcg_gen_ext16u_i32(tcg_ctx, tcg_r1, tcg_r1); + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3, int_rs3); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + + cont = gen_new_label(tcg_ctx); + fin = gen_new_label(tcg_ctx); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_OVF, r1_local, 0x0); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_OVF, 0x1, cont); + tcg_gen_br(tcg_ctx, fin); + + gen_set_label(tcg_ctx, cont); ///// + tcg_gen_remu_i32(tcg_ctx, r3_local, r2_local, r1_local); + tcg_gen_divu_i32(tcg_ctx, r2_local, r2_local, r1_local); + + if(rs2==int_rs3){ + gen_set_gpr(tcg_ctx, rs2, r3_local); + } else { + gen_set_gpr(tcg_ctx, rs2, r2_local); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + } + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_LT, cpu_SF, r2_local, 0x0); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + + gen_set_label(tcg_ctx, fin); ///// + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + } + break; + + case OPC_RH850_DIVU_reg1_reg2_reg3:{ + + // reg2/0x0000=undefined; cpu_OVF=1 + // if reg2==reg3; reg2=remainder + + TCGLabel *cont; + TCGLabel *fin; + + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv r2_local = tcg_temp_local_new(tcg_ctx); + TCGv r3_local = tcg_temp_local_new(tcg_ctx); + TCGv check = tcg_temp_local_new(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, r1_local, tcg_r1); + tcg_gen_mov_i32(tcg_ctx, r2_local, tcg_r2); + + int_rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, tcg_r3, int_rs3); + tcg_gen_mov_i32(tcg_ctx, r3_local, tcg_r3); + + cont = gen_new_label(tcg_ctx); + fin = gen_new_label(tcg_ctx); + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_OVF, r1_local, 0x0); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_OVF, 0x1, cont); + tcg_gen_br(tcg_ctx, fin); + + gen_set_label(tcg_ctx, cont); ///// + + tcg_gen_remu_i32(tcg_ctx, r3_local, r2_local, r1_local); + tcg_gen_divu_i32(tcg_ctx, r2_local, r2_local, r1_local); + + if(rs2==int_rs3){ + gen_set_gpr(tcg_ctx, rs2, r3_local); + } else { + gen_set_gpr(tcg_ctx, rs2, r2_local); + gen_set_gpr(tcg_ctx, int_rs3, r3_local); + } + + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, r2_local, 0x0); + tcg_gen_andi_i32(tcg_ctx, check, r2_local, 0x80000000); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_SF, check, 0x80000000); + + gen_set_label(tcg_ctx, fin); ///// + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, r2_local); + tcg_temp_free(tcg_ctx, r3_local); + tcg_temp_free(tcg_ctx, check); + } + break; + } + + tcg_temp_free_i32(tcg_ctx, tcg_r1); + tcg_temp_free_i32(tcg_ctx, tcg_r2); + tcg_temp_free_i32(tcg_ctx, tcg_r3); +} + +static void gen_branch(CPURH850State *env, DisasContext *ctx, uint32_t cond, + int rs1, int rs2, target_long bimm) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGLabel *l = gen_new_label(tcg_ctx); + TCGv condOK = tcg_temp_new(tcg_ctx); + TCGv condResult = condition_satisfied(tcg_ctx, cond); + tcg_gen_movi_i32(tcg_ctx, condOK, 0x1); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_EQ, condResult, condOK, l); + + tcg_temp_free(tcg_ctx, condResult); + tcg_temp_free(tcg_ctx, condOK); + + gen_goto_tb_imm(ctx, 1, ctx->base.pc_next); // no jump, continue with next instr. + gen_set_label(tcg_ctx, l); /* branch taken */ + gen_goto_tb_imm(ctx, 0, ctx->pc + bimm); // jump + ctx->base.is_jmp = DISAS_TB_EXIT_ALREADY_GENERATED; +} + +static void gen_jmp(DisasContext *ctx, int rs1, uint32_t disp32, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + // disp32 is already generated when entering this function + int rs2, rs3; + TCGv link_addr = tcg_temp_new(tcg_ctx); + TCGv dest_addr = tcg_temp_new(tcg_ctx); + + switch (operation) + { + /** + * Jump with immediate displacement. + * PC and disp32 are fixed and won't change at + * execution time, we can call gen_goto_tb_imm() with + * the computed destination address. + */ + case OPC_RH850_JR_imm22: + case OPC_RH850_JR_imm32: + { + gen_goto_tb_imm(ctx, 0, ctx->pc + disp32); + ctx->base.is_jmp = DISAS_TB_EXIT_ALREADY_GENERATED; + } + break; + + /** + * Jump with immediate displacement but store + * PC+4 first in reg2. We first call tcg_goto_tb(), + * update PC and reg2 and then issue an exit TB. + **/ + case OPC_RH850_JARL_disp22_reg2: + { + rs2 = extract32(ctx->opcode, 11, 5); + tcg_gen_movi_i32(tcg_ctx, link_addr, ctx->pc); + tcg_gen_addi_i32(tcg_ctx, link_addr, link_addr, 0x4); + gen_set_gpr(tcg_ctx, rs2, link_addr); + + /* Update pc */ + tcg_gen_movi_i32(tcg_ctx, cpu_pc, ctx->pc + disp32); + + /* Goto corresponding TB (indirect jump). */ + ctx->base.is_jmp = DISAS_INDIRECT_JUMP; + } + break; + + /** + * Jump with immediate displacement but store PC+6 first in reg1. + * We first call tcg_gen_goto_tb(), update PC and reg1 and then + * issue an exit TB. + **/ + + case OPC_RH850_JARL_disp32_reg1: + { + gen_goto_tb_rl(ctx, 0, rs1, 6, ctx->pc + disp32); + ctx->base.is_jmp = DISAS_TB_EXIT_ALREADY_GENERATED; + } + break; + + /** + * This is a pure indirect call that will move GR[reg1] into PC, + * so we need to process in a different way. + **/ + + case OPC_RH850_JARL_reg1_reg3: + { + /* Get reg1 content into dest_addr. */ + gen_get_gpr(tcg_ctx, dest_addr, rs1); + + /* Get reg3 index, and store PC+4 in it. */ + rs3 = extract32(ctx->opcode, 27, 5); + tcg_gen_movi_i32(tcg_ctx, link_addr, ctx->pc); + tcg_gen_addi_i32(tcg_ctx, link_addr, link_addr, 0x4); + gen_set_gpr(tcg_ctx, rs3, link_addr); + + /* Update pc */ + tcg_gen_andi_i32(tcg_ctx, dest_addr, dest_addr, 0xfffffffe); + tcg_gen_mov_i32(tcg_ctx, cpu_pc, dest_addr); + + /* Goto corresponding TB (indirect jump). */ + ctx->base.is_jmp = DISAS_INDIRECT_JUMP; + } + break; + + default: // JMP instruction + { + /* Get reg1 into dest_addr. */ + gen_get_gpr(tcg_ctx, dest_addr, rs1); + + /* Apply displacement if provided. */ + if (disp32 != 0) + { + tcg_gen_addi_i32(tcg_ctx, dest_addr, dest_addr, disp32); + } + + /* Align and update PC. */ + tcg_gen_andi_i32(tcg_ctx, dest_addr, dest_addr, 0xfffffffe); + tcg_gen_mov_i32(tcg_ctx, cpu_pc, dest_addr); + + /* Indirect jump. */ + ctx->base.is_jmp = DISAS_INDIRECT_JUMP; + } + break; + } + + /* Free temporary values. */ + tcg_temp_free_i32(tcg_ctx, link_addr); + tcg_temp_free_i32(tcg_ctx, dest_addr); +} + +static void gen_loop(DisasContext *ctx, int rs1, int32_t disp16) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGLabel *l = gen_new_label(tcg_ctx); + TCGv zero_local = tcg_temp_local_new(tcg_ctx); + TCGv r1_local = tcg_temp_local_new(tcg_ctx); + TCGv minusone_local = tcg_temp_local_new(tcg_ctx); + + tcg_gen_movi_i32(tcg_ctx, zero_local, 0); + tcg_gen_movi_i32(tcg_ctx, minusone_local, 0xffffffff); + gen_get_gpr(tcg_ctx, r1_local, rs1); + gen_flags_on_add(tcg_ctx, r1_local, minusone_local); //set flags + tcg_gen_add_i32(tcg_ctx, r1_local, r1_local, minusone_local); + gen_set_gpr(tcg_ctx, rs1, r1_local); + + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_NE, r1_local, zero_local, l); + + tcg_temp_free(tcg_ctx, r1_local); + tcg_temp_free(tcg_ctx, zero_local); + tcg_temp_free(tcg_ctx, minusone_local); + + gen_goto_tb_imm(ctx, 0, ctx->base.pc_next); // no jump, continue with next instr. + gen_set_label(tcg_ctx, l); // branch taken + gen_goto_tb_imm(ctx, 1, ctx->pc - disp16); + + ctx->base.is_jmp = DISAS_TB_EXIT_ALREADY_GENERATED; +} + +static void gen_bit_manipulation(DisasContext *ctx, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGv r1 = tcg_temp_new_i32(tcg_ctx); + TCGv r2 = tcg_temp_new_i32(tcg_ctx); + TCGv tcg_disp = tcg_temp_new_i32(tcg_ctx); + TCGv one = tcg_temp_new_i32(tcg_ctx); + + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv test = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + uint32_t disp16 = extract32(ctx->opcode, 16, 16); + + int bit; + + switch(operation){ + case OPC_RH850_SET1_reg2_reg1: + + gen_get_gpr(tcg_ctx, adr, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + tcg_gen_movi_i32(tcg_ctx, one, 0x1); + + tcg_gen_qemu_ld_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + + tcg_gen_shl_i32(tcg_ctx, r2, one, r2); + + tcg_gen_and_i32(tcg_ctx, test, temp, r2); + tcg_gen_setcond_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, test, r2); + + tcg_gen_or_i32(tcg_ctx, temp, temp, r2); + + tcg_gen_qemu_st_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + + break; + case OPC_RH850_SET1_bit3_disp16_reg1: + + gen_get_gpr(tcg_ctx, r1, rs1); + tcg_gen_movi_i32(tcg_ctx, tcg_disp, disp16); + tcg_gen_ext16s_i32(tcg_ctx, tcg_disp, tcg_disp); + tcg_gen_add_i32(tcg_ctx, adr, r1, tcg_disp); + + bit = extract32(ctx->opcode, 11, 3); + + tcg_gen_qemu_ld_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + + tcg_gen_andi_i32(tcg_ctx, test, temp, (0x1 << bit)); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, test, (0x1 << bit)); + + tcg_gen_ori_i32(tcg_ctx, temp, temp, (0x1 << bit)); + + tcg_gen_qemu_st_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + break; + + case OPC_RH850_NOT1_reg2_reg1: + + gen_get_gpr(tcg_ctx, adr, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + tcg_gen_movi_i32(tcg_ctx, one, 0x1); + + tcg_gen_qemu_ld_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + + tcg_gen_shl_i32(tcg_ctx, r2, one, r2); // r2 = mask + + tcg_gen_and_i32(tcg_ctx, test, temp, r2); + tcg_gen_setcond_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, test, r2); + + //test = temp & mask + tcg_gen_and_i32(tcg_ctx, test, temp, r2); + //test = not (test) & mask + tcg_gen_not_i32(tcg_ctx, test, test); + tcg_gen_and_i32(tcg_ctx, test, test, r2); + //temp = temp & not(mask) + tcg_gen_not_i32(tcg_ctx, r2, r2); + tcg_gen_and_i32(tcg_ctx, temp, temp, r2); + //temp = temp or test + tcg_gen_or_i32(tcg_ctx, temp, temp, test); + + tcg_gen_qemu_st_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + break; + + case OPC_RH850_NOT1_bit3_disp16_reg1: + + gen_get_gpr(tcg_ctx, r1, rs1); + tcg_gen_movi_i32(tcg_ctx, tcg_disp, disp16); + tcg_gen_ext16s_i32(tcg_ctx, tcg_disp, tcg_disp); + tcg_gen_add_i32(tcg_ctx, adr, r1, tcg_disp); + + bit = extract32(ctx->opcode, 11, 3); + + tcg_gen_qemu_ld_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + + tcg_gen_andi_i32(tcg_ctx, test, temp, (0x1 << bit)); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, test, (0x1 << bit)); + + tcg_gen_movi_i32(tcg_ctx, r2, (0x1 << bit)); // r2 = mask + + //test = temp & mask + tcg_gen_and_i32(tcg_ctx, test, temp, r2); + //test = not (test) & mask + tcg_gen_not_i32(tcg_ctx, test, test); + tcg_gen_and_i32(tcg_ctx, test, test, r2); + //temp = temp & not(mask) + tcg_gen_not_i32(tcg_ctx, r2, r2); + tcg_gen_and_i32(tcg_ctx, temp, temp, r2); + //temp = temp or test + tcg_gen_or_i32(tcg_ctx, temp, temp, test); + + tcg_gen_qemu_st_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + break; + + case OPC_RH850_CLR1_reg2_reg1: + + gen_get_gpr(tcg_ctx, adr, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + tcg_gen_movi_i32(tcg_ctx, one, 0x1); + + tcg_gen_qemu_ld_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + tcg_gen_andi_i32(tcg_ctx, r2, r2, 0x7); + tcg_gen_shl_i32(tcg_ctx, r2, one, r2); + + tcg_gen_and_i32(tcg_ctx, test, temp, r2); + tcg_gen_setcond_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, test, r2); + + tcg_gen_not_i32(tcg_ctx, r2, r2); + tcg_gen_and_i32(tcg_ctx, temp, temp, r2); + + tcg_gen_qemu_st_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + break; + + case OPC_RH850_CLR1_bit3_disp16_reg1: + + gen_get_gpr(tcg_ctx, r1, rs1); + tcg_gen_movi_i32(tcg_ctx, tcg_disp, disp16); + tcg_gen_ext16s_i32(tcg_ctx, tcg_disp, tcg_disp); + tcg_gen_add_i32(tcg_ctx, adr, r1, tcg_disp); + + bit = extract32(ctx->opcode, 11, 3); + + tcg_gen_qemu_ld_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + + tcg_gen_movi_i32(tcg_ctx, test, (0x1 << bit)); + tcg_gen_andi_i32(tcg_ctx, test, temp, (0x1 << bit)); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, test, (0x1 << bit)); + + tcg_gen_movi_i32(tcg_ctx, test, (0x1 << bit)); + tcg_gen_not_i32(tcg_ctx, test, test); + tcg_gen_and_i32(tcg_ctx, temp, temp, test); + + tcg_gen_qemu_st_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + break; + + case OPC_RH850_TST1_reg2_reg1: + + gen_get_gpr(tcg_ctx, adr, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + tcg_gen_movi_i32(tcg_ctx, one, 0x1); + + tcg_gen_qemu_ld_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + + tcg_gen_shl_i32(tcg_ctx, r2, one, r2); + + tcg_gen_and_i32(tcg_ctx, test, temp, r2); + tcg_gen_setcond_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, test, r2); + break; + + case OPC_RH850_TST1_bit3_disp16_reg1: + + gen_get_gpr(tcg_ctx, r1, rs1); + tcg_gen_movi_i32(tcg_ctx, tcg_disp, disp16); + tcg_gen_ext16s_i32(tcg_ctx, tcg_disp, tcg_disp); + tcg_gen_add_i32(tcg_ctx, adr, r1, tcg_disp); + + bit = extract32(ctx->opcode, 11, 3); + + tcg_gen_qemu_ld_i32(tcg_ctx, temp, adr, MEM_IDX, MO_UB); + + tcg_gen_movi_i32(tcg_ctx, test, (0x1 << bit)); + tcg_gen_andi_i32(tcg_ctx, test, temp, (0x1 << bit)); + tcg_gen_setcondi_i32(tcg_ctx, TCG_COND_NE, cpu_ZF, test, (0x1 << bit)); + break; + } + + tcg_temp_free_i32(tcg_ctx, r1); + tcg_temp_free_i32(tcg_ctx, r2); + tcg_temp_free_i32(tcg_ctx, tcg_disp); + tcg_temp_free_i32(tcg_ctx, one); + tcg_temp_free_i32(tcg_ctx, temp); + tcg_temp_free_i32(tcg_ctx, test); + tcg_temp_free_i32(tcg_ctx, adr); + +} + +static void gen_update_ispr(DisasContext *ctx, CPURH850State *env) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGLabel *do_not_update = gen_new_label(tcg_ctx); + TCGLabel *clear_bit = gen_new_label(tcg_ctx); + TCGLabel *loop = gen_new_label(tcg_ctx); + TCGv temp = tcg_temp_local_new_i32(tcg_ctx); + TCGv idx = tcg_temp_local_new_i32(tcg_ctx); + TCGv ispr = tcg_temp_local_new_i32(tcg_ctx); + + /* Move ISPR value into intcfg. */ + tcg_gen_mov_i32(tcg_ctx, temp, cpu_sysRegs[BANK_ID_BASIC_2][INTCFG_IDX2]); + + /* And intcfg with 1. */ + tcg_gen_andi_i32(tcg_ctx, temp, temp, 1); + + /* Compare intcfg, jump to do_not_process if 1. */ + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, temp, 0, do_not_update); + + /* INTCFG.ICSP = 0, now check EP (EP == 1 -> do not update ISRP) */ + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, cpu_EP, 0, do_not_update); + + /** + * Okay, now update ISPR (clear the highest priority bit). + * We need to loop from bit 0 to bit 15, clear bit and exit loop if bit is + * set. + **/ + + /* Set mask to 1. */ + tcg_gen_movi_i32(tcg_ctx, temp, 1); + tcg_gen_movi_i32(tcg_ctx, idx, 0); + + gen_set_label(tcg_ctx, loop); + + /* Load ISPR. */ + tcg_gen_mov_i32(tcg_ctx, ispr, cpu_sysRegs[BANK_ID_BASIC_2][ISPR_IDX2]); + tcg_gen_and_i32(tcg_ctx, ispr, ispr, temp); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, ispr, 1, clear_bit); + + /* shift left our mask, exit if done. */ + tcg_gen_shli_i32(tcg_ctx, temp, temp, 1); + tcg_gen_addi_i32(tcg_ctx, idx, idx, 1); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_LT, idx, 2, loop); + + tcg_gen_br(tcg_ctx, do_not_update); + + /* Clear bit. */ + gen_set_label(tcg_ctx, clear_bit); + tcg_gen_xor_i32(tcg_ctx, cpu_sysRegs[BANK_ID_BASIC_2][ISPR_IDX2], cpu_sysRegs[BANK_ID_BASIC_2][ISPR_IDX2], temp); + + /* Set label do_not_update here. */ + gen_set_label(tcg_ctx, do_not_update); + + /* Free resources. */ + tcg_temp_free_i32(tcg_ctx, temp); + tcg_temp_free_i32(tcg_ctx, ispr); +} + +static void gen_special(DisasContext *ctx, CPURH850State *env, int rs1, int rs2, int operation) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + TCGLabel *storeReg3; + TCGLabel *cont; + int regID; + int selID = 0; + int imm; + int vector; + + switch(operation){ + case OPC_RH850_CALLT_imm6: { + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + + //setting CTPC to PC+2 + tcg_gen_addi_i32(tcg_ctx, cpu_sysRegs[BANK_ID_BASIC_0][CTPC_IDX], cpu_pc, 0x2); + //setting CPTSW bits 0:4 + flags_to_tcgv_z_cy_ov_s_sat(tcg_ctx, cpu_sysRegs[BANK_ID_BASIC_0][CTPSW_IDX]); + + imm = extract32(ctx->opcode, 0, 6); + tcg_gen_movi_i32(tcg_ctx, adr, imm); + tcg_gen_shli_i32(tcg_ctx, adr, adr, 0x1); + tcg_gen_ext8s_i32(tcg_ctx, adr, adr); + tcg_gen_add_i32(tcg_ctx, adr, cpu_sysRegs[BANK_ID_BASIC_0][CTBP_IDX], adr); + + tcg_gen_qemu_ld16u(tcg_ctx, temp, adr, 0); + + tcg_gen_add_i32(tcg_ctx, cpu_pc, temp, cpu_sysRegs[BANK_ID_BASIC_0][CTBP_IDX]); + ctx->base.is_jmp = DISAS_EXIT_TB; + + tcg_temp_free(tcg_ctx, temp); + tcg_temp_free(tcg_ctx, adr); + } break; + + case OPC_RH850_CAXI_reg1_reg2_reg3: { + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + TCGv r2 = tcg_temp_new(tcg_ctx); + TCGv r3 = tcg_temp_new(tcg_ctx); + + storeReg3 = gen_new_label(tcg_ctx); + gen_get_gpr(tcg_ctx, adr, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + int rs3 = extract32(ctx->opcode, 27, 5); + gen_get_gpr(tcg_ctx, r3, rs3); + tcg_gen_qemu_ld32u(tcg_ctx, temp, adr, 0); + storeReg3 = gen_new_label(tcg_ctx); + cont = gen_new_label(tcg_ctx); + + TCGv local_adr = tcg_temp_local_new_i32(tcg_ctx); + TCGv local_r2 = tcg_temp_local_new_i32(tcg_ctx); + TCGv local_r3 = tcg_temp_local_new_i32(tcg_ctx); + TCGv local_temp = tcg_temp_local_new_i32(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, local_adr, adr); + tcg_gen_mov_i32(tcg_ctx, local_r2, r2); + tcg_gen_mov_i32(tcg_ctx, local_r3, r3); + tcg_gen_mov_i32(tcg_ctx, local_temp, temp); + + gen_flags_on_sub(tcg_ctx, local_r2, local_temp); + + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_EQ, cpu_ZF, 0x1, storeReg3); + tcg_gen_qemu_st_tl(tcg_ctx, local_temp, local_adr, MEM_IDX, MO_TESL); + tcg_gen_br(tcg_ctx, cont); + + gen_set_label(tcg_ctx, storeReg3); + tcg_gen_qemu_st_tl(tcg_ctx, local_r3, local_adr, MEM_IDX, MO_TESL); + + gen_set_label(tcg_ctx, cont); + gen_set_gpr(tcg_ctx, rs3, local_temp); + + tcg_temp_free(tcg_ctx, temp); + tcg_temp_free(tcg_ctx, adr); + tcg_temp_free(tcg_ctx, r2); + tcg_temp_free(tcg_ctx, r3); + break; + } + + case OPC_RH850_CTRET: { + TCGv temp = tcg_temp_new_i32(tcg_ctx); + + tcg_gen_mov_i32(tcg_ctx, cpu_pc, cpu_sysRegs[BANK_ID_BASIC_0][CTPC_IDX]); + tcgv_to_flags_z_cy_ov_s_sat(tcg_ctx, cpu_sysRegs[BANK_ID_BASIC_0][CTPSW_IDX]); + + ctx->base.is_jmp = DISAS_EXIT_TB; + + tcg_temp_free(tcg_ctx, temp); + } break; + + case OPC_RH850_DI: + tcg_gen_movi_i32(tcg_ctx, cpu_ID, 0x1); + break; + + case OPC_RH850_DISPOSE_imm5_list12: { + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + + int list [12] = {31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20}; + int numOfListItems = sizeof(list) / sizeof(list[0]); + int list12 = extract32(ctx->opcode, 0, 1) | ( (extract32(ctx->opcode, 21, 11)) << 1); + + // reorganising bits that indicate the registers to load + // doing this for easier looping in correct order + int dispList = ((list12 & 0x80) << 4) | + ((list12 & 0x40) << 4) | + ((list12 & 0x20) << 4) | + ((list12 & 0x10) << 4) | + ((list12 & 0x800) >> 4) | + ((list12 & 0x400) >> 4) | + ((list12 & 0x200) >> 4) | + ((list12 & 0x100) >> 4) | + ((list12 & 0x8) << 0) | + ((list12 & 0x4) << 0) | + ((list12 & 0x2) >> 1) | + ((list12 & 0x1) << 1) ; + + int test = 0x1; + gen_get_gpr(tcg_ctx, temp, 3); // stack pointer (sp) register is cpu_gpr[3] + tcg_gen_addi_i32(tcg_ctx, temp, temp, (extract32(ctx->opcode, 1, 5) << 2)); + + TCGv regToLoad = tcg_temp_new_i32(tcg_ctx); + + for(int i=0; i<numOfListItems; i++){ + tcg_gen_andi_i32(tcg_ctx, adr, temp, 0xfffffffc); //masking the lower two bits + + if( !((dispList & test)==0x0) ){ + tcg_gen_qemu_ld_i32(tcg_ctx, regToLoad, adr, MEM_IDX, MO_TESL); + + gen_set_gpr(tcg_ctx, list[i], regToLoad); + tcg_gen_addi_i32(tcg_ctx, temp, temp, 0x4); + } + test = test << 1; + } + gen_set_gpr(tcg_ctx, 3, temp); + + tcg_temp_free(tcg_ctx, temp); + tcg_temp_free(tcg_ctx, adr); + } + + break; + + case OPC_RH850_DISPOSE_imm5_list12_reg1: { + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + + int list [12] = {31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20}; + int numOfListItems = sizeof(list) / sizeof(list[0]); + int list12 = extract32(ctx->opcode, 0, 1) | ( (extract32(ctx->opcode, 21, 11)) << 1); + TCGv jmpAddr = tcg_temp_new_i32(tcg_ctx); + + // reorganising bits that indicate the registers to load + // doing this for easier looping in correct order + int dispList = ((list12 & 0x80) << 4) | + ((list12 & 0x40) << 4) | + ((list12 & 0x20) << 4) | + ((list12 & 0x10) << 4) | + ((list12 & 0x800) >> 4) | + ((list12 & 0x400) >> 4) | + ((list12 & 0x200) >> 4) | + ((list12 & 0x100) >> 4) | + ((list12 & 0x8) << 0) | + ((list12 & 0x4) << 0) | + ((list12 & 0x2) >> 1) | + ((list12 & 0x1) << 1) ; + + int test = 0x1; + gen_get_gpr(tcg_ctx, temp, 3); // stack pointer (sp) register is cpu_gpr[3] + tcg_gen_addi_i32(tcg_ctx, temp, temp, (extract32(ctx->opcode, 1, 5) << 2)); + + TCGv regToLoad = tcg_temp_new_i32(tcg_ctx); + + for(int i=0; i<numOfListItems; i++){ + tcg_gen_andi_i32(tcg_ctx, adr, temp, 0xfffffffc); //masking the lower two bits + + if( !((dispList & test)==0x0) ){ + tcg_gen_qemu_ld_i32(tcg_ctx, regToLoad, adr, MEM_IDX, MO_TESL); + + gen_set_gpr(tcg_ctx, list[i], regToLoad); + tcg_gen_addi_i32(tcg_ctx, temp, temp, 0x4); + } + test = test << 1; + } + + gen_get_gpr(tcg_ctx, jmpAddr, (extract32(ctx->opcode, 16, 5))); + tcg_gen_mov_i32(tcg_ctx, cpu_pc, jmpAddr); + + gen_set_gpr(tcg_ctx, 3, temp); + ctx->base.is_jmp = DISAS_EXIT_TB; + + tcg_temp_free(tcg_ctx, temp); + tcg_temp_free(tcg_ctx, adr); + } + break; + + case OPC_RH850_EI: + tcg_gen_movi_i32(tcg_ctx, cpu_ID, 0x0); + break; + case OPC_RH850_EIRET: + /* Move EIPC to PC and EIPSW to PSW. */ + tcg_gen_mov_i32(tcg_ctx, cpu_pc, cpu_sysRegs[BANK_ID_BASIC_0][EIPC_IDX]); + tcgv_to_flags(tcg_ctx, cpu_sysRegs[BANK_ID_BASIC_0][EIPSW_IDX]); + + /* Update ISPR. */ + gen_update_ispr(ctx, env); + ctx->base.is_jmp = DISAS_EXIT_TB; + break; + case OPC_RH850_FERET: + tcg_gen_mov_i32(tcg_ctx, cpu_pc, cpu_sysRegs[BANK_ID_BASIC_0][FEPC_IDX]); + tcgv_to_flags(tcg_ctx, cpu_sysRegs[BANK_ID_BASIC_0][FEPSW_IDX]); + ctx->base.is_jmp = DISAS_EXIT_TB; + break; + + case OPC_RH850_FETRAP_vector4: { + + vector = extract32(ctx->opcode, 11, 4); + TCGv_i32 excp = tcg_const_i32(tcg_ctx, RH850_EXCP_FETRAP); + TCGv_i32 cause = tcg_const_i32(tcg_ctx, vector + 0x30); + gen_helper_raise_exception_with_cause(tcg_ctx, tcg_ctx->cpu_env, excp, cause); + tcg_temp_free_i32(tcg_ctx, excp); + tcg_temp_free_i32(tcg_ctx, cause); + ctx->base.is_jmp = DISAS_NORETURN; + } break; + + case OPC_RH850_HALT: + // nop, interupts are not implemented, so HALT would never continue + // tcg_abort(); + break; + + case OPC_RH850_LDSR_reg2_regID_selID: + selID = extract32(ctx->opcode, 27, 5); + regID = rs2; + + // Modify only sytem regs, which exist. Real device executes instruction, but + // value is not stored for system regs, which do not exist. No exception is + // thrown. + if(cpu_sysRegs[selID][regID] != NULL || (selID == BANK_ID_BASIC_0 && regID == PSW_IDX)) { + + TCGv tmp = tcg_temp_new(tcg_ctx); + gen_get_gpr(tcg_ctx, tmp, rs1); + + if(selID == BANK_ID_BASIC_0 && regID == PSW_IDX){ + tcgv_to_flags(tcg_ctx, tmp); + } else { + // clear read-only bits in value, all other bits in sys reg. This way + // read-only bits preserve their value given at reset + tcg_gen_andi_i32(tcg_ctx, tmp, tmp, rh850_sys_reg_read_only_masks[selID][regID]); + tcg_gen_andi_i32(tcg_ctx, cpu_sysRegs[selID][regID], cpu_sysRegs[selID][regID], ~rh850_sys_reg_read_only_masks[selID][regID]); + tcg_gen_or_i32(tcg_ctx, cpu_sysRegs[selID][regID], cpu_sysRegs[selID][regID], tmp); + } + tcg_temp_free(tcg_ctx, tmp); + } + break; + + //case OPC_RH850_LDLW: + //break; + + //case OPC_RH850_NOP: + //break; + + case OPC_RH850_POPSP_rh_rt: { + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + + uint32_t rs3 = extract32(ctx->opcode, 27, 5); + + int numOfRegs = (rs3-rs1)+1; + + gen_get_gpr(tcg_ctx, temp, 3); // stack pointer register is cpu_gpr[3] + TCGv regToLoad = tcg_temp_new_i32(tcg_ctx); + + if(rs1<=rs3){ + + for(int i=0; i<numOfRegs; i++){ + + tcg_gen_andi_i32(tcg_ctx, adr, temp, 0xfffffffc); // masking the lower two bits + + tcg_gen_qemu_ld_i32(tcg_ctx, regToLoad, adr, MEM_IDX, MO_TESL); + + gen_set_gpr(tcg_ctx, rs3-i, regToLoad); + tcg_gen_addi_i32(tcg_ctx, temp, temp, 0x4); + + } + gen_set_gpr(tcg_ctx, 3, temp); + } + + tcg_temp_free(tcg_ctx, temp); + tcg_temp_free(tcg_ctx, adr); + } break; + + case OPC_RH850_PREPARE_list12_imm5:{ + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + + // how to manually affect the ff field? + + int list [12] = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + int list12 = ( (extract32(ctx->opcode, 21, 11) << 1) | (extract32(ctx->opcode, 0, 1) ) ) ; + int numOfListItems = sizeof(list) / sizeof(list[0]); + int prepList = ((list12 & 0x80) >> 7) | + ((list12 & 0x40) >> 5) | + ((list12 & 0x20) >> 3) | + ((list12 & 0x10) >> 1) | + ((list12 & 0x800) >> 7) | + ((list12 & 0x400) >> 5) | + ((list12 & 0x200) >> 3) | + ((list12 & 0x100) >> 1) | + ((list12 & 0x8) << 5) | + ((list12 & 0x4) << 7) | + ((list12 & 0x2) << 10) | + ((list12 & 0x1) << 10) ; + + int test = 0x1; + gen_get_gpr(tcg_ctx, temp, 3); // stack pointer register is cpu_gpr[3] + TCGv regToStore = tcg_temp_new_i32(tcg_ctx); + + for(int i=0; i<numOfListItems; i++){ + + if( !((prepList & test)==0x0) ){ + tcg_gen_subi_i32(tcg_ctx, temp, temp, 0x4); + tcg_gen_andi_i32(tcg_ctx, adr, temp, 0xfffffffc); //masking the lower two bits + gen_get_gpr(tcg_ctx, regToStore, list[i]); + tcg_gen_qemu_st_i32(tcg_ctx, regToStore, adr, MEM_IDX, MO_TESL); + gen_set_gpr(tcg_ctx, list[i], regToStore); + } + test = test << 1; + } + tcg_gen_subi_i32(tcg_ctx, temp, temp, (extract32(ctx->opcode, 1, 5) << 2)); + gen_set_gpr(tcg_ctx, 3, temp); + + tcg_temp_free(tcg_ctx, temp); + tcg_temp_free(tcg_ctx, adr); + } break; + + case OPC_RH850_PREPARE_list12_imm5_sp:{ + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + + int list [12] = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + uint32_t list12 = extract32(ctx->opcode, 0, 1) | ( (extract32(ctx->opcode, 21, 11)) << 1); + int numOfListItems = sizeof(list) / sizeof(list[0]); + int prepList = ((list12 & 0x80) >> 7) | + ((list12 & 0x40) >> 5) | + ((list12 & 0x20) >> 3) | + ((list12 & 0x10) >> 1) | + ((list12 & 0x800) >> 7) | + ((list12 & 0x400) >> 5) | + ((list12 & 0x200) >> 3) | + ((list12 & 0x100) >> 1) | + ((list12 & 0x8) << 5) | + ((list12 & 0x4) << 7) | + ((list12 & 0x2) << 10) | + ((list12 & 0x1) << 10) ; + + uint32_t imm = 0x0; + + int test = 0x1; + int ff = extract32(ctx->opcode, 19, 2); + gen_get_gpr(tcg_ctx, temp, 3); // stack pointer register is cpu_gpr[3] + TCGv regToStore = tcg_temp_new_i32(tcg_ctx); + + for(int i=0; i<numOfListItems; i++){ + + if( !((prepList & test)==0x0) ){ + tcg_gen_subi_i32(tcg_ctx, temp, temp, 0x4); + tcg_gen_andi_i32(tcg_ctx, adr, temp, 0xfffffffc); //masking the lower two bits + gen_get_gpr(tcg_ctx, regToStore, list[i]); + tcg_gen_qemu_st32(tcg_ctx, regToStore, adr, MEM_IDX); + gen_set_gpr(tcg_ctx, list[i], regToStore); + } + test = test << 1; + } + + tcg_gen_subi_i32(tcg_ctx, temp, temp, (extract32(ctx->opcode, 1, 5) << 2)); + + gen_set_gpr(tcg_ctx, 3, temp); + + switch(ff){ + + case 0x0: + gen_set_gpr(tcg_ctx, 30, temp); //moving sp to ep (element pointer is at cpu_gpr[30]) + break; + + case 0x1: + imm = cpu_lduw_code(env, ctx->base.pc_next); // fetching additional 16bits from memory + tcg_gen_movi_i32(tcg_ctx, temp, imm); + tcg_gen_ext16s_i32(tcg_ctx, temp, temp); + gen_set_gpr(tcg_ctx, 30, temp); + ctx->base.pc_next+=2; // increasing PC due to additional fetch + break; + + case 0x2: + imm = cpu_lduw_code(env, ctx->base.pc_next); // fetching additional 16bits from memory + tcg_gen_movi_i32(tcg_ctx, temp, imm); + tcg_gen_shli_i32(tcg_ctx, temp, temp, 0x10); + gen_set_gpr(tcg_ctx, 30, temp); + ctx->base.pc_next+=2; + break; + + case 0x3: + imm = cpu_lduw_code(env, ctx->base.pc_next) | + (cpu_lduw_code(env, ctx->base.pc_next + 2) << 0x10); + // fetching additional 32bits from memory + + tcg_gen_movi_i32(tcg_ctx, temp, imm); + gen_set_gpr(tcg_ctx, 30, temp); + ctx->base.pc_next = ctx->base.pc_next + 4; + break; + } + + tcg_temp_free(tcg_ctx, temp); + tcg_temp_free(tcg_ctx, adr); + } break; + + case OPC_RH850_PUSHSP_rh_rt: { + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + + uint32_t rs3 = extract32(ctx->opcode, 27, 5); + + int numOfRegs = (rs3-rs1)+1; + + gen_get_gpr(tcg_ctx, temp, 3); // stack pointer register is cpu_gpr[3] + TCGv regToStore = tcg_temp_new_i32(tcg_ctx); + if(rs1<=rs3){ + + for(int i=0; i<numOfRegs; i++){ + tcg_gen_subi_i32(tcg_ctx, temp, temp, 0x4); + tcg_gen_andi_i32(tcg_ctx, adr, temp, 0xfffffffc); // masking the lower two bits + + gen_get_gpr(tcg_ctx, regToStore, rs1+i); + + tcg_gen_qemu_st_i32(tcg_ctx, regToStore, adr, MEM_IDX, MO_TESL); + } + gen_set_gpr(tcg_ctx, 3, temp); + } + + tcg_temp_free(tcg_ctx, temp); + tcg_temp_free(tcg_ctx, adr); + } break; + + case OPC_RH850_RIE: { + + TCGv_i32 excp = tcg_const_i32(tcg_ctx, RH850_EXCP_RIE); + TCGv_i32 cause = tcg_const_i32(tcg_ctx, 0x60); + gen_helper_raise_exception_with_cause(tcg_ctx, tcg_ctx->cpu_env, excp, cause); + tcg_temp_free_i32(tcg_ctx, excp); + tcg_temp_free_i32(tcg_ctx, cause); + ctx->base.is_jmp = DISAS_NORETURN; + + } break; + + case OPC_RH850_SNOOZE: + break; + + //case OPC_RH850_STCW: + // break; + + case OPC_RH850_STSR_regID_reg2_selID: + regID=rs1; + selID = extract32(ctx->opcode, 27, 5); + if(selID == BANK_ID_BASIC_0 && regID == PSW_IDX){ + TCGv tmp = tcg_temp_new_i32(tcg_ctx); + tcg_gen_movi_tl(tcg_ctx, tmp, 0); + flags_to_tcgv(tcg_ctx, tmp); + gen_set_gpr(tcg_ctx, rs2, tmp); + tcg_temp_free(tcg_ctx, tmp); + } else { + if (cpu_sysRegs[selID][regID] != NULL) { + gen_set_gpr(tcg_ctx, rs2, cpu_sysRegs[selID][regID]); + } else { + TCGv dat = tcg_temp_local_new(tcg_ctx); + tcg_gen_movi_i32(tcg_ctx, dat, 0); + gen_set_gpr(tcg_ctx, rs2, 0); // if sys reg does not exist, write 0 + tcg_temp_free(tcg_ctx, dat); + } + } + break; + + case OPC_RH850_SWITCH_reg1: { + TCGv temp = tcg_temp_new_i32(tcg_ctx); + TCGv adr = tcg_temp_new_i32(tcg_ctx); + + gen_get_gpr(tcg_ctx, adr, rs1); + tcg_gen_shli_i32(tcg_ctx, adr, adr, 0x1); + tcg_gen_add_i32(tcg_ctx, adr, adr, cpu_pc); + tcg_gen_addi_i32(tcg_ctx, adr, adr, 0x2); + + tcg_gen_addi_i32(tcg_ctx, cpu_pc, cpu_pc, 0x2); + tcg_gen_qemu_ld16s(tcg_ctx, temp, adr, MEM_IDX); + tcg_gen_ext16s_i32(tcg_ctx, temp, temp); + tcg_gen_shli_i32(tcg_ctx, temp, temp, 0x1); + tcg_gen_add_i32(tcg_ctx, cpu_pc, cpu_pc, temp); + ctx->base.is_jmp = DISAS_EXIT_TB; + } break; + + // SYNC instructions will not be implemented + case OPC_RH850_SYNCE: + case OPC_RH850_SYNCI: + case OPC_RH850_SYNCM: + case OPC_RH850_SYNCP: + break; + + case OPC_RH850_TRAP: + { + int vector5 = rs1; + TCGv_i32 excp = tcg_const_i32(tcg_ctx, RH850_EXCP_TRAP); + TCGv_i32 cause = tcg_const_i32(tcg_ctx, vector5 + 0x40); + gen_helper_raise_exception_with_cause(tcg_ctx, tcg_ctx->cpu_env, excp, cause); + tcg_temp_free_i32(tcg_ctx, excp); + tcg_temp_free_i32(tcg_ctx, cause); + ctx->base.is_jmp = DISAS_NORETURN; + } + break; + + case OPC_RH850_SYSCALL: + { + int vector = extract32(ctx->opcode, 0, 5) | ((extract32(ctx->opcode, 27, 3)) << 5); + // int vector=5; + TCGv_i32 excp = tcg_const_i32(tcg_ctx, RH850_EXCP_SYSCALL); + TCGv_i32 cause = tcg_const_i32(tcg_ctx, vector + 0x8000); + gen_helper_raise_exception_with_cause(tcg_ctx, tcg_ctx->cpu_env, excp, cause); + tcg_temp_free_i32(tcg_ctx, excp); + tcg_temp_free_i32(tcg_ctx, cause); + ctx->base.is_jmp = DISAS_NORETURN; + } + break; + } +} + +/* Cache operations are not supported on single core emulation. */ +static void gen_cache(DisasContext *ctx, int rs1, int rs2, int operation){ + int cache_op = (extract32(ctx->opcode,11, 2) << 5 ) | (extract32(ctx->opcode, 27, 5)); + switch(cache_op){ + case CHBII: + // printf("CHBII\n"); + break; + case CIBII: + // printf("CIBII\n"); + break; + case CFALI: + // printf("CFALI\n"); + break; + case CISTI: + // printf("CISTI\n"); + break; + case CILDI: + // printf("CILDI\n"); + break; + case CLL: + // printf("CLL\n"); + // this operation is not implemented on single core + break; + } +} + +/* 48-bit RH850 instruction decoding */ +static void decode_RH850_48(CPURH850State *env, DisasContext *ctx) +{ + int rs1, rs3; + uint64_t opcode48; + + rs1 = GET_RS1(ctx->opcode); + rs3 = extract32(ctx->opcode, 27, 5); + + opcode48 = (ctx->opcode1); + opcode48 = (ctx->opcode) | (opcode48 << 0x20); + uint32_t opcode20 = extract32(opcode48,0,20) & 0xfffe0; + + uint32_t disp23 = (ctx->opcode1 << 7) | (extract32(ctx->opcode, 21, 6) << 1); + uint32_t disp32 = (opcode48 >> 16); + + switch(opcode20) { + + + case OPC_RH850_LDB2: + gen_load(ctx, MO_SB, rs3, rs1, disp23, 1); + break; + case OPC_RH850_LDH2: + gen_load(ctx, MO_TESW, rs3, rs1, disp23, 1); + break; + case OPC_RH850_LDW2: + gen_load(ctx, MO_TESL, rs3, rs1, disp23, 1); + break; + case OPC_RH850_LDDW: + gen_load(ctx, MO_TEQ, rs3, rs1, disp23, 1); + break; + case OPC_RH850_LDBU2: + gen_load(ctx, MO_UB, rs3, rs1, disp23, 1); + break; + case OPC_RH850_LDHU2: + gen_load(ctx, MO_TEUW, rs3, rs1, disp23, 1); + break; + + case OPC_RH850_STB2: + gen_store(ctx, MO_SB, rs1, rs3, disp23, 1); + break; + case OPC_RH850_STH2: + gen_store(ctx, MO_TESW, rs1, rs3, disp23, 1); + break; + case OPC_RH850_STW2: + gen_store(ctx, MO_TESL, rs1, rs3, disp23, 1); + break; + case OPC_RH850_STDW: + gen_store(ctx, MO_TEQ, rs1, rs3, disp23, 1); + break; + } + + if (extract32(ctx->opcode, 5, 11) == 0x31) { + gen_arithmetic(ctx, 0, rs1, OPC_RH850_MOV_imm32_reg1); + } else if (extract32(ctx->opcode, 5, 12) == 0x37) { + gen_jmp(ctx, rs1, disp32, OPC_RH850_JMP_disp32_reg1); + } else if (extract32(ctx->opcode, 5, 11) == 0x17) { + if (rs1 == 0x0){ + gen_jmp(ctx, 0, disp32, OPC_RH850_JR_imm32); + + } else { + gen_jmp(ctx, rs1, disp32, OPC_RH850_JARL_disp32_reg1); + } + } +} + +/* 32-bit RH850 instruction decoding */ +static void decode_RH850_32(CPURH850State *env, DisasContext *ctx) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + + int rs1; + int rs2; + int cond; + uint32_t op; + uint32_t formXop; + uint32_t checkXII; + uint32_t check32bitZERO; + target_long imm_32; + target_long ld_imm; + + op = MASK_OP_MAJOR(ctx->opcode); + rs1 = GET_RS1(ctx->opcode); // rs1 is at b0-b4; + rs2 = GET_RS2(ctx->opcode); // rs2 is at b11-b15; + TCGv r1 = tcg_temp_local_new(tcg_ctx); + TCGv r2 = tcg_temp_local_new(tcg_ctx); + imm_32 = GET_IMM_32(ctx->opcode); + ld_imm = extract32(ctx->opcode, 16, 16); + + gen_get_gpr(tcg_ctx, r1, rs1); + gen_get_gpr(tcg_ctx, r2, rs2); + + switch(op){ + + case OPC_RH850_LDB: + gen_load(ctx, MO_SB, rs2, rs1, ld_imm, 0); + break; + + case OPC_RH850_LDH_LDW: + if ( extract32(ctx->opcode, 16, 1) == 0 ){ + gen_load(ctx, MO_TESW, rs2, rs1, ld_imm, 0); // LD.H + } + else{ + gen_load(ctx, MO_TESL, rs2, rs1, ld_imm & 0xfffe, 0); // LD.W + } + break; + + case OPC_RH850_STB: + gen_store(ctx, MO_SB, rs1, rs2, (extract32(ctx->opcode, 16, 16)), 0); + break; + + case OPC_RH850_STH_STW: + if ( extract32(ctx->opcode, 16, 1)==1 ) { + gen_store(ctx, MO_TESL, rs1, rs2, ((extract32(ctx->opcode, 17, 15))) << 1, 0); + //this is STORE WORD + break; + } + gen_store(ctx, MO_TESW, rs1, rs2, ((extract32(ctx->opcode, 17, 15))) << 1, 0); + //this is STORE HALFWORD + break; + + case OPC_RH850_ADDI_imm16_reg1_reg2: + gen_arithmetic(ctx, rs1,rs2, OPC_RH850_ADDI_imm16_reg1_reg2); + break; + + case OPC_RH850_ANDI_imm16_reg1_reg2: + gen_logical(ctx, rs1, rs2, OPC_RH850_ANDI_imm16_reg1_reg2); + break; + + case OPC_RH850_MOVEA: + if ( extract32(ctx->opcode, 11, 5) == 0 ){ + // This is 48bit MOV + // This instruction should be reached first in decode_RH850_48 + } else { + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_MOVEA_imm16_reg1_reg2); + } + break; + + case OPC_RH850_MOVHI_imm16_reg1_reg2: + if(extract32(ctx->opcode, 11, 5)!=0x0){ + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_MOVHI_imm16_reg1_reg2); + } else { + if(extract32(ctx->opcode, 16, 5)==0x0){ + gen_special(ctx, env, rs1, rs2, OPC_RH850_DISPOSE_imm5_list12); + } else { + gen_special(ctx, env, rs1, rs2, OPC_RH850_DISPOSE_imm5_list12_reg1); + } + } + break; + + case OPC_RH850_ORI_imm16_reg1_reg2: + gen_logical(ctx, rs1, rs2, OPC_RH850_ORI_imm16_reg1_reg2); + break; + + case OPC_RH850_SATSUBI_imm16_reg1_reg2: + if(extract32(ctx->opcode, 11, 5)!=0x0){ + gen_sat_op(ctx, rs1, rs2, OPC_RH850_SATSUBI_imm16_reg1_reg2); + } else { + if(extract32(ctx->opcode, 16, 5)==0x0){ + gen_special(ctx, env, rs1, rs2, OPC_RH850_DISPOSE_imm5_list12); + } else { + gen_special(ctx, env, rs1, rs2, OPC_RH850_DISPOSE_imm5_list12_reg1); + } + } + + break; + case OPC_RH850_XORI_imm16_reg1_reg2: + gen_logical(ctx, rs1, rs2, OPC_RH850_XORI_imm16_reg1_reg2); + break; + + case OPC_RH850_LOOP: + if (extract32(ctx->opcode, 11, 5) == 0x0) + gen_loop(ctx, rs1, ld_imm & 0xfffe); // LOOP + else + gen_multiply(ctx, rs1, rs2, OPC_RH850_MULHI_imm16_reg1_reg2); + break; + case OPC_RH850_BIT_MANIPULATION_2: + + switch(extract32(ctx->opcode, 14, 2)){ + case 0: + gen_bit_manipulation(ctx, rs1, rs2, OPC_RH850_SET1_bit3_disp16_reg1); + break; + case 1: + gen_bit_manipulation(ctx, rs1, rs2, OPC_RH850_NOT1_bit3_disp16_reg1); + break; + case 2: + gen_bit_manipulation(ctx, rs1, rs2, OPC_RH850_CLR1_bit3_disp16_reg1); + break; + case 3: + gen_bit_manipulation(ctx, rs1, rs2, OPC_RH850_TST1_bit3_disp16_reg1); + break; + } + break; + case OPC_RH850_32bit_1: /* case for opcode = 111111 ; formats IX, X, XI, XII */ + if (extract32(ctx->opcode, 16, 1) == 0x1 ) { + /* BCOND disp17 */ + if (rs2 == 0x0) + { + /* Get condition. */ + cond = extract32(ctx->opcode, 0, 4); + + /* Extract immediate value (16 higher bits of 17 bits set by the instruction). */ + imm_32 = ((extract32(ctx->opcode, 4, 1)<<16) | (extract32(ctx->opcode, 17, 15) << 1)); + + /* Sign-extend value to 32 bits. */ + if ((imm_32 & 0x10000) == 0x10000) + { + imm_32 |= (0x7fff << 17); + } + + gen_branch(env, ctx, cond, rs1, rs2, imm_32); + + break; + } + else + { + /* LD.HU */ + gen_load(ctx, MO_TEUW, rs2, rs1, ld_imm & 0xfffe, 0); + break; + } + } + formXop = MASK_OP_32BIT_SUB(ctx->opcode); //sub groups based on bits b23-b26 + switch(formXop){ + case OPC_RH850_LDSR_RIE_SETF_STSR: + check32bitZERO = extract32(ctx->opcode, 21, 2); + switch(check32bitZERO){ + case 0: + if(extract32(ctx->opcode, 4, 1)==1) + { + gen_special(ctx, env, rs1, rs2, OPC_RH850_RIE); + } + else + { + printf("gen SETF\r\n"); + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SETF_cccc_reg2); + } + break; + case OPC_RH850_LDSR_reg2_regID_selID: + gen_special(ctx, env, rs1, rs2, OPC_RH850_LDSR_reg2_regID_selID); + break; + case OPC_RH850_STSR_regID_reg2_selID: + gen_special(ctx, env, rs1, rs2, OPC_RH850_STSR_regID_reg2_selID); + break; + } + break; + case OPC_RH850_FORMAT_IX: //format IX instructions + formXop = MASK_OP_FORMAT_IX(ctx->opcode); //mask on bits 21, 22 + switch(formXop) + { + case OPC_RH850_BINS_0: + if (extract32(ctx->opcode, 20, 1) == 1) + { + //BINS0 + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_BINS); + } + else + { + if (extract32(ctx->opcode, 17, 1) == 0) + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SHR_reg1_reg2); + } + else + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SHR_reg1_reg2_reg3); + } + } + break; + case OPC_RH850_BINS_1: + if (extract32(ctx->opcode, 20, 1) == 1) + { + //BINS1 + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_BINS); + } + else + { + if (extract32(ctx->opcode, 17, 1) == 0) + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SAR_reg1_reg2); + } + else + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SAR_reg1_reg2_reg3); + } + } + break; + case OPC_RH850_BINS_2: + if (extract32(ctx->opcode, 20, 1) == 1) + { + //BINS2 + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_BINS); + } + else + { + if (extract32(ctx->opcode, 17, 1) == 0) + { + if (extract32(ctx->opcode, 18, 1) == 1) + { + gen_data_manipulation(ctx, rs1, rs2, + OPC_RH850_ROTL_imm5_reg2_reg3); + } + else + { + gen_data_manipulation(ctx, rs1, rs2, + OPC_RH850_SHL_reg1_reg2); + } + } + else + { + if (extract32(ctx->opcode, 18, 1) == 1) + { + gen_data_manipulation(ctx, rs1, rs2, + OPC_RH850_ROTL_reg1_reg2_reg3); + } + else + { + gen_data_manipulation(ctx, rs1, rs2, + OPC_RH850_SHL_reg1_reg2_reg3); + } + } + } + break; + case OPC_RH850_BIT_MANIPULATION: // in format IX + check32bitZERO = extract32(ctx->opcode, 16, 3); + switch(check32bitZERO){ + case OPC_RH850_SET1_reg2_reg1: + gen_bit_manipulation(ctx, rs1, rs2, OPC_RH850_SET1_reg2_reg1); + break; + case OPC_RH850_NOT1_reg2_reg1: + gen_bit_manipulation(ctx, rs1, rs2, OPC_RH850_NOT1_reg2_reg1); + break; + case OPC_RH850_CLR1_reg2_reg1: + gen_bit_manipulation(ctx, rs1, rs2, OPC_RH850_CLR1_reg2_reg1); + break; + case OPC_RH850_TST1_reg2_reg1: + if (extract32(ctx->opcode, 19, 1) == 0){ + gen_bit_manipulation(ctx, rs1, rs2, OPC_RH850_TST1_reg2_reg1); + } else { + gen_special(ctx, env, rs1, rs2, OPC_RH850_CAXI_reg1_reg2_reg3); + } + } + break; + } + break; + + + case OPC_RH850_FORMAT_X: //format X instructions + //(+JARL3 - added due to MASK_OP_FORMAT_X matching) + formXop = MASK_OP_FORMAT_X(ctx->opcode); + + switch(formXop){ + + case OPC_RH850_CTRET: + gen_special(ctx, env, rs1, rs2, OPC_RH850_CTRET); + break; + case OPC_RH850_DI: + gen_special(ctx, env, rs1, rs2, OPC_RH850_DI); + break; + case OPC_RH850_EI: + gen_special(ctx, env, rs1, rs2, OPC_RH850_EI); + break; + case OPC_RH850_EIRET: + gen_special(ctx, env, rs1, rs2, OPC_RH850_EIRET); + break; + case OPC_RH850_FERET: + gen_special(ctx, env, rs1, rs2, OPC_RH850_FERET); + break; + case OPC_RH850_HALT: + gen_special(ctx, env, rs1, rs2, OPC_RH850_HALT); + break; + case OPC_RH850_JARL3: + gen_jmp(ctx, rs1, 0, OPC_RH850_JARL_reg1_reg3); + break; + case OPC_RH850_SNOOZE: + gen_special(ctx, env, rs1, rs2, OPC_RH850_SNOOZE); + break; + case OPC_RH850_SYSCALL: + gen_special(ctx, env, rs1, rs2, OPC_RH850_SYSCALL); + break; + case OPC_RH850_TRAP: + gen_special(ctx, env, rs1, rs2, OPC_RH850_TRAP); + break; + case OPC_RH850_PREF: + //printf("PREF \n"); + break; + case OPC_RH850_POPSP_rh_rt: + gen_special(ctx, env, rs1, rs2, OPC_RH850_POPSP_rh_rt); + break; + case OPC_RH850_PUSHSP_rh_rt: + gen_special(ctx, env, rs1, rs2, OPC_RH850_PUSHSP_rh_rt); + break; + default: + if ((extract32(ctx->opcode, 13, 12) == 0xB07)) + { + if ((extract32(ctx->opcode, 27, 5) == 0x1E) && + (extract32(ctx->opcode, 0, 5) == 0x1F)) + { + if ((extract32(ctx->opcode, 23, 4) == 0x2)) // CLL + gen_mutual_exclusion(ctx, extract32(ctx->opcode, 27, 5), rs1, operation_CLL); + } else { + //CACHE; if cacheop bits are 1111110, opcode matches CLL ins, + //then they are THE SAME instruction, so this should be correct + gen_cache(ctx,rs1,rs2, 1); + } + } else + printf("ERROR! \n"); + break; + } + break; + case OPC_RH850_MUL_INSTS: + if (extract32(ctx->opcode, 22, 1) == 0) + { + if (extract32(ctx->opcode, 21, 1) == 0) + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SASF_cccc_reg2); + } + else + { + if (extract32(ctx->opcode, 17, 1) == 1) + { + gen_multiply(ctx, rs1, rs2, OPC_RH850_MULU_reg1_reg2_reg3); + } + else + { + gen_multiply(ctx, rs1, rs2, OPC_RH850_MUL_reg1_reg2_reg3); + } + } + break; + } else if (extract32(ctx->opcode, 22, 1) == 1) + { + if (extract32(ctx->opcode, 17, 1) == 1) + { + gen_multiply(ctx, rs1, rs2, OPC_RH850_MULU_imm9_reg2_reg3); + } + else + { + gen_multiply(ctx, rs1, rs2, OPC_RH850_MUL_imm9_reg2_reg3); + } + break; + } + break; + + case OPC_RH850_FORMAT_XI: // DIV instructions in format XI + formXop = extract32(ctx->opcode, 16, 7); + switch(formXop){ + + case OPC_RH850_DIV_reg1_reg2_reg3: + gen_divide(ctx, rs1, rs2, OPC_RH850_DIV_reg1_reg2_reg3); + //DIV + break; + case OPC_RH850_DIVH_reg1_reg2_reg3: + gen_divide(ctx, rs1, rs2, OPC_RH850_DIVH_reg1_reg2_reg3); + //DIVH 2 + break; + case OPC_RH850_DIVHU_reg1_reg2_reg3: + gen_divide(ctx, rs1, rs2, OPC_RH850_DIVHU_reg1_reg2_reg3); + //DIVHU + break; + + case OPC_RH850_DIVQ: + gen_divide(ctx, rs1, rs2, OPC_RH850_DIV_reg1_reg2_reg3); + //DIVQ => using DIV implementation, will be changed if needed + break; + case OPC_RH850_DIVQU: + gen_divide(ctx, rs1, rs2, OPC_RH850_DIVU_reg1_reg2_reg3); + //DIVQU => using DIVU implementation, will be changed if needed + break; + case OPC_RH850_DIVU_reg1_reg2_reg3: + gen_divide(ctx, rs1, rs2, OPC_RH850_DIVU_reg1_reg2_reg3); + //DIVU + break; + } + break; + + case OPC_RH850_FORMAT_XII: // for opcode = 0110 ; format XII instructions + //excluding MUL and including CMOV + // also LDL.W and STC.W (Format VII) + checkXII = extract32(ctx->opcode, 21, 2); + + switch(checkXII) + { + case 0: + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_CMOV_cccc_imm5_reg2_reg3); + break; + case 1: + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_CMOV_cccc_reg1_reg2_reg3); + break; + case 2: + formXop = extract32(ctx->opcode, 17, 2); + + switch(formXop) + { + case OPC_RH850_BSW_reg2_reg3: + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_BSW_reg2_reg3); + break; + case OPC_RH850_BSH_reg2_reg3: + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_BSH_reg2_reg3); + break; + case OPC_RH850_HSW_reg2_reg3: + //HSW + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_HSW_reg2_reg3); + break; + case OPC_RH850_HSH_reg2_reg3: + //HSH + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_HSH_reg2_reg3); + break; + } + break; + case 3: //these are SCHOL, SCHOR, SCH1L, SCH1R. Also LDL.W + formXop = extract32(ctx->opcode, 17, 2); + switch(formXop) + { + case OPC_RH850_SCH0R_reg2_reg3: + if (extract32(ctx->opcode, 5, 11) == 0x3F && + extract32(ctx->opcode, 16, 5) == 0x18) + gen_mutual_exclusion(ctx, extract32(ctx->opcode, 27, 5), + rs1, operation_LDL_W); + else + gen_bit_search(ctx, rs2, OPC_RH850_SCH0R_reg2_reg3); + break; + case OPC_RH850_SCH1R_reg2_reg3: + if (extract32(ctx->opcode, 19, 2) == 0x0) + { + gen_bit_search(ctx, rs2, OPC_RH850_SCH1R_reg2_reg3); + } + else if (extract32(ctx->opcode, 5, 11) == 0x3F && + extract32(ctx->opcode, 16, 5) == 0x1a) + gen_mutual_exclusion(ctx, extract32(ctx->opcode, 27, 5), + rs1, operation_STC_W); + break; + case OPC_RH850_SCH0L_reg2_reg3: + gen_bit_search(ctx, rs2, OPC_RH850_SCH0L_reg2_reg3); + break; + case OPC_RH850_SCH1L_reg2_reg3: + gen_bit_search(ctx, rs2, OPC_RH850_SCH1L_reg2_reg3); + break; + } + + } + break; + + case OPC_RH850_ADDIT_ARITH: + formXop = extract32(ctx->opcode, 21, 2); + switch(formXop) + { + + case OPC_RH850_ADF_SATADD3: + if (extract32(ctx->opcode, 16, 5) == 0x1A) + { + gen_sat_op(ctx, rs1, rs2, OPC_RH850_SATADD_reg1_reg2_reg3); + } + else + { + gen_cond_arith(ctx, rs1, rs2, OPC_RH850_ADF_cccc_reg1_reg2_reg3); + } + break; + case OPC_RH850_SBF_SATSUB: + if (extract32(ctx->opcode, 16, 5) == 0x1A) + { + gen_sat_op(ctx, rs1, rs2, OPC_RH850_SATSUB_reg1_reg2_reg3); + } + else + { + gen_cond_arith(ctx, rs1, rs2, OPC_RH850_SBF_cccc_reg1_reg2_reg3); + } + break; + case OPC_RH850_MAC_reg1_reg2_reg3_reg4: + gen_mul_accumulate(ctx, rs1, rs2, OPC_RH850_MAC_reg1_reg2_reg3_reg4); + break; + case OPC_RH850_MACU_reg1_reg2_reg3_reg4: + gen_mul_accumulate(ctx, rs1, rs2, OPC_RH850_MACU_reg1_reg2_reg3_reg4); + break; + } + break; + + /* Floating-point instruction format F:I. */ + case OPC_RH850_FORMAT_FI_CAT0: + { + /* Dispatch to FPU generator (category 0). */ + fpu_decode_cat0_instn(env, ctx); + } + break; + + case OPC_RH850_FORMAT_FI_CAT1: + { + /* Dispatch to FPU generator (category 1). */ + fpu_decode_cat1_instn(env, ctx); + } + break; + } + } + + if (MASK_OP_FORMAT_V_FORMAT_XIII(ctx->opcode) == OPC_RH850_FORMAT_V_XIII){ + if(extract32(ctx->opcode, 16, 1) == 0) + { + uint32_t disp22 = extract32(ctx->opcode, 16, 16) | + (extract32(ctx->opcode, 0, 6) << 16 ); + if( (disp22 & 0x200000) == 0x200000) + { + disp22 = disp22 | (0x3ff << 22); + } + + if (extract32(ctx->opcode, 11, 5) == 0) + { + gen_jmp(ctx, 0, disp22, OPC_RH850_JR_imm22); //JR disp22 + } + else + { + gen_jmp(ctx, 0, disp22, OPC_RH850_JARL_disp22_reg2); + } + } + else + { + if (extract32(ctx->opcode, 11, 5) != 0) + { + //LD.BU + gen_load(ctx, MO_UB, rs2, rs1, (ld_imm & 0xfffe) | extract32(ctx->opcode, 5, 1), 0); + + } + else + { + if (extract32(ctx->opcode, 16, 3) == 0x3){ + gen_special(ctx, env, rs1, rs2, OPC_RH850_PREPARE_list12_imm5_sp); + //PREPARE2 + } + else if (extract32(ctx->opcode, 16, 3) == 0x1){ + gen_special(ctx, env, rs1, rs2, OPC_RH850_PREPARE_list12_imm5); + //PREPARE1 + } + } + } + } + + tcg_temp_free(tcg_ctx, r1); + tcg_temp_free(tcg_ctx, r2); +} + +/* 16-bit RH850 instruction decoding */ +static void decode_RH850_16(CPURH850State *env, DisasContext *ctx) +{ + int rs1; + int rs2; + int cond; + uint32_t op; + uint32_t subOpCheck; + uint32_t imm; + uint32_t disp32 = 0; + + op = MASK_OP_MAJOR(ctx->opcode); + rs1 = GET_RS1(ctx->opcode); // rs1 at bits b0-b4; + rs2 = GET_RS2(ctx->opcode); // rs2 at bits b11-b15; + imm = rs1; + + if((op & 0xf << 7) == OPC_RH850_BCOND ) + { // checking for 4 bit opcode for BCOND + cond = extract32(ctx->opcode, 0, 4); + imm = ( extract32(ctx->opcode, 4, 3) | (extract32(ctx->opcode, 11, 5) << 3)) << 1 ; + + if ( (imm & 0x100) == 0x100){ + imm |= (0x7fffff << 9); + } + gen_branch(env, ctx, cond, rs1, rs2, imm); + + return; + } + + switch(op) + { + case OPC_RH850_16bit_0: + if (rs2 != 0) { + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_MOV_reg1_reg2); + break; + } else { + subOpCheck = MASK_OP_FORMAT_I_0(op); + switch(subOpCheck){ + case OPC_RH850_NOP: + break; + case OPC_RH850_SYNCI: + break; + case OPC_RH850_SYNCE: + break; + case OPC_RH850_SYNCM: + break; + case OPC_RH850_SYNCP: + break; + } + } + break; + + case OPC_RH850_16bit_2: + if (rs2 == 0) + { + if (rs1 == 0) + { + gen_special(ctx, env, rs1, rs2, OPC_RH850_RIE); + break; + } + else + { + gen_special(ctx, env, rs1, rs2, OPC_RH850_SWITCH_reg1); + break; + } + } + else + { + if (rs1 == 0) + { + gen_special(ctx, env, rs1, rs2, OPC_RH850_FETRAP_vector4); + break; + } + else + { + gen_divide(ctx, rs1, rs2, OPC_RH850_DIVH_reg1_reg2); + break; + } + } + break; + + case OPC_RH850_16bit_4: + if (rs2 == 0) + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_ZXB_reg1); + break; + } + else + { + gen_sat_op(ctx, rs1, rs2, OPC_RH850_SATSUBR_reg1_reg2); + break; + } + break; + case OPC_RH850_16bit_5: + if (rs2 == 0) + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SXB_reg1); + break; + } + else + { + gen_sat_op(ctx, rs1, rs2, OPC_RH850_SATSUB_reg1_reg2); + break; + } + break; + case OPC_RH850_16bit_6: + if (rs2 == 0) + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_ZXH_reg1); + break; + } + else + { + gen_sat_op(ctx, rs1, rs2, OPC_RH850_SATADD_reg1_reg2); + break; + } + break; + case OPC_RH850_16bit_7: + if (rs2 == 0) + { + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SXH_reg1); + break; + } + else + { + gen_multiply(ctx, rs1, rs2, OPC_RH850_MULH_reg1_reg2); + break; + } + break; + case OPC_RH850_NOT_reg1_reg2: + gen_logical(ctx, rs1, rs2, OPC_RH850_NOT_reg1_reg2); + break; + // decode properly (handle also case when rs2 != 0), then uncomment + // case OPC_RH850_JMP_DISP: + // JMP opcode: DDDD DDDD DDDD DDDD dddd dddd dddd ddd0 0000 0110 111R RRRR + // disp32 = ctx->opcode >> 16; + + + // this case is already handled in decode_RH850_48() + + case OPC_RH850_16bit_3: + if (rs2 == 0) + { // JMP + gen_jmp(ctx, rs1, disp32, OPC_RH850_JMP_reg1); + break; + } + else + { + if(extract32(rs1,4,1)==1){ + //SLD.HU + gen_load(ctx, MO_TEUW, rs2, 30, extract32(ctx->opcode, 0, 4) << 1, 0); + }else{ + //SLD.BU + gen_load(ctx, MO_UB, rs2, 30, extract32(ctx->opcode, 0, 4), 0); + } + break; + } + break; + case OPC_RH850_OR_reg1_reg2: + gen_logical(ctx, rs1, rs2, OPC_RH850_OR_reg1_reg2); + break; + case OPC_RH850_XOR_reg1_reg2: + gen_logical(ctx, rs1, rs2, OPC_RH850_XOR_reg1_reg2); + break; + case OPC_RH850_AND_reg1_reg2: + gen_logical(ctx, rs1, rs2, OPC_RH850_AND_reg1_reg2); + break; + case OPC_RH850_TST_reg1_reg2: + gen_logical(ctx, rs1, rs2, OPC_RH850_TST_reg1_reg2); + break; + case OPC_RH850_SUBR_reg1_reg2: + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_SUBR_reg1_reg2); + break; + case OPC_RH850_SUB_reg1_reg2: + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_SUB_reg1_reg2); + break; + case OPC_RH850_ADD_reg1_reg2: + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_ADD_reg1_reg2); + break; + case OPC_RH850_CMP_reg1_reg2: + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_CMP_reg1_reg2); + break; + case OPC_RH850_16bit_16: + if (rs2 == 0) + { + gen_special(ctx, env, rs1, rs2, OPC_RH850_CALLT_imm6); + break; + } + else + { + gen_arithmetic(ctx, imm, rs2, OPC_RH850_MOV_imm5_reg2); + break; + } + break; + case OPC_RH850_16bit_17: + if (rs2 == 0) + { + gen_special(ctx, env, rs1, rs2, OPC_RH850_CALLT_imm6); + break; + } + else + { + gen_sat_op(ctx, rs1, rs2, OPC_RH850_SATADD_imm5_reg2); + break; + } + break; + case OPC_RH850_ADD_imm5_reg2: + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_ADD_imm5_reg2); + break; + case OPC_RH850_CMP_imm5_reg2: + gen_arithmetic(ctx, rs1, rs2, OPC_RH850_CMP_imm5_reg2); + break; + case OPC_RH850_SHR_imm5_reg2: + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SHR_imm5_reg2); + break; + case OPC_RH850_SAR_imm5_reg2: + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SAR_imm5_reg2); + break; + case OPC_RH850_SHL_imm5_reg2: + gen_data_manipulation(ctx, rs1, rs2, OPC_RH850_SHL_imm5_reg2); + break; + case OPC_RH850_MULH_imm5_reg2: + gen_multiply(ctx, rs1, rs2, OPC_RH850_MULH_imm5_reg2); + break; + } + + //Format IV ; dividing on code bits b7-b10 + uint32_t opIV = (op >> 7); + opIV = opIV << 5; + + switch(opIV) + { + case OPC_RH850_16bit_SLDB: + gen_load(ctx, MO_SB, rs2, 30, extract32(ctx->opcode, 0, 7), 0); + break; + case OPC_RH850_16bit_SLDH: + gen_load(ctx, MO_TESW, rs2, 30, extract32(ctx->opcode, 0, 7) << 1, 0); + break; + case OPC_RH850_16bit_IV10: + if ( extract32(rs1,0,1) == 1 ) { + //SST.W + gen_store(ctx, MO_TEUL, 30, rs2, (extract32(ctx->opcode, 1, 6)) << 2, 0); + /// Note An MAE or MDP exception might occur + /// depending on the result of address calculation. + } + else{ + //SLD.W + gen_load(ctx, MO_TESL, rs2, 30, extract32(ctx->opcode, 1, 6) << 2, 0); + } + break; + case OPC_RH850_16bit_SSTB: + gen_store(ctx, MO_UB, 30, rs2, (extract32(ctx->opcode, 0, 7)), 0); + /// Note An MDP exception might occur depending on the result of address calculation. + break; + case OPC_RH850_16bit_SSTH: + gen_store(ctx, MO_TEUW, 30, rs2, (extract32(ctx->opcode, 0, 7)) << 1, 0); + /// Note An MAE or MDP exception might occur + ///depending on the result of address calculation. + break; + } +} + + +// ################################################################################### +// ################################################################################### +// ################################################################################### + +static void rh850_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) +{ + DisasContext *dc = container_of(dcbase, DisasContext, base); + struct uc_struct *uc = cpu->uc; + dc->uc = uc; + + CPURH850State *env = cpu->env_ptr; + dc->env = env; + dc->pc = dc->base.pc_first; +} + +static void rh850_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu) +{ +} + +static void rh850_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) +{ + DisasContext *dc = container_of(dcbase, DisasContext, base); + TCGContext *tcg_ctx = dc->uc->tcg_ctx; + + tcg_gen_insn_start(tcg_ctx, dc->base.pc_next); +} + +/* + * This f. is called when breakpoint is hit. It should implement + * handling of breakpoint - for example HW breakpoints may be + * handled differently from SW breakpoints (see arm/translate.c). + * However, in RH850 we currently implement only SW breakpoints. + * + * Comment from translator.c: + * The breakpoint_check hook may use DISAS_TOO_MANY to indicate + * that only one more instruction is to be executed. Otherwise + * it should use DISAS_NORETURN when generating an exception, + * but may use a DISAS_TARGET_* value for Something Else. + */ +static bool rh850_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, + const CPUBreakpoint *bp) +{ + DisasContext *dc = container_of(dcbase, DisasContext, base); + + gen_exception_debug(dc); + /* The address covered by the breakpoint must be included in + [tb->pc, tb->pc + tb->size) in order to for it to be + properly cleared -- thus we increment the PC here so that + the logic setting tb->size below does the right thing. */ + dc->base.pc_next += 2; + dc->base.is_jmp = DISAS_NORETURN; + return true; +} + +/* RH850 instruction translation callback. */ +static void rh850_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) +{ + DisasContext *dc = container_of(dcbase, DisasContext, base); + struct uc_struct *uc = dc->uc; + TCGContext *tcg_ctx = uc->tcg_ctx; + TCGOp *tcg_op, *prev_op = NULL; + CPURH850State *env = dc->env; + bool insn_hook = false; + + if (uc_addr_is_exit(dc->uc, dc->base.pc_next)) { + // imitate PGM exception to halt emulation + dcbase->is_jmp = DISAS_UNICORN_HALT; + } + else + { + #if 0 + // Unicorn: trace this instruction on request + if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, dc->pc)) { + + // Sync PC in advance + tcg_gen_movi_i32(tcg_ctx, cpu_pc, dc->pc); + + // save the last operand + prev_op = tcg_last_op(tcg_ctx); + insn_hook = true; + + gen_uc_tracecode(tcg_ctx, 0xF1F1F1F1, UC_HOOK_CODE_IDX, env->uc, dc->pc); + + // the callback might want to stop emulation immediately + check_exit_request(tcg_ctx); + } + #endif + + dc->opcode = cpu_lduw_code(env, dc->pc); // get opcode from memory + + if ((extract32(dc->opcode, 9, 2) != 0x3) && (extract32(dc->opcode, 5, 11) != 0x17)) { + dc->base.pc_next = dc->pc + 2; + decode_RH850_16(env, dc); //this function includes 32-bit JR and JARL + } else { + dc->opcode = (dc->opcode) | (cpu_lduw_code(env, dc->pc + 2) << 0x10); + if (((extract32(dc->opcode, 6, 11) == 0x41e) && ((extract32(dc->opcode, 17, 2) > 0x1) || + (extract32(dc->opcode, 17, 3) == 0x4))) || + (extract32(dc->opcode, 5, 11) == 0x31) || // 48-bit MOV + (extract32(dc->opcode, 5, 12) == 0x37) || // 48-bit JMP + (extract32(dc->opcode, 5, 11) == 0x17) || // 48-bit JARL & JR + ((extract32(dc->opcode, 5, 11) == 0x3D) && (extract32(dc->opcode, 16, 5) == 0x07)) // 48-bit LD.HU + ) + { + dc->opcode1 = cpu_lduw_code(env, dc->pc + 4); + dc->base.pc_next = dc->pc + 6; + decode_RH850_48(env, dc); + } + else + { + dc->base.pc_next = dc->pc + 4; + decode_RH850_32(env, dc); + } + } + + #if 0 + if (insn_hook) { + // Unicorn: patch the callback to have the proper instruction size. + if (prev_op) { + // As explained further up in the function where prev_op is + // assigned, we move forward in the tail queue, so we're modifying the + // move instruction generated by gen_uc_tracecode() that contains + // the instruction size to assign the proper size (replacing 0xF1F1F1F1). + tcg_op = QTAILQ_NEXT(prev_op, link); + } else { + // this instruction is the first emulated code ever, + // so the instruction operand is the first operand + tcg_op = QTAILQ_FIRST(&tcg_ctx->ops); + } + + tcg_op->args[1] = dc->base.pc_next - dc->pc; + } + #endif + + dc->pc = dc->base.pc_next; + } +} + +static void update_pc_addr(DisasContext *s) +{ + /* psw.addr */ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + tcg_gen_movi_i32(tcg_ctx, tcg_ctx->cpu_pc, s->base.pc_next); +} + +// Emit exit TB code according to base.is_jmp +static void rh850_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) +{ + DisasContext *dc = container_of(dcbase, DisasContext, base); + TCGContext *tcg_ctx = dc->uc->tcg_ctx; + + if (dc->base.is_jmp == DISAS_NORETURN) + { + return; + } + if (dc->base.singlestep_enabled) { + if (dc->base.is_jmp == DISAS_NEXT || dc->base.is_jmp == DISAS_TOO_MANY) { + // PC is not loaded inside TB, so we have to do it here in case of + // single stepping + tcg_gen_movi_tl(tcg_ctx, cpu_pc, dc->pc); + } + gen_exception_debug(dc); + } + + switch (dc->base.is_jmp) + { + case DISAS_UNICORN_HALT: + tcg_gen_movi_tl(tcg_ctx, cpu_pc, dc->pc); + gen_exception_halt(dc); + break; + case DISAS_TOO_MANY: + case DISAS_PC_STALE: + case DISAS_PC_STALE_NOCHAIN: + update_pc_addr(dc); + gen_goto_tb_imm(dc, 0, dc->pc); + break; + case DISAS_INDIRECT_JUMP: + /* PC in CPURH850State must have been updated! */ + tcg_gen_lookup_and_goto_ptr(tcg_ctx); + break; + case DISAS_EXIT_TB: + tcg_gen_exit_tb(tcg_ctx, NULL, 0); + break; + case DISAS_NORETURN: + case DISAS_TB_EXIT_ALREADY_GENERATED: + break; + default: + g_assert_not_reached(); + } +} + +static const TranslatorOps rh850_tr_ops = { + .init_disas_context = rh850_tr_init_disas_context, + .tb_start = rh850_tr_tb_start, + .insn_start = rh850_tr_insn_start, + .breakpoint_check = rh850_tr_breakpoint_check, + .translate_insn = rh850_tr_translate_insn, + .tb_stop = rh850_tr_tb_stop, +}; + +/** + * This function translates one translation block (translation block + * is a sequence of instructions without jumps). Translation block + * is the longest translated sequence of instructions. The sequence + * may be shorter, if we are in singlestep mode (1 instruction), if + * breakpoint is detected, ... - see if statements, which break + * while loop below. + */ + +void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) +{ + DisasContext dc; + translator_loop(&rh850_tr_ops, &dc.base, cpu, tb, max_insns); +} + +void rh850_translate_init(struct uc_struct *uc) +{ + TCGContext *tcg_ctx = uc->tcg_ctx; + int i; + + /* cpu_gpr[0] is a placeholder for the zero register. Do not use it. */ + /* Use the gen_set_gpr and gen_get_gpr helper functions when accessing */ + /* registers, unless you specifically block writes to reg 0 */ + + for (i = 0; i < NUM_GP_REGS; i++) { + cpu_gpr[i] = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, + offsetof(CPURH850State, gpRegs[i]), rh850_gp_regnames[i]); + } + + for (int bankIdx = 0; bankIdx < NUM_SYS_REG_BANKS; bankIdx++) { + for (int regIdx = 0; regIdx < MAX_SYS_REGS_IN_BANK; regIdx++) { + const char *regName = rh850_sys_regnames[bankIdx][regIdx]; + if (regName != NULL) { + cpu_sysRegs[bankIdx][regIdx] = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, + offsetof(CPURH850State, systemRegs[bankIdx][regIdx]), + regName); + } else { + cpu_sysRegs[bankIdx][regIdx] = NULL; // mark register as not present + } + } + } + + for (i = 0; i < 1; i++) { + cpu_sysDatabuffRegs[i] = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, + offsetof(CPURH850State, sysDatabuffRegs[i]), rh850_sys_databuff_regnames[i]); + } + + // PSW register flags + cpu_ZF = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, Z_flag), "ZF"); + cpu_SF = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, S_flag), "SF"); + cpu_OVF = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, OV_flag), "OVF"); + cpu_CYF = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, CY_flag), "CYF"); + cpu_SATF = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, SAT_flag), "SAT"); + cpu_ID = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, ID_flag), "ID"); + cpu_EP = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, EP_flag), "EP"); + cpu_NP = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, NP_flag), "NP"); + cpu_EBV = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, EBV_flag), "EBV"); + cpu_CU0 = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, CU0_flag), "CU0"); + cpu_CU1 = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, CU1_flag), "CU1"); + cpu_CU2 = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, CU2_flag), "CU2"); + cpu_UM = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, UM_flag), "UM"); + + cpu_pc = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, pc), "pc"); + load_res = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, load_res), "load_res"); + load_val = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, load_val), "load_val"); + + cpu_LLbit = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, cpu_LLbit), "cpu_LLbit"); + cpu_LLAddress = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPURH850State, cpu_LLAddress), "cpu_LLAddress"); + +} diff --git a/qemu/target/rh850/translate.h b/qemu/target/rh850/translate.h new file mode 100644 index 0000000000..a622c4ce58 --- /dev/null +++ b/qemu/target/rh850/translate.h @@ -0,0 +1,35 @@ +#ifndef _RH850_TRANSLATE_H +#define _RH850_TRANSLATE_H + +#include "cpu.h" +#include "exec/translator.h" +#include "tcg/tcg-op.h" + +/** + * This structure contains data, which is needed to translate a + * sequence of instructions, usually inside one translation + * block. The most important member is therefore 'pc', which + * points to the instruction to be translated. This variable stores + * PC during compile time (guest instructions to TCG instructions). + * We must increment this variable manually during translation + * according to instruction size. + * Note: Consider renaming to TranslationContext, instead of DisasContext, + * because it contains information for translation, not disassembler. + */ +typedef struct DisasContext { + DisasContextBase base; + CPURH850State *env; + target_ulong pc; // pointer to instruction being translated + uint32_t opcode; + uint32_t opcode1; // used for 48 bit instructions + + // Unicorn + struct uc_struct *uc; +} DisasContext; + +void gen_get_gpr(TCGContext *tcg_ctx, TCGv t, int reg_num); +void gen_set_gpr(TCGContext *tcg_ctx, int reg_num_dst, TCGv t); +void gen_set_spr(TCGContext *tcg_ctx, int bank_id, int reg_id, TCGv t); +void gen_get_spr(TCGContext *tcg_ctx, int bank_id, int reg_id, TCGv t); + +#endif /* _RH850_TRANSLATE_H */ \ No newline at end of file diff --git a/qemu/target/rh850/unicorn.c b/qemu/target/rh850/unicorn.c new file mode 100644 index 0000000000..362c92dc8c --- /dev/null +++ b/qemu/target/rh850/unicorn.c @@ -0,0 +1,140 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2021 */ +/* Modified for Unicorn Engine by Damien Cauquil<dcauquil@quarkslab.com>, 2020 */ + +#include "sysemu/cpus.h" +#include "cpu.h" +#include "unicorn_common.h" +#include "uc_priv.h" +#include "unicorn.h" + +RH850CPU *cpu_rh850_init(struct uc_struct *uc, const char *cpu_model); + +static void rh850_set_pc(struct uc_struct *uc, uint64_t address) +{ + ((CPURH850State *)uc->cpu->env_ptr)->pc = address; +} + +static uint64_t rh850_get_pc(struct uc_struct *uc) +{ + return ((CPURH850State *)uc->cpu->env_ptr)->pc; +} + +static void rh850_release(void *ctx) +{ + + int i; + TCGContext *tcg_ctx = (TCGContext *)ctx; + RH850CPU *cpu = (RH850CPU *)tcg_ctx->uc->cpu; + CPUTLBDesc *d = cpu->neg.tlb.d; + CPUTLBDescFast *f = cpu->neg.tlb.f; + CPUTLBDesc *desc; + CPUTLBDescFast *fast; + + release_common(ctx); + for (i = 0; i < NB_MMU_MODES; i++) { + desc = &(d[i]); + fast = &(f[i]); + g_free(desc->iotlb); + g_free(fast->table); + } +} + +static void reg_reset(struct uc_struct *uc) +{ + CPUArchState *env = uc->cpu->env_ptr; + + memset(env->gpRegs, 0, sizeof(env->gpRegs)); + env->pc = 0; +} + +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, size_t *size) +{ + int sel_id; + CPURH850State *env = _env; + uc_err ret = UC_ERR_ARG; + + /* PC */ + if (regid == UC_RH850_REG_PC) + { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->pc; + } + + /* General purpose register. */ + if ((regid >= UC_RH850_REG_R0) && (regid <= UC_RH850_REG_R31)) + { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->gpRegs[regid]; + } + + /* System registers. */ + if ((regid >= UC_RH850_SYSREG_SELID0) && (regid < (UC_RH850_SYSREG_SELID7 + 32))) + { + CHECK_REG_TYPE(uint32_t); + sel_id = (regid - 32)/32; + *(uint32_t *)value = env->systemRegs[sel_id][regid % 32]; + } + + return ret; +} + + +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, size_t *size, int *setpc) +{ + int sel_id; + CPURH850State *env = _env; + uc_err ret = UC_ERR_ARG; + + /* PC */ + if (regid == UC_RH850_REG_PC) + { + CHECK_REG_TYPE(uint32_t); + env->pc = *(uint32_t *)value; + *setpc = 1; + } + + /* General purpose register. */ + if ((regid >= UC_RH850_REG_R0) && (regid <= UC_RH850_REG_R31)) + { + CHECK_REG_TYPE(uint32_t); + env->gpRegs[regid] = *(uint32_t *)value; + } + + /* System registers. */ + if ((regid >= UC_RH850_SYSREG_SELID0) && (regid <= (UC_RH850_SYSREG_SELID7 + 32))) + { + CHECK_REG_TYPE(uint32_t); + sel_id = (regid - 32)/32; + env->systemRegs[sel_id][regid % 32] = *(uint32_t *)value; + } + + return ret; +} + +static int rh850_cpus_init(struct uc_struct *uc, const char *cpu_model) +{ + RH850CPU *cpu; + + cpu = cpu_rh850_init(uc, cpu_model); + if (cpu == NULL) { + return -1; + } + return 0; +} + +DEFAULT_VISIBILITY +void rh850_uc_init(struct uc_struct *uc) +{ + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; + uc->release = rh850_release; + uc->set_pc = rh850_set_pc; + uc->get_pc = rh850_get_pc; + uc->cpus_init = rh850_cpus_init; + uc->cpu_context_size = offsetof(CPURH850State, uc); + uc_common_init(uc); +} diff --git a/qemu/target/rh850/unicorn.h b/qemu/target/rh850/unicorn.h new file mode 100644 index 0000000000..7ce57301a4 --- /dev/null +++ b/qemu/target/rh850/unicorn.h @@ -0,0 +1,16 @@ +/* Unicorn Emulator Engine */ +/* By Damien Cauquil <dcauquil@quarkslab.com>, 2023 */ + +#ifndef UC_QEMU_TARGET_RH850_H +#define UC_QEMU_TARGET_RH850_H + +// functions to read & write registers +uc_err reg_read_rh850(void *_env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_rh850(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc); + +void reg_reset_rh850(struct uc_struct *uc); + +void rh850_uc_init(struct uc_struct *uc); +#endif diff --git a/samples/sample_rh850.c b/samples/sample_rh850.c new file mode 100644 index 0000000000..8f74bf5e77 --- /dev/null +++ b/samples/sample_rh850.c @@ -0,0 +1,118 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2021 */ + +/* Sample code to demonstrate how to emulate S390X code */ + +#include <unicorn/unicorn.h> +#include <string.h> + +// code to be emulated +#define RH850_CODE "\x01\x0e\x06\x00\xc1\x11\x01\x1f\x00\x00\x41\x1f\x00\x00" + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, + void *user_data) +{ + printf(">>> Tracing basic block at 0x%" PRIx64 ", block size = 0x%x\n", + address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, + void *user_data) +{ + printf(">>> Tracing instruction at 0x%" PRIx64 + ", instruction size = 0x%x\n", + address, size); +} + +static void hook_mem64(uc_engine *uc, uc_mem_type type, uint64_t address, + int size, int64_t value, void *user_data) +{ + uint64_t pc; + switch (type) { + default: + break; + case UC_MEM_READ: + uc_reg_read(uc, UC_RH850_REG_PC, &pc); + printf(">>> Memory read operation at 0x%" PRIx64 "\n", pc); + printf(">>> Memory is being READ at 0x%" PRIx64 ", data size = %u\n", + address, size); + break; + case UC_MEM_WRITE: + uc_reg_read(uc, UC_RH850_REG_PC, &pc); + printf(">>> Memory write operation at 0x%" PRIx64 "\n", pc); + printf(">>> Memory is being WRITE at 0x%" PRIx64 + ", data size = %u, data value = 0x%" PRIx64 "\n", + address, size, value); + break; + } +} + + +static void test_rh850(void) +{ + uc_engine *uc; + uc_hook trace1, trace2, trace3; + uc_err err; + + uint64_t r1 = 0x10000, r2 = 3, r3; + + printf("Emulate RH850 code\n"); + + // Initialize emulator in S390X mode + err = uc_open(UC_ARCH_RH850, UC_MODE_LITTLE_ENDIAN, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", err, + uc_strerror(err)); + return; + } + + // map 1MB memory for this emulation + uc_mem_map(uc, ADDRESS, 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, RH850_CODE, sizeof(RH850_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_RH850_REG_R1, &r1); + uc_reg_write(uc, UC_RH850_REG_R2, &r2); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); + + // tracing all instruction + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0); + + // tracing mem read + uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(RH850_CODE) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, + uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_RH850_REG_R1, &r1); + uc_reg_read(uc, UC_RH850_REG_R2, &r2); + uc_reg_read(uc, UC_RH850_REG_R3, &r3); + + printf(">>> R1 = 0x%" PRIx64 "\t\t>>> R2 = 0x%" PRIx64 "\n", r1, r2); + printf(">>> R3 = 0x%" PRIx64 "\n", r3); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + test_rh850(); + + return 0; +} diff --git a/symbols.sh b/symbols.sh index e038b46fb3..456922703b 100755 --- a/symbols.sh +++ b/symbols.sh @@ -6268,6 +6268,12 @@ tcg_s390_program_interrupt \ tcg_s390_data_exception \ " +rh850_SYMBOLS="restore_state_to_opc \ +helper_tlb_flush \ +helper_uc_rh850_exit \ +gen_intermediate_code \ +" + tricore_SYMBOLS=" helper_fadd \ helper_fsub \ @@ -6281,7 +6287,7 @@ restore_state_to_opc \ helper_uc_tricore_exit \ " -ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore" +ARCHS="x86_64 arm aarch64 rh850 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore" for arch in $ARCHS; do diff --git a/tests/unit/test_rh850.c b/tests/unit/test_rh850.c new file mode 100644 index 0000000000..e02e704167 --- /dev/null +++ b/tests/unit/test_rh850.c @@ -0,0 +1,40 @@ +#include "unicorn_test.h" + +const uint64_t code_start = 0x1000; +const uint64_t code_len = 0x4000; + +static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode, + const char *code, uint64_t size) +{ + OK(uc_open(arch, mode, uc)); + OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL)); + OK(uc_mem_write(*uc, code_start, code, size)); +} + +static void test_rh850_add(void) +{ + char code[] = "\x01\x0e\x06\x00\xc1\x11"; + uint32_t r1 = 0x1234; + uint32_t r2 = 0x7777; + uint32_t pc; + uc_engine *uc; + + uc_common_setup(&uc, UC_ARCH_RH850, UC_MODE_LITTLE_ENDIAN, code, + sizeof(code) - 1); + OK(uc_reg_write(uc, UC_RH850_REG_R1, &r1)); + OK(uc_reg_write(uc, UC_RH850_REG_R2, &r2)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_RH850_REG_R1, &r1)); + OK(uc_reg_read(uc, UC_RH850_REG_R2, &r2)); + OK(uc_reg_read(uc, UC_RH850_REG_PC, &pc)); + + TEST_CHECK(r1 == 0x1234 + 6); + TEST_CHECK(r2 == 0x89b1); + TEST_CHECK(pc == code_start + sizeof(code) - 1); + + OK(uc_close(uc)); +} + +TEST_LIST = {{"test_rh850_add", test_rh850_add}, {NULL, NULL}}; \ No newline at end of file diff --git a/uc.c b/uc.c index 1098344711..ae961ede49 100644 --- a/uc.c +++ b/uc.c @@ -23,6 +23,7 @@ #include "qemu/target/mips/unicorn.h" #include "qemu/target/sparc/unicorn.h" #include "qemu/target/ppc/unicorn.h" +#include "qemu/target/rh850/unicorn.h" #include "qemu/target/riscv/unicorn.h" #include "qemu/target/s390x/unicorn.h" #include "qemu/target/tricore/unicorn.h" @@ -187,6 +188,10 @@ bool uc_arch_supported(uc_arch arch) case UC_ARCH_X86: return true; #endif +#ifdef UNICORN_HAS_RH850 + case UC_ARCH_RH850: + return true; +#endif #ifdef UNICORN_HAS_RISCV case UC_ARCH_RISCV: return true; @@ -401,6 +406,15 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) } break; #endif +#ifdef UNICORN_HAS_RH850 + case UC_ARCH_RH850: + if (mode != UC_MODE_LITTLE_ENDIAN) { + free(uc); + return UC_ERR_MODE; + } + uc->init_arch = rh850_uc_init; + break; +#endif #ifdef UNICORN_HAS_RISCV case UC_ARCH_RISCV: if ((mode & ~UC_MODE_RISCV_MASK) || @@ -971,6 +985,11 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, } break; #endif +#ifdef UNICORN_HAS_RH850 + case UC_ARCH_RH850: + uc_reg_write(uc, UC_RH850_REG_PC, &begin); + break; +#endif #ifdef UNICORN_HAS_RISCV case UC_ARCH_RISCV: if (uc->mode & UC_MODE_RISCV64) { @@ -1046,6 +1065,7 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, if (timeout) { // wait for the timer to finish + printf("Wait VM to finish ...\n"); qemu_thread_join(&uc->timer); } @@ -2130,6 +2150,12 @@ static context_reg_rw_t find_context_reg_rw(uc_arch arch, uc_mode mode) } break; #endif +#ifdef UNICORN_HAS_RH850 + case UC_ARCH_RH850: + rw.read = reg_read_rh850; + rw.write = reg_write_rh850; + break; +#endif #ifdef UNICORN_HAS_RISCV case UC_ARCH_RISCV: if (mode & UC_MODE_RISCV32) {