diff --git a/CMakeLists.txt b/CMakeLists.txt index b1f389bf49..02fb38593d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,7 @@ option(UNICORN_FUZZ "Enable fuzzing" OFF) option(UNICORN_LOGGING "Enable logging" 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;s390x;tricore;avr" CACHE STRING "Enabled unicorn architectures") option(UNICORN_TRACER "Trace unicorn execution" OFF) foreach(ARCH_LOOP ${UNICORN_ARCH}) @@ -273,6 +273,11 @@ else() set(UNICORN_TARGET_ARCH "tricore") break() endif() + string(FIND ${UC_COMPILER_MACRO} "__AVR__" UC_RET) + if (${UC_RET} GREATER_EQUAL "0") + set(UNICORN_TARGET_ARCH "avr") + break() + endif() message(FATAL_ERROR "Unknown host compiler: ${CMAKE_C_COMPILER}.") endwhile(TRUE) endif() @@ -308,6 +313,9 @@ else() if (UNICORN_HAS_TRICORE) set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_TRICORE ") endif() + if (UNICORN_HAS_AVR) + set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_AVR ") + endif() set(EXTRA_CFLAGS "${EXTRA_CFLAGS}-fPIC") if(ANDROID_ABI) @@ -359,6 +367,9 @@ else() if (UNICORN_HAS_TRICORE) set (TARGET_LIST "${TARGET_LIST}tricore-softmmu, ") endif() + if (UNICORN_HAS_AVR) + set (TARGET_LIST "${TARGET_LIST}avr-softmmu, ") + endif() set(TARGET_LIST "${TARGET_LIST} ") # GEN config-host.mak & target directories @@ -456,6 +467,12 @@ else() OUTPUT_FILE ${CMAKE_BINARY_DIR}/tricore-softmmu/config-target.h ) endif() + if (UNICORN_HAS_AVR) + execute_process(COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/qemu/scripts/create_config + INPUT_FILE ${CMAKE_BINARY_DIR}/avr-softmmu/config-target.mak + OUTPUT_FILE ${CMAKE_BINARY_DIR}/avr-softmmu/config-target.h + ) + endif() add_compile_options( ${UNICORN_CFLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/qemu/tcg/${UNICORN_TARGET_ARCH} @@ -1154,6 +1171,34 @@ endif() endif() +if (UNICORN_HAS_AVR) +add_library(avr-softmmu STATIC + ${UNICORN_ARCH_COMMON} + + qemu/target/avr/cpu.c + qemu/target/avr/helper.c + qemu/target/avr/translate.c + qemu/target/avr/unicorn.c +) + +if(MSVC) + target_compile_options(avr-softmmu PRIVATE + -DNEED_CPU_H + /FIavr.h + /I${CMAKE_CURRENT_SOURCE_DIR}/msvc/avr-softmmu + /I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/avr + ) +else() + target_compile_options(avr-softmmu PRIVATE + -DNEED_CPU_H + -include avr.h + -I${CMAKE_BINARY_DIR}/avr-softmmu + -I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/avr + ) +endif() +endif() + + set(UNICORN_SRCS uc.c @@ -1328,6 +1373,13 @@ if (UNICORN_HAS_TRICORE) target_link_libraries(tricore-softmmu unicorn-common) set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_tricore) endif() +if (UNICORN_HAS_AVR) + set(UNICORN_COMPILE_OPTIONS ${UNICORN_COMPILE_OPTIONS} -DUNICORN_HAS_AVR) + set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} avr-softmmu) + set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_avr) + target_link_libraries(avr-softmmu unicorn-common) + set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_avr) +endif() # Extra tests set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_mem) diff --git a/CREDITS.TXT b/CREDITS.TXT index ee443858b7..f2dc6118a0 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -81,3 +81,4 @@ Ziqiao Kong (lazymio): uc_context_free() API and various bug fix & improvement. Sven Almgren (blindmatrix): bug fix Chenxu Wu (kabeor): Documentation Philipp Takacs: virtual tlb, memory snapshots +Glenn Baker: AVR architecture support diff --git a/Cargo.toml b/Cargo.toml index 76db12c3f0..d1e7975fca 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_avr"] arch_x86 = [] arch_arm = [] # NOTE: unicorn-c only separates on top-level arch name, @@ -55,3 +55,4 @@ arch_m68k = [] arch_ppc = [] arch_s390x = [] arch_tricore = [] +arch_avr = [] diff --git a/README.md b/README.md index 293d05db01..cc07f1d4ce 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framew Unicorn offers some unparalleled features: -- Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, PowerPC, RISCV, SPARC, S390X, TriCore and X86 (16, 32, 64-bit) +- Multi-architecture: ARM, ARM64 (ARMv8), AVR, M68K, MIPS, PowerPC, RISCV, SPARC, S390X, TriCore and X86 (16, 32, 64-bit) - Clean/simple/lightweight/intuitive architecture-neutral API - Implemented in pure C language, with bindings for Crystal, Clojure, Visual Basic, Perl, Rust, Ruby, Python, Java, .NET, Go, Delphi/Free Pascal, Haskell, Pharo, Lua and Zig. - Native support for Windows & *nix (with Mac OSX, Linux, Android, *BSD & Solaris confirmed) diff --git a/bindings/const_generator.py b/bindings/const_generator.py index 982b48f4cb..2243548cec 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', 'avr.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'ppc.h', 'riscv.h', 's390x.h', 'tricore.h', 'unicorn.h' ] template = { 'python': { @@ -17,6 +17,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'arm', 'arm64.h': 'arm64', + 'avr.h': 'avr', 'mips.h': 'mips', 'x86.h': 'x86', 'sparc.h': 'sparc', @@ -37,6 +38,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'arm', 'arm64.h': 'arm64', + 'avr.h': 'avr', 'mips.h': 'mips', 'x86.h': 'x86', 'sparc.h': 'sparc', @@ -57,6 +59,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'arm', 'arm64.h': 'arm64', + 'avr.h': 'avr', 'mips.h': 'mips', 'x86.h': 'x86', 'sparc.h': 'sparc', @@ -77,6 +80,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'Arm', 'arm64.h': 'Arm64', + 'avr.h': 'AVR', 'mips.h': 'Mips', 'x86.h': 'X86', 'sparc.h': 'Sparc', @@ -97,6 +101,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'Arm', 'arm64.h': 'Arm64', + 'avr.h': 'AVR', 'mips.h': 'Mips', 'x86.h': 'X86', 'sparc.h': 'Sparc', @@ -117,6 +122,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'Arm', 'arm64.h': 'Arm64', + 'avr.h': 'AVR', 'mips.h': 'Mips', 'x86.h': 'X86', 'sparc.h': 'Sparc', @@ -137,6 +143,7 @@ # prefixes for constant filenames of all archs - case sensitive 'arm.h': 'arm', 'arm64.h': 'arm64', + 'avr.h': 'AVR', 'mips.h': 'mips', 'x86.h': 'x86', 'sparc.h': 'sparc', diff --git a/bindings/dotnet/UnicornEngine/Const/AVR.fs b/bindings/dotnet/UnicornEngine/Const/AVR.fs new file mode 100644 index 0000000000..d7613dac85 --- /dev/null +++ b/bindings/dotnet/UnicornEngine/Const/AVR.fs @@ -0,0 +1,155 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +namespace UnicornEngine.Const + +open System + +[] +module AVR = + + // AVR architectures + let UC_AVR_ARCH_AVR1 = 10 + let UC_AVR_ARCH_AVR2 = 20 + let UC_AVR_ARCH_AVR25 = 25 + let UC_AVR_ARCH_AVR3 = 30 + let UC_AVR_ARCH_AVR4 = 40 + let UC_AVR_ARCH_AVR5 = 50 + let UC_AVR_ARCH_AVR51 = 51 + let UC_AVR_ARCH_AVR6 = 60 + let UC_CPU_AVR_ARCH = 1000 + + // AVR CPU + let UC_CPU_AVR_ATMEGA16 = 50016 + let UC_CPU_AVR_ATMEGA32 = 50032 + let UC_CPU_AVR_ATMEGA64 = 50064 + let UC_CPU_AVR_ATMEGA128 = 51128 + let UC_CPU_AVR_ATMEGA128RFR2 = 51129 + let UC_CPU_AVR_ATMEGA1280 = 51130 + let UC_CPU_AVR_ATMEGA256 = 60256 + let UC_CPU_AVR_ATMEGA256RFR2 = 60257 + let UC_CPU_AVR_ATMEGA2560 = 60258 + + // AVR memory + let UC_AVR_MEM_FLASH = 134217728 + + // AVR registers + + let UC_AVR_REG_INVALID = 0 + let UC_AVR_REG_R0 = 1 + let UC_AVR_REG_R1 = 2 + let UC_AVR_REG_R2 = 3 + let UC_AVR_REG_R3 = 4 + let UC_AVR_REG_R4 = 5 + let UC_AVR_REG_R5 = 6 + let UC_AVR_REG_R6 = 7 + let UC_AVR_REG_R7 = 8 + let UC_AVR_REG_R8 = 9 + let UC_AVR_REG_R9 = 10 + let UC_AVR_REG_R10 = 11 + let UC_AVR_REG_R11 = 12 + let UC_AVR_REG_R12 = 13 + let UC_AVR_REG_R13 = 14 + let UC_AVR_REG_R14 = 15 + let UC_AVR_REG_R15 = 16 + let UC_AVR_REG_R16 = 17 + let UC_AVR_REG_R17 = 18 + let UC_AVR_REG_R18 = 19 + let UC_AVR_REG_R19 = 20 + let UC_AVR_REG_R20 = 21 + let UC_AVR_REG_R21 = 22 + let UC_AVR_REG_R22 = 23 + let UC_AVR_REG_R23 = 24 + let UC_AVR_REG_R24 = 25 + let UC_AVR_REG_R25 = 26 + let UC_AVR_REG_R26 = 27 + let UC_AVR_REG_R27 = 28 + let UC_AVR_REG_R28 = 29 + let UC_AVR_REG_R29 = 30 + let UC_AVR_REG_R30 = 31 + let UC_AVR_REG_R31 = 32 + let UC_AVR_REG_PC = 33 + let UC_AVR_REG_SP = 34 + let UC_AVR_REG_RAMPD = 57 + let UC_AVR_REG_RAMPX = 58 + let UC_AVR_REG_RAMPY = 59 + let UC_AVR_REG_RAMPZ = 60 + let UC_AVR_REG_EIND = 61 + let UC_AVR_REG_SPL = 62 + let UC_AVR_REG_SPH = 63 + let UC_AVR_REG_SREG = 64 + + // 16-bit coalesced registers + let UC_AVR_REG_R0W = 65 + let UC_AVR_REG_R1W = 66 + let UC_AVR_REG_R2W = 67 + let UC_AVR_REG_R3W = 68 + let UC_AVR_REG_R4W = 69 + let UC_AVR_REG_R5W = 70 + let UC_AVR_REG_R6W = 71 + let UC_AVR_REG_R7W = 72 + let UC_AVR_REG_R8W = 73 + let UC_AVR_REG_R9W = 74 + let UC_AVR_REG_R10W = 75 + let UC_AVR_REG_R11W = 76 + let UC_AVR_REG_R12W = 77 + let UC_AVR_REG_R13W = 78 + let UC_AVR_REG_R14W = 79 + let UC_AVR_REG_R15W = 80 + let UC_AVR_REG_R16W = 81 + let UC_AVR_REG_R17W = 82 + let UC_AVR_REG_R18W = 83 + let UC_AVR_REG_R19W = 84 + let UC_AVR_REG_R20W = 85 + let UC_AVR_REG_R21W = 86 + let UC_AVR_REG_R22W = 87 + let UC_AVR_REG_R23W = 88 + let UC_AVR_REG_R24W = 89 + let UC_AVR_REG_R25W = 90 + let UC_AVR_REG_R26W = 91 + let UC_AVR_REG_R27W = 92 + let UC_AVR_REG_R28W = 93 + let UC_AVR_REG_R29W = 94 + let UC_AVR_REG_R30W = 95 + + // 32-bit coalesced registers + let UC_AVR_REG_R0D = 97 + let UC_AVR_REG_R1D = 98 + let UC_AVR_REG_R2D = 99 + let UC_AVR_REG_R3D = 100 + let UC_AVR_REG_R4D = 101 + let UC_AVR_REG_R5D = 102 + let UC_AVR_REG_R6D = 103 + let UC_AVR_REG_R7D = 104 + let UC_AVR_REG_R8D = 105 + let UC_AVR_REG_R9D = 106 + let UC_AVR_REG_R10D = 107 + let UC_AVR_REG_R11D = 108 + let UC_AVR_REG_R12D = 109 + let UC_AVR_REG_R13D = 110 + let UC_AVR_REG_R14D = 111 + let UC_AVR_REG_R15D = 112 + let UC_AVR_REG_R16D = 113 + let UC_AVR_REG_R17D = 114 + let UC_AVR_REG_R18D = 115 + let UC_AVR_REG_R19D = 116 + let UC_AVR_REG_R20D = 117 + let UC_AVR_REG_R21D = 118 + let UC_AVR_REG_R22D = 119 + let UC_AVR_REG_R23D = 120 + let UC_AVR_REG_R24D = 121 + let UC_AVR_REG_R25D = 122 + let UC_AVR_REG_R26D = 123 + let UC_AVR_REG_R27D = 124 + let UC_AVR_REG_R28D = 125 + + // Alias registers + let UC_AVR_REG_Xhi = 28 + let UC_AVR_REG_Xlo = 27 + let UC_AVR_REG_Yhi = 30 + let UC_AVR_REG_Ylo = 29 + let UC_AVR_REG_Zhi = 32 + let UC_AVR_REG_Zlo = 31 + let UC_AVR_REG_X = 91 + let UC_AVR_REG_Y = 93 + let UC_AVR_REG_Z = 95 + diff --git a/bindings/dotnet/UnicornEngine/Const/Common.fs b/bindings/dotnet/UnicornEngine/Const/Common.fs index 76f1ce118b..4b97dbdbb5 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_AVR = 11 + let UC_ARCH_MAX = 12 let UC_MODE_LITTLE_ENDIAN = 0 let UC_MODE_BIG_ENDIAN = 1073741824 diff --git a/bindings/go/unicorn/avr_const.go b/bindings/go/unicorn/avr_const.go new file mode 100644 index 0000000000..985bf7d009 --- /dev/null +++ b/bindings/go/unicorn/avr_const.go @@ -0,0 +1,150 @@ +package unicorn +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [avr_const.go] +const ( + +// AVR architectures + AVR_ARCH_AVR1 = 10 + AVR_ARCH_AVR2 = 20 + AVR_ARCH_AVR25 = 25 + AVR_ARCH_AVR3 = 30 + AVR_ARCH_AVR4 = 40 + AVR_ARCH_AVR5 = 50 + AVR_ARCH_AVR51 = 51 + AVR_ARCH_AVR6 = 60 + CPU_AVR_ARCH = 1000 + +// AVR CPU + CPU_AVR_ATMEGA16 = 50016 + CPU_AVR_ATMEGA32 = 50032 + CPU_AVR_ATMEGA64 = 50064 + CPU_AVR_ATMEGA128 = 51128 + CPU_AVR_ATMEGA128RFR2 = 51129 + CPU_AVR_ATMEGA1280 = 51130 + CPU_AVR_ATMEGA256 = 60256 + CPU_AVR_ATMEGA256RFR2 = 60257 + CPU_AVR_ATMEGA2560 = 60258 + +// AVR memory + AVR_MEM_FLASH = 134217728 + +// AVR registers + + AVR_REG_INVALID = 0 + AVR_REG_R0 = 1 + AVR_REG_R1 = 2 + AVR_REG_R2 = 3 + AVR_REG_R3 = 4 + AVR_REG_R4 = 5 + AVR_REG_R5 = 6 + AVR_REG_R6 = 7 + AVR_REG_R7 = 8 + AVR_REG_R8 = 9 + AVR_REG_R9 = 10 + AVR_REG_R10 = 11 + AVR_REG_R11 = 12 + AVR_REG_R12 = 13 + AVR_REG_R13 = 14 + AVR_REG_R14 = 15 + AVR_REG_R15 = 16 + AVR_REG_R16 = 17 + AVR_REG_R17 = 18 + AVR_REG_R18 = 19 + AVR_REG_R19 = 20 + AVR_REG_R20 = 21 + AVR_REG_R21 = 22 + AVR_REG_R22 = 23 + AVR_REG_R23 = 24 + AVR_REG_R24 = 25 + AVR_REG_R25 = 26 + AVR_REG_R26 = 27 + AVR_REG_R27 = 28 + AVR_REG_R28 = 29 + AVR_REG_R29 = 30 + AVR_REG_R30 = 31 + AVR_REG_R31 = 32 + AVR_REG_PC = 33 + AVR_REG_SP = 34 + AVR_REG_RAMPD = 57 + AVR_REG_RAMPX = 58 + AVR_REG_RAMPY = 59 + AVR_REG_RAMPZ = 60 + AVR_REG_EIND = 61 + AVR_REG_SPL = 62 + AVR_REG_SPH = 63 + AVR_REG_SREG = 64 + +// 16-bit coalesced registers + AVR_REG_R0W = 65 + AVR_REG_R1W = 66 + AVR_REG_R2W = 67 + AVR_REG_R3W = 68 + AVR_REG_R4W = 69 + AVR_REG_R5W = 70 + AVR_REG_R6W = 71 + AVR_REG_R7W = 72 + AVR_REG_R8W = 73 + AVR_REG_R9W = 74 + AVR_REG_R10W = 75 + AVR_REG_R11W = 76 + AVR_REG_R12W = 77 + AVR_REG_R13W = 78 + AVR_REG_R14W = 79 + AVR_REG_R15W = 80 + AVR_REG_R16W = 81 + AVR_REG_R17W = 82 + AVR_REG_R18W = 83 + AVR_REG_R19W = 84 + AVR_REG_R20W = 85 + AVR_REG_R21W = 86 + AVR_REG_R22W = 87 + AVR_REG_R23W = 88 + AVR_REG_R24W = 89 + AVR_REG_R25W = 90 + AVR_REG_R26W = 91 + AVR_REG_R27W = 92 + AVR_REG_R28W = 93 + AVR_REG_R29W = 94 + AVR_REG_R30W = 95 + +// 32-bit coalesced registers + AVR_REG_R0D = 97 + AVR_REG_R1D = 98 + AVR_REG_R2D = 99 + AVR_REG_R3D = 100 + AVR_REG_R4D = 101 + AVR_REG_R5D = 102 + AVR_REG_R6D = 103 + AVR_REG_R7D = 104 + AVR_REG_R8D = 105 + AVR_REG_R9D = 106 + AVR_REG_R10D = 107 + AVR_REG_R11D = 108 + AVR_REG_R12D = 109 + AVR_REG_R13D = 110 + AVR_REG_R14D = 111 + AVR_REG_R15D = 112 + AVR_REG_R16D = 113 + AVR_REG_R17D = 114 + AVR_REG_R18D = 115 + AVR_REG_R19D = 116 + AVR_REG_R20D = 117 + AVR_REG_R21D = 118 + AVR_REG_R22D = 119 + AVR_REG_R23D = 120 + AVR_REG_R24D = 121 + AVR_REG_R25D = 122 + AVR_REG_R26D = 123 + AVR_REG_R27D = 124 + AVR_REG_R28D = 125 + +// Alias registers + AVR_REG_Xhi = 28 + AVR_REG_Xlo = 27 + AVR_REG_Yhi = 30 + AVR_REG_Ylo = 29 + AVR_REG_Zhi = 32 + AVR_REG_Zlo = 31 + AVR_REG_X = 91 + AVR_REG_Y = 93 + AVR_REG_Z = 95 +) \ No newline at end of file diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 16b03619ae..796f8d2b06 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_AVR = 11 + ARCH_MAX = 12 MODE_LITTLE_ENDIAN = 0 MODE_BIG_ENDIAN = 1073741824 diff --git a/bindings/java/src/main/java/unicorn/AVRConst.java b/bindings/java/src/main/java/unicorn/AVRConst.java new file mode 100644 index 0000000000..066fd97774 --- /dev/null +++ b/bindings/java/src/main/java/unicorn/AVRConst.java @@ -0,0 +1,153 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +package unicorn; + +public interface AVRConst { + + // AVR architectures + public static final int UC_AVR_ARCH_AVR1 = 10; + public static final int UC_AVR_ARCH_AVR2 = 20; + public static final int UC_AVR_ARCH_AVR25 = 25; + public static final int UC_AVR_ARCH_AVR3 = 30; + public static final int UC_AVR_ARCH_AVR4 = 40; + public static final int UC_AVR_ARCH_AVR5 = 50; + public static final int UC_AVR_ARCH_AVR51 = 51; + public static final int UC_AVR_ARCH_AVR6 = 60; + public static final int UC_CPU_AVR_ARCH = 1000; + + // AVR CPU + public static final int UC_CPU_AVR_ATMEGA16 = 50016; + public static final int UC_CPU_AVR_ATMEGA32 = 50032; + public static final int UC_CPU_AVR_ATMEGA64 = 50064; + public static final int UC_CPU_AVR_ATMEGA128 = 51128; + public static final int UC_CPU_AVR_ATMEGA128RFR2 = 51129; + public static final int UC_CPU_AVR_ATMEGA1280 = 51130; + public static final int UC_CPU_AVR_ATMEGA256 = 60256; + public static final int UC_CPU_AVR_ATMEGA256RFR2 = 60257; + public static final int UC_CPU_AVR_ATMEGA2560 = 60258; + + // AVR memory + public static final int UC_AVR_MEM_FLASH = 134217728; + + // AVR registers + + public static final int UC_AVR_REG_INVALID = 0; + public static final int UC_AVR_REG_R0 = 1; + public static final int UC_AVR_REG_R1 = 2; + public static final int UC_AVR_REG_R2 = 3; + public static final int UC_AVR_REG_R3 = 4; + public static final int UC_AVR_REG_R4 = 5; + public static final int UC_AVR_REG_R5 = 6; + public static final int UC_AVR_REG_R6 = 7; + public static final int UC_AVR_REG_R7 = 8; + public static final int UC_AVR_REG_R8 = 9; + public static final int UC_AVR_REG_R9 = 10; + public static final int UC_AVR_REG_R10 = 11; + public static final int UC_AVR_REG_R11 = 12; + public static final int UC_AVR_REG_R12 = 13; + public static final int UC_AVR_REG_R13 = 14; + public static final int UC_AVR_REG_R14 = 15; + public static final int UC_AVR_REG_R15 = 16; + public static final int UC_AVR_REG_R16 = 17; + public static final int UC_AVR_REG_R17 = 18; + public static final int UC_AVR_REG_R18 = 19; + public static final int UC_AVR_REG_R19 = 20; + public static final int UC_AVR_REG_R20 = 21; + public static final int UC_AVR_REG_R21 = 22; + public static final int UC_AVR_REG_R22 = 23; + public static final int UC_AVR_REG_R23 = 24; + public static final int UC_AVR_REG_R24 = 25; + public static final int UC_AVR_REG_R25 = 26; + public static final int UC_AVR_REG_R26 = 27; + public static final int UC_AVR_REG_R27 = 28; + public static final int UC_AVR_REG_R28 = 29; + public static final int UC_AVR_REG_R29 = 30; + public static final int UC_AVR_REG_R30 = 31; + public static final int UC_AVR_REG_R31 = 32; + public static final int UC_AVR_REG_PC = 33; + public static final int UC_AVR_REG_SP = 34; + public static final int UC_AVR_REG_RAMPD = 57; + public static final int UC_AVR_REG_RAMPX = 58; + public static final int UC_AVR_REG_RAMPY = 59; + public static final int UC_AVR_REG_RAMPZ = 60; + public static final int UC_AVR_REG_EIND = 61; + public static final int UC_AVR_REG_SPL = 62; + public static final int UC_AVR_REG_SPH = 63; + public static final int UC_AVR_REG_SREG = 64; + + // 16-bit coalesced registers + public static final int UC_AVR_REG_R0W = 65; + public static final int UC_AVR_REG_R1W = 66; + public static final int UC_AVR_REG_R2W = 67; + public static final int UC_AVR_REG_R3W = 68; + public static final int UC_AVR_REG_R4W = 69; + public static final int UC_AVR_REG_R5W = 70; + public static final int UC_AVR_REG_R6W = 71; + public static final int UC_AVR_REG_R7W = 72; + public static final int UC_AVR_REG_R8W = 73; + public static final int UC_AVR_REG_R9W = 74; + public static final int UC_AVR_REG_R10W = 75; + public static final int UC_AVR_REG_R11W = 76; + public static final int UC_AVR_REG_R12W = 77; + public static final int UC_AVR_REG_R13W = 78; + public static final int UC_AVR_REG_R14W = 79; + public static final int UC_AVR_REG_R15W = 80; + public static final int UC_AVR_REG_R16W = 81; + public static final int UC_AVR_REG_R17W = 82; + public static final int UC_AVR_REG_R18W = 83; + public static final int UC_AVR_REG_R19W = 84; + public static final int UC_AVR_REG_R20W = 85; + public static final int UC_AVR_REG_R21W = 86; + public static final int UC_AVR_REG_R22W = 87; + public static final int UC_AVR_REG_R23W = 88; + public static final int UC_AVR_REG_R24W = 89; + public static final int UC_AVR_REG_R25W = 90; + public static final int UC_AVR_REG_R26W = 91; + public static final int UC_AVR_REG_R27W = 92; + public static final int UC_AVR_REG_R28W = 93; + public static final int UC_AVR_REG_R29W = 94; + public static final int UC_AVR_REG_R30W = 95; + + // 32-bit coalesced registers + public static final int UC_AVR_REG_R0D = 97; + public static final int UC_AVR_REG_R1D = 98; + public static final int UC_AVR_REG_R2D = 99; + public static final int UC_AVR_REG_R3D = 100; + public static final int UC_AVR_REG_R4D = 101; + public static final int UC_AVR_REG_R5D = 102; + public static final int UC_AVR_REG_R6D = 103; + public static final int UC_AVR_REG_R7D = 104; + public static final int UC_AVR_REG_R8D = 105; + public static final int UC_AVR_REG_R9D = 106; + public static final int UC_AVR_REG_R10D = 107; + public static final int UC_AVR_REG_R11D = 108; + public static final int UC_AVR_REG_R12D = 109; + public static final int UC_AVR_REG_R13D = 110; + public static final int UC_AVR_REG_R14D = 111; + public static final int UC_AVR_REG_R15D = 112; + public static final int UC_AVR_REG_R16D = 113; + public static final int UC_AVR_REG_R17D = 114; + public static final int UC_AVR_REG_R18D = 115; + public static final int UC_AVR_REG_R19D = 116; + public static final int UC_AVR_REG_R20D = 117; + public static final int UC_AVR_REG_R21D = 118; + public static final int UC_AVR_REG_R22D = 119; + public static final int UC_AVR_REG_R23D = 120; + public static final int UC_AVR_REG_R24D = 121; + public static final int UC_AVR_REG_R25D = 122; + public static final int UC_AVR_REG_R26D = 123; + public static final int UC_AVR_REG_R27D = 124; + public static final int UC_AVR_REG_R28D = 125; + + // Alias registers + public static final int UC_AVR_REG_Xhi = 28; + public static final int UC_AVR_REG_Xlo = 27; + public static final int UC_AVR_REG_Yhi = 30; + public static final int UC_AVR_REG_Ylo = 29; + public static final int UC_AVR_REG_Zhi = 32; + public static final int UC_AVR_REG_Zlo = 31; + public static final int UC_AVR_REG_X = 91; + public static final int UC_AVR_REG_Y = 93; + public static final int UC_AVR_REG_Z = 95; + +} diff --git a/bindings/java/src/main/java/unicorn/UnicornConst.java b/bindings/java/src/main/java/unicorn/UnicornConst.java index b0d135a845..6e138e0313 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_AVR = 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; diff --git a/bindings/pascal/unicorn/AVRConst.pas b/bindings/pascal/unicorn/AVRConst.pas new file mode 100644 index 0000000000..c607d54ac9 --- /dev/null +++ b/bindings/pascal/unicorn/AVRConst.pas @@ -0,0 +1,155 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit AVRConst; + +interface + +const +// AVR architectures + UC_AVR_ARCH_AVR1 = 10; + UC_AVR_ARCH_AVR2 = 20; + UC_AVR_ARCH_AVR25 = 25; + UC_AVR_ARCH_AVR3 = 30; + UC_AVR_ARCH_AVR4 = 40; + UC_AVR_ARCH_AVR5 = 50; + UC_AVR_ARCH_AVR51 = 51; + UC_AVR_ARCH_AVR6 = 60; + UC_CPU_AVR_ARCH = 1000; + +// AVR CPU + UC_CPU_AVR_ATMEGA16 = 50016; + UC_CPU_AVR_ATMEGA32 = 50032; + UC_CPU_AVR_ATMEGA64 = 50064; + UC_CPU_AVR_ATMEGA128 = 51128; + UC_CPU_AVR_ATMEGA128RFR2 = 51129; + UC_CPU_AVR_ATMEGA1280 = 51130; + UC_CPU_AVR_ATMEGA256 = 60256; + UC_CPU_AVR_ATMEGA256RFR2 = 60257; + UC_CPU_AVR_ATMEGA2560 = 60258; + +// AVR memory + UC_AVR_MEM_FLASH = 134217728; + +// AVR registers + + UC_AVR_REG_INVALID = 0; + UC_AVR_REG_R0 = 1; + UC_AVR_REG_R1 = 2; + UC_AVR_REG_R2 = 3; + UC_AVR_REG_R3 = 4; + UC_AVR_REG_R4 = 5; + UC_AVR_REG_R5 = 6; + UC_AVR_REG_R6 = 7; + UC_AVR_REG_R7 = 8; + UC_AVR_REG_R8 = 9; + UC_AVR_REG_R9 = 10; + UC_AVR_REG_R10 = 11; + UC_AVR_REG_R11 = 12; + UC_AVR_REG_R12 = 13; + UC_AVR_REG_R13 = 14; + UC_AVR_REG_R14 = 15; + UC_AVR_REG_R15 = 16; + UC_AVR_REG_R16 = 17; + UC_AVR_REG_R17 = 18; + UC_AVR_REG_R18 = 19; + UC_AVR_REG_R19 = 20; + UC_AVR_REG_R20 = 21; + UC_AVR_REG_R21 = 22; + UC_AVR_REG_R22 = 23; + UC_AVR_REG_R23 = 24; + UC_AVR_REG_R24 = 25; + UC_AVR_REG_R25 = 26; + UC_AVR_REG_R26 = 27; + UC_AVR_REG_R27 = 28; + UC_AVR_REG_R28 = 29; + UC_AVR_REG_R29 = 30; + UC_AVR_REG_R30 = 31; + UC_AVR_REG_R31 = 32; + UC_AVR_REG_PC = 33; + UC_AVR_REG_SP = 34; + UC_AVR_REG_RAMPD = 57; + UC_AVR_REG_RAMPX = 58; + UC_AVR_REG_RAMPY = 59; + UC_AVR_REG_RAMPZ = 60; + UC_AVR_REG_EIND = 61; + UC_AVR_REG_SPL = 62; + UC_AVR_REG_SPH = 63; + UC_AVR_REG_SREG = 64; + +// 16-bit coalesced registers + UC_AVR_REG_R0W = 65; + UC_AVR_REG_R1W = 66; + UC_AVR_REG_R2W = 67; + UC_AVR_REG_R3W = 68; + UC_AVR_REG_R4W = 69; + UC_AVR_REG_R5W = 70; + UC_AVR_REG_R6W = 71; + UC_AVR_REG_R7W = 72; + UC_AVR_REG_R8W = 73; + UC_AVR_REG_R9W = 74; + UC_AVR_REG_R10W = 75; + UC_AVR_REG_R11W = 76; + UC_AVR_REG_R12W = 77; + UC_AVR_REG_R13W = 78; + UC_AVR_REG_R14W = 79; + UC_AVR_REG_R15W = 80; + UC_AVR_REG_R16W = 81; + UC_AVR_REG_R17W = 82; + UC_AVR_REG_R18W = 83; + UC_AVR_REG_R19W = 84; + UC_AVR_REG_R20W = 85; + UC_AVR_REG_R21W = 86; + UC_AVR_REG_R22W = 87; + UC_AVR_REG_R23W = 88; + UC_AVR_REG_R24W = 89; + UC_AVR_REG_R25W = 90; + UC_AVR_REG_R26W = 91; + UC_AVR_REG_R27W = 92; + UC_AVR_REG_R28W = 93; + UC_AVR_REG_R29W = 94; + UC_AVR_REG_R30W = 95; + +// 32-bit coalesced registers + UC_AVR_REG_R0D = 97; + UC_AVR_REG_R1D = 98; + UC_AVR_REG_R2D = 99; + UC_AVR_REG_R3D = 100; + UC_AVR_REG_R4D = 101; + UC_AVR_REG_R5D = 102; + UC_AVR_REG_R6D = 103; + UC_AVR_REG_R7D = 104; + UC_AVR_REG_R8D = 105; + UC_AVR_REG_R9D = 106; + UC_AVR_REG_R10D = 107; + UC_AVR_REG_R11D = 108; + UC_AVR_REG_R12D = 109; + UC_AVR_REG_R13D = 110; + UC_AVR_REG_R14D = 111; + UC_AVR_REG_R15D = 112; + UC_AVR_REG_R16D = 113; + UC_AVR_REG_R17D = 114; + UC_AVR_REG_R18D = 115; + UC_AVR_REG_R19D = 116; + UC_AVR_REG_R20D = 117; + UC_AVR_REG_R21D = 118; + UC_AVR_REG_R22D = 119; + UC_AVR_REG_R23D = 120; + UC_AVR_REG_R24D = 121; + UC_AVR_REG_R25D = 122; + UC_AVR_REG_R26D = 123; + UC_AVR_REG_R27D = 124; + UC_AVR_REG_R28D = 125; + +// Alias registers + UC_AVR_REG_Xhi = 28; + UC_AVR_REG_Xlo = 27; + UC_AVR_REG_Yhi = 30; + UC_AVR_REG_Ylo = 29; + UC_AVR_REG_Zhi = 32; + UC_AVR_REG_Zlo = 31; + UC_AVR_REG_X = 91; + UC_AVR_REG_Y = 93; + UC_AVR_REG_Z = 95; + +implementation +end. \ No newline at end of file diff --git a/bindings/pascal/unicorn/UnicornConst.pas b/bindings/pascal/unicorn/UnicornConst.pas index 92a99d4a56..63a447f2e9 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_AVR = 11; + UC_ARCH_MAX = 12; UC_MODE_LITTLE_ENDIAN = 0; UC_MODE_BIG_ENDIAN = 1073741824; diff --git a/bindings/python/unicorn/__init__.py b/bindings/python/unicorn/__init__.py index a93e12a05c..04894a8e2b 100644 --- a/bindings/python/unicorn/__init__.py +++ b/bindings/python/unicorn/__init__.py @@ -1,4 +1,4 @@ # Forwarding defs for compatibility -from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const, s390x_const, tricore_const +from . import arm_const, arm64_const, avr_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const, s390x_const, tricore_const from .unicorn_const import * from .unicorn import Uc, ucsubclass, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__ diff --git a/bindings/python/unicorn/avr_const.py b/bindings/python/unicorn/avr_const.py new file mode 100644 index 0000000000..1bf80a3fa5 --- /dev/null +++ b/bindings/python/unicorn/avr_const.py @@ -0,0 +1,147 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [avr_const.py] + +# AVR architectures +UC_AVR_ARCH_AVR1 = 10 +UC_AVR_ARCH_AVR2 = 20 +UC_AVR_ARCH_AVR25 = 25 +UC_AVR_ARCH_AVR3 = 30 +UC_AVR_ARCH_AVR4 = 40 +UC_AVR_ARCH_AVR5 = 50 +UC_AVR_ARCH_AVR51 = 51 +UC_AVR_ARCH_AVR6 = 60 +UC_CPU_AVR_ARCH = 1000 + +# AVR CPU +UC_CPU_AVR_ATMEGA16 = 50016 +UC_CPU_AVR_ATMEGA32 = 50032 +UC_CPU_AVR_ATMEGA64 = 50064 +UC_CPU_AVR_ATMEGA128 = 51128 +UC_CPU_AVR_ATMEGA128RFR2 = 51129 +UC_CPU_AVR_ATMEGA1280 = 51130 +UC_CPU_AVR_ATMEGA256 = 60256 +UC_CPU_AVR_ATMEGA256RFR2 = 60257 +UC_CPU_AVR_ATMEGA2560 = 60258 + +# AVR memory +UC_AVR_MEM_FLASH = 134217728 + +# AVR registers + +UC_AVR_REG_INVALID = 0 +UC_AVR_REG_R0 = 1 +UC_AVR_REG_R1 = 2 +UC_AVR_REG_R2 = 3 +UC_AVR_REG_R3 = 4 +UC_AVR_REG_R4 = 5 +UC_AVR_REG_R5 = 6 +UC_AVR_REG_R6 = 7 +UC_AVR_REG_R7 = 8 +UC_AVR_REG_R8 = 9 +UC_AVR_REG_R9 = 10 +UC_AVR_REG_R10 = 11 +UC_AVR_REG_R11 = 12 +UC_AVR_REG_R12 = 13 +UC_AVR_REG_R13 = 14 +UC_AVR_REG_R14 = 15 +UC_AVR_REG_R15 = 16 +UC_AVR_REG_R16 = 17 +UC_AVR_REG_R17 = 18 +UC_AVR_REG_R18 = 19 +UC_AVR_REG_R19 = 20 +UC_AVR_REG_R20 = 21 +UC_AVR_REG_R21 = 22 +UC_AVR_REG_R22 = 23 +UC_AVR_REG_R23 = 24 +UC_AVR_REG_R24 = 25 +UC_AVR_REG_R25 = 26 +UC_AVR_REG_R26 = 27 +UC_AVR_REG_R27 = 28 +UC_AVR_REG_R28 = 29 +UC_AVR_REG_R29 = 30 +UC_AVR_REG_R30 = 31 +UC_AVR_REG_R31 = 32 +UC_AVR_REG_PC = 33 +UC_AVR_REG_SP = 34 +UC_AVR_REG_RAMPD = 57 +UC_AVR_REG_RAMPX = 58 +UC_AVR_REG_RAMPY = 59 +UC_AVR_REG_RAMPZ = 60 +UC_AVR_REG_EIND = 61 +UC_AVR_REG_SPL = 62 +UC_AVR_REG_SPH = 63 +UC_AVR_REG_SREG = 64 + +# 16-bit coalesced registers +UC_AVR_REG_R0W = 65 +UC_AVR_REG_R1W = 66 +UC_AVR_REG_R2W = 67 +UC_AVR_REG_R3W = 68 +UC_AVR_REG_R4W = 69 +UC_AVR_REG_R5W = 70 +UC_AVR_REG_R6W = 71 +UC_AVR_REG_R7W = 72 +UC_AVR_REG_R8W = 73 +UC_AVR_REG_R9W = 74 +UC_AVR_REG_R10W = 75 +UC_AVR_REG_R11W = 76 +UC_AVR_REG_R12W = 77 +UC_AVR_REG_R13W = 78 +UC_AVR_REG_R14W = 79 +UC_AVR_REG_R15W = 80 +UC_AVR_REG_R16W = 81 +UC_AVR_REG_R17W = 82 +UC_AVR_REG_R18W = 83 +UC_AVR_REG_R19W = 84 +UC_AVR_REG_R20W = 85 +UC_AVR_REG_R21W = 86 +UC_AVR_REG_R22W = 87 +UC_AVR_REG_R23W = 88 +UC_AVR_REG_R24W = 89 +UC_AVR_REG_R25W = 90 +UC_AVR_REG_R26W = 91 +UC_AVR_REG_R27W = 92 +UC_AVR_REG_R28W = 93 +UC_AVR_REG_R29W = 94 +UC_AVR_REG_R30W = 95 + +# 32-bit coalesced registers +UC_AVR_REG_R0D = 97 +UC_AVR_REG_R1D = 98 +UC_AVR_REG_R2D = 99 +UC_AVR_REG_R3D = 100 +UC_AVR_REG_R4D = 101 +UC_AVR_REG_R5D = 102 +UC_AVR_REG_R6D = 103 +UC_AVR_REG_R7D = 104 +UC_AVR_REG_R8D = 105 +UC_AVR_REG_R9D = 106 +UC_AVR_REG_R10D = 107 +UC_AVR_REG_R11D = 108 +UC_AVR_REG_R12D = 109 +UC_AVR_REG_R13D = 110 +UC_AVR_REG_R14D = 111 +UC_AVR_REG_R15D = 112 +UC_AVR_REG_R16D = 113 +UC_AVR_REG_R17D = 114 +UC_AVR_REG_R18D = 115 +UC_AVR_REG_R19D = 116 +UC_AVR_REG_R20D = 117 +UC_AVR_REG_R21D = 118 +UC_AVR_REG_R22D = 119 +UC_AVR_REG_R23D = 120 +UC_AVR_REG_R24D = 121 +UC_AVR_REG_R25D = 122 +UC_AVR_REG_R26D = 123 +UC_AVR_REG_R27D = 124 +UC_AVR_REG_R28D = 125 + +# Alias registers +UC_AVR_REG_Xhi = 28 +UC_AVR_REG_Xlo = 27 +UC_AVR_REG_Yhi = 30 +UC_AVR_REG_Ylo = 29 +UC_AVR_REG_Zhi = 32 +UC_AVR_REG_Zlo = 31 +UC_AVR_REG_X = 91 +UC_AVR_REG_Y = 93 +UC_AVR_REG_Z = 95 diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index 46c53ddc14..249f8fed6b 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_AVR = 11 +UC_ARCH_MAX = 12 UC_MODE_LITTLE_ENDIAN = 0 UC_MODE_BIG_ENDIAN = 1073741824 diff --git a/bindings/ruby/unicorn_gem/lib/unicorn_engine/avr_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn_engine/avr_const.rb new file mode 100644 index 0000000000..126ebd0c8f --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn_engine/avr_const.rb @@ -0,0 +1,150 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [avr_const.rb] + +module UnicornEngine + +# AVR architectures + UC_AVR_ARCH_AVR1 = 10 + UC_AVR_ARCH_AVR2 = 20 + UC_AVR_ARCH_AVR25 = 25 + UC_AVR_ARCH_AVR3 = 30 + UC_AVR_ARCH_AVR4 = 40 + UC_AVR_ARCH_AVR5 = 50 + UC_AVR_ARCH_AVR51 = 51 + UC_AVR_ARCH_AVR6 = 60 + UC_CPU_AVR_ARCH = 1000 + +# AVR CPU + UC_CPU_AVR_ATMEGA16 = 50016 + UC_CPU_AVR_ATMEGA32 = 50032 + UC_CPU_AVR_ATMEGA64 = 50064 + UC_CPU_AVR_ATMEGA128 = 51128 + UC_CPU_AVR_ATMEGA128RFR2 = 51129 + UC_CPU_AVR_ATMEGA1280 = 51130 + UC_CPU_AVR_ATMEGA256 = 60256 + UC_CPU_AVR_ATMEGA256RFR2 = 60257 + UC_CPU_AVR_ATMEGA2560 = 60258 + +# AVR memory + UC_AVR_MEM_FLASH = 134217728 + +# AVR registers + + UC_AVR_REG_INVALID = 0 + UC_AVR_REG_R0 = 1 + UC_AVR_REG_R1 = 2 + UC_AVR_REG_R2 = 3 + UC_AVR_REG_R3 = 4 + UC_AVR_REG_R4 = 5 + UC_AVR_REG_R5 = 6 + UC_AVR_REG_R6 = 7 + UC_AVR_REG_R7 = 8 + UC_AVR_REG_R8 = 9 + UC_AVR_REG_R9 = 10 + UC_AVR_REG_R10 = 11 + UC_AVR_REG_R11 = 12 + UC_AVR_REG_R12 = 13 + UC_AVR_REG_R13 = 14 + UC_AVR_REG_R14 = 15 + UC_AVR_REG_R15 = 16 + UC_AVR_REG_R16 = 17 + UC_AVR_REG_R17 = 18 + UC_AVR_REG_R18 = 19 + UC_AVR_REG_R19 = 20 + UC_AVR_REG_R20 = 21 + UC_AVR_REG_R21 = 22 + UC_AVR_REG_R22 = 23 + UC_AVR_REG_R23 = 24 + UC_AVR_REG_R24 = 25 + UC_AVR_REG_R25 = 26 + UC_AVR_REG_R26 = 27 + UC_AVR_REG_R27 = 28 + UC_AVR_REG_R28 = 29 + UC_AVR_REG_R29 = 30 + UC_AVR_REG_R30 = 31 + UC_AVR_REG_R31 = 32 + UC_AVR_REG_PC = 33 + UC_AVR_REG_SP = 34 + UC_AVR_REG_RAMPD = 57 + UC_AVR_REG_RAMPX = 58 + UC_AVR_REG_RAMPY = 59 + UC_AVR_REG_RAMPZ = 60 + UC_AVR_REG_EIND = 61 + UC_AVR_REG_SPL = 62 + UC_AVR_REG_SPH = 63 + UC_AVR_REG_SREG = 64 + +# 16-bit coalesced registers + UC_AVR_REG_R0W = 65 + UC_AVR_REG_R1W = 66 + UC_AVR_REG_R2W = 67 + UC_AVR_REG_R3W = 68 + UC_AVR_REG_R4W = 69 + UC_AVR_REG_R5W = 70 + UC_AVR_REG_R6W = 71 + UC_AVR_REG_R7W = 72 + UC_AVR_REG_R8W = 73 + UC_AVR_REG_R9W = 74 + UC_AVR_REG_R10W = 75 + UC_AVR_REG_R11W = 76 + UC_AVR_REG_R12W = 77 + UC_AVR_REG_R13W = 78 + UC_AVR_REG_R14W = 79 + UC_AVR_REG_R15W = 80 + UC_AVR_REG_R16W = 81 + UC_AVR_REG_R17W = 82 + UC_AVR_REG_R18W = 83 + UC_AVR_REG_R19W = 84 + UC_AVR_REG_R20W = 85 + UC_AVR_REG_R21W = 86 + UC_AVR_REG_R22W = 87 + UC_AVR_REG_R23W = 88 + UC_AVR_REG_R24W = 89 + UC_AVR_REG_R25W = 90 + UC_AVR_REG_R26W = 91 + UC_AVR_REG_R27W = 92 + UC_AVR_REG_R28W = 93 + UC_AVR_REG_R29W = 94 + UC_AVR_REG_R30W = 95 + +# 32-bit coalesced registers + UC_AVR_REG_R0D = 97 + UC_AVR_REG_R1D = 98 + UC_AVR_REG_R2D = 99 + UC_AVR_REG_R3D = 100 + UC_AVR_REG_R4D = 101 + UC_AVR_REG_R5D = 102 + UC_AVR_REG_R6D = 103 + UC_AVR_REG_R7D = 104 + UC_AVR_REG_R8D = 105 + UC_AVR_REG_R9D = 106 + UC_AVR_REG_R10D = 107 + UC_AVR_REG_R11D = 108 + UC_AVR_REG_R12D = 109 + UC_AVR_REG_R13D = 110 + UC_AVR_REG_R14D = 111 + UC_AVR_REG_R15D = 112 + UC_AVR_REG_R16D = 113 + UC_AVR_REG_R17D = 114 + UC_AVR_REG_R18D = 115 + UC_AVR_REG_R19D = 116 + UC_AVR_REG_R20D = 117 + UC_AVR_REG_R21D = 118 + UC_AVR_REG_R22D = 119 + UC_AVR_REG_R23D = 120 + UC_AVR_REG_R24D = 121 + UC_AVR_REG_R25D = 122 + UC_AVR_REG_R26D = 123 + UC_AVR_REG_R27D = 124 + UC_AVR_REG_R28D = 125 + +# Alias registers + UC_AVR_REG_Xhi = 28 + UC_AVR_REG_Xlo = 27 + UC_AVR_REG_Yhi = 30 + UC_AVR_REG_Ylo = 29 + UC_AVR_REG_Zhi = 32 + UC_AVR_REG_Zlo = 31 + UC_AVR_REG_X = 91 + UC_AVR_REG_Y = 93 + UC_AVR_REG_Z = 95 +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 8c004ed0e8..f8c5132f7e 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_AVR = 11 + UC_ARCH_MAX = 12 UC_MODE_LITTLE_ENDIAN = 0 UC_MODE_BIG_ENDIAN = 1073741824 diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 821367d39b..43f556e856 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_AVR").is_ok() { + archs.push_str("avr;"); + } if !archs.is_empty() { archs.pop(); diff --git a/bindings/rust/src/avr.rs b/bindings/rust/src/avr.rs new file mode 100644 index 0000000000..1660933497 --- /dev/null +++ b/bindings/rust/src/avr.rs @@ -0,0 +1,211 @@ +#![allow(non_camel_case_types)] +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum RegisterAVR { + INVALID = 0, + + // General purpose registers (GPR) + R0 = 1, + R1 = 2, + R2 = 3, + R3 = 4, + R4 = 5, + R5 = 6, + R6 = 7, + R7 = 8, + R8 = 9, + R9 = 10, + R10 = 11, + R11 = 12, + R12 = 13, + R13 = 14, + R14 = 15, + R15 = 16, + R16 = 17, + R17 = 18, + R18 = 19, + R19 = 20, + R20 = 21, + R21 = 22, + R22 = 23, + R23 = 24, + R24 = 25, + R25 = 26, + R26 = 27, + R27 = 28, + R28 = 29, + R29 = 30, + R30 = 31, + R31 = 32, + + PC = 33, + SP = 34, + + RAMPD = 57, + RAMPX = 58, + RAMPY = 59, + RAMPZ = 60, + EIND = 61, + SPL = 62, + SPH = 63, + SREG = 64, + + // 16-bit coalesced registers + R0W = 65, + R1W = 66, + R2W = 67, + R3W = 68, + R4W = 69, + R5W = 70, + R6W = 71, + R7W = 72, + R8W = 73, + R9W = 74, + R10W = 75, + R11W = 76, + R12W = 77, + R13W = 78, + R14W = 79, + R15W = 80, + R16W = 81, + R17W = 82, + R18W = 83, + R19W = 84, + R20W = 85, + R21W = 86, + R22W = 87, + R23W = 88, + R24W = 89, + R25W = 90, + R26W = 91, + R27W = 92, + R28W = 93, + R29W = 94, + R30W = 95, + + // 32-bit coalesced registers + R0D = 97, + R1D = 98, + R2D = 99, + R3D = 100, + R4D = 101, + R5D = 102, + R6D = 103, + R7D = 104, + R8D = 105, + R9D = 106, + R10D = 107, + R11D = 108, + R12D = 109, + R13D = 110, + R14D = 111, + R15D = 112, + R16D = 113, + R17D = 114, + R18D = 115, + R19D = 116, + R20D = 117, + R21D = 118, + R22D = 119, + R23D = 120, + R24D = 121, + R25D = 122, + R26D = 123, + R27D = 124, + R28D = 125, +} + +impl RegisterAVR { + // alias registers + // (assoc) Xhi = 28 + // (assoc) Xlo = 27 + // (assoc) Yhi = 30 + // (assoc) Ylo = 29 + // (assoc) Zhi = 32 + // (assoc) Zlo = 31 + pub const XHI: RegisterAVR = RegisterAVR::R27; + pub const XLO: RegisterAVR = RegisterAVR::R26; + pub const YHI: RegisterAVR = RegisterAVR::R29; + pub const YLO: RegisterAVR = RegisterAVR::R28; + pub const ZHI: RegisterAVR = RegisterAVR::R31; + pub const ZLO: RegisterAVR = RegisterAVR::R30; + + // (assoc) X = 91 + // (assoc) Y = 93 + // (assoc) Z = 95 + pub const X: RegisterAVR = RegisterAVR::R26W; + pub const Y: RegisterAVR = RegisterAVR::R28W; + pub const Z: RegisterAVR = RegisterAVR::R30W; +} + +impl From for i32 { + fn from(r: RegisterAVR) -> Self { + r as i32 + } +} + +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum AvrArch { + UC_AVR_ARCH_AVR1 = 10, + UC_AVR_ARCH_AVR2 = 20, + UC_AVR_ARCH_AVR25 = 25, + UC_AVR_ARCH_AVR3 = 30, + UC_AVR_ARCH_AVR4 = 40, + UC_AVR_ARCH_AVR5 = 50, + UC_AVR_ARCH_AVR51 = 51, + UC_AVR_ARCH_AVR6 = 60, +} + +impl From for i32 { + fn from(value: AvrArch) -> Self { + value as i32 + } +} + +impl From<&AvrArch> for i32 { + fn from(value: &AvrArch) -> Self { + *value as i32 + } +} + +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum AvrCpuModel { + UC_CPU_AVR_ATMEGA16 = 50016, + UC_CPU_AVR_ATMEGA32 = 50032, + UC_CPU_AVR_ATMEGA64 = 50064, + UC_CPU_AVR_ATMEGA128 = 51128, + UC_CPU_AVR_ATMEGA128RFR2 = 51129, + UC_CPU_AVR_ATMEGA1280 = 51130, + UC_CPU_AVR_ATMEGA256 = 60256, + UC_CPU_AVR_ATMEGA256RFR2 = 60257, + UC_CPU_AVR_ATMEGA2560 = 60258, +} + +impl From for i32 { + fn from(value: AvrCpuModel) -> Self { + value as i32 + } +} + +impl From<&AvrCpuModel> for i32 { + fn from(value: &AvrCpuModel) -> Self { + *value as i32 + } +} + +#[repr(i32)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum AvrMem { + // Flash program memory (code) + FLASH = 0x08000000, +} + +impl From for i32 { + fn from(r: AvrMem) -> Self { + r as i32 + } +} diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 7cc95a3946..9c8b8aa1ec 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -59,6 +59,12 @@ mod arm64; #[cfg(feature = "arch_aarch64")] pub use crate::arm64::*; +// include avr support if conditionally compiled in +#[cfg(feature = "arch_avr")] +mod avr; +#[cfg(feature = "arch_avr")] +pub use crate::avr::*; + // include m68k support if conditionally compiled in #[cfg(feature = "arch_m68k")] mod m68k; @@ -1052,6 +1058,8 @@ impl<'a, D> Unicorn<'a, D> { Arch::S390X => Ok(RegisterS390X::PC as i32), #[cfg(feature = "arch_tricore")] Arch::TRICORE => Ok(RegisterTRICORE::PC as i32), + #[cfg(feature = "arch_avr")] + Arch::AVR => Ok(RegisterAVR::PC as i32), // returns `uc_error::ARCH` for `Arch::MAX`, and any // other architecture that are not compiled in _ => Err(uc_error::ARCH), diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index 6d122e14c2..ddea2c58c2 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -175,7 +175,8 @@ pub enum Arch { RISCV = 8, S390X = 9, TRICORE = 10, - MAX = 11, + AVR = 11, + MAX = 12, } impl TryFrom for Arch { diff --git a/bindings/zig/unicorn/AVR_const.zig b/bindings/zig/unicorn/AVR_const.zig new file mode 100644 index 0000000000..e408f18e01 --- /dev/null +++ b/bindings/zig/unicorn/AVR_const.zig @@ -0,0 +1,151 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +pub const AVRConst = enum(c_int) { + +// AVR architectures + AVR_ARCH_AVR1 = 10, + AVR_ARCH_AVR2 = 20, + AVR_ARCH_AVR25 = 25, + AVR_ARCH_AVR3 = 30, + AVR_ARCH_AVR4 = 40, + AVR_ARCH_AVR5 = 50, + AVR_ARCH_AVR51 = 51, + AVR_ARCH_AVR6 = 60, + CPU_AVR_ARCH = 1000, + +// AVR CPU + CPU_AVR_ATMEGA16 = 50016, + CPU_AVR_ATMEGA32 = 50032, + CPU_AVR_ATMEGA64 = 50064, + CPU_AVR_ATMEGA128 = 51128, + CPU_AVR_ATMEGA128RFR2 = 51129, + CPU_AVR_ATMEGA1280 = 51130, + CPU_AVR_ATMEGA256 = 60256, + CPU_AVR_ATMEGA256RFR2 = 60257, + CPU_AVR_ATMEGA2560 = 60258, + +// AVR memory + AVR_MEM_FLASH = 134217728, + +// AVR registers + + AVR_REG_INVALID = 0, + AVR_REG_R0 = 1, + AVR_REG_R1 = 2, + AVR_REG_R2 = 3, + AVR_REG_R3 = 4, + AVR_REG_R4 = 5, + AVR_REG_R5 = 6, + AVR_REG_R6 = 7, + AVR_REG_R7 = 8, + AVR_REG_R8 = 9, + AVR_REG_R9 = 10, + AVR_REG_R10 = 11, + AVR_REG_R11 = 12, + AVR_REG_R12 = 13, + AVR_REG_R13 = 14, + AVR_REG_R14 = 15, + AVR_REG_R15 = 16, + AVR_REG_R16 = 17, + AVR_REG_R17 = 18, + AVR_REG_R18 = 19, + AVR_REG_R19 = 20, + AVR_REG_R20 = 21, + AVR_REG_R21 = 22, + AVR_REG_R22 = 23, + AVR_REG_R23 = 24, + AVR_REG_R24 = 25, + AVR_REG_R25 = 26, + AVR_REG_R26 = 27, + AVR_REG_R27 = 28, + AVR_REG_R28 = 29, + AVR_REG_R29 = 30, + AVR_REG_R30 = 31, + AVR_REG_R31 = 32, + AVR_REG_PC = 33, + AVR_REG_SP = 34, + AVR_REG_RAMPD = 57, + AVR_REG_RAMPX = 58, + AVR_REG_RAMPY = 59, + AVR_REG_RAMPZ = 60, + AVR_REG_EIND = 61, + AVR_REG_SPL = 62, + AVR_REG_SPH = 63, + AVR_REG_SREG = 64, + +// 16-bit coalesced registers + AVR_REG_R0W = 65, + AVR_REG_R1W = 66, + AVR_REG_R2W = 67, + AVR_REG_R3W = 68, + AVR_REG_R4W = 69, + AVR_REG_R5W = 70, + AVR_REG_R6W = 71, + AVR_REG_R7W = 72, + AVR_REG_R8W = 73, + AVR_REG_R9W = 74, + AVR_REG_R10W = 75, + AVR_REG_R11W = 76, + AVR_REG_R12W = 77, + AVR_REG_R13W = 78, + AVR_REG_R14W = 79, + AVR_REG_R15W = 80, + AVR_REG_R16W = 81, + AVR_REG_R17W = 82, + AVR_REG_R18W = 83, + AVR_REG_R19W = 84, + AVR_REG_R20W = 85, + AVR_REG_R21W = 86, + AVR_REG_R22W = 87, + AVR_REG_R23W = 88, + AVR_REG_R24W = 89, + AVR_REG_R25W = 90, + AVR_REG_R26W = 91, + AVR_REG_R27W = 92, + AVR_REG_R28W = 93, + AVR_REG_R29W = 94, + AVR_REG_R30W = 95, + +// 32-bit coalesced registers + AVR_REG_R0D = 97, + AVR_REG_R1D = 98, + AVR_REG_R2D = 99, + AVR_REG_R3D = 100, + AVR_REG_R4D = 101, + AVR_REG_R5D = 102, + AVR_REG_R6D = 103, + AVR_REG_R7D = 104, + AVR_REG_R8D = 105, + AVR_REG_R9D = 106, + AVR_REG_R10D = 107, + AVR_REG_R11D = 108, + AVR_REG_R12D = 109, + AVR_REG_R13D = 110, + AVR_REG_R14D = 111, + AVR_REG_R15D = 112, + AVR_REG_R16D = 113, + AVR_REG_R17D = 114, + AVR_REG_R18D = 115, + AVR_REG_R19D = 116, + AVR_REG_R20D = 117, + AVR_REG_R21D = 118, + AVR_REG_R22D = 119, + AVR_REG_R23D = 120, + AVR_REG_R24D = 121, + AVR_REG_R25D = 122, + AVR_REG_R26D = 123, + AVR_REG_R27D = 124, + AVR_REG_R28D = 125, + +// Alias registers + AVR_REG_Xhi = 28, + AVR_REG_Xlo = 27, + AVR_REG_Yhi = 30, + AVR_REG_Ylo = 29, + AVR_REG_Zhi = 32, + AVR_REG_Zlo = 31, + AVR_REG_X = 91, + AVR_REG_Y = 93, + AVR_REG_Z = 95, + +}; diff --git a/bindings/zig/unicorn/unicorn_const.zig b/bindings/zig/unicorn/unicorn_const.zig index aaf1169f58..e0511746ea 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_AVR = 11, + ARCH_MAX = 12, MODE_LITTLE_ENDIAN = 0, MODE_BIG_ENDIAN = 1073741824, diff --git a/build.zig b/build.zig index e1eae62470..ca5f905bfb 100644 --- a/build.zig +++ b/build.zig @@ -74,6 +74,7 @@ pub fn build(b: *std.Build) void { .{ .file_type = .zig, .root_file_path = "bindings/zig/sample/sample_riscv_zig.zig" }, .{ .file_type = .c, .root_file_path = "samples/sample_arm.c" }, .{ .file_type = .c, .root_file_path = "samples/sample_arm64.c" }, + .{ .file_type = .c, .root_file_path = "samples/sample_avr.c" }, .{ .file_type = .c, .root_file_path = "samples/sample_ctl.c" }, .{ .file_type = .c, .root_file_path = "samples/sample_batch_reg.c" }, .{ .file_type = .c, .root_file_path = "samples/sample_m68k.c" }, diff --git a/include/uc_priv.h b/include/uc_priv.h index 07b5c244cf..c60c62522f 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -35,6 +35,7 @@ (UC_MODE_RISCV32 | UC_MODE_RISCV64 | UC_MODE_LITTLE_ENDIAN) #define UC_MODE_S390X_MASK (UC_MODE_BIG_ENDIAN) #define UC_MODE_TRICORE_MASK (UC_MODE_LITTLE_ENDIAN) +#define UC_MODE_AVR_MASK (UC_MODE_LITTLE_ENDIAN) #define ARR_SIZE(a) (sizeof(a) / sizeof(a[0])) diff --git a/include/unicorn/avr.h b/include/unicorn/avr.h new file mode 100644 index 0000000000..0487d3fd09 --- /dev/null +++ b/include/unicorn/avr.h @@ -0,0 +1,189 @@ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +/* + Created for Unicorn Engine by Glenn Baker , 2024 +*/ + +#ifndef UNICORN_AVR_H +#define UNICORN_AVR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#pragma warning(disable : 4201) +#endif + +//> AVR architectures +typedef enum uc_avr_arch { + UC_AVR_ARCH_AVR1 = 10, + UC_AVR_ARCH_AVR2 = 20, + UC_AVR_ARCH_AVR25 = 25, + UC_AVR_ARCH_AVR3 = 30, + UC_AVR_ARCH_AVR4 = 40, + UC_AVR_ARCH_AVR5 = 50, + UC_AVR_ARCH_AVR51 = 51, + UC_AVR_ARCH_AVR6 = 60, +} uc_avr_arch; + +#define UC_CPU_AVR_ARCH 1000 + +//> AVR CPU +typedef enum uc_cpu_avr { + // Enhanced Core with 16K up to 64K of program memory ("AVR5") + UC_CPU_AVR_ATMEGA16 = UC_AVR_ARCH_AVR5*UC_CPU_AVR_ARCH + 16, + UC_CPU_AVR_ATMEGA32 = UC_AVR_ARCH_AVR5*UC_CPU_AVR_ARCH + 32, + UC_CPU_AVR_ATMEGA64 = UC_AVR_ARCH_AVR5*UC_CPU_AVR_ARCH + 64, + + // Enhanced Core with 128K of program memory ("AVR5.1") + UC_CPU_AVR_ATMEGA128 = UC_AVR_ARCH_AVR51*UC_CPU_AVR_ARCH + 128, + UC_CPU_AVR_ATMEGA128RFR2, + UC_CPU_AVR_ATMEGA1280, + + // Enhanced Core with 128K+ of program memory, i.e. 3-byte PC ("AVR6") + UC_CPU_AVR_ATMEGA256 = UC_AVR_ARCH_AVR6*UC_CPU_AVR_ARCH + 256, + UC_CPU_AVR_ATMEGA256RFR2, + UC_CPU_AVR_ATMEGA2560, +} uc_cpu_avr; + +//> AVR memory +typedef enum uc_avr_mem { + // Flash program memory (code) + UC_AVR_MEM_FLASH = 0x08000000, +} uc_avr_mem; + +//> AVR registers +typedef enum uc_avr_reg { + UC_AVR_REG_INVALID = 0, + + // General purpose registers (GPR) + UC_AVR_REG_R0 = 1, + UC_AVR_REG_R1, + UC_AVR_REG_R2, + UC_AVR_REG_R3, + UC_AVR_REG_R4, + UC_AVR_REG_R5, + UC_AVR_REG_R6, + UC_AVR_REG_R7, + UC_AVR_REG_R8, + UC_AVR_REG_R9, + UC_AVR_REG_R10, + UC_AVR_REG_R11, + UC_AVR_REG_R12, + UC_AVR_REG_R13, + UC_AVR_REG_R14, + UC_AVR_REG_R15, + UC_AVR_REG_R16, + UC_AVR_REG_R17, + UC_AVR_REG_R18, + UC_AVR_REG_R19, + UC_AVR_REG_R20, + UC_AVR_REG_R21, + UC_AVR_REG_R22, + UC_AVR_REG_R23, + UC_AVR_REG_R24, + UC_AVR_REG_R25, + UC_AVR_REG_R26, + UC_AVR_REG_R27, + UC_AVR_REG_R28, + UC_AVR_REG_R29, + UC_AVR_REG_R30, + UC_AVR_REG_R31, + + UC_AVR_REG_PC, + UC_AVR_REG_SP, + + UC_AVR_REG_RAMPD = UC_AVR_REG_PC + 16 + 8, + UC_AVR_REG_RAMPX, + UC_AVR_REG_RAMPY, + UC_AVR_REG_RAMPZ, + UC_AVR_REG_EIND, + UC_AVR_REG_SPL, + UC_AVR_REG_SPH, + UC_AVR_REG_SREG, + + //> 16-bit coalesced registers + UC_AVR_REG_R0W = UC_AVR_REG_PC + 32, + UC_AVR_REG_R1W, + UC_AVR_REG_R2W, + UC_AVR_REG_R3W, + UC_AVR_REG_R4W, + UC_AVR_REG_R5W, + UC_AVR_REG_R6W, + UC_AVR_REG_R7W, + UC_AVR_REG_R8W, + UC_AVR_REG_R9W, + UC_AVR_REG_R10W, + UC_AVR_REG_R11W, + UC_AVR_REG_R12W, + UC_AVR_REG_R13W, + UC_AVR_REG_R14W, + UC_AVR_REG_R15W, + UC_AVR_REG_R16W, + UC_AVR_REG_R17W, + UC_AVR_REG_R18W, + UC_AVR_REG_R19W, + UC_AVR_REG_R20W, + UC_AVR_REG_R21W, + UC_AVR_REG_R22W, + UC_AVR_REG_R23W, + UC_AVR_REG_R24W, + UC_AVR_REG_R25W, + UC_AVR_REG_R26W, + UC_AVR_REG_R27W, + UC_AVR_REG_R28W, + UC_AVR_REG_R29W, + UC_AVR_REG_R30W, + + //> 32-bit coalesced registers + UC_AVR_REG_R0D = UC_AVR_REG_PC + 64, + UC_AVR_REG_R1D, + UC_AVR_REG_R2D, + UC_AVR_REG_R3D, + UC_AVR_REG_R4D, + UC_AVR_REG_R5D, + UC_AVR_REG_R6D, + UC_AVR_REG_R7D, + UC_AVR_REG_R8D, + UC_AVR_REG_R9D, + UC_AVR_REG_R10D, + UC_AVR_REG_R11D, + UC_AVR_REG_R12D, + UC_AVR_REG_R13D, + UC_AVR_REG_R14D, + UC_AVR_REG_R15D, + UC_AVR_REG_R16D, + UC_AVR_REG_R17D, + UC_AVR_REG_R18D, + UC_AVR_REG_R19D, + UC_AVR_REG_R20D, + UC_AVR_REG_R21D, + UC_AVR_REG_R22D, + UC_AVR_REG_R23D, + UC_AVR_REG_R24D, + UC_AVR_REG_R25D, + UC_AVR_REG_R26D, + UC_AVR_REG_R27D, + UC_AVR_REG_R28D, + + //> Alias registers + UC_AVR_REG_Xhi = UC_AVR_REG_R27, + UC_AVR_REG_Xlo = UC_AVR_REG_R26, + UC_AVR_REG_Yhi = UC_AVR_REG_R29, + UC_AVR_REG_Ylo = UC_AVR_REG_R28, + UC_AVR_REG_Zhi = UC_AVR_REG_R31, + UC_AVR_REG_Zlo = UC_AVR_REG_R30, + + UC_AVR_REG_X = UC_AVR_REG_R26W, + UC_AVR_REG_Y = UC_AVR_REG_R28W, + UC_AVR_REG_Z = UC_AVR_REG_R30W, +} uc_avr_reg; + +#ifdef __cplusplus +} +#endif + +#endif /* UNICORN_AVR_H */ diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 1ee78f3aa1..a26e23d7d2 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -36,6 +36,7 @@ typedef size_t uc_hook; #include "riscv.h" #include "s390x.h" #include "tricore.h" +#include "avr.h" #ifdef __GNUC__ #define DEFAULT_VISIBILITY __attribute__((visibility("default"))) @@ -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_AVR, // AVR architecture UC_ARCH_MAX, } uc_arch; diff --git a/msvc/avr-softmmu/config-target.h b/msvc/avr-softmmu/config-target.h new file mode 100644 index 0000000000..3afeec6c7a --- /dev/null +++ b/msvc/avr-softmmu/config-target.h @@ -0,0 +1,5 @@ +/* Automatically generated by create_config - do not modify */ +#define TARGET_AVR 1 +#define TARGET_NAME "avr" +#define TARGET_AVR 1 +#define CONFIG_SOFTMMU 1 diff --git a/qemu/MAINTAINERS b/qemu/MAINTAINERS index 8cbc1fac2b..ed80410291 100644 --- a/qemu/MAINTAINERS +++ b/qemu/MAINTAINERS @@ -952,6 +952,15 @@ F: include/hw/*/nrf51*.h F: include/hw/*/microbit*.h F: tests/qtest/microbit-test.c +AVR Machines +------------- + +AVR MCUs +M: Michael Rolnik +R: Sarah Harris +S: Maintained +F: default-configs/avr-softmmu.mak + CRIS Machines ------------- Axis Dev88 diff --git a/qemu/avr.h b/qemu/avr.h new file mode 100644 index 0000000000..bb37176913 --- /dev/null +++ b/qemu/avr.h @@ -0,0 +1,1297 @@ +/* Autogen header for Unicorn Engine - DONOT MODIFY */ +#ifndef UNICORN_AUTOGEN_avr_H +#define UNICORN_AUTOGEN_avr_H +#ifndef UNICORN_ARCH_POSTFIX +#define UNICORN_ARCH_POSTFIX _avr +#endif +#define uc_add_inline_hook uc_add_inline_hook_avr +#define uc_del_inline_hook uc_del_inline_hook_avr +#define tb_invalidate_phys_range tb_invalidate_phys_range_avr +#define use_idiv_instructions use_idiv_instructions_avr +#define arm_arch arm_arch_avr +#define tb_target_set_jmp_target tb_target_set_jmp_target_avr +#define have_bmi1 have_bmi1_avr +#define have_popcnt have_popcnt_avr +#define have_avx1 have_avx1_avr +#define have_avx2 have_avx2_avr +#define have_isa have_isa_avr +#define have_altivec have_altivec_avr +#define have_vsx have_vsx_avr +#define flush_icache_range flush_icache_range_avr +#define s390_facilities s390_facilities_avr +#define tcg_dump_op tcg_dump_op_avr +#define tcg_dump_ops tcg_dump_ops_avr +#define tcg_gen_and_i64 tcg_gen_and_i64_avr +#define tcg_gen_discard_i64 tcg_gen_discard_i64_avr +#define tcg_gen_ld16s_i64 tcg_gen_ld16s_i64_avr +#define tcg_gen_ld16u_i64 tcg_gen_ld16u_i64_avr +#define tcg_gen_ld32s_i64 tcg_gen_ld32s_i64_avr +#define tcg_gen_ld32u_i64 tcg_gen_ld32u_i64_avr +#define tcg_gen_ld8s_i64 tcg_gen_ld8s_i64_avr +#define tcg_gen_ld8u_i64 tcg_gen_ld8u_i64_avr +#define tcg_gen_ld_i64 tcg_gen_ld_i64_avr +#define tcg_gen_mov_i64 tcg_gen_mov_i64_avr +#define tcg_gen_movi_i64 tcg_gen_movi_i64_avr +#define tcg_gen_mul_i64 tcg_gen_mul_i64_avr +#define tcg_gen_or_i64 tcg_gen_or_i64_avr +#define tcg_gen_sar_i64 tcg_gen_sar_i64_avr +#define tcg_gen_shl_i64 tcg_gen_shl_i64_avr +#define tcg_gen_shr_i64 tcg_gen_shr_i64_avr +#define tcg_gen_st_i64 tcg_gen_st_i64_avr +#define tcg_gen_xor_i64 tcg_gen_xor_i64_avr +#define cpu_icount_to_ns cpu_icount_to_ns_avr +#define cpu_is_stopped cpu_is_stopped_avr +#define cpu_get_ticks cpu_get_ticks_avr +#define cpu_get_clock cpu_get_clock_avr +#define cpu_resume cpu_resume_avr +#define qemu_init_vcpu qemu_init_vcpu_avr +#define cpu_stop_current cpu_stop_current_avr +#define resume_all_vcpus resume_all_vcpus_avr +#define vm_start vm_start_avr +#define address_space_dispatch_compact address_space_dispatch_compact_avr +#define flatview_translate flatview_translate_avr +#define flatview_copy flatview_copy_avr +#define address_space_translate_for_iotlb address_space_translate_for_iotlb_avr +#define qemu_get_cpu qemu_get_cpu_avr +#define cpu_address_space_init cpu_address_space_init_avr +#define cpu_get_address_space cpu_get_address_space_avr +#define cpu_exec_unrealizefn cpu_exec_unrealizefn_avr +#define cpu_exec_initfn cpu_exec_initfn_avr +#define cpu_exec_realizefn cpu_exec_realizefn_avr +#define tb_invalidate_phys_addr tb_invalidate_phys_addr_avr +#define cpu_watchpoint_insert cpu_watchpoint_insert_avr +#define cpu_watchpoint_remove_by_ref cpu_watchpoint_remove_by_ref_avr +#define cpu_watchpoint_remove_all cpu_watchpoint_remove_all_avr +#define cpu_watchpoint_address_matches cpu_watchpoint_address_matches_avr +#define cpu_breakpoint_insert cpu_breakpoint_insert_avr +#define cpu_breakpoint_remove cpu_breakpoint_remove_avr +#define cpu_breakpoint_remove_by_ref cpu_breakpoint_remove_by_ref_avr +#define cpu_breakpoint_remove_all cpu_breakpoint_remove_all_avr +#define cpu_abort cpu_abort_avr +#define cpu_physical_memory_test_and_clear_dirty cpu_physical_memory_test_and_clear_dirty_avr +#define memory_region_section_get_iotlb memory_region_section_get_iotlb_avr +#define flatview_add_to_dispatch flatview_add_to_dispatch_avr +#define qemu_ram_get_host_addr qemu_ram_get_host_addr_avr +#define qemu_ram_get_offset qemu_ram_get_offset_avr +#define qemu_ram_get_used_length qemu_ram_get_used_length_avr +#define qemu_ram_is_shared qemu_ram_is_shared_avr +#define qemu_ram_pagesize qemu_ram_pagesize_avr +#define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_avr +#define qemu_ram_alloc qemu_ram_alloc_avr +#define qemu_ram_free qemu_ram_free_avr +#define qemu_map_ram_ptr qemu_map_ram_ptr_avr +#define qemu_ram_block_host_offset qemu_ram_block_host_offset_avr +#define qemu_ram_block_from_host qemu_ram_block_from_host_avr +#define qemu_ram_addr_from_host qemu_ram_addr_from_host_avr +#define cpu_check_watchpoint cpu_check_watchpoint_avr +#define iotlb_to_section iotlb_to_section_avr +#define address_space_dispatch_new address_space_dispatch_new_avr +#define address_space_dispatch_free address_space_dispatch_free_avr +#define address_space_dispatch_clear address_space_dispatch_clear_avr +#define flatview_read_continue flatview_read_continue_avr +#define address_space_read_full address_space_read_full_avr +#define address_space_write address_space_write_avr +#define address_space_rw address_space_rw_avr +#define cpu_physical_memory_rw cpu_physical_memory_rw_avr +#define address_space_write_rom address_space_write_rom_avr +#define cpu_flush_icache_range cpu_flush_icache_range_avr +#define cpu_exec_init_all cpu_exec_init_all_avr +#define address_space_access_valid address_space_access_valid_avr +#define address_space_map address_space_map_avr +#define address_space_unmap address_space_unmap_avr +#define cpu_physical_memory_map cpu_physical_memory_map_avr +#define cpu_physical_memory_unmap cpu_physical_memory_unmap_avr +#define cpu_memory_rw_debug cpu_memory_rw_debug_avr +#define qemu_target_page_size qemu_target_page_size_avr +#define qemu_target_page_bits qemu_target_page_bits_avr +#define qemu_target_page_bits_min qemu_target_page_bits_min_avr +#define target_words_bigendian target_words_bigendian_avr +#define cpu_physical_memory_is_io cpu_physical_memory_is_io_avr +#define ram_block_discard_range ram_block_discard_range_avr +#define ramblock_is_pmem ramblock_is_pmem_avr +#define page_size_init page_size_init_avr +#define set_preferred_target_page_bits set_preferred_target_page_bits_avr +#define finalize_target_page_bits finalize_target_page_bits_avr +#define cpu_outb cpu_outb_avr +#define cpu_outw cpu_outw_avr +#define cpu_outl cpu_outl_avr +#define cpu_inb cpu_inb_avr +#define cpu_inw cpu_inw_avr +#define cpu_inl cpu_inl_avr +#define memory_map memory_map_avr +#define memory_map_io memory_map_io_avr +#define memory_map_ptr memory_map_ptr_avr +#define memory_unmap memory_unmap_avr +#define memory_free memory_free_avr +#define flatview_unref flatview_unref_avr +#define address_space_get_flatview address_space_get_flatview_avr +#define memory_region_transaction_begin memory_region_transaction_begin_avr +#define memory_region_transaction_commit memory_region_transaction_commit_avr +#define memory_region_init memory_region_init_avr +#define memory_region_access_valid memory_region_access_valid_avr +#define memory_region_dispatch_read memory_region_dispatch_read_avr +#define memory_region_dispatch_write memory_region_dispatch_write_avr +#define memory_region_init_io memory_region_init_io_avr +#define memory_region_init_ram_ptr memory_region_init_ram_ptr_avr +#define memory_region_size memory_region_size_avr +#define memory_region_set_readonly memory_region_set_readonly_avr +#define memory_region_get_ram_ptr memory_region_get_ram_ptr_avr +#define memory_region_from_host memory_region_from_host_avr +#define memory_region_get_ram_addr memory_region_get_ram_addr_avr +#define memory_region_add_subregion memory_region_add_subregion_avr +#define memory_region_del_subregion memory_region_del_subregion_avr +#define memory_region_find memory_region_find_avr +#define memory_listener_register memory_listener_register_avr +#define memory_listener_unregister memory_listener_unregister_avr +#define address_space_remove_listeners address_space_remove_listeners_avr +#define address_space_init address_space_init_avr +#define address_space_destroy address_space_destroy_avr +#define memory_region_init_ram memory_region_init_ram_avr +#define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_avr +#define exec_inline_op exec_inline_op_avr +#define floatx80_default_nan floatx80_default_nan_avr +#define float_raise float_raise_avr +#define float16_is_quiet_nan float16_is_quiet_nan_avr +#define float16_is_signaling_nan float16_is_signaling_nan_avr +#define float32_is_quiet_nan float32_is_quiet_nan_avr +#define float32_is_signaling_nan float32_is_signaling_nan_avr +#define float64_is_quiet_nan float64_is_quiet_nan_avr +#define float64_is_signaling_nan float64_is_signaling_nan_avr +#define floatx80_is_quiet_nan floatx80_is_quiet_nan_avr +#define floatx80_is_signaling_nan floatx80_is_signaling_nan_avr +#define floatx80_silence_nan floatx80_silence_nan_avr +#define propagateFloatx80NaN propagateFloatx80NaN_avr +#define float128_is_quiet_nan float128_is_quiet_nan_avr +#define float128_is_signaling_nan float128_is_signaling_nan_avr +#define float128_silence_nan float128_silence_nan_avr +#define float16_add float16_add_avr +#define float16_sub float16_sub_avr +#define float32_add float32_add_avr +#define float32_sub float32_sub_avr +#define float64_add float64_add_avr +#define float64_sub float64_sub_avr +#define float16_mul float16_mul_avr +#define float32_mul float32_mul_avr +#define float64_mul float64_mul_avr +#define float16_muladd float16_muladd_avr +#define float32_muladd float32_muladd_avr +#define float64_muladd float64_muladd_avr +#define float16_div float16_div_avr +#define float32_div float32_div_avr +#define float64_div float64_div_avr +#define float16_to_float32 float16_to_float32_avr +#define float16_to_float64 float16_to_float64_avr +#define float32_to_float16 float32_to_float16_avr +#define float32_to_float64 float32_to_float64_avr +#define float64_to_float16 float64_to_float16_avr +#define float64_to_float32 float64_to_float32_avr +#define float16_round_to_int float16_round_to_int_avr +#define float32_round_to_int float32_round_to_int_avr +#define float64_round_to_int float64_round_to_int_avr +#define float16_to_int16_scalbn float16_to_int16_scalbn_avr +#define float16_to_int32_scalbn float16_to_int32_scalbn_avr +#define float16_to_int64_scalbn float16_to_int64_scalbn_avr +#define float32_to_int16_scalbn float32_to_int16_scalbn_avr +#define float32_to_int32_scalbn float32_to_int32_scalbn_avr +#define float32_to_int64_scalbn float32_to_int64_scalbn_avr +#define float64_to_int16_scalbn float64_to_int16_scalbn_avr +#define float64_to_int32_scalbn float64_to_int32_scalbn_avr +#define float64_to_int64_scalbn float64_to_int64_scalbn_avr +#define float16_to_int16 float16_to_int16_avr +#define float16_to_int32 float16_to_int32_avr +#define float16_to_int64 float16_to_int64_avr +#define float32_to_int16 float32_to_int16_avr +#define float32_to_int32 float32_to_int32_avr +#define float32_to_int64 float32_to_int64_avr +#define float64_to_int16 float64_to_int16_avr +#define float64_to_int32 float64_to_int32_avr +#define float64_to_int64 float64_to_int64_avr +#define float16_to_int16_round_to_zero float16_to_int16_round_to_zero_avr +#define float16_to_int32_round_to_zero float16_to_int32_round_to_zero_avr +#define float16_to_int64_round_to_zero float16_to_int64_round_to_zero_avr +#define float32_to_int16_round_to_zero float32_to_int16_round_to_zero_avr +#define float32_to_int32_round_to_zero float32_to_int32_round_to_zero_avr +#define float32_to_int64_round_to_zero float32_to_int64_round_to_zero_avr +#define float64_to_int16_round_to_zero float64_to_int16_round_to_zero_avr +#define float64_to_int32_round_to_zero float64_to_int32_round_to_zero_avr +#define float64_to_int64_round_to_zero float64_to_int64_round_to_zero_avr +#define float16_to_uint16_scalbn float16_to_uint16_scalbn_avr +#define float16_to_uint32_scalbn float16_to_uint32_scalbn_avr +#define float16_to_uint64_scalbn float16_to_uint64_scalbn_avr +#define float32_to_uint16_scalbn float32_to_uint16_scalbn_avr +#define float32_to_uint32_scalbn float32_to_uint32_scalbn_avr +#define float32_to_uint64_scalbn float32_to_uint64_scalbn_avr +#define float64_to_uint16_scalbn float64_to_uint16_scalbn_avr +#define float64_to_uint32_scalbn float64_to_uint32_scalbn_avr +#define float64_to_uint64_scalbn float64_to_uint64_scalbn_avr +#define float16_to_uint16 float16_to_uint16_avr +#define float16_to_uint32 float16_to_uint32_avr +#define float16_to_uint64 float16_to_uint64_avr +#define float32_to_uint16 float32_to_uint16_avr +#define float32_to_uint32 float32_to_uint32_avr +#define float32_to_uint64 float32_to_uint64_avr +#define float64_to_uint16 float64_to_uint16_avr +#define float64_to_uint32 float64_to_uint32_avr +#define float64_to_uint64 float64_to_uint64_avr +#define float16_to_uint16_round_to_zero float16_to_uint16_round_to_zero_avr +#define float16_to_uint32_round_to_zero float16_to_uint32_round_to_zero_avr +#define float16_to_uint64_round_to_zero float16_to_uint64_round_to_zero_avr +#define float32_to_uint16_round_to_zero float32_to_uint16_round_to_zero_avr +#define float32_to_uint32_round_to_zero float32_to_uint32_round_to_zero_avr +#define float32_to_uint64_round_to_zero float32_to_uint64_round_to_zero_avr +#define float64_to_uint16_round_to_zero float64_to_uint16_round_to_zero_avr +#define float64_to_uint32_round_to_zero float64_to_uint32_round_to_zero_avr +#define float64_to_uint64_round_to_zero float64_to_uint64_round_to_zero_avr +#define int64_to_float16_scalbn int64_to_float16_scalbn_avr +#define int32_to_float16_scalbn int32_to_float16_scalbn_avr +#define int16_to_float16_scalbn int16_to_float16_scalbn_avr +#define int64_to_float16 int64_to_float16_avr +#define int32_to_float16 int32_to_float16_avr +#define int16_to_float16 int16_to_float16_avr +#define int64_to_float32_scalbn int64_to_float32_scalbn_avr +#define int32_to_float32_scalbn int32_to_float32_scalbn_avr +#define int16_to_float32_scalbn int16_to_float32_scalbn_avr +#define int64_to_float32 int64_to_float32_avr +#define int32_to_float32 int32_to_float32_avr +#define int16_to_float32 int16_to_float32_avr +#define int64_to_float64_scalbn int64_to_float64_scalbn_avr +#define int32_to_float64_scalbn int32_to_float64_scalbn_avr +#define int16_to_float64_scalbn int16_to_float64_scalbn_avr +#define int64_to_float64 int64_to_float64_avr +#define int32_to_float64 int32_to_float64_avr +#define int16_to_float64 int16_to_float64_avr +#define uint64_to_float16_scalbn uint64_to_float16_scalbn_avr +#define uint32_to_float16_scalbn uint32_to_float16_scalbn_avr +#define uint16_to_float16_scalbn uint16_to_float16_scalbn_avr +#define uint64_to_float16 uint64_to_float16_avr +#define uint32_to_float16 uint32_to_float16_avr +#define uint16_to_float16 uint16_to_float16_avr +#define uint64_to_float32_scalbn uint64_to_float32_scalbn_avr +#define uint32_to_float32_scalbn uint32_to_float32_scalbn_avr +#define uint16_to_float32_scalbn uint16_to_float32_scalbn_avr +#define uint64_to_float32 uint64_to_float32_avr +#define uint32_to_float32 uint32_to_float32_avr +#define uint16_to_float32 uint16_to_float32_avr +#define uint64_to_float64_scalbn uint64_to_float64_scalbn_avr +#define uint32_to_float64_scalbn uint32_to_float64_scalbn_avr +#define uint16_to_float64_scalbn uint16_to_float64_scalbn_avr +#define uint64_to_float64 uint64_to_float64_avr +#define uint32_to_float64 uint32_to_float64_avr +#define uint16_to_float64 uint16_to_float64_avr +#define float16_min float16_min_avr +#define float16_minnum float16_minnum_avr +#define float16_minnummag float16_minnummag_avr +#define float16_max float16_max_avr +#define float16_maxnum float16_maxnum_avr +#define float16_maxnummag float16_maxnummag_avr +#define float32_min float32_min_avr +#define float32_minnum float32_minnum_avr +#define float32_minnummag float32_minnummag_avr +#define float32_max float32_max_avr +#define float32_maxnum float32_maxnum_avr +#define float32_maxnummag float32_maxnummag_avr +#define float64_min float64_min_avr +#define float64_minnum float64_minnum_avr +#define float64_minnummag float64_minnummag_avr +#define float64_max float64_max_avr +#define float64_maxnum float64_maxnum_avr +#define float64_maxnummag float64_maxnummag_avr +#define float16_compare float16_compare_avr +#define float16_compare_quiet float16_compare_quiet_avr +#define float32_compare float32_compare_avr +#define float32_compare_quiet float32_compare_quiet_avr +#define float64_compare float64_compare_avr +#define float64_compare_quiet float64_compare_quiet_avr +#define float16_scalbn float16_scalbn_avr +#define float32_scalbn float32_scalbn_avr +#define float64_scalbn float64_scalbn_avr +#define float16_sqrt float16_sqrt_avr +#define float32_sqrt float32_sqrt_avr +#define float64_sqrt float64_sqrt_avr +#define float16_default_nan float16_default_nan_avr +#define float32_default_nan float32_default_nan_avr +#define float64_default_nan float64_default_nan_avr +#define float128_default_nan float128_default_nan_avr +#define float16_silence_nan float16_silence_nan_avr +#define float32_silence_nan float32_silence_nan_avr +#define float64_silence_nan float64_silence_nan_avr +#define float16_squash_input_denormal float16_squash_input_denormal_avr +#define float32_squash_input_denormal float32_squash_input_denormal_avr +#define float64_squash_input_denormal float64_squash_input_denormal_avr +#define normalizeFloatx80Subnormal normalizeFloatx80Subnormal_avr +#define roundAndPackFloatx80 roundAndPackFloatx80_avr +#define normalizeRoundAndPackFloatx80 normalizeRoundAndPackFloatx80_avr +#define int32_to_floatx80 int32_to_floatx80_avr +#define int32_to_float128 int32_to_float128_avr +#define int64_to_floatx80 int64_to_floatx80_avr +#define int64_to_float128 int64_to_float128_avr +#define uint64_to_float128 uint64_to_float128_avr +#define float32_to_floatx80 float32_to_floatx80_avr +#define float32_to_float128 float32_to_float128_avr +#define float32_rem float32_rem_avr +#define float32_exp2 float32_exp2_avr +#define float32_log2 float32_log2_avr +#define float32_eq float32_eq_avr +#define float32_le float32_le_avr +#define float32_lt float32_lt_avr +#define float32_unordered float32_unordered_avr +#define float32_eq_quiet float32_eq_quiet_avr +#define float32_le_quiet float32_le_quiet_avr +#define float32_lt_quiet float32_lt_quiet_avr +#define float32_unordered_quiet float32_unordered_quiet_avr +#define float64_to_floatx80 float64_to_floatx80_avr +#define float64_to_float128 float64_to_float128_avr +#define float64_rem float64_rem_avr +#define float64_log2 float64_log2_avr +#define float64_eq float64_eq_avr +#define float64_le float64_le_avr +#define float64_lt float64_lt_avr +#define float64_unordered float64_unordered_avr +#define float64_eq_quiet float64_eq_quiet_avr +#define float64_le_quiet float64_le_quiet_avr +#define float64_lt_quiet float64_lt_quiet_avr +#define float64_unordered_quiet float64_unordered_quiet_avr +#define floatx80_to_int32 floatx80_to_int32_avr +#define floatx80_to_int32_round_to_zero floatx80_to_int32_round_to_zero_avr +#define floatx80_to_int64 floatx80_to_int64_avr +#define floatx80_to_int64_round_to_zero floatx80_to_int64_round_to_zero_avr +#define floatx80_to_float32 floatx80_to_float32_avr +#define floatx80_to_float64 floatx80_to_float64_avr +#define floatx80_to_float128 floatx80_to_float128_avr +#define floatx80_round floatx80_round_avr +#define floatx80_round_to_int floatx80_round_to_int_avr +#define floatx80_add floatx80_add_avr +#define floatx80_sub floatx80_sub_avr +#define floatx80_mul floatx80_mul_avr +#define floatx80_div floatx80_div_avr +#define floatx80_rem floatx80_rem_avr +#define floatx80_sqrt floatx80_sqrt_avr +#define floatx80_eq floatx80_eq_avr +#define floatx80_le floatx80_le_avr +#define floatx80_lt floatx80_lt_avr +#define floatx80_unordered floatx80_unordered_avr +#define floatx80_eq_quiet floatx80_eq_quiet_avr +#define floatx80_le_quiet floatx80_le_quiet_avr +#define floatx80_lt_quiet floatx80_lt_quiet_avr +#define floatx80_unordered_quiet floatx80_unordered_quiet_avr +#define float128_to_int32 float128_to_int32_avr +#define float128_to_int32_round_to_zero float128_to_int32_round_to_zero_avr +#define float128_to_int64 float128_to_int64_avr +#define float128_to_int64_round_to_zero float128_to_int64_round_to_zero_avr +#define float128_to_uint64 float128_to_uint64_avr +#define float128_to_uint64_round_to_zero float128_to_uint64_round_to_zero_avr +#define float128_to_uint32_round_to_zero float128_to_uint32_round_to_zero_avr +#define float128_to_uint32 float128_to_uint32_avr +#define float128_to_float32 float128_to_float32_avr +#define float128_to_float64 float128_to_float64_avr +#define float128_to_floatx80 float128_to_floatx80_avr +#define float128_round_to_int float128_round_to_int_avr +#define float128_add float128_add_avr +#define float128_sub float128_sub_avr +#define float128_mul float128_mul_avr +#define float128_div float128_div_avr +#define float128_rem float128_rem_avr +#define float128_sqrt float128_sqrt_avr +#define float128_eq float128_eq_avr +#define float128_le float128_le_avr +#define float128_lt float128_lt_avr +#define float128_unordered float128_unordered_avr +#define float128_eq_quiet float128_eq_quiet_avr +#define float128_le_quiet float128_le_quiet_avr +#define float128_lt_quiet float128_lt_quiet_avr +#define float128_unordered_quiet float128_unordered_quiet_avr +#define floatx80_compare floatx80_compare_avr +#define floatx80_compare_quiet floatx80_compare_quiet_avr +#define float128_compare float128_compare_avr +#define float128_compare_quiet float128_compare_quiet_avr +#define floatx80_scalbn floatx80_scalbn_avr +#define float128_scalbn float128_scalbn_avr +#define softfloat_init softfloat_init_avr +#define tcg_optimize tcg_optimize_avr +#define gen_new_label gen_new_label_avr +#define tcg_can_emit_vec_op tcg_can_emit_vec_op_avr +#define tcg_expand_vec_op tcg_expand_vec_op_avr +#define tcg_register_jit tcg_register_jit_avr +#define tcg_tb_insert tcg_tb_insert_avr +#define tcg_tb_remove tcg_tb_remove_avr +#define tcg_tb_lookup tcg_tb_lookup_avr +#define tcg_tb_foreach tcg_tb_foreach_avr +#define tcg_nb_tbs tcg_nb_tbs_avr +#define tcg_region_reset_all tcg_region_reset_all_avr +#define tcg_region_init tcg_region_init_avr +#define tcg_code_size tcg_code_size_avr +#define tcg_code_capacity tcg_code_capacity_avr +#define tcg_tb_phys_invalidate_count tcg_tb_phys_invalidate_count_avr +#define tcg_malloc_internal tcg_malloc_internal_avr +#define tcg_pool_reset tcg_pool_reset_avr +#define tcg_context_init tcg_context_init_avr +#define tcg_tb_alloc tcg_tb_alloc_avr +#define tcg_prologue_init tcg_prologue_init_avr +#define tcg_func_start tcg_func_start_avr +#define tcg_set_frame tcg_set_frame_avr +#define tcg_global_mem_new_internal tcg_global_mem_new_internal_avr +#define tcg_temp_new_internal tcg_temp_new_internal_avr +#define tcg_temp_new_vec tcg_temp_new_vec_avr +#define tcg_temp_new_vec_matching tcg_temp_new_vec_matching_avr +#define tcg_temp_free_internal tcg_temp_free_internal_avr +#define tcg_const_i32 tcg_const_i32_avr +#define tcg_const_i64 tcg_const_i64_avr +#define tcg_const_local_i32 tcg_const_local_i32_avr +#define tcg_const_local_i64 tcg_const_local_i64_avr +#define tcg_op_supported tcg_op_supported_avr +#define tcg_gen_callN tcg_gen_callN_avr +#define tcg_op_remove tcg_op_remove_avr +#define tcg_emit_op tcg_emit_op_avr +#define tcg_op_insert_before tcg_op_insert_before_avr +#define tcg_op_insert_after tcg_op_insert_after_avr +#define tcg_cpu_exec_time tcg_cpu_exec_time_avr +#define tcg_gen_code tcg_gen_code_avr +#define tcg_gen_op1 tcg_gen_op1_avr +#define tcg_gen_op2 tcg_gen_op2_avr +#define tcg_gen_op3 tcg_gen_op3_avr +#define tcg_gen_op4 tcg_gen_op4_avr +#define tcg_gen_op5 tcg_gen_op5_avr +#define tcg_gen_op6 tcg_gen_op6_avr +#define tcg_gen_mb tcg_gen_mb_avr +#define tcg_gen_addi_i32 tcg_gen_addi_i32_avr +#define tcg_gen_subfi_i32 tcg_gen_subfi_i32_avr +#define tcg_gen_subi_i32 tcg_gen_subi_i32_avr +#define tcg_gen_andi_i32 tcg_gen_andi_i32_avr +#define tcg_gen_ori_i32 tcg_gen_ori_i32_avr +#define tcg_gen_xori_i32 tcg_gen_xori_i32_avr +#define tcg_gen_shli_i32 tcg_gen_shli_i32_avr +#define tcg_gen_shri_i32 tcg_gen_shri_i32_avr +#define tcg_gen_sari_i32 tcg_gen_sari_i32_avr +#define tcg_gen_brcond_i32 tcg_gen_brcond_i32_avr +#define tcg_gen_brcondi_i32 tcg_gen_brcondi_i32_avr +#define tcg_gen_setcond_i32 tcg_gen_setcond_i32_avr +#define tcg_gen_setcondi_i32 tcg_gen_setcondi_i32_avr +#define tcg_gen_muli_i32 tcg_gen_muli_i32_avr +#define tcg_gen_div_i32 tcg_gen_div_i32_avr +#define tcg_gen_rem_i32 tcg_gen_rem_i32_avr +#define tcg_gen_divu_i32 tcg_gen_divu_i32_avr +#define tcg_gen_remu_i32 tcg_gen_remu_i32_avr +#define tcg_gen_andc_i32 tcg_gen_andc_i32_avr +#define tcg_gen_eqv_i32 tcg_gen_eqv_i32_avr +#define tcg_gen_nand_i32 tcg_gen_nand_i32_avr +#define tcg_gen_nor_i32 tcg_gen_nor_i32_avr +#define tcg_gen_orc_i32 tcg_gen_orc_i32_avr +#define tcg_gen_clz_i32 tcg_gen_clz_i32_avr +#define tcg_gen_clzi_i32 tcg_gen_clzi_i32_avr +#define tcg_gen_ctz_i32 tcg_gen_ctz_i32_avr +#define tcg_gen_ctzi_i32 tcg_gen_ctzi_i32_avr +#define tcg_gen_clrsb_i32 tcg_gen_clrsb_i32_avr +#define tcg_gen_ctpop_i32 tcg_gen_ctpop_i32_avr +#define tcg_gen_rotl_i32 tcg_gen_rotl_i32_avr +#define tcg_gen_rotli_i32 tcg_gen_rotli_i32_avr +#define tcg_gen_rotr_i32 tcg_gen_rotr_i32_avr +#define tcg_gen_rotri_i32 tcg_gen_rotri_i32_avr +#define tcg_gen_deposit_i32 tcg_gen_deposit_i32_avr +#define tcg_gen_deposit_z_i32 tcg_gen_deposit_z_i32_avr +#define tcg_gen_extract_i32 tcg_gen_extract_i32_avr +#define tcg_gen_sextract_i32 tcg_gen_sextract_i32_avr +#define tcg_gen_extract2_i32 tcg_gen_extract2_i32_avr +#define tcg_gen_movcond_i32 tcg_gen_movcond_i32_avr +#define tcg_gen_add2_i32 tcg_gen_add2_i32_avr +#define tcg_gen_sub2_i32 tcg_gen_sub2_i32_avr +#define tcg_gen_mulu2_i32 tcg_gen_mulu2_i32_avr +#define tcg_gen_muls2_i32 tcg_gen_muls2_i32_avr +#define tcg_gen_mulsu2_i32 tcg_gen_mulsu2_i32_avr +#define tcg_gen_ext8s_i32 tcg_gen_ext8s_i32_avr +#define tcg_gen_ext16s_i32 tcg_gen_ext16s_i32_avr +#define tcg_gen_ext8u_i32 tcg_gen_ext8u_i32_avr +#define tcg_gen_ext16u_i32 tcg_gen_ext16u_i32_avr +#define tcg_gen_bswap16_i32 tcg_gen_bswap16_i32_avr +#define tcg_gen_bswap32_i32 tcg_gen_bswap32_i32_avr +#define tcg_gen_smin_i32 tcg_gen_smin_i32_avr +#define tcg_gen_umin_i32 tcg_gen_umin_i32_avr +#define tcg_gen_smax_i32 tcg_gen_smax_i32_avr +#define tcg_gen_umax_i32 tcg_gen_umax_i32_avr +#define tcg_gen_abs_i32 tcg_gen_abs_i32_avr +#define tcg_gen_addi_i64 tcg_gen_addi_i64_avr +#define tcg_gen_subfi_i64 tcg_gen_subfi_i64_avr +#define tcg_gen_subi_i64 tcg_gen_subi_i64_avr +#define tcg_gen_andi_i64 tcg_gen_andi_i64_avr +#define tcg_gen_ori_i64 tcg_gen_ori_i64_avr +#define tcg_gen_xori_i64 tcg_gen_xori_i64_avr +#define tcg_gen_shli_i64 tcg_gen_shli_i64_avr +#define tcg_gen_shri_i64 tcg_gen_shri_i64_avr +#define tcg_gen_sari_i64 tcg_gen_sari_i64_avr +#define tcg_gen_brcond_i64 tcg_gen_brcond_i64_avr +#define tcg_gen_brcondi_i64 tcg_gen_brcondi_i64_avr +#define tcg_gen_setcond_i64 tcg_gen_setcond_i64_avr +#define tcg_gen_setcondi_i64 tcg_gen_setcondi_i64_avr +#define tcg_gen_muli_i64 tcg_gen_muli_i64_avr +#define tcg_gen_div_i64 tcg_gen_div_i64_avr +#define tcg_gen_rem_i64 tcg_gen_rem_i64_avr +#define tcg_gen_divu_i64 tcg_gen_divu_i64_avr +#define tcg_gen_remu_i64 tcg_gen_remu_i64_avr +#define tcg_gen_ext8s_i64 tcg_gen_ext8s_i64_avr +#define tcg_gen_ext16s_i64 tcg_gen_ext16s_i64_avr +#define tcg_gen_ext32s_i64 tcg_gen_ext32s_i64_avr +#define tcg_gen_ext8u_i64 tcg_gen_ext8u_i64_avr +#define tcg_gen_ext16u_i64 tcg_gen_ext16u_i64_avr +#define tcg_gen_ext32u_i64 tcg_gen_ext32u_i64_avr +#define tcg_gen_bswap16_i64 tcg_gen_bswap16_i64_avr +#define tcg_gen_bswap32_i64 tcg_gen_bswap32_i64_avr +#define tcg_gen_bswap64_i64 tcg_gen_bswap64_i64_avr +#define tcg_gen_not_i64 tcg_gen_not_i64_avr +#define tcg_gen_andc_i64 tcg_gen_andc_i64_avr +#define tcg_gen_eqv_i64 tcg_gen_eqv_i64_avr +#define tcg_gen_nand_i64 tcg_gen_nand_i64_avr +#define tcg_gen_nor_i64 tcg_gen_nor_i64_avr +#define tcg_gen_orc_i64 tcg_gen_orc_i64_avr +#define tcg_gen_clz_i64 tcg_gen_clz_i64_avr +#define tcg_gen_clzi_i64 tcg_gen_clzi_i64_avr +#define tcg_gen_ctz_i64 tcg_gen_ctz_i64_avr +#define tcg_gen_ctzi_i64 tcg_gen_ctzi_i64_avr +#define tcg_gen_clrsb_i64 tcg_gen_clrsb_i64_avr +#define tcg_gen_ctpop_i64 tcg_gen_ctpop_i64_avr +#define tcg_gen_rotl_i64 tcg_gen_rotl_i64_avr +#define tcg_gen_rotli_i64 tcg_gen_rotli_i64_avr +#define tcg_gen_rotr_i64 tcg_gen_rotr_i64_avr +#define tcg_gen_rotri_i64 tcg_gen_rotri_i64_avr +#define tcg_gen_deposit_i64 tcg_gen_deposit_i64_avr +#define tcg_gen_deposit_z_i64 tcg_gen_deposit_z_i64_avr +#define tcg_gen_extract_i64 tcg_gen_extract_i64_avr +#define tcg_gen_sextract_i64 tcg_gen_sextract_i64_avr +#define tcg_gen_extract2_i64 tcg_gen_extract2_i64_avr +#define tcg_gen_movcond_i64 tcg_gen_movcond_i64_avr +#define tcg_gen_add2_i64 tcg_gen_add2_i64_avr +#define tcg_gen_sub2_i64 tcg_gen_sub2_i64_avr +#define tcg_gen_mulu2_i64 tcg_gen_mulu2_i64_avr +#define tcg_gen_muls2_i64 tcg_gen_muls2_i64_avr +#define tcg_gen_mulsu2_i64 tcg_gen_mulsu2_i64_avr +#define tcg_gen_smin_i64 tcg_gen_smin_i64_avr +#define tcg_gen_umin_i64 tcg_gen_umin_i64_avr +#define tcg_gen_smax_i64 tcg_gen_smax_i64_avr +#define tcg_gen_umax_i64 tcg_gen_umax_i64_avr +#define tcg_gen_abs_i64 tcg_gen_abs_i64_avr +#define tcg_gen_extrl_i64_i32 tcg_gen_extrl_i64_i32_avr +#define tcg_gen_extrh_i64_i32 tcg_gen_extrh_i64_i32_avr +#define tcg_gen_extu_i32_i64 tcg_gen_extu_i32_i64_avr +#define tcg_gen_ext_i32_i64 tcg_gen_ext_i32_i64_avr +#define tcg_gen_concat_i32_i64 tcg_gen_concat_i32_i64_avr +#define tcg_gen_extr_i64_i32 tcg_gen_extr_i64_i32_avr +#define tcg_gen_extr32_i64 tcg_gen_extr32_i64_avr +#define tcg_gen_exit_tb tcg_gen_exit_tb_avr +#define tcg_gen_goto_tb tcg_gen_goto_tb_avr +#define tcg_gen_lookup_and_goto_ptr tcg_gen_lookup_and_goto_ptr_avr +#define check_exit_request check_exit_request_avr +#define tcg_gen_qemu_ld_i32 tcg_gen_qemu_ld_i32_avr +#define tcg_gen_qemu_st_i32 tcg_gen_qemu_st_i32_avr +#define tcg_gen_qemu_ld_i64 tcg_gen_qemu_ld_i64_avr +#define tcg_gen_qemu_st_i64 tcg_gen_qemu_st_i64_avr +#define tcg_gen_atomic_cmpxchg_i32 tcg_gen_atomic_cmpxchg_i32_avr +#define tcg_gen_atomic_cmpxchg_i64 tcg_gen_atomic_cmpxchg_i64_avr +#define tcg_gen_atomic_fetch_add_i32 tcg_gen_atomic_fetch_add_i32_avr +#define tcg_gen_atomic_fetch_add_i64 tcg_gen_atomic_fetch_add_i64_avr +#define tcg_gen_atomic_fetch_and_i32 tcg_gen_atomic_fetch_and_i32_avr +#define tcg_gen_atomic_fetch_and_i64 tcg_gen_atomic_fetch_and_i64_avr +#define tcg_gen_atomic_fetch_or_i32 tcg_gen_atomic_fetch_or_i32_avr +#define tcg_gen_atomic_fetch_or_i64 tcg_gen_atomic_fetch_or_i64_avr +#define tcg_gen_atomic_fetch_xor_i32 tcg_gen_atomic_fetch_xor_i32_avr +#define tcg_gen_atomic_fetch_xor_i64 tcg_gen_atomic_fetch_xor_i64_avr +#define tcg_gen_atomic_fetch_smin_i32 tcg_gen_atomic_fetch_smin_i32_avr +#define tcg_gen_atomic_fetch_smin_i64 tcg_gen_atomic_fetch_smin_i64_avr +#define tcg_gen_atomic_fetch_umin_i32 tcg_gen_atomic_fetch_umin_i32_avr +#define tcg_gen_atomic_fetch_umin_i64 tcg_gen_atomic_fetch_umin_i64_avr +#define tcg_gen_atomic_fetch_smax_i32 tcg_gen_atomic_fetch_smax_i32_avr +#define tcg_gen_atomic_fetch_smax_i64 tcg_gen_atomic_fetch_smax_i64_avr +#define tcg_gen_atomic_fetch_umax_i32 tcg_gen_atomic_fetch_umax_i32_avr +#define tcg_gen_atomic_fetch_umax_i64 tcg_gen_atomic_fetch_umax_i64_avr +#define tcg_gen_atomic_add_fetch_i32 tcg_gen_atomic_add_fetch_i32_avr +#define tcg_gen_atomic_add_fetch_i64 tcg_gen_atomic_add_fetch_i64_avr +#define tcg_gen_atomic_and_fetch_i32 tcg_gen_atomic_and_fetch_i32_avr +#define tcg_gen_atomic_and_fetch_i64 tcg_gen_atomic_and_fetch_i64_avr +#define tcg_gen_atomic_or_fetch_i32 tcg_gen_atomic_or_fetch_i32_avr +#define tcg_gen_atomic_or_fetch_i64 tcg_gen_atomic_or_fetch_i64_avr +#define tcg_gen_atomic_xor_fetch_i32 tcg_gen_atomic_xor_fetch_i32_avr +#define tcg_gen_atomic_xor_fetch_i64 tcg_gen_atomic_xor_fetch_i64_avr +#define tcg_gen_atomic_smin_fetch_i32 tcg_gen_atomic_smin_fetch_i32_avr +#define tcg_gen_atomic_smin_fetch_i64 tcg_gen_atomic_smin_fetch_i64_avr +#define tcg_gen_atomic_umin_fetch_i32 tcg_gen_atomic_umin_fetch_i32_avr +#define tcg_gen_atomic_umin_fetch_i64 tcg_gen_atomic_umin_fetch_i64_avr +#define tcg_gen_atomic_smax_fetch_i32 tcg_gen_atomic_smax_fetch_i32_avr +#define tcg_gen_atomic_smax_fetch_i64 tcg_gen_atomic_smax_fetch_i64_avr +#define tcg_gen_atomic_umax_fetch_i32 tcg_gen_atomic_umax_fetch_i32_avr +#define tcg_gen_atomic_umax_fetch_i64 tcg_gen_atomic_umax_fetch_i64_avr +#define tcg_gen_atomic_xchg_i32 tcg_gen_atomic_xchg_i32_avr +#define tcg_gen_atomic_xchg_i64 tcg_gen_atomic_xchg_i64_avr +#define simd_desc simd_desc_avr +#define tcg_gen_gvec_2_ool tcg_gen_gvec_2_ool_avr +#define tcg_gen_gvec_2i_ool tcg_gen_gvec_2i_ool_avr +#define tcg_gen_gvec_3_ool tcg_gen_gvec_3_ool_avr +#define tcg_gen_gvec_4_ool tcg_gen_gvec_4_ool_avr +#define tcg_gen_gvec_5_ool tcg_gen_gvec_5_ool_avr +#define tcg_gen_gvec_2_ptr tcg_gen_gvec_2_ptr_avr +#define tcg_gen_gvec_3_ptr tcg_gen_gvec_3_ptr_avr +#define tcg_gen_gvec_4_ptr tcg_gen_gvec_4_ptr_avr +#define tcg_gen_gvec_5_ptr tcg_gen_gvec_5_ptr_avr +#define tcg_gen_gvec_2 tcg_gen_gvec_2_avr +#define tcg_gen_gvec_2i tcg_gen_gvec_2i_avr +#define tcg_gen_gvec_2s tcg_gen_gvec_2s_avr +#define tcg_gen_gvec_3 tcg_gen_gvec_3_avr +#define tcg_gen_gvec_3i tcg_gen_gvec_3i_avr +#define tcg_gen_gvec_4 tcg_gen_gvec_4_avr +#define tcg_gen_gvec_mov tcg_gen_gvec_mov_avr +#define tcg_gen_gvec_dup_i32 tcg_gen_gvec_dup_i32_avr +#define tcg_gen_gvec_dup_i64 tcg_gen_gvec_dup_i64_avr +#define tcg_gen_gvec_dup_mem tcg_gen_gvec_dup_mem_avr +#define tcg_gen_gvec_dup64i tcg_gen_gvec_dup64i_avr +#define tcg_gen_gvec_dup32i tcg_gen_gvec_dup32i_avr +#define tcg_gen_gvec_dup16i tcg_gen_gvec_dup16i_avr +#define tcg_gen_gvec_dup8i tcg_gen_gvec_dup8i_avr +#define tcg_gen_gvec_not tcg_gen_gvec_not_avr +#define tcg_gen_vec_add8_i64 tcg_gen_vec_add8_i64_avr +#define tcg_gen_vec_add16_i64 tcg_gen_vec_add16_i64_avr +#define tcg_gen_vec_add32_i64 tcg_gen_vec_add32_i64_avr +#define tcg_gen_gvec_add tcg_gen_gvec_add_avr +#define tcg_gen_gvec_adds tcg_gen_gvec_adds_avr +#define tcg_gen_gvec_addi tcg_gen_gvec_addi_avr +#define tcg_gen_gvec_subs tcg_gen_gvec_subs_avr +#define tcg_gen_vec_sub8_i64 tcg_gen_vec_sub8_i64_avr +#define tcg_gen_vec_sub16_i64 tcg_gen_vec_sub16_i64_avr +#define tcg_gen_vec_sub32_i64 tcg_gen_vec_sub32_i64_avr +#define tcg_gen_gvec_sub tcg_gen_gvec_sub_avr +#define tcg_gen_gvec_mul tcg_gen_gvec_mul_avr +#define tcg_gen_gvec_muls tcg_gen_gvec_muls_avr +#define tcg_gen_gvec_muli tcg_gen_gvec_muli_avr +#define tcg_gen_gvec_ssadd tcg_gen_gvec_ssadd_avr +#define tcg_gen_gvec_sssub tcg_gen_gvec_sssub_avr +#define tcg_gen_gvec_usadd tcg_gen_gvec_usadd_avr +#define tcg_gen_gvec_ussub tcg_gen_gvec_ussub_avr +#define tcg_gen_gvec_smin tcg_gen_gvec_smin_avr +#define tcg_gen_gvec_umin tcg_gen_gvec_umin_avr +#define tcg_gen_gvec_smax tcg_gen_gvec_smax_avr +#define tcg_gen_gvec_umax tcg_gen_gvec_umax_avr +#define tcg_gen_vec_neg8_i64 tcg_gen_vec_neg8_i64_avr +#define tcg_gen_vec_neg16_i64 tcg_gen_vec_neg16_i64_avr +#define tcg_gen_vec_neg32_i64 tcg_gen_vec_neg32_i64_avr +#define tcg_gen_gvec_neg tcg_gen_gvec_neg_avr +#define tcg_gen_gvec_abs tcg_gen_gvec_abs_avr +#define tcg_gen_gvec_and tcg_gen_gvec_and_avr +#define tcg_gen_gvec_or tcg_gen_gvec_or_avr +#define tcg_gen_gvec_xor tcg_gen_gvec_xor_avr +#define tcg_gen_gvec_andc tcg_gen_gvec_andc_avr +#define tcg_gen_gvec_orc tcg_gen_gvec_orc_avr +#define tcg_gen_gvec_nand tcg_gen_gvec_nand_avr +#define tcg_gen_gvec_nor tcg_gen_gvec_nor_avr +#define tcg_gen_gvec_eqv tcg_gen_gvec_eqv_avr +#define tcg_gen_gvec_ands tcg_gen_gvec_ands_avr +#define tcg_gen_gvec_andi tcg_gen_gvec_andi_avr +#define tcg_gen_gvec_xors tcg_gen_gvec_xors_avr +#define tcg_gen_gvec_xori tcg_gen_gvec_xori_avr +#define tcg_gen_gvec_ors tcg_gen_gvec_ors_avr +#define tcg_gen_gvec_ori tcg_gen_gvec_ori_avr +#define tcg_gen_vec_shl8i_i64 tcg_gen_vec_shl8i_i64_avr +#define tcg_gen_vec_shl16i_i64 tcg_gen_vec_shl16i_i64_avr +#define tcg_gen_gvec_shli tcg_gen_gvec_shli_avr +#define tcg_gen_vec_shr8i_i64 tcg_gen_vec_shr8i_i64_avr +#define tcg_gen_vec_shr16i_i64 tcg_gen_vec_shr16i_i64_avr +#define tcg_gen_gvec_shri tcg_gen_gvec_shri_avr +#define tcg_gen_vec_sar8i_i64 tcg_gen_vec_sar8i_i64_avr +#define tcg_gen_vec_sar16i_i64 tcg_gen_vec_sar16i_i64_avr +#define tcg_gen_gvec_sari tcg_gen_gvec_sari_avr +#define tcg_gen_gvec_shls tcg_gen_gvec_shls_avr +#define tcg_gen_gvec_shrs tcg_gen_gvec_shrs_avr +#define tcg_gen_gvec_sars tcg_gen_gvec_sars_avr +#define tcg_gen_gvec_shlv tcg_gen_gvec_shlv_avr +#define tcg_gen_gvec_shrv tcg_gen_gvec_shrv_avr +#define tcg_gen_gvec_sarv tcg_gen_gvec_sarv_avr +#define tcg_gen_gvec_cmp tcg_gen_gvec_cmp_avr +#define tcg_gen_gvec_bitsel tcg_gen_gvec_bitsel_avr +#define tcg_can_emit_vecop_list tcg_can_emit_vecop_list_avr +#define vec_gen_2 vec_gen_2_avr +#define vec_gen_3 vec_gen_3_avr +#define vec_gen_4 vec_gen_4_avr +#define tcg_gen_mov_vec tcg_gen_mov_vec_avr +#define tcg_const_zeros_vec tcg_const_zeros_vec_avr +#define tcg_const_ones_vec tcg_const_ones_vec_avr +#define tcg_const_zeros_vec_matching tcg_const_zeros_vec_matching_avr +#define tcg_const_ones_vec_matching tcg_const_ones_vec_matching_avr +#define tcg_gen_dup64i_vec tcg_gen_dup64i_vec_avr +#define tcg_gen_dup32i_vec tcg_gen_dup32i_vec_avr +#define tcg_gen_dup16i_vec tcg_gen_dup16i_vec_avr +#define tcg_gen_dup8i_vec tcg_gen_dup8i_vec_avr +#define tcg_gen_dupi_vec tcg_gen_dupi_vec_avr +#define tcg_gen_dup_i64_vec tcg_gen_dup_i64_vec_avr +#define tcg_gen_dup_i32_vec tcg_gen_dup_i32_vec_avr +#define tcg_gen_dup_mem_vec tcg_gen_dup_mem_vec_avr +#define tcg_gen_ld_vec tcg_gen_ld_vec_avr +#define tcg_gen_st_vec tcg_gen_st_vec_avr +#define tcg_gen_stl_vec tcg_gen_stl_vec_avr +#define tcg_gen_and_vec tcg_gen_and_vec_avr +#define tcg_gen_or_vec tcg_gen_or_vec_avr +#define tcg_gen_xor_vec tcg_gen_xor_vec_avr +#define tcg_gen_andc_vec tcg_gen_andc_vec_avr +#define tcg_gen_orc_vec tcg_gen_orc_vec_avr +#define tcg_gen_nand_vec tcg_gen_nand_vec_avr +#define tcg_gen_nor_vec tcg_gen_nor_vec_avr +#define tcg_gen_eqv_vec tcg_gen_eqv_vec_avr +#define tcg_gen_not_vec tcg_gen_not_vec_avr +#define tcg_gen_neg_vec tcg_gen_neg_vec_avr +#define tcg_gen_abs_vec tcg_gen_abs_vec_avr +#define tcg_gen_shli_vec tcg_gen_shli_vec_avr +#define tcg_gen_shri_vec tcg_gen_shri_vec_avr +#define tcg_gen_sari_vec tcg_gen_sari_vec_avr +#define tcg_gen_cmp_vec tcg_gen_cmp_vec_avr +#define tcg_gen_add_vec tcg_gen_add_vec_avr +#define tcg_gen_sub_vec tcg_gen_sub_vec_avr +#define tcg_gen_mul_vec tcg_gen_mul_vec_avr +#define tcg_gen_ssadd_vec tcg_gen_ssadd_vec_avr +#define tcg_gen_usadd_vec tcg_gen_usadd_vec_avr +#define tcg_gen_sssub_vec tcg_gen_sssub_vec_avr +#define tcg_gen_ussub_vec tcg_gen_ussub_vec_avr +#define tcg_gen_smin_vec tcg_gen_smin_vec_avr +#define tcg_gen_umin_vec tcg_gen_umin_vec_avr +#define tcg_gen_smax_vec tcg_gen_smax_vec_avr +#define tcg_gen_umax_vec tcg_gen_umax_vec_avr +#define tcg_gen_shlv_vec tcg_gen_shlv_vec_avr +#define tcg_gen_shrv_vec tcg_gen_shrv_vec_avr +#define tcg_gen_sarv_vec tcg_gen_sarv_vec_avr +#define tcg_gen_shls_vec tcg_gen_shls_vec_avr +#define tcg_gen_shrs_vec tcg_gen_shrs_vec_avr +#define tcg_gen_sars_vec tcg_gen_sars_vec_avr +#define tcg_gen_bitsel_vec tcg_gen_bitsel_vec_avr +#define tcg_gen_cmpsel_vec tcg_gen_cmpsel_vec_avr +#define tb_htable_lookup tb_htable_lookup_avr +#define tb_set_jmp_target tb_set_jmp_target_avr +#define cpu_exec cpu_exec_avr +#define cpu_loop_exit_noexc cpu_loop_exit_noexc_avr +#define cpu_reloading_memory_map cpu_reloading_memory_map_avr +#define cpu_loop_exit cpu_loop_exit_avr +#define cpu_loop_exit_restore cpu_loop_exit_restore_avr +#define cpu_loop_exit_atomic cpu_loop_exit_atomic_avr +#define tlb_init tlb_init_avr +#define tlb_flush_by_mmuidx tlb_flush_by_mmuidx_avr +#define tlb_flush tlb_flush_avr +#define tlb_flush_by_mmuidx_all_cpus tlb_flush_by_mmuidx_all_cpus_avr +#define tlb_flush_all_cpus tlb_flush_all_cpus_avr +#define tlb_flush_by_mmuidx_all_cpus_synced tlb_flush_by_mmuidx_all_cpus_synced_avr +#define tlb_flush_all_cpus_synced tlb_flush_all_cpus_synced_avr +#define tlb_flush_page_by_mmuidx tlb_flush_page_by_mmuidx_avr +#define tlb_flush_page tlb_flush_page_avr +#define tlb_flush_page_by_mmuidx_all_cpus tlb_flush_page_by_mmuidx_all_cpus_avr +#define tlb_flush_page_all_cpus tlb_flush_page_all_cpus_avr +#define tlb_flush_page_by_mmuidx_all_cpus_synced tlb_flush_page_by_mmuidx_all_cpus_synced_avr +#define tlb_flush_page_all_cpus_synced tlb_flush_page_all_cpus_synced_avr +#define tlb_protect_code tlb_protect_code_avr +#define tlb_unprotect_code tlb_unprotect_code_avr +#define tlb_reset_dirty tlb_reset_dirty_avr +#define tlb_set_dirty tlb_set_dirty_avr +#define tlb_set_page_with_attrs tlb_set_page_with_attrs_avr +#define tlb_set_page tlb_set_page_avr +#define get_page_addr_code_hostp get_page_addr_code_hostp_avr +#define get_page_addr_code get_page_addr_code_avr +#define probe_access probe_access_avr +#define tlb_vaddr_to_host tlb_vaddr_to_host_avr +#define helper_ret_ldub_mmu helper_ret_ldub_mmu_avr +#define helper_le_lduw_mmu helper_le_lduw_mmu_avr +#define helper_be_lduw_mmu helper_be_lduw_mmu_avr +#define helper_le_ldul_mmu helper_le_ldul_mmu_avr +#define helper_be_ldul_mmu helper_be_ldul_mmu_avr +#define helper_le_ldq_mmu helper_le_ldq_mmu_avr +#define helper_be_ldq_mmu helper_be_ldq_mmu_avr +#define helper_ret_ldsb_mmu helper_ret_ldsb_mmu_avr +#define helper_le_ldsw_mmu helper_le_ldsw_mmu_avr +#define helper_be_ldsw_mmu helper_be_ldsw_mmu_avr +#define helper_le_ldsl_mmu helper_le_ldsl_mmu_avr +#define helper_be_ldsl_mmu helper_be_ldsl_mmu_avr +#define cpu_ldub_mmuidx_ra cpu_ldub_mmuidx_ra_avr +#define cpu_ldsb_mmuidx_ra cpu_ldsb_mmuidx_ra_avr +#define cpu_lduw_mmuidx_ra cpu_lduw_mmuidx_ra_avr +#define cpu_ldsw_mmuidx_ra cpu_ldsw_mmuidx_ra_avr +#define cpu_ldl_mmuidx_ra cpu_ldl_mmuidx_ra_avr +#define cpu_ldq_mmuidx_ra cpu_ldq_mmuidx_ra_avr +#define cpu_ldub_data_ra cpu_ldub_data_ra_avr +#define cpu_ldsb_data_ra cpu_ldsb_data_ra_avr +#define cpu_lduw_data_ra cpu_lduw_data_ra_avr +#define cpu_ldsw_data_ra cpu_ldsw_data_ra_avr +#define cpu_ldl_data_ra cpu_ldl_data_ra_avr +#define cpu_ldq_data_ra cpu_ldq_data_ra_avr +#define cpu_ldub_data cpu_ldub_data_avr +#define cpu_ldsb_data cpu_ldsb_data_avr +#define cpu_lduw_data cpu_lduw_data_avr +#define cpu_ldsw_data cpu_ldsw_data_avr +#define cpu_ldl_data cpu_ldl_data_avr +#define cpu_ldq_data cpu_ldq_data_avr +#define helper_ret_stb_mmu helper_ret_stb_mmu_avr +#define helper_le_stw_mmu helper_le_stw_mmu_avr +#define helper_be_stw_mmu helper_be_stw_mmu_avr +#define helper_le_stl_mmu helper_le_stl_mmu_avr +#define helper_be_stl_mmu helper_be_stl_mmu_avr +#define helper_le_stq_mmu helper_le_stq_mmu_avr +#define helper_be_stq_mmu helper_be_stq_mmu_avr +#define cpu_stb_mmuidx_ra cpu_stb_mmuidx_ra_avr +#define cpu_stw_mmuidx_ra cpu_stw_mmuidx_ra_avr +#define cpu_stl_mmuidx_ra cpu_stl_mmuidx_ra_avr +#define cpu_stq_mmuidx_ra cpu_stq_mmuidx_ra_avr +#define cpu_stb_data_ra cpu_stb_data_ra_avr +#define cpu_stw_data_ra cpu_stw_data_ra_avr +#define cpu_stl_data_ra cpu_stl_data_ra_avr +#define cpu_stq_data_ra cpu_stq_data_ra_avr +#define cpu_stb_data cpu_stb_data_avr +#define cpu_stw_data cpu_stw_data_avr +#define cpu_stl_data cpu_stl_data_avr +#define cpu_stq_data cpu_stq_data_avr +#define helper_atomic_cmpxchgb_mmu helper_atomic_cmpxchgb_mmu_avr +#define helper_atomic_xchgb_mmu helper_atomic_xchgb_mmu_avr +#define helper_atomic_fetch_addb_mmu helper_atomic_fetch_addb_mmu_avr +#define helper_atomic_fetch_andb_mmu helper_atomic_fetch_andb_mmu_avr +#define helper_atomic_fetch_orb_mmu helper_atomic_fetch_orb_mmu_avr +#define helper_atomic_fetch_xorb_mmu helper_atomic_fetch_xorb_mmu_avr +#define helper_atomic_add_fetchb_mmu helper_atomic_add_fetchb_mmu_avr +#define helper_atomic_and_fetchb_mmu helper_atomic_and_fetchb_mmu_avr +#define helper_atomic_or_fetchb_mmu helper_atomic_or_fetchb_mmu_avr +#define helper_atomic_xor_fetchb_mmu helper_atomic_xor_fetchb_mmu_avr +#define helper_atomic_fetch_sminb_mmu helper_atomic_fetch_sminb_mmu_avr +#define helper_atomic_fetch_uminb_mmu helper_atomic_fetch_uminb_mmu_avr +#define helper_atomic_fetch_smaxb_mmu helper_atomic_fetch_smaxb_mmu_avr +#define helper_atomic_fetch_umaxb_mmu helper_atomic_fetch_umaxb_mmu_avr +#define helper_atomic_smin_fetchb_mmu helper_atomic_smin_fetchb_mmu_avr +#define helper_atomic_umin_fetchb_mmu helper_atomic_umin_fetchb_mmu_avr +#define helper_atomic_smax_fetchb_mmu helper_atomic_smax_fetchb_mmu_avr +#define helper_atomic_umax_fetchb_mmu helper_atomic_umax_fetchb_mmu_avr +#define helper_atomic_cmpxchgw_le_mmu helper_atomic_cmpxchgw_le_mmu_avr +#define helper_atomic_xchgw_le_mmu helper_atomic_xchgw_le_mmu_avr +#define helper_atomic_fetch_addw_le_mmu helper_atomic_fetch_addw_le_mmu_avr +#define helper_atomic_fetch_andw_le_mmu helper_atomic_fetch_andw_le_mmu_avr +#define helper_atomic_fetch_orw_le_mmu helper_atomic_fetch_orw_le_mmu_avr +#define helper_atomic_fetch_xorw_le_mmu helper_atomic_fetch_xorw_le_mmu_avr +#define helper_atomic_add_fetchw_le_mmu helper_atomic_add_fetchw_le_mmu_avr +#define helper_atomic_and_fetchw_le_mmu helper_atomic_and_fetchw_le_mmu_avr +#define helper_atomic_or_fetchw_le_mmu helper_atomic_or_fetchw_le_mmu_avr +#define helper_atomic_xor_fetchw_le_mmu helper_atomic_xor_fetchw_le_mmu_avr +#define helper_atomic_fetch_sminw_le_mmu helper_atomic_fetch_sminw_le_mmu_avr +#define helper_atomic_fetch_uminw_le_mmu helper_atomic_fetch_uminw_le_mmu_avr +#define helper_atomic_fetch_smaxw_le_mmu helper_atomic_fetch_smaxw_le_mmu_avr +#define helper_atomic_fetch_umaxw_le_mmu helper_atomic_fetch_umaxw_le_mmu_avr +#define helper_atomic_smin_fetchw_le_mmu helper_atomic_smin_fetchw_le_mmu_avr +#define helper_atomic_umin_fetchw_le_mmu helper_atomic_umin_fetchw_le_mmu_avr +#define helper_atomic_smax_fetchw_le_mmu helper_atomic_smax_fetchw_le_mmu_avr +#define helper_atomic_umax_fetchw_le_mmu helper_atomic_umax_fetchw_le_mmu_avr +#define helper_atomic_cmpxchgw_be_mmu helper_atomic_cmpxchgw_be_mmu_avr +#define helper_atomic_xchgw_be_mmu helper_atomic_xchgw_be_mmu_avr +#define helper_atomic_fetch_andw_be_mmu helper_atomic_fetch_andw_be_mmu_avr +#define helper_atomic_fetch_orw_be_mmu helper_atomic_fetch_orw_be_mmu_avr +#define helper_atomic_fetch_xorw_be_mmu helper_atomic_fetch_xorw_be_mmu_avr +#define helper_atomic_and_fetchw_be_mmu helper_atomic_and_fetchw_be_mmu_avr +#define helper_atomic_or_fetchw_be_mmu helper_atomic_or_fetchw_be_mmu_avr +#define helper_atomic_xor_fetchw_be_mmu helper_atomic_xor_fetchw_be_mmu_avr +#define helper_atomic_fetch_sminw_be_mmu helper_atomic_fetch_sminw_be_mmu_avr +#define helper_atomic_fetch_uminw_be_mmu helper_atomic_fetch_uminw_be_mmu_avr +#define helper_atomic_fetch_smaxw_be_mmu helper_atomic_fetch_smaxw_be_mmu_avr +#define helper_atomic_fetch_umaxw_be_mmu helper_atomic_fetch_umaxw_be_mmu_avr +#define helper_atomic_smin_fetchw_be_mmu helper_atomic_smin_fetchw_be_mmu_avr +#define helper_atomic_umin_fetchw_be_mmu helper_atomic_umin_fetchw_be_mmu_avr +#define helper_atomic_smax_fetchw_be_mmu helper_atomic_smax_fetchw_be_mmu_avr +#define helper_atomic_umax_fetchw_be_mmu helper_atomic_umax_fetchw_be_mmu_avr +#define helper_atomic_fetch_addw_be_mmu helper_atomic_fetch_addw_be_mmu_avr +#define helper_atomic_add_fetchw_be_mmu helper_atomic_add_fetchw_be_mmu_avr +#define helper_atomic_cmpxchgl_le_mmu helper_atomic_cmpxchgl_le_mmu_avr +#define helper_atomic_xchgl_le_mmu helper_atomic_xchgl_le_mmu_avr +#define helper_atomic_fetch_addl_le_mmu helper_atomic_fetch_addl_le_mmu_avr +#define helper_atomic_fetch_andl_le_mmu helper_atomic_fetch_andl_le_mmu_avr +#define helper_atomic_fetch_orl_le_mmu helper_atomic_fetch_orl_le_mmu_avr +#define helper_atomic_fetch_xorl_le_mmu helper_atomic_fetch_xorl_le_mmu_avr +#define helper_atomic_add_fetchl_le_mmu helper_atomic_add_fetchl_le_mmu_avr +#define helper_atomic_and_fetchl_le_mmu helper_atomic_and_fetchl_le_mmu_avr +#define helper_atomic_or_fetchl_le_mmu helper_atomic_or_fetchl_le_mmu_avr +#define helper_atomic_xor_fetchl_le_mmu helper_atomic_xor_fetchl_le_mmu_avr +#define helper_atomic_fetch_sminl_le_mmu helper_atomic_fetch_sminl_le_mmu_avr +#define helper_atomic_fetch_uminl_le_mmu helper_atomic_fetch_uminl_le_mmu_avr +#define helper_atomic_fetch_smaxl_le_mmu helper_atomic_fetch_smaxl_le_mmu_avr +#define helper_atomic_fetch_umaxl_le_mmu helper_atomic_fetch_umaxl_le_mmu_avr +#define helper_atomic_smin_fetchl_le_mmu helper_atomic_smin_fetchl_le_mmu_avr +#define helper_atomic_umin_fetchl_le_mmu helper_atomic_umin_fetchl_le_mmu_avr +#define helper_atomic_smax_fetchl_le_mmu helper_atomic_smax_fetchl_le_mmu_avr +#define helper_atomic_umax_fetchl_le_mmu helper_atomic_umax_fetchl_le_mmu_avr +#define helper_atomic_cmpxchgl_be_mmu helper_atomic_cmpxchgl_be_mmu_avr +#define helper_atomic_xchgl_be_mmu helper_atomic_xchgl_be_mmu_avr +#define helper_atomic_fetch_andl_be_mmu helper_atomic_fetch_andl_be_mmu_avr +#define helper_atomic_fetch_orl_be_mmu helper_atomic_fetch_orl_be_mmu_avr +#define helper_atomic_fetch_xorl_be_mmu helper_atomic_fetch_xorl_be_mmu_avr +#define helper_atomic_and_fetchl_be_mmu helper_atomic_and_fetchl_be_mmu_avr +#define helper_atomic_or_fetchl_be_mmu helper_atomic_or_fetchl_be_mmu_avr +#define helper_atomic_xor_fetchl_be_mmu helper_atomic_xor_fetchl_be_mmu_avr +#define helper_atomic_fetch_sminl_be_mmu helper_atomic_fetch_sminl_be_mmu_avr +#define helper_atomic_fetch_uminl_be_mmu helper_atomic_fetch_uminl_be_mmu_avr +#define helper_atomic_fetch_smaxl_be_mmu helper_atomic_fetch_smaxl_be_mmu_avr +#define helper_atomic_fetch_umaxl_be_mmu helper_atomic_fetch_umaxl_be_mmu_avr +#define helper_atomic_smin_fetchl_be_mmu helper_atomic_smin_fetchl_be_mmu_avr +#define helper_atomic_umin_fetchl_be_mmu helper_atomic_umin_fetchl_be_mmu_avr +#define helper_atomic_smax_fetchl_be_mmu helper_atomic_smax_fetchl_be_mmu_avr +#define helper_atomic_umax_fetchl_be_mmu helper_atomic_umax_fetchl_be_mmu_avr +#define helper_atomic_fetch_addl_be_mmu helper_atomic_fetch_addl_be_mmu_avr +#define helper_atomic_add_fetchl_be_mmu helper_atomic_add_fetchl_be_mmu_avr +#define helper_atomic_cmpxchgq_le_mmu helper_atomic_cmpxchgq_le_mmu_avr +#define helper_atomic_xchgq_le_mmu helper_atomic_xchgq_le_mmu_avr +#define helper_atomic_fetch_addq_le_mmu helper_atomic_fetch_addq_le_mmu_avr +#define helper_atomic_fetch_andq_le_mmu helper_atomic_fetch_andq_le_mmu_avr +#define helper_atomic_fetch_orq_le_mmu helper_atomic_fetch_orq_le_mmu_avr +#define helper_atomic_fetch_xorq_le_mmu helper_atomic_fetch_xorq_le_mmu_avr +#define helper_atomic_add_fetchq_le_mmu helper_atomic_add_fetchq_le_mmu_avr +#define helper_atomic_and_fetchq_le_mmu helper_atomic_and_fetchq_le_mmu_avr +#define helper_atomic_or_fetchq_le_mmu helper_atomic_or_fetchq_le_mmu_avr +#define helper_atomic_xor_fetchq_le_mmu helper_atomic_xor_fetchq_le_mmu_avr +#define helper_atomic_fetch_sminq_le_mmu helper_atomic_fetch_sminq_le_mmu_avr +#define helper_atomic_fetch_uminq_le_mmu helper_atomic_fetch_uminq_le_mmu_avr +#define helper_atomic_fetch_smaxq_le_mmu helper_atomic_fetch_smaxq_le_mmu_avr +#define helper_atomic_fetch_umaxq_le_mmu helper_atomic_fetch_umaxq_le_mmu_avr +#define helper_atomic_smin_fetchq_le_mmu helper_atomic_smin_fetchq_le_mmu_avr +#define helper_atomic_umin_fetchq_le_mmu helper_atomic_umin_fetchq_le_mmu_avr +#define helper_atomic_smax_fetchq_le_mmu helper_atomic_smax_fetchq_le_mmu_avr +#define helper_atomic_umax_fetchq_le_mmu helper_atomic_umax_fetchq_le_mmu_avr +#define helper_atomic_cmpxchgq_be_mmu helper_atomic_cmpxchgq_be_mmu_avr +#define helper_atomic_xchgq_be_mmu helper_atomic_xchgq_be_mmu_avr +#define helper_atomic_fetch_andq_be_mmu helper_atomic_fetch_andq_be_mmu_avr +#define helper_atomic_fetch_orq_be_mmu helper_atomic_fetch_orq_be_mmu_avr +#define helper_atomic_fetch_xorq_be_mmu helper_atomic_fetch_xorq_be_mmu_avr +#define helper_atomic_and_fetchq_be_mmu helper_atomic_and_fetchq_be_mmu_avr +#define helper_atomic_or_fetchq_be_mmu helper_atomic_or_fetchq_be_mmu_avr +#define helper_atomic_xor_fetchq_be_mmu helper_atomic_xor_fetchq_be_mmu_avr +#define helper_atomic_fetch_sminq_be_mmu helper_atomic_fetch_sminq_be_mmu_avr +#define helper_atomic_fetch_uminq_be_mmu helper_atomic_fetch_uminq_be_mmu_avr +#define helper_atomic_fetch_smaxq_be_mmu helper_atomic_fetch_smaxq_be_mmu_avr +#define helper_atomic_fetch_umaxq_be_mmu helper_atomic_fetch_umaxq_be_mmu_avr +#define helper_atomic_smin_fetchq_be_mmu helper_atomic_smin_fetchq_be_mmu_avr +#define helper_atomic_umin_fetchq_be_mmu helper_atomic_umin_fetchq_be_mmu_avr +#define helper_atomic_smax_fetchq_be_mmu helper_atomic_smax_fetchq_be_mmu_avr +#define helper_atomic_umax_fetchq_be_mmu helper_atomic_umax_fetchq_be_mmu_avr +#define helper_atomic_fetch_addq_be_mmu helper_atomic_fetch_addq_be_mmu_avr +#define helper_atomic_add_fetchq_be_mmu helper_atomic_add_fetchq_be_mmu_avr +#define helper_atomic_cmpxchgb helper_atomic_cmpxchgb_avr +#define helper_atomic_xchgb helper_atomic_xchgb_avr +#define helper_atomic_fetch_addb helper_atomic_fetch_addb_avr +#define helper_atomic_fetch_andb helper_atomic_fetch_andb_avr +#define helper_atomic_fetch_orb helper_atomic_fetch_orb_avr +#define helper_atomic_fetch_xorb helper_atomic_fetch_xorb_avr +#define helper_atomic_add_fetchb helper_atomic_add_fetchb_avr +#define helper_atomic_and_fetchb helper_atomic_and_fetchb_avr +#define helper_atomic_or_fetchb helper_atomic_or_fetchb_avr +#define helper_atomic_xor_fetchb helper_atomic_xor_fetchb_avr +#define helper_atomic_fetch_sminb helper_atomic_fetch_sminb_avr +#define helper_atomic_fetch_uminb helper_atomic_fetch_uminb_avr +#define helper_atomic_fetch_smaxb helper_atomic_fetch_smaxb_avr +#define helper_atomic_fetch_umaxb helper_atomic_fetch_umaxb_avr +#define helper_atomic_smin_fetchb helper_atomic_smin_fetchb_avr +#define helper_atomic_umin_fetchb helper_atomic_umin_fetchb_avr +#define helper_atomic_smax_fetchb helper_atomic_smax_fetchb_avr +#define helper_atomic_umax_fetchb helper_atomic_umax_fetchb_avr +#define helper_atomic_cmpxchgw_le helper_atomic_cmpxchgw_le_avr +#define helper_atomic_xchgw_le helper_atomic_xchgw_le_avr +#define helper_atomic_fetch_addw_le helper_atomic_fetch_addw_le_avr +#define helper_atomic_fetch_andw_le helper_atomic_fetch_andw_le_avr +#define helper_atomic_fetch_orw_le helper_atomic_fetch_orw_le_avr +#define helper_atomic_fetch_xorw_le helper_atomic_fetch_xorw_le_avr +#define helper_atomic_add_fetchw_le helper_atomic_add_fetchw_le_avr +#define helper_atomic_and_fetchw_le helper_atomic_and_fetchw_le_avr +#define helper_atomic_or_fetchw_le helper_atomic_or_fetchw_le_avr +#define helper_atomic_xor_fetchw_le helper_atomic_xor_fetchw_le_avr +#define helper_atomic_fetch_sminw_le helper_atomic_fetch_sminw_le_avr +#define helper_atomic_fetch_uminw_le helper_atomic_fetch_uminw_le_avr +#define helper_atomic_fetch_smaxw_le helper_atomic_fetch_smaxw_le_avr +#define helper_atomic_fetch_umaxw_le helper_atomic_fetch_umaxw_le_avr +#define helper_atomic_smin_fetchw_le helper_atomic_smin_fetchw_le_avr +#define helper_atomic_umin_fetchw_le helper_atomic_umin_fetchw_le_avr +#define helper_atomic_smax_fetchw_le helper_atomic_smax_fetchw_le_avr +#define helper_atomic_umax_fetchw_le helper_atomic_umax_fetchw_le_avr +#define helper_atomic_cmpxchgw_be helper_atomic_cmpxchgw_be_avr +#define helper_atomic_xchgw_be helper_atomic_xchgw_be_avr +#define helper_atomic_fetch_andw_be helper_atomic_fetch_andw_be_avr +#define helper_atomic_fetch_orw_be helper_atomic_fetch_orw_be_avr +#define helper_atomic_fetch_xorw_be helper_atomic_fetch_xorw_be_avr +#define helper_atomic_and_fetchw_be helper_atomic_and_fetchw_be_avr +#define helper_atomic_or_fetchw_be helper_atomic_or_fetchw_be_avr +#define helper_atomic_xor_fetchw_be helper_atomic_xor_fetchw_be_avr +#define helper_atomic_fetch_sminw_be helper_atomic_fetch_sminw_be_avr +#define helper_atomic_fetch_uminw_be helper_atomic_fetch_uminw_be_avr +#define helper_atomic_fetch_smaxw_be helper_atomic_fetch_smaxw_be_avr +#define helper_atomic_fetch_umaxw_be helper_atomic_fetch_umaxw_be_avr +#define helper_atomic_smin_fetchw_be helper_atomic_smin_fetchw_be_avr +#define helper_atomic_umin_fetchw_be helper_atomic_umin_fetchw_be_avr +#define helper_atomic_smax_fetchw_be helper_atomic_smax_fetchw_be_avr +#define helper_atomic_umax_fetchw_be helper_atomic_umax_fetchw_be_avr +#define helper_atomic_fetch_addw_be helper_atomic_fetch_addw_be_avr +#define helper_atomic_add_fetchw_be helper_atomic_add_fetchw_be_avr +#define helper_atomic_cmpxchgl_le helper_atomic_cmpxchgl_le_avr +#define helper_atomic_xchgl_le helper_atomic_xchgl_le_avr +#define helper_atomic_fetch_addl_le helper_atomic_fetch_addl_le_avr +#define helper_atomic_fetch_andl_le helper_atomic_fetch_andl_le_avr +#define helper_atomic_fetch_orl_le helper_atomic_fetch_orl_le_avr +#define helper_atomic_fetch_xorl_le helper_atomic_fetch_xorl_le_avr +#define helper_atomic_add_fetchl_le helper_atomic_add_fetchl_le_avr +#define helper_atomic_and_fetchl_le helper_atomic_and_fetchl_le_avr +#define helper_atomic_or_fetchl_le helper_atomic_or_fetchl_le_avr +#define helper_atomic_xor_fetchl_le helper_atomic_xor_fetchl_le_avr +#define helper_atomic_fetch_sminl_le helper_atomic_fetch_sminl_le_avr +#define helper_atomic_fetch_uminl_le helper_atomic_fetch_uminl_le_avr +#define helper_atomic_fetch_smaxl_le helper_atomic_fetch_smaxl_le_avr +#define helper_atomic_fetch_umaxl_le helper_atomic_fetch_umaxl_le_avr +#define helper_atomic_smin_fetchl_le helper_atomic_smin_fetchl_le_avr +#define helper_atomic_umin_fetchl_le helper_atomic_umin_fetchl_le_avr +#define helper_atomic_smax_fetchl_le helper_atomic_smax_fetchl_le_avr +#define helper_atomic_umax_fetchl_le helper_atomic_umax_fetchl_le_avr +#define helper_atomic_cmpxchgl_be helper_atomic_cmpxchgl_be_avr +#define helper_atomic_xchgl_be helper_atomic_xchgl_be_avr +#define helper_atomic_fetch_andl_be helper_atomic_fetch_andl_be_avr +#define helper_atomic_fetch_orl_be helper_atomic_fetch_orl_be_avr +#define helper_atomic_fetch_xorl_be helper_atomic_fetch_xorl_be_avr +#define helper_atomic_and_fetchl_be helper_atomic_and_fetchl_be_avr +#define helper_atomic_or_fetchl_be helper_atomic_or_fetchl_be_avr +#define helper_atomic_xor_fetchl_be helper_atomic_xor_fetchl_be_avr +#define helper_atomic_fetch_sminl_be helper_atomic_fetch_sminl_be_avr +#define helper_atomic_fetch_uminl_be helper_atomic_fetch_uminl_be_avr +#define helper_atomic_fetch_smaxl_be helper_atomic_fetch_smaxl_be_avr +#define helper_atomic_fetch_umaxl_be helper_atomic_fetch_umaxl_be_avr +#define helper_atomic_smin_fetchl_be helper_atomic_smin_fetchl_be_avr +#define helper_atomic_umin_fetchl_be helper_atomic_umin_fetchl_be_avr +#define helper_atomic_smax_fetchl_be helper_atomic_smax_fetchl_be_avr +#define helper_atomic_umax_fetchl_be helper_atomic_umax_fetchl_be_avr +#define helper_atomic_fetch_addl_be helper_atomic_fetch_addl_be_avr +#define helper_atomic_add_fetchl_be helper_atomic_add_fetchl_be_avr +#define helper_atomic_cmpxchgq_le helper_atomic_cmpxchgq_le_avr +#define helper_atomic_xchgq_le helper_atomic_xchgq_le_avr +#define helper_atomic_fetch_addq_le helper_atomic_fetch_addq_le_avr +#define helper_atomic_fetch_andq_le helper_atomic_fetch_andq_le_avr +#define helper_atomic_fetch_orq_le helper_atomic_fetch_orq_le_avr +#define helper_atomic_fetch_xorq_le helper_atomic_fetch_xorq_le_avr +#define helper_atomic_add_fetchq_le helper_atomic_add_fetchq_le_avr +#define helper_atomic_and_fetchq_le helper_atomic_and_fetchq_le_avr +#define helper_atomic_or_fetchq_le helper_atomic_or_fetchq_le_avr +#define helper_atomic_xor_fetchq_le helper_atomic_xor_fetchq_le_avr +#define helper_atomic_fetch_sminq_le helper_atomic_fetch_sminq_le_avr +#define helper_atomic_fetch_uminq_le helper_atomic_fetch_uminq_le_avr +#define helper_atomic_fetch_smaxq_le helper_atomic_fetch_smaxq_le_avr +#define helper_atomic_fetch_umaxq_le helper_atomic_fetch_umaxq_le_avr +#define helper_atomic_smin_fetchq_le helper_atomic_smin_fetchq_le_avr +#define helper_atomic_umin_fetchq_le helper_atomic_umin_fetchq_le_avr +#define helper_atomic_smax_fetchq_le helper_atomic_smax_fetchq_le_avr +#define helper_atomic_umax_fetchq_le helper_atomic_umax_fetchq_le_avr +#define helper_atomic_cmpxchgq_be helper_atomic_cmpxchgq_be_avr +#define helper_atomic_xchgq_be helper_atomic_xchgq_be_avr +#define helper_atomic_fetch_andq_be helper_atomic_fetch_andq_be_avr +#define helper_atomic_fetch_orq_be helper_atomic_fetch_orq_be_avr +#define helper_atomic_fetch_xorq_be helper_atomic_fetch_xorq_be_avr +#define helper_atomic_and_fetchq_be helper_atomic_and_fetchq_be_avr +#define helper_atomic_or_fetchq_be helper_atomic_or_fetchq_be_avr +#define helper_atomic_xor_fetchq_be helper_atomic_xor_fetchq_be_avr +#define helper_atomic_fetch_sminq_be helper_atomic_fetch_sminq_be_avr +#define helper_atomic_fetch_uminq_be helper_atomic_fetch_uminq_be_avr +#define helper_atomic_fetch_smaxq_be helper_atomic_fetch_smaxq_be_avr +#define helper_atomic_fetch_umaxq_be helper_atomic_fetch_umaxq_be_avr +#define helper_atomic_smin_fetchq_be helper_atomic_smin_fetchq_be_avr +#define helper_atomic_umin_fetchq_be helper_atomic_umin_fetchq_be_avr +#define helper_atomic_smax_fetchq_be helper_atomic_smax_fetchq_be_avr +#define helper_atomic_umax_fetchq_be helper_atomic_umax_fetchq_be_avr +#define helper_atomic_fetch_addq_be helper_atomic_fetch_addq_be_avr +#define helper_atomic_add_fetchq_be helper_atomic_add_fetchq_be_avr +#define cpu_ldub_code cpu_ldub_code_avr +#define cpu_lduw_code cpu_lduw_code_avr +#define cpu_ldl_code cpu_ldl_code_avr +#define cpu_ldq_code cpu_ldq_code_avr +#define helper_div_i32 helper_div_i32_avr +#define helper_rem_i32 helper_rem_i32_avr +#define helper_divu_i32 helper_divu_i32_avr +#define helper_remu_i32 helper_remu_i32_avr +#define helper_shl_i64 helper_shl_i64_avr +#define helper_shr_i64 helper_shr_i64_avr +#define helper_sar_i64 helper_sar_i64_avr +#define helper_div_i64 helper_div_i64_avr +#define helper_rem_i64 helper_rem_i64_avr +#define helper_divu_i64 helper_divu_i64_avr +#define helper_remu_i64 helper_remu_i64_avr +#define helper_muluh_i64 helper_muluh_i64_avr +#define helper_mulsh_i64 helper_mulsh_i64_avr +#define helper_clz_i32 helper_clz_i32_avr +#define helper_ctz_i32 helper_ctz_i32_avr +#define helper_clz_i64 helper_clz_i64_avr +#define helper_ctz_i64 helper_ctz_i64_avr +#define helper_clrsb_i32 helper_clrsb_i32_avr +#define helper_clrsb_i64 helper_clrsb_i64_avr +#define helper_ctpop_i32 helper_ctpop_i32_avr +#define helper_ctpop_i64 helper_ctpop_i64_avr +#define helper_lookup_tb_ptr helper_lookup_tb_ptr_avr +#define helper_exit_atomic helper_exit_atomic_avr +#define helper_gvec_add8 helper_gvec_add8_avr +#define helper_gvec_add16 helper_gvec_add16_avr +#define helper_gvec_add32 helper_gvec_add32_avr +#define helper_gvec_add64 helper_gvec_add64_avr +#define helper_gvec_adds8 helper_gvec_adds8_avr +#define helper_gvec_adds16 helper_gvec_adds16_avr +#define helper_gvec_adds32 helper_gvec_adds32_avr +#define helper_gvec_adds64 helper_gvec_adds64_avr +#define helper_gvec_sub8 helper_gvec_sub8_avr +#define helper_gvec_sub16 helper_gvec_sub16_avr +#define helper_gvec_sub32 helper_gvec_sub32_avr +#define helper_gvec_sub64 helper_gvec_sub64_avr +#define helper_gvec_subs8 helper_gvec_subs8_avr +#define helper_gvec_subs16 helper_gvec_subs16_avr +#define helper_gvec_subs32 helper_gvec_subs32_avr +#define helper_gvec_subs64 helper_gvec_subs64_avr +#define helper_gvec_mul8 helper_gvec_mul8_avr +#define helper_gvec_mul16 helper_gvec_mul16_avr +#define helper_gvec_mul32 helper_gvec_mul32_avr +#define helper_gvec_mul64 helper_gvec_mul64_avr +#define helper_gvec_muls8 helper_gvec_muls8_avr +#define helper_gvec_muls16 helper_gvec_muls16_avr +#define helper_gvec_muls32 helper_gvec_muls32_avr +#define helper_gvec_muls64 helper_gvec_muls64_avr +#define helper_gvec_neg8 helper_gvec_neg8_avr +#define helper_gvec_neg16 helper_gvec_neg16_avr +#define helper_gvec_neg32 helper_gvec_neg32_avr +#define helper_gvec_neg64 helper_gvec_neg64_avr +#define helper_gvec_abs8 helper_gvec_abs8_avr +#define helper_gvec_abs16 helper_gvec_abs16_avr +#define helper_gvec_abs32 helper_gvec_abs32_avr +#define helper_gvec_abs64 helper_gvec_abs64_avr +#define helper_gvec_mov helper_gvec_mov_avr +#define helper_gvec_dup64 helper_gvec_dup64_avr +#define helper_gvec_dup32 helper_gvec_dup32_avr +#define helper_gvec_dup16 helper_gvec_dup16_avr +#define helper_gvec_dup8 helper_gvec_dup8_avr +#define helper_gvec_not helper_gvec_not_avr +#define helper_gvec_and helper_gvec_and_avr +#define helper_gvec_or helper_gvec_or_avr +#define helper_gvec_xor helper_gvec_xor_avr +#define helper_gvec_andc helper_gvec_andc_avr +#define helper_gvec_orc helper_gvec_orc_avr +#define helper_gvec_nand helper_gvec_nand_avr +#define helper_gvec_nor helper_gvec_nor_avr +#define helper_gvec_eqv helper_gvec_eqv_avr +#define helper_gvec_ands helper_gvec_ands_avr +#define helper_gvec_xors helper_gvec_xors_avr +#define helper_gvec_ors helper_gvec_ors_avr +#define helper_gvec_shl8i helper_gvec_shl8i_avr +#define helper_gvec_shl16i helper_gvec_shl16i_avr +#define helper_gvec_shl32i helper_gvec_shl32i_avr +#define helper_gvec_shl64i helper_gvec_shl64i_avr +#define helper_gvec_shr8i helper_gvec_shr8i_avr +#define helper_gvec_shr16i helper_gvec_shr16i_avr +#define helper_gvec_shr32i helper_gvec_shr32i_avr +#define helper_gvec_shr64i helper_gvec_shr64i_avr +#define helper_gvec_sar8i helper_gvec_sar8i_avr +#define helper_gvec_sar16i helper_gvec_sar16i_avr +#define helper_gvec_sar32i helper_gvec_sar32i_avr +#define helper_gvec_sar64i helper_gvec_sar64i_avr +#define helper_gvec_shl8v helper_gvec_shl8v_avr +#define helper_gvec_shl16v helper_gvec_shl16v_avr +#define helper_gvec_shl32v helper_gvec_shl32v_avr +#define helper_gvec_shl64v helper_gvec_shl64v_avr +#define helper_gvec_shr8v helper_gvec_shr8v_avr +#define helper_gvec_shr16v helper_gvec_shr16v_avr +#define helper_gvec_shr32v helper_gvec_shr32v_avr +#define helper_gvec_shr64v helper_gvec_shr64v_avr +#define helper_gvec_sar8v helper_gvec_sar8v_avr +#define helper_gvec_sar16v helper_gvec_sar16v_avr +#define helper_gvec_sar32v helper_gvec_sar32v_avr +#define helper_gvec_sar64v helper_gvec_sar64v_avr +#define helper_gvec_eq8 helper_gvec_eq8_avr +#define helper_gvec_ne8 helper_gvec_ne8_avr +#define helper_gvec_lt8 helper_gvec_lt8_avr +#define helper_gvec_le8 helper_gvec_le8_avr +#define helper_gvec_ltu8 helper_gvec_ltu8_avr +#define helper_gvec_leu8 helper_gvec_leu8_avr +#define helper_gvec_eq16 helper_gvec_eq16_avr +#define helper_gvec_ne16 helper_gvec_ne16_avr +#define helper_gvec_lt16 helper_gvec_lt16_avr +#define helper_gvec_le16 helper_gvec_le16_avr +#define helper_gvec_ltu16 helper_gvec_ltu16_avr +#define helper_gvec_leu16 helper_gvec_leu16_avr +#define helper_gvec_eq32 helper_gvec_eq32_avr +#define helper_gvec_ne32 helper_gvec_ne32_avr +#define helper_gvec_lt32 helper_gvec_lt32_avr +#define helper_gvec_le32 helper_gvec_le32_avr +#define helper_gvec_ltu32 helper_gvec_ltu32_avr +#define helper_gvec_leu32 helper_gvec_leu32_avr +#define helper_gvec_eq64 helper_gvec_eq64_avr +#define helper_gvec_ne64 helper_gvec_ne64_avr +#define helper_gvec_lt64 helper_gvec_lt64_avr +#define helper_gvec_le64 helper_gvec_le64_avr +#define helper_gvec_ltu64 helper_gvec_ltu64_avr +#define helper_gvec_leu64 helper_gvec_leu64_avr +#define helper_gvec_ssadd8 helper_gvec_ssadd8_avr +#define helper_gvec_ssadd16 helper_gvec_ssadd16_avr +#define helper_gvec_ssadd32 helper_gvec_ssadd32_avr +#define helper_gvec_ssadd64 helper_gvec_ssadd64_avr +#define helper_gvec_sssub8 helper_gvec_sssub8_avr +#define helper_gvec_sssub16 helper_gvec_sssub16_avr +#define helper_gvec_sssub32 helper_gvec_sssub32_avr +#define helper_gvec_sssub64 helper_gvec_sssub64_avr +#define helper_gvec_usadd8 helper_gvec_usadd8_avr +#define helper_gvec_usadd16 helper_gvec_usadd16_avr +#define helper_gvec_usadd32 helper_gvec_usadd32_avr +#define helper_gvec_usadd64 helper_gvec_usadd64_avr +#define helper_gvec_ussub8 helper_gvec_ussub8_avr +#define helper_gvec_ussub16 helper_gvec_ussub16_avr +#define helper_gvec_ussub32 helper_gvec_ussub32_avr +#define helper_gvec_ussub64 helper_gvec_ussub64_avr +#define helper_gvec_smin8 helper_gvec_smin8_avr +#define helper_gvec_smin16 helper_gvec_smin16_avr +#define helper_gvec_smin32 helper_gvec_smin32_avr +#define helper_gvec_smin64 helper_gvec_smin64_avr +#define helper_gvec_smax8 helper_gvec_smax8_avr +#define helper_gvec_smax16 helper_gvec_smax16_avr +#define helper_gvec_smax32 helper_gvec_smax32_avr +#define helper_gvec_smax64 helper_gvec_smax64_avr +#define helper_gvec_umin8 helper_gvec_umin8_avr +#define helper_gvec_umin16 helper_gvec_umin16_avr +#define helper_gvec_umin32 helper_gvec_umin32_avr +#define helper_gvec_umin64 helper_gvec_umin64_avr +#define helper_gvec_umax8 helper_gvec_umax8_avr +#define helper_gvec_umax16 helper_gvec_umax16_avr +#define helper_gvec_umax32 helper_gvec_umax32_avr +#define helper_gvec_umax64 helper_gvec_umax64_avr +#define helper_gvec_bitsel helper_gvec_bitsel_avr +#define cpu_restore_state cpu_restore_state_avr +#define page_collection_lock page_collection_lock_avr +#define page_collection_unlock page_collection_unlock_avr +#define free_code_gen_buffer free_code_gen_buffer_avr +#define tcg_exec_init tcg_exec_init_avr +#define tb_cleanup tb_cleanup_avr +#define tb_flush tb_flush_avr +#define tb_phys_invalidate tb_phys_invalidate_avr +#define tb_gen_code tb_gen_code_avr +#define tb_exec_lock tb_exec_lock_avr +#define tb_exec_unlock tb_exec_unlock_avr +#define tb_invalidate_phys_page_range tb_invalidate_phys_page_range_avr +#define tb_invalidate_phys_range tb_invalidate_phys_range_avr +#define tb_invalidate_phys_page_fast tb_invalidate_phys_page_fast_avr +#define tb_check_watchpoint tb_check_watchpoint_avr +#define cpu_io_recompile cpu_io_recompile_avr +#define tb_flush_jmp_cache tb_flush_jmp_cache_avr +#define tcg_flush_softmmu_tlb tcg_flush_softmmu_tlb_avr +#define translator_loop_temp_check translator_loop_temp_check_avr +#define translator_loop translator_loop_avr +#define helper_atomic_cmpxchgo_le_mmu helper_atomic_cmpxchgo_le_mmu_avr +#define helper_atomic_cmpxchgo_be_mmu helper_atomic_cmpxchgo_be_mmu_avr +#define helper_atomic_ldo_le_mmu helper_atomic_ldo_le_mmu_avr +#define helper_atomic_ldo_be_mmu helper_atomic_ldo_be_mmu_avr +#define helper_atomic_sto_le_mmu helper_atomic_sto_le_mmu_avr +#define helper_atomic_sto_be_mmu helper_atomic_sto_be_mmu_avr +#define unassigned_mem_ops unassigned_mem_ops_avr +#define floatx80_infinity floatx80_infinity_avr +#define dup_const_func dup_const_func_avr +#define gen_helper_raise_exception gen_helper_raise_exception_avr +#define gen_helper_raise_interrupt gen_helper_raise_interrupt_avr +#define gen_helper_vfp_get_fpscr gen_helper_vfp_get_fpscr_avr +#define gen_helper_vfp_set_fpscr gen_helper_vfp_set_fpscr_avr +#define gen_helper_cpsr_read gen_helper_cpsr_read_avr +#define gen_helper_cpsr_write gen_helper_cpsr_write_avr +#define helper_sleep helper_sleep_avr +#define helper_unsupported helper_unsupported_avr +#define helper_debug helper_debug_avr +#define helper_break helper_break_avr +#define helper_inb helper_inb_avr +#define helper_outb helper_outb_avr +#define helper_fullrd helper_fullrd_avr +#define helper_fullwr helper_fullwr_avr +#define helper_wdr helper_wdr_avr +#define gen_intermediate_code gen_intermediate_code_avr +#define restore_state_to_opc restore_state_to_opc_avr + +#define reg_read reg_read_avr +#define reg_write reg_write_avr +#define uc_init uc_init_avr +#endif diff --git a/qemu/configure b/qemu/configure index 47d4a4c6ef..ffb49af863 100755 --- a/qemu/configure +++ b/qemu/configure @@ -491,6 +491,8 @@ elif check_define __aarch64__ ; then cpu="aarch64" elif check_define __tricore__ ; then cpu="tricore" +elif check_define __AVR__ ; then + cpu="avr" else cpu=$(uname -m) fi @@ -534,6 +536,10 @@ case "$cpu" in cpu="tricore" supported_cpu="yes" ;; + avr) + cpu="avr" + supported_cpu="yes" + ;; *) # This will result in either an error or falling back to TCI later ARCH=unknown @@ -859,7 +865,7 @@ 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 \ - tricore-softmmu" + tricore-softmmu avr-softmmu" if test x"$show_help" = x"yes" ; then cat << EOF @@ -2788,6 +2794,10 @@ case "$target_name" in TARGET_ARCH=tricore TARGET_BASE_ARCH=tricore ;; + avr) + TARGET_ARCH=avr + TARGET_BASE_ARCH=avr + ;; unicore32) ;; xtensa|xtensaeb) diff --git a/qemu/include/tcg/tcg.h b/qemu/include/tcg/tcg.h index c1d16b0b42..a00a31866b 100644 --- a/qemu/include/tcg/tcg.h +++ b/qemu/include/tcg/tcg.h @@ -713,7 +713,7 @@ struct TCGContext { void *tb_ret_addr; /* target/riscv/translate.c */ - TCGv cpu_gpr[32], cpu_pc; // also target/mips/translate.c + TCGv cpu_gpr[32], cpu_pc; // also target/mips/translate.c, target/avr/translate.c TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */ TCGv load_res; TCGv load_val; @@ -808,6 +808,23 @@ struct TCGContext { char s390x_cpu_reg_names[16][4]; // renamed from original cpu_reg_names[][] to avoid name clash with m68k TCGv_i64 regs[16]; + + // target/avr/translate.c + TCGv cpu_Cf; + TCGv cpu_Zf; + TCGv cpu_Nf; + TCGv cpu_Vf; + TCGv cpu_Sf; + TCGv cpu_Hf; + TCGv cpu_Tf; + TCGv cpu_If; + TCGv cpu_rampD; + TCGv cpu_rampX; + TCGv cpu_rampY; + TCGv cpu_rampZ; + TCGv cpu_eind; + TCGv cpu_sp; + TCGv cpu_skip; }; static inline size_t temp_idx(TCGContext *tcg_ctx, TCGTemp *ts) diff --git a/qemu/target/avr/cpu-param.h b/qemu/target/avr/cpu-param.h new file mode 100644 index 0000000000..7ef4e7c679 --- /dev/null +++ b/qemu/target/avr/cpu-param.h @@ -0,0 +1,36 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#ifndef AVR_CPU_PARAM_H +#define AVR_CPU_PARAM_H + +#define TARGET_LONG_BITS 32 +/* + * TARGET_PAGE_BITS cannot be more than 8 bits because + * 1. all IO registers occupy [0x0000 .. 0x00ff] address range, and they + * should be implemented as a device and not memory + * 2. SRAM starts at the address 0x0100 + */ +#define TARGET_PAGE_BITS 8 +#define TARGET_PHYS_ADDR_SPACE_BITS 24 +#define TARGET_VIRT_ADDR_SPACE_BITS 24 +#define NB_MMU_MODES 2 + +#endif diff --git a/qemu/target/avr/cpu-qom.h b/qemu/target/avr/cpu-qom.h new file mode 100644 index 0000000000..9ba1ea1b37 --- /dev/null +++ b/qemu/target/avr/cpu-qom.h @@ -0,0 +1,56 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#ifndef QEMU_AVR_QOM_H +#define QEMU_AVR_QOM_H + +#include "hw/core/cpu.h" + +typedef void Object; +typedef void ObjectClass; + +typedef void DeviceState; +typedef void (*DeviceRealize)(DeviceState *ds); +typedef void (*DeviceReset)(DeviceState *ds); + +#define TYPE_AVR_CPU "avr-cpu" + +#define AVR_CPU(obj) ((AVRCPU *)obj) +#define AVR_CPU_CLASS(klass) ((AVRCPUClass *)klass) +#define AVR_CPU_GET_CLASS(obj) (&((AVRCPU *)obj)->cc) + +/** + * AVRCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * @vr: Version Register value. + * + * A AVR CPU model. + */ +typedef struct AVRCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; + DeviceReset parent_reset; +} AVRCPUClass; + + +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */ diff --git a/qemu/target/avr/cpu.c b/qemu/target/avr/cpu.c new file mode 100644 index 0000000000..c062723814 --- /dev/null +++ b/qemu/target/avr/cpu.c @@ -0,0 +1,459 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "exec/exec-all.h" +#include "cpu.h" +#include "unicorn_helper.h" + +static void avr_cpu_set_pc(CPUState *cs, vaddr value) +{ + AVRCPU *cpu = AVR_CPU(cs); + + cpu->env.pc_w = value / 2; /* internally PC points to words */ +} + +static bool avr_cpu_has_work(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + return (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_RESET)) + && cpu_interrupts_enabled(env); +} + +static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + env->pc_w = tb->pc / 2; /* internally PC points to words */ +} + +static void avr_cpu_reset(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu); + CPUAVRState *env = &cpu->env; + + if (mcc->parent_reset) + mcc->parent_reset(cs); + + env->pc_w = 0; + env->sregI = 1; + env->sregC = 0; + env->sregZ = 0; + env->sregN = 0; + env->sregV = 0; + env->sregS = 0; + env->sregH = 0; + env->sregT = 0; + + env->rampD = 0; + env->rampX = 0; + env->rampY = 0; + env->rampZ = 0; + env->eind = 0; + env->sp = 0; + + env->skip = 0; + + memset(env->r, 0, sizeof(env->r)); +} + +#if 0 +static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->mach = bfd_arch_avr; + info->print_insn = avr_print_insn; +} +#endif + +static void avr_cpu_realizefn(DeviceState *dev) +{ + CPUState *cs = CPU(dev); + AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); + + cpu_exec_realizefn(cs); + qemu_init_vcpu(cs); + cpu_reset(cs); + + if (mcc->parent_realize) + mcc->parent_realize(dev); +} + +#if 0 +static void avr_cpu_set_int(void *opaque, int irq, int level) +{ + AVRCPU *cpu = opaque; + CPUAVRState *env = &cpu->env; + CPUState *cs = CPU(cpu); + uint64_t mask = (1ull << irq); + + if (level) { + env->intsrc |= mask; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + env->intsrc &= ~mask; + if (env->intsrc == 0) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + } +} +#endif + +static void avr_cpu_initfn(Object *obj, struct uc_struct *uc) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *const env = &cpu->env; + + env->uc = uc; + cpu_set_cpustate_pointers(cpu); + +#if 0 + /* Set the number of interrupts supported by the CPU. */ + qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, + sizeof(cpu->env.intsrc) * 8); +#endif +} + +#if 0 +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + oc = object_class_by_name(cpu_model); + if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL || + object_class_is_abstract(oc)) { + oc = NULL; + } + return oc; +} +#endif + +#if 0 +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + int i; + + qemu_fprintf(f, "\n"); + qemu_fprintf(f, "PC: %06x\n", env->pc_w * 2); /* PC points to words */ + qemu_fprintf(f, "SP: %04x\n", env->sp); + qemu_fprintf(f, "rampD: %02x\n", env->rampD >> 16); + qemu_fprintf(f, "rampX: %02x\n", env->rampX >> 16); + qemu_fprintf(f, "rampY: %02x\n", env->rampY >> 16); + qemu_fprintf(f, "rampZ: %02x\n", env->rampZ >> 16); + qemu_fprintf(f, "EIND: %02x\n", env->eind >> 16); + qemu_fprintf(f, "X: %02x%02x\n", env->r[27], env->r[26]); + qemu_fprintf(f, "Y: %02x%02x\n", env->r[29], env->r[28]); + qemu_fprintf(f, "Z: %02x%02x\n", env->r[31], env->r[30]); + qemu_fprintf(f, "SREG: [ %c %c %c %c %c %c %c %c ]\n", + env->sregI ? 'I' : '-', + env->sregT ? 'T' : '-', + env->sregH ? 'H' : '-', + env->sregS ? 'S' : '-', + env->sregV ? 'V' : '-', + env->sregN ? '-' : 'N', /* Zf has negative logic */ + env->sregZ ? 'Z' : '-', + env->sregC ? 'I' : '-'); + qemu_fprintf(f, "SKIP: %02x\n", env->skip); + + qemu_fprintf(f, "\n"); + for (i = 0; i < ARRAY_SIZE(env->r); i++) { + qemu_fprintf(f, "R[%02d]: %02x ", i, env->r[i]); + + if ((i % 8) == 7) { + qemu_fprintf(f, "\n"); + } + } + qemu_fprintf(f, "\n"); +} +#endif + +static void avr_cpu_class_init(ObjectClass *oc, void *data) +{ + CPUClass *cc = CPU_CLASS(oc); + AVRCPUClass *mcc = AVR_CPU_CLASS(oc); + + mcc->parent_realize = NULL; + mcc->parent_reset = NULL; + +#if 0 + cc->class_by_name = avr_cpu_class_by_name; +#endif + + cc->reset = avr_cpu_reset; + cc->has_work = avr_cpu_has_work; + cc->do_interrupt = avr_cpu_do_interrupt; + cc->cpu_exec_interrupt = avr_cpu_exec_interrupt; +#if 0 + cc->dump_state = avr_cpu_dump_state; +#endif + cc->set_pc = avr_cpu_set_pc; +#if 0 + cc->memory_rw_debug = avr_cpu_memory_rw_debug; +#endif + cc->get_phys_page_debug = avr_cpu_get_phys_page_debug; + cc->tlb_fill = avr_cpu_tlb_fill; +#if 0 + cc->vmsd = &vms_avr_cpu; + cc->disas_set_info = avr_cpu_disas_set_info; +#endif + cc->tcg_initialize = avr_cpu_tcg_init; + cc->synchronize_from_tb = avr_cpu_synchronize_from_tb; +#if 0 + cc->gdb_read_register = avr_cpu_gdb_read_register; + cc->gdb_write_register = avr_cpu_gdb_write_register; + cc->gdb_num_core_regs = 35; + cc->gdb_core_xml_file = "avr-cpu.xml"; +#endif +} + +/* + * Setting features of AVR core type avr5 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * ata5702m322, ata5782, ata5790, ata5790n, ata5791, ata5795, ata5831, ata6613c, + * ata6614q, ata8210, ata8510, atmega16, atmega16a, atmega161, atmega162, + * atmega163, atmega164a, atmega164p, atmega164pa, atmega165, atmega165a, + * atmega165p, atmega165pa, atmega168, atmega168a, atmega168p, atmega168pa, + * atmega168pb, atmega169, atmega169a, atmega169p, atmega169pa, atmega16hvb, + * atmega16hvbrevb, atmega16m1, atmega16u4, atmega32a, atmega32, atmega323, + * atmega324a, atmega324p, atmega324pa, atmega325, atmega325a, atmega325p, + * atmega325pa, atmega3250, atmega3250a, atmega3250p, atmega3250pa, atmega328, + * atmega328p, atmega328pb, atmega329, atmega329a, atmega329p, atmega329pa, + * atmega3290, atmega3290a, atmega3290p, atmega3290pa, atmega32c1, atmega32m1, + * atmega32u4, atmega32u6, atmega406, atmega64, atmega64a, atmega640, atmega644, + * atmega644a, atmega644p, atmega644pa, atmega645, atmega645a, atmega645p, + * atmega6450, atmega6450a, atmega6450p, atmega649, atmega649a, atmega649p, + * atmega6490, atmega16hva, atmega16hva2, atmega32hvb, atmega6490a, atmega6490p, + * atmega64c1, atmega64m1, atmega64hve, atmega64hve2, atmega64rfr2, + * atmega644rfr2, atmega32hvbrevb, at90can32, at90can64, at90pwm161, at90pwm216, + * at90pwm316, at90scr100, at90usb646, at90usb647, at94k, m3000 + */ +static void avr_avr5_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_2_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +/* + * Setting features of AVR core type avr51 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * atmega128, atmega128a, atmega1280, atmega1281, atmega1284, atmega1284p, + * atmega128rfa1, atmega128rfr2, atmega1284rfr2, at90can128, at90usb1286, + * at90usb1287 + */ +static void avr_avr51_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_2_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_RAMPZ); + set_avr_feature(env, AVR_FEATURE_ELPMX); + set_avr_feature(env, AVR_FEATURE_ELPM); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +/* + * Setting features of AVR core type avr6 + * -------------------------------------- + * + * This type of AVR core is present in the following AVR MCUs: + * + * atmega2560, atmega2561, atmega256rfr2, atmega2564rfr2 + */ +static void avr_avr6_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + CPUAVRState *env = &cpu->env; + + set_avr_feature(env, AVR_FEATURE_LPM); + set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); + set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); + set_avr_feature(env, AVR_FEATURE_SRAM); + set_avr_feature(env, AVR_FEATURE_BREAK); + + set_avr_feature(env, AVR_FEATURE_3_BYTE_PC); + set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); + set_avr_feature(env, AVR_FEATURE_RAMPZ); + set_avr_feature(env, AVR_FEATURE_EIJMP_EICALL); + set_avr_feature(env, AVR_FEATURE_ELPMX); + set_avr_feature(env, AVR_FEATURE_ELPM); + set_avr_feature(env, AVR_FEATURE_JMP_CALL); + set_avr_feature(env, AVR_FEATURE_LPMX); + set_avr_feature(env, AVR_FEATURE_MOVW); + set_avr_feature(env, AVR_FEATURE_MUL); +} + +typedef struct AVRCPUInfo { + int model; + const char *name; + void (*initfn)(Object *obj); +} AVRCPUInfo; + +static const AVRCPUInfo avr_cpu_info[] ={ + {UC_CPU_AVR_ATMEGA16, "arch:avr5", avr_avr5_initfn}, + {UC_CPU_AVR_ATMEGA16, "atmega16", avr_avr5_initfn}, + {UC_CPU_AVR_ATMEGA32, "atmega32", avr_avr5_initfn}, + {UC_CPU_AVR_ATMEGA64, "atmega64", avr_avr5_initfn}, + + {UC_CPU_AVR_ATMEGA128, "arch:avr51", avr_avr51_initfn}, + {UC_CPU_AVR_ATMEGA128, "atmega128", avr_avr51_initfn}, + {UC_CPU_AVR_ATMEGA128RFR2, "atmega128rfr2", avr_avr51_initfn}, + {UC_CPU_AVR_ATMEGA1280, "atmega1280", avr_avr51_initfn}, + + {UC_CPU_AVR_ATMEGA256, "arch:avr6", avr_avr6_initfn}, + {UC_CPU_AVR_ATMEGA256RFR2, "atmega256rfr2", avr_avr6_initfn}, + {UC_CPU_AVR_ATMEGA2560, "atmega2560", avr_avr6_initfn}, +}; + +static const AVRCPUInfo *avr_cpu_info_get(int cpu_model) +{ + for (int i = 0; i < ARRAY_SIZE(avr_cpu_info); i++) { + const AVRCPUInfo *const cip = &avr_cpu_info[i]; + if (cpu_model == cip->model) + return cip; + } + return NULL; +} + +DEFAULT_VISIBILITY +int avr_cpu_model_valid(int cpu_model) +{ + return avr_cpu_info_get(cpu_model) != NULL; +} + +#if 0 +static void avr_cpu_list_entry(gpointer data, gpointer user_data) +{ + const char *typename = object_class_get_name(OBJECT_CLASS(data)); + + qemu_printf("%s\n", typename); +} + +void avr_cpu_list(void) +{ + GSList *list; + list = object_class_get_list_sorted(TYPE_AVR_CPU, false); + g_slist_foreach(list, avr_cpu_list_entry, NULL); + g_slist_free(list); +} + +#define DEFINE_AVR_CPU_TYPE(model, initfn) \ + { \ + .parent = TYPE_AVR_CPU, \ + .instance_init = initfn, \ + .name = AVR_CPU_TYPE_NAME(model), \ + } + +static const TypeInfo avr_cpu_type_info[] = { + { + .name = TYPE_AVR_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(AVRCPU), + .instance_init = avr_cpu_initfn, + .class_size = sizeof(AVRCPUClass), + .class_init = avr_cpu_class_init, + .abstract = true, + }, + DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn), + DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn), + DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn), +}; + +DEFINE_TYPES(avr_cpu_type_info) +#endif + +AVRCPU *cpu_avr_init(struct uc_struct *uc) +{ + AVRCPU *cpu; + CPUState *cs; + CPUClass *cc; + ObjectClass *oc; + + cpu = qemu_memalign(8, sizeof(*cpu)); + if (cpu == NULL) { + return NULL; + } + memset((void *)cpu, 0, sizeof(*cpu)); + + if (uc->cpu_model == INT_MAX) + uc->cpu_model = UC_CPU_AVR_ATMEGA128; + const AVRCPUInfo *const cip = avr_cpu_info_get(uc->cpu_model); + if (!cip) { + qemu_vfree(cpu); + return NULL; + } + + cs = &cpu->parent_obj; + cc = &AVR_CPU_GET_CLASS(cpu)->parent_class; + oc = (ObjectClass *)cc; + cs->cc = cc; + cs->uc = uc; + uc->cpu = cs; + + cpu_class_init(uc, cc); + avr_cpu_class_init(oc, NULL); + + cpu_common_initfn(uc, cs); + avr_cpu_initfn(cs, uc); + cip->initfn(cs); + + avr_cpu_realizefn(cs); + + // init address space + cpu_address_space_init(cs, 0, cs->memory); + + qemu_init_vcpu(cs); + + return cpu; +} diff --git a/qemu/target/avr/cpu.h b/qemu/target/avr/cpu.h new file mode 100644 index 0000000000..f7781c7ffe --- /dev/null +++ b/qemu/target/avr/cpu.h @@ -0,0 +1,274 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#ifndef QEMU_AVR_CPU_H +#define QEMU_AVR_CPU_H + +#include "cpu-qom.h" +#include "exec/cpu-defs.h" + +#ifdef CONFIG_USER_ONLY +#error "AVR 8-bit does not support user mode" +#endif + +#define AVR_CPU_TYPE_SUFFIX "-" TYPE_AVR_CPU +#define AVR_CPU_TYPE_NAME(name) (name AVR_CPU_TYPE_SUFFIX) +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU + +#define TCG_GUEST_DEFAULT_MO 0 + +/* + * AVR has two memory spaces, data & code. + * e.g. both have 0 address + * ST/LD instructions access data space + * LPM/SPM and instruction fetching access code memory space + */ +#define MMU_CODE_IDX 0 +#define MMU_DATA_IDX 1 + +#define EXCP_RESET 1 +#define EXCP_INT(n) (EXCP_RESET + (n) + 1) + +/* Number of CPU registers */ +#define NUMBER_OF_CPU_REGISTERS 32 +/* Number of IO registers accessible by ld/st/in/out */ +#define NUMBER_OF_IO_REGISTERS 64 + +/* + * Offsets of AVR memory regions in host memory space. + * + * This is needed because the AVR has separate code and data address + * spaces that both have start from zero but have to go somewhere in + * host memory. + * + * It's also useful to know where some things are, like the IO registers. + */ +#if 1 +// Unicorn: +#define OFFSET_CODE 0x08000000 /* UC_AVR_MEM_FLASH */ +#define OFFSET_DATA 0x00000000 +#else +/* Flash program memory */ +#define OFFSET_CODE 0x00000000 +/* CPU registers, IO registers, and SRAM */ +#define OFFSET_DATA 0x00800000 +#endif +/* CPU registers specifically, these are mapped at the start of data */ +#define OFFSET_CPU_REGISTERS OFFSET_DATA +/* + * IO registers, including status register, stack pointer, and memory + * mapped peripherals, mapped just after CPU registers + */ +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NUMBER_OF_CPU_REGISTERS) + +typedef enum AVRFeature { + AVR_FEATURE_SRAM, + + AVR_FEATURE_1_BYTE_PC, + AVR_FEATURE_2_BYTE_PC, + AVR_FEATURE_3_BYTE_PC, + + AVR_FEATURE_1_BYTE_SP, + AVR_FEATURE_2_BYTE_SP, + + AVR_FEATURE_BREAK, + AVR_FEATURE_DES, + AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */ + + AVR_FEATURE_EIJMP_EICALL, + AVR_FEATURE_IJMP_ICALL, + AVR_FEATURE_JMP_CALL, + + AVR_FEATURE_ADIW_SBIW, + + AVR_FEATURE_SPM, + AVR_FEATURE_SPMX, + + AVR_FEATURE_ELPMX, + AVR_FEATURE_ELPM, + AVR_FEATURE_LPMX, + AVR_FEATURE_LPM, + + AVR_FEATURE_MOVW, + AVR_FEATURE_MUL, + AVR_FEATURE_RAMPD, + AVR_FEATURE_RAMPX, + AVR_FEATURE_RAMPY, + AVR_FEATURE_RAMPZ, + + AVR_FEATURE_FLASH, /* Unicorn: was Flash program memory mapped? */ +} AVRFeature; + +typedef struct CPUAVRState CPUAVRState; + +struct CPUAVRState { + uint32_t pc_w; /* 0x003fffff up to 22 bits */ + + uint32_t sregC; /* 0x00000001 1 bit */ + uint32_t sregZ; /* 0x00000001 1 bit */ + uint32_t sregN; /* 0x00000001 1 bit */ + uint32_t sregV; /* 0x00000001 1 bit */ + uint32_t sregS; /* 0x00000001 1 bit */ + uint32_t sregH; /* 0x00000001 1 bit */ + uint32_t sregT; /* 0x00000001 1 bit */ + uint32_t sregI; /* 0x00000001 1 bit */ + + uint32_t rampD; /* 0x00ff0000 8 bits */ + uint32_t rampX; /* 0x00ff0000 8 bits */ + uint32_t rampY; /* 0x00ff0000 8 bits */ + uint32_t rampZ; /* 0x00ff0000 8 bits */ + uint32_t eind; /* 0x00ff0000 8 bits */ + + uint32_t r[NUMBER_OF_CPU_REGISTERS]; /* 8 bits each */ + uint32_t sp; /* 16 bits */ + + uint32_t skip; /* if set skip instruction */ + + uint64_t intsrc; /* interrupt sources */ + bool fullacc; /* CPU/MEM if true MEM only otherwise */ + + uint64_t features; + + // Unicorn engine + struct uc_struct *uc; +}; + +/** + * AVRCPU: + * @env: #CPUAVRState + * + * A AVR CPU. + */ +typedef struct AVRCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUNegativeOffsetState neg; + CPUAVRState env; + + AVRCPUClass cc; +} AVRCPU; + +extern const struct VMStateDescription vms_avr_cpu; + +void avr_cpu_do_interrupt(CPUState *cpu); +bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); +hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int avr_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); +int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); + +static inline int avr_feature(CPUAVRState *env, AVRFeature feature) +{ + return (env->features & (1U << feature)) != 0; +} + +static inline void set_avr_feature(CPUAVRState *env, int feature) +{ + env->features |= (1U << feature); +} + +#define cpu_list avr_cpu_list +#define cpu_signal_handler cpu_avr_signal_handler +#define cpu_mmu_index avr_cpu_mmu_index + +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch) +{ + return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; +} + +static inline uint32_t avr_code_base(CPUAVRState *env) +{ + return OFFSET_CODE && avr_feature(env, AVR_FEATURE_FLASH) ? + OFFSET_CODE : 0; +} + +void avr_cpu_tcg_init(struct uc_struct *uc); + +void avr_cpu_list(void); +int cpu_avr_exec(CPUState *cpu); +int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc); +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf, + int len, bool is_write); + +enum { + TB_FLAGS_FULL_ACCESS = 1, + TB_FLAGS_SKIP = 2, +}; + +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + uint32_t flags = 0; + + *pc = env->pc_w * 2; + *cs_base = 0; + + if (env->fullacc) { + flags |= TB_FLAGS_FULL_ACCESS; + } + if (env->skip) { + flags |= TB_FLAGS_SKIP; + } + + *pflags = flags; +} + +static inline int cpu_interrupts_enabled(CPUAVRState *env) +{ + return env->sregI != 0; +} + +static inline uint8_t cpu_get_sreg(CPUAVRState *env) +{ + uint8_t sreg; + sreg = (env->sregC) << 0 + | (env->sregZ) << 1 + | (env->sregN) << 2 + | (env->sregV) << 3 + | (env->sregS) << 4 + | (env->sregH) << 5 + | (env->sregT) << 6 + | (env->sregI) << 7; + return sreg; +} + +static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg) +{ + env->sregC = (sreg >> 0) & 0x01; + env->sregZ = (sreg >> 1) & 0x01; + env->sregN = (sreg >> 2) & 0x01; + env->sregV = (sreg >> 3) & 0x01; + env->sregS = (sreg >> 4) & 0x01; + env->sregH = (sreg >> 5) & 0x01; + env->sregT = (sreg >> 6) & 0x01; + env->sregI = (sreg >> 7) & 0x01; +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + +typedef CPUAVRState CPUArchState; +typedef AVRCPU ArchCPU; + +#include "exec/cpu-all.h" + +#endif /* !defined (QEMU_AVR_CPU_H) */ diff --git a/qemu/target/avr/decode-insn.c.inc b/qemu/target/avr/decode-insn.c.inc new file mode 100644 index 0000000000..0e96565474 --- /dev/null +++ b/qemu/target/avr/decode-insn.c.inc @@ -0,0 +1,1097 @@ +/* This file is autogenerated by scripts/decodetree.py. */ + +typedef struct { + int bit; + int rd; +} arg_decode_insn10; + +typedef struct { + int rd; +} arg_decode_insn2; + +typedef struct { + int imm; +} arg_decode_insn3; + +typedef struct { + int bit; +} arg_decode_insn4; + +typedef struct { + int bit; + int imm; +} arg_decode_insn5; + +typedef struct { + int noarg_; +} arg_decode_insn6; + +typedef struct { + int bit; + int rr; +} arg_decode_insn7; + +typedef struct { + int bit; + int reg; +} arg_decode_insn8; + +typedef struct { + int rr; +} arg_decode_insn9; + +typedef struct { + int imm; + int rd; +} arg_rd_imm; + +typedef struct { + int rd; + int rr; +} arg_rd_rr; + +typedef arg_rd_rr arg_ADD; +static bool trans_ADD(DisasContext *ctx, arg_ADD *a); +typedef arg_rd_rr arg_ADC; +static bool trans_ADC(DisasContext *ctx, arg_ADC *a); +typedef arg_rd_imm arg_ADIW; +static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a); +typedef arg_rd_rr arg_SUB; +static bool trans_SUB(DisasContext *ctx, arg_SUB *a); +typedef arg_rd_imm arg_SUBI; +static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a); +typedef arg_rd_rr arg_SBC; +static bool trans_SBC(DisasContext *ctx, arg_SBC *a); +typedef arg_rd_imm arg_SBCI; +static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a); +typedef arg_rd_imm arg_SBIW; +static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a); +typedef arg_rd_rr arg_AND; +static bool trans_AND(DisasContext *ctx, arg_AND *a); +typedef arg_rd_imm arg_ANDI; +static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a); +typedef arg_rd_rr arg_OR; +static bool trans_OR(DisasContext *ctx, arg_OR *a); +typedef arg_rd_imm arg_ORI; +static bool trans_ORI(DisasContext *ctx, arg_ORI *a); +typedef arg_rd_rr arg_EOR; +static bool trans_EOR(DisasContext *ctx, arg_EOR *a); +typedef arg_decode_insn2 arg_COM; +static bool trans_COM(DisasContext *ctx, arg_COM *a); +typedef arg_decode_insn2 arg_NEG; +static bool trans_NEG(DisasContext *ctx, arg_NEG *a); +typedef arg_decode_insn2 arg_INC; +static bool trans_INC(DisasContext *ctx, arg_INC *a); +typedef arg_decode_insn2 arg_DEC; +static bool trans_DEC(DisasContext *ctx, arg_DEC *a); +typedef arg_rd_rr arg_MUL; +static bool trans_MUL(DisasContext *ctx, arg_MUL *a); +typedef arg_rd_rr arg_MULS; +static bool trans_MULS(DisasContext *ctx, arg_MULS *a); +typedef arg_rd_rr arg_MULSU; +static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a); +typedef arg_rd_rr arg_FMUL; +static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a); +typedef arg_rd_rr arg_FMULS; +static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a); +typedef arg_rd_rr arg_FMULSU; +static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a); +typedef arg_decode_insn3 arg_DES; +static bool trans_DES(DisasContext *ctx, arg_DES *a); +typedef arg_decode_insn3 arg_RJMP; +static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a); +typedef arg_decode_insn6 arg_IJMP; +static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a); +typedef arg_decode_insn6 arg_EIJMP; +static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a); +typedef arg_decode_insn3 arg_JMP; +static bool trans_JMP(DisasContext *ctx, arg_JMP *a); +typedef arg_decode_insn3 arg_RCALL; +static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a); +typedef arg_decode_insn6 arg_ICALL; +static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a); +typedef arg_decode_insn6 arg_EICALL; +static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a); +typedef arg_decode_insn3 arg_CALL; +static bool trans_CALL(DisasContext *ctx, arg_CALL *a); +typedef arg_decode_insn6 arg_RET; +static bool trans_RET(DisasContext *ctx, arg_RET *a); +typedef arg_decode_insn6 arg_RETI; +static bool trans_RETI(DisasContext *ctx, arg_RETI *a); +typedef arg_rd_rr arg_CPSE; +static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a); +typedef arg_rd_rr arg_CP; +static bool trans_CP(DisasContext *ctx, arg_CP *a); +typedef arg_rd_rr arg_CPC; +static bool trans_CPC(DisasContext *ctx, arg_CPC *a); +typedef arg_rd_imm arg_CPI; +static bool trans_CPI(DisasContext *ctx, arg_CPI *a); +typedef arg_decode_insn7 arg_SBRC; +static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a); +typedef arg_decode_insn7 arg_SBRS; +static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a); +typedef arg_decode_insn8 arg_SBIC; +static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a); +typedef arg_decode_insn8 arg_SBIS; +static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a); +typedef arg_decode_insn5 arg_BRBS; +static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a); +typedef arg_decode_insn5 arg_BRBC; +static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a); +typedef arg_rd_rr arg_MOV; +static bool trans_MOV(DisasContext *ctx, arg_MOV *a); +typedef arg_rd_rr arg_MOVW; +static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a); +typedef arg_rd_imm arg_LDI; +static bool trans_LDI(DisasContext *ctx, arg_LDI *a); +typedef arg_rd_imm arg_LDS; +static bool trans_LDS(DisasContext *ctx, arg_LDS *a); +typedef arg_decode_insn2 arg_LDX1; +static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a); +typedef arg_decode_insn2 arg_LDX2; +static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a); +typedef arg_decode_insn2 arg_LDX3; +static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a); +typedef arg_decode_insn2 arg_LDY2; +static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a); +typedef arg_decode_insn2 arg_LDY3; +static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a); +typedef arg_decode_insn2 arg_LDZ2; +static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a); +typedef arg_decode_insn2 arg_LDZ3; +static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a); +typedef arg_rd_imm arg_LDDY; +static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a); +typedef arg_rd_imm arg_LDDZ; +static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a); +typedef arg_rd_imm arg_STS; +static bool trans_STS(DisasContext *ctx, arg_STS *a); +typedef arg_decode_insn9 arg_STX1; +static bool trans_STX1(DisasContext *ctx, arg_STX1 *a); +typedef arg_decode_insn9 arg_STX2; +static bool trans_STX2(DisasContext *ctx, arg_STX2 *a); +typedef arg_decode_insn9 arg_STX3; +static bool trans_STX3(DisasContext *ctx, arg_STX3 *a); +typedef arg_decode_insn2 arg_STY2; +static bool trans_STY2(DisasContext *ctx, arg_STY2 *a); +typedef arg_decode_insn2 arg_STY3; +static bool trans_STY3(DisasContext *ctx, arg_STY3 *a); +typedef arg_decode_insn2 arg_STZ2; +static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a); +typedef arg_decode_insn2 arg_STZ3; +static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a); +typedef arg_rd_imm arg_STDY; +static bool trans_STDY(DisasContext *ctx, arg_STDY *a); +typedef arg_rd_imm arg_STDZ; +static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a); +typedef arg_decode_insn6 arg_LPM1; +static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a); +typedef arg_decode_insn2 arg_LPM2; +static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a); +typedef arg_decode_insn2 arg_LPMX; +static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a); +typedef arg_decode_insn6 arg_ELPM1; +static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a); +typedef arg_decode_insn2 arg_ELPM2; +static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a); +typedef arg_decode_insn2 arg_ELPMX; +static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a); +typedef arg_decode_insn6 arg_SPM; +static bool trans_SPM(DisasContext *ctx, arg_SPM *a); +typedef arg_decode_insn6 arg_SPMX; +static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a); +typedef arg_rd_imm arg_IN; +static bool trans_IN(DisasContext *ctx, arg_IN *a); +typedef arg_rd_imm arg_OUT; +static bool trans_OUT(DisasContext *ctx, arg_OUT *a); +typedef arg_decode_insn2 arg_PUSH; +static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a); +typedef arg_decode_insn2 arg_POP; +static bool trans_POP(DisasContext *ctx, arg_POP *a); +typedef arg_decode_insn2 arg_XCH; +static bool trans_XCH(DisasContext *ctx, arg_XCH *a); +typedef arg_decode_insn2 arg_LAC; +static bool trans_LAC(DisasContext *ctx, arg_LAC *a); +typedef arg_decode_insn2 arg_LAS; +static bool trans_LAS(DisasContext *ctx, arg_LAS *a); +typedef arg_decode_insn2 arg_LAT; +static bool trans_LAT(DisasContext *ctx, arg_LAT *a); +typedef arg_decode_insn2 arg_LSR; +static bool trans_LSR(DisasContext *ctx, arg_LSR *a); +typedef arg_decode_insn2 arg_ROR; +static bool trans_ROR(DisasContext *ctx, arg_ROR *a); +typedef arg_decode_insn2 arg_ASR; +static bool trans_ASR(DisasContext *ctx, arg_ASR *a); +typedef arg_decode_insn2 arg_SWAP; +static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a); +typedef arg_decode_insn8 arg_SBI; +static bool trans_SBI(DisasContext *ctx, arg_SBI *a); +typedef arg_decode_insn8 arg_CBI; +static bool trans_CBI(DisasContext *ctx, arg_CBI *a); +typedef arg_decode_insn10 arg_BST; +static bool trans_BST(DisasContext *ctx, arg_BST *a); +typedef arg_decode_insn10 arg_BLD; +static bool trans_BLD(DisasContext *ctx, arg_BLD *a); +typedef arg_decode_insn4 arg_BSET; +static bool trans_BSET(DisasContext *ctx, arg_BSET *a); +typedef arg_decode_insn4 arg_BCLR; +static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a); +typedef arg_decode_insn6 arg_BREAK; +static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a); +typedef arg_decode_insn6 arg_NOP; +static bool trans_NOP(DisasContext *ctx, arg_NOP *a); +typedef arg_decode_insn6 arg_SLEEP; +static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a); +typedef arg_decode_insn6 arg_WDR; +static bool trans_WDR(DisasContext *ctx, arg_WDR *a); + +static void decode_insn_extract_decode_insn_Fmt_10(DisasContext *ctx, arg_decode_insn6 *a, uint16_t insn) +{ +} + +static void decode_insn_extract_decode_insn_Fmt_11(DisasContext *ctx, arg_decode_insn3 *a, uint16_t insn) +{ + a->imm = append_16(ctx, deposit32(extract32(insn, 0, 1), 1, 31, extract32(insn, 4, 5))); +} + +static void decode_insn_extract_decode_insn_Fmt_12(DisasContext *ctx, arg_decode_insn7 *a, uint16_t insn) +{ + a->rr = extract32(insn, 4, 5); + a->bit = extract32(insn, 0, 3); +} + +static void decode_insn_extract_decode_insn_Fmt_13(DisasContext *ctx, arg_decode_insn8 *a, uint16_t insn) +{ + a->reg = extract32(insn, 3, 5); + a->bit = extract32(insn, 0, 3); +} + +static void decode_insn_extract_decode_insn_Fmt_17(DisasContext *ctx, arg_rd_rr *a, uint16_t insn) +{ + a->rd = to_regs_00_30_by_two(ctx, extract32(insn, 4, 4)); + a->rr = to_regs_00_30_by_two(ctx, extract32(insn, 0, 4)); +} + +static void decode_insn_extract_decode_insn_Fmt_18(DisasContext *ctx, arg_decode_insn9 *a, uint16_t insn) +{ + a->rr = extract32(insn, 4, 5); +} + +static void decode_insn_extract_decode_insn_Fmt_19(DisasContext *ctx, arg_decode_insn10 *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->bit = extract32(insn, 0, 3); +} + +static void decode_insn_extract_decode_insn_Fmt_4(DisasContext *ctx, arg_decode_insn2 *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); +} + +static void decode_insn_extract_decode_insn_Fmt_5(DisasContext *ctx, arg_rd_rr *a, uint16_t insn) +{ + a->rd = to_regs_16_31_by_one(ctx, extract32(insn, 4, 4)); + a->rr = to_regs_16_31_by_one(ctx, extract32(insn, 0, 4)); +} + +static void decode_insn_extract_decode_insn_Fmt_6(DisasContext *ctx, arg_decode_insn3 *a, uint16_t insn) +{ + a->imm = extract32(insn, 4, 4); +} + +static void decode_insn_extract_decode_insn_Fmt_9(DisasContext *ctx, arg_decode_insn3 *a, uint16_t insn) +{ + a->imm = sextract32(insn, 0, 12); +} + +static void decode_insn_extract_fmul(DisasContext *ctx, arg_rd_rr *a, uint16_t insn) +{ + a->rd = to_regs_16_23_by_one(ctx, extract32(insn, 4, 3)); + a->rr = to_regs_16_23_by_one(ctx, extract32(insn, 0, 3)); +} + +static void decode_insn_extract_io_rd_imm(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->imm = deposit32(extract32(insn, 0, 4), 4, 28, extract32(insn, 9, 2)); +} + +static void decode_insn_extract_ldst_d(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->imm = deposit32(deposit32(extract32(insn, 0, 3), 3, 29, extract32(insn, 10, 2)), 5, 27, extract32(insn, 13, 1)); +} + +static void decode_insn_extract_ldst_s(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->imm = 0; +} + +static void decode_insn_extract_op_bit(DisasContext *ctx, arg_decode_insn4 *a, uint16_t insn) +{ + a->bit = extract32(insn, 4, 3); +} + +static void decode_insn_extract_op_bit_imm(DisasContext *ctx, arg_decode_insn5 *a, uint16_t insn) +{ + a->imm = sextract32(insn, 3, 7); + a->bit = extract32(insn, 0, 3); +} + +static void decode_insn_extract_op_rd_imm6(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = to_regs_24_30_by_two(ctx, extract32(insn, 4, 2)); + a->imm = deposit32(extract32(insn, 0, 4), 4, 28, extract32(insn, 6, 2)); +} + +static void decode_insn_extract_op_rd_imm8(DisasContext *ctx, arg_rd_imm *a, uint16_t insn) +{ + a->rd = to_regs_16_31_by_one(ctx, extract32(insn, 4, 4)); + a->imm = deposit32(extract32(insn, 0, 4), 4, 28, extract32(insn, 8, 4)); +} + +static void decode_insn_extract_op_rd_rr(DisasContext *ctx, arg_rd_rr *a, uint16_t insn) +{ + a->rd = extract32(insn, 4, 5); + a->rr = deposit32(extract32(insn, 0, 4), 4, 28, extract32(insn, 9, 1)); +} + +bool decode_insn(DisasContext *ctx, uint16_t insn) +{ + union { + arg_decode_insn10 f_decode_insn10; + arg_decode_insn2 f_decode_insn2; + arg_decode_insn3 f_decode_insn3; + arg_decode_insn4 f_decode_insn4; + arg_decode_insn5 f_decode_insn5; + arg_decode_insn6 f_decode_insn6; + arg_decode_insn7 f_decode_insn7; + arg_decode_insn8 f_decode_insn8; + arg_decode_insn9 f_decode_insn9; + arg_rd_imm f_rd_imm; + arg_rd_rr f_rd_rr; + } u; + + switch (insn & 0x0000d000) { + case 0x00000000: + /* 00.0.... ........ */ + switch (insn & 0x00002c00) { + case 0x00000000: + /* 000000.. ........ */ + switch ((insn >> 8) & 0x3) { + case 0x0: + /* 00000000 ........ */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch (insn & 0x000000ff) { + case 0x00000000: + /* 00000000 00000000 */ + /* insn.decode:185 */ + if (trans_NOP(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + case 0x1: + /* 00000001 ........ */ + /* insn.decode:128 */ + decode_insn_extract_decode_insn_Fmt_17(ctx, &u.f_rd_rr, insn); + if (trans_MOVW(ctx, &u.f_rd_rr)) return true; + break; + case 0x2: + /* 00000010 ........ */ + /* insn.decode:71 */ + decode_insn_extract_decode_insn_Fmt_5(ctx, &u.f_rd_rr, insn); + if (trans_MULS(ctx, &u.f_rd_rr)) return true; + break; + case 0x3: + /* 00000011 ........ */ + decode_insn_extract_fmul(ctx, &u.f_rd_rr, insn); + switch (insn & 0x00000088) { + case 0x00000000: + /* 00000011 0...0... */ + /* insn.decode:72 */ + if (trans_MULSU(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000008: + /* 00000011 0...1... */ + /* insn.decode:73 */ + if (trans_FMUL(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000080: + /* 00000011 1...0... */ + /* insn.decode:74 */ + if (trans_FMULS(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000088: + /* 00000011 1...1... */ + /* insn.decode:75 */ + if (trans_FMULSU(ctx, &u.f_rd_rr)) return true; + break; + } + break; + } + break; + case 0x00000400: + /* 000001.. ........ */ + /* insn.decode:102 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_CPC(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000800: + /* 000010.. ........ */ + /* insn.decode:58 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_SBC(ctx, &u.f_rd_rr)) return true; + break; + case 0x00000c00: + /* 000011.. ........ */ + /* insn.decode:53 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_ADD(ctx, &u.f_rd_rr)) return true; + break; + case 0x00002000: + /* 001000.. ........ */ + /* insn.decode:61 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_AND(ctx, &u.f_rd_rr)) return true; + break; + case 0x00002400: + /* 001001.. ........ */ + /* insn.decode:65 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_EOR(ctx, &u.f_rd_rr)) return true; + break; + case 0x00002800: + /* 001010.. ........ */ + /* insn.decode:63 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_OR(ctx, &u.f_rd_rr)) return true; + break; + case 0x00002c00: + /* 001011.. ........ */ + /* insn.decode:127 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_MOV(ctx, &u.f_rd_rr)) return true; + break; + } + break; + case 0x00001000: + /* 00.1.... ........ */ + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 0001.... ........ */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + switch ((insn >> 10) & 0x3) { + case 0x0: + /* 000100.. ........ */ + /* insn.decode:100 */ + if (trans_CPSE(ctx, &u.f_rd_rr)) return true; + break; + case 0x1: + /* 000101.. ........ */ + /* insn.decode:101 */ + if (trans_CP(ctx, &u.f_rd_rr)) return true; + break; + case 0x2: + /* 000110.. ........ */ + /* insn.decode:56 */ + if (trans_SUB(ctx, &u.f_rd_rr)) return true; + break; + case 0x3: + /* 000111.. ........ */ + /* insn.decode:54 */ + if (trans_ADC(ctx, &u.f_rd_rr)) return true; + break; + } + break; + case 0x1: + /* 0011.... ........ */ + /* insn.decode:103 */ + decode_insn_extract_op_rd_imm8(ctx, &u.f_rd_imm, insn); + if (trans_CPI(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x00004000: + /* 01.0.... ........ */ + decode_insn_extract_op_rd_imm8(ctx, &u.f_rd_imm, insn); + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 0100.... ........ */ + /* insn.decode:59 */ + if (trans_SBCI(ctx, &u.f_rd_imm)) return true; + break; + case 0x1: + /* 0110.... ........ */ + /* insn.decode:64 */ + if (trans_ORI(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x00005000: + /* 01.1.... ........ */ + decode_insn_extract_op_rd_imm8(ctx, &u.f_rd_imm, insn); + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 0101.... ........ */ + /* insn.decode:57 */ + if (trans_SUBI(ctx, &u.f_rd_imm)) return true; + break; + case 0x1: + /* 0111.... ........ */ + /* insn.decode:62 */ + if (trans_ANDI(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x00008000: + /* 10.0.... ........ */ + decode_insn_extract_ldst_d(ctx, &u.f_rd_imm, insn); + switch (insn & 0x00000208) { + case 0x00000000: + /* 10.0..0. ....0... */ + /* insn.decode:139 */ + if (trans_LDDZ(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000008: + /* 10.0..0. ....1... */ + /* insn.decode:138 */ + if (trans_LDDY(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000200: + /* 10.0..1. ....0... */ + /* insn.decode:149 */ + if (trans_STDZ(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000208: + /* 10.0..1. ....1... */ + /* insn.decode:148 */ + if (trans_STDY(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x00009000: + /* 10.1.... ........ */ + switch (insn & 0x00002800) { + case 0x00000000: + /* 10010... ........ */ + switch ((insn >> 9) & 0x3) { + case 0x0: + /* 1001000. ........ */ + switch (insn & 0x0000000f) { + case 0x00000000: + /* 1001000. ....0000 */ + /* insn.decode:130 */ + decode_insn_extract_ldst_s(ctx, &u.f_rd_imm, insn); + if (trans_LDS(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000001: + /* 1001000. ....0001 */ + /* insn.decode:136 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDZ2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000002: + /* 1001000. ....0010 */ + /* insn.decode:137 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDZ3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000004: + /* 1001000. ....0100 */ + /* insn.decode:151 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LPM2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000005: + /* 1001000. ....0101 */ + /* insn.decode:152 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LPMX(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000006: + /* 1001000. ....0110 */ + /* insn.decode:154 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_ELPM2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000007: + /* 1001000. ....0111 */ + /* insn.decode:155 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_ELPMX(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000009: + /* 1001000. ....1001 */ + /* insn.decode:134 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDY2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000a: + /* 1001000. ....1010 */ + /* insn.decode:135 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDY3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000c: + /* 1001000. ....1100 */ + /* insn.decode:131 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDX1(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000d: + /* 1001000. ....1101 */ + /* insn.decode:132 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDX2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000e: + /* 1001000. ....1110 */ + /* insn.decode:133 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LDX3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000f: + /* 1001000. ....1111 */ + /* insn.decode:161 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_POP(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x1: + /* 1001001. ........ */ + switch (insn & 0x0000000f) { + case 0x00000000: + /* 1001001. ....0000 */ + /* insn.decode:140 */ + decode_insn_extract_ldst_s(ctx, &u.f_rd_imm, insn); + if (trans_STS(ctx, &u.f_rd_imm)) return true; + break; + case 0x00000001: + /* 1001001. ....0001 */ + /* insn.decode:146 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_STZ2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000002: + /* 1001001. ....0010 */ + /* insn.decode:147 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_STZ3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000004: + /* 1001001. ....0100 */ + /* insn.decode:162 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_XCH(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000005: + /* 1001001. ....0101 */ + /* insn.decode:164 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LAS(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000006: + /* 1001001. ....0110 */ + /* insn.decode:163 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LAC(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000007: + /* 1001001. ....0111 */ + /* insn.decode:165 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_LAT(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000009: + /* 1001001. ....1001 */ + /* insn.decode:144 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_STY2(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000a: + /* 1001001. ....1010 */ + /* insn.decode:145 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_STY3(ctx, &u.f_decode_insn2)) return true; + break; + case 0x0000000c: + /* 1001001. ....1100 */ + /* insn.decode:141 */ + decode_insn_extract_decode_insn_Fmt_18(ctx, &u.f_decode_insn9, insn); + if (trans_STX1(ctx, &u.f_decode_insn9)) return true; + break; + case 0x0000000d: + /* 1001001. ....1101 */ + /* insn.decode:142 */ + decode_insn_extract_decode_insn_Fmt_18(ctx, &u.f_decode_insn9, insn); + if (trans_STX2(ctx, &u.f_decode_insn9)) return true; + break; + case 0x0000000e: + /* 1001001. ....1110 */ + /* insn.decode:143 */ + decode_insn_extract_decode_insn_Fmt_18(ctx, &u.f_decode_insn9, insn); + if (trans_STX3(ctx, &u.f_decode_insn9)) return true; + break; + case 0x0000000f: + /* 1001001. ....1111 */ + /* insn.decode:160 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_PUSH(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x2: + /* 1001010. ........ */ + switch ((insn >> 1) & 0x7) { + case 0x0: + /* 1001010. ....000. */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + switch (insn & 0x00000001) { + case 0x00000000: + /* 1001010. ....0000 */ + /* insn.decode:66 */ + if (trans_COM(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000001: + /* 1001010. ....0001 */ + /* insn.decode:67 */ + if (trans_NEG(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x1: + /* 1001010. ....001. */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + switch (insn & 0x00000001) { + case 0x00000000: + /* 1001010. ....0010 */ + /* insn.decode:173 */ + if (trans_SWAP(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000001: + /* 1001010. ....0011 */ + /* insn.decode:68 */ + if (trans_INC(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x2: + /* 1001010. ....010. */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + switch (insn & 0x00000001) { + case 0x00000001: + /* 1001010. ....0101 */ + /* insn.decode:172 */ + if (trans_ASR(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x3: + /* 1001010. ....011. */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + switch (insn & 0x00000001) { + case 0x00000000: + /* 1001010. ....0110 */ + /* insn.decode:170 */ + if (trans_LSR(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000001: + /* 1001010. ....0111 */ + /* insn.decode:171 */ + if (trans_ROR(ctx, &u.f_decode_insn2)) return true; + break; + } + break; + case 0x4: + /* 1001010. ....100. */ + switch (insn & 0x00000181) { + case 0x00000000: + /* 10010100 0...1000 */ + /* insn.decode:178 */ + decode_insn_extract_op_bit(ctx, &u.f_decode_insn4, insn); + if (trans_BSET(ctx, &u.f_decode_insn4)) return true; + break; + case 0x00000001: + /* 10010100 0...1001 */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch ((insn >> 4) & 0x7) { + case 0x0: + /* 10010100 00001001 */ + /* insn.decode:91 */ + if (trans_IJMP(ctx, &u.f_decode_insn6)) return true; + break; + case 0x1: + /* 10010100 00011001 */ + /* insn.decode:92 */ + if (trans_EIJMP(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + case 0x00000080: + /* 10010100 1...1000 */ + /* insn.decode:179 */ + decode_insn_extract_op_bit(ctx, &u.f_decode_insn4, insn); + if (trans_BCLR(ctx, &u.f_decode_insn4)) return true; + break; + case 0x00000100: + /* 10010101 0...1000 */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch ((insn >> 4) & 0x7) { + case 0x0: + /* 10010101 00001000 */ + /* insn.decode:98 */ + if (trans_RET(ctx, &u.f_decode_insn6)) return true; + break; + case 0x1: + /* 10010101 00011000 */ + /* insn.decode:99 */ + if (trans_RETI(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + case 0x00000101: + /* 10010101 0...1001 */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch ((insn >> 4) & 0x7) { + case 0x0: + /* 10010101 00001001 */ + /* insn.decode:95 */ + if (trans_ICALL(ctx, &u.f_decode_insn6)) return true; + break; + case 0x1: + /* 10010101 00011001 */ + /* insn.decode:96 */ + if (trans_EICALL(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + case 0x00000180: + /* 10010101 1...1000 */ + decode_insn_extract_decode_insn_Fmt_10(ctx, &u.f_decode_insn6, insn); + switch ((insn >> 4) & 0x7) { + case 0x0: + /* 10010101 10001000 */ + /* insn.decode:186 */ + if (trans_SLEEP(ctx, &u.f_decode_insn6)) return true; + break; + case 0x1: + /* 10010101 10011000 */ + /* insn.decode:184 */ + if (trans_BREAK(ctx, &u.f_decode_insn6)) return true; + break; + case 0x2: + /* 10010101 10101000 */ + /* insn.decode:187 */ + if (trans_WDR(ctx, &u.f_decode_insn6)) return true; + break; + case 0x4: + /* 10010101 11001000 */ + /* insn.decode:150 */ + if (trans_LPM1(ctx, &u.f_decode_insn6)) return true; + break; + case 0x5: + /* 10010101 11011000 */ + /* insn.decode:153 */ + if (trans_ELPM1(ctx, &u.f_decode_insn6)) return true; + break; + case 0x6: + /* 10010101 11101000 */ + /* insn.decode:156 */ + if (trans_SPM(ctx, &u.f_decode_insn6)) return true; + break; + case 0x7: + /* 10010101 11111000 */ + /* insn.decode:157 */ + if (trans_SPMX(ctx, &u.f_decode_insn6)) return true; + break; + } + break; + } + break; + case 0x5: + /* 1001010. ....101. */ + switch (insn & 0x00000001) { + case 0x00000000: + /* 1001010. ....1010 */ + /* insn.decode:69 */ + decode_insn_extract_decode_insn_Fmt_4(ctx, &u.f_decode_insn2, insn); + if (trans_DEC(ctx, &u.f_decode_insn2)) return true; + break; + case 0x00000001: + /* 1001010. ....1011 */ + decode_insn_extract_decode_insn_Fmt_6(ctx, &u.f_decode_insn3, insn); + switch ((insn >> 8) & 0x1) { + case 0x0: + /* 10010100 ....1011 */ + /* insn.decode:76 */ + if (trans_DES(ctx, &u.f_decode_insn3)) return true; + break; + } + break; + } + break; + case 0x6: + /* 1001010. ....110. */ + /* insn.decode:93 */ + decode_insn_extract_decode_insn_Fmt_11(ctx, &u.f_decode_insn3, insn); + if (trans_JMP(ctx, &u.f_decode_insn3)) return true; + break; + case 0x7: + /* 1001010. ....111. */ + /* insn.decode:97 */ + decode_insn_extract_decode_insn_Fmt_11(ctx, &u.f_decode_insn3, insn); + if (trans_CALL(ctx, &u.f_decode_insn3)) return true; + break; + } + break; + case 0x3: + /* 1001011. ........ */ + decode_insn_extract_op_rd_imm6(ctx, &u.f_rd_imm, insn); + switch ((insn >> 8) & 0x1) { + case 0x0: + /* 10010110 ........ */ + /* insn.decode:55 */ + if (trans_ADIW(ctx, &u.f_rd_imm)) return true; + break; + case 0x1: + /* 10010111 ........ */ + /* insn.decode:60 */ + if (trans_SBIW(ctx, &u.f_rd_imm)) return true; + break; + } + break; + } + break; + case 0x00000800: + /* 10011... ........ */ + switch ((insn >> 10) & 0x1) { + case 0x0: + /* 100110.. ........ */ + decode_insn_extract_decode_insn_Fmt_13(ctx, &u.f_decode_insn8, insn); + switch ((insn >> 8) & 0x3) { + case 0x0: + /* 10011000 ........ */ + /* insn.decode:175 */ + if (trans_CBI(ctx, &u.f_decode_insn8)) return true; + break; + case 0x1: + /* 10011001 ........ */ + /* insn.decode:106 */ + if (trans_SBIC(ctx, &u.f_decode_insn8)) return true; + break; + case 0x2: + /* 10011010 ........ */ + /* insn.decode:174 */ + if (trans_SBI(ctx, &u.f_decode_insn8)) return true; + break; + case 0x3: + /* 10011011 ........ */ + /* insn.decode:107 */ + if (trans_SBIS(ctx, &u.f_decode_insn8)) return true; + break; + } + break; + case 0x1: + /* 100111.. ........ */ + /* insn.decode:70 */ + decode_insn_extract_op_rd_rr(ctx, &u.f_rd_rr, insn); + if (trans_MUL(ctx, &u.f_rd_rr)) return true; + break; + } + break; + case 0x00002000: + /* 10110... ........ */ + /* insn.decode:158 */ + decode_insn_extract_io_rd_imm(ctx, &u.f_rd_imm, insn); + if (trans_IN(ctx, &u.f_rd_imm)) return true; + break; + case 0x00002800: + /* 10111... ........ */ + /* insn.decode:159 */ + decode_insn_extract_io_rd_imm(ctx, &u.f_rd_imm, insn); + if (trans_OUT(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x0000c000: + /* 11.0.... ........ */ + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 1100.... ........ */ + /* insn.decode:90 */ + decode_insn_extract_decode_insn_Fmt_9(ctx, &u.f_decode_insn3, insn); + if (trans_RJMP(ctx, &u.f_decode_insn3)) return true; + break; + case 0x1: + /* 1110.... ........ */ + /* insn.decode:129 */ + decode_insn_extract_op_rd_imm8(ctx, &u.f_rd_imm, insn); + if (trans_LDI(ctx, &u.f_rd_imm)) return true; + break; + } + break; + case 0x0000d000: + /* 11.1.... ........ */ + switch ((insn >> 13) & 0x1) { + case 0x0: + /* 1101.... ........ */ + /* insn.decode:94 */ + decode_insn_extract_decode_insn_Fmt_9(ctx, &u.f_decode_insn3, insn); + if (trans_RCALL(ctx, &u.f_decode_insn3)) return true; + break; + case 0x1: + /* 1111.... ........ */ + switch ((insn >> 10) & 0x3) { + case 0x0: + /* 111100.. ........ */ + /* insn.decode:108 */ + decode_insn_extract_op_bit_imm(ctx, &u.f_decode_insn5, insn); + if (trans_BRBS(ctx, &u.f_decode_insn5)) return true; + break; + case 0x1: + /* 111101.. ........ */ + /* insn.decode:109 */ + decode_insn_extract_op_bit_imm(ctx, &u.f_decode_insn5, insn); + if (trans_BRBC(ctx, &u.f_decode_insn5)) return true; + break; + case 0x2: + /* 111110.. ........ */ + decode_insn_extract_decode_insn_Fmt_19(ctx, &u.f_decode_insn10, insn); + switch (insn & 0x00000208) { + case 0x00000000: + /* 1111100. ....0... */ + /* insn.decode:177 */ + if (trans_BLD(ctx, &u.f_decode_insn10)) return true; + break; + case 0x00000200: + /* 1111101. ....0... */ + /* insn.decode:176 */ + if (trans_BST(ctx, &u.f_decode_insn10)) return true; + break; + } + break; + case 0x3: + /* 111111.. ........ */ + decode_insn_extract_decode_insn_Fmt_12(ctx, &u.f_decode_insn7, insn); + switch (insn & 0x00000208) { + case 0x00000000: + /* 1111110. ....0... */ + /* insn.decode:104 */ + if (trans_SBRC(ctx, &u.f_decode_insn7)) return true; + break; + case 0x00000200: + /* 1111111. ....0... */ + /* insn.decode:105 */ + if (trans_SBRS(ctx, &u.f_decode_insn7)) return true; + break; + } + break; + } + break; + } + break; + } + return false; +} diff --git a/qemu/target/avr/gdbstub.c b/qemu/target/avr/gdbstub.c new file mode 100644 index 0000000000..c28ed67efe --- /dev/null +++ b/qemu/target/avr/gdbstub.c @@ -0,0 +1,84 @@ +/* + * QEMU AVR gdbstub + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "exec/gdbstub.h" + +int avr_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + /* R */ + if (n < 32) { + return gdb_get_reg8(mem_buf, env->r[n]); + } + + /* SREG */ + if (n == 32) { + uint8_t sreg = cpu_get_sreg(env); + + return gdb_get_reg8(mem_buf, sreg); + } + + /* SP */ + if (n == 33) { + return gdb_get_reg16(mem_buf, env->sp & 0x0000ffff); + } + + /* PC */ + if (n == 34) { + return gdb_get_reg32(mem_buf, env->pc_w * 2); + } + + return 0; +} + +int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + /* R */ + if (n < 32) { + env->r[n] = *mem_buf; + return 1; + } + + /* SREG */ + if (n == 32) { + cpu_set_sreg(env, *mem_buf); + return 1; + } + + /* SP */ + if (n == 33) { + env->sp = lduw_p(mem_buf); + return 2; + } + + /* PC */ + if (n == 34) { + env->pc_w = ldl_p(mem_buf) / 2; + return 4; + } + + return 0; +} diff --git a/qemu/target/avr/helper.c b/qemu/target/avr/helper.c new file mode 100644 index 0000000000..60d0a648eb --- /dev/null +++ b/qemu/target/avr/helper.c @@ -0,0 +1,373 @@ +/* + * QEMU AVR CPU helpers + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "unicorn_helper.h" + +bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + bool ret = false; + CPUClass *cc = CPU_GET_CLASS(cs); + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + if (interrupt_request & CPU_INTERRUPT_RESET) { + if (cpu_interrupts_enabled(env)) { + cs->exception_index = EXCP_RESET; + cc->do_interrupt(cs); + + cs->interrupt_request &= ~CPU_INTERRUPT_RESET; + + ret = true; + } + } + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu_interrupts_enabled(env) && env->intsrc != 0) { + int index = ctz32(env->intsrc); + cs->exception_index = EXCP_INT(index); + cc->do_interrupt(cs); + + env->intsrc &= env->intsrc - 1; /* clear the interrupt */ + cs->interrupt_request &= ~CPU_INTERRUPT_HARD; + + ret = true; + } + } + return ret; +} + +void avr_cpu_do_interrupt(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + uint32_t ret = env->pc_w; + int vector = 0; + int size = avr_feature(env, AVR_FEATURE_JMP_CALL) ? 2 : 1; + int base = 0; + + if (cs->exception_index == EXCP_RESET) { + vector = 0; + } else if (env->intsrc != 0) { + vector = ctz32(env->intsrc) + 1; + } + + if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + cpu_stb_data(env, env->sp--, (ret & 0xff0000) >> 16); + } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + } else { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + } + + env->pc_w = base + vector * size; + env->sregI = 0; /* clear Global Interrupt Flag */ + + cs->exception_index = -1; +} + +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, + int len, bool is_write) +{ + return cpu_memory_rw_debug(cs, addr, buf, len, is_write); +} + +hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + return addr; /* I assume 1:1 address correspondance */ +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + int prot = 0; + MemTxAttrs attrs = {0}; + uint32_t paddr; + + address &= TARGET_PAGE_MASK; + + if (mmu_idx == MMU_CODE_IDX) { + /* access to code in flash */ + paddr = avr_code_base(&AVR_CPU(cs)->env) | address; + prot = PAGE_READ | PAGE_EXEC; +#if 0 + if (paddr + TARGET_PAGE_SIZE > OFFSET_DATA) { + error_report("execution left flash memory"); + abort(); + } +#endif + } else if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* + * access to CPU registers, exit and rebuilt this TB to use full access + * incase it touches specially handled registers like SREG or SP + */ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + env->fullacc = 1; + cpu_loop_exit_restore(cs, retaddr); + } else { + /* access to memory. nothing special */ + paddr = OFFSET_DATA | address; + prot = PAGE_READ | PAGE_WRITE; + } + + tlb_set_page_with_attrs(cs, address, paddr, attrs, prot, + mmu_idx, TARGET_PAGE_SIZE); + + return true; +} + +/* + * helpers + */ + +void helper_sleep(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_HLT; + cpu_loop_exit(cs); +} + +void helper_unsupported(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + /* + * I count not find what happens on the real platform, so + * it's EXCP_DEBUG for meanwhile + */ + cs->exception_index = EXCP_DEBUG; +#if 0 + if (qemu_loglevel_mask(LOG_UNIMP)) { + qemu_log("UNSUPPORTED\n"); + cpu_dump_state(cs, stderr, 0); + } +#endif + cpu_loop_exit(cs); +} + +void helper_debug(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +void helper_break(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +void helper_wdr(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + /* WD is not implemented yet, placeholder */ + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} + +/* + * This function implements IN instruction + * + * It does the following + * a. if an IO register belongs to CPU, its value is read and returned + * b. otherwise io address is translated to mem address and physical memory + * is read. + * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation + * + */ +target_ulong helper_inb(CPUAVRState *env, uint32_t port) +{ + CPUAVRState *const cpu = env; + struct uc_struct *const uc = env->uc; + + target_ulong data = 0; + + switch (port) { + case 0x38: /* RAMPD */ + data = 0xff & (env->rampD >> 16); + break; + case 0x39: /* RAMPX */ + data = 0xff & (env->rampX >> 16); + break; + case 0x3a: /* RAMPY */ + data = 0xff & (env->rampY >> 16); + break; + case 0x3b: /* RAMPZ */ + data = 0xff & (env->rampZ >> 16); + break; + case 0x3c: /* EIND */ + data = 0xff & (env->eind >> 16); + break; + case 0x3d: /* SPL */ + data = env->sp & 0x00ff; + break; + case 0x3e: /* SPH */ + data = env->sp >> 8; + break; + case 0x3f: /* SREG */ + data = cpu_get_sreg(env); + break; + default: + /* not a special register, pass to normal memory access */ + data = address_space_ldub(&address_space_memory, + OFFSET_IO_REGISTERS + port, + MEMTXATTRS_UNSPECIFIED, NULL); + } + + return data; +} + +/* + * This function implements OUT instruction + * + * It does the following + * a. if an IO register belongs to CPU, its value is written into the register + * b. otherwise io address is translated to mem address and physical memory + * is written. + * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation + * + */ +void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) +{ + CPUAVRState *const cpu = env; + struct uc_struct *const uc = env->uc; + + data &= 0x000000ff; + + switch (port) { + case 0x38: /* RAMPD */ + if (avr_feature(env, AVR_FEATURE_RAMPD)) { + env->rampD = (data & 0xff) << 16; + } + break; + case 0x39: /* RAMPX */ + if (avr_feature(env, AVR_FEATURE_RAMPX)) { + env->rampX = (data & 0xff) << 16; + } + break; + case 0x3a: /* RAMPY */ + if (avr_feature(env, AVR_FEATURE_RAMPY)) { + env->rampY = (data & 0xff) << 16; + } + break; + case 0x3b: /* RAMPZ */ + if (avr_feature(env, AVR_FEATURE_RAMPZ)) { + env->rampZ = (data & 0xff) << 16; + } + break; + case 0x3c: /* EIDN */ + env->eind = (data & 0xff) << 16; + break; + case 0x3d: /* SPL */ + env->sp = (env->sp & 0xff00) | (data); + break; + case 0x3e: /* SPH */ + if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { + env->sp = (env->sp & 0x00ff) | (data << 8); + } + break; + case 0x3f: /* SREG */ + cpu_set_sreg(env, data); + break; + default: + /* not a special register, pass to normal memory access */ + address_space_stb(&address_space_memory, OFFSET_IO_REGISTERS + port, + data, MEMTXATTRS_UNSPECIFIED, NULL); + } +} + +/* + * this function implements LD instruction when there is a posibility to read + * from a CPU register + */ +target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) +{ + CPUAVRState *const cpu = env; + struct uc_struct *const uc = env->uc; + + uint8_t data; + + env->fullacc = false; + + if (addr < NUMBER_OF_CPU_REGISTERS) { + /* CPU registers */ + data = env->r[addr]; + } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* IO registers */ + data = helper_inb(env, addr - NUMBER_OF_CPU_REGISTERS); + } else { + /* memory */ + data = address_space_ldub(&address_space_memory, OFFSET_DATA | addr, + MEMTXATTRS_UNSPECIFIED, NULL); + } + return data; +} + +/* + * this function implements ST instruction when there is a posibility to write + * into a CPU register + */ +void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) +{ + CPUAVRState *const cpu = env; + struct uc_struct *const uc = env->uc; + + env->fullacc = false; + + /* Following logic assumes this: */ + assert(OFFSET_CPU_REGISTERS == OFFSET_DATA); + assert(OFFSET_IO_REGISTERS == OFFSET_CPU_REGISTERS + + NUMBER_OF_CPU_REGISTERS); + + if (addr < NUMBER_OF_CPU_REGISTERS) { + /* CPU registers */ + env->r[addr] = data; + } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { + /* IO registers */ + helper_outb(env, addr - NUMBER_OF_CPU_REGISTERS, data); + } else { + /* memory */ + address_space_stb(&address_space_memory, OFFSET_DATA | addr, data, + MEMTXATTRS_UNSPECIFIED, NULL); + } +} + +void helper_uc_avr_exit(CPUAVRState *env) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_HLT; + cs->halted = 1; + cpu_loop_exit(cs); +} diff --git a/qemu/target/avr/helper.h b/qemu/target/avr/helper.h new file mode 100644 index 0000000000..06fc1d323c --- /dev/null +++ b/qemu/target/avr/helper.h @@ -0,0 +1,37 @@ +/* + * QEMU AVR CPU helpers + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +/* + Modified for Unicorn Engine by Glenn Baker , 2024 +*/ + +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_avr_exit,void, env) + +DEF_HELPER_1(wdr, void, env) +DEF_HELPER_1(debug, void, env) +DEF_HELPER_1(break, void, env) +DEF_HELPER_1(sleep, void, env) +DEF_HELPER_1(unsupported, void, env) +DEF_HELPER_3(outb, void, env, i32, i32) +DEF_HELPER_2(inb, tl, env, i32) +DEF_HELPER_3(fullwr, void, env, i32, i32) +DEF_HELPER_2(fullrd, tl, env, i32) diff --git a/qemu/target/avr/insn.decode b/qemu/target/avr/insn.decode new file mode 100644 index 0000000000..482c23ad0c --- /dev/null +++ b/qemu/target/avr/insn.decode @@ -0,0 +1,187 @@ +# +# AVR instruction decode definitions. +# +# Copyright (c) 2019-2020 Michael Rolnik +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . +# + +# +# regs_16_31_by_one = [16 .. 31] +# regs_16_23_by_one = [16 .. 23] +# regs_24_30_by_two = [24, 26, 28, 30] +# regs_00_30_by_two = [0, 2, 4, 6, 8, .. 30] + +%rd 4:5 +%rr 9:1 0:4 + +%rd_a 4:4 !function=to_regs_16_31_by_one +%rd_b 4:3 !function=to_regs_16_23_by_one +%rd_c 4:2 !function=to_regs_24_30_by_two +%rr_a 0:4 !function=to_regs_16_31_by_one +%rr_b 0:3 !function=to_regs_16_23_by_one + +%imm6 6:2 0:4 +%imm8 8:4 0:4 + +%io_imm 9:2 0:4 +%ldst_d_imm 13:1 10:2 0:3 + + +&rd_rr rd rr +&rd_imm rd imm + +@op_rd_rr .... .. . ..... .... &rd_rr rd=%rd rr=%rr +@op_rd_imm6 .... .... .. .. .... &rd_imm rd=%rd_c imm=%imm6 +@op_rd_imm8 .... .... .... .... &rd_imm rd=%rd_a imm=%imm8 +@fmul .... .... . ... . ... &rd_rr rd=%rd_b rr=%rr_b + +# +# Arithmetic Instructions +# +ADD 0000 11 . ..... .... @op_rd_rr +ADC 0001 11 . ..... .... @op_rd_rr +ADIW 1001 0110 .. .. .... @op_rd_imm6 +SUB 0001 10 . ..... .... @op_rd_rr +SUBI 0101 .... .... .... @op_rd_imm8 +SBC 0000 10 . ..... .... @op_rd_rr +SBCI 0100 .... .... .... @op_rd_imm8 +SBIW 1001 0111 .. .. .... @op_rd_imm6 +AND 0010 00 . ..... .... @op_rd_rr +ANDI 0111 .... .... .... @op_rd_imm8 +OR 0010 10 . ..... .... @op_rd_rr +ORI 0110 .... .... .... @op_rd_imm8 +EOR 0010 01 . ..... .... @op_rd_rr +COM 1001 010 rd:5 0000 +NEG 1001 010 rd:5 0001 +INC 1001 010 rd:5 0011 +DEC 1001 010 rd:5 1010 +MUL 1001 11 . ..... .... @op_rd_rr +MULS 0000 0010 .... .... &rd_rr rd=%rd_a rr=%rr_a +MULSU 0000 0011 0 ... 0 ... @fmul +FMUL 0000 0011 0 ... 1 ... @fmul +FMULS 0000 0011 1 ... 0 ... @fmul +FMULSU 0000 0011 1 ... 1 ... @fmul +DES 1001 0100 imm:4 1011 + +# +# Branch Instructions +# + +# The 22-bit immediate is partially in the opcode word, +# and partially in the next. Use append_16 to build the +# complete 22-bit value. +%imm_call 4:5 0:1 !function=append_16 + +@op_bit .... .... . bit:3 .... +@op_bit_imm .... .. imm:s7 bit:3 + +RJMP 1100 imm:s12 +IJMP 1001 0100 0000 1001 +EIJMP 1001 0100 0001 1001 +JMP 1001 010 ..... 110 . imm=%imm_call +RCALL 1101 imm:s12 +ICALL 1001 0101 0000 1001 +EICALL 1001 0101 0001 1001 +CALL 1001 010 ..... 111 . imm=%imm_call +RET 1001 0101 0000 1000 +RETI 1001 0101 0001 1000 +CPSE 0001 00 . ..... .... @op_rd_rr +CP 0001 01 . ..... .... @op_rd_rr +CPC 0000 01 . ..... .... @op_rd_rr +CPI 0011 .... .... .... @op_rd_imm8 +SBRC 1111 110 rr:5 0 bit:3 +SBRS 1111 111 rr:5 0 bit:3 +SBIC 1001 1001 reg:5 bit:3 +SBIS 1001 1011 reg:5 bit:3 +BRBS 1111 00 ....... ... @op_bit_imm +BRBC 1111 01 ....... ... @op_bit_imm + +# +# Data Transfer Instructions +# + +%rd_d 4:4 !function=to_regs_00_30_by_two +%rr_d 0:4 !function=to_regs_00_30_by_two + +@io_rd_imm .... . .. ..... .... &rd_imm rd=%rd imm=%io_imm +@ldst_d .. . . .. . rd:5 . ... &rd_imm imm=%ldst_d_imm + +# The 16-bit immediate is completely in the next word. +# Fields cannot be defined with no bits, so we cannot play +# the same trick and append to a zero-bit value. +# Defer reading the immediate until trans_{LDS,STS}. +@ldst_s .... ... rd:5 .... imm=0 + +MOV 0010 11 . ..... .... @op_rd_rr +MOVW 0000 0001 .... .... &rd_rr rd=%rd_d rr=%rr_d +LDI 1110 .... .... .... @op_rd_imm8 +LDS 1001 000 ..... 0000 @ldst_s +LDX1 1001 000 rd:5 1100 +LDX2 1001 000 rd:5 1101 +LDX3 1001 000 rd:5 1110 +LDY2 1001 000 rd:5 1001 +LDY3 1001 000 rd:5 1010 +LDZ2 1001 000 rd:5 0001 +LDZ3 1001 000 rd:5 0010 +LDDY 10 . 0 .. 0 ..... 1 ... @ldst_d +LDDZ 10 . 0 .. 0 ..... 0 ... @ldst_d +STS 1001 001 ..... 0000 @ldst_s +STX1 1001 001 rr:5 1100 +STX2 1001 001 rr:5 1101 +STX3 1001 001 rr:5 1110 +STY2 1001 001 rd:5 1001 +STY3 1001 001 rd:5 1010 +STZ2 1001 001 rd:5 0001 +STZ3 1001 001 rd:5 0010 +STDY 10 . 0 .. 1 ..... 1 ... @ldst_d +STDZ 10 . 0 .. 1 ..... 0 ... @ldst_d +LPM1 1001 0101 1100 1000 +LPM2 1001 000 rd:5 0100 +LPMX 1001 000 rd:5 0101 +ELPM1 1001 0101 1101 1000 +ELPM2 1001 000 rd:5 0110 +ELPMX 1001 000 rd:5 0111 +SPM 1001 0101 1110 1000 +SPMX 1001 0101 1111 1000 +IN 1011 0 .. ..... .... @io_rd_imm +OUT 1011 1 .. ..... .... @io_rd_imm +PUSH 1001 001 rd:5 1111 +POP 1001 000 rd:5 1111 +XCH 1001 001 rd:5 0100 +LAC 1001 001 rd:5 0110 +LAS 1001 001 rd:5 0101 +LAT 1001 001 rd:5 0111 + +# +# Bit and Bit-test Instructions +# +LSR 1001 010 rd:5 0110 +ROR 1001 010 rd:5 0111 +ASR 1001 010 rd:5 0101 +SWAP 1001 010 rd:5 0010 +SBI 1001 1010 reg:5 bit:3 +CBI 1001 1000 reg:5 bit:3 +BST 1111 101 rd:5 0 bit:3 +BLD 1111 100 rd:5 0 bit:3 +BSET 1001 0100 0 bit:3 1000 +BCLR 1001 0100 1 bit:3 1000 + +# +# MCU Control Instructions +# +BREAK 1001 0101 1001 1000 +NOP 0000 0000 0000 0000 +SLEEP 1001 0101 1000 1000 +WDR 1001 0101 1010 1000 diff --git a/qemu/target/avr/machine.c b/qemu/target/avr/machine.c new file mode 100644 index 0000000000..e315442787 --- /dev/null +++ b/qemu/target/avr/machine.c @@ -0,0 +1,119 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "migration/cpu.h" + +static int get_sreg(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + CPUAVRState *env = opaque; + uint8_t sreg; + + sreg = qemu_get_byte(f); + cpu_set_sreg(env, sreg); + return 0; +} + +static int put_sreg(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + CPUAVRState *env = opaque; + uint8_t sreg = cpu_get_sreg(env); + + qemu_put_byte(f, sreg); + return 0; +} + +static const VMStateInfo vms_sreg = { + .name = "sreg", + .get = get_sreg, + .put = put_sreg, +}; + +static int get_segment(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + uint32_t *ramp = opaque; + uint8_t temp; + + temp = qemu_get_byte(f); + *ramp = ((uint32_t)temp) << 16; + return 0; +} + +static int put_segment(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + uint32_t *ramp = opaque; + uint8_t temp = *ramp >> 16; + + qemu_put_byte(f, temp); + return 0; +} + +static const VMStateInfo vms_rampD = { + .name = "rampD", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampX = { + .name = "rampX", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampY = { + .name = "rampY", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_rampZ = { + .name = "rampZ", + .get = get_segment, + .put = put_segment, +}; +static const VMStateInfo vms_eind = { + .name = "eind", + .get = get_segment, + .put = put_segment, +}; + +const VMStateDescription vms_avr_cpu = { + .name = "cpu", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(env.pc_w, AVRCPU), + VMSTATE_UINT32(env.sp, AVRCPU), + VMSTATE_UINT32(env.skip, AVRCPU), + + VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NUMBER_OF_CPU_REGISTERS), + + VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState), + VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t), + VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t), + VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t), + VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t), + VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t), + + VMSTATE_END_OF_LIST() + } +}; diff --git a/qemu/target/avr/translate.c b/qemu/target/avr/translate.c new file mode 100644 index 0000000000..9ebc7dcf45 --- /dev/null +++ b/qemu/target/avr/translate.c @@ -0,0 +1,3270 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "tcg/tcg.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "tcg/tcg-op.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "exec/translator.h" +#include "exec/gen-icount.h" +#include "unicorn_helper.h" + +#define gen_decl(func, ...) \ + glue(gen_,func)(TCGContext *tcg_ctx, ## __VA_ARGS__) +#define gen_call(func, ...) \ + glue(gen_,func)(tcg_ctx, ## __VA_ARGS__) + +#define gen_io_end() gen_call(io_end) +#define gen_tb_start(...) gen_call(tb_start, __VA_ARGS__) +#define gen_tb_end(...) gen_call(tb_end, __VA_ARGS__) + +#define gen_helper_call(name, ...) \ + glue(gen_helper_,name)(tcg_ctx, ## __VA_ARGS__) +#define gen_helper_unsupported(...) \ + gen_helper_call(unsupported, __VA_ARGS__) + +#define gen_helper_debug(...) gen_helper_call(debug, __VA_ARGS__) +#define gen_helper_sleep(...) gen_helper_call(sleep, __VA_ARGS__) +#define gen_helper_inb(...) gen_helper_call(inb, __VA_ARGS__) +#define gen_helper_outb(...) gen_helper_call(outb, __VA_ARGS__) +#define gen_helper_fullrd(...) gen_helper_call(fullrd, __VA_ARGS__) +#define gen_helper_fullwr(...) gen_helper_call(fullwr, __VA_ARGS__) +#define gen_helper_wdr(...) gen_helper_call(wdr, __VA_ARGS__) + +/* + * Define if you want a BREAK instruction translated to a breakpoint + * Active debugging connection is assumed + * This is for + * https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests + * tests + */ +#undef BREAKPOINT_ON_BREAK + +#define cpu_pc (tcg_ctx->cpu_pc) +#define cpu_Cf (tcg_ctx->cpu_Cf) +#define cpu_Zf (tcg_ctx->cpu_ZF) +#define cpu_Nf (tcg_ctx->cpu_NF) +#define cpu_Vf (tcg_ctx->cpu_VF) +#define cpu_Sf (tcg_ctx->cpu_Sf) +#define cpu_Hf (tcg_ctx->cpu_Hf) +#define cpu_Tf (tcg_ctx->cpu_Tf) +#define cpu_If (tcg_ctx->cpu_If) +#define cpu_rampD (tcg_ctx->cpu_rampD) +#define cpu_rampX (tcg_ctx->cpu_rampX) +#define cpu_rampY (tcg_ctx->cpu_rampY) +#define cpu_rampZ (tcg_ctx->cpu_rampZ) +#define cpu_r (tcg_ctx->cpu_gpr) +#define cpu_eind (tcg_ctx->cpu_eind) +#define cpu_sp (tcg_ctx->cpu_sp) +#define cpu_skip (tcg_ctx->cpu_skip) + +static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +}; +#define REG(x) (cpu_r[x]) + +enum { + DISAS_EXIT = DISAS_TARGET_0, /* We want return to the cpu main loop. */ + DISAS_LOOKUP = DISAS_TARGET_1, /* We have a variable condition exit. */ + DISAS_CHAIN = DISAS_TARGET_2, /* We have a single condition exit. */ + DISAS_UC_EXIT = DISAS_TARGET_3, /* Unicorn: special state for exiting in the middle of tb. */ +}; + +typedef struct DisasContext DisasContext; + +/* This is the state at translation time. */ +struct DisasContext { + TranslationBlock *tb; + + CPUAVRState *env; + CPUState *cs; + + target_long npc; + uint32_t opcode; + + /* Routine used to access memory */ + int memidx; + int bstate; + int singlestep; + + /* + * some AVR instructions can make the following instruction to be skipped + * Let's name those instructions + * A - instruction that can skip the next one + * B - instruction that can be skipped. this depends on execution of A + * there are two scenarios + * 1. A and B belong to the same translation block + * 2. A is the last instruction in the translation block and B is the last + * + * following variables are used to simplify the skipping logic, they are + * used in the following manner (sketch) + * + * TCGLabel *skip_label = NULL; + * if (ctx.skip_cond != TCG_COND_NEVER) { + * skip_label = gen_new_label(); + * tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label); + * } + * + * if (free_skip_var0) { + * tcg_temp_free(skip_var0); + * free_skip_var0 = false; + * } + * + * translate(&ctx); + * + * if (skip_label) { + * gen_set_label(skip_label); + * } + */ + TCGv skip_var0; + TCGv skip_var1; + TCGCond skip_cond; + bool free_skip_var0; +}; + +void avr_cpu_tcg_init(struct uc_struct *uc) +{ + int i; + + INIT_TCG_CONTEXT_FROM_UC(uc); + INIT_CPU_ENV_FROM_TCG_CONTEXT(tcg_ctx); + +#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x) + cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc"); + cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf"); + cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf"); + cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf"); + cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf"); + cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf"); + cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf"); + cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf"); + cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If"); + cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD"); + cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX"); + cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY"); + cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ"); + cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind"); + cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp"); + cpu_skip = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip"); + + for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) { + cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), + reg_names[i]); + } +#undef AVR_REG_OFFS +} + +static int to_regs_16_31_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 16); +} + +static int to_regs_16_23_by_one(DisasContext *ctx, int indx) +{ + return 16 + (indx % 8); +} + +static int to_regs_24_30_by_two(DisasContext *ctx, int indx) +{ + return 24 + (indx % 4) * 2; +} + +static int to_regs_00_30_by_two(DisasContext *ctx, int indx) +{ + return (indx % 16) * 2; +} + +static uint16_t next_word(DisasContext *ctx) +{ + // Unicorn: + return cpu_lduw_code(ctx->env, avr_code_base(ctx->env) | (ctx->npc++ * 2)); +} + +static int append_16(DisasContext *ctx, int x) +{ + return x << 16 | next_word(ctx); +} + +static bool avr_have_feature(DisasContext *ctx, int feature) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + if (!avr_feature(ctx->env, feature)) { + gen_helper_unsupported(cpu_env); + ctx->bstate = DISAS_NORETURN; + return false; + } + return true; +} + +static bool decode_insn(DisasContext *ctx, uint16_t insn); +#include "decode-insn.c.inc" + +/* + * Arithmetic Instructions + */ + +/* + * Utility functions for updating status registers: + * + * - gen_add_CHf() + * - gen_add_Vf() + * - gen_sub_CHf() + * - gen_sub_Vf() + * - gen_NSf() + * - gen_ZNSf() + * + */ + +static void gen_decl(add_CHf, TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + TCGv t3 = tcg_temp_new_i32(); + + tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ + tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ + tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ + tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ + tcg_gen_or_tl(t1, t1, t3); + + tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ + tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ + tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_decl(add_Vf, TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + + /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */ + /* = (Rd ^ R) & ~(Rd ^ Rr) */ + tcg_gen_xor_tl(t1, Rd, R); + tcg_gen_xor_tl(t2, Rd, Rr); + tcg_gen_andc_tl(t1, t1, t2); + + tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_decl(sub_CHf, TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + TCGv t3 = tcg_temp_new_i32(); + + tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */ + tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */ + tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */ + tcg_gen_and_tl(t3, t3, R); + tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */ + + tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */ + tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */ + tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_decl(sub_Vf, TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 = tcg_temp_new_i32(); + TCGv t2 = tcg_temp_new_i32(); + + /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */ + /* = (Rd ^ R) & (Rd ^ R) */ + tcg_gen_xor_tl(t1, Rd, R); + tcg_gen_xor_tl(t2, Rd, Rr); + tcg_gen_and_tl(t1, t1, t2); + + tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + +static void gen_decl(NSf, TCGv R) +{ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +static void gen_decl(ZNSf, TCGv R) +{ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +#define gen_add_CHf(...) gen_call(add_CHf, __VA_ARGS__) +#define gen_add_Vf(...) gen_call(add_Vf, __VA_ARGS__) +#define gen_sub_CHf(...) gen_call(sub_CHf, __VA_ARGS__) +#define gen_sub_Vf(...) gen_call(sub_Vf, __VA_ARGS__) +#define gen_NSf(...) gen_call(NSf, __VA_ARGS__) +#define gen_ZNSf(...) gen_call(ZNSf, __VA_ARGS__) + +#define gen_new_label_avr() gen_call(new_label_avr) +#define gen_set_label(...) gen_call(set_label, __VA_ARGS__) + +/* + * Adds two registers without the C Flag and places the result in the + * destination register Rd. + */ +static bool trans_ADD(DisasContext *ctx, arg_ADD *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_add_CHf(R, Rd, Rr); + gen_add_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds two registers and the contents of the C Flag and places the result in + * the destination register Rd. + */ +static bool trans_ADC(DisasContext *ctx, arg_ADC *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */ + tcg_gen_add_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_add_CHf(R, Rd, Rr); + gen_add_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds an immediate value (0 - 63) to a register pair and places the result + * in the register pair. This instruction operates on the upper four register + * pairs, and is well suited for operations on the pointer registers. This + * instruction is not available in all devices. Refer to the device specific + * instruction set summary. + */ +static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + int Imm = (a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv Rd = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ + tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ + tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); + tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */ + tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */ + + /* update output registers */ + tcg_gen_andi_tl(RdL, R, 0xff); + tcg_gen_shri_tl(RdH, R, 8); + + tcg_temp_free_i32(Rd); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Subtracts two registers and places the result in the destination + * register Rd. + */ +static bool trans_SUB(DisasContext *ctx, arg_SUB *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Subtracts a register and a constant and places the result in the + * destination register Rd. This instruction is working on Register R16 to R31 + * and is very well suited for operations on the X, Y, and Z-pointers. + */ +static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = tcg_const_i32(a->imm); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * Subtracts two registers and subtracts with the C Flag and places the + * result in the destination register Rd. + */ +static bool trans_SBC(DisasContext *ctx, arg_SBC *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + + return true; +} + +/* + * SBCI -- Subtract Immediate with Carry + */ +static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = tcg_const_i32(a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * Subtracts an immediate value (0-63) from a register pair and places the + * result in the register pair. This instruction operates on the upper four + * register pairs, and is well suited for operations on the Pointer Registers. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + int Imm = (a->imm); + TCGv R = tcg_temp_new_i32(); + TCGv Rd = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ + tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_andc_tl(cpu_Cf, R, Rd); + tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */ + tcg_gen_andc_tl(cpu_Vf, Rd, R); + tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ + + /* update output registers */ + tcg_gen_andi_tl(RdL, R, 0xff); + tcg_gen_shri_tl(RdH, R, 8); + + tcg_temp_free_i32(Rd); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical AND between the contents of register Rd and register + * Rr and places the result in the destination register Rd. + */ +static bool trans_AND(DisasContext *ctx, arg_AND *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical AND between the contents of register Rd and a constant + * and places the result in the destination register Rd. + */ +static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + int Imm = (a->imm); + + tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Performs the logical OR between the contents of register Rd and register + * Rr and places the result in the destination register Rd. + */ +static bool trans_OR(DisasContext *ctx, arg_OR *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_or_tl(R, Rd, Rr); + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Performs the logical OR between the contents of register Rd and a + * constant and places the result in the destination register Rd. + */ +static bool trans_ORI(DisasContext *ctx, arg_ORI *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + int Imm = (a->imm); + + tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */ + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Performs the logical EOR between the contents of register Rd and + * register Rr and places the result in the destination register Rd. + */ +static bool trans_EOR(DisasContext *ctx, arg_EOR *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + + tcg_gen_xor_tl(Rd, Rd, Rr); + + /* update status register */ + tcg_gen_movi_tl(cpu_Vf, 0); + gen_ZNSf(Rd); + + return true; +} + +/* + * Clears the specified bits in register Rd. Performs the logical AND + * between the contents of register Rd and the complement of the constant mask + * K. The result will be placed in register Rd. + */ +static bool trans_COM(DisasContext *ctx, arg_COM *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_xori_tl(Rd, Rd, 0xff); + + /* update status register */ + tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */ + tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ + gen_ZNSf(Rd); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Replaces the contents of register Rd with its two's complement; the + * value $80 is left unchanged. + */ +static bool trans_NEG(DisasContext *ctx, arg_NEG *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_const_i32(0); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, t0, Rd); + gen_sub_Vf(R, t0, Rd); + gen_ZNSf(R); + + /* update output registers */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * Adds one -1- to the contents of register Rd and places the result in the + * destination register Rd. The C Flag in SREG is not affected by the + * operation, thus allowing the INC instruction to be used on a loop counter in + * multiple-precision computations. When operating on unsigned numbers, only + * BREQ and BRNE branches can be expected to perform consistently. When + * operating on two's complement values, all signed branches are available. + */ +static bool trans_INC(DisasContext *ctx, arg_INC *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_addi_tl(Rd, Rd, 1); + tcg_gen_andi_tl(Rd, Rd, 0xff); + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */ + gen_ZNSf(Rd); + + return true; +} + +/* + * Subtracts one -1- from the contents of register Rd and places the result + * in the destination register Rd. The C Flag in SREG is not affected by the + * operation, thus allowing the DEC instruction to be used on a loop counter in + * multiple-precision computations. When operating on unsigned values, only + * BREQ and BRNE branches can be expected to perform consistently. When + * operating on two's complement values, all signed branches are available. + */ +static bool trans_DEC(DisasContext *ctx, arg_DEC *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */ + tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */ + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */ + gen_ZNSf(Rd); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication. + */ +static bool trans_MUL(DisasContext *ctx, arg_MUL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication. + */ +static bool trans_MULS(DisasContext *ctx, arg_MULS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ + tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a + * signed and an unsigned number. + */ +static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */ + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit unsigned + * multiplication and shifts the result one bit left. + */ +static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication + * and shifts the result one bit left. + */ +static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ + tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication + * and shifts the result one bit left. + */ +static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv R0 = cpu_r[0]; + TCGv R1 = cpu_r[1]; + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* update status register */ + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + + /* update output registers */ + tcg_gen_shli_tl(R, R, 1); + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + +/* + * The module is an instruction set extension to the AVR CPU, performing + * DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in + * the CPU register file, registers R0-R7, where LSB of data is placed in LSB + * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including + * parity bits) is placed in registers R8- R15, organized in the register file + * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES + * instruction performs one round in the DES algorithm. Sixteen rounds must be + * executed in increasing order to form the correct DES ciphertext or + * plaintext. Intermediate results are stored in the register file (R0-R15) + * after each DES instruction. The instruction's operand (K) determines which + * round is executed, and the half carry flag (H) determines whether encryption + * or decryption is performed. The DES algorithm is described in + * "Specifications for the Data Encryption Standard" (Federal Information + * Processing Standards Publication 46). Intermediate results in this + * implementation differ from the standard because the initial permutation and + * the inverse initial permutation are performed each iteration. This does not + * affect the result in the final ciphertext or plaintext, but reduces + * execution time. + */ +static bool trans_DES(DisasContext *ctx, arg_DES *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_DES)) { + return true; + } + + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + + return true; +} + +/* + * Branch Instructions + */ +static void gen_jmp_ez(DisasContext *ctx) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); + tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind); + ctx->bstate = DISAS_LOOKUP; +} + +static void gen_jmp_z(DisasContext *ctx) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); + ctx->bstate = DISAS_LOOKUP; +} + +static void gen_push_ret(DisasContext *ctx, int ret) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { + + TCGv t0 = tcg_const_i32((ret & 0x0000ff)); + + tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(t0); + } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { + + TCGv t0 = tcg_const_i32((ret & 0x00ffff)); + + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(t0); + + } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { + + TCGv lo = tcg_const_i32((ret & 0x0000ff)); + TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8); + + tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 2); + tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } +} + +static void gen_pop_ret(DisasContext *ctx, TCGv ret) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB); + } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { + TCGv lo = tcg_temp_new_i32(); + TCGv hi = tcg_temp_new_i32(); + + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); + + tcg_gen_addi_tl(cpu_sp, cpu_sp, 2); + tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); + + tcg_gen_deposit_tl(ret, lo, hi, 8, 16); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } +} + +static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + TranslationBlock *tb = ctx->tb; + + if (ctx->singlestep == 0) { + tcg_gen_goto_tb(n); + tcg_gen_movi_i32(cpu_pc, dest); + tcg_gen_exit_tb(tb, n); + } else { + tcg_gen_movi_i32(cpu_pc, dest); + gen_helper_debug(cpu_env); + tcg_gen_exit_tb(NULL, 0); + } + ctx->bstate = DISAS_NORETURN; +} + +/* + * Relative jump to an address within PC - 2K +1 and PC + 2K (words). For + * AVR microcontrollers with Program memory not exceeding 4K words (8KB) this + * instruction can address the entire memory from every address location. See + * also JMP. + */ +static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a) +{ + int dst = ctx->npc + a->imm; + + gen_goto_tb(ctx, 0, dst); + + return true; +} + +/* + * Indirect jump to the address pointed to by the Z (16 bits) Pointer + * Register in the Register File. The Z-pointer Register is 16 bits wide and + * allows jump within the lowest 64K words (128KB) section of Program memory. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { + return true; + } + + gen_jmp_z(ctx); + + return true; +} + +/* + * Indirect jump to the address pointed to by the Z (16 bits) Pointer + * Register in the Register File and the EIND Register in the I/O space. This + * instruction allows for indirect jumps to the entire 4M (words) Program + * memory space. See also IJMP. This instruction is not available in all + * devices. Refer to the device specific instruction set summary. + */ +static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { + return true; + } + + gen_jmp_ez(ctx); + return true; +} + +/* + * Jump to an address within the entire 4M (words) Program memory. See also + * RJMP. This instruction is not available in all devices. Refer to the device + * specific instruction set summary.0 + */ +static bool trans_JMP(DisasContext *ctx, arg_JMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { + return true; + } + + gen_goto_tb(ctx, 0, a->imm); + + return true; +} + +/* + * Relative call to an address within PC - 2K + 1 and PC + 2K (words). The + * return address (the instruction after the RCALL) is stored onto the Stack. + * See also CALL. For AVR microcontrollers with Program memory not exceeding 4K + * words (8KB) this instruction can address the entire memory from every + * address location. The Stack Pointer uses a post-decrement scheme during + * RCALL. + */ +static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a) +{ + int ret = ctx->npc; + int dst = ctx->npc + a->imm; + + gen_push_ret(ctx, ret); + gen_goto_tb(ctx, 0, dst); + + return true; +} + +/* + * Calls to a subroutine within the entire 4M (words) Program memory. The + * return address (to the instruction after the CALL) will be stored onto the + * Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during + * CALL. This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { + return true; + } + + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_jmp_z(ctx); + + return true; +} + +/* + * Indirect call of a subroutine pointed to by the Z (16 bits) Pointer + * Register in the Register File and the EIND Register in the I/O space. This + * instruction allows for indirect calls to the entire 4M (words) Program + * memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme + * during EICALL. This instruction is not available in all devices. Refer to + * the device specific instruction set summary. + */ +static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { + return true; + } + + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_jmp_ez(ctx); + return true; +} + +/* + * Calls to a subroutine within the entire Program memory. The return + * address (to the instruction after the CALL) will be stored onto the Stack. + * (See also RCALL). The Stack Pointer uses a post-decrement scheme during + * CALL. This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_CALL(DisasContext *ctx, arg_CALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { + return true; + } + + int Imm = a->imm; + int ret = ctx->npc; + + gen_push_ret(ctx, ret); + gen_goto_tb(ctx, 0, Imm); + + return true; +} + +/* + * Returns from subroutine. The return address is loaded from the STACK. + * The Stack Pointer uses a preincrement scheme during RET. + */ +static bool trans_RET(DisasContext *ctx, arg_RET *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + gen_pop_ret(ctx, cpu_pc); + + ctx->bstate = DISAS_LOOKUP; + return true; +} + +/* + * Returns from interrupt. The return address is loaded from the STACK and + * the Global Interrupt Flag is set. Note that the Status Register is not + * automatically stored when entering an interrupt routine, and it is not + * restored when returning from an interrupt routine. This must be handled by + * the application program. The Stack Pointer uses a pre-increment scheme + * during RETI. + */ +static bool trans_RETI(DisasContext *ctx, arg_RETI *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + gen_pop_ret(ctx, cpu_pc); + tcg_gen_movi_tl(cpu_If, 1); + + /* Need to return to main loop to re-evaluate interrupts. */ + ctx->bstate = DISAS_EXIT; + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr, and + * skips the next instruction if Rd = Rr. + */ +static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = cpu_r[a->rd]; + ctx->skip_var1 = cpu_r[a->rr]; + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr. + * None of the registers are changed. All conditional branches can be used + * after this instruction. + */ +static bool trans_CP(DisasContext *ctx, arg_CP *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs a compare between two registers Rd and Rr and + * also takes into account the previous carry. None of the registers are + * changed. All conditional branches can be used after this instruction. + */ +static bool trans_CPC(DisasContext *ctx, arg_CPC *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + TCGv R = tcg_temp_new_i32(); + TCGv zero = tcg_const_i32(0); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); + + tcg_temp_free_i32(zero); + tcg_temp_free_i32(R); + + return true; +} + +/* + * This instruction performs a compare between register Rd and a constant. + * The register is not changed. All conditional branches can be used after this + * instruction. + */ +static bool trans_CPI(DisasContext *ctx, arg_CPI *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + int Imm = a->imm; + TCGv Rr = tcg_const_i32(Imm); + TCGv R = tcg_temp_new_i32(); + + tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + /* update status register */ + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + +/* + * This instruction tests a single bit in a register and skips the next + * instruction if the bit is cleared. + */ +static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rr = cpu_r[a->rr]; + + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = tcg_temp_new(); + ctx->free_skip_var0 = true; + + tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); + return true; +} + +/* + * This instruction tests a single bit in a register and skips the next + * instruction if the bit is set. + */ +static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rr = cpu_r[a->rr]; + + ctx->skip_cond = TCG_COND_NE; + ctx->skip_var0 = tcg_temp_new(); + ctx->free_skip_var0 = true; + + tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); + return true; +} + +/* + * This instruction tests a single bit in an I/O Register and skips the + * next instruction if the bit is cleared. This instruction operates on the + * lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + TCGv temp = tcg_const_i32(a->reg); + + gen_helper_inb(temp, cpu_env, temp); + tcg_gen_andi_tl(temp, temp, 1 << a->bit); + ctx->skip_cond = TCG_COND_EQ; + ctx->skip_var0 = temp; + ctx->free_skip_var0 = true; + + return true; +} + +/* + * This instruction tests a single bit in an I/O Register and skips the + * next instruction if the bit is set. This instruction operates on the lower + * 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + TCGv temp = tcg_const_i32(a->reg); + + gen_helper_inb(temp, cpu_env, temp); + tcg_gen_andi_tl(temp, temp, 1 << a->bit); + ctx->skip_cond = TCG_COND_NE; + ctx->skip_var0 = temp; + ctx->free_skip_var0 = true; + + return true; +} + +/* + * Conditional relative branch. Tests a single bit in SREG and branches + * relatively to PC if the bit is cleared. This instruction branches relatively + * to PC in either direction (PC - 63 < = destination <= PC + 64). The + * parameter k is the offset from PC and is represented in two's complement + * form. + */ +static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGLabel *not_taken = gen_new_label(); + + TCGv var; + + switch (a->bit) { + case 0x00: + var = cpu_Cf; + break; + case 0x01: + var = cpu_Zf; + break; + case 0x02: + var = cpu_Nf; + break; + case 0x03: + var = cpu_Vf; + break; + case 0x04: + var = cpu_Sf; + break; + case 0x05: + var = cpu_Hf; + break; + case 0x06: + var = cpu_Tf; + break; + case 0x07: + var = cpu_If; + break; + default: + g_assert_not_reached(); + } + + tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken); + gen_goto_tb(ctx, 0, ctx->npc + a->imm); + gen_set_label(not_taken); + + ctx->bstate = DISAS_CHAIN; + return true; +} + +/* + * Conditional relative branch. Tests a single bit in SREG and branches + * relatively to PC if the bit is set. This instruction branches relatively to + * PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k + * is the offset from PC and is represented in two's complement form. + */ +static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGLabel *not_taken = gen_new_label(); + + TCGv var; + + switch (a->bit) { + case 0x00: + var = cpu_Cf; + break; + case 0x01: + var = cpu_Zf; + break; + case 0x02: + var = cpu_Nf; + break; + case 0x03: + var = cpu_Vf; + break; + case 0x04: + var = cpu_Sf; + break; + case 0x05: + var = cpu_Hf; + break; + case 0x06: + var = cpu_Tf; + break; + case 0x07: + var = cpu_If; + break; + default: + g_assert_not_reached(); + } + + tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken); + gen_goto_tb(ctx, 0, ctx->npc + a->imm); + gen_set_label(not_taken); + + ctx->bstate = DISAS_CHAIN; + return true; +} + +/* + * Data Transfer Instructions + */ + +/* + * in the gen_set_addr & gen_get_addr functions + * H assumed to be in 0x00ff0000 format + * M assumed to be in 0x000000ff format + * L assumed to be in 0x000000ff format + */ +static void gen_decl(set_addr, TCGv addr, TCGv H, TCGv M, TCGv L) +{ + tcg_gen_andi_tl(L, addr, 0x000000ff); + + tcg_gen_andi_tl(M, addr, 0x0000ff00); + tcg_gen_shri_tl(M, M, 8); + + tcg_gen_andi_tl(H, addr, 0x00ff0000); +} + +static void gen_set_xaddr(TCGContext *tcg_ctx, TCGv addr) +{ + gen_set_addr(tcg_ctx, addr, cpu_rampX, cpu_r[27], cpu_r[26]); +} + +static void gen_set_yaddr(TCGContext *tcg_ctx, TCGv addr) +{ + gen_set_addr(tcg_ctx, addr, cpu_rampY, cpu_r[29], cpu_r[28]); +} + +static void gen_set_zaddr(TCGContext *tcg_ctx, TCGv addr) +{ + gen_set_addr(tcg_ctx, addr, cpu_rampZ, cpu_r[31], cpu_r[30]); +} + +static TCGv gen_decl(get_addr, TCGv H, TCGv M, TCGv L) +{ + TCGv addr = tcg_temp_new_i32(); + + tcg_gen_deposit_tl(addr, M, H, 8, 8); + tcg_gen_deposit_tl(addr, L, addr, 8, 16); + + return addr; +} + +static TCGv gen_get_xaddr(TCGContext *tcg_ctx) +{ + return gen_get_addr(tcg_ctx, cpu_rampX, cpu_r[27], cpu_r[26]); +} + +static TCGv gen_get_yaddr(TCGContext *tcg_ctx) +{ + return gen_get_addr(tcg_ctx, cpu_rampY, cpu_r[29], cpu_r[28]); +} + +static TCGv gen_get_zaddr(TCGContext *tcg_ctx) +{ + return gen_get_addr(tcg_ctx, cpu_rampZ, cpu_r[31], cpu_r[30]); +} + +#define gen_set_xaddr(...) gen_call(set_xaddr, __VA_ARGS__) +#define gen_set_yaddr(...) gen_call(set_yaddr, __VA_ARGS__) +#define gen_set_zaddr(...) gen_call(set_zaddr, __VA_ARGS__) +#define gen_get_xaddr() gen_call(get_xaddr) +#define gen_get_yaddr() gen_call(get_yaddr) +#define gen_get_zaddr() gen_call(get_zaddr) + +/* + * Load one byte indirect from data space to register and stores an clear + * the bits in data space specified by the register. The instruction can only + * be used towards internal SRAM. The data location is pointed to by the Z (16 + * bits) Pointer Register in the Register File. Memory access is limited to the + * current data segment of 64KB. To access another data segment in devices with + * more than 64KB data space, the RAMPZ in register in the I/O area has to be + * changed. The Z-pointer Register is left unchanged by the operation. This + * instruction is especially suited for clearing status bits stored in SRAM. + */ +static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { + gen_helper_fullwr(cpu_env, data, addr); + } else { + tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */ + } +} + +static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { + gen_helper_fullrd(data, cpu_env, addr); + } else { + tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */ + } +} + +static void gen_code_load(DisasContext *ctx, TCGv Rd, TCGv addr) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + // Unicorn: + const uint32_t code_base = avr_code_base(ctx->env); + if (code_base) { + TCGv Rc = tcg_const_i32(code_base); + tcg_gen_or_tl(addr, addr, Rc); + tcg_temp_free_i32(Rc); + } + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ +} + +/* + * This instruction makes a copy of one register into another. The source + * register Rr is left unchanged, while the destination register Rd is loaded + * with a copy of Rr. + */ +static bool trans_MOV(DisasContext *ctx, arg_MOV *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv Rr = cpu_r[a->rr]; + + tcg_gen_mov_tl(Rd, Rr); + + return true; +} + +/* + * This instruction makes a copy of one register pair into another register + * pair. The source register pair Rr+1:Rr is left unchanged, while the + * destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr. This + * instruction is not available in all devices. Refer to the device specific + * instruction set summary. + */ +static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv RdL = cpu_r[a->rd]; + TCGv RdH = cpu_r[a->rd + 1]; + TCGv RrL = cpu_r[a->rr]; + TCGv RrH = cpu_r[a->rr + 1]; + + tcg_gen_mov_tl(RdH, RrH); + tcg_gen_mov_tl(RdL, RrL); + + return true; +} + +/* + * Loads an 8 bit constant directly to register 16 to 31. + */ +static bool trans_LDI(DisasContext *ctx, arg_LDI *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + int imm = a->imm; + + tcg_gen_movi_tl(Rd, imm); + + return true; +} + +/* + * Loads one byte from the data space to a register. For parts with SRAM, + * the data space consists of the Register File, I/O memory and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the register file only. The EEPROM has a separate address space. + * A 16-bit address must be supplied. Memory access is limited to the current + * data segment of 64KB. The LDS instruction uses the RAMPD Register to access + * memory above 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPD in register in the I/O area has to be changed. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_LDS(DisasContext *ctx, arg_LDS *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_rampD; + a->imm = next_word(ctx); + + tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ + tcg_gen_shli_tl(addr, addr, 16); + tcg_gen_ori_tl(addr, addr, a->imm); + + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect from the data space to a register. For parts + * with SRAM, the data space consists of the Register File, I/O memory and + * internal SRAM (and external SRAM if applicable). For parts without SRAM, the + * data space consists of the Register File only. In some parts the Flash + * Memory has been mapped to the data space and can be read using this command. + * The EEPROM has a separate address space. The data location is pointed to by + * the X (16 bits) Pointer Register in the Register File. Memory access is + * limited to the current data segment of 64KB. To access another data segment + * in devices with more than 64KB data space, the RAMPX in register in the I/O + * area has to be changed. The X-pointer Register can either be left unchanged + * by the operation, or it can be post-incremented or predecremented. These + * features are especially suited for accessing arrays, tables, and Stack + * Pointer usage of the X-pointer Register. Note that only the low byte of the + * X-pointer is updated in devices with no more than 256 bytes data space. For + * such devices, the high byte of the pointer is not used by this instruction + * and can be used for other purposes. The RAMPX Register in the I/O area is + * updated in parts with more than 64KB data space or more than 64KB Program + * memory, and the increment/decrement is added to the entire 24-bit address on + * such devices. Not all variants of this instruction is available in all + * devices. Refer to the device specific instruction set summary. In the + * Reduced Core tinyAVR the LD instruction can be used to achieve the same + * operation as LPM since the program memory is mapped to the data memory + * space. + */ +static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_xaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect with or without displacement from the data space + * to a register. For parts with SRAM, the data space consists of the Register + * File, I/O memory and internal SRAM (and external SRAM if applicable). For + * parts without SRAM, the data space consists of the Register File only. In + * some parts the Flash Memory has been mapped to the data space and can be + * read using this command. The EEPROM has a separate address space. The data + * location is pointed to by the Y (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. The Y-pointer Register + * can either be left unchanged by the operation, or it can be post-incremented + * or predecremented. These features are especially suited for accessing + * arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that + * only the low byte of the Y-pointer is updated in devices with no more than + * 256 bytes data space. For such devices, the high byte of the pointer is not + * used by this instruction and can be used for other purposes. The RAMPY + * Register in the I/O area is updated in parts with more than 64KB data space + * or more than 64KB Program memory, and the increment/decrement/displacement + * is added to the entire 24-bit address on such devices. Not all variants of + * this instruction is available in all devices. Refer to the device specific + * instruction set summary. In the Reduced Core tinyAVR the LD instruction can + * be used to achieve the same operation as LPM since the program memory is + * mapped to the data memory space. + */ +static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte indirect with or without displacement from the data space + * to a register. For parts with SRAM, the data space consists of the Register + * File, I/O memory and internal SRAM (and external SRAM if applicable). For + * parts without SRAM, the data space consists of the Register File only. In + * some parts the Flash Memory has been mapped to the data space and can be + * read using this command. The EEPROM has a separate address space. The data + * location is pointed to by the Z (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPZ in register in the I/O area has to be changed. The Z-pointer Register + * can either be left unchanged by the operation, or it can be post-incremented + * or predecremented. These features are especially suited for Stack Pointer + * usage of the Z-pointer Register, however because the Z-pointer Register can + * be used for indirect subroutine calls, indirect jumps and table lookup, it + * is often more convenient to use the X or Y-pointer as a dedicated Stack + * Pointer. Note that only the low byte of the Z-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPZ Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the + * increment/decrement/displacement is added to the entire 24-bit address on + * such devices. Not all variants of this instruction is available in all + * devices. Refer to the device specific instruction set summary. In the + * Reduced Core tinyAVR the LD instruction can be used to achieve the same + * operation as LPM since the program memory is mapped to the data memory + * space. For using the Z-pointer for table lookup in Program memory see the + * LPM and ELPM instructions. + */ +static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_load(ctx, Rd, addr); + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte from a Register to the data space. For parts with SRAM, + * the data space consists of the Register File, I/O memory and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the Register File only. The EEPROM has a separate address space. + * A 16-bit address must be supplied. Memory access is limited to the current + * data segment of 64KB. The STS instruction uses the RAMPD Register to access + * memory above 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPD in register in the I/O area has to be changed. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_STS(DisasContext *ctx, arg_STS *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_rampD; + a->imm = next_word(ctx); + + tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ + tcg_gen_shli_tl(addr, addr, 16); + tcg_gen_ori_tl(addr, addr, a->imm); + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect from a register to data space. For parts with SRAM, + * the data space consists of the Register File, I/O memory, and internal SRAM + * (and external SRAM if applicable). For parts without SRAM, the data space + * consists of the Register File only. The EEPROM has a separate address space. + * + * The data location is pointed to by the X (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPX in register in the I/O area has to be changed. + * + * The X-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the + * X-pointer Register. Note that only the low byte of the X-pointer is updated + * in devices with no more than 256 bytes data space. For such devices, the high + * byte of the pointer is not used by this instruction and can be used for other + * purposes. The RAMPX Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement is added to the entire 24-bit address on such devices. + */ +static bool trans_STX1(DisasContext *ctx, arg_STX1 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STX2(DisasContext *ctx, arg_STX2 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STX3(DisasContext *ctx, arg_STX3 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rr]; + TCGv addr = gen_get_xaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect with or without displacement from a register to data + * space. For parts with SRAM, the data space consists of the Register File, I/O + * memory, and internal SRAM (and external SRAM if applicable). For parts + * without SRAM, the data space consists of the Register File only. The EEPROM + * has a separate address space. + * + * The data location is pointed to by the Y (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. + * + * The Y-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer + * Register. Note that only the low byte of the Y-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPY Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement / displacement is added to the entire 24-bit address on such + * devices. + */ +static bool trans_STY2(DisasContext *ctx, arg_STY2 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STY3(DisasContext *ctx, arg_STY3 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STDY(DisasContext *ctx, arg_STDY *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_yaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Stores one byte indirect with or without displacement from a register to data + * space. For parts with SRAM, the data space consists of the Register File, I/O + * memory, and internal SRAM (and external SRAM if applicable). For parts + * without SRAM, the data space consists of the Register File only. The EEPROM + * has a separate address space. + * + * The data location is pointed to by the Y (16 bits) Pointer Register in the + * Register File. Memory access is limited to the current data segment of 64KB. + * To access another data segment in devices with more than 64KB data space, the + * RAMPY in register in the I/O area has to be changed. + * + * The Y-pointer Register can either be left unchanged by the operation, or it + * can be post-incremented or pre-decremented. These features are especially + * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer + * Register. Note that only the low byte of the Y-pointer is updated in devices + * with no more than 256 bytes data space. For such devices, the high byte of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPY Register in the I/O area is updated in parts with more + * than 64KB data space or more than 64KB Program memory, and the increment / + * decrement / displacement is added to the entire 24-bit address on such + * devices. + */ +static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ + gen_data_store(ctx, Rd, addr); + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte pointed to by the Z-register into the destination + * register Rd. This instruction features a 100% space effective constant + * initialization or constant data fetch. The Program memory is organized in + * 16-bit words while the Z-pointer is a byte address. Thus, the least + * significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high + * byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of + * Program memory. The Zpointer Register can either be left unchanged by the + * operation, or it can be incremented. The incrementation does not apply to + * the RAMPZ Register. + * + * Devices with Self-Programming capability can use the LPM instruction to read + * the Fuse and Lock bit values. + */ +static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[0]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + gen_code_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + gen_code_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = tcg_temp_new_i32(); + TCGv H = cpu_r[31]; + TCGv L = cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ + tcg_gen_or_tl(addr, addr, L); + gen_code_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + tcg_gen_andi_tl(L, addr, 0xff); + tcg_gen_shri_tl(addr, addr, 8); + tcg_gen_andi_tl(H, addr, 0xff); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Loads one byte pointed to by the Z-register and the RAMPZ Register in + * the I/O space, and places this byte in the destination register Rd. This + * instruction features a 100% space effective constant initialization or + * constant data fetch. The Program memory is organized in 16-bit words while + * the Z-pointer is a byte address. Thus, the least significant bit of the + * Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This + * instruction can address the entire Program memory space. The Z-pointer + * Register can either be left unchanged by the operation, or it can be + * incremented. The incrementation applies to the entire 24-bit concatenation + * of the RAMPZ and Z-pointer Registers. + * + * Devices with Self-Programming capability can use the ELPM instruction to + * read the Fuse and Lock bit value. + */ +static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[0]; + TCGv addr = gen_get_zaddr(); + + gen_code_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + gen_code_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + + gen_code_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +/* + * SPM can be used to erase a page in the Program memory, to write a page + * in the Program memory (that is already erased), and to set Boot Loader Lock + * bits. In some devices, the Program memory can be written one word at a time, + * in other devices an entire page can be programmed simultaneously after first + * filling a temporary page buffer. In all cases, the Program memory must be + * erased one page at a time. When erasing the Program memory, the RAMPZ and + * Z-register are used as page address. When writing the Program memory, the + * RAMPZ and Z-register are used as page or word address, and the R1:R0 + * register pair is used as data(1). When setting the Boot Loader Lock bits, + * the R1:R0 register pair is used as data. Refer to the device documentation + * for detailed description of SPM usage. This instruction can address the + * entire Program memory. + * + * The SPM instruction is not available in all devices. Refer to the device + * specific instruction set summary. + * + * Note: 1. R1 determines the instruction high byte, and R0 determines the + * instruction low byte. + */ +static bool trans_SPM(DisasContext *ctx, arg_SPM *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) { + return true; + } + + return true; +} + +static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) { + return true; + } + + return true; +} + +/* + * Loads data from the I/O Space (Ports, Timers, Configuration Registers, + * etc.) into register Rd in the Register File. + */ +static bool trans_IN(DisasContext *ctx, arg_IN *a) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv port = tcg_const_i32(a->imm); + + gen_helper_inb(Rd, cpu_env, port); + + tcg_temp_free_i32(port); + + return true; +} + +/* + * Stores data from register Rr in the Register File to I/O Space (Ports, + * Timers, Configuration Registers, etc.). + */ +static bool trans_OUT(DisasContext *ctx, arg_OUT *a) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv port = tcg_const_i32(a->imm); + + gen_helper_outb(cpu_env, port, Rd); + + tcg_temp_free_i32(port); + + return true; +} + +/* + * This instruction stores the contents of register Rr on the STACK. The + * Stack Pointer is post-decremented by 1 after the PUSH. This instruction is + * not available in all devices. Refer to the device specific instruction set + * summary. + */ +static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + + gen_data_store(ctx, Rd, cpu_sp); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + return true; +} + +/* + * This instruction loads register Rd with a byte from the STACK. The Stack + * Pointer is pre-incremented by 1 before the POP. This instruction is not + * available in all devices. Refer to the device specific instruction set + * summary. + */ +static bool trans_POP(DisasContext *ctx, arg_POP *a) +{ + /* + * Using a temp to work around some strange behaviour: + * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + * gen_data_load(ctx, Rd, cpu_sp); + * seems to cause the add to happen twice. + * This doesn't happen if either the add or the load is removed. + */ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv t1 = tcg_temp_new_i32(); + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_addi_tl(t1, cpu_sp, 1); + gen_data_load(ctx, Rd, t1); + tcg_gen_mov_tl(cpu_sp, t1); + + return true; +} + +/* + * Exchanges one byte indirect between register and data space. The data + * location is pointed to by the Z (16 bits) Pointer Register in the Register + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space, the + * RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for writing/reading status bits stored in SRAM. + */ +static bool trans_XCH(DisasContext *ctx, arg_XCH *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + TCGv addr = gen_get_zaddr(); + + gen_data_load(ctx, t0, addr); + gen_data_store(ctx, Rd, addr); + tcg_gen_mov_tl(Rd, t0); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Load one byte indirect from data space to register and set bits in data + * space specified by the register. The instruction can only be used towards + * internal SRAM. The data location is pointed to by the Z (16 bits) Pointer + * Register in the Register File. Memory access is limited to the current data + * segment of 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for setting status bits stored in SRAM. + */ +static bool trans_LAS(DisasContext *ctx, arg_LAS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rr = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_or_tl(t1, t0, Rr); + tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Load one byte indirect from data space to register and stores and clear + * the bits in data space specified by the register. The instruction can + * only be used towards internal SRAM. The data location is pointed to by + * the Z (16 bits) Pointer Register in the Register File. Memory access is + * limited to the current data segment of 64KB. To access another data + * segment in devices with more than 64KB data space, the RAMPZ in register + * in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for clearing status bits stored in SRAM. + */ +static bool trans_LAC(DisasContext *ctx, arg_LAC *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rr = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */ + tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Load one byte indirect from data space to register and toggles bits in + * the data space specified by the register. The instruction can only be used + * towards SRAM. The data location is pointed to by the Z (16 bits) Pointer + * Register in the Register File. Memory access is limited to the current data + * segment of 64KB. To access another data segment in devices with more than + * 64KB data space, the RAMPZ in register in the I/O area has to be changed. + * + * The Z-pointer Register is left unchanged by the operation. This instruction + * is especially suited for changing status bits stored in SRAM. + */ +static bool trans_LAT(DisasContext *ctx, arg_LAT *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv addr = gen_get_zaddr(); + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ + tcg_gen_xor_tl(t1, t0, Rd); + tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + +/* + * Bit and Bit-test Instructions + */ +static void gen_decl(rshift_ZNVSf, TCGv R) +{ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ + tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf); + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +#define gen_rshift_ZNVSf(...) gen_call(rshift_ZNVSf, __VA_ARGS__) + +/* + * Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is + * loaded into the C Flag of the SREG. This operation effectively divides an + * unsigned value by two. The C Flag can be used to round the result. + */ +static bool trans_LSR(DisasContext *ctx, arg_LSR *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_andi_tl(cpu_Cf, Rd, 1); + tcg_gen_shri_tl(Rd, Rd, 1); + + /* update status register */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */ + tcg_gen_movi_tl(cpu_Nf, 0); + tcg_gen_mov_tl(cpu_Vf, cpu_Cf); + tcg_gen_mov_tl(cpu_Sf, cpu_Vf); + + return true; +} + +/* + * Shifts all bits in Rd one place to the right. The C Flag is shifted into + * bit 7 of Rd. Bit 0 is shifted into the C Flag. This operation, combined + * with ASR, effectively divides multi-byte signed values by two. Combined with + * LSR it effectively divides multi-byte unsigned values by two. The Carry Flag + * can be used to round the result. + */ +static bool trans_ROR(DisasContext *ctx, arg_ROR *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + + tcg_gen_shli_tl(t0, cpu_Cf, 7); + + /* update status register */ + tcg_gen_andi_tl(cpu_Cf, Rd, 1); + + /* update output register */ + tcg_gen_shri_tl(Rd, Rd, 1); + tcg_gen_or_tl(Rd, Rd, t0); + + /* update status register */ + gen_rshift_ZNVSf(Rd); + + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0 + * is loaded into the C Flag of the SREG. This operation effectively divides a + * signed value by two without changing its sign. The Carry Flag can be used to + * round the result. + */ +static bool trans_ASR(DisasContext *ctx, arg_ASR *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + + /* update status register */ + tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */ + + /* update output register */ + tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */ + tcg_gen_shri_tl(Rd, Rd, 1); + tcg_gen_or_tl(Rd, Rd, t0); + + /* update status register */ + gen_rshift_ZNVSf(Rd); + + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Swaps high and low nibbles in a register. + */ +static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv t0 = tcg_temp_new_i32(); + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_andi_tl(t0, Rd, 0x0f); + tcg_gen_shli_tl(t0, t0, 4); + tcg_gen_andi_tl(t1, Rd, 0xf0); + tcg_gen_shri_tl(t1, t1, 4); + tcg_gen_or_tl(Rd, t0, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + + return true; +} + +/* + * Sets a specified bit in an I/O Register. This instruction operates on + * the lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBI(DisasContext *ctx, arg_SBI *a) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + TCGv data = tcg_temp_new_i32(); + TCGv port = tcg_const_i32(a->reg); + + gen_helper_inb(data, cpu_env, port); + tcg_gen_ori_tl(data, data, 1 << a->bit); + gen_helper_outb(cpu_env, port, data); + + tcg_temp_free_i32(port); + tcg_temp_free_i32(data); + + return true; +} + +/* + * Clears a specified bit in an I/O Register. This instruction operates on + * the lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_CBI(DisasContext *ctx, arg_CBI *a) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + TCGv data = tcg_temp_new_i32(); + TCGv port = tcg_const_i32(a->reg); + + gen_helper_inb(data, cpu_env, port); + tcg_gen_andi_tl(data, data, ~(1 << a->bit)); + gen_helper_outb(cpu_env, port, data); + + tcg_temp_free_i32(data); + tcg_temp_free_i32(port); + + return true; +} + +/* + * Stores bit b from Rd to the T Flag in SREG (Status Register). + */ +static bool trans_BST(DisasContext *ctx, arg_BST *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + + tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit); + tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit); + + return true; +} + +/* + * Copies the T Flag in the SREG (Status Register) to bit b in register Rd. + */ +static bool trans_BLD(DisasContext *ctx, arg_BLD *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + TCGv Rd = cpu_r[a->rd]; + TCGv t1 = tcg_temp_new_i32(); + + tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */ + tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */ + tcg_gen_or_tl(Rd, Rd, t1); + + tcg_temp_free_i32(t1); + + return true; +} + +/* + * Sets a single Flag or bit in SREG. + */ +static bool trans_BSET(DisasContext *ctx, arg_BSET *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + switch (a->bit) { + case 0x00: + tcg_gen_movi_tl(cpu_Cf, 0x01); + break; + case 0x01: + tcg_gen_movi_tl(cpu_Zf, 0x01); + break; + case 0x02: + tcg_gen_movi_tl(cpu_Nf, 0x01); + break; + case 0x03: + tcg_gen_movi_tl(cpu_Vf, 0x01); + break; + case 0x04: + tcg_gen_movi_tl(cpu_Sf, 0x01); + break; + case 0x05: + tcg_gen_movi_tl(cpu_Hf, 0x01); + break; + case 0x06: + tcg_gen_movi_tl(cpu_Tf, 0x01); + break; + case 0x07: + tcg_gen_movi_tl(cpu_If, 0x01); + break; + } + + return true; +} + +/* + * Clears a single Flag in SREG. + */ +static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + switch (a->bit) { + case 0x00: + tcg_gen_movi_tl(cpu_Cf, 0x00); + break; + case 0x01: + tcg_gen_movi_tl(cpu_Zf, 0x00); + break; + case 0x02: + tcg_gen_movi_tl(cpu_Nf, 0x00); + break; + case 0x03: + tcg_gen_movi_tl(cpu_Vf, 0x00); + break; + case 0x04: + tcg_gen_movi_tl(cpu_Sf, 0x00); + break; + case 0x05: + tcg_gen_movi_tl(cpu_Hf, 0x00); + break; + case 0x06: + tcg_gen_movi_tl(cpu_Tf, 0x00); + break; + case 0x07: + tcg_gen_movi_tl(cpu_If, 0x00); + break; + } + + return true; +} + +/* + * MCU Control Instructions + */ + +/* + * The BREAK instruction is used by the On-chip Debug system, and is + * normally not used in the application software. When the BREAK instruction is + * executed, the AVR CPU is set in the Stopped Mode. This gives the On-chip + * Debugger access to internal resources. If any Lock bits are set, or either + * the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the BREAK + * instruction as a NOP and will not enter the Stopped mode. This instruction + * is not available in all devices. Refer to the device specific instruction + * set summary. + */ +static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_BREAK)) { + return true; + } + +#ifdef BREAKPOINT_ON_BREAK + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + tcg_gen_movi_tl(cpu_pc, ctx->npc - 1); + gen_helper_debug(cpu_env); + ctx->bstate = DISAS_EXIT; +#else + /* NOP */ +#endif + + return true; +} + +/* + * This instruction performs a single cycle No Operation. + */ +static bool trans_NOP(DisasContext *ctx, arg_NOP *a) +{ + + /* NOP */ + + return true; +} + +/* + * This instruction sets the circuit in sleep mode defined by the MCU + * Control Register. + */ +static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + gen_helper_sleep(cpu_env); + ctx->bstate = DISAS_NORETURN; + return true; +} + +/* + * This instruction resets the Watchdog Timer. This instruction must be + * executed within a limited time given by the WD prescaler. See the Watchdog + * Timer hardware specification. + */ +static bool trans_WDR(DisasContext *ctx, arg_WDR *a) +{ + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + gen_helper_wdr(cpu_env); + + return true; +} + +/* + * Core translation mechanism functions: + * + * - translate() + * - canonicalize_skip() + * - gen_intermediate_code() + * - restore_state_to_opc() + * + */ +static void translate(DisasContext *ctx) +{ + INIT_UC_CONTEXT_FROM_DISAS(ctx); + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx); + + // Unicorn: end address tells us to stop emulation + const target_ulong insn_pc = ctx->npc; + if (uc_addr_is_exit(uc, insn_pc*2)) { + ctx->bstate = DISAS_UC_EXIT; + return; + } + + // Unicorn: trace this instruction on request + bool insn_hook = false; + TCGOp *insn_prev_op = NULL; + if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, insn_pc*2)) { + + // sync PC in advance + tcg_gen_movi_tl(cpu_pc, insn_pc); + + // save the last operand + insn_prev_op = tcg_last_op(tcg_ctx); + insn_hook = true; + gen_uc_tracecode(tcg_ctx, 0xf1, UC_HOOK_CODE_IDX, uc, insn_pc*2); + + // the callback might want to stop emulation immediately + check_exit_request(tcg_ctx); + } + + uint32_t opcode = next_word(ctx); + if (!decode_insn(ctx, opcode)) { + gen_helper_unsupported(cpu_env); + ctx->bstate = DISAS_NORETURN; + } + + if (insn_hook) { + // Unicorn: patch the callback to have the proper instruction size. + TCGOp *const tcg_op = insn_prev_op ? + QTAILQ_NEXT(insn_prev_op, link) : QTAILQ_FIRST(&tcg_ctx->ops); + tcg_op->args[1] = (ctx->npc - insn_pc)*2; + } +} + +/* Standardize the cpu_skip condition to NE. */ +static bool canonicalize_skip(DisasContext *ctx) +{ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); + switch (ctx->skip_cond) { + case TCG_COND_NEVER: + /* Normal case: cpu_skip is known to be false. */ + return false; + + case TCG_COND_ALWAYS: + /* + * Breakpoint case: cpu_skip is known to be true, via TB_FLAGS_SKIP. + * The breakpoint is on the instruction being skipped, at the start + * of the TranslationBlock. No need to update. + */ + return false; + + case TCG_COND_NE: + if (ctx->skip_var1 == NULL) { + tcg_gen_mov_tl(cpu_skip, ctx->skip_var0); + } else { + tcg_gen_xor_tl(cpu_skip, ctx->skip_var0, ctx->skip_var1); + ctx->skip_var1 = NULL; + } + break; + + default: + /* Convert to a NE condition vs 0. */ + if (ctx->skip_var1 == NULL) { + tcg_gen_setcondi_tl(ctx->skip_cond, cpu_skip, ctx->skip_var0, 0); + } else { + tcg_gen_setcond_tl(ctx->skip_cond, cpu_skip, + ctx->skip_var0, ctx->skip_var1); + ctx->skip_var1 = NULL; + } + ctx->skip_cond = TCG_COND_NE; + break; + } + if (ctx->free_skip_var0) { + tcg_temp_free(ctx->skip_var0); + ctx->free_skip_var0 = false; + } + ctx->skip_var0 = cpu_skip; + return true; +} + +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +{ + CPUAVRState *env = cs->env_ptr; + DisasContext ctx = { + .tb = tb, + .cs = cs, + .env = env, + .memidx = 0, + .bstate = DISAS_NEXT, + .skip_cond = TCG_COND_NEVER, + .singlestep = cs->singlestep_enabled, + }; + target_ulong pc_start = tb->pc / 2; + int num_insns = 0; + + INIT_UC_CONTEXT_FROM_DISAS(&ctx); + INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(&ctx); + + if (tb->flags & TB_FLAGS_FULL_ACCESS) { + /* + * This flag is set by ST/LD instruction we will regenerate it ONLY + * with mem/cpu memory access instead of mem access + */ + max_insns = 1; + } + if (ctx.singlestep) { + max_insns = 1; + } + + // Unicorn: trace this block on request + bool block_hook = false; + TCGOp *block_prev_op = NULL; + if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_BLOCK, tb->pc)) { + + // save the last operand + block_prev_op = tcg_last_op(tcg_ctx); + block_hook = true; + gen_uc_tracecode(tcg_ctx, 0xf8, UC_HOOK_BLOCK_IDX, uc, tb->pc); + } + + gen_tb_start(tb); + + ctx.npc = pc_start; + if (tb->flags & TB_FLAGS_SKIP) { + ctx.skip_cond = TCG_COND_ALWAYS; + ctx.skip_var0 = cpu_skip; + } + + do { + TCGLabel *skip_label = NULL; + + /* translate current instruction */ + tcg_gen_insn_start(ctx.npc); + num_insns++; + + /* + * this is due to some strange GDB behavior + * let's assume main has address 0x100 + * b main - sets breakpoint at address 0x00000100 (code) + * b *0x100 - sets breakpoint at address 0x00800100 (data) + */ + if (unlikely(!ctx.singlestep && + (cpu_breakpoint_test(cs, avr_code_base(env) | ctx.npc * 2, BP_ANY) || + cpu_breakpoint_test(cs, OFFSET_DATA | ctx.npc * 2, BP_ANY)))) { + canonicalize_skip(&ctx); + tcg_gen_movi_tl(cpu_pc, ctx.npc); + gen_helper_debug(cpu_env); + goto done_generating; + } + + /* Conditionally skip the next instruction, if indicated. */ + if (ctx.skip_cond != TCG_COND_NEVER) { + skip_label = gen_new_label(); + if (ctx.skip_var0 == cpu_skip) { + /* + * Copy cpu_skip so that we may zero it before the branch. + * This ensures that cpu_skip is non-zero after the label + * if and only if the skipped insn itself sets a skip. + */ + ctx.free_skip_var0 = true; + ctx.skip_var0 = tcg_temp_new(); + tcg_gen_mov_tl(ctx.skip_var0, cpu_skip); + tcg_gen_movi_tl(cpu_skip, 0); + } + if (ctx.skip_var1 == NULL) { + tcg_gen_brcondi_tl(ctx.skip_cond, ctx.skip_var0, 0, skip_label); + } else { + tcg_gen_brcond_tl(ctx.skip_cond, ctx.skip_var0, + ctx.skip_var1, skip_label); + ctx.skip_var1 = NULL; + } + if (ctx.free_skip_var0) { + tcg_temp_free(ctx.skip_var0); + ctx.free_skip_var0 = false; + } + ctx.skip_cond = TCG_COND_NEVER; + ctx.skip_var0 = NULL; + } + + translate(&ctx); + + if (skip_label) { + canonicalize_skip(&ctx); + gen_set_label(skip_label); + if (ctx.bstate == DISAS_NORETURN) { + ctx.bstate = DISAS_CHAIN; + } + } + } while (ctx.bstate == DISAS_NEXT + && num_insns < max_insns + && (ctx.npc - pc_start) * 2 < TARGET_PAGE_SIZE - 4 + && !tcg_op_buf_full()); + + if (tb->cflags & CF_LAST_IO) { + gen_io_end(); + } + + bool nonconst_skip = canonicalize_skip(&ctx); + + switch (ctx.bstate) { + case DISAS_NORETURN: + assert(!nonconst_skip); + break; + case DISAS_NEXT: + case DISAS_TOO_MANY: + case DISAS_CHAIN: + if (!nonconst_skip) { + /* Note gen_goto_tb checks singlestep. */ + gen_goto_tb(&ctx, 1, ctx.npc); + break; + } + tcg_gen_movi_tl(cpu_pc, ctx.npc); + /* fall through */ + case DISAS_LOOKUP: + if (!ctx.singlestep) { + tcg_gen_lookup_and_goto_ptr(); + break; + } + /* fall through */ + case DISAS_EXIT: + if (ctx.singlestep) { + gen_helper_debug(cpu_env); + } else { + tcg_gen_exit_tb(NULL, 0); + } + break; + case DISAS_UC_EXIT: + tcg_gen_movi_tl(cpu_pc, ctx.npc); + gen_helper_uc_avr_exit(tcg_ctx, cpu_env); + break; + default: + g_assert_not_reached(); + } + +done_generating: + gen_tb_end(tb, num_insns); + + tb->size = (ctx.npc - pc_start) * 2; + tb->icount = num_insns; + + hooked_regions_check(uc, tb->pc, tb->size); + + if (block_hook) { + // Unicorn: patch the callback to have the proper block size. + TCGOp *const tcg_op = block_prev_op ? + QTAILQ_NEXT(block_prev_op, link) : QTAILQ_FIRST(&tcg_ctx->ops); + tcg_op->args[1] = (ctx.npc - pc_start)*2; + } + +#ifdef DEBUG_DISAS +#if 0 + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) + && qemu_log_in_addr_range(tb->pc)) { + FILE *fd; + fd = qemu_log_lock(); + qemu_log("IN: %s\n", lookup_symbol(tb->pc)); + log_target_disas(cs, tb->pc, tb->size); + qemu_log("\n"); + qemu_log_unlock(fd); + } +#endif +#endif +} + +void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, + target_ulong *data) +{ + env->pc_w = data[0]; +} diff --git a/qemu/target/avr/unicorn.c b/qemu/target/avr/unicorn.c new file mode 100644 index 0000000000..09b5f628dd --- /dev/null +++ b/qemu/target/avr/unicorn.c @@ -0,0 +1,280 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh , 2015 */ + +/* + Created for Unicorn Engine by Glenn Baker , 2024 +*/ + +#include "qemu/typedefs.h" +#include "unicorn/unicorn.h" +#include "sysemu/cpus.h" +#include "sysemu/tcg.h" +#include "cpu.h" +#include "uc_priv.h" +#include "unicorn_common.h" +#include "unicorn.h" + +AVRCPU *cpu_avr_init(struct uc_struct *uc); + +static inline uint32_t get_pc(CPUAVRState *env) +{ + return env->pc_w*2; +} + +static uint64_t avr_get_pc(struct uc_struct *uc) +{ + return get_pc((CPUAVRState *)uc->cpu->env_ptr); +} + +static inline void set_pc(CPUAVRState *env, uint32_t value) +{ + env->pc_w = value/2; +} + +static void avr_set_pc(struct uc_struct *uc, uint64_t address) +{ + set_pc((CPUAVRState *)uc->cpu->env_ptr, address); +} + +static void reg_reset(struct uc_struct *uc) +{ +} + +#define GET_BYTE(x, n) (((x) >> (n)*8) & 0xff) +#define SET_BYTE(x, n, b) (x = ((x) & ~(0xff << ((n)*8))) | ((b) << ((n)*8))) +#define GET_RAMP(reg) GET_BYTE(env->glue(ramp,reg), 2) +#define SET_RAMP(reg, val) SET_BYTE(env->glue(ramp,reg), 2, val) + +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) +{ + CPUAVRState *const env = _env; + uc_err ret = UC_ERR_ARG; + + switch (regid) { + case UC_AVR_REG_PC: + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = get_pc(env); + break; + case UC_AVR_REG_SP: + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->sp; + break; + + case UC_AVR_REG_RAMPD: + CHECK_REG_TYPE(uint8_t); + *(uint8_t *)value = GET_RAMP(D); + break; + case UC_AVR_REG_RAMPX: + CHECK_REG_TYPE(uint8_t); + *(uint8_t *)value = GET_RAMP(X); + break; + case UC_AVR_REG_RAMPY: + CHECK_REG_TYPE(uint8_t); + *(uint8_t *)value = GET_RAMP(Y); + break; + case UC_AVR_REG_RAMPZ: + CHECK_REG_TYPE(uint8_t); + *(uint8_t *)value = GET_RAMP(Z); + break; + case UC_AVR_REG_EIND: + CHECK_REG_TYPE(uint8_t); + *(uint8_t *)value = GET_BYTE(env->eind, 2); + break; + case UC_AVR_REG_SPL: + CHECK_REG_TYPE(uint8_t); + *(uint8_t *)value = GET_BYTE(env->sp, 0); + break; + case UC_AVR_REG_SPH: + CHECK_REG_TYPE(uint8_t); + *(uint8_t *)value = GET_BYTE(env->sp, 1); + break; + case UC_AVR_REG_SREG: + CHECK_REG_TYPE(uint8_t); + *(uint8_t *)value = cpu_get_sreg(env); + break; + + default: { + uint64_t v = 0; + if (regid >= UC_AVR_REG_R0 && regid <= UC_AVR_REG_R31) { + CHECK_REG_TYPE(uint8_t); + *(int8_t *)value = (int8_t)env->r[regid - UC_AVR_REG_R0]; + } + else if (regid >= UC_AVR_REG_R0W && regid <= UC_AVR_REG_R30W) { + const uint32_t *const r = &env->r[regid - UC_AVR_REG_R0W]; + for (int k = 0; k < 2; k++) + SET_BYTE(v, k, (r[k] & 0xff)); + CHECK_REG_TYPE(uint16_t); + *(int16_t *)value = (int16_t)v; + } + else if (regid >= UC_AVR_REG_R0D && regid <= UC_AVR_REG_R28D) { + const uint32_t *const r = &env->r[regid - UC_AVR_REG_R0D]; + for (int k = 0; k < 4; k++) + SET_BYTE(v, k, (r[k] & 0xff)); + CHECK_REG_TYPE(uint32_t); + *(int32_t *)value = (int32_t)v; + } + break; + } + } + + CHECK_RET_DEPRECATE(ret, regid); + return ret; +} + +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) +{ + CPUAVRState *const env = _env; + uc_err ret = UC_ERR_ARG; + + switch (regid) { + case UC_AVR_REG_PC: + CHECK_REG_TYPE(uint32_t); + set_pc(env, *(uint32_t *)value); + *setpc = 1; + break; + case UC_AVR_REG_SP: + CHECK_REG_TYPE(uint32_t); + env->sp = *(uint32_t *)value; + break; + + case UC_AVR_REG_RAMPD: + CHECK_REG_TYPE(uint8_t); + SET_RAMP(D, *(uint8_t *)value); + break; + case UC_AVR_REG_RAMPX: + CHECK_REG_TYPE(uint8_t); + SET_RAMP(X, *(uint8_t *)value); + break; + case UC_AVR_REG_RAMPY: + CHECK_REG_TYPE(uint8_t); + SET_RAMP(Y, *(uint8_t *)value); + break; + case UC_AVR_REG_RAMPZ: + CHECK_REG_TYPE(uint8_t); + SET_RAMP(Z, *(uint8_t *)value); + break; + case UC_AVR_REG_EIND: + CHECK_REG_TYPE(uint8_t); + SET_BYTE(env->eind, 2, *(uint8_t *)value); + break; + case UC_AVR_REG_SPL: + CHECK_REG_TYPE(uint8_t); + SET_BYTE(env->sp, 0, *(uint8_t *)value); + break; + case UC_AVR_REG_SPH: + CHECK_REG_TYPE(uint8_t); + SET_BYTE(env->sp, 1, *(uint8_t *)value); + break; + case UC_AVR_REG_SREG: + CHECK_REG_TYPE(uint8_t); + cpu_set_sreg(env, *(uint8_t *)value); + break; + + default: { + uint64_t v; + uint32_t *r = NULL; + int rlen = 0; + if (regid >= UC_AVR_REG_R0 && regid <= UC_AVR_REG_R31) { + v = *(uint8_t *)value; + r = &env->r[regid - UC_AVR_REG_R0]; + rlen = 1; + CHECK_REG_TYPE(uint8_t); + } + else if (regid >= UC_AVR_REG_R0W && regid <= UC_AVR_REG_R30W) { + v = *(uint16_t *)value; + r = &env->r[regid - UC_AVR_REG_R0W]; + rlen = 2; + CHECK_REG_TYPE(uint16_t); + } + else if (regid >= UC_AVR_REG_R0D && regid <= UC_AVR_REG_R28D) { + v = *(uint32_t *)value; + r = &env->r[regid - UC_AVR_REG_R0D]; + rlen = 4; + CHECK_REG_TYPE(uint32_t); + } + if (r && rlen > 0) { + for (int k = 0; k < rlen; k++) + r[k] = GET_BYTE(v, k); + } + } + } + + CHECK_RET_DEPRECATE(ret, regid); + return ret; +} + +static int avr_cpus_init(struct uc_struct *uc, const char *cpu_model) +{ + AVRCPU *cpu; + + cpu = cpu_avr_init(uc); + if (cpu == NULL) { + return -1; + } + + return 0; +} + +static void avr_release(void *ctx) +{ + int i; + TCGContext *tcg_ctx = (TCGContext *)ctx; + AVRCPU *cpu = (AVRCPU *)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 inline bool is_flash_memory(hwaddr addr, size_t size, uint32_t perms) +{ + if ((addr ^ UC_AVR_MEM_FLASH) >> 24) + return false; + if ((perms & UC_PROT_ALL) != (UC_PROT_READ|UC_PROT_EXEC)) + return false; + return true; +} + +static MemoryRegion *avr_memory_map(struct uc_struct *uc, hwaddr begin, size_t size, uint32_t perms) +{ + MemoryRegion *const mr = memory_map(uc, begin, size, perms); + if (mr && is_flash_memory(begin, size, perms)) + set_avr_feature(&AVR_CPU(uc->cpu)->env, AVR_FEATURE_FLASH); + return mr; +} + +static MemoryRegion *avr_memory_map_ptr(struct uc_struct *uc, hwaddr begin, size_t size, uint32_t perms, void *ptr) +{ + MemoryRegion *const mr = memory_map_ptr(uc, begin, size, perms, ptr); + if (mr && is_flash_memory(begin, size, perms)) + set_avr_feature(&AVR_CPU(uc->cpu)->env, AVR_FEATURE_FLASH); + return mr; +} + +DEFAULT_VISIBILITY +void uc_init(struct uc_struct *uc) +{ + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; + uc->set_pc = avr_set_pc; + uc->get_pc = avr_get_pc; + uc->cpus_init = avr_cpus_init; + uc->release = avr_release; + uc->cpu_context_size = offsetof(CPUAVRState, features); + uc_common_init(uc); + uc->memory_map = avr_memory_map; + uc->memory_map_ptr = avr_memory_map_ptr; +} diff --git a/qemu/target/avr/unicorn.h b/qemu/target/avr/unicorn.h new file mode 100644 index 0000000000..a90b109016 --- /dev/null +++ b/qemu/target/avr/unicorn.h @@ -0,0 +1,21 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh , 2015 */ + +/* + Modified for Unicorn Engine by Glenn Baker , 2024 +*/ + +#ifndef UC_QEMU_TARGET_AVR_H +#define UC_QEMU_TARGET_AVR_H + +// functions to read & write registers +uc_err reg_read_avr(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_avr(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); + +void uc_init_avr(struct uc_struct *uc); + +int avr_cpu_model_valid(int cpu_model); + +#endif /* UC_QEMU_TARGET_AVR_H */ diff --git a/qemu/target/avr/unicorn_helper.h b/qemu/target/avr/unicorn_helper.h new file mode 100644 index 0000000000..117b375f19 --- /dev/null +++ b/qemu/target/avr/unicorn_helper.h @@ -0,0 +1,165 @@ +#ifndef QEMU_UNICORN_HELPER_H +#define QEMU_UNICORN_HELPER_H + +#include + +#define UC_GET_TCG_CONTEXT(uc) ((uc)->tcg_ctx) +#define DISAS_GET_UC_CONTEXT(ctx) ((ctx)->env->uc) +#define DISAS_GET_TCG_CONTEXT(ctx) UC_GET_TCG_CONTEXT(DISAS_GET_UC_CONTEXT(ctx)) + +#define INIT_UC_CONTEXT_FROM_DISAS(ctx) \ + struct uc_struct *const uc = DISAS_GET_UC_CONTEXT(ctx) +#define INIT_TCG_CONTEXT_FROM_UC(uc) \ + TCGContext *const tcg_ctx = UC_GET_TCG_CONTEXT(uc) +#define INIT_CPU_ENV_FROM_TCG_CONTEXT(ctx) \ + TCGv_ptr const cpu_env = (ctx)->cpu_env +#define INIT_TCG_CONTEXT_FROM_DISAS(ctx) \ + INIT_TCG_CONTEXT_FROM_UC((ctx)->env->uc) +#define INIT_TCG_CONTEXT_AND_CPU_ENV_FROM_DISAS(ctx) \ + INIT_TCG_CONTEXT_FROM_DISAS(ctx); \ + INIT_CPU_ENV_FROM_TCG_CONTEXT(tcg_ctx) + +/* "qapi/error.h */ +#if 0 +#include +#define error_report(...) \ + (error)(EXIT_FAILURE, 0, __VA_ARGS__) +#endif + +/* "exec/address-spaces.h" */ +#define address_space_memory \ + (cpu->uc->address_space_memory) +#define address_space_ldub(...) \ + glue(address_space_ldub, UNICORN_ARCH_POSTFIX)(uc, __VA_ARGS__) +#define address_space_stb(...) \ + glue(address_space_stb, UNICORN_ARCH_POSTFIX)(uc, __VA_ARGS__) + +/* "tcg/tch.h" */ +#define tcg_wrapper_I(func, ...) \ + (glue(tcg_,func))(tcg_ctx, ## __VA_ARGS__) +#define tcg_wrapper_X(func, ...) \ + tcg_wrapper_I(glue(func,_avr), ## __VA_ARGS__) +#define tcg_wrapper_tl(func, ...) \ + tcg_wrapper_I(glue(func,_i32), ## __VA_ARGS__) + +#undef tcg_const_i32 +#define tcg_const_i32(...) tcg_wrapper_X(const_i32, __VA_ARGS__) +#undef tcg_gen_addi_i32 +#define tcg_gen_addi_i32(...) tcg_wrapper_X(gen_addi_i32, __VA_ARGS__) +//#undef tcg_gen_addi_tl +//#define tcg_gen_addi_tl(...) tcg_wrapper_tl(gen_addi, __VA_ARGS__) +#undef tcg_gen_add_i32 +#define tcg_gen_add_i32(...) tcg_wrapper_I(gen_add_i32, __VA_ARGS__) +#undef tcg_gen_add_tl +#define tcg_gen_add_tl(...) tcg_wrapper_tl(gen_add, __VA_ARGS__) +#undef tcg_gen_andc_i32 +#define tcg_gen_andc_i32(...) tcg_wrapper_X(gen_andc_i32, __VA_ARGS__) +//#undef tcg_gen_andc_tl +//#define tcg_gen_andc_tl(...) tcg_wrapper_tl(gen_andc, __VA_ARGS__) +#undef tcg_gen_andi_i32 +#define tcg_gen_andi_i32(...) tcg_wrapper_X(gen_andi_i32, __VA_ARGS__) +//#undef tcg_gen_andi_tl +//#define tcg_gen_andi_tl(...) tcg_wrapper_tl(gen_andi, __VA_ARGS__) +#undef tcg_gen_and_i32 +#define tcg_gen_and_i32(...) tcg_wrapper_I(gen_and_i32, __VA_ARGS__) +#undef tcg_gen_and_tl +#define tcg_gen_and_tl(...) tcg_wrapper_tl(gen_and, __VA_ARGS__) +#undef tcg_gen_brcondi_i32 +#define tcg_gen_brcondi_i32(...) tcg_wrapper_X(gen_brcondi_i32, __VA_ARGS__) +//#undef tcg_gen_brcondi_tl +//#define tcg_gen_brcondi_tl(...) tcg_wrapper_tl(gen_brcondi, __VA_ARGS__) +#undef tcg_gen_brcond_i32 +#define tcg_gen_brcond_i32(...) tcg_wrapper_X(gen_brcond_i32, __VA_ARGS__) +//#undef tcg_gen_brcond_tl +//#define tcg_gen_brcond_tl(...) tcg_wrapper_tl(gen_brcond, __VA_ARGS__) +#undef tcg_gen_deposit_i32 +#define tcg_gen_deposit_i32(...) tcg_wrapper_X(gen_deposit_i32, __VA_ARGS__) +//#undef tcg_gen_deposit_tl +//#define tcg_gen_deposit_tl(...) tcg_wrapper_tl(gen_deposit, __VA_ARGS__) +#undef tcg_gen_exit_tb +#define tcg_gen_exit_tb(...) tcg_wrapper_X(gen_exit_tb, __VA_ARGS__) +#undef tcg_gen_ext8s_tl +#define tcg_gen_ext8s_tl(...) tcg_wrapper_tl(gen_ext8s, __VA_ARGS__) +#undef tcg_gen_goto_tb +#define tcg_gen_goto_tb(...) tcg_wrapper_X(gen_goto_tb, __VA_ARGS__) +#undef tcg_gen_insn_start +#define tcg_gen_insn_start(...) tcg_wrapper_I(gen_insn_start, __VA_ARGS__) +#undef tcg_gen_movcond_tl +#define tcg_gen_movcond_tl(...) tcg_wrapper_tl(gen_movcond, __VA_ARGS__) +#undef tcg_gen_movi_i32 +#define tcg_gen_movi_i32(...) tcg_wrapper_I(gen_movi_i32, __VA_ARGS__) +//#undef tcg_gen_movi_i32 +//#define tcg_gen_movi_i32(...) tcg_wrapper(gen_movi_i32, __VA_ARGS__) +#undef tcg_gen_movi_tl +#define tcg_gen_movi_tl(...) tcg_wrapper_tl(gen_movi, __VA_ARGS__) +#undef tcg_gen_mov_i32 +#define tcg_gen_mov_i32(...) tcg_wrapper(gen_mov_i32, __VA_ARGS__) +#undef tcg_gen_mov_tl +#define tcg_gen_mov_tl(...) tcg_wrapper_tl(gen_mov, __VA_ARGS__) +#undef tcg_gen_mul_i32 +#define tcg_gen_mul_i32(...) tcg_wrapper(gen_mul_i32, __VA_ARGS__) +#undef tcg_gen_mul_tl +#define tcg_gen_mul_tl(...) tcg_wrapper_tl(gen_mul, __VA_ARGS__) +#undef tcg_gen_not_i32 +#define tcg_gen_not_i32(...) tcg_wrapper(gen_not_i32, __VA_ARGS__) +#undef tcg_gen_not_tl +#define tcg_gen_not_tl(...) tcg_wrapper_tl(gen_not, __VA_ARGS__) +#undef tcg_gen_ori_i32 +#define tcg_gen_ori_i32(...) tcg_wrapper_X(gen_ori_i32, __VA_ARGS__) +//#undef tcg_gen_ori_tl +//#define tcg_gen_ori_tl(...) tcg_wrapper_tl(gen_ori, __VA_ARGS__) +#undef tcg_gen_or_i32 +#define tcg_gen_or_i32(...) tcg_wrapper_I(gen_or_i32, __VA_ARGS__) +#undef tcg_gen_or_tl +#define tcg_gen_or_tl(...) tcg_wrapper_tl(gen_or, __VA_ARGS__) +#undef tcg_gen_qemu_ld8u +#define tcg_gen_qemu_ld8u(...) tcg_wrapper_I(gen_qemu_ld8u, __VA_ARGS__) +#undef tcg_gen_qemu_ld_tl +#define tcg_gen_qemu_ld_tl(...) tcg_wrapper_tl(gen_qemu_ld, __VA_ARGS__) +#undef tcg_gen_qemu_st8 +#define tcg_gen_qemu_st8(...) tcg_wrapper_I(gen_qemu_st8, __VA_ARGS__) +#undef tcg_gen_qemu_st_tl +#define tcg_gen_qemu_st_tl(...) tcg_wrapper_tl(gen_qemu_st, __VA_ARGS__) +#undef tcg_gen_setcondi_tl +#define tcg_gen_setcondi_tl(...) tcg_wrapper_tl(gen_setcondi, __VA_ARGS__) +#undef tcg_gen_setcond_tl +#define tcg_gen_setcond_tl(...) tcg_wrapper_tl(gen_setcond, __VA_ARGS__) +#undef tcg_gen_shli_i32 +#define tcg_gen_shli_i32(...) tcg_wrapper_X(gen_shli_i32, __VA_ARGS__) +//#undef tcg_gen_shli_tl +//#define tcg_gen_shli_tl(...) tcg_wrapper_tl(gen_shli, __VA_ARGS__) +#undef tcg_gen_shri_i32 +#define tcg_gen_shri_i32(...) tcg_wrapper_X(gen_shri_i32, __VA_ARGS__) +//#undef tcg_gen_shri_tl +//#define tcg_gen_shri_tl(...) tcg_wrapper_tl(gen_shri, __VA_ARGS__) +#undef tcg_gen_subi_i32 +#define tcg_gen_subi_i32(...) tcg_wrapper_X(gen_subi_i32, __VA_ARGS__) +//#undef tcg_gen_subi_tl +//#define tcg_gen_subi_tl(...) tcg_wrapper_tl(gen_subi, __VA_ARGS__) +#undef tcg_gen_sub_i32 +#define tcg_gen_sub_i32(...) tcg_wrapper(gen_sub_i32, __VA_ARGS__) +#undef tcg_gen_sub_tl +#define tcg_gen_sub_tl(...) tcg_wrapper_tl(gen_sub, __VA_ARGS__) +#undef tcg_gen_xori_i32 +#define tcg_gen_xori_i32(...) tcg_wrapper_X(gen_xori_i32, __VA_ARGS__) +//#undef tcg_gen_xori_tl +//#define tcg_gen_xori_tl(...) tcg_wrapper_tl(gen_xori, __VA_ARGS__) +#undef tcg_gen_xor_i32 +#define tcg_gen_xor_i32(...) tcg_wrapper(gen_xor_i32, __VA_ARGS__) +#undef tcg_gen_xor_tl +#define tcg_gen_xor_tl(...) tcg_wrapper_tl(gen_xor, __VA_ARGS__) +#undef tcg_global_mem_new_i32 +#define tcg_global_mem_new_i32(...) tcg_wrapper_I(global_mem_new_i32, __VA_ARGS__) +#undef tcg_temp_new_i32 +#define tcg_temp_new_i32() tcg_wrapper_I(temp_new_i32) +#undef tcg_temp_free +#define tcg_temp_free(...) tcg_wrapper_tl(temp_free, __VA_ARGS__) +#undef tcg_temp_free_i32 +#define tcg_temp_free_i32(...) tcg_wrapper_I(temp_free_i32, __VA_ARGS__) +#undef tcg_op_buf_full +#define tcg_op_buf_full() tcg_wrapper_I(op_buf_full) +#undef tcg_gen_lookup_and_goto_ptr +#define tcg_gen_lookup_and_goto_ptr() \ + tcg_wrapper_X(gen_lookup_and_goto_ptr) + +#endif /* QEMU_UNICORN_HELPER_H */ diff --git a/samples/Makefile b/samples/Makefile index cbb3d91fb7..b896aecb43 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -93,6 +93,9 @@ endif ifneq (,$(findstring tricore,$(UNICORN_ARCHS))) SOURCES += sample_tricore.c endif +ifneq (,$(findstring avr,$(UNICORN_ARCHS))) +SOURCES += sample_avr.c +endif BINS = $(SOURCES:.c=$(BIN_EXT)) OBJS = $(SOURCES:.c=.o) diff --git a/samples/sample_avr.c b/samples/sample_avr.c new file mode 100644 index 0000000000..7482bbc204 --- /dev/null +++ b/samples/sample_avr.c @@ -0,0 +1,131 @@ +/* + Created for Unicorn Engine by Glenn Baker , 2024 +*/ + +/* Sample code to demonstrate how to emulate AVR code */ + +#include +#include +#include + +// Code to be emulated +static const uint32_t CODE_BASE = 0x0000; +static const uint8_t CODE[] = + "\x86\x0f" // add r24, r22 + "\x97\x1f" // adc r25, r23 + "\x88\x0f" // add r24, r24 + "\x99\x1f" // adc r25, r25 + "\x01\x96" // adiw r24, 0x01 + "\x08\x95" // ret + ; +enum { + CODE_SIZE = sizeof(CODE) - 1, + CODE_SIZE_ALIGNED = (CODE_SIZE + 0xff) & -0x100, +}; + +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 bool is_error(uc_err err, const char *what) +{ + if (err != UC_ERR_OK) { + fprintf(stderr, "error: failed on %s() with error %u: %s\n", + what, err, uc_strerror(err)); + return true; + } + return false; +} + +static bool test_avr(void) +{ + uc_engine *uc = NULL; + uc_hook trace1, trace2; + bool success = false; + + uint8_t regs[32]; + int reg_ids[32]; + void *reg_vals[32]; + int i; + + printf("Emulate AVR code\n"); + do { + // Initialize emulator in AVR mode + uc_err err = uc_open(UC_ARCH_AVR, UC_MODE_LITTLE_ENDIAN, &uc); + if (is_error(err, "uc_open")) + break; + + // Map program code + err = uc_mem_map(uc, CODE_BASE, CODE_SIZE_ALIGNED, UC_PROT_READ|UC_PROT_EXEC); + if (is_error(err, "uc_mem_map")) + break; + + // Write machine code to be emulated to memory + err = uc_mem_write(uc, CODE_BASE, CODE, CODE_SIZE); + if (is_error(err, "uc_mem_write")) + break; + + // Tracing all basic blocks with customized callback + err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); + if (is_error(err, "uc_hook_add[UC_HOOK_BLOCK]")) + break; + + // Tracing one instruction at CODE_BASE with customized callback + err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, CODE_BASE, + CODE_BASE + 1); + if (is_error(err, "uc_hook_add[UC_HOOK_CODE]")) + break; + + // Initialize registers + memset(regs, 0, sizeof(regs)); + regs[25] = 0; regs[24] = 1; + regs[23] = 0; regs[22] = 2; + + for (i = 0; i < 4; i++) { + reg_ids[i] = UC_AVR_REG_R0 + 22 + i; + reg_vals[i] = ®s[22 + i]; + } + err = uc_reg_write_batch(uc, reg_ids, reg_vals, 4); + if (is_error(err, "uc_reg_write_batch")) + break; + + // Emulate machine code in infinite time (last param = 0), or + // when finishing all the code. + err = uc_emu_start(uc, CODE_BASE, CODE_BASE + 4, 0, 0); + if (is_error(err, "uc_emu_start")) + break; + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_AVR_REG_R25, ®s[25]); + uc_reg_read(uc, UC_AVR_REG_R24, ®s[24]); + uc_reg_read(uc, UC_AVR_REG_R23, ®s[23]); + uc_reg_read(uc, UC_AVR_REG_R22, ®s[22]); + printf(">>> r25,r24 = 0x%02x%02x\n", regs[25], regs[24]); + if (regs[25] == 0 && regs[24] == 3 && regs[23] == 0 && regs[22] == 2) + success = true; + } while (0); + + if (uc) + uc_close(uc); + return success; +} + +int main(int argc, char **argv, char **envp) +{ + if (!test_avr()) + abort(); + return 0; +} diff --git a/symbols.sh b/symbols.sh index 29600c7e2d..8249fbf29e 100755 --- a/symbols.sh +++ b/symbols.sh @@ -6284,7 +6284,21 @@ 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" +avr_SYMBOLS=" +helper_sleep \ +helper_unsupported \ +helper_debug \ +helper_break \ +helper_inb \ +helper_outb \ +helper_fullrd \ +helper_fullwr \ +helper_wdr \ +gen_intermediate_code \ +restore_state_to_opc \ +" + +ARCHS="x86_64 arm aarch64 riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x tricore avr" for arch in $ARCHS; do diff --git a/tests/unit/test_avr.c b/tests/unit/test_avr.c new file mode 100644 index 0000000000..e9e6aecbcc --- /dev/null +++ b/tests/unit/test_avr.c @@ -0,0 +1,268 @@ +#include +#include "unicorn_test.h" + +#define ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) + +#define PAGE_SIZE 256 +#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & -PAGE_SIZE) + +enum { + ADDR__init__ = 0x0000, // __init__ + ADDR_test_func = 0x001a, // test_func() + ADDR_test_1 = 0x0030, // test_1() + ADDR_main = 0x0058, // main() + ADDR_abort = 0x0062, // abort() + ADDR_exit = 0x006c, // _exit() + ADDR__stop_program = 0x006e, // __stop_program() + ADDR__data__ = 0x0070, // __data__ + ADDR__data__end = 0x0072, +}; + +enum { + SIZE__init__ = ADDR_test_func - ADDR__init__, + SIZE_test_func = ADDR_test_1 - ADDR_test_func, + SIZE_test_1 = ADDR_main - ADDR_test_1, + SIZE_main = ADDR_abort - ADDR_main, + SIZE_abort = ADDR_exit - ADDR_abort, + SIZE_exit = ADDR__stop_program - ADDR_exit, + SIZE__stop_program = ADDR__data__ - ADDR__stop_program, + SIZE__data__ = ADDR__data__end - ADDR__data__, +}; + +static const uint8_t FLASH[] = + // 00000000 <__ctors_end>: + "\x12\xe0" // ldi r17, 0x02 + "\xa0\xe0" // ldi r26, 0x00 + "\xb2\xe0" // ldi r27, 0x02 + "\xe0\xe7" // ldi r30, 0x70 + "\xf0\xe0" // ldi r31, 0x00 + "\x00\xe0" // ldi r16, 0x00 + "\x0b\xbf" // out 0x3b, r16 + "\x02\xc0" // rjmp .+4 + "\x07\x90" // elpm r0, Z+ + "\x0d\x92" // st X+, r0 + "\xa2\x30" // cpi r26, 0x02 + "\xb1\x07" // cpc r27, r17 + "\xd9\xf7" // brne .-10 + + // 0000001a : + "\x20\x91\x00\x02" // lds r18, 0x0200 + "\x30\x91\x01\x02" // lds r19, 0x0201 + "\x86\x0f" // add r24, r22 + "\x97\x1f" // adc r25, r23 + "\x88\x0f" // add r24, r24 + "\x99\x1f" // adc r25, r25 + "\x82\x0f" // add r24, r18 + "\x93\x1f" // adc r25, r19 + "\x08\x95" // ret + + // 00000030 : + "\x62\xe0" // ldi r22, 0x02 + "\x70\xe0" // ldi r23, 0x00 + "\x81\xe0" // ldi r24, 0x01 + "\x90\xe0" // ldi r25, 0x00 + "\x0e\x94\x0d\x00" // call 0x1a + "\x07\x97" // sbiw r24, 0x07 + "\x11\xf0" // breq .+4 + "\x0e\x94\x31\x00" // call 0x62 + "\x60\xe8" // ldi r22, 0x80 + "\x70\xe0" // ldi r23, 0x00 + "\x80\xe4" // ldi r24, 0x40 + "\x90\xe0" // ldi r25, 0x00 + "\x0e\x94\x0d\x00" // call 0x1a + "\x81\x38" // cpi r24, 0x81 + "\x91\x40" // sbci r25, 0x01 + "\xa9\xf7" // brne .-22 + "\x08\x95" // ret + + // 00000058
: + "\x0e\x94\x18\x00" // call 0x30 + "\x80\xe0" // ldi r24, 0x00 + "\x90\xe0" // ldi r25, 0x00 + "\x08\x95" // ret + + // 00000062 : + "\x81\xe0" // ldi r24, 0x01 + "\x90\xe0" // ldi r25, 0x00 + "\xf8\x94" // cli + "\x0c\x94\x36\x00" // jmp 0x6c + + // 0000006c <_exit>: + "\xf8\x94" // cli + + // 0000006e <__stop_program>: + "\xff\xcf" // rjmp .-2 + + // 0x000070 .data + "\x01\x00" + ; +const uint64_t FLASH_SIZE = sizeof(FLASH); + +const uint64_t MEM_BASE = 0x0200; +const uint64_t MEM_SIZE = 0x0100; + +static void uc_common_setup(uc_engine **uc, uc_cpu_avr cpu_model, + const uint8_t *code, uint64_t code_size) +{ + OK(uc_open(UC_ARCH_AVR, UC_MODE_LITTLE_ENDIAN, uc)); + if (cpu_model != 0) + OK(uc_ctl_set_cpu_model(*uc, cpu_model)); + + OK(uc_mem_map(*uc, UC_AVR_MEM_FLASH, PAGE_ALIGN(code_size), + UC_PROT_READ|UC_PROT_EXEC)); + OK(uc_mem_write(*uc, UC_AVR_MEM_FLASH, code, code_size)); + OK(uc_mem_map(*uc, MEM_BASE, MEM_SIZE, UC_PROT_READ|UC_PROT_WRITE)); +} + +static void test_avr_basic_alu(void) +{ + uc_engine *uc = NULL; + + uint8_t r[32] = {0,}; + uint32_t r_pc; + uint16_t r_func_arg0 = 1, r_func_arg1 = 2, r_func_ret; + r[24] = 1; + r[22] = 2; + + uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); + OK(uc_reg_write(uc, UC_AVR_REG_R24W, &r_func_arg0)); + OK(uc_reg_write(uc, UC_AVR_REG_R22W, &r_func_arg1)); + + const uint64_t code_start = ADDR_test_func + 8; + OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0)); + + OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); + OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25])); + OK(uc_reg_read(uc, UC_AVR_REG_R24, &r[24])); + OK(uc_reg_read(uc, UC_AVR_REG_R23, &r[23])); + OK(uc_reg_read(uc, UC_AVR_REG_R22, &r[22])); + + TEST_CHECK(r_pc == code_start + 4); + TEST_CHECK(r[25] == 0 && r[24] == 3); + TEST_CHECK(r[23] == 0 && r[22] == 2); + + OK(uc_reg_read(uc, UC_AVR_REG_R24W, &r_func_ret)); + OK(uc_reg_read(uc, UC_AVR_REG_R22W, &r_func_arg1)); + + TEST_CHECK(r_func_ret == r[24]); + TEST_CHECK(r_func_arg1 == r[22]); + + OK(uc_close(uc)); +} + +typedef struct MEM_HOOK_RESULT_s { + uc_mem_type type; + uint64_t address; + int size; + uint64_t value; +} MEM_HOOK_RESULT; + +typedef struct MEM_HOOK_RESULTS_s { + uint64_t count; + MEM_HOOK_RESULT results[16]; +} MEM_HOOK_RESULTS; + +static bool test_avr_basic_mem_cb_eventmem(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, void *user_data) +{ + MEM_HOOK_RESULTS *const r = user_data; + + uint64_t count = r->count; + if (count >= ARRAY_ELEMS(r->results)) { + TEST_ASSERT(false); + } + + r->results[count].type = type; + r->results[count].address = address; + r->results[count].size = size; + r->results[count].value = value; + r->count++; + return true; +} + +static void test_avr_basic_mem(void) +{ + uc_engine *uc = NULL; + uc_hook eventmem_hook; + MEM_HOOK_RESULTS eventmem_trace = {0}; + + const uint8_t *const DATA = &FLASH[ADDR__data__]; + uint8_t mem[SIZE__data__]; + + uint32_t r_pc; + int i; + + uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); + OK(uc_hook_add(uc, &eventmem_hook, UC_HOOK_MEM_VALID, + test_avr_basic_mem_cb_eventmem, &eventmem_trace, 1, 0)); + + const uint64_t code_start = ADDR__init__; + OK(uc_emu_start(uc, code_start, ADDR__init__ + SIZE__init__, 0, 0)); + + OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); + TEST_CHECK(r_pc == ADDR__init__ + SIZE__init__); + + // Check SRAM was correctly initialized with data from Flash program memory + OK(uc_mem_read(uc, MEM_BASE, mem, sizeof(mem))); + TEST_CHECK(memcmp(mem, DATA, SIZE__data__) == 0); + + TEST_CHECK(eventmem_trace.count == 2*SIZE__data__); + for (i = 0; i < SIZE__data__; i++) { + const MEM_HOOK_RESULT *const mr = &eventmem_trace.results[2*i]; + TEST_CHECK(mr->type == UC_MEM_READ); + TEST_CHECK(mr->address == (UC_AVR_MEM_FLASH|(ADDR__data__+i))); + TEST_CHECK(mr->size == 1); + TEST_CHECK(mr->value == 0); + + const MEM_HOOK_RESULT *const mw = &eventmem_trace.results[2*i+1]; + TEST_CHECK(mw->type == UC_MEM_WRITE); + TEST_CHECK(mw->address == MEM_BASE+i); + TEST_CHECK(mw->size == 1); + TEST_CHECK(mw->value == DATA[i]); + } + + OK(uc_close(uc)); +} + +static void test_avr_full_exec(void) +{ + uc_engine *uc = NULL; + + uint8_t r[32] = {0,}; + uint32_t r_pc; + uint32_t r_sp; + + uc_common_setup(&uc, 0, FLASH, FLASH_SIZE); + + const uint64_t code_start = ADDR__init__; + OK(uc_emu_start(uc, code_start, ADDR__init__ + SIZE__init__, 0, 0)); + + OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc)); + TEST_CHECK(r_pc == ADDR__init__ + SIZE__init__); + + r_sp = MEM_BASE + MEM_SIZE - 1; + OK(uc_reg_write(uc, UC_AVR_REG_SP, &r_sp)); + + const uint64_t exits[] = { + ADDR_main, + ADDR__stop_program + }; + OK(uc_ctl_exits_enable(uc)); + OK(uc_ctl_set_exits(uc, exits, ARRAY_ELEMS(exits))); + + const uint64_t code_main = ADDR_main; + OK(uc_emu_start(uc, code_main, 0, 0, 0)); + + OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25])); + OK(uc_reg_read(uc, UC_AVR_REG_R24, &r[24])); + TEST_CHECK(r[25] == 0 && r[24] == 0); + + OK(uc_close(uc)); +} + +TEST_LIST = { + {"test_avr_basic_alu", test_avr_basic_alu}, + {"test_avr_basic_mem", test_avr_basic_mem}, + {"test_avr_full_exec", test_avr_full_exec}, + {NULL, NULL} +}; diff --git a/uc.c b/uc.c index e1dcd4d549..811aabe2ff 100644 --- a/uc.c +++ b/uc.c @@ -26,6 +26,7 @@ #include "qemu/target/riscv/unicorn.h" #include "qemu/target/s390x/unicorn.h" #include "qemu/target/tricore/unicorn.h" +#include "qemu/target/avr/unicorn.h" #include "qemu/include/tcg/tcg-apple-jit.h" #include "qemu/include/qemu/queue.h" @@ -237,6 +238,10 @@ bool uc_arch_supported(uc_arch arch) #ifdef UNICORN_HAS_TRICORE case UC_ARCH_TRICORE: return true; +#endif +#ifdef UNICORN_HAS_AVR + case UC_ARCH_AVR: + return true; #endif /* Invalid or disabled arch */ default: @@ -474,6 +479,15 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) } uc->init_arch = uc_init_tricore; break; +#endif +#ifdef UNICORN_HAS_AVR + case UC_ARCH_AVR: + if ((mode & ~UC_MODE_AVR_MASK)) { + free(uc); + return UC_ERR_MODE; + } + uc->init_arch = uc_init_avr; + break; #endif } @@ -1057,6 +1071,11 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, case UC_ARCH_TRICORE: uc_reg_write(uc, UC_TRICORE_REG_PC, &begin_pc32); break; +#endif +#ifdef UNICORN_HAS_AVR + case UC_ARCH_AVR: + uc_reg_write(uc, UC_AVR_REG_PC, &begin_pc32); + break; #endif } @@ -2291,6 +2310,12 @@ static context_reg_rw_t find_context_reg_rw(uc_arch arch, uc_mode mode) rw.read = reg_read_tricore; rw.write = reg_write_tricore; break; +#endif +#ifdef UNICORN_HAS_AVR + case UC_ARCH_AVR: + rw.read = reg_read_avr; + rw.write = reg_write_avr; + break; #endif } @@ -2720,6 +2745,11 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) err = UC_ERR_ARG; break; } + } else if (uc->arch == UC_ARCH_AVR) { + if (!avr_cpu_model_valid(model)) { + err = UC_ERR_ARG; + break; + } } else { err = UC_ERR_ARG; break;