summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt6
-rw-r--r--Doxyfile2369
-rw-r--r--doc-icon.pngbin0 -> 8791 bytes
-rw-r--r--externals/inih/CMakeLists.txt11
m---------externals/inih/inih0
-rw-r--r--src/citra/CMakeLists.txt5
-rw-r--r--src/citra/citra.cpp11
-rw-r--r--src/citra/config.cpp77
-rw-r--r--src/citra/config.h26
-rw-r--r--src/citra/default_ini.h37
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp57
-rw-r--r--src/citra/emu_window/emu_window_glfw.h18
-rw-r--r--src/citra_qt/CMakeLists.txt2
-rw-r--r--src/citra_qt/bootmanager.cpp89
-rw-r--r--src/citra_qt/bootmanager.hxx21
-rw-r--r--src/citra_qt/config.cpp110
-rw-r--r--src/citra_qt/config.h27
-rw-r--r--src/citra_qt/debugger/disassembler.cpp2
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.hxx2
-rw-r--r--src/citra_qt/main.cpp18
-rw-r--r--src/citra_qt/main.hxx2
-rw-r--r--src/common/CMakeLists.txt4
-rw-r--r--src/common/bit_field.h2
-rw-r--r--src/common/chunk_file.h244
-rw-r--r--src/common/common.h6
-rw-r--r--src/common/common_paths.h45
-rw-r--r--src/common/common_types.h45
-rw-r--r--src/common/console_listener.cpp26
-rw-r--r--src/common/console_listener.h2
-rw-r--r--src/common/emu_window.cpp17
-rw-r--r--src/common/emu_window.h28
-rw-r--r--src/common/extended_trace.cpp2
-rw-r--r--src/common/file_search.cpp10
-rw-r--r--src/common/file_util.cpp194
-rw-r--r--src/common/file_util.h64
-rw-r--r--src/common/fixed_size_queue.h70
-rw-r--r--src/common/key_map.cpp25
-rw-r--r--src/common/key_map.h45
-rw-r--r--src/common/log.h1
-rw-r--r--src/common/log_manager.cpp6
-rw-r--r--src/common/log_manager.h4
-rw-r--r--src/common/math_util.cpp3
-rw-r--r--src/common/mem_arena.cpp6
-rw-r--r--src/common/memory_util.cpp5
-rw-r--r--src/common/msg_handler.cpp2
-rw-r--r--src/common/string_util.cpp204
-rw-r--r--src/common/string_util.h17
-rw-r--r--src/common/swap.h1
-rw-r--r--src/common/thread.cpp1
-rw-r--r--src/common/timer.cpp7
-rw-r--r--src/common/utf8.cpp4
-rw-r--r--src/core/CMakeLists.txt111
-rw-r--r--src/core/arm/disassembler/arm_disasm.cpp78
-rw-r--r--src/core/arm/disassembler/load_symbol_map.cpp3
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp166
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h90
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.cpp402
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.h155
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp6564
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.h7
-rw-r--r--src/core/arm/dyncom/arm_dyncom_run.cpp120
-rw-r--r--src/core/arm/dyncom/arm_dyncom_run.h55
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp521
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.h51
-rw-r--r--src/core/arm/interpreter/arm_interpreter.cpp5
-rw-r--r--src/core/arm/interpreter/arm_interpreter.h28
-rw-r--r--src/core/arm/interpreter/armcopro.cpp1007
-rw-r--r--src/core/arm/interpreter/armemu.cpp285
-rw-r--r--src/core/arm/interpreter/arminit.cpp4
-rw-r--r--src/core/arm/interpreter/armmmu.cpp238
-rw-r--r--src/core/arm/interpreter/armos.cpp742
-rw-r--r--src/core/arm/interpreter/armsupp.cpp15
-rw-r--r--src/core/arm/interpreter/armvirt.cpp685
-rw-r--r--src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp1132
-rw-r--r--src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h37
-rw-r--r--src/core/arm/interpreter/mmu/cache.cpp370
-rw-r--r--src/core/arm/interpreter/mmu/cache.h168
-rw-r--r--src/core/arm/interpreter/mmu/maverick.cpp1206
-rw-r--r--src/core/arm/interpreter/mmu/rb.cpp126
-rw-r--r--src/core/arm/interpreter/mmu/rb.h55
-rw-r--r--src/core/arm/interpreter/mmu/sa_mmu.cpp864
-rw-r--r--src/core/arm/interpreter/mmu/sa_mmu.h58
-rw-r--r--src/core/arm/interpreter/mmu/tlb.cpp307
-rw-r--r--src/core/arm/interpreter/mmu/tlb.h87
-rw-r--r--src/core/arm/interpreter/mmu/wb.cpp149
-rw-r--r--src/core/arm/interpreter/mmu/wb.h63
-rw-r--r--src/core/arm/interpreter/mmu/xscale_copro.cpp1391
-rw-r--r--src/core/arm/interpreter/thumbemu.cpp8
-rw-r--r--src/core/arm/interpreter/vfp/vfp.cpp357
-rw-r--r--src/core/arm/interpreter/vfp/vfpdouble.cpp1263
-rw-r--r--src/core/arm/interpreter/vfp/vfpsingle.cpp1278
-rw-r--r--src/core/arm/skyeye_common/arm_regformat.h (renamed from src/core/arm/interpreter/arm_regformat.h)4
-rw-r--r--src/core/arm/skyeye_common/armcpu.h (renamed from src/core/arm/interpreter/armcpu.h)5
-rw-r--r--src/core/arm/skyeye_common/armdefs.h (renamed from src/core/arm/interpreter/armdefs.h)5
-rw-r--r--src/core/arm/skyeye_common/armemu.h (renamed from src/core/arm/interpreter/armemu.h)2
-rw-r--r--src/core/arm/skyeye_common/armmmu.h (renamed from src/core/arm/interpreter/armmmu.h)117
-rw-r--r--src/core/arm/skyeye_common/armos.h (renamed from src/core/arm/interpreter/armos.h)9
-rw-r--r--src/core/arm/skyeye_common/skyeye_defs.h (renamed from src/core/arm/interpreter/skyeye_defs.h)4
-rw-r--r--src/core/arm/skyeye_common/skyeye_types.h55
-rw-r--r--src/core/arm/skyeye_common/vfp/asm_vfp.h (renamed from src/core/arm/interpreter/vfp/asm_vfp.h)0
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp397
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h (renamed from src/core/arm/interpreter/vfp/vfp.h)26
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h (renamed from src/core/arm/interpreter/vfp/vfp_helper.h)19
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp1432
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp (renamed from src/core/arm/interpreter/vfp/vfpinstr.cpp)48
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp1356
-rw-r--r--src/core/core.cpp23
-rw-r--r--src/core/core.h19
-rw-r--r--src/core/core_timing.cpp12
-rw-r--r--src/core/file_sys/archive.h134
-rw-r--r--src/core/file_sys/archive_romfs.cpp33
-rw-r--r--src/core/file_sys/archive_romfs.h22
-rw-r--r--src/core/file_sys/archive_sdmc.cpp129
-rw-r--r--src/core/file_sys/archive_sdmc.h97
-rw-r--r--src/core/file_sys/directory.h59
-rw-r--r--src/core/file_sys/directory_romfs.cpp38
-rw-r--r--src/core/file_sys/directory_romfs.h37
-rw-r--r--src/core/file_sys/directory_sdmc.cpp81
-rw-r--r--src/core/file_sys/directory_sdmc.h48
-rw-r--r--src/core/file_sys/file.h66
-rw-r--r--src/core/file_sys/file_romfs.cpp76
-rw-r--r--src/core/file_sys/file_romfs.h67
-rw-r--r--src/core/file_sys/file_sdmc.cpp107
-rw-r--r--src/core/file_sys/file_sdmc.h75
-rw-r--r--src/core/hle/config_mem.cpp1
-rw-r--r--src/core/hle/coprocessor.cpp1
-rw-r--r--src/core/hle/coprocessor.h20
-rw-r--r--src/core/hle/hle.cpp1
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp8
-rw-r--r--src/core/hle/kernel/archive.cpp263
-rw-r--r--src/core/hle/kernel/archive.h32
-rw-r--r--src/core/hle/kernel/event.cpp8
-rw-r--r--src/core/hle/kernel/kernel.cpp45
-rw-r--r--src/core/hle/kernel/kernel.h1
-rw-r--r--src/core/hle/kernel/mutex.cpp10
-rw-r--r--src/core/hle/kernel/shared_memory.cpp6
-rw-r--r--src/core/hle/kernel/thread.cpp11
-rw-r--r--src/core/hle/service/ac_u.cpp44
-rw-r--r--src/core/hle/service/ac_u.h (renamed from src/core/hle/service/hid.h)13
-rw-r--r--src/core/hle/service/apt_u.cpp (renamed from src/core/hle/service/apt.cpp)113
-rw-r--r--src/core/hle/service/apt_u.h (renamed from src/core/hle/service/apt.h)2
-rw-r--r--src/core/hle/service/cfg_u.cpp36
-rw-r--r--src/core/hle/service/cfg_u.h27
-rw-r--r--src/core/hle/service/dsp_dsp.cpp52
-rw-r--r--src/core/hle/service/dsp_dsp.h27
-rw-r--r--src/core/hle/service/err_f.cpp27
-rw-r--r--src/core/hle/service/err_f.h27
-rw-r--r--src/core/hle/service/frd_u.cpp35
-rw-r--r--src/core/hle/service/frd_u.h27
-rw-r--r--src/core/hle/service/fs.cpp148
-rw-r--r--src/core/hle/service/fs_user.cpp352
-rw-r--r--src/core/hle/service/fs_user.h (renamed from src/core/hle/service/fs.h)2
-rw-r--r--src/core/hle/service/gsp_gpu.cpp (renamed from src/core/hle/service/gsp.cpp)4
-rw-r--r--src/core/hle/service/gsp_gpu.h (renamed from src/core/hle/service/gsp.h)2
-rw-r--r--src/core/hle/service/hid.cpp72
-rw-r--r--src/core/hle/service/hid_user.cpp205
-rw-r--r--src/core/hle/service/hid_user.h120
-rw-r--r--src/core/hle/service/mic_u.cpp43
-rw-r--r--src/core/hle/service/mic_u.h29
-rw-r--r--src/core/hle/service/ndm_u.cpp (renamed from src/core/hle/service/ndm.cpp)4
-rw-r--r--src/core/hle/service/ndm_u.h (renamed from src/core/hle/service/ndm.h)2
-rw-r--r--src/core/hle/service/nwm_uds.cpp35
-rw-r--r--src/core/hle/service/nwm_uds.h29
-rw-r--r--src/core/hle/service/ptm_u.cpp42
-rw-r--r--src/core/hle/service/ptm_u.h29
-rw-r--r--src/core/hle/service/service.cpp35
-rw-r--r--src/core/hle/service/service.h10
-rw-r--r--src/core/hle/service/soc_u.cpp58
-rw-r--r--src/core/hle/service/soc_u.h27
-rw-r--r--src/core/hle/service/srv.cpp3
-rw-r--r--src/core/hle/service/srv.h2
-rw-r--r--src/core/hle/service/ssl_c.cpp31
-rw-r--r--src/core/hle/service/ssl_c.h27
-rw-r--r--src/core/hle/svc.cpp11
-rw-r--r--src/core/hw/gpu.cpp41
-rw-r--r--src/core/hw/gpu.h19
-rw-r--r--src/core/hw/hw.cpp5
-rw-r--r--src/core/hw/ndma.cpp5
-rw-r--r--src/core/loader/elf.cpp2
-rw-r--r--src/core/loader/loader.cpp34
-rw-r--r--src/core/loader/ncch.cpp6
-rw-r--r--src/core/mem_map.cpp1
-rw-r--r--src/core/mem_map_funcs.cpp3
-rw-r--r--src/core/settings.cpp11
-rw-r--r--src/core/settings.h37
-rw-r--r--src/video_core/clipper.cpp10
-rw-r--r--src/video_core/command_processor.cpp14
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp10
-rw-r--r--src/video_core/gpu_debugger.h2
-rw-r--r--src/video_core/pica.h4
-rw-r--r--src/video_core/rasterizer.cpp12
-rw-r--r--src/video_core/renderer_base.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h46
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp329
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h88
-rw-r--r--src/video_core/utils.cpp32
-rw-r--r--src/video_core/utils.h2
-rw-r--r--src/video_core/vertex_shader.cpp2
-rw-r--r--src/video_core/vertex_shader.h2
-rw-r--r--src/video_core/video_core.cpp7
-rw-r--r--src/video_core/video_core.h5
204 files changed, 18674 insertions, 13068 deletions
diff --git a/.gitignore b/.gitignore
index cc8abe9ff..659736ff5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# Build directory
build/
+doc-build/
# Generated source files
src/common/scm_rev.cpp
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..d7201387a
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "externals/inih/inih"]
+ path = externals/inih/inih
+ url = https://github.com/svn2github/inih
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 83b0863f9..bbe9f76cd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -68,7 +68,7 @@ if (ENABLE_GLFW)
if (NOT APPLE)
find_package(X11 REQUIRED)
endif()
-
+
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
endif()
@@ -127,6 +127,10 @@ get_git_head_revision(GIT_REF_SPEC GIT_REV)
git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
+set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih")
+include_directories(${INI_PREFIX})
+add_subdirectory(${INI_PREFIX})
+
# process subdirectories
if(ENABLE_QT)
include_directories(externals/qhexedit)
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 000000000..981121d92
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2369 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = Citra
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "Nintendo 3DS emulator/debugger"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO = doc-icon.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc-build/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = YES
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = src/
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doc-icon.png b/doc-icon.png
new file mode 100644
index 000000000..420b1546f
--- /dev/null
+++ b/doc-icon.png
Binary files differ
diff --git a/externals/inih/CMakeLists.txt b/externals/inih/CMakeLists.txt
new file mode 100644
index 000000000..c87f78bfc
--- /dev/null
+++ b/externals/inih/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(SRCS
+ inih/ini.c
+ inih/cpp/INIReader.cpp
+ )
+set(HEADERS
+ inih/ini.h
+ inih/cpp/INIReader.h
+ )
+
+create_directory_groups(${SRCS} ${HEADERS})
+add_library(inih ${SRCS} ${HEADERS})
diff --git a/externals/inih/inih b/externals/inih/inih
new file mode 160000
+Subproject 603729dec89aaca42d7bd08f08bc333165b7d5d
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt
index f10f3e603..f2add394f 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -1,9 +1,12 @@
set(SRCS
emu_window/emu_window_glfw.cpp
citra.cpp
+ config.cpp
)
set(HEADERS
emu_window/emu_window_glfw.h
+ config.h
+ default_ini.h
resource.h
)
@@ -16,7 +19,7 @@ endif()
add_executable(citra ${SRCS} ${HEADERS})
target_link_libraries(citra core common video_core)
-target_link_libraries(citra ${OPENGL_gl_LIBRARY} ${GLFW_LIBRARIES})
+target_link_libraries(citra ${OPENGL_gl_LIBRARY} ${GLFW_LIBRARIES} inih)
if (APPLE)
target_link_libraries(citra iconv pthread ${COREFOUNDATION_LIBRARY})
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index 7dc721dc3..6ac5c5dc5 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -4,12 +4,12 @@
#include "common/common.h"
#include "common/log_manager.h"
-#include "common/file_util.h"
#include "core/system.h"
#include "core/core.h"
#include "core/loader/loader.h"
+#include "citra/config.h"
#include "citra/emu_window/emu_window_glfw.h"
/// Application entry point
@@ -21,17 +21,20 @@ int __cdecl main(int argc, char **argv) {
return -1;
}
+ Config config;
+
std::string boot_filename = argv[1];
EmuWindow_GLFW* emu_window = new EmuWindow_GLFW;
System::Init(emu_window);
- if (Loader::ResultStatus::Success != Loader::LoadFile(boot_filename)) {
- ERROR_LOG(BOOT, "Failed to load ROM!");
+ Loader::ResultStatus load_result = Loader::LoadFile(boot_filename);
+ if (Loader::ResultStatus::Success != load_result) {
+ ERROR_LOG(BOOT, "Failed to load ROM (Error %i)!", load_result);
return -1;
}
- while(true) {
+ while (emu_window->IsOpen()) {
Core::RunLoop();
}
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
new file mode 100644
index 000000000..c5ce8a164
--- /dev/null
+++ b/src/citra/config.cpp
@@ -0,0 +1,77 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <GLFW/glfw3.h>
+
+#include "citra/default_ini.h"
+#include "common/file_util.h"
+#include "core/settings.h"
+#include "core/core.h"
+
+#include "config.h"
+
+Config::Config() {
+ // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
+ glfw_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "glfw-config.ini";
+ glfw_config = new INIReader(glfw_config_loc);
+
+ Reload();
+}
+
+bool Config::LoadINI(INIReader* config, const char* location, const std::string& default_contents, bool retry) {
+ if (config->ParseError() < 0) {
+ if (retry) {
+ ERROR_LOG(CONFIG, "Failed to load %s. Creating file from defaults...", location);
+ FileUtil::CreateFullPath(location);
+ FileUtil::WriteStringToFile(true, default_contents, location);
+ *config = INIReader(location); // Reopen file
+
+ return LoadINI(config, location, default_contents, false);
+ }
+ ERROR_LOG(CONFIG, "Failed.");
+ return false;
+ }
+ INFO_LOG(CONFIG, "Successfully loaded %s", location);
+ return true;
+}
+
+void Config::ReadControls() {
+ Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A);
+ Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S);
+ Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z);
+ Settings::values.pad_y_key = glfw_config->GetInteger("Controls", "pad_y", GLFW_KEY_X);
+ Settings::values.pad_l_key = glfw_config->GetInteger("Controls", "pad_l", GLFW_KEY_Q);
+ Settings::values.pad_r_key = glfw_config->GetInteger("Controls", "pad_r", GLFW_KEY_W);
+ Settings::values.pad_start_key = glfw_config->GetInteger("Controls", "pad_start", GLFW_KEY_M);
+ Settings::values.pad_select_key = glfw_config->GetInteger("Controls", "pad_select", GLFW_KEY_N);
+ Settings::values.pad_home_key = glfw_config->GetInteger("Controls", "pad_home", GLFW_KEY_B);
+ Settings::values.pad_dup_key = glfw_config->GetInteger("Controls", "pad_dup", GLFW_KEY_T);
+ Settings::values.pad_ddown_key = glfw_config->GetInteger("Controls", "pad_ddown", GLFW_KEY_G);
+ Settings::values.pad_dleft_key = glfw_config->GetInteger("Controls", "pad_dleft", GLFW_KEY_F);
+ Settings::values.pad_dright_key = glfw_config->GetInteger("Controls", "pad_dright", GLFW_KEY_H);
+ Settings::values.pad_sup_key = glfw_config->GetInteger("Controls", "pad_sup", GLFW_KEY_UP);
+ Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN);
+ Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT);
+ Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT);
+}
+
+void Config::ReadCore() {
+ Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter);
+ Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 60);
+}
+
+void Config::ReadData() {
+ Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true);
+}
+
+void Config::Reload() {
+ LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file);
+ ReadControls();
+ ReadCore();
+ ReadData();
+}
+
+Config::~Config() {
+ delete glfw_config;
+}
diff --git a/src/citra/config.h b/src/citra/config.h
new file mode 100644
index 000000000..4f6551876
--- /dev/null
+++ b/src/citra/config.h
@@ -0,0 +1,26 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <map>
+
+#include <inih/cpp/INIReader.h>
+
+#include "common/common_types.h"
+
+class Config {
+ INIReader* glfw_config;
+ std::string glfw_config_loc;
+
+ bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true);
+ void ReadControls();
+ void ReadCore();
+ void ReadData();
+public:
+ Config();
+ ~Config();
+
+ void Reload();
+};
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
new file mode 100644
index 000000000..557da881b
--- /dev/null
+++ b/src/citra/default_ini.h
@@ -0,0 +1,37 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace DefaultINI {
+
+const char* glfw_config_file = R"(
+[Controls]
+pad_start =
+pad_select =
+pad_home =
+pad_dup =
+pad_ddown =
+pad_dleft =
+pad_dright =
+pad_a =
+pad_b =
+pad_x =
+pad_y =
+pad_r =
+pad_l =
+pad_sup =
+pad_sdown =
+pad_sleft =
+pad_sright =
+
+[Core]
+cpu_core = ## 0: Interpreter (default), 1: FastInterpreter (experimental)
+gpu_refresh_rate = ## 60 (default)
+
+[Data Storage]
+use_virtual_sd =
+)";
+
+}
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 02f524e03..0c774bbc5 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -6,20 +6,40 @@
#include "video_core/video_core.h"
+#include "core/settings.h"
+
#include "citra/emu_window/emu_window_glfw.h"
-static void OnKeyEvent(GLFWwindow* win, int key, int action) {
- // TODO(bunnei): ImplementMe
+/// Called by GLFW when a key event occurs
+void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) {
+
+ if (!VideoCore::g_emu_window) {
+ return;
+ }
+
+ int keyboard_id = ((EmuWindow_GLFW*)VideoCore::g_emu_window)->keyboard_id;
+
+ if (action == GLFW_PRESS) {
+ EmuWindow::KeyPressed({key, keyboard_id});
+ }
+
+ if (action == GLFW_RELEASE) {
+ EmuWindow::KeyReleased({key, keyboard_id});
+ }
+ HID_User::PadUpdateComplete();
}
-static void OnWindowSizeEvent(GLFWwindow* win, int width, int height) {
- EmuWindow_GLFW* emu_window = (EmuWindow_GLFW*)glfwGetWindowUserPointer(win);
- emu_window->SetClientAreaWidth(width);
- emu_window->SetClientAreaHeight(height);
+/// Whether the window is still open, and a close request hasn't yet been sent
+const bool EmuWindow_GLFW::IsOpen() {
+ return glfwWindowShouldClose(m_render_window) == 0;
}
/// EmuWindow_GLFW constructor
EmuWindow_GLFW::EmuWindow_GLFW() {
+ keyboard_id = KeyMap::NewDeviceId();
+
+ ReloadSetKeymaps();
+
// Initialize the window
if(glfwInit() != GL_TRUE) {
printf("Failed to initialize GLFW! Exiting...");
@@ -27,12 +47,9 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
-
-#if EMU_PLATFORM == PLATFORM_MACOSX
// GLFW on OSX requires these window hints to be set to create a 3.2+ GL context.
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-#endif
m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth,
(VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight),
@@ -45,8 +62,7 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
// Setup callbacks
glfwSetWindowUserPointer(m_render_window, this);
- //glfwSetKeyCallback(m_render_window, OnKeyEvent);
- //glfwSetWindowSizeCallback(m_render_window, OnWindowSizeEvent);
+ glfwSetKeyCallback(m_render_window, OnKeyEvent);
DoneCurrent();
}
@@ -75,3 +91,22 @@ void EmuWindow_GLFW::MakeCurrent() {
void EmuWindow_GLFW::DoneCurrent() {
glfwMakeContextCurrent(NULL);
}
+
+void EmuWindow_GLFW::ReloadSetKeymaps() {
+ KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A);
+ KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B);
+ KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT);
+ KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START);
+ KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT);
+ KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT);
+ KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP);
+ KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN);
+ KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R);
+ KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L);
+ KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X);
+ KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y);
+ KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT);
+ KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT);
+ KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP);
+ KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN);
+}
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h
index c1b41203b..7c3072145 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -14,19 +14,27 @@ public:
~EmuWindow_GLFW();
/// Swap buffers to display the next frame
- void SwapBuffers();
+ void SwapBuffers() override;
/// Polls window events
- void PollEvents();
+ void PollEvents() override;
/// Makes the graphics context current for the caller thread
- void MakeCurrent();
+ void MakeCurrent() override;
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
- void DoneCurrent();
+ void DoneCurrent() override;
- GLFWwindow* m_render_window; ///< Internal GLFW render window
+ static void OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods);
+
+ /// Whether the window is still open, and a close request hasn't yet been sent
+ const bool IsOpen();
+
+ void ReloadSetKeymaps() override;
private:
+ GLFWwindow* m_render_window; ///< Internal GLFW render window
+ /// Device id of keyboard for use with KeyMap
+ int keyboard_id;
};
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 426e4ef99..98a48a69a 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -4,6 +4,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(SRCS
config/controller_config.cpp
config/controller_config_util.cpp
+ config.cpp
debugger/callstack.cpp
debugger/disassembler.cpp
debugger/graphics.cpp
@@ -18,6 +19,7 @@ set(SRCS
set(HEADERS
config/controller_config.hxx
config/controller_config_util.hxx
+ config.h
debugger/callstack.hxx
debugger/disassembler.hxx
debugger/graphics.hxx
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 573060d30..20824692d 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -6,12 +6,11 @@
#include "bootmanager.hxx"
#include "core/core.h"
-#include "core/loader/loader.h"
-#include "core/hw/hw.h"
+#include "core/settings.h"
#include "video_core/video_core.h"
-#include "version.h"
+#include "citra_qt/version.h"
#define APP_NAME "citra"
#define APP_VERSION "0.1-" VERSION
@@ -19,9 +18,8 @@
#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
EmuThread::EmuThread(GRenderWindow* render_window) :
- exec_cpu_step(false), cpu_running(false),
- render_window(render_window), filename(""),
- stop_run(false)
+ filename(""), exec_cpu_step(false), cpu_running(false),
+ stop_run(false), render_window(render_window)
{
}
@@ -35,19 +33,16 @@ void EmuThread::run()
stop_run = false;
while (!stop_run)
{
- for (int tight_loop = 0; tight_loop < 10000; ++tight_loop)
+ if (cpu_running)
{
- if (cpu_running || exec_cpu_step)
- {
- if (exec_cpu_step)
- exec_cpu_step = false;
-
- Core::SingleStep();
- if (!cpu_running) {
- emit CPUStepped();
- yieldCurrentThread();
- }
- }
+ Core::RunLoop();
+ }
+ else if (exec_cpu_step)
+ {
+ exec_cpu_step = false;
+ Core::SingleStep();
+ emit CPUStepped();
+ yieldCurrentThread();
}
}
render_window->moveContext();
@@ -92,10 +87,10 @@ public:
parent_ = parent;
}
- void paintEvent(QPaintEvent* ev)
+ void paintEvent(QPaintEvent* ev) override
{
}
- void resizeEvent(QResizeEvent* ev) {
+ void resizeEvent(QResizeEvent* ev) override {
parent_->SetClientAreaWidth(size().width());
parent_->SetClientAreaHeight(size().height());
}
@@ -103,20 +98,22 @@ private:
GRenderWindow* parent_;
};
-
EmuThread& GRenderWindow::GetEmuThread()
{
return emu_thread;
}
-GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this)
+GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0)
{
+ keyboard_id = KeyMap::NewDeviceId();
+ ReloadSetKeymaps();
+
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose
QGLFormat fmt;
- fmt.setProfile(QGLFormat::CoreProfile);
fmt.setVersion(3,2);
- fmt.setSampleBuffers(true);
- fmt.setSamples(4);
+ fmt.setProfile(QGLFormat::CoreProfile);
+ // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X
+ fmt.setOption(QGL::NoDeprecatedFunctions);
child = new GGLWidgetInternal(fmt, this);
QBoxLayout* layout = new QHBoxLayout(this);
@@ -209,27 +206,33 @@ QByteArray GRenderWindow::saveGeometry()
void GRenderWindow::keyPressEvent(QKeyEvent* event)
{
- /*
- bool key_processed = false;
- for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel)
- if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED))
- key_processed = true;
-
- if (!key_processed)
- QWidget::keyPressEvent(event);
- */
+ EmuWindow::KeyPressed({event->key(), keyboard_id});
+ HID_User::PadUpdateComplete();
}
void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
{
- /*
- bool key_processed = false;
- for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel)
- if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::RELEASED))
- key_processed = true;
-
- if (!key_processed)
- QWidget::keyPressEvent(event);
- */
+ EmuWindow::KeyReleased({event->key(), keyboard_id});
+ HID_User::PadUpdateComplete();
+}
+
+void GRenderWindow::ReloadSetKeymaps()
+{
+ KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A);
+ KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B);
+ KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT);
+ KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START);
+ KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT);
+ KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT);
+ KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP);
+ KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN);
+ KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R);
+ KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L);
+ KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X);
+ KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y);
+ KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT);
+ KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT);
+ KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP);
+ KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN);
}
diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx
index 51cb781e9..f8afc403e 100644
--- a/src/citra_qt/bootmanager.hxx
+++ b/src/citra_qt/bootmanager.hxx
@@ -25,7 +25,7 @@ public:
*
* @warning Only call when not running!
*/
- void run();
+ void run() override;
/**
* Allow the CPU to process a single instruction (if cpu is not running)
@@ -89,13 +89,13 @@ public:
GRenderWindow(QWidget* parent = NULL);
~GRenderWindow();
- void closeEvent(QCloseEvent*);
+ void closeEvent(QCloseEvent*) override;
// EmuWindow implementation
- void SwapBuffers();
- void MakeCurrent();
- void DoneCurrent();
- void PollEvents();
+ void SwapBuffers() override;
+ void MakeCurrent() override;
+ void DoneCurrent() override;
+ void PollEvents() override;
void BackupGeometry();
void RestoreGeometry();
@@ -104,8 +104,10 @@ public:
EmuThread& GetEmuThread();
- void keyPressEvent(QKeyEvent* event);
- void keyReleaseEvent(QKeyEvent* event);
+ void keyPressEvent(QKeyEvent* event) override;
+ void keyReleaseEvent(QKeyEvent* event) override;
+
+ void ReloadSetKeymaps() override;
public slots:
void moveContext();
@@ -116,4 +118,7 @@ private:
EmuThread emu_thread;
QByteArray geometry;
+
+ /// Device id of keyboard for use with KeyMap
+ int keyboard_id;
};
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
new file mode 100644
index 000000000..63d396439
--- /dev/null
+++ b/src/citra_qt/config.cpp
@@ -0,0 +1,110 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <QString>
+#include <QStringList>
+
+#include "core/settings.h"
+#include "core/core.h"
+#include "common/file_util.h"
+
+#include "config.h"
+
+Config::Config() {
+
+ // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
+ qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini";
+ FileUtil::CreateFullPath(qt_config_loc);
+ qt_config = new QSettings(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
+
+ Reload();
+}
+
+void Config::ReadControls() {
+ qt_config->beginGroup("Controls");
+ Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt();
+ Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt();
+ Settings::values.pad_x_key = qt_config->value("pad_x", Qt::Key_Z).toInt();
+ Settings::values.pad_y_key = qt_config->value("pad_y", Qt::Key_X).toInt();
+ Settings::values.pad_l_key = qt_config->value("pad_l", Qt::Key_Q).toInt();
+ Settings::values.pad_r_key = qt_config->value("pad_r", Qt::Key_W).toInt();
+ Settings::values.pad_start_key = qt_config->value("pad_start", Qt::Key_M).toInt();
+ Settings::values.pad_select_key = qt_config->value("pad_select", Qt::Key_N).toInt();
+ Settings::values.pad_home_key = qt_config->value("pad_home", Qt::Key_B).toInt();
+ Settings::values.pad_dup_key = qt_config->value("pad_dup", Qt::Key_T).toInt();
+ Settings::values.pad_ddown_key = qt_config->value("pad_ddown", Qt::Key_G).toInt();
+ Settings::values.pad_dleft_key = qt_config->value("pad_dleft", Qt::Key_F).toInt();
+ Settings::values.pad_dright_key = qt_config->value("pad_dright", Qt::Key_H).toInt();
+ Settings::values.pad_sup_key = qt_config->value("pad_sup", Qt::Key_Up).toInt();
+ Settings::values.pad_sdown_key = qt_config->value("pad_sdown", Qt::Key_Down).toInt();
+ Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt();
+ Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt();
+ qt_config->endGroup();
+}
+
+void Config::SaveControls() {
+ qt_config->beginGroup("Controls");
+ qt_config->setValue("pad_a", Settings::values.pad_a_key);
+ qt_config->setValue("pad_b", Settings::values.pad_b_key);
+ qt_config->setValue("pad_x", Settings::values.pad_x_key);
+ qt_config->setValue("pad_y", Settings::values.pad_y_key);
+ qt_config->setValue("pad_l", Settings::values.pad_l_key);
+ qt_config->setValue("pad_r", Settings::values.pad_r_key);
+ qt_config->setValue("pad_start", Settings::values.pad_start_key);
+ qt_config->setValue("pad_select", Settings::values.pad_select_key);
+ qt_config->setValue("pad_home", Settings::values.pad_home_key);
+ qt_config->setValue("pad_dup", Settings::values.pad_dup_key);
+ qt_config->setValue("pad_ddown", Settings::values.pad_ddown_key);
+ qt_config->setValue("pad_dleft", Settings::values.pad_dleft_key);
+ qt_config->setValue("pad_dright", Settings::values.pad_dright_key);
+ qt_config->setValue("pad_sup", Settings::values.pad_sup_key);
+ qt_config->setValue("pad_sdown", Settings::values.pad_sdown_key);
+ qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key);
+ qt_config->setValue("pad_sright", Settings::values.pad_sright_key);
+ qt_config->endGroup();
+}
+
+void Config::ReadCore() {
+ qt_config->beginGroup("Core");
+ Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt();
+ Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 60).toInt();
+ qt_config->endGroup();
+}
+
+void Config::SaveCore() {
+ qt_config->beginGroup("Core");
+ qt_config->setValue("cpu_core", Settings::values.cpu_core);
+ qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate);
+ qt_config->endGroup();
+}
+
+void Config::ReadData() {
+ qt_config->beginGroup("Data Storage");
+ Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
+ qt_config->endGroup();
+}
+
+void Config::SaveData() {
+ qt_config->beginGroup("Data Storage");
+ qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
+ qt_config->endGroup();
+}
+
+void Config::Reload() {
+ ReadControls();
+ ReadCore();
+ ReadData();
+}
+
+void Config::Save() {
+ SaveControls();
+ SaveCore();
+ SaveData();
+}
+
+Config::~Config() {
+ Save();
+
+ delete qt_config;
+}
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h
new file mode 100644
index 000000000..782c26287
--- /dev/null
+++ b/src/citra_qt/config.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <QSettings>
+
+#include "common/common_types.h"
+
+class Config {
+ QSettings* qt_config;
+ std::string qt_config_loc;
+
+ void ReadControls();
+ void SaveControls();
+ void ReadCore();
+ void SaveCore();
+ void ReadData();
+ void SaveData();
+public:
+ Config();
+ ~Config();
+
+ void Reload();
+ void Save();
+};
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index 856baf63d..2ee877743 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -9,7 +9,7 @@
#include "core/core.h"
#include "common/break_points.h"
#include "common/symbols.h"
-#include "core/arm/interpreter/armdefs.h"
+#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/disassembler/arm_disasm.h"
DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractItemModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) {
diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx
index 479ef0326..1523e724f 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.hxx
+++ b/src/citra_qt/debugger/graphics_cmdlists.hxx
@@ -17,7 +17,7 @@ class GPUCommandListModel : public QAbstractListModel
public:
GPUCommandListModel(QObject* parent);
- int columnCount(const QModelIndex& parent = QModelIndex()) const;
+ int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 1bf9bc53c..304c169b9 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -26,12 +26,16 @@
#include "core/core.h"
#include "core/loader/loader.h"
#include "core/arm/disassembler/load_symbol_map.h"
+#include "citra_qt/config.h"
#include "version.h"
GMainWindow::GMainWindow()
{
+ LogManager::Init();
+ Config config;
+
ui.setupUi(this);
statusBar()->hide();
@@ -112,8 +116,10 @@ GMainWindow::GMainWindow()
show();
- LogManager::Init();
- System::Init(render_window);
+ QStringList args = QApplication::arguments();
+ if (args.length() >= 2) {
+ BootGame(args[1].toStdString());
+ }
}
GMainWindow::~GMainWindow()
@@ -125,10 +131,11 @@ GMainWindow::~GMainWindow()
void GMainWindow::BootGame(std::string filename)
{
- NOTICE_LOG(MASTER_LOG, "citra starting...\n");
+ NOTICE_LOG(MASTER_LOG, "Citra starting...\n");
+ System::Init(render_window);
if (Core::Init()) {
- ERROR_LOG(MASTER_LOG, "core initialization failed, exiting...");
+ ERROR_LOG(MASTER_LOG, "Core initialization failed, exiting...");
Core::Stop();
exit(1);
}
@@ -146,6 +153,7 @@ void GMainWindow::BootGame(std::string filename)
render_window->GetEmuThread().start();
render_window->show();
+ OnStartGame();
}
void GMainWindow::OnMenuLoadFile()
@@ -182,6 +190,7 @@ void GMainWindow::OnPauseGame()
void GMainWindow::OnStopGame()
{
render_window->GetEmuThread().SetCpuRunning(false);
+ // TODO: Shutdown core
ui.action_Start->setEnabled(true);
ui.action_Pause->setEnabled(false);
@@ -243,7 +252,6 @@ int __cdecl main(int argc, char* argv[])
QApplication::setAttribute(Qt::AA_X11InitThreads);
QApplication app(argc, argv);
GMainWindow main_window;
-
main_window.show();
return app.exec();
}
diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx
index a0b41f5f4..b1b40df46 100644
--- a/src/citra_qt/main.hxx
+++ b/src/citra_qt/main.hxx
@@ -32,7 +32,7 @@ public:
private:
void BootGame(std::string filename);
- void closeEvent(QCloseEvent* event);
+ void closeEvent(QCloseEvent* event) override;
private slots:
void OnStartGame();
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 868fda55e..9d5a90762 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -4,10 +4,12 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU
set(SRCS
break_points.cpp
console_listener.cpp
+ emu_window.cpp
extended_trace.cpp
file_search.cpp
file_util.cpp
hash.cpp
+ key_map.cpp
log_manager.cpp
math_util.cpp
mem_arena.cpp
@@ -38,8 +40,8 @@ set(HEADERS
fifo_queue.h
file_search.h
file_util.h
- fixed_size_queue.h
hash.h
+ key_map.h
linear_disk_cache.h
log.h
log_manager.h
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index b6f0179c6..9e02210f9 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -68,7 +68,7 @@
* u32 hex;
*
* BitField<0,7,u32> first_seven_bits; // unsigned
- * BitField<7,8,32> next_eight_bits; // unsigned
+ * BitField<7,8,u32> next_eight_bits; // unsigned
* BitField<3,15,s32> some_signed_fields; // signed
* };
*
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index 2b0f120e6..dc8ac1fd9 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -32,35 +32,10 @@
#include <string>
#include <list>
#include <set>
-#ifndef __SYMBIAN32__
-#if defined(IOS) || defined(MACGNUSTD)
-#include <tr1/type_traits>
-#else
#include <type_traits>
-#endif
-#endif
#include "common/common.h"
#include "common/file_util.h"
-//#include "../ext/snappy/snappy-c.h"
-
-#if defined(IOS) || defined(MACGNUSTD)
-namespace std {
- using tr1::is_pointer;
-}
-#endif
-#ifdef __SYMBIAN32__
-namespace std {
- template <bool bool_value>
- struct bool_constant {
- typedef bool_constant<bool_value> type;
- static const bool value = bool_value;
- };
- template <bool bool_value> const bool bool_constant<bool_value>::value;
- template <typename T> struct is_pointer : public bool_constant<false> {};
- template <typename T> struct is_pointer<T*> : public bool_constant<true> {};
-}
-#endif
template <class T>
struct LinkedListItem : public T
@@ -651,222 +626,3 @@ inline PointerWrapSection::~PointerWrapSection() {
p_.DoMarker(title_);
}
}
-
-
-// Commented out because it is currently unused, and breaks builds on OSX
-/*class CChunkFileReader
-{
-public:
- enum Error {
- ERROR_NONE,
- ERROR_BAD_FILE,
- ERROR_BROKEN_STATE,
- };
-
- // Load file template
- template<class T>
- static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason)
- {
- INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str());
- _failureReason->clear();
- _failureReason->append("LoadStateWrongVersion");
-
- if (!File::Exists(_rFilename)) {
- _failureReason->clear();
- _failureReason->append("LoadStateDoesntExist");
- ERROR_LOG(COMMON, "ChunkReader: File doesn't exist");
- return ERROR_BAD_FILE;
- }
-
- // Check file size
- const u64 fileSize = File::GetSize(_rFilename);
- static const u64 headerSize = sizeof(SChunkHeader);
- if (fileSize < headerSize)
- {
- ERROR_LOG(COMMON,"ChunkReader: File too small");
- return ERROR_BAD_FILE;
- }
-
- File::IOFile pFile(_rFilename, "rb");
- if (!pFile)
- {
- ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading");
- return ERROR_BAD_FILE;
- }
-
- // read the header
- SChunkHeader header;
- if (!pFile.ReadArray(&header, 1))
- {
- ERROR_LOG(COMMON,"ChunkReader: Bad header size");
- return ERROR_BAD_FILE;
- }
-
- // Check revision
- if (header.Revision != _Revision)
- {
- ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d",
- header.Revision, _Revision);
- return ERROR_BAD_FILE;
- }
-
- if (strcmp(header.GitVersion, _VersionString) != 0)
- {
- WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.",
- header.GitVersion);
- }
-
- // get size
- const int sz = (int)(fileSize - headerSize);
- if (header.ExpectedSize != sz)
- {
- ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d",
- sz, header.ExpectedSize);
- return ERROR_BAD_FILE;
- }
-
- // read the state
- u8* buffer = new u8[sz];
- if (!pFile.ReadBytes(buffer, sz))
- {
- ERROR_LOG(COMMON,"ChunkReader: Error reading file");
- return ERROR_BAD_FILE;
- }
-
- u8 *ptr = buffer;
- u8 *buf = buffer;
- if (header.Compress) {
- u8 *uncomp_buffer = new u8[header.UncompressedSize];
- size_t uncomp_size = header.UncompressedSize;
- snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size);
- if ((int)uncomp_size != header.UncompressedSize) {
- ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size);
- }
- ptr = uncomp_buffer;
- buf = uncomp_buffer;
- delete [] buffer;
- }
-
- PointerWrap p(&ptr, PointerWrap::MODE_READ);
- _class.DoState(p);
- delete[] buf;
-
- INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str());
- if (p.error != p.ERROR_FAILURE) {
- return ERROR_NONE;
- } else {
- return ERROR_BROKEN_STATE;
- }
- }
-
- // Save file template
- template<class T>
- static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class)
- {
- INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str());
-
- File::IOFile pFile(_rFilename, "wb");
- if (!pFile)
- {
- ERROR_LOG(COMMON,"ChunkReader: Error opening file for write");
- return ERROR_BAD_FILE;
- }
-
- bool compress = true;
-
- // Get data
- u8 *ptr = 0;
- PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
- _class.DoState(p);
- size_t const sz = (size_t)ptr;
-
- u8 * buffer = new u8[sz];
- ptr = &buffer[0];
- p.SetMode(PointerWrap::MODE_WRITE);
- _class.DoState(p);
-
- // Create header
- SChunkHeader header;
- header.Compress = compress ? 1 : 0;
- header.Revision = _Revision;
- header.ExpectedSize = (int)sz;
- header.UncompressedSize = (int)sz;
- strncpy(header.GitVersion, _VersionString, 32);
- header.GitVersion[31] = '\0';
-
- // Write to file
- if (compress) {
- size_t comp_len = snappy_max_compressed_length(sz);
- u8 *compressed_buffer = new u8[comp_len];
- snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len);
- delete [] buffer;
- header.ExpectedSize = (int)comp_len;
- if (!pFile.WriteArray(&header, 1))
- {
- ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
- return ERROR_BAD_FILE;
- }
- if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) {
- ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data");
- return ERROR_BAD_FILE;
- } else {
- INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len);
- }
- delete [] compressed_buffer;
- } else {
- if (!pFile.WriteArray(&header, 1))
- {
- ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
- return ERROR_BAD_FILE;
- }
- if (!pFile.WriteBytes(&buffer[0], sz))
- {
- ERROR_LOG(COMMON,"ChunkReader: Failed writing data");
- return ERROR_BAD_FILE;
- }
- delete [] buffer;
- }
-
- INFO_LOG(COMMON,"ChunkReader: Done writing %s",
- _rFilename.c_str());
- if (p.error != p.ERROR_FAILURE) {
- return ERROR_NONE;
- } else {
- return ERROR_BROKEN_STATE;
- }
- }
-
- template <class T>
- static Error Verify(T& _class)
- {
- u8 *ptr = 0;
-
- // Step 1: Measure the space required.
- PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
- _class.DoState(p);
- size_t const sz = (size_t)ptr;
- std::vector<u8> buffer(sz);
-
- // Step 2: Dump the state.
- ptr = &buffer[0];
- p.SetMode(PointerWrap::MODE_WRITE);
- _class.DoState(p);
-
- // Step 3: Verify the state.
- ptr = &buffer[0];
- p.SetMode(PointerWrap::MODE_VERIFY);
- _class.DoState(p);
-
- return ERROR_NONE;
- }
-
-private:
- struct SChunkHeader
- {
- int Revision;
- int Compress;
- int ExpectedSize;
- int UncompressedSize;
- char GitVersion[32];
- };
-}; */
diff --git a/src/common/common.h b/src/common/common.h
index cb69eabe4..9f3016d34 100644
--- a/src/common/common.h
+++ b/src/common/common.h
@@ -20,11 +20,6 @@
#define STACKALIGN
-#if __cplusplus >= 201103L || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__)
-#define HAVE_CXX11_SYNTAX 1
-#endif
-
-#if HAVE_CXX11_SYNTAX
// An inheritable class to disallow the copy constructor and operator= functions
class NonCopyable
{
@@ -36,7 +31,6 @@ private:
NonCopyable(NonCopyable&);
NonCopyable& operator=(NonCopyable& other);
};
-#endif
#include "common/log.h"
#include "common/common_types.h"
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index a36de9227..ae08d082a 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -7,25 +7,25 @@
// Make sure we pick up USER_DIR if set in config.h
#include "common/common.h"
-// Directory seperators, do we need this?
+// Directory separators, do we need this?
#define DIR_SEP "/"
#define DIR_SEP_CHR '/'
#ifndef MAX_PATH
-#define MAX_PATH 260
+#define MAX_PATH 260
#endif
// The user data dir
#define ROOT_DIR "."
#ifdef _WIN32
#define USERDATA_DIR "user"
- #define EMU_DATA_DIR "emu"
+ #define EMU_DATA_DIR "Citra Emulator"
#else
#define USERDATA_DIR "user"
#ifdef USER_DIR
#define EMU_DATA_DIR USER_DIR
#else
- #define EMU_DATA_DIR ".emu"
+ #define EMU_DATA_DIR ".citra-emu"
#endif
#endif
@@ -48,29 +48,30 @@
#define JAP_DIR "JAP"
// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
-#define CONFIG_DIR "config"
-#define GAMECONFIG_DIR "game_config"
-#define MAPS_DIR "maps"
-#define CACHE_DIR "cache"
-#define SHADERCACHE_DIR "shader_cache"
-#define STATESAVES_DIR "state_saves"
-#define SCREENSHOTS_DIR "screenShots"
-#define DUMP_DIR "dump"
-#define DUMP_TEXTURES_DIR "textures"
-#define DUMP_FRAMES_DIR "frames"
-#define DUMP_AUDIO_DIR "audio"
-#define LOGS_DIR "logs"
-#define SHADERS_DIR "shaders"
-#define SYSCONF_DIR "sysconf"
+#define CONFIG_DIR "config"
+#define GAMECONFIG_DIR "game_config"
+#define MAPS_DIR "maps"
+#define CACHE_DIR "cache"
+#define SDMC_DIR "sdmc"
+#define SHADERCACHE_DIR "shader_cache"
+#define STATESAVES_DIR "state_saves"
+#define SCREENSHOTS_DIR "screenShots"
+#define DUMP_DIR "dump"
+#define DUMP_TEXTURES_DIR "textures"
+#define DUMP_FRAMES_DIR "frames"
+#define DUMP_AUDIO_DIR "audio"
+#define LOGS_DIR "logs"
+#define SHADERS_DIR "shaders"
+#define SYSCONF_DIR "sysconf"
// Filenames
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
#define EMU_CONFIG "emu.ini"
-#define DEBUGGER_CONFIG "debugger.ini"
-#define LOGGER_CONFIG "logger.ini"
+#define DEBUGGER_CONFIG "debugger.ini"
+#define LOGGER_CONFIG "logger.ini"
// Files in the directory returned by GetUserPath(D_LOGS_IDX)
-#define MAIN_LOG "emu.log"
+#define MAIN_LOG "emu.log"
// Files in the directory returned by GetUserPath(D_SYSCONF_IDX)
-#define SYSCONF "SYSCONF"
+#define SYSCONF "SYSCONF"
diff --git a/src/common/common_types.h b/src/common/common_types.h
index 9d41e5971..7ce6b2240 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -25,42 +25,21 @@
#pragma once
#include <cmath>
+#include <cstdint>
#include <xmmintrin.h> // data_types__m128.cpp
-#ifdef _WIN32
+typedef std::uint8_t u8; ///< 8-bit unsigned byte
+typedef std::uint16_t u16; ///< 16-bit unsigned short
+typedef std::uint32_t u32; ///< 32-bit unsigned word
+typedef std::uint64_t u64; ///< 64-bit unsigned int
-#include <tchar.h>
+typedef std::int8_t s8; ///< 8-bit signed byte
+typedef std::int16_t s16; ///< 16-bit signed short
+typedef std::int32_t s32; ///< 32-bit signed word
+typedef std::int64_t s64; ///< 64-bit signed int
-typedef unsigned __int8 u8; ///< 8-bit unsigned byte
-typedef unsigned __int16 u16; ///< 16-bit unsigned short
-typedef unsigned __int32 u32; ///< 32-bit unsigned word
-typedef unsigned __int64 u64; ///< 64-bit unsigned int
-
-typedef signed __int8 s8; ///< 8-bit signed byte
-typedef signed __int16 s16; ///< 16-bit signed short
-typedef signed __int32 s32; ///< 32-bit signed word
-typedef signed __int64 s64; ///< 64-bit signed int
-
-#else
-
-typedef unsigned char u8; ///< 8-bit unsigned byte
-typedef unsigned short u16; ///< 16-bit unsigned short
-typedef unsigned int u32; ///< 32-bit unsigned word
-typedef unsigned long long u64; ///< 64-bit unsigned int
-
-typedef signed char s8; ///< 8-bit signed byte
-typedef signed short s16; ///< 16-bit signed short
-typedef signed int s32; ///< 32-bit signed word
-typedef signed long long s64; ///< 64-bit signed int
-
-// For using windows lock code
-#define TCHAR char
-#define LONG int
-
-#endif // _WIN32
-
-typedef float f32; ///< 32-bit floating point
-typedef double f64; ///< 64-bit floating point
+typedef float f32; ///< 32-bit floating point
+typedef double f64; ///< 64-bit floating point
#include "common/common.h"
@@ -100,7 +79,7 @@ union t128 {
__m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers)
};
-namespace common {
+namespace Common {
/// Rectangle data structure
class Rect {
public:
diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp
index 27697ef1f..53f20d754 100644
--- a/src/common/console_listener.cpp
+++ b/src/common/console_listener.cpp
@@ -3,14 +3,10 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <cmath>
-#include <cstdio>
-#include <string>
+
#ifdef _WIN32
#include <windows.h>
#include <array>
-#else
-#include <cstdarg>
#endif
#include "common/common.h"
@@ -47,7 +43,7 @@ void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title
// Save the window handle that AllocConsole() created
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Set the console window title
- SetConsoleTitle(UTF8ToTStr(Title).c_str());
+ SetConsoleTitle(Common::UTF8ToTStr(Title).c_str());
// Set letter space
LetterSpace(80, 4000);
//MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
@@ -193,11 +189,11 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
{
Str.resize(Str.size() + 1);
if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead))
- SLog += StringFromFormat("WriteConsoleOutputCharacter error");
+ SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error");
Attr.resize(Attr.size() + 1);
if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead))
- SLog += StringFromFormat("WriteConsoleOutputAttribute error");
+ SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error");
// Break on error
if (cAttrRead == 0) break;
@@ -223,9 +219,9 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
for (size_t i = 0; i < Attr.size(); i++)
{
if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten))
- SLog += StringFromFormat("WriteConsoleOutputCharacter error");
+ SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error");
if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten))
- SLog += StringFromFormat("WriteConsoleOutputAttribute error");
+ SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error");
BytesWritten += cAttrWritten;
coordScreen = GetCoordinates(BytesWritten, LBufWidth);
@@ -245,16 +241,6 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
{
#if defined(_WIN32)
- /*
- const int MAX_BYTES = 1024*10;
- char Str[MAX_BYTES];
- va_list ArgPtr;
- int Cnt;
- va_start(ArgPtr, Text);
- Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr);
- va_end(ArgPtr);
- */
- DWORD cCharsWritten;
WORD Color;
switch (Level)
diff --git a/src/common/console_listener.h b/src/common/console_listener.h
index 3c0e420c6..ebd90a105 100644
--- a/src/common/console_listener.h
+++ b/src/common/console_listener.h
@@ -26,7 +26,7 @@ public:
#ifdef _WIN32
COORD GetCoordinates(int BytesRead, int BufferWidth);
#endif
- void Log(LogTypes::LOG_LEVELS, const char *Text);
+ void Log(LogTypes::LOG_LEVELS, const char *Text) override;
void ClearScreen(bool Cursor = true);
private:
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
new file mode 100644
index 000000000..7a2c50ac8
--- /dev/null
+++ b/src/common/emu_window.cpp
@@ -0,0 +1,17 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "emu_window.h"
+
+void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) {
+ HID_User::PadState mapped_key = KeyMap::GetPadKey(key);
+
+ HID_User::PadButtonPress(mapped_key);
+}
+
+void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) {
+ HID_User::PadState mapped_key = KeyMap::GetPadKey(key);
+
+ HID_User::PadButtonRelease(mapped_key);
+}
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 5e2c33d7a..4d09acb8b 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -6,6 +6,8 @@
#include "common/common.h"
#include "common/scm_rev.h"
+#include "common/string_util.h"
+#include "common/key_map.h"
// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL,
// QGLWidget, GLFW, etc...)
@@ -14,7 +16,7 @@ class EmuWindow
public:
/// Data structure to store an emuwindow configuration
- struct Config{
+ struct WindowConfig {
bool fullscreen;
int res_width;
int res_height;
@@ -32,11 +34,19 @@ public:
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
virtual void DoneCurrent() = 0;
- Config GetConfig() const {
+ virtual void ReloadSetKeymaps() = 0;
+
+ /// Signals a key press action to the HID module
+ static void KeyPressed(KeyMap::HostDeviceKey key);
+
+ /// Signals a key release action to the HID module
+ static void KeyReleased(KeyMap::HostDeviceKey key);
+
+ WindowConfig GetConfig() const {
return m_config;
}
- void SetConfig(const Config& val) {
+ void SetConfig(const WindowConfig& val) {
m_config = val;
}
@@ -65,11 +75,11 @@ public:
}
protected:
- EmuWindow() : m_client_area_width(640), m_client_area_height(480) {
- char window_title[255];
- sprintf(window_title, "Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
- m_window_title = window_title;
- }
+ EmuWindow():
+ m_client_area_width(640),
+ m_client_area_height(480),
+ m_window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc))
+ {}
virtual ~EmuWindow() {}
std::string m_window_title; ///< Current window title, should be used by window impl.
@@ -78,6 +88,6 @@ protected:
int m_client_area_height; ///< Current client height, should be set by window impl.
private:
- Config m_config; ///< Internal configuration
+ WindowConfig m_config; ///< Internal configuration
};
diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp
index 66dae4935..9cd0398ed 100644
--- a/src/common/extended_trace.cpp
+++ b/src/common/extended_trace.cpp
@@ -278,7 +278,7 @@ void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack)
GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo);
GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo);
- etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n");
+ etfprint(file, " " + Common::TStrToUTF8(srcInfo) + " : " + Common::TStrToUTF8(symInfo) + "\n");
}
void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file )
diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp
index a9d19477d..63580f688 100644
--- a/src/common/file_search.cpp
+++ b/src/common/file_search.cpp
@@ -4,15 +4,13 @@
#include "common/common.h"
-#include "common/common_paths.h"
+
#ifndef _WIN32
-#include <sys/types.h>
#include <dirent.h>
#else
#include <windows.h>
#endif
-#include <string>
#include <algorithm>
#include "common/file_search.h"
@@ -35,10 +33,10 @@ CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, cons
void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath)
{
std::string GCMSearchPath;
- BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
+ Common::BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
#ifdef _WIN32
WIN32_FIND_DATA findData;
- HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData);
+ HANDLE FindFirst = FindFirstFile(Common::UTF8ToTStr(GCMSearchPath).c_str(), &findData);
if (FindFirst != INVALID_HANDLE_VALUE)
{
@@ -49,7 +47,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
if (findData.cFileName[0] != '.')
{
std::string strFilename;
- BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName));
+ Common::BuildCompleteFilename(strFilename, _strPath, Common::TStrToUTF8(findData.cFileName));
m_FileNames.push_back(strFilename);
}
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index b6ff2e40b..35da07306 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -4,9 +4,7 @@
#include "common/common.h"
-#include "common/common_paths.h"
#include "common/file_util.h"
-#include "common/string_util.h"
#ifdef _WIN32
#include <windows.h>
@@ -15,11 +13,9 @@
#include <commdlg.h> // for GetSaveFileName
#include <io.h>
#include <direct.h> // getcwd
+#include <tchar.h>
#else
-#include <cerrno>
-#include <cstdlib>
#include <sys/param.h>
-#include <sys/types.h>
#include <dirent.h>
#endif
@@ -32,8 +28,6 @@
#include <algorithm>
#include <sys/stat.h>
-#include "common/string_util.h"
-
#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif
@@ -46,7 +40,7 @@
// This namespace has various generic functions related to files and paths.
// The code still needs a ton of cleanup.
// REMEMBER: strdup considered harmful!
-namespace File
+namespace FileUtil
{
// Remove any ending forward slashes from directory paths
@@ -71,7 +65,7 @@ bool Exists(const std::string &filename)
StripTailDirSlashes(copy);
#ifdef _WIN32
- int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info);
+ int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info);
#else
int result = stat64(copy.c_str(), &file_info);
#endif
@@ -88,7 +82,7 @@ bool IsDirectory(const std::string &filename)
StripTailDirSlashes(copy);
#ifdef _WIN32
- int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info);
+ int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info);
#else
int result = stat64(copy.c_str(), &file_info);
#endif
@@ -124,7 +118,7 @@ bool Delete(const std::string &filename)
}
#ifdef _WIN32
- if (!DeleteFile(UTF8ToTStr(filename).c_str()))
+ if (!DeleteFile(Common::UTF8ToTStr(filename).c_str()))
{
WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s",
filename.c_str(), GetLastErrorMsg());
@@ -146,7 +140,7 @@ bool CreateDir(const std::string &path)
{
INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
#ifdef _WIN32
- if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL))
+ if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), NULL))
return true;
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS)
@@ -179,7 +173,7 @@ bool CreateFullPath(const std::string &fullPath)
int panicCounter = 100;
INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str());
- if (File::Exists(fullPath))
+ if (FileUtil::Exists(fullPath))
{
INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str());
return true;
@@ -197,8 +191,10 @@ bool CreateFullPath(const std::string &fullPath)
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
std::string const subPath(fullPath.substr(0, position + 1));
- if (!File::IsDirectory(subPath))
- File::CreateDir(subPath);
+ if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
+ ERROR_LOG(COMMON, "CreateFullPath: directory creation failed");
+ return false;
+ }
// A safety check
panicCounter--;
@@ -218,14 +214,14 @@ bool DeleteDir(const std::string &filename)
INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str());
// check if a directory
- if (!File::IsDirectory(filename))
+ if (!FileUtil::IsDirectory(filename))
{
ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str());
return false;
}
#ifdef _WIN32
- if (::RemoveDirectory(UTF8ToTStr(filename).c_str()))
+ if (::RemoveDirectory(Common::UTF8ToTStr(filename).c_str()))
return true;
#else
if (rmdir(filename.c_str()) == 0)
@@ -254,7 +250,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
INFO_LOG(COMMON, "Copy: %s --> %s",
srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
- if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE))
+ if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE))
return true;
ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
@@ -342,7 +338,7 @@ u64 GetSize(const std::string &filename)
struct stat64 buf;
#ifdef _WIN32
- if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0)
+ if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0)
#else
if (stat64(filename.c_str(), &buf) == 0)
#endif
@@ -393,7 +389,7 @@ bool CreateEmptyFile(const std::string &filename)
{
INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
- if (!File::IOFile(filename, "wb"))
+ if (!FileUtil::IOFile(filename, "wb"))
{
ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s",
filename.c_str(), GetLastErrorMsg());
@@ -415,7 +411,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
- HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);
+ HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
FindClose(hFind);
@@ -425,7 +421,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
do
{
FSTEntry entry;
- const std::string virtualName(TStrToUTF8(ffd.cFileName));
+ const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = NULL;
@@ -482,7 +478,7 @@ bool DeleteDirRecursively(const std::string &directory)
#ifdef _WIN32
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
- HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);
+ HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
@@ -493,7 +489,7 @@ bool DeleteDirRecursively(const std::string &directory)
// windows loop
do
{
- const std::string virtualName(TStrToUTF8(ffd.cFileName));
+ const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = NULL;
DIR *dirp = opendir(directory.c_str());
@@ -526,7 +522,7 @@ bool DeleteDirRecursively(const std::string &directory)
}
else
{
- if (!File::Delete(newPath))
+ if (!FileUtil::Delete(newPath))
{
#ifndef _WIN32
closedir(dirp);
@@ -543,7 +539,7 @@ bool DeleteDirRecursively(const std::string &directory)
}
closedir(dirp);
#endif
- File::DeleteDir(directory);
+ FileUtil::DeleteDir(directory);
return true;
}
@@ -553,8 +549,8 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
{
#ifndef _WIN32
if (source_path == dest_path) return;
- if (!File::Exists(source_path)) return;
- if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);
+ if (!FileUtil::Exists(source_path)) return;
+ if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path);
struct dirent dirent, *result = NULL;
DIR *dirp = opendir(source_path.c_str());
@@ -576,10 +572,10 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
{
source += '/';
dest += '/';
- if (!File::Exists(dest)) File::CreateFullPath(dest);
+ if (!FileUtil::Exists(dest)) FileUtil::CreateFullPath(dest);
CopyDir(source, dest);
}
- else if (!File::Exists(dest)) File::Copy(source, dest);
+ else if (!FileUtil::Exists(dest)) FileUtil::Copy(source, dest);
}
closedir(dirp);
#endif
@@ -631,7 +627,7 @@ std::string& GetExeDirectory()
{
TCHAR Dolphin_exe_Path[2048];
GetModuleFileName(NULL, Dolphin_exe_Path, 2048);
- DolphinPath = TStrToUTF8(Dolphin_exe_Path);
+ DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path);
DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
}
return DolphinPath;
@@ -655,7 +651,7 @@ std::string GetSysDirectory()
return sysDir;
}
-// Returns a string with a Dolphin data dir or file in the user's home
+// Returns a string with a Citra data dir or file in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath)
{
@@ -667,7 +663,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
#ifdef _WIN32
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
#else
- if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
+ if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
else
paths[D_USER_IDX] = std::string(getenv("HOME") ?
@@ -675,27 +671,28 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP;
#endif
- paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
- paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
- paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
- paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
+ paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
+ paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
+ paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
+ paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
+ paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
- paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
+ paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
- paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
- paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
- paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
- paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
- paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
- paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
- paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
+ paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
+ paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
+ paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
+ paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
+ paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
+ paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
+ paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
}
if (!newPath.empty())
{
- if (!File::IsDirectory(newPath))
+ if (!FileUtil::IsDirectory(newPath))
{
WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str());
return paths[DirIDX];
@@ -708,43 +705,44 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
switch (DirIDX)
{
case D_ROOT_IDX:
- paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
- paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP;
- paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF;
+ paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
+ paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP;
+ paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF;
break;
case D_USER_IDX:
- paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
- paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
- paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
- paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
- paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
+ paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
+ paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
+ paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
+ paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
+ paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
+ paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
- paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
+ paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
- paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
- paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
- paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
- paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
- paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
+ paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
+ paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
+ paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
+ paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
+ paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP;
- paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
- paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
- paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
+ paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
+ paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
+ paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
break;
case D_CONFIG_IDX:
- paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
- paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
- paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
+ paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
+ paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
+ paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
break;
case D_DUMP_IDX:
- paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
- paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
- paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
+ paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
+ paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
+ paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
break;
case D_LOGS_IDX:
@@ -757,25 +755,25 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
//std::string GetThemeDir(const std::string& theme_name)
//{
-// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/";
+// std::string dir = FileUtil::GetUserPath(D_THEMES_IDX) + theme_name + "/";
//
//#if !defined(_WIN32)
// // If theme does not exist in user's dir load from shared directory
-// if (!File::Exists(dir))
+// if (!FileUtil::Exists(dir))
// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
//#endif
//
// return dir;
//}
-bool WriteStringToFile(bool text_file, const std::string &str, const char *filename)
+size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename)
{
- return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
+ return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
}
-bool ReadFileToString(bool text_file, const char *filename, std::string &str)
+size_t ReadFileToString(bool text_file, const char *filename, std::string &str)
{
- File::IOFile file(filename, text_file ? "r" : "rb");
+ FileUtil::IOFile file(filename, text_file ? "r" : "rb");
auto const f = file.GetHandle();
if (!f)
@@ -785,6 +783,48 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str)
return file.ReadArray(&str[0], str.size());
}
+/**
+ * Splits the filename into 8.3 format
+ * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename
+ * @param filename The normal filename to use
+ * @param short_name A 9-char array in which the short name will be written
+ * @param extension A 4-char array in which the extension will be written
+ */
+void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
+ std::array<char, 4>& extension) {
+ const std::string forbidden_characters = ".\"/\\[]:;=, ";
+
+ // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces.
+ short_name = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'};
+ extension = {' ', ' ', ' ', '\0'};
+
+ std::string::size_type point = filename.rfind('.');
+ if (point == filename.size() - 1)
+ point = filename.rfind('.', point);
+
+ // Get short name.
+ int j = 0;
+ for (char letter : filename.substr(0, point)) {
+ if (forbidden_characters.find(letter, 0) != std::string::npos)
+ continue;
+ if (j == 8) {
+ // TODO(Link Mauve): also do that for filenames containing a space.
+ // TODO(Link Mauve): handle multiple files having the same short name.
+ short_name[6] = '~';
+ short_name[7] = '1';
+ break;
+ }
+ short_name[j++] = toupper(letter);
+ }
+
+ // Get extension.
+ if (point != std::string::npos) {
+ j = 0;
+ for (char letter : filename.substr(point + 1, 3))
+ extension[j++] = toupper(letter);
+ }
+}
+
IOFile::IOFile()
: m_file(NULL), m_good(true)
{}
@@ -826,7 +866,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
{
Close();
#ifdef _WIN32
- _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str());
+ _tfopen_s(&m_file, Common::UTF8ToTStr(filename).c_str(), Common::UTF8ToTStr(openmode).c_str());
#else
m_file = fopen(filename.c_str(), openmode);
#endif
@@ -861,7 +901,7 @@ void IOFile::SetHandle(std::FILE* file)
u64 IOFile::GetSize()
{
if (IsOpen())
- return File::GetSize(m_file);
+ return FileUtil::GetSize(m_file);
else
return 0;
}
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 0871734d4..173ce6623 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -4,11 +4,12 @@
#pragma once
+#include <array>
#include <fstream>
#include <cstdio>
+#include <cstring>
#include <string>
#include <vector>
-#include <string.h>
#include "common/common.h"
#include "common/string_util.h"
@@ -25,6 +26,7 @@ enum {
D_SHADERS_IDX,
D_STATESAVES_IDX,
D_SCREENSHOTS_IDX,
+ D_SDMC_IDX,
D_HIRESTEXTURES_IDX,
D_DUMP_IDX,
D_DUMPFRAMES_IDX,
@@ -43,10 +45,10 @@ enum {
NUM_PATH_INDICES
};
-namespace File
+namespace FileUtil
{
-// FileSystem tree node/
+// FileSystem tree node/
struct FSTEntry
{
bool isDirectory;
@@ -84,13 +86,13 @@ bool Delete(const std::string &filename);
// Deletes a directory filename, returns true on success
bool DeleteDir(const std::string &filename);
-// renames file srcFilename to destFilename, returns true on success
+// renames file srcFilename to destFilename, returns true on success
bool Rename(const std::string &srcFilename, const std::string &destFilename);
-// copies file srcFilename to destFilename, returns true on success
+// copies file srcFilename to destFilename, returns true on success
bool Copy(const std::string &srcFilename, const std::string &destFilename);
-// creates an empty file filename, returns true on success
+// creates an empty file filename, returns true on success
bool CreateEmptyFile(const std::string &filename);
// Scans the directory tree gets, starting from _Directory and adds the
@@ -109,7 +111,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path);
// Set the current directory to given directory
bool SetCurrentDir(const std::string &directory);
-// Returns a pointer to a string with a Dolphin data dir in the user's home
+// Returns a pointer to a string with a Citra data dir in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
@@ -127,8 +129,18 @@ std::string GetBundleDirectory();
std::string &GetExeDirectory();
#endif
-bool WriteStringToFile(bool text_file, const std::string &str, const char *filename);
-bool ReadFileToString(bool text_file, const char *filename, std::string &str);
+size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename);
+size_t ReadFileToString(bool text_file, const char *filename, std::string &str);
+
+/**
+ * Splits the filename into 8.3 format
+ * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename
+ * @param filename The normal filename to use
+ * @param short_name A 9-char array in which the short name will be written
+ * @param extension A 4-char array in which the extension will be written
+ */
+void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
+ std::array<char, 4>& extension);
// simple wrapper for cstdlib file functions to
// hopefully will make error checking easier
@@ -141,39 +153,51 @@ public:
IOFile(const std::string& filename, const char openmode[]);
~IOFile();
-
+
IOFile(IOFile&& other);
IOFile& operator=(IOFile&& other);
-
+
void Swap(IOFile& other);
bool Open(const std::string& filename, const char openmode[]);
bool Close();
template <typename T>
- bool ReadArray(T* data, size_t length)
+ size_t ReadArray(T* data, size_t length)
{
- if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file))
+ if (!IsOpen()) {
m_good = false;
+ return -1;
+ }
- return m_good;
+ size_t items_read = std::fread(data, sizeof(T), length, m_file);
+ if (items_read != length)
+ m_good = false;
+
+ return items_read;
}
template <typename T>
- bool WriteArray(const T* data, size_t length)
+ size_t WriteArray(const T* data, size_t length)
{
- if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file))
+ if (!IsOpen()) {
+ m_good = false;
+ return -1;
+ }
+
+ size_t items_written = std::fwrite(data, sizeof(T), length, m_file);
+ if (items_written != length)
m_good = false;
- return m_good;
+ return items_written;
}
- bool ReadBytes(void* data, size_t length)
+ size_t ReadBytes(void* data, size_t length)
{
return ReadArray(reinterpret_cast<char*>(data), length);
}
- bool WriteBytes(const void* data, size_t length)
+ size_t WriteBytes(const void* data, size_t length)
{
return WriteArray(reinterpret_cast<const char*>(data), length);
}
@@ -213,7 +237,7 @@ template <typename T>
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode)
{
#ifdef _WIN32
- fstream.open(UTF8ToTStr(filename).c_str(), openmode);
+ fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode);
#else
fstream.open(filename.c_str(), openmode);
#endif
diff --git a/src/common/fixed_size_queue.h b/src/common/fixed_size_queue.h
deleted file mode 100644
index 1e3a5dea6..000000000
--- a/src/common/fixed_size_queue.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the
-// real STL classes.
-
-// Not fully featured, no safety checking yet. Add features as needed.
-
-// TODO: "inline" storage?
-
-template <class T, int N>
-class fixed_size_queue.h
-{
- T *storage;
- int head;
- int tail;
- int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future.
-
- // Make copy constructor private for now.
- fixed_size_queue.h(fixed_size_queue.h &other) { }
-
-public:
- fixed_size_queue.h()
- {
- storage = new T[N];
- clear();
- }
-
- ~fixed_size_queue.h()
- {
- delete [] storage;
- }
-
- void clear() {
- head = 0;
- tail = 0;
- count = 0;
- }
-
- void push(T t) {
- storage[tail] = t;
- tail++;
- if (tail == N)
- tail = 0;
- count++;
- }
-
- void pop() {
- head++;
- if (head == N)
- head = 0;
- count--;
- }
-
- T pop_front() {
- const T &temp = storage[head];
- pop();
- return temp;
- }
-
- T &front() { return storage[head]; }
- const T &front() const { return storage[head]; }
-
- size_t size() const {
- return count;
- }
-};
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp
new file mode 100644
index 000000000..309caab98
--- /dev/null
+++ b/src/common/key_map.cpp
@@ -0,0 +1,25 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "key_map.h"
+#include <map>
+
+namespace KeyMap {
+
+static std::map<HostDeviceKey, HID_User::PadState> key_map;
+static int next_device_id = 0;
+
+int NewDeviceId() {
+ return next_device_id++;
+}
+
+void SetKeyMapping(HostDeviceKey key, HID_User::PadState padState) {
+ key_map[key].hex = padState.hex;
+}
+
+HID_User::PadState GetPadKey(HostDeviceKey key) {
+ return key_map[key];
+}
+
+}
diff --git a/src/common/key_map.h b/src/common/key_map.h
new file mode 100644
index 000000000..bf72362c0
--- /dev/null
+++ b/src/common/key_map.h
@@ -0,0 +1,45 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/hid_user.h"
+
+namespace KeyMap {
+
+/**
+ * Represents a key for a specific host device.
+ */
+struct HostDeviceKey {
+ int key_code;
+ int device_id; ///< Uniquely identifies a host device
+
+ bool operator < (const HostDeviceKey &other) const {
+ if (device_id == other.device_id) {
+ return key_code < other.key_code;
+ }
+ return device_id < other.device_id;
+ }
+
+ bool operator == (const HostDeviceKey &other) const {
+ return device_id == other.device_id && key_code == other.key_code;
+ }
+};
+
+/**
+ * Generates a new device id, which uniquely identifies a host device within KeyMap.
+ */
+int NewDeviceId();
+
+/**
+ * Maps a device-specific key to a PadState.
+ */
+void SetKeyMapping(HostDeviceKey key, HID_User::PadState padState);
+
+/**
+ * Gets the PadState that's mapped to the provided device-specific key.
+ */
+HID_User::PadState GetPadKey(HostDeviceKey key);
+
+}
diff --git a/src/common/log.h b/src/common/log.h
index 291534c67..bfd73f8a5 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -28,6 +28,7 @@ enum LOG_TYPE {
COMMANDPROCESSOR,
COMMON,
CONSOLE,
+ CONFIG,
DISCIO,
FILEMON,
DSPHLE,
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp
index 4e1cb60bd..4d590d98f 100644
--- a/src/common/log_manager.cpp
+++ b/src/common/log_manager.cpp
@@ -8,7 +8,6 @@
#include "common/console_listener.h"
#include "common/timer.h"
#include "common/thread.h"
-#include "common/file_util.h"
void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
const char* function, const char* fmt, ...)
@@ -31,6 +30,7 @@ LogManager::LogManager()
m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log");
m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot");
m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common");
+ m_Log[LogTypes::CONFIG] = new LogContainer("CONFIG", "Configuration");
m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO");
m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor");
m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad");
@@ -76,7 +76,7 @@ LogManager::LogManager()
m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager");
m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay");
- m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str());
+ m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str());
m_consoleLog = new ConsoleListener();
m_debuggerLog = new DebuggerLogListener();
@@ -121,7 +121,7 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const
if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
return;
- CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args);
+ Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args);
static const char level_to_char[7] = "ONEWID";
sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line,
diff --git a/src/common/log_manager.h b/src/common/log_manager.h
index ce62d0361..de1d16ee5 100644
--- a/src/common/log_manager.h
+++ b/src/common/log_manager.h
@@ -30,7 +30,7 @@ class FileLogListener : public LogListener
public:
FileLogListener(const char *filename);
- void Log(LogTypes::LOG_LEVELS, const char *msg);
+ void Log(LogTypes::LOG_LEVELS, const char *msg) override;
bool IsValid() { return !m_logfile.fail(); }
bool IsEnabled() const { return m_enable; }
@@ -47,7 +47,7 @@ private:
class DebuggerLogListener : public LogListener
{
public:
- void Log(LogTypes::LOG_LEVELS, const char *msg);
+ void Log(LogTypes::LOG_LEVELS, const char *msg) override;
};
class LogContainer
diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp
index 82eceab00..ab0e6b75c 100644
--- a/src/common/math_util.cpp
+++ b/src/common/math_util.cpp
@@ -6,8 +6,7 @@
#include "common/common.h"
#include "common/math_util.h"
-#include <cmath>
-#include <numeric>
+#include <numeric> // Necessary on OS X, but not Linux
namespace MathUtil
{
diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp
index b76ac92d3..40d9c03a2 100644
--- a/src/common/mem_arena.cpp
+++ b/src/common/mem_arena.cpp
@@ -22,11 +22,7 @@
#include "common/string_util.h"
#ifndef _WIN32
-#include <sys/stat.h>
#include <fcntl.h>
-#include <unistd.h>
-#include <cerrno>
-#include <cstring>
#ifdef ANDROID
#include <sys/ioctl.h>
#include <linux/ashmem.h>
@@ -143,7 +139,7 @@ void MemArena::GrabLowMemSpace(size_t size)
// a bit more.
for (int i = 0; i < 10000; i++)
{
- std::string file_name = StringFromFormat("/citramem.%d", i);
+ std::string file_name = Common::StringFromFormat("/citramem.%d", i);
fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd != -1)
{
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index e01e63175..bab7d9f7a 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -10,9 +10,6 @@
#ifdef _WIN32
#include <windows.h>
#include <psapi.h>
-#else
-#include <cerrno>
-#include <cstdio>
#endif
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
@@ -190,7 +187,7 @@ std::string MemUsage()
if (NULL == hProcess) return "MemUsage Error";
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
- Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
+ Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
CloseHandle(hProcess);
return Ret;
diff --git a/src/common/msg_handler.cpp b/src/common/msg_handler.cpp
index 3e02ec4d7..b3556aaa8 100644
--- a/src/common/msg_handler.cpp
+++ b/src/common/msg_handler.cpp
@@ -72,7 +72,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...)
va_list args;
va_start(args, format);
- CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args);
+ Common::CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args);
va_end(args);
ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer);
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index c1f22bda3..54943d306 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -3,34 +3,29 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <cstdlib>
-#include <cstdio>
#include "common/common.h"
-#include "common/common_paths.h"
#include "common/string_util.h"
#ifdef _WIN32
#include <Windows.h>
+ #include <codecvt>
#else
- #include <cerrno>
#include <iconv.h>
#endif
+namespace Common {
+
/// Make a string lowercase
-void LowerStr(char* str) {
- for (int i = 0; str[i]; i++) {
- str[i] = tolower(str[ i ]);
- }
+std::string ToLower(std::string str) {
+ std::transform(str.begin(), str.end(), str.begin(), ::tolower);
+ return str;
}
/// Make a string uppercase
-void UpperStr(char* str) {
- for (int i=0; i < strlen(str); i++) {
- if(str[i] >= 'a' && str[i] <= 'z') {
- str[i] &= 0xDF;
- }
- }
+std::string ToUpper(std::string str) {
+ std::transform(str.begin(), str.end(), str.begin(), ::toupper);
+ return str;
}
// faster than sscanf
@@ -192,9 +187,9 @@ bool TryParse(const std::string &str, u32 *const output)
bool TryParse(const std::string &str, bool *const output)
{
- if ("1" == str || !strcasecmp("true", str.c_str()))
+ if ("1" == str || "true" == ToLower(str))
*output = true;
- else if ("0" == str || !strcasecmp("false", str.c_str()))
+ else if ("0" == str || "false" == ToLower(str))
*output = false;
else
return false;
@@ -202,13 +197,6 @@ bool TryParse(const std::string &str, bool *const output)
return true;
}
-std::string StringFromInt(int value)
-{
- char temp[16];
- sprintf(temp, "%i", value);
- return temp;
-}
-
std::string StringFromBool(bool value)
{
return value ? "True" : "False";
@@ -283,12 +271,17 @@ std::string TabsToSpaces(int tab_size, const std::string &in)
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest)
{
- while(1)
+ size_t pos = 0;
+
+ if (src == dest)
+ return result;
+
+ while ((pos = result.find(src, pos)) != std::string::npos)
{
- size_t pos = result.find(src);
- if (pos == std::string::npos) break;
result.replace(pos, src.size(), dest);
+ pos += dest.length();
}
+
return result;
}
@@ -419,7 +412,19 @@ std::string UriEncode(const std::string & sSrc)
#ifdef _WIN32
-std::string UTF16ToUTF8(const std::wstring& input)
+std::string UTF16ToUTF8(const std::u16string& input)
+{
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+ return convert.to_bytes(input);
+}
+
+std::u16string UTF8ToUTF16(const std::string& input)
+{
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+ return convert.from_bytes(input);
+}
+
+static std::string UTF16ToUTF8(const std::wstring& input)
{
auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr);
@@ -432,7 +437,7 @@ std::string UTF16ToUTF8(const std::wstring& input)
return output;
}
-std::wstring CPToUTF16(u32 code_page, const std::string& input)
+static std::wstring CPToUTF16(u32 code_page, const std::string& input)
{
auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0);
@@ -445,7 +450,7 @@ std::wstring CPToUTF16(u32 code_page, const std::string& input)
return output;
}
-std::wstring UTF8ToUTF16(const std::string& input)
+std::wstring UTF8ToUTF16W(const std::string &input)
{
return CPToUTF16(CP_UTF8, input);
}
@@ -463,61 +468,123 @@ std::string CP1252ToUTF8(const std::string& input)
#else
template <typename T>
-std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
+static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
{
std::string result;
iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
- if ((iconv_t)-1 == conv_desc)
+ if ((iconv_t)(-1) == conv_desc)
{
ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
+ iconv_close(conv_desc);
+ return {};
}
- else
- {
- size_t const in_bytes = sizeof(T) * input.size();
- size_t const out_buffer_size = 4 * in_bytes;
- std::string out_buffer;
- out_buffer.resize(out_buffer_size);
+ const size_t in_bytes = sizeof(T) * input.size();
+ // Multiply by 4, which is the max number of bytes to encode a codepoint
+ const size_t out_buffer_size = 4 * in_bytes;
- auto src_buffer = &input[0];
- size_t src_bytes = in_bytes;
- auto dst_buffer = &out_buffer[0];
- size_t dst_bytes = out_buffer.size();
+ std::string out_buffer;
+ out_buffer.resize(out_buffer_size);
- while (src_bytes != 0)
- {
- size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
- &dst_buffer, &dst_bytes);
+ auto src_buffer = &input[0];
+ size_t src_bytes = in_bytes;
+ auto dst_buffer = &out_buffer[0];
+ size_t dst_bytes = out_buffer.size();
+
+ while (0 != src_bytes)
+ {
+ size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
+ &dst_buffer, &dst_bytes);
- if ((size_t)-1 == iconv_result)
+ if (static_cast<size_t>(-1) == iconv_result)
+ {
+ if (EILSEQ == errno || EINVAL == errno)
{
- if (EILSEQ == errno || EINVAL == errno)
+ // Try to skip the bad character
+ if (0 != src_bytes)
{
- // Try to skip the bad character
- if (src_bytes != 0)
- {
- --src_bytes;
- ++src_buffer;
- }
- }
- else
- {
- ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno));
- break;
+ --src_bytes;
+ ++src_buffer;
}
}
+ else
+ {
+ ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno));
+ break;
+ }
}
+ }
- out_buffer.resize(out_buffer_size - dst_bytes);
- out_buffer.swap(result);
-
+ out_buffer.resize(out_buffer_size - dst_bytes);
+ out_buffer.swap(result);
+
+ iconv_close(conv_desc);
+
+ return result;
+}
+
+std::u16string UTF8ToUTF16(const std::string& input)
+{
+ std::u16string result;
+
+ iconv_t const conv_desc = iconv_open("UTF-16", "UTF-8");
+ if ((iconv_t)(-1) == conv_desc)
+ {
+ ERROR_LOG(COMMON, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
iconv_close(conv_desc);
+ return {};
+ }
+
+ const size_t in_bytes = sizeof(char) * input.size();
+ // Multiply by 4, which is the max number of bytes to encode a codepoint
+ const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes;
+
+ std::u16string out_buffer;
+ out_buffer.resize(out_buffer_size);
+
+ char* src_buffer = const_cast<char*>(&input[0]);
+ size_t src_bytes = in_bytes;
+ char* dst_buffer = (char*)(&out_buffer[0]);
+ size_t dst_bytes = out_buffer.size();
+
+ while (0 != src_bytes)
+ {
+ size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes,
+ &dst_buffer, &dst_bytes);
+
+ if (static_cast<size_t>(-1) == iconv_result)
+ {
+ if (EILSEQ == errno || EINVAL == errno)
+ {
+ // Try to skip the bad character
+ if (0 != src_bytes)
+ {
+ --src_bytes;
+ ++src_buffer;
+ }
+ }
+ else
+ {
+ ERROR_LOG(COMMON, "iconv failure [UTF-8]: %s", strerror(errno));
+ break;
+ }
+ }
}
+
+ out_buffer.resize(out_buffer_size - dst_bytes);
+ out_buffer.swap(result);
+
+ iconv_close(conv_desc);
return result;
}
+std::string UTF16ToUTF8(const std::u16string& input)
+{
+ return CodeToUTF8("UTF-16", input);
+}
+
std::string CP1252ToUTF8(const std::string& input)
{
//return CodeToUTF8("CP1252//TRANSLIT", input);
@@ -531,17 +598,6 @@ std::string SHIFTJISToUTF8(const std::string& input)
return CodeToUTF8("SJIS", input);
}
-std::string UTF16ToUTF8(const std::wstring& input)
-{
- std::string result =
- // CodeToUTF8("UCS-2", input);
- // CodeToUTF8("UCS-2LE", input);
- // CodeToUTF8("UTF-16", input);
- CodeToUTF8("UTF-16LE", input);
-
- // TODO: why is this needed?
- result.erase(std::remove(result.begin(), result.end(), 0x00), result.end());
- return result;
-}
-
#endif
+
+}
diff --git a/src/common/string_util.h b/src/common/string_util.h
index ba4cd363e..787a5663f 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -12,11 +12,13 @@
#include "common/common.h"
+namespace Common {
+
/// Make a string lowercase
-void LowerStr(char* str);
+std::string ToLower(std::string str);
/// Make a string uppercase
-void UpperStr(char* str);
+std::string ToUpper(std::string str);
std::string StringFromFormat(const char* format, ...);
// Cheap!
@@ -52,7 +54,6 @@ std::string ThousandSeparate(I value, int spaces = 0)
return oss.str();
}
-std::string StringFromInt(int value);
std::string StringFromBool(bool value);
bool TryParse(const std::string &str, bool *output);
@@ -88,20 +89,22 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
std::string UriDecode(const std::string & sSrc);
std::string UriEncode(const std::string & sSrc);
+std::string UTF16ToUTF8(const std::u16string& input);
+std::u16string UTF8ToUTF16(const std::string& input);
+
std::string CP1252ToUTF8(const std::string& str);
std::string SHIFTJISToUTF8(const std::string& str);
-std::string UTF16ToUTF8(const std::wstring& str);
#ifdef _WIN32
-std::wstring UTF8ToUTF16(const std::string& str);
+std::wstring UTF8ToUTF16W(const std::string& str);
#ifdef _UNICODE
inline std::string TStrToUTF8(const std::wstring& str)
{ return UTF16ToUTF8(str); }
inline std::wstring UTF8ToTStr(const std::string& str)
-{ return UTF8ToUTF16(str); }
+{ return UTF8ToUTF16W(str); }
#else
inline std::string TStrToUTF8(const std::string& str)
{ return str; }
@@ -111,3 +114,5 @@ inline std::string UTF8ToTStr(const std::string& str)
#endif
#endif
+
+}
diff --git a/src/common/swap.h b/src/common/swap.h
index 123019fd1..4f8f39efb 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -85,7 +85,6 @@ public:
return *this;
}
- operator long() const { return (long)swap(); }
operator s8() const { return (s8)swap(); }
operator u8() const { return (u8)swap(); }
operator s16() const { return (s16)swap(); }
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 830795182..60d8ed075 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include "common/thread.h"
-#include "common/common.h"
#ifdef __APPLE__
#include <mach/mach.h>
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index f8e1fadca..ded4a344e 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -169,7 +169,6 @@ std::string Timer::GetTimeFormatted()
{
time_t sysTime;
struct tm * gmTime;
- char formattedTime[13];
char tmp[13];
time(&sysTime);
@@ -181,14 +180,12 @@ std::string Timer::GetTimeFormatted()
#ifdef _WIN32
struct timeb tp;
(void)::ftime(&tp);
- sprintf(formattedTime, "%s:%03i", tmp, tp.millitm);
+ return StringFromFormat("%s:%03i", tmp, tp.millitm);
#else
struct timeval t;
(void)gettimeofday(&t, NULL);
- sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000));
+ return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000));
#endif
-
- return std::string(formattedTime);
}
// Returns a timestamp with decimals for precise time comparisons
diff --git a/src/common/utf8.cpp b/src/common/utf8.cpp
index c83824d35..be4ebc855 100644
--- a/src/common/utf8.cpp
+++ b/src/common/utf8.cpp
@@ -19,12 +19,8 @@
#endif
#include <cstdlib>
-#include <cstdio>
#include <cstring>
-#include <cstdarg>
-
#include <algorithm>
-#include <string>
#include "common/common_types.h"
#include "common/utf8.h"
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 1f358ec8d..f41d52e80 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,28 +1,28 @@
set(SRCS
arm/disassembler/arm_disasm.cpp
arm/disassembler/load_symbol_map.cpp
- arm/interpreter/mmu/arm1176jzf_s_mmu.cpp
- arm/interpreter/mmu/cache.cpp
- arm/interpreter/mmu/maverick.cpp
- arm/interpreter/mmu/rb.cpp
- arm/interpreter/mmu/sa_mmu.cpp
- arm/interpreter/mmu/tlb.cpp
- arm/interpreter/mmu/wb.cpp
- arm/interpreter/mmu/xscale_copro.cpp
- arm/interpreter/vfp/vfp.cpp
- arm/interpreter/vfp/vfpdouble.cpp
- arm/interpreter/vfp/vfpinstr.cpp
- arm/interpreter/vfp/vfpsingle.cpp
+ arm/dyncom/arm_dyncom.cpp
+ arm/dyncom/arm_dyncom_dec.cpp
+ arm/dyncom/arm_dyncom_interpreter.cpp
+ arm/dyncom/arm_dyncom_run.cpp
+ arm/dyncom/arm_dyncom_thumb.cpp
arm/interpreter/arm_interpreter.cpp
arm/interpreter/armcopro.cpp
arm/interpreter/armemu.cpp
arm/interpreter/arminit.cpp
- arm/interpreter/armmmu.cpp
- arm/interpreter/armos.cpp
arm/interpreter/armsupp.cpp
arm/interpreter/armvirt.cpp
arm/interpreter/thumbemu.cpp
+ arm/skyeye_common/vfp/vfp.cpp
+ arm/skyeye_common/vfp/vfpdouble.cpp
+ arm/skyeye_common/vfp/vfpinstr.cpp
+ arm/skyeye_common/vfp/vfpsingle.cpp
file_sys/archive_romfs.cpp
+ file_sys/archive_sdmc.cpp
+ file_sys/file_romfs.cpp
+ file_sys/file_sdmc.cpp
+ file_sys/directory_romfs.cpp
+ file_sys/directory_sdmc.cpp
hle/kernel/address_arbiter.cpp
hle/kernel/archive.cpp
hle/kernel/event.cpp
@@ -30,15 +30,24 @@ set(SRCS
hle/kernel/mutex.cpp
hle/kernel/shared_memory.cpp
hle/kernel/thread.cpp
- hle/service/apt.cpp
- hle/service/fs.cpp
- hle/service/gsp.cpp
- hle/service/hid.cpp
- hle/service/ndm.cpp
+ hle/service/ac_u.cpp
+ hle/service/apt_u.cpp
+ hle/service/cfg_u.cpp
+ hle/service/dsp_dsp.cpp
+ hle/service/err_f.cpp
+ hle/service/fs_user.cpp
+ hle/service/frd_u.cpp
+ hle/service/gsp_gpu.cpp
+ hle/service/hid_user.cpp
+ hle/service/mic_u.cpp
+ hle/service/ndm_u.cpp
+ hle/service/nwm_uds.cpp
+ hle/service/ptm_u.cpp
hle/service/service.cpp
+ hle/service/soc_u.cpp
hle/service/srv.cpp
+ hle/service/ssl_c.cpp
hle/config_mem.cpp
- hle/coprocessor.cpp
hle/hle.cpp
hle/svc.cpp
hw/gpu.cpp
@@ -51,32 +60,40 @@ set(SRCS
core_timing.cpp
mem_map.cpp
mem_map_funcs.cpp
+ settings.cpp
system.cpp
)
set(HEADERS
arm/disassembler/arm_disasm.h
arm/disassembler/load_symbol_map.h
- arm/interpreter/mmu/arm1176jzf_s_mmu.h
- arm/interpreter/mmu/cache.h
- arm/interpreter/mmu/rb.h
- arm/interpreter/mmu/sa_mmu.h
- arm/interpreter/mmu/tlb.h
- arm/interpreter/mmu/wb.h
- arm/interpreter/vfp/asm_vfp.h
- arm/interpreter/vfp/vfp.h
- arm/interpreter/vfp/vfp_helper.h
+ arm/dyncom/arm_dyncom.h
+ arm/dyncom/arm_dyncom_dec.h
+ arm/dyncom/arm_dyncom_interpreter.h
+ arm/dyncom/arm_dyncom_run.h
+ arm/dyncom/arm_dyncom_thumb.h
arm/interpreter/arm_interpreter.h
- arm/interpreter/arm_regformat.h
- arm/interpreter/armcpu.h
- arm/interpreter/armdefs.h
- arm/interpreter/armemu.h
- arm/interpreter/armmmu.h
- arm/interpreter/armos.h
- arm/interpreter/skyeye_defs.h
+ arm/skyeye_common/arm_regformat.h
+ arm/skyeye_common/armcpu.h
+ arm/skyeye_common/armdefs.h
+ arm/skyeye_common/armemu.h
+ arm/skyeye_common/armmmu.h
+ arm/skyeye_common/armos.h
+ arm/skyeye_common/skyeye_defs.h
+ arm/skyeye_common/skyeye_types.h
+ arm/skyeye_common/vfp/asm_vfp.h
+ arm/skyeye_common/vfp/vfp.h
+ arm/skyeye_common/vfp/vfp_helper.h
arm/arm_interface.h
file_sys/archive.h
file_sys/archive_romfs.h
+ file_sys/archive_sdmc.h
+ file_sys/file.h
+ file_sys/file_romfs.h
+ file_sys/file_sdmc.h
+ file_sys/directory.h
+ file_sys/directory_romfs.h
+ file_sys/directory_sdmc.h
hle/kernel/address_arbiter.h
hle/kernel/archive.h
hle/kernel/event.h
@@ -84,15 +101,24 @@ set(HEADERS
hle/kernel/mutex.h
hle/kernel/shared_memory.h
hle/kernel/thread.h
- hle/service/apt.h
- hle/service/fs.h
- hle/service/gsp.h
- hle/service/hid.h
- hle/service/ndm.h
+ hle/service/ac_u.h
+ hle/service/apt_u.h
+ hle/service/cfg_u.h
+ hle/service/dsp_dsp.h
+ hle/service/err_f.h
+ hle/service/fs_user.h
+ hle/service/frd_u.h
+ hle/service/gsp_gpu.h
+ hle/service/hid_user.h
+ hle/service/mic_u.h
+ hle/service/ndm_u.h
+ hle/service/nwm_uds.h
+ hle/service/ptm_u.h
hle/service/service.h
+ hle/service/soc_u.h
hle/service/srv.h
+ hle/service/ssl_c.h
hle/config_mem.h
- hle/coprocessor.h
hle/function_wrappers.h
hle/hle.h
hle/svc.h
@@ -105,6 +131,7 @@ set(HEADERS
core.h
core_timing.h
mem_map.h
+ settings.h
system.h
)
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index 33e036cbf..45c720e16 100644
--- a/src/core/arm/disassembler/arm_disasm.cpp
+++ b/src/core/arm/disassembler/arm_disasm.cpp
@@ -260,14 +260,14 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn)
// The "mov" instruction ignores the first operand (rn).
rn_str[0] = 0;
if ((flags & kNoOperand1) == 0) {
- rn_str = StringFromFormat("r%d, ", rn);
+ rn_str = Common::StringFromFormat("r%d, ", rn);
}
// The following instructions do not write the result register (rd):
// tst, teq, cmp, cmn.
rd_str[0] = 0;
if ((flags & kNoDest) == 0) {
- rd_str = StringFromFormat("r%d, ", rd);
+ rd_str = Common::StringFromFormat("r%d, ", rd);
}
const char *sbit_str = "";
@@ -275,7 +275,7 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn)
sbit_str = "s";
if (is_immed) {
- return StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x",
+ return Common::StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x",
opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed);
}
@@ -290,24 +290,24 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn)
rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2));
if (!shift_is_reg && shift_type == 0 && shift_amount == 0) {
- return StringFromFormat("%s%s%s\t%s%sr%d",
+ return Common::StringFromFormat("%s%s%s\t%s%sr%d",
opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm);
}
const char *shift_name = shift_names[shift_type];
if (shift_is_reg) {
- return StringFromFormat("%s%s%s\t%s%sr%d, %s r%d",
+ return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s r%d",
opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm,
shift_name, rs);
}
if (shift_amount == 0) {
if (shift_type == 3) {
- return StringFromFormat("%s%s%s\t%s%sr%d, RRX",
+ return Common::StringFromFormat("%s%s%s\t%s%sr%d, RRX",
opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm);
}
shift_amount = 32;
}
- return StringFromFormat("%s%s%s\t%s%sr%d, %s #%u",
+ return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s #%u",
opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm,
shift_name, shift_amount);
}
@@ -325,20 +325,20 @@ std::string ARM_Disasm::DisassembleBranch(uint32_t addr, Opcode opcode, uint32_t
offset += 8;
addr += offset;
const char *opname = opcode_names[opcode];
- return StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr);
+ return Common::StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr);
}
std::string ARM_Disasm::DisassembleBX(uint32_t insn)
{
uint8_t cond = (insn >> 28) & 0xf;
uint8_t rn = insn & 0xf;
- return StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn);
+ return Common::StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn);
}
std::string ARM_Disasm::DisassembleBKPT(uint32_t insn)
{
uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf);
- return StringFromFormat("bkpt\t#%d", immed);
+ return Common::StringFromFormat("bkpt\t#%d", immed);
}
std::string ARM_Disasm::DisassembleCLZ(uint32_t insn)
@@ -346,7 +346,7 @@ std::string ARM_Disasm::DisassembleCLZ(uint32_t insn)
uint8_t cond = (insn >> 28) & 0xf;
uint8_t rd = (insn >> 12) & 0xf;
uint8_t rm = insn & 0xf;
- return StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm);
+ return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm);
}
std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn)
@@ -376,7 +376,7 @@ std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn)
tmp_list[0] = 0;
for (int ii = 0; ii < 16; ++ii) {
if (reg_list & (1 << ii)) {
- tmp_list += StringFromFormat("%sr%d", comma, ii);
+ tmp_list += Common::StringFromFormat("%sr%d", comma, ii);
comma = ",";
}
}
@@ -396,7 +396,7 @@ std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn)
}
}
- return StringFromFormat("%s%s%s\tr%d%s, {%s}%s",
+ return Common::StringFromFormat("%s%s%s\tr%d%s, {%s}%s",
opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list.c_str(), carret);
}
@@ -432,10 +432,10 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn)
if (is_reg == 0) {
if (is_pre) {
if (offset == 0) {
- return StringFromFormat("%s%s%s\tr%d, [r%d]",
+ return Common::StringFromFormat("%s%s%s\tr%d, [r%d]",
opname, cond_to_str(cond), byte, rd, rn);
} else {
- return StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s",
+ return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s",
opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang);
}
} else {
@@ -443,7 +443,7 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn)
if (write_back)
transfer = "t";
- return StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u",
+ return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u",
opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset);
}
}
@@ -457,16 +457,16 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn)
if (is_pre) {
if (shift_amount == 0) {
if (shift_type == 0) {
- return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s",
+ return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s",
opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang);
}
if (shift_type == 3) {
- return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s",
+ return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s",
opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang);
}
shift_amount = 32;
}
- return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s",
+ return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s",
opname, cond_to_str(cond), byte, rd, rn, minus, rm,
shift_name, shift_amount, bang);
}
@@ -477,17 +477,17 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn)
if (shift_amount == 0) {
if (shift_type == 0) {
- return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d",
+ return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d",
opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm);
}
if (shift_type == 3) {
- return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX",
+ return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX",
opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm);
}
shift_amount = 32;
}
- return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u",
+ return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u",
opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm,
shift_name, shift_amount);
}
@@ -528,22 +528,22 @@ std::string ARM_Disasm::DisassembleMemHalf(uint32_t insn)
if (is_immed) {
if (is_pre) {
if (offset == 0) {
- return StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn);
+ return Common::StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn);
} else {
- return StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s",
+ return Common::StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s",
opname, cond_to_str(cond), rd, rn, minus, offset, bang);
}
} else {
- return StringFromFormat("%s%sh\tr%d, [r%d], #%s%u",
+ return Common::StringFromFormat("%s%sh\tr%d, [r%d], #%s%u",
opname, cond_to_str(cond), rd, rn, minus, offset);
}
}
if (is_pre) {
- return StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s",
+ return Common::StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s",
opname, cond_to_str(cond), rd, rn, minus, rm, bang);
} else {
- return StringFromFormat("%s%sh\tr%d, [r%d], %sr%d",
+ return Common::StringFromFormat("%s%sh\tr%d, [r%d], %sr%d",
opname, cond_to_str(cond), rd, rn, minus, rm);
}
}
@@ -558,7 +558,7 @@ std::string ARM_Disasm::DisassembleMCR(Opcode opcode, uint32_t insn)
uint8_t crm = insn & 0xf;
const char *opname = opcode_names[opcode];
- return StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}",
+ return Common::StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}",
opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2);
}
@@ -572,7 +572,7 @@ std::string ARM_Disasm::DisassembleMLA(Opcode opcode, uint32_t insn)
uint8_t bit_s = (insn >> 20) & 1;
const char *opname = opcode_names[opcode];
- return StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d",
+ return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d",
opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn);
}
@@ -586,7 +586,7 @@ std::string ARM_Disasm::DisassembleUMLAL(Opcode opcode, uint32_t insn)
uint8_t bit_s = (insn >> 20) & 1;
const char *opname = opcode_names[opcode];
- return StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d",
+ return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d",
opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs);
}
@@ -599,7 +599,7 @@ std::string ARM_Disasm::DisassembleMUL(Opcode opcode, uint32_t insn)
uint8_t bit_s = (insn >> 20) & 1;
const char *opname = opcode_names[opcode];
- return StringFromFormat("%s%s%s\tr%d, r%d, r%d",
+ return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d",
opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs);
}
@@ -609,7 +609,7 @@ std::string ARM_Disasm::DisassembleMRS(uint32_t insn)
uint8_t rd = (insn >> 12) & 0xf;
uint8_t ps = (insn >> 22) & 1;
- return StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr");
+ return Common::StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr");
}
std::string ARM_Disasm::DisassembleMSR(uint32_t insn)
@@ -636,13 +636,13 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn)
uint8_t rotate = (insn >> 8) & 0xf;
uint8_t rotate2 = rotate << 1;
uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2));
- return StringFromFormat("msr%s\t%s_%s, #0x%x",
+ return Common::StringFromFormat("msr%s\t%s_%s, #0x%x",
cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val);
}
uint8_t rm = insn & 0xf;
- return StringFromFormat("msr%s\t%s_%s, r%d",
+ return Common::StringFromFormat("msr%s\t%s_%s, r%d",
cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm);
}
@@ -658,14 +658,14 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn)
if (is_reg) {
uint8_t rm = insn & 0xf;
- return StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm);
+ return Common::StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm);
}
uint16_t offset = insn & 0xfff;
if (offset == 0) {
- return StringFromFormat("pld\t[r%d]", rn);
+ return Common::StringFromFormat("pld\t[r%d]", rn);
} else {
- return StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset);
+ return Common::StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset);
}
}
@@ -674,7 +674,7 @@ std::string ARM_Disasm::DisassembleSWI(uint32_t insn)
uint8_t cond = (insn >> 28) & 0xf;
uint32_t sysnum = insn & 0x00ffffff;
- return StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum);
+ return Common::StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum);
}
std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn)
@@ -685,7 +685,7 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn)
uint8_t rm = insn & 0xf;
const char *opname = opcode_names[opcode];
- return StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn);
+ return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn);
}
Opcode ARM_Disasm::Decode(uint32_t insn) {
diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp
index d7fc0a042..0f384ad3e 100644
--- a/src/core/arm/disassembler/load_symbol_map.cpp
+++ b/src/core/arm/disassembler/load_symbol_map.cpp
@@ -6,7 +6,6 @@
#include <vector>
#include "common/symbols.h"
-#include "common/common_types.h"
#include "common/file_util.h"
#include "core/arm/disassembler/load_symbol_map.h"
@@ -19,7 +18,7 @@ void LoadSymbolMap(std::string filename) {
std::ifstream infile(filename);
std::string address_str, function_name, line;
- u32 size, address;
+ u32 size;
while (std::getline(infile, line)) {
std::istringstream iss(line);
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
new file mode 100644
index 000000000..a3ed3e31e
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -0,0 +1,166 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "core/arm/skyeye_common/armcpu.h"
+#include "core/arm/skyeye_common/armemu.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
+
+#include "core/arm/dyncom/arm_dyncom.h"
+#include "core/arm/dyncom/arm_dyncom_interpreter.h"
+
+const static cpu_config_t s_arm11_cpu_info = {
+ "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE
+};
+
+ARM_DynCom::ARM_DynCom() : ticks(0) {
+ state = std::unique_ptr<ARMul_State>(new ARMul_State);
+
+ ARMul_EmulateInit();
+ memset(state.get(), 0, sizeof(ARMul_State));
+
+ ARMul_NewState((ARMul_State*)state.get());
+
+ state->abort_model = 0;
+ state->cpu = (cpu_config_t*)&s_arm11_cpu_info;
+ state->bigendSig = LOW;
+
+ ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
+ state->lateabtSig = LOW;
+
+ // Reset the core to initial state
+ ARMul_CoProInit(state.get());
+ ARMul_Reset(state.get());
+ state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext
+ state->Emulate = 3;
+
+ state->pc = state->Reg[15] = 0x00000000;
+ state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
+ state->servaddr = 0xFFFF0000;
+ state->NirqSig = HIGH;
+
+ VFPInit(state.get()); // Initialize the VFP
+
+ ARMul_EmulateInit();
+}
+
+ARM_DynCom::~ARM_DynCom() {
+}
+
+/**
+ * Set the Program Counter to an address
+ * @param addr Address to set PC to
+ */
+void ARM_DynCom::SetPC(u32 pc) {
+ state->pc = state->Reg[15] = pc;
+}
+
+/*
+ * Get the current Program Counter
+ * @return Returns current PC
+ */
+u32 ARM_DynCom::GetPC() const {
+ return state->Reg[15];
+}
+
+/**
+ * Get an ARM register
+ * @param index Register index (0-15)
+ * @return Returns the value in the register
+ */
+u32 ARM_DynCom::GetReg(int index) const {
+ return state->Reg[index];
+}
+
+/**
+ * Set an ARM register
+ * @param index Register index (0-15)
+ * @param value Value to set register to
+ */
+void ARM_DynCom::SetReg(int index, u32 value) {
+ state->Reg[index] = value;
+}
+
+/**
+ * Get the current CPSR register
+ * @return Returns the value of the CPSR register
+ */
+u32 ARM_DynCom::GetCPSR() const {
+ return state->Cpsr;
+}
+
+/**
+ * Set the current CPSR register
+ * @param cpsr Value to set CPSR to
+ */
+void ARM_DynCom::SetCPSR(u32 cpsr) {
+ state->Cpsr = cpsr;
+}
+
+/**
+ * Returns the number of clock ticks since the last reset
+ * @return Returns number of clock ticks
+ */
+u64 ARM_DynCom::GetTicks() const {
+ return ticks;
+}
+
+/**
+ * Executes the given number of instructions
+ * @param num_instructions Number of instructions to executes
+ */
+void ARM_DynCom::ExecuteInstructions(int num_instructions) {
+ state->NumInstrsToExecute = num_instructions;
+
+ // Dyncom only breaks on instruction dispatch. This only happens on every instruction when
+ // executing one instruction at a time. Otherwise, if a block is being executed, more
+ // instructions may actually be executed than specified.
+ ticks += InterpreterMainLoop(state.get());
+}
+
+/**
+ * Saves the current CPU context
+ * @param ctx Thread context to save
+ * @todo Do we need to save Reg[15] and NextInstr?
+ */
+void ARM_DynCom::SaveContext(ThreadContext& ctx) {
+ memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
+ memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
+
+ ctx.sp = state->Reg[13];
+ ctx.lr = state->Reg[14];
+ ctx.pc = state->Reg[15];
+ ctx.cpsr = state->Cpsr;
+
+ ctx.fpscr = state->VFP[1];
+ ctx.fpexc = state->VFP[2];
+
+ ctx.reg_15 = state->Reg[15];
+ ctx.mode = state->NextInstr;
+}
+
+/**
+ * Loads a CPU context
+ * @param ctx Thread context to load
+ * @param Do we need to load Reg[15] and NextInstr?
+ */
+void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
+ memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
+ memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
+
+ state->Reg[13] = ctx.sp;
+ state->Reg[14] = ctx.lr;
+ state->pc = ctx.pc;
+ state->Cpsr = ctx.cpsr;
+
+ state->VFP[1] = ctx.fpscr;
+ state->VFP[2] = ctx.fpexc;
+
+ state->Reg[15] = ctx.reg_15;
+ state->NextInstr = ctx.mode;
+}
+
+/// Prepare core for thread reschedule (if needed to correctly handle state)
+void ARM_DynCom::PrepareReschedule() {
+ state->NumInstrsToExecute = 0;
+}
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
new file mode 100644
index 000000000..1f8cd3a3a
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -0,0 +1,90 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+
+#include "common/common_types.h"
+
+#include "core/arm/arm_interface.h"
+#include "core/arm/skyeye_common/armdefs.h"
+
+class ARM_DynCom final : virtual public ARM_Interface {
+public:
+
+ ARM_DynCom();
+ ~ARM_DynCom();
+
+ /**
+ * Set the Program Counter to an address
+ * @param addr Address to set PC to
+ */
+ void SetPC(u32 pc) override;
+
+ /*
+ * Get the current Program Counter
+ * @return Returns current PC
+ */
+ u32 GetPC() const;
+
+ /**
+ * Get an ARM register
+ * @param index Register index (0-15)
+ * @return Returns the value in the register
+ */
+ u32 GetReg(int index) const;
+
+ /**
+ * Set an ARM register
+ * @param index Register index (0-15)
+ * @param value Value to set register to
+ */
+ void SetReg(int index, u32 value) override;
+
+ /**
+ * Get the current CPSR register
+ * @return Returns the value of the CPSR register
+ */
+ u32 GetCPSR() const;
+
+ /**
+ * Set the current CPSR register
+ * @param cpsr Value to set CPSR to
+ */
+ void SetCPSR(u32 cpsr) override;
+
+ /**
+ * Returns the number of clock ticks since the last reset
+ * @return Returns number of clock ticks
+ */
+ u64 GetTicks() const;
+
+ /**
+ * Saves the current CPU context
+ * @param ctx Thread context to save
+ */
+ void SaveContext(ThreadContext& ctx) override;
+
+ /**
+ * Loads a CPU context
+ * @param ctx Thread context to load
+ */
+ void LoadContext(const ThreadContext& ctx) override;
+
+ /// Prepare core for thread reschedule (if needed to correctly handle state)
+ void PrepareReschedule() override;
+
+ /**
+ * Executes the given number of instructions
+ * @param num_instructions Number of instructions to executes
+ */
+ void ExecuteInstructions(int num_instructions) override;
+
+private:
+
+ std::unique_ptr<ARMul_State> state;
+ u64 ticks;
+
+};
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp
new file mode 100644
index 000000000..5d174a08f
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp
@@ -0,0 +1,402 @@
+/* Copyright (C)
+* 2012 - Michael.Kang blackfin.kang@gmail.com
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+*/
+/**
+* @file arm_dyncom_dec.cpp
+* @brief Some common utility for arm decoder
+* @author Michael.Kang blackfin.kang@gmail.com
+* @version 7849
+* @date 2012-03-15
+*/
+
+#include "core/arm/skyeye_common/arm_regformat.h"
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/dyncom/arm_dyncom_dec.h"
+
+const ISEITEM arm_instruction[] = {
+ #define VFP_DECODE
+ #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+ #undef VFP_DECODE
+ {"srs" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005},
+ {"rfe" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a},
+ {"bkpt" , 2 , 3 , 20, 31, 0x00000e12, 4, 7, 0x00000007},
+ {"blx" , 1 , 3 , 25, 31, 0x0000007d},
+ {"cps" , 3 , 6 , 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000},
+ {"pld" , 4 , 4 , 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f},
+ {"setend" , 2 , 6 , 16, 31, 0x0000f101, 4, 7, 0x00000000},
+ {"clrex" , 1 , 6 , 0, 31, 0xf57ff01f},
+ {"rev16" , 2 , 6 , 16, 27, 0x000006bf, 4, 11, 0x000000fb},
+ {"usad8" , 3 , 6 , 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001},
+ {"sxtb" , 2 , 6 , 16, 27, 0x000006af, 4, 7, 0x00000007},
+ {"uxtb" , 2 , 6 , 16, 27, 0x000006ef, 4, 7, 0x00000007},
+ {"sxth" , 2 , 6 , 16, 27, 0x000006bf, 4, 7, 0x00000007},
+ {"sxtb16" , 2 , 6 , 16, 27, 0x0000068f, 4, 7, 0x00000007},
+ {"uxth" , 2 , 6 , 16, 27, 0x000006ff, 4, 7, 0x00000007},
+ {"uxtb16" , 2 , 6 , 16, 27, 0x000006cf, 4, 7, 0x00000007},
+ {"cpy" , 2 , 6 , 20, 27, 0x0000001a, 4, 11, 0x00000000},
+ {"uxtab" , 2 , 6 , 20, 27, 0x0000006e, 4, 9, 0x00000007},
+ {"ssub8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x0000000f},
+ {"shsub8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x0000000f},
+ {"ssubaddx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000005},
+ {"strex" , 2 , 6 , 20, 27, 0x00000018, 4, 7, 0x00000009},
+ {"strexb" , 2 , 7 , 20, 27, 0x0000001c, 4, 7, 0x00000009},
+ {"swp" , 2 , 0 , 20, 27, 0x00000010, 4, 7, 0x00000009},
+ {"swpb" , 2 , 0 , 20, 27, 0x00000014, 4, 7, 0x00000009},
+ {"ssub16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000007},
+ {"ssat16" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000003},
+ {"shsubaddx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000005},
+ {"qsubaddx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000005},
+ {"shaddsubx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000003},
+ {"shadd8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000009},
+ {"shadd16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000001},
+ {"sel" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x0000000b},
+ {"saddsubx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000003},
+ {"sadd8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000009},
+ {"sadd16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000001},
+ {"shsub16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000007},
+ {"umaal" , 2 , 6 , 20, 27, 0x00000004, 4, 7, 0x00000009},
+ {"uxtab16" , 2 , 6 , 20, 27, 0x0000006c, 4, 7, 0x00000007},
+ {"usubaddx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000005},
+ {"usub8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x0000000f},
+ {"usub16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000007},
+ {"usat16" , 2 , 6 , 20, 27, 0x0000006e, 4, 7, 0x00000003},
+ {"usada8" , 2 , 6 , 20, 27, 0x00000078, 4, 7, 0x00000001},
+ {"uqsubaddx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000005},
+ {"uqsub8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x0000000f},
+ {"uqsub16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000007},
+ {"uqaddsubx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000003},
+ {"uqadd8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000009},
+ {"uqadd16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000001},
+ {"sxtab" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000007},
+ {"uhsubaddx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000005},
+ {"uhsub8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x0000000f},
+ {"uhsub16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000007},
+ {"uhaddsubx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000003},
+ {"uhadd8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000009},
+ {"uhadd16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000001},
+ {"uaddsubx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000003},
+ {"uadd8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000009},
+ {"uadd16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000001},
+ {"sxtah" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000007},
+ {"sxtab16" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x00000007},
+ {"qadd8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000009},
+ {"bxj" , 2 , 5 , 20, 27, 0x00000012, 4, 7, 0x00000002},
+ {"clz" , 2 , 3 , 20, 27, 0x00000016, 4, 7, 0x00000001},
+ {"uxtah" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x00000007},
+ {"bx" , 2 , 2 , 20, 27, 0x00000012, 4, 7, 0x00000001},
+ {"rev" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000003},
+ {"blx" , 2 , 3 , 20, 27, 0x00000012, 4, 7, 0x00000003},
+ {"revsh" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x0000000b},
+ {"qadd" , 2 , 4 , 20, 27, 0x00000010, 4, 7, 0x00000005},
+ {"qadd16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000001},
+ {"qaddsubx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000003},
+ {"ldrex" , 2 , 0 , 20, 27, 0x00000019, 4, 7, 0x00000009},
+ {"qdadd" , 2 , 4 , 20, 27, 0x00000014, 4, 7, 0x00000005},
+ {"qdsub" , 2 , 4 , 20, 27, 0x00000016, 4, 7, 0x00000005},
+ {"qsub" , 2 , 4 , 20, 27, 0x00000012, 4, 7, 0x00000005},
+ {"ldrexb" , 2 , 7 , 20, 27, 0x0000001d, 4, 7, 0x00000009},
+ {"qsub8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x0000000f},
+ {"qsub16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000007},
+ {"smuad" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001},
+ {"smmul" , 4 , 6 , 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001},
+ {"smusd" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001},
+ {"smlsd" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001},
+ {"smlsld" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001},
+ {"smmla" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001},
+ {"smmls" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001},
+ {"smlald" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001},
+ {"smlad" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001},
+ {"smlaw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000},
+ {"smulw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002},
+ {"pkhtb" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000005},
+ {"pkhbt" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000001},
+ {"smul" , 3 , 4 , 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000},
+ {"smlalxy" , 3 , 4 , 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000},
+// {"smlal" , 2 , 4 , 21, 27, 0x00000007, 4, 7, 0x00000009},
+ {"smla" , 3 , 4 , 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000},
+ {"mcrr" , 1 , 6 , 20, 27, 0x000000c4},
+ {"mrrc" , 1 , 6 , 20, 27, 0x000000c5},
+ {"cmp" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000015},
+ {"tst" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000011},
+ {"teq" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000013},
+ {"cmn" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000017},
+ {"smull" , 2 , 0 , 21, 27, 0x00000006, 4, 7, 0x00000009},
+ {"umull" , 2 , 0 , 21, 27, 0x00000004, 4, 7, 0x00000009},
+ {"umlal" , 2 , 0 , 21, 27, 0x00000005, 4, 7, 0x00000009},
+ {"smlal" , 2 , 0 , 21, 27, 0x00000007, 4, 7, 0x00000009},
+ {"mul" , 2 , 0 , 21, 27, 0x00000000, 4, 7, 0x00000009},
+ {"mla" , 2 , 0 , 21, 27, 0x00000001, 4, 7, 0x00000009},
+ {"ssat" , 2 , 6 , 21, 27, 0x00000035, 4, 5, 0x00000001},
+ {"usat" , 2 , 6 , 21, 27, 0x00000037, 4, 5, 0x00000001},
+ {"mrs" , 4 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000},
+ {"msr" , 3 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000},
+ {"and" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000000},
+ {"bic" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000e},
+ {"ldm" , 3 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000},
+ {"eor" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000001},
+ {"add" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000004},
+ {"rsb" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000003},
+ {"rsc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000007},
+ {"sbc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000006},
+ {"adc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000005},
+ {"sub" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000002},
+ {"orr" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000c},
+ {"mvn" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000f},
+ {"mov" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000d},
+ {"stm" , 2 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000004},
+ {"ldm" , 4 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001},
+ {"ldrsh" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f},
+ {"stm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000},
+ {"ldm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001},
+ {"ldrsb" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d},
+ {"strd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f},
+ {"ldrh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b},
+ {"strh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b},
+ {"ldrd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d},
+ {"strt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002},
+ {"strbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006},
+ {"ldrbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007},
+ {"ldrt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003},
+ {"mrc" , 3 , 6 , 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001},
+ {"mcr" , 3 , 0 , 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001},
+ {"msr" , 2 , 0 , 23, 27, 0x00000006, 20, 21, 0x00000002},
+ {"ldrb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001},
+ {"strb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000},
+ {"ldr" , 4 , 0 , 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001},
+ {"ldrcond" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001},
+ {"str" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000},
+ {"cdp" , 2 , 0 , 24, 27, 0x0000000e, 4, 4, 0x00000000},
+ {"stc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000000},
+ {"ldc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000001},
+ {"swi" , 1 , 0 , 24, 27, 0x0000000f},
+ {"bbl" , 1 , 0 , 25, 27, 0x00000005},
+};
+
+const ISEITEM arm_exclusion_code[] = {
+ #define VFP_DECODE_EXCLUSION
+ #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+ #undef VFP_DECODE_EXCLUSION
+ {"srs" , 0 , 6 , 0},
+ {"rfe" , 0 , 6 , 0},
+ {"bkpt" , 0 , 3 , 0},
+ {"blx" , 0 , 3 , 0},
+ {"cps" , 0 , 6 , 0},
+ {"pld" , 0 , 4 , 0},
+ {"setend" , 0 , 6 , 0},
+ {"clrex" , 0 , 6 , 0},
+ {"rev16" , 0 , 6 , 0},
+ {"usad8" , 0 , 6 , 0},
+ {"sxtb" , 0 , 6 , 0},
+ {"uxtb" , 0 , 6 , 0},
+ {"sxth" , 0 , 6 , 0},
+ {"sxtb16" , 0 , 6 , 0},
+ {"uxth" , 0 , 6 , 0},
+ {"uxtb16" , 0 , 6 , 0},
+ {"cpy" , 0 , 6 , 0},
+ {"uxtab" , 0 , 6 , 0},
+ {"ssub8" , 0 , 6 , 0},
+ {"shsub8" , 0 , 6 , 0},
+ {"ssubaddx" , 0 , 6 , 0},
+ {"strex" , 0 , 6 , 0},
+ {"strexb" , 0 , 7 , 0},
+ {"swp" , 0 , 0 , 0},
+ {"swpb" , 0 , 0 , 0},
+ {"ssub16" , 0 , 6 , 0},
+ {"ssat16" , 0 , 6 , 0},
+ {"shsubaddx" , 0 , 6 , 0},
+ {"qsubaddx" , 0 , 6 , 0},
+ {"shaddsubx" , 0 , 6 , 0},
+ {"shadd8" , 0 , 6 , 0},
+ {"shadd16" , 0 , 6 , 0},
+ {"sel" , 0 , 6 , 0},
+ {"saddsubx" , 0 , 6 , 0},
+ {"sadd8" , 0 , 6 , 0},
+ {"sadd16" , 0 , 6 , 0},
+ {"shsub16" , 0 , 6 , 0},
+ {"umaal" , 0 , 6 , 0},
+ {"uxtab16" , 0 , 6 , 0},
+ {"usubaddx" , 0 , 6 , 0},
+ {"usub8" , 0 , 6 , 0},
+ {"usub16" , 0 , 6 , 0},
+ {"usat16" , 0 , 6 , 0},
+ {"usada8" , 0 , 6 , 0},
+ {"uqsubaddx" , 0 , 6 , 0},
+ {"uqsub8" , 0 , 6 , 0},
+ {"uqsub16" , 0 , 6 , 0},
+ {"uqaddsubx" , 0 , 6 , 0},
+ {"uqadd8" , 0 , 6 , 0},
+ {"uqadd16" , 0 , 6 , 0},
+ {"sxtab" , 0 , 6 , 0},
+ {"uhsubaddx" , 0 , 6 , 0},
+ {"uhsub8" , 0 , 6 , 0},
+ {"uhsub16" , 0 , 6 , 0},
+ {"uhaddsubx" , 0 , 6 , 0},
+ {"uhadd8" , 0 , 6 , 0},
+ {"uhadd16" , 0 , 6 , 0},
+ {"uaddsubx" , 0 , 6 , 0},
+ {"uadd8" , 0 , 6 , 0},
+ {"uadd16" , 0 , 6 , 0},
+ {"sxtah" , 0 , 6 , 0},
+ {"sxtab16" , 0 , 6 , 0},
+ {"qadd8" , 0 , 6 , 0},
+ {"bxj" , 0 , 5 , 0},
+ {"clz" , 0 , 3 , 0},
+ {"uxtah" , 0 , 6 , 0},
+ {"bx" , 0 , 2 , 0},
+ {"rev" , 0 , 6 , 0},
+ {"blx" , 0 , 3 , 0},
+ {"revsh" , 0 , 6 , 0},
+ {"qadd" , 0 , 4 , 0},
+ {"qadd16" , 0 , 6 , 0},
+ {"qaddsubx" , 0 , 6 , 0},
+ {"ldrex" , 0 , 0 , 0},
+ {"qdadd" , 0 , 4 , 0},
+ {"qdsub" , 0 , 4 , 0},
+ {"qsub" , 0 , 4 , 0},
+ {"ldrexb" , 0 , 7 , 0},
+ {"qsub8" , 0 , 6 , 0},
+ {"qsub16" , 0 , 6 , 0},
+ {"smuad" , 0 , 6 , 0},
+ {"smmul" , 0 , 6 , 0},
+ {"smusd" , 0 , 6 , 0},
+ {"smlsd" , 0 , 6 , 0},
+ {"smlsld" , 0 , 6 , 0},
+ {"smmla" , 0 , 6 , 0},
+ {"smmls" , 0 , 6 , 0},
+ {"smlald" , 0 , 6 , 0},
+ {"smlad" , 0 , 6 , 0},
+ {"smlaw" , 0 , 4 , 0},
+ {"smulw" , 0 , 4 , 0},
+ {"pkhtb" , 0 , 6 , 0},
+ {"pkhbt" , 0 , 6 , 0},
+ {"smul" , 0 , 4 , 0},
+ {"smlal" , 0 , 4 , 0},
+ {"smla" , 0 , 4 , 0},
+ {"mcrr" , 0 , 6 , 0},
+ {"mrrc" , 0 , 6 , 0},
+ {"cmp" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"tst" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"teq" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"cmn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"smull" , 0 , 0 , 0},
+ {"umull" , 0 , 0 , 0},
+ {"umlal" , 0 , 0 , 0},
+ {"smlal" , 0 , 0 , 0},
+ {"mul" , 0 , 0 , 0},
+ {"mla" , 0 , 0 , 0},
+ {"ssat" , 0 , 6 , 0},
+ {"usat" , 0 , 6 , 0},
+ {"mrs" , 0 , 0 , 0},
+ {"msr" , 0 , 0 , 0},
+ {"and" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"bic" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"ldm" , 0 , 0 , 0},
+ {"eor" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"add" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"rsb" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"rsc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"sbc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"adc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"sub" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"orr" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"mvn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"mov" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
+ {"stm" , 0 , 0 , 0},
+ {"ldm" , 0 , 0 , 0},
+ {"ldrsh" , 0 , 2 , 0},
+ {"stm" , 0 , 0 , 0},
+ {"ldm" , 0 , 0 , 0},
+ {"ldrsb" , 0 , 2 , 0},
+ {"strd" , 0 , 4 , 0},
+ {"ldrh" , 0 , 0 , 0},
+ {"strh" , 0 , 0 , 0},
+ {"ldrd" , 0 , 4 , 0},
+ {"strt" , 0 , 0 , 0},
+ {"strbt" , 0 , 0 , 0},
+ {"ldrbt" , 0 , 0 , 0},
+ {"ldrt" , 0 , 0 , 0},
+ {"mrc" , 0 , 6 , 0},
+ {"mcr" , 0 , 0 , 0},
+ {"msr" , 0 , 0 , 0},
+ {"ldrb" , 0 , 0 , 0},
+ {"strb" , 0 , 0 , 0},
+ {"ldr" , 0 , 0 , 0},
+ {"ldrcond" , 1 , 0 , 28, 31, 0x0000000e},
+ {"str" , 0 , 0 , 0},
+ {"cdp" , 0 , 0 , 0},
+ {"stc" , 0 , 0 , 0},
+ {"ldc" , 0 , 0 , 0},
+ {"swi" , 0 , 0 , 0},
+ {"bbl" , 0 , 0 , 0},
+ {"bl_1_thumb", 0, INVALID, 0},/* should be table[-4] */
+ {"bl_2_thumb", 0, INVALID, 0}, /* should be located at the end of the table[-3] */
+ {"blx_1_thumb", 0, INVALID, 0}, /* should be located at table[-2] */
+ {"invalid", 0, INVALID, 0}
+};
+
+int decode_arm_instr(uint32_t instr, int32_t *idx)
+{
+ int n = 0;
+ int base = 0;
+ int ret = DECODE_FAILURE;
+ int i = 0;
+ int instr_slots = sizeof(arm_instruction)/sizeof(ISEITEM);
+ for (i = 0; i < instr_slots; i++)
+ {
+// ret = DECODE_SUCCESS;
+ n = arm_instruction[i].attribute_value;
+ base = 0;
+ while (n) {
+ if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) {
+ /* clrex */
+ if (instr != arm_instruction[i].content[base + 2]) {
+ break;
+ }
+ } else if (BITS(arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) {
+ break;
+ }
+ base += 3;
+ n --;
+ }
+ //All conditions is satisfied.
+ if (n == 0)
+ ret = DECODE_SUCCESS;
+
+ if (ret == DECODE_SUCCESS) {
+ n = arm_exclusion_code[i].attribute_value;
+ if (n != 0) {
+ base = 0;
+ while (n) {
+ if (BITS(arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) {
+ break; }
+ base += 3;
+ n --;
+ }
+ //All conditions is satisfied.
+ if (n == 0)
+ ret = DECODE_FAILURE;
+ }
+ }
+
+ if (ret == DECODE_SUCCESS) {
+ *idx = i;
+ return ret;
+ }
+ }
+ return ret;
+}
+
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h
new file mode 100644
index 000000000..19d94f369
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_dec.h
@@ -0,0 +1,155 @@
+/* Copyright (C)
+* 2012 - Michael.Kang blackfin.kang@gmail.com
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+*/
+
+/**
+* @file arm_dyncom_dec.h
+* @brief Some common utility for arm instruction decoder
+* @author Michael.Kang blackfin.kang@gmail.com
+* @version 7849
+* @date 2012-03-15
+*/
+
+#ifndef __ARM_DYNCOM_DEC__
+#define __ARM_DYNCOM_DEC__
+
+#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1))
+#define BIT(n) ((instr >> (n)) & 1)
+#define BAD do{printf("meet BAD at %s, instr is %x\n", __FUNCTION__, instr ); /*exit(0);*/}while(0);
+#define ptr_N cpu->ptr_N
+#define ptr_Z cpu->ptr_Z
+#define ptr_C cpu->ptr_C
+#define ptr_V cpu->ptr_V
+#define ptr_I cpu->ptr_I
+#define ptr_T cpu->ptr_T
+#define ptr_CPSR cpu->ptr_gpr[16]
+
+/* for MUL instructions */
+/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */
+#define RDHi ((instr >> 16) & 0xF)
+/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */
+#define RDLo ((instr >> 12) & 0xF)
+/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */
+#define MUL_RD ((instr >> 16) & 0xF)
+/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */
+#define MUL_RN ((instr >> 12) & 0xF)
+/*xxxx xxxx xxxx xxxx xxxx 1111 xxxx xxxx */
+#define RS ((instr >> 8) & 0xF)
+
+/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */
+#define RD ((instr >> 12) & 0xF)
+/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */
+#define RN ((instr >> 16) & 0xF)
+/*xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 */
+#define RM (instr & 0xF)
+#define BIT(n) ((instr >> (n)) & 1)
+#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1))
+
+/* CP15 registers */
+#define OPCODE_1 BITS(21, 23)
+#define CRn BITS(16, 19)
+#define CRm BITS(0, 3)
+#define OPCODE_2 BITS(5, 7)
+
+/*xxxx xx1x xxxx xxxx xxxx xxxx xxxx xxxx */
+#define I BIT(25)
+/*xxxx xxxx xxx1 xxxx xxxx xxxx xxxx xxxx */
+#define S BIT(20)
+
+#define SHIFT BITS(5,6)
+#define SHIFT_IMM BITS(7,11)
+#define IMMH BITS(8,11)
+#define IMML BITS(0,3)
+
+#define LSPBIT BIT(24)
+#define LSUBIT BIT(23)
+#define LSBBIT BIT(22)
+#define LSWBIT BIT(21)
+#define LSLBIT BIT(20)
+#define LSSHBITS BITS(5,6)
+#define OFFSET12 BITS(0,11)
+#define SBIT BIT(20)
+#define DESTReg (BITS (12, 15))
+
+/* they are in unused state, give a corrent value when using */
+#define IS_V5E 0
+#define IS_V5 0
+#define IS_V6 0
+#define LHSReg 0
+
+/* temp define the using the pc reg need implement a flow */
+#define STORE_CHECK_RD_PC ADD(R(RD), CONST(INSTR_SIZE * 2))
+
+#define OPERAND operand(cpu,instr,bb,NULL)
+#define SCO_OPERAND(sco) operand(cpu,instr,bb,sco)
+#define BOPERAND boperand(instr)
+
+#define CHECK_RN_PC (RN==15? ADD(AND(R(RN), CONST(~0x1)), CONST(INSTR_SIZE * 2)):R(RN))
+#define CHECK_RN_PC_WA (RN==15? ADD(AND(R(RN), CONST(~0x3)), CONST(INSTR_SIZE * 2)):R(RN))
+
+#define GET_USER_MODE() (OR(ICMP_EQ(R(MODE_REG), CONST(USER32MODE)), ICMP_EQ(R(MODE_REG), CONST(SYSTEM32MODE))))
+
+int decode_arm_instr(uint32_t instr, int32_t *idx);
+
+enum DECODE_STATUS {
+ DECODE_SUCCESS,
+ DECODE_FAILURE
+};
+
+struct instruction_set_encoding_item {
+ const char *name;
+ int attribute_value;
+ int version;
+ u32 content[21];
+};
+
+typedef struct instruction_set_encoding_item ISEITEM;
+
+#define RECORD_WB(value, flag) {cpu->dyncom_engine->wb_value = value;cpu->dyncom_engine->wb_flag = flag;}
+#define INIT_WB(wb_value, wb_flag) RECORD_WB(wb_value, wb_flag)
+
+#define EXECUTE_WB(base_reg) {if(cpu->dyncom_engine->wb_flag) \
+ LET(base_reg, cpu->dyncom_engine->wb_value);}
+inline int get_reg_count(uint32_t instr){
+ int i = BITS(0,15);
+ int count = 0;
+ while(i){
+ if(i & 1)
+ count ++;
+ i = i >> 1;
+ }
+ return count;
+}
+
+enum ARMVER {
+ INVALID = 0,
+ ARMALL,
+ ARMV4,
+ ARMV4T,
+ ARMV5T,
+ ARMV5TE,
+ ARMV5TEJ,
+ ARMV6,
+ ARM1176JZF_S,
+ ARMVFP2,
+ ARMVFP3
+};
+
+//extern const INSTRACT arm_instruction_action[];
+extern const ISEITEM arm_instruction[];
+
+#endif
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
new file mode 100644
index 000000000..f899e2e8a
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -0,0 +1,6564 @@
+/* Copyright (C)
+* 2012 - Michael.Kang blackfin.kang@gmail.com
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+*/
+/**
+* @file arm_dyncom_interpreter.cpp
+* @brief The fast interpreter for arm
+* @author Michael.Kang blackfin.kang@gmail.com
+* @version 7849
+* @date 2012-03-15
+*/
+
+#define CITRA_IGNORE_EXIT(x)
+
+#include <algorithm>
+#include <map>
+#include <stdio.h>
+#include <assert.h>
+#include <cstdio>
+#include <vector>
+
+using namespace std;
+
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armmmu.h"
+#include "arm_dyncom_thumb.h"
+#include "arm_dyncom_run.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
+/* shenoubang 2012-6-14 */
+#ifdef __WIN32__
+#include "bank_defs.h"
+#endif
+
+#include "core/mem_map.h"
+#include "core/hle/hle.h"
+
+enum {
+ COND = (1 << 0),
+ NON_BRANCH = (1 << 1),
+ DIRECT_BRANCH = (1 << 2),
+ INDIRECT_BRANCH = (1 << 3),
+ CALL = (1 << 4),
+ RET = (1 << 5),
+ END_OF_PAGE = (1 << 6),
+ THUMB = (1 << 7)
+};
+
+#define USER_MODE_OPT 1
+#define HYBRID_MODE 0 // Enable for JIT mode
+
+#define THRESHOLD 1000
+#define DURATION 500
+//#define PRINT_PROFILE_INFO
+
+#define CHECK_RS if(RS == 15) rs += 8
+#define CHECK_RM if(RM == 15) rm += 8
+
+//#define BITS(s, a, b) (((s) >> (a)) & ((1 << (1 + (b) - (a))) - 1))
+#undef BITS
+#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
+#define BIT(s, n) ((s >> (n)) & 1)
+#define RM BITS(sht_oper, 0, 3)
+#define RS BITS(sht_oper, 8, 11)
+
+#define glue(x, y) x ## y
+#define DPO(s) glue(DataProcessingOperands, s)
+#define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i))
+#define ROTATE_LEFT(n, i, l) ((n >> (l - i)) | (n << i))
+#define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32)
+#define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32)
+
+//#define rotr(x,n) ((((x)>>(n))&((1<<(sizeof(x) * 8)-1))|(x<<(sizeof(x)*8-n))))
+//#define rotl(x,n) ((((x)<<(n))&(-(1<<(n))))|(((x)>>(sizeof(x)*8-n))&((1<<(n))-1)))
+#define rotr(x,n) ( (x >> n) | ((x & ((1 << (n + 1)) - 1)) << (32 - n)) )
+
+extern void switch_mode(arm_core_t *core, uint32_t mode);
+//extern bool InAPrivilegedMode(arm_core_t *core);
+
+typedef arm_core_t arm_processor;
+typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper);
+
+/* exclusive memory access */
+static int exclusive_detect(ARMul_State* state, ARMword addr){
+ int i;
+ #if 0
+ for(i = 0; i < 128; i++){
+ if(state->exclusive_tag_array[i] == addr)
+ return 0;
+ }
+ #endif
+ if(state->exclusive_tag == addr)
+ return 0;
+ else
+ return -1;
+}
+
+static void add_exclusive_addr(ARMul_State* state, ARMword addr){
+ int i;
+ #if 0
+ for(i = 0; i < 128; i++){
+ if(state->exclusive_tag_array[i] == 0xffffffff){
+ state->exclusive_tag_array[i] = addr;
+ //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr);
+ return;
+ }
+ }
+ DEBUG_LOG(ARM11, "In %s ,can not monitor the addr, out of array\n", __FUNCTION__);
+ #endif
+ state->exclusive_tag = addr;
+ return;
+}
+
+static void remove_exclusive(ARMul_State* state, ARMword addr){
+ #if 0
+ int i;
+ for(i = 0; i < 128; i++){
+ if(state->exclusive_tag_array[i] == addr){
+ state->exclusive_tag_array[i] = 0xffffffff;
+ //DEBUG_LOG(ARM11, "In %s, remove addr 0x%x\n", __func__, addr);
+ return;
+ }
+ }
+ #endif
+ state->exclusive_tag = 0xFFFFFFFF;
+}
+
+
+unsigned int DPO(Immediate)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ unsigned int immed_8 = BITS(sht_oper, 0, 7);
+ unsigned int rotate_imm = BITS(sht_oper, 8, 11);
+// DEBUG_LOG(ARM11, "immed_8 is %x\n", immed_8);
+// DEBUG_LOG(ARM11, "rotate_imm is %x\n", rotate_imm);
+ unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);//ROTATE_RIGHT_32(immed_8, rotate_imm * 2);
+// DEBUG_LOG(ARM11, "shifter_operand : %x\n", shifter_operand);
+ /* set c flag */
+ if (rotate_imm == 0)
+ cpu->shifter_carry_out = cpu->CFlag;
+ else
+ cpu->shifter_carry_out = BIT(shifter_operand, 31);
+ return shifter_operand;
+}
+
+unsigned int DPO(Register)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ //if (RM == 15) rm += 8;
+ unsigned int shifter_operand = rm;
+ cpu->shifter_carry_out = cpu->CFlag;
+ return shifter_operand;
+}
+
+unsigned int DPO(LogicalShiftLeftByImmediate)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ int shift_imm = BITS(sht_oper, 7, 11);
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ //if (RM == 15) rm += 8;
+ unsigned int shifter_operand;
+ if (shift_imm == 0) {
+ shifter_operand = rm;
+ cpu->shifter_carry_out = cpu->CFlag;
+ } else {
+ shifter_operand = rm << shift_imm;
+ cpu->shifter_carry_out = BIT(rm, 32 - shift_imm);
+ }
+ return shifter_operand;
+}
+
+unsigned int DPO(LogicalShiftLeftByRegister)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ int shifter_operand;
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ unsigned int rs = CHECK_READ_REG15(cpu, RS);
+ //if (RM == 15) rm += 8;
+ //if (RS == 15) rs += 8;
+ if (BITS(rs, 0, 7) == 0) {
+ shifter_operand = rm;
+ cpu->shifter_carry_out = cpu->CFlag;
+ } else if (BITS(rs, 0, 7) < 32) {
+ shifter_operand = rm << BITS(rs, 0, 7);
+ cpu->shifter_carry_out = BIT(rm, 32 - BITS(rs, 0, 7));
+ } else if (BITS(rs, 0, 7) == 32) {
+ shifter_operand = 0;
+ cpu->shifter_carry_out = BIT(rm, 0);
+ } else {
+ shifter_operand = 0;
+ cpu->shifter_carry_out = 0;
+ }
+ return shifter_operand;
+}
+
+unsigned int DPO(LogicalShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ //unsigned int rm = cpu->Reg[RM];
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ //if (RM == 15) rm += 8;
+ unsigned int shifter_operand;
+ int shift_imm = BITS(sht_oper, 7, 11);
+ if (shift_imm == 0) {
+ shifter_operand = 0;
+ cpu->shifter_carry_out = BIT(rm, 31);
+ } else {
+ shifter_operand = rm >> shift_imm;
+ cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
+ }
+ return shifter_operand;
+}
+
+unsigned int DPO(LogicalShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ unsigned int rs = CHECK_READ_REG15(cpu, RS);
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ //if (RS == 15) rs += 8;
+ //if (RM == 15) rm += 8;
+ unsigned int shifter_operand;
+ if (BITS(rs, 0, 7) == 0) {
+ shifter_operand = rm;
+ cpu->shifter_carry_out = cpu->CFlag;
+ } else if (BITS(rs, 0, 7) < 32) {
+ shifter_operand = rm >> BITS(rs, 0, 7);
+ cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
+ } else if (BITS(rs, 0, 7) == 32) {
+ shifter_operand = 0;
+ cpu->shifter_carry_out = BIT(rm, 31);
+ } else {
+ shifter_operand = 0;
+ cpu->shifter_carry_out = 0;
+ }
+ return shifter_operand;
+}
+
+unsigned int DPO(ArithmeticShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ //unsigned int rm = cpu->Reg[RM];
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ //if (RM == 15) rm += 8;
+ unsigned int shifter_operand;
+ int shift_imm = BITS(sht_oper, 7, 11);
+ if (shift_imm == 0) {
+ if (BIT(rm, 31)) {
+ shifter_operand = 0;
+ cpu->shifter_carry_out = BIT(rm, 31);
+ } else {
+ shifter_operand = 0xFFFFFFFF;
+ cpu->shifter_carry_out = BIT(rm, 31);
+ }
+ } else {
+ shifter_operand = static_cast<int>(rm) >> shift_imm;
+ cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
+ }
+ return shifter_operand;
+}
+
+unsigned int DPO(ArithmeticShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ //unsigned int rs = cpu->Reg[RS];
+ unsigned int rs = CHECK_READ_REG15(cpu, RS);
+ //unsigned int rm = cpu->Reg[RM];
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ //if (RS == 15) rs += 8;
+ //if (RM == 15) rm += 8;
+ unsigned int shifter_operand;
+ if (BITS(rs, 0, 7) == 0) {
+ shifter_operand = rm;
+ cpu->shifter_carry_out = cpu->CFlag;
+ } else if (BITS(rs, 0, 7) < 32) {
+ shifter_operand = static_cast<int>(rm) >> BITS(rs, 0, 7);
+ cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
+ } else {
+ if (BIT(rm, 31) == 0) {
+ shifter_operand = 0;
+ } else
+ shifter_operand = 0xffffffff;
+ cpu->shifter_carry_out = BIT(rm, 31);
+ }
+ return shifter_operand;
+}
+
+unsigned int DPO(RotateRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ unsigned int shifter_operand;
+ //unsigned int rm = cpu->Reg[RM];
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ //if (RM == 15) rm += 8;
+ int shift_imm = BITS(sht_oper, 7, 11);
+ if (shift_imm == 0) {
+ shifter_operand = (cpu->CFlag << 31) |
+ (rm >> 1);
+ cpu->shifter_carry_out = BIT(rm, 0);
+ } else {
+ shifter_operand = ROTATE_RIGHT_32(rm, shift_imm);
+ cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
+ }
+ return shifter_operand;
+}
+
+unsigned int DPO(RotateRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
+{
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ unsigned int rm = CHECK_READ_REG15(cpu, RM);
+ //if (RM == 15) rm += 8;
+ unsigned int rs = CHECK_READ_REG15(cpu, RS);
+ //if (RS == 15) rs += 8;
+ unsigned int shifter_operand;
+ if (BITS(rs, 0, 7) == 0) {
+ shifter_operand = rm;
+ cpu->shifter_carry_out = cpu->CFlag;
+ } else if (BITS(rs, 0, 4) == 0) {
+ shifter_operand = rm;
+ cpu->shifter_carry_out = BIT(rm, 31);
+ } else {
+ shifter_operand = ROTATE_RIGHT_32(rm, BITS(rs, 0, 4));
+ cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 4) - 1);
+ }
+ #if 0
+ if (cpu->icounter >= 20371544) {
+ DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ DEBUG_LOG(ARM11, "RM:%d\nRS:%d\n", RM, RS);
+ DEBUG_LOG(ARM11, "rm:0x%08x\nrs:0x%08x\n", cpu->Reg[RM], cpu->Reg[RS]);
+ }
+ #endif
+ return shifter_operand;
+}
+
+//typedef unsigned int (*get_addr_fp_t)(arm_processor *cpu);
+typedef struct _MiscImmeData {
+ unsigned int U;
+ unsigned int Rn;
+ unsigned int offset_8;
+} MiscLSData;
+
+typedef struct _MiscRegData {
+ unsigned int U;
+ unsigned int Rn;
+ unsigned int Rm;
+} MiscRegData;
+
+typedef struct _MiscImmePreIdx {
+ unsigned int offset_8;
+ unsigned int U;
+ unsigned int Rn;
+} MiscImmePreIdx;
+
+typedef struct _MiscRegPreIdx {
+ unsigned int U;
+ unsigned int Rn;
+ unsigned int Rm;
+} MiscRegPreIdx;
+
+typedef struct _MiscImmePstIdx {
+ unsigned int offset_8;
+ unsigned int U;
+ unsigned int Rn;
+} MIscImmePstIdx;
+
+typedef struct _MiscRegPstIdx {
+ unsigned int Rn;
+ unsigned int Rm;
+ unsigned int U;
+} MiscRegPstIdx;
+
+typedef struct _LSWordorUnsignedByte {
+} LDnST;
+
+#if USER_MODE_OPT
+static inline fault_t interpreter_read_memory(addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size){
+ switch(size) {
+ case 8:
+ value = Memory::Read8(virt_addr);
+ break;
+ case 16:
+ value = Memory::Read16(virt_addr);
+ break;
+ case 32:
+ value = Memory::Read32(virt_addr);
+ break;
+ }
+ return NO_FAULT;
+}
+
+//static inline void interpreter_write_memory(void *mem_ptr, uint32_t offset, uint32_t value, int size)
+static inline fault_t interpreter_write_memory(addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size)
+{
+ switch(size) {
+ case 8:
+ Memory::Write8(virt_addr, value & 0xff);
+ break;
+ case 16:
+ Memory::Write16(virt_addr, value & 0xffff);
+ break;
+ case 32:
+ Memory::Write32(virt_addr, value);
+ break;
+ }
+ return NO_FAULT;
+}
+
+static inline fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw){
+ *phys_addr = virt_addr;
+ return NO_FAULT;
+}
+
+#else
+fault_t interpreter_read_memory(cpu_t *cpu, addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size);
+fault_t interpreter_write_memory(cpu_t *cpu, addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size);
+fault_t interpreter_fetch(cpu_t *cpu, addr_t virt_addr, uint32_t &value, uint32_t size);
+fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw, tlb_type_t access_type = DATA_TLB);
+#endif
+
+typedef fault_t (*get_addr_fp_t)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw);
+
+typedef struct _ldst_inst {
+ unsigned int inst;
+ get_addr_fp_t get_addr;
+} ldst_inst;
+#define DEBUG_MSG DEBUG_LOG(ARM11, "in %s %d\n", __FUNCTION__, __LINE__); \
+ DEBUG_LOG(ARM11, "inst is %x\n", inst); \
+ CITRA_IGNORE_EXIT(0)
+
+int CondPassed(arm_processor *cpu, unsigned int cond);
+#define LnSWoUB(s) glue(LnSWoUB, s)
+#define MLnS(s) glue(MLnS, s)
+#define LdnStM(s) glue(LdnStM, s)
+
+#define W_BIT BIT(inst, 21)
+#define U_BIT BIT(inst, 23)
+#define I_BIT BIT(inst, 25)
+#define P_BIT BIT(inst, 24)
+#define OFFSET_12 BITS(inst, 0, 11)
+fault_t LnSWoUB(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int addr;
+ fault_t fault;
+ if (U_BIT) {
+ addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12;
+ } else {
+ addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12;
+ }
+ //if (Rn == 15) rn += 8;
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ return fault;
+// return addr;
+}
+
+fault_t LnSWoUB(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ //if (Rm == 15) rm += 8;
+ unsigned int addr;
+ if (U_BIT) {
+ addr = rn + rm;
+ } else {
+ addr = rn - rm;
+ }
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ return fault;
+}
+
+fault_t LnSWoUB(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) addr += 8;
+
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if (fault) return fault;
+
+ if (U_BIT) {
+ cpu->Reg[Rn] += OFFSET_12;
+ } else {
+ cpu->Reg[Rn] -= OFFSET_12;
+ }
+ return fault;
+}
+
+fault_t LnSWoUB(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int addr;
+ if (U_BIT) {
+ addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12;
+ } else {
+ addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12;
+ }
+ #if 0
+ if (Rn == 15) {
+ addr += 8;
+ }
+ #endif
+
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ cpu->Reg[Rn] = addr;
+ }
+ return fault;
+}
+
+fault_t MLnS(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int addr;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ //if (Rn == 15) rn += 8;
+ //if (Rm == 15) rm += 8;
+ if (U_BIT) {
+ addr = rn + rm;
+ } else
+ addr = rn - rm;
+ if(BIT(inst, 20)){ /* L BIT */
+ }
+ if(BIT(inst, 6)){ /* Sign Bit */
+ }
+ if(BIT(inst, 5)){ /* Half Bit */
+ }
+
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ cpu->Reg[Rn] = addr;
+ }
+ return fault;
+}
+
+fault_t LnSWoUB(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ //if (Rm == 15) rm += 8;
+ unsigned int addr;
+ if (U_BIT) {
+ addr = rn + rm;
+ } else {
+ addr = rn - rm;
+ }
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if(fault)
+ return fault;
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ cpu->Reg[Rn] = addr;
+ }
+ return fault;
+}
+fault_t LnSWoUB(ScaledRegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int shift = BITS(inst, 5, 6);
+ unsigned int shift_imm = BITS(inst, 7, 11);
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int index;
+ unsigned int addr;
+
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ //if (Rm == 15) rm += 8;
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+ switch (shift) {
+ case 0:
+ //DEBUG_MSG;
+ index = rm << shift_imm;
+ break;
+ case 1:
+// DEBUG_MSG;
+ if (shift_imm == 0) {
+ index = 0;
+ } else {
+ index = rm >> shift_imm;
+ }
+ break;
+ case 2:
+ DEBUG_MSG;
+ break;
+ case 3:
+ DEBUG_MSG;
+ break;
+ }
+ if (U_BIT) {
+ addr = rn + index;
+ } else
+ addr = rn - index;
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if(fault)
+ return fault;
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ cpu->Reg[Rn] = addr;
+ }
+
+ return fault;
+}
+
+fault_t LnSWoUB(ScaledRegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int shift = BITS(inst, 5, 6);
+ unsigned int shift_imm = BITS(inst, 7, 11);
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int index;
+ unsigned int addr;
+
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ //if (Rm == 15) rm += 8;
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+ addr = rn;
+ switch (shift) {
+ case 0:
+ //DEBUG_MSG;
+ index = rm << shift_imm;
+ break;
+ case 1:
+// DEBUG_MSG;
+ if (shift_imm == 0) {
+ index = 0;
+ } else {
+ index = rm >> shift_imm;
+ }
+ break;
+ case 2:
+ DEBUG_MSG;
+ break;
+ case 3:
+ DEBUG_MSG;
+ break;
+ }
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if(fault)
+ return fault;
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ if (U_BIT)
+ cpu->Reg[Rn] += index;
+ else
+ cpu->Reg[Rn] -= index;
+ }
+
+ return fault;
+}
+
+fault_t LnSWoUB(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+
+ unsigned int addr = rn;
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ if (U_BIT) {
+ cpu->Reg[Rn] += rm;
+ } else {
+ cpu->Reg[Rn] -= rm;
+ }
+ }
+ return fault;
+}
+
+fault_t MLnS(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int immedL = BITS(inst, 0, 3);
+ unsigned int immedH = BITS(inst, 8, 11);
+
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int addr;
+
+ unsigned int offset_8 = (immedH << 4) | immedL;
+ if (U_BIT) {
+ addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8;
+ } else
+ addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8;
+ #if 0
+ if (Rn == 15) {
+ addr += 8;
+ }
+ #endif
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ return fault;
+}
+
+fault_t MLnS(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int addr;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ //if (Rn == 15) rn += 8;
+ //if (Rm == 15) rm += 8;
+ if (U_BIT) {
+ addr = rn + rm;
+ } else
+ addr = rn - rm;
+ if(BIT(inst, 20)){ /* L BIT */
+ }
+ if(BIT(inst, 6)){ /* Sign Bit */
+ }
+ if(BIT(inst, 5)){ /* Half Bit */
+ }
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ return fault;
+}
+
+fault_t MLnS(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int immedH = BITS(inst, 8, 11);
+ unsigned int immedL = BITS(inst, 0, 3);
+ unsigned int addr;
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+
+// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
+ unsigned int offset_8 = (immedH << 4) | immedL;
+ if (U_BIT) {
+ addr = rn + offset_8;
+ } else
+ addr = rn - offset_8;
+
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ cpu->Reg[Rn] = addr;
+ }
+ return fault;
+}
+
+fault_t MLnS(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int immedH = BITS(inst, 8, 11);
+ unsigned int immedL = BITS(inst, 0, 3);
+ unsigned int addr;
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ addr = rn;
+
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ unsigned int offset_8 = (immedH << 4) | immedL;
+ if (U_BIT) {
+ rn += offset_8;
+ } else {
+ rn -= offset_8;
+ }
+ cpu->Reg[Rn] = rn;
+ }
+
+ return fault;
+}
+fault_t MLnS(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+
+ unsigned int addr = rn;
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31))) {
+ if (U_BIT) {
+ cpu->Reg[Rn] += rm;
+ } else {
+ cpu->Reg[Rn] -= rm;
+ }
+ }
+ return fault;
+}
+
+fault_t LdnStM(DecrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int i = BITS(inst, 0, 15);
+ int count = 0;
+ while(i) {
+ if(i & 1) count ++;
+ i = i >> 1;
+ }
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+ unsigned int start_addr = rn - count * 4;
+ unsigned int end_addr = rn - 4;
+
+ fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
+ virt_addr = end_addr;
+ if (fault) return fault;
+
+ fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
+ virt_addr = start_addr;
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
+ cpu->Reg[Rn] -= count * 4;
+ }
+
+ return fault;
+}
+
+fault_t LdnStM(IncrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int i = BITS(inst, 0, 15);
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+ int count = 0;
+ while(i) {
+ if(i & 1) count ++;
+ i = i >> 1;
+ }
+
+ unsigned int start_addr = rn + 4;
+ unsigned int end_addr = rn + count * 4;
+
+ fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
+ virt_addr = end_addr;
+ if (fault) return fault;
+
+ fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
+ virt_addr = start_addr;
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
+ cpu->Reg[Rn] += count * 4;
+ }
+ return fault;
+}
+
+fault_t LdnStM(IncrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int i = BITS(inst, 0, 15);
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ int count = 0;
+ while(i) {
+ if(i & 1) count ++;
+ i = i >> 1;
+ }
+ //if (Rn == 15) rn += 8;
+ unsigned int start_addr = rn;
+ unsigned int end_addr = rn + count * 4 - 4;
+
+ fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
+ virt_addr = end_addr;
+ if (fault) return fault;
+
+ fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
+ virt_addr = start_addr;
+ if (fault) return fault;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
+ cpu->Reg[Rn] += count * 4;
+ }
+ return fault;
+}
+
+fault_t LdnStM(DecrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int i = BITS(inst, 0, 15);
+ int count = 0;
+ while(i) {
+ if(i & 1) count ++;
+ i = i >> 1;
+ }
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+ unsigned int start_addr = rn - count * 4 + 4;
+ unsigned int end_addr = rn;
+
+ fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
+ virt_addr = end_addr;
+ if (fault) return fault;
+
+ fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
+ if (fault) return fault;
+ virt_addr = start_addr;
+
+ if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
+ cpu->Reg[Rn] -= count * 4;
+ }
+ return fault;
+}
+
+fault_t LnSWoUB(ScaledRegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
+{
+ fault_t fault;
+ unsigned int shift = BITS(inst, 5, 6);
+ unsigned int shift_imm = BITS(inst, 7, 11);
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int Rm = BITS(inst, 0, 3);
+ unsigned int index;
+ unsigned int addr;
+
+ unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
+ //if (Rm == 15) rm += 8;
+ unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
+ //if (Rn == 15) rn += 8;
+ switch (shift) {
+ case 0:
+ //DEBUG_MSG;
+ index = rm << shift_imm;
+ break;
+ case 1:
+// DEBUG_MSG;
+ if (shift_imm == 0) {
+ index = 0;
+ } else {
+ index = rm >> shift_imm;
+ }
+ break;
+ case 2:
+ if (shift_imm == 0){ /* ASR #32 */
+ if (rm >> 31)
+ index = 0xFFFFFFFF;
+ else
+ index = 0;
+ }
+ else {
+ index = static_cast<int>(rm) >> shift_imm;
+ }
+ break;
+ case 3:
+ DEBUG_MSG;
+ break;
+ }
+ if (U_BIT) {
+ addr = rn + index;
+ } else
+ addr = rn - index;
+ virt_addr = addr;
+ fault = check_address_validity(cpu, addr, &phys_addr, rw);
+ return fault;
+}
+
+#define ISNEG(n) (n < 0)
+#define ISPOS(n) (n >= 0)
+
+//enum {
+// COND = (1 << 0),
+// NON_BRANCH = (1 << 1),
+// DIRECT_BRANCH = (1 << 2),
+// INDIRECT_BRANCH = (1 << 3),
+// CALL = (1 << 4),
+// RET = (1 << 5),
+// END_OF_PAGE = (1 << 6),
+// THUMB = (1 << 7)
+//};
+
+typedef struct _arm_inst {
+ unsigned int idx;
+ unsigned int cond;
+ int br;
+ int load_r15;
+ char component[0];
+} arm_inst;
+
+typedef struct _adc_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} adc_inst;
+
+typedef struct _add_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} add_inst;
+
+typedef struct _orr_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} orr_inst;
+
+typedef struct _and_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} and_inst;
+
+typedef struct _eor_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} eor_inst;
+
+typedef struct _bbl_inst {
+ unsigned int L;
+ int signed_immed_24;
+ unsigned int next_addr;
+ unsigned int jmp_addr;
+} bbl_inst;
+
+typedef struct _bx_inst {
+ unsigned int Rm;
+} bx_inst;
+
+typedef struct _blx_inst {
+ union {
+ int32_t signed_immed_24;
+ uint32_t Rm;
+ } val;
+ unsigned int inst;
+} blx_inst;
+
+typedef struct _clz_inst {
+ unsigned int Rm;
+ unsigned int Rd;
+} clz_inst;
+
+typedef struct _cps_inst {
+ unsigned int imod0;
+ unsigned int imod1;
+ unsigned int mmod;
+ unsigned int A, I, F;
+ unsigned int mode;
+} cps_inst;
+
+typedef struct _clrex_inst {
+} clrex_inst;
+
+typedef struct _cpy_inst {
+ unsigned int Rm;
+ unsigned int Rd;
+} cpy_inst;
+
+typedef struct _bic_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} bic_inst;
+
+typedef struct _sub_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} sub_inst;
+
+typedef struct _tst_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} tst_inst;
+
+typedef struct _cmn_inst {
+ unsigned int I;
+ //unsigned int S;
+ unsigned int Rn;
+ //unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} cmn_inst;
+
+typedef struct _teq_inst {
+ unsigned int I;
+ unsigned int Rn;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} teq_inst;
+
+typedef struct _stm_inst {
+ unsigned int inst;
+} stm_inst;
+
+struct bkpt_inst {
+};
+
+struct blx1_inst {
+ unsigned int addr;
+};
+
+struct blx2_inst {
+ unsigned int Rm;
+};
+
+typedef struct _stc_inst {
+} stc_inst;
+
+typedef struct _ldc_inst {
+} ldc_inst;
+
+typedef struct _swi_inst {
+ unsigned int num;
+} swi_inst;
+
+typedef struct _cmp_inst {
+ unsigned int I;
+ unsigned int Rn;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} cmp_inst;
+
+typedef struct _mov_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} mov_inst;
+
+typedef struct _mvn_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} mvn_inst;
+
+typedef struct _rev_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+} rev_inst;
+
+typedef struct _rsb_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} rsb_inst;
+
+typedef struct _rsc_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} rsc_inst;
+
+typedef struct _sbc_inst {
+ unsigned int I;
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int shifter_operand;
+ shtop_fp_t shtop_func;
+} sbc_inst;
+
+typedef struct _mul_inst {
+ unsigned int S;
+ unsigned int Rd;
+ unsigned int Rs;
+ unsigned int Rm;
+} mul_inst;
+
+typedef struct _smul_inst {
+ unsigned int Rd;
+ unsigned int Rs;
+ unsigned int Rm;
+ unsigned int x;
+ unsigned int y;
+} smul_inst;
+
+typedef struct _umull_inst {
+ unsigned int S;
+ unsigned int RdHi;
+ unsigned int RdLo;
+ unsigned int Rs;
+ unsigned int Rm;
+} umull_inst;
+typedef struct _smlad_inst {
+ unsigned int m;
+ unsigned int Rm;
+ unsigned int Rd;
+ unsigned int Ra;
+ unsigned int Rn;
+} smlad_inst;
+
+typedef struct _smla_inst {
+ unsigned int x;
+ unsigned int y;
+ unsigned int Rm;
+ unsigned int Rd;
+ unsigned int Rs;
+ unsigned int Rn;
+} smla_inst;
+
+typedef struct _umlal_inst {
+ unsigned int S;
+ unsigned int Rm;
+ unsigned int Rs;
+ unsigned int RdHi;
+ unsigned int RdLo;
+} umlal_inst;
+
+typedef struct _smlal_inst {
+ unsigned int S;
+ unsigned int Rm;
+ unsigned int Rs;
+ unsigned int RdHi;
+ unsigned int RdLo;
+} smlal_inst;
+
+typedef struct _mla_inst {
+ unsigned int S;
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int Rs;
+ unsigned int Rm;
+} mla_inst;
+
+typedef struct _mrc_inst {
+ unsigned int opcode_1;
+ unsigned int opcode_2;
+ unsigned int cp_num;
+ unsigned int crn;
+ unsigned int crm;
+ unsigned int Rd;
+ unsigned int inst;
+} mrc_inst;
+
+typedef struct _mcr_inst {
+ unsigned int opcode_1;
+ unsigned int opcode_2;
+ unsigned int cp_num;
+ unsigned int crn;
+ unsigned int crm;
+ unsigned int Rd;
+ unsigned int inst;
+} mcr_inst;
+
+typedef struct _mrs_inst {
+ unsigned int R;
+ unsigned int Rd;
+} mrs_inst;
+
+typedef struct _msr_inst {
+ unsigned int field_mask;
+ unsigned int R;
+ unsigned int inst;
+} msr_inst;
+
+typedef struct _pld_inst {
+} pld_inst;
+
+typedef struct _sxtb_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int rotate;
+} sxtb_inst;
+
+typedef struct _sxtab_inst {
+ unsigned int Rd;
+ unsigned int Rn;
+ unsigned int Rm;
+ unsigned rotate;
+} sxtab_inst;
+
+typedef struct _sxtah_inst {
+ unsigned int Rd;
+ unsigned int Rn;
+ unsigned int Rm;
+ unsigned int rotate;
+} sxtah_inst;
+
+typedef struct _sxth_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int rotate;
+} sxth_inst;
+
+typedef struct _uxtab_inst {
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int rotate;
+ unsigned int Rm;
+} uxtab_inst;
+
+typedef struct _uxtah_inst {
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int rotate;
+ unsigned int Rm;
+} uxtah_inst;
+
+typedef struct _uxth_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int rotate;
+} uxth_inst;
+
+typedef struct _cdp_inst {
+ unsigned int opcode_1;
+ unsigned int CRn;
+ unsigned int CRd;
+ unsigned int cp_num;
+ unsigned int opcode_2;
+ unsigned int CRm;
+ uint32 inst;
+}cdp_inst;
+
+typedef struct _uxtb_inst {
+ unsigned int Rd;
+ unsigned int Rm;
+ unsigned int rotate;
+} uxtb_inst;
+
+typedef struct _swp_inst {
+ unsigned int Rn;
+ unsigned int Rd;
+ unsigned int Rm;
+} swp_inst;
+
+typedef struct _b_2_thumb {
+ unsigned int imm;
+}b_2_thumb;
+typedef struct _b_cond_thumb {
+ unsigned int imm;
+ unsigned int cond;
+}b_cond_thumb;
+
+typedef struct _bl_1_thumb {
+ unsigned int imm;
+}bl_1_thumb;
+typedef struct _bl_2_thumb {
+ unsigned int imm;
+}bl_2_thumb;
+typedef struct _blx_1_thumb {
+ unsigned int imm;
+ unsigned int instr;
+}blx_1_thumb;
+
+typedef arm_inst * ARM_INST_PTR;
+
+#define CACHE_BUFFER_SIZE (64 * 1024 * 2000)
+char inst_buf[CACHE_BUFFER_SIZE];
+int top = 0;
+inline void *AllocBuffer(unsigned int size)
+{
+ int start = top;
+ top += size;
+ if (top > CACHE_BUFFER_SIZE) {
+ DEBUG_LOG(ARM11, "inst_buf is full\n");
+ CITRA_IGNORE_EXIT(-1);
+ }
+ return (void *)&inst_buf[start];
+}
+
+int CondPassed(arm_processor *cpu, unsigned int cond)
+{
+ #define NFLAG cpu->NFlag
+ #define ZFLAG cpu->ZFlag
+ #define CFLAG cpu->CFlag
+ #define VFLAG cpu->VFlag
+ int temp;
+ switch (cond) {
+ case 0x0:
+ temp = ZFLAG;
+ break;
+ case 0x1: /* NE */
+ temp = !ZFLAG;
+ break;
+ case 0x6: /* VS */
+ temp = VFLAG;
+ break;
+ case 0x7: /* VC */
+ temp = !VFLAG;
+ break;
+ case 0x4: /* MI */
+ temp = NFLAG;
+ break;
+ case 0x5: /* PL */
+ temp = !NFLAG;
+ break;
+ case 0x2: /* CS */
+ temp = CFLAG;
+ break;
+ case 0x3: /* CC */
+ temp = !CFLAG;
+ break;
+ case 0x8: /* HI */
+ temp = (CFLAG && !ZFLAG);
+ break;
+ case 0x9: /* LS */
+ temp = (!CFLAG || ZFLAG);
+ break;
+ case 0xa: /* GE */
+ temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
+ break;
+ case 0xb: /* LT */
+ temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
+ break;
+ case 0xc: /* GT */
+ temp = ((!NFLAG && !VFLAG && !ZFLAG)
+ || (NFLAG && VFLAG && !ZFLAG));
+ break;
+ case 0xd: /* LE */
+ temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG))
+ || ZFLAG;
+ break;
+ case 0xe: /* AL */
+ temp = 1;
+ break;
+ case 0xf:
+// DEBUG_LOG(ARM11, "inst is %x\n");
+// DEBUG_LOG(ARM11, "icounter is %lld\n", cpu->icounter);
+// CITRA_IGNORE_EXIT(-1);
+ temp = 1;
+ break;
+ }
+ return temp;
+}
+
+enum DECODE_STATUS {
+ DECODE_SUCCESS,
+ DECODE_FAILURE
+};
+
+int decode_arm_instr(uint32_t instr, int32_t *idx);
+
+shtop_fp_t get_shtop(unsigned int inst)
+{
+ if (BIT(inst, 25)) {
+ return DPO(Immediate);
+ } else if (BITS(inst, 4, 11) == 0) {
+ return DPO(Register);
+ } else if (BITS(inst, 4, 6) == 0) {
+ return DPO(LogicalShiftLeftByImmediate);
+ } else if (BITS(inst, 4, 7) == 1) {
+ return DPO(LogicalShiftLeftByRegister);
+ } else if (BITS(inst, 4, 6) == 2) {
+ return DPO(LogicalShiftRightByImmediate);
+ } else if (BITS(inst, 4, 7) == 3) {
+ return DPO(LogicalShiftRightByRegister);
+ } else if (BITS(inst, 4, 6) == 4) {
+ return DPO(ArithmeticShiftRightByImmediate);
+ } else if (BITS(inst, 4, 7) == 5) {
+ return DPO(ArithmeticShiftRightByRegister);
+ } else if (BITS(inst, 4, 6) == 6) {
+ return DPO(RotateRightByImmediate);
+ } else if (BITS(inst, 4, 7) == 7) {
+ return DPO(RotateRightByRegister);
+ }
+ return NULL;
+}
+
+get_addr_fp_t get_calc_addr_op(unsigned int inst)
+{
+ /* 1 */
+ if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) {
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return LnSWoUB(ImmediateOffset);
+ } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
+// DEBUG_MSG;
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return LnSWoUB(RegisterOffset);
+ } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) {
+// DEBUG_MSG;
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return LnSWoUB(ScaledRegisterOffset);
+ } else if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 1) {
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return LnSWoUB(ImmediatePreIndexed);
+ } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BITS(inst, 4, 11) == 0) {
+ return LnSWoUB(RegisterPreIndexed);
+ } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BIT(inst, 4) == 0) {
+ return LnSWoUB(ScaledRegisterPreIndexed);
+ } else if (BITS(inst, 24, 27) == 4 && BIT(inst, 21) == 0) {
+ return LnSWoUB(ImmediatePostIndexed);
+ } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
+// DEBUG_MSG;
+ return LnSWoUB(RegisterPostIndexed);
+ } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) {
+ return LnSWoUB(ScaledRegisterPostIndexed);
+// DEBUG_MSG;
+ } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
+ /* 2 */
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return MLnS(ImmediateOffset);
+// DEBUG_MSG;
+ } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
+// DEBUG_LOG(ARM11, "line is %d\n", __LINE__);
+ return MLnS(RegisterOffset);
+// DEBUG_MSG;
+ } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 3 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
+// DEBUG_LOG(ARM11, "line is %d\n", __LINE__);
+ return MLnS(ImmediatePreIndexed);
+// DEBUG_MSG;
+ } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 1 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
+ return MLnS(RegisterPreIndexed);
+ } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
+// DEBUG_MSG;
+ return MLnS(ImmediatePostIndexed);
+ } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
+ //DEBUG_MSG;
+ return MLnS(RegisterPostIndexed);
+ } else if (BITS(inst, 23, 27) == 0x11) {
+ /* 3 */
+// DEBUG_MSG;
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return LdnStM(IncrementAfter);
+ } else if (BITS(inst, 23, 27) == 0x13) {
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return LdnStM(IncrementBefore);
+// DEBUG_MSG;
+ } else if (BITS(inst, 23, 27) == 0x10) {
+// DEBUG_MSG;
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return LdnStM(DecrementAfter);
+ } else if (BITS(inst, 23, 27) == 0x12) {
+// DEBUG_MSG;
+// DEBUG_LOG(ARM11, "line is %d", __LINE__);
+ return LdnStM(DecrementBefore);
+ }
+ #if 0
+ DEBUG_LOG(ARM11, "In %s Unknown addressing mode\n", __FUNCTION__);
+ DEBUG_LOG(ARM11, "inst:%x\n", inst);
+ CITRA_IGNORE_EXIT(-1);
+ #endif
+ return NULL;
+}
+
+#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s)
+
+#define CHECK_RN (inst_cream->Rn == 15)
+#define CHECK_RM (inst_cream->Rm == 15)
+#define CHECK_RS (inst_cream->Rs == 15)
+
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst));
+ adc_inst *inst_cream = (adc_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst));
+ add_inst *inst_cream = (add_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst));
+ and_inst *inst_cream = (and_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (inst_cream->Rd == 15)
+ inst_base->br = INDIRECT_BRANCH;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index)
+{
+ #define POSBRANCH ((inst & 0x7fffff) << 2)
+ #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2)
+
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst));
+ bbl_inst *inst_cream = (bbl_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = DIRECT_BRANCH;
+
+ if (BIT(inst, 24))
+ inst_base->br = CALL;
+ if (BITS(inst, 28, 31) <= 0xe)
+ inst_base->br |= COND;
+
+ inst_cream->L = BIT(inst, 24);
+ inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst));
+ bic_inst *inst_cream = (bic_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+
+ if (inst_cream->Rd == 15)
+ inst_base->br = INDIRECT_BRANCH;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst));
+ blx_inst *inst_cream = (blx_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = INDIRECT_BRANCH;
+
+ inst_cream->inst = inst;
+ if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
+ inst_cream->val.Rm = BITS(inst, 0, 3);
+ } else {
+ inst_cream->val.signed_immed_24 = BITS(inst, 0, 23);
+ //DEBUG_LOG(ARM11, " blx inst is %x\n", inst);
+ //CITRA_IGNORE_EXIT(-1);
+// DEBUG_MSG;
+ }
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst));
+ bx_inst *inst_cream = (bx_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = INDIRECT_BRANCH;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst));
+ cdp_inst *inst_cream = (cdp_inst *)inst_base->component;
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->CRm = BITS(inst, 0, 3);
+ inst_cream->CRd = BITS(inst, 12, 15);
+ inst_cream->CRn = BITS(inst, 16, 19);
+ inst_cream->cp_num = BITS(inst, 8, 11);
+ inst_cream->opcode_2 = BITS(inst, 5, 7);
+ inst_cream->opcode_1 = BITS(inst, 20, 23);
+ inst_cream->inst = inst;
+
+ DEBUG_LOG(ARM11, "in func %s inst %x index %x\n", __FUNCTION__, inst, index);
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst));
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst));
+ clz_inst *inst_cream = (clz_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ if (CHECK_RM)
+ inst_base->load_r15 = 1;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst));
+ cmn_inst *inst_cream = (cmn_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ //inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ //inst_cream->Rd = BITS(inst, 12, 15);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst));
+ cmp_inst *inst_cream = (cmp_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst));
+ cps_inst *inst_cream = (cps_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->imod0 = BIT(inst, 18);
+ inst_cream->imod1 = BIT(inst, 19);
+ inst_cream->mmod = BIT(inst, 17);
+ inst_cream->A = BIT(inst, 8);
+ inst_cream->I = BIT(inst, 7);
+ inst_cream->F = BIT(inst, 6);
+ inst_cream->mode = BITS(inst, 0, 4);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
+ mov_inst *inst_cream = (mov_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst));
+ eor_inst *inst_cream = (eor_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst));
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BIT(inst, 15)) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
+ sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ if (CHECK_RM)
+ inst_base->load_r15 = 1;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
+ uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ if (CHECK_RM)
+ inst_base->load_r15 = 1;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst));
+ uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ if (CHECK_RM || CHECK_RN)
+ inst_base->load_r15 = 1;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ if (I_BIT == 0) {
+ inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
+ } else {
+ DEBUG_MSG;
+ }
+ #if 0
+ inst_cream->get_addr = get_calc_addr_op(inst);
+ if(inst == 0x54f13001) {
+ DEBUG_LOG(ARM11, "get_calc_addr_op:%llx\n", inst_cream->get_addr);
+ }
+ #endif
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ return inst_base;
+}
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ //inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ if (I_BIT == 0) {
+ inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
+ } else {
+ DEBUG_MSG;
+ }
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst));
+ mcr_inst *inst_cream = (mcr_inst *)inst_base->component;
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->crn = BITS(inst, 16, 19);
+ inst_cream->crm = BITS(inst, 0, 3);
+ inst_cream->opcode_1 = BITS(inst, 21, 23);
+ inst_cream->opcode_2 = BITS(inst, 5, 7);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->cp_num = BITS(inst, 8, 11);
+ inst_cream->inst = inst;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst));
+ mla_inst *inst_cream = (mla_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 12, 15);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ if (CHECK_RM || CHECK_RN || CHECK_RS)
+ inst_base->load_r15 = 1;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
+ mov_inst *inst_cream = (mov_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst));
+ mrc_inst *inst_cream = (mrc_inst *)inst_base->component;
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->crn = BITS(inst, 16, 19);
+ inst_cream->crm = BITS(inst, 0, 3);
+ inst_cream->opcode_1 = BITS(inst, 21, 23);
+ inst_cream->opcode_2 = BITS(inst, 5, 7);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->cp_num = BITS(inst, 8, 11);
+ inst_cream->inst = inst;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst));
+ mrs_inst *inst_cream = (mrs_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->R = BIT(inst, 22);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst));
+ msr_inst *inst_cream = (msr_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->field_mask = BITS(inst, 16, 19);
+ inst_cream->R = BIT(inst, 22);
+ inst_cream->inst = inst;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst));
+ mul_inst *inst_cream = (mul_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->Rd = BITS(inst, 16, 19);
+
+ if (CHECK_RM || CHECK_RS)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst));
+ mvn_inst *inst_cream = (mvn_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst));
+ orr_inst *inst_cream = (orr_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst));
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
+ rev_inst *inst_cream = (rev_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
+ rev_inst *inst_cream = (rev_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst));
+ rsb_inst *inst_cream = (rsb_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst));
+ rsc_inst *inst_cream = (rsc_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst));
+ sbc_inst *inst_cream = (sbc_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst));
+ smla_inst *inst_cream = (smla_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->x = BIT(inst, 5);
+ inst_cream->y = BIT(inst, 6);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Rn = BITS(inst, 12, 15);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
+ smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->m = BIT(inst, 4);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Ra = BITS(inst, 12, 15);
+
+ if (CHECK_RM )
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
+ umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+
+ if (CHECK_RM || CHECK_RS)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst));
+ smul_inst *inst_cream = (smul_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rd = BITS(inst, 16, 19);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ inst_cream->x = BIT(inst, 5);
+ inst_cream->y = BIT(inst, 6);
+
+ if (CHECK_RM || CHECK_RS)
+ inst_base->load_r15 = 1;
+ return inst_base;
+
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
+ umull_inst *inst_cream = (umull_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+
+ if (CHECK_RM || CHECK_RS)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
+ smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->m = BIT(inst, 6);
+ inst_cream->Rm = BITS(inst, 8, 11);
+ inst_cream->Rn = BITS(inst, 0, 3);
+ inst_cream->Rd = BITS(inst, 16, 19);
+
+ if (CHECK_RM || CHECK_RN)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst));
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
+ sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->rotate = BITS(inst, 10, 11);
+
+ if (CHECK_RM)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
+ uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ if (CHECK_RM)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));
+ uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+// inst_cream->get_addr = get_calc_addr_op(inst);
+ if (I_BIT == 0) {
+ inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
+ } else {
+ DEBUG_MSG;
+ }
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ inst_cream->get_addr = get_calc_addr_op(inst);
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->inst = inst;
+ if (I_BIT == 0) {
+ inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
+ } else {
+ DEBUG_MSG;
+ }
+
+ if (BITS(inst, 12, 15) == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst));
+ sub_inst *inst_cream = (sub_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst));
+ swi_inst *inst_cream = (swi_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->num = BITS(inst, 0, 23);
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
+ swp_inst *inst_cream = (swp_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
+ swp_inst *inst_cream = (swp_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rm = BITS(inst, 0, 3);
+
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst));
+ sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index){
+ DEBUG_LOG(ARM11, "in func %s, SXTAH untested\n", __func__);
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst));
+ sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->rotate = BITS(inst, 10, 11);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rn = BITS(inst, 16, 19);
+
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst));
+ teq_inst *inst_cream = (teq_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst));
+ tst_inst *inst_cream = (tst_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->I = BIT(inst, 25);
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rn = BITS(inst, 16, 19);
+ inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->shifter_operand = BITS(inst, 0, 11);
+ inst_cream->shtop_func = get_shtop(inst);
+ if (inst_cream->Rd == 15) {
+ inst_base->br = INDIRECT_BRANCH;
+ }
+
+ if (CHECK_RN)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
+ umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+
+ if (CHECK_RM || CHECK_RS)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
+ umull_inst *inst_cream = (umull_inst *)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->S = BIT(inst, 20);
+ inst_cream->Rm = BITS(inst, 0, 3);
+ inst_cream->Rs = BITS(inst, 8, 11);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+
+ if (CHECK_RM || CHECK_RS)
+ inst_base->load_r15 = 1;
+ return inst_base;
+}
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb));
+ b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component;
+
+ inst_cream->imm =((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0);
+ //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
+ inst_base->idx = index;
+ inst_base->br = DIRECT_BRANCH;
+ return inst_base;
+}
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb));
+ b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component;
+
+ inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0));
+ inst_cream->cond = ((tinst >> 8) & 0xf);
+ //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x, cond=0x%x\n", __FUNCTION__, tinst, inst_cream->imm, inst_cream->cond);
+ inst_base->idx = index;
+ inst_base->br = DIRECT_BRANCH;
+ return inst_base;
+}
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb));
+ bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component;
+
+ inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0));
+ //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
+
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb));
+ bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component;
+
+ inst_cream->imm = (tinst & 0x07FF) << 1;
+ //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
+ inst_base->idx = index;
+ inst_base->br = DIRECT_BRANCH;
+ return inst_base;
+}
+ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index)
+{
+ arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb));
+ blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component;
+
+ inst_cream->imm = (tinst & 0x07FF) << 1;
+ //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
+ inst_cream->instr = tinst;
+ inst_base->idx = index;
+ inst_base->br = DIRECT_BRANCH;
+ return inst_base;
+}
+
+ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
+
+
+
+/* Floating point VFPv3 structures and instructions */
+
+#define VFP_INTERPRETER_STRUCT
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_INTERPRETER_STRUCT
+
+#define VFP_INTERPRETER_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_INTERPRETER_TRANS
+
+
+
+typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int);
+
+const transop_fp_t arm_instruction_trans[] = {
+ #define VFP_INTERPRETER_TABLE
+ #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+ #undef VFP_INTERPRETER_TABLE
+ INTERPRETER_TRANSLATE(srs),
+ INTERPRETER_TRANSLATE(rfe),
+ INTERPRETER_TRANSLATE(bkpt),
+ INTERPRETER_TRANSLATE(blx),
+ INTERPRETER_TRANSLATE(cps),
+ INTERPRETER_TRANSLATE(pld),
+ INTERPRETER_TRANSLATE(setend),
+ INTERPRETER_TRANSLATE(clrex),
+ INTERPRETER_TRANSLATE(rev16),
+ INTERPRETER_TRANSLATE(usad8),
+ INTERPRETER_TRANSLATE(sxtb),
+ INTERPRETER_TRANSLATE(uxtb),
+ INTERPRETER_TRANSLATE(sxth),
+ INTERPRETER_TRANSLATE(sxtb16),
+ INTERPRETER_TRANSLATE(uxth),
+ INTERPRETER_TRANSLATE(uxtb16),
+ INTERPRETER_TRANSLATE(cpy),
+ INTERPRETER_TRANSLATE(uxtab),
+ INTERPRETER_TRANSLATE(ssub8),
+ INTERPRETER_TRANSLATE(shsub8),
+ INTERPRETER_TRANSLATE(ssubaddx),
+ INTERPRETER_TRANSLATE(strex),
+ INTERPRETER_TRANSLATE(strexb),
+ INTERPRETER_TRANSLATE(swp),
+ INTERPRETER_TRANSLATE(swpb),
+ INTERPRETER_TRANSLATE(ssub16),
+ INTERPRETER_TRANSLATE(ssat16),
+ INTERPRETER_TRANSLATE(shsubaddx),
+ INTERPRETER_TRANSLATE(qsubaddx),
+ INTERPRETER_TRANSLATE(shaddsubx),
+ INTERPRETER_TRANSLATE(shadd8),
+ INTERPRETER_TRANSLATE(shadd16),
+ INTERPRETER_TRANSLATE(sel),
+ INTERPRETER_TRANSLATE(saddsubx),
+ INTERPRETER_TRANSLATE(sadd8),
+ INTERPRETER_TRANSLATE(sadd16),
+ INTERPRETER_TRANSLATE(shsub16),
+ INTERPRETER_TRANSLATE(umaal),
+ INTERPRETER_TRANSLATE(uxtab16),
+ INTERPRETER_TRANSLATE(usubaddx),
+ INTERPRETER_TRANSLATE(usub8),
+ INTERPRETER_TRANSLATE(usub16),
+ INTERPRETER_TRANSLATE(usat16),
+ INTERPRETER_TRANSLATE(usada8),
+ INTERPRETER_TRANSLATE(uqsubaddx),
+ INTERPRETER_TRANSLATE(uqsub8),
+ INTERPRETER_TRANSLATE(uqsub16),
+ INTERPRETER_TRANSLATE(uqaddsubx),
+ INTERPRETER_TRANSLATE(uqadd8),
+ INTERPRETER_TRANSLATE(uqadd16),
+ INTERPRETER_TRANSLATE(sxtab),
+ INTERPRETER_TRANSLATE(uhsubaddx),
+ INTERPRETER_TRANSLATE(uhsub8),
+ INTERPRETER_TRANSLATE(uhsub16),
+ INTERPRETER_TRANSLATE(uhaddsubx),
+ INTERPRETER_TRANSLATE(uhadd8),
+ INTERPRETER_TRANSLATE(uhadd16),
+ INTERPRETER_TRANSLATE(uaddsubx),
+ INTERPRETER_TRANSLATE(uadd8),
+ INTERPRETER_TRANSLATE(uadd16),
+ INTERPRETER_TRANSLATE(sxtah),
+ INTERPRETER_TRANSLATE(sxtab16),
+ INTERPRETER_TRANSLATE(qadd8),
+ INTERPRETER_TRANSLATE(bxj),
+ INTERPRETER_TRANSLATE(clz),
+ INTERPRETER_TRANSLATE(uxtah),
+ INTERPRETER_TRANSLATE(bx),
+ INTERPRETER_TRANSLATE(rev),
+ INTERPRETER_TRANSLATE(blx),
+ INTERPRETER_TRANSLATE(revsh),
+ INTERPRETER_TRANSLATE(qadd),
+ INTERPRETER_TRANSLATE(qadd16),
+ INTERPRETER_TRANSLATE(qaddsubx),
+ INTERPRETER_TRANSLATE(ldrex),
+ INTERPRETER_TRANSLATE(qdadd),
+ INTERPRETER_TRANSLATE(qdsub),
+ INTERPRETER_TRANSLATE(qsub),
+ INTERPRETER_TRANSLATE(ldrexb),
+ INTERPRETER_TRANSLATE(qsub8),
+ INTERPRETER_TRANSLATE(qsub16),
+ INTERPRETER_TRANSLATE(smuad),
+ INTERPRETER_TRANSLATE(smmul),
+ INTERPRETER_TRANSLATE(smusd),
+ INTERPRETER_TRANSLATE(smlsd),
+ INTERPRETER_TRANSLATE(smlsld),
+ INTERPRETER_TRANSLATE(smmla),
+ INTERPRETER_TRANSLATE(smmls),
+ INTERPRETER_TRANSLATE(smlald),
+ INTERPRETER_TRANSLATE(smlad),
+ INTERPRETER_TRANSLATE(smlaw),
+ INTERPRETER_TRANSLATE(smulw),
+ INTERPRETER_TRANSLATE(pkhtb),
+ INTERPRETER_TRANSLATE(pkhbt),
+ INTERPRETER_TRANSLATE(smul),
+ INTERPRETER_TRANSLATE(smlalxy),
+ INTERPRETER_TRANSLATE(smla),
+ INTERPRETER_TRANSLATE(mcrr),
+ INTERPRETER_TRANSLATE(mrrc),
+ INTERPRETER_TRANSLATE(cmp),
+ INTERPRETER_TRANSLATE(tst),
+ INTERPRETER_TRANSLATE(teq),
+ INTERPRETER_TRANSLATE(cmn),
+ INTERPRETER_TRANSLATE(smull),
+ INTERPRETER_TRANSLATE(umull),
+ INTERPRETER_TRANSLATE(umlal),
+ INTERPRETER_TRANSLATE(smlal),
+ INTERPRETER_TRANSLATE(mul),
+ INTERPRETER_TRANSLATE(mla),
+ INTERPRETER_TRANSLATE(ssat),
+ INTERPRETER_TRANSLATE(usat),
+ INTERPRETER_TRANSLATE(mrs),
+ INTERPRETER_TRANSLATE(msr),
+ INTERPRETER_TRANSLATE(and),
+ INTERPRETER_TRANSLATE(bic),
+ INTERPRETER_TRANSLATE(ldm),
+ INTERPRETER_TRANSLATE(eor),
+ INTERPRETER_TRANSLATE(add),
+ INTERPRETER_TRANSLATE(rsb),
+ INTERPRETER_TRANSLATE(rsc),
+ INTERPRETER_TRANSLATE(sbc),
+ INTERPRETER_TRANSLATE(adc),
+ INTERPRETER_TRANSLATE(sub),
+ INTERPRETER_TRANSLATE(orr),
+ INTERPRETER_TRANSLATE(mvn),
+ INTERPRETER_TRANSLATE(mov),
+ INTERPRETER_TRANSLATE(stm),
+ INTERPRETER_TRANSLATE(ldm),
+ INTERPRETER_TRANSLATE(ldrsh),
+ INTERPRETER_TRANSLATE(stm),
+ INTERPRETER_TRANSLATE(ldm),
+ INTERPRETER_TRANSLATE(ldrsb),
+ INTERPRETER_TRANSLATE(strd),
+ INTERPRETER_TRANSLATE(ldrh),
+ INTERPRETER_TRANSLATE(strh),
+ INTERPRETER_TRANSLATE(ldrd),
+ INTERPRETER_TRANSLATE(strt),
+ INTERPRETER_TRANSLATE(strbt),
+ INTERPRETER_TRANSLATE(ldrbt),
+ INTERPRETER_TRANSLATE(ldrt),
+ INTERPRETER_TRANSLATE(mrc),
+ INTERPRETER_TRANSLATE(mcr),
+ INTERPRETER_TRANSLATE(msr),
+ INTERPRETER_TRANSLATE(ldrb),
+ INTERPRETER_TRANSLATE(strb),
+ INTERPRETER_TRANSLATE(ldr),
+ INTERPRETER_TRANSLATE(ldrcond),
+ INTERPRETER_TRANSLATE(str),
+ INTERPRETER_TRANSLATE(cdp),
+ INTERPRETER_TRANSLATE(stc),
+ INTERPRETER_TRANSLATE(ldc),
+ INTERPRETER_TRANSLATE(swi),
+ INTERPRETER_TRANSLATE(bbl),
+ /* All the thumb instructions should be placed the end of table */
+ INTERPRETER_TRANSLATE(b_2_thumb),
+ INTERPRETER_TRANSLATE(b_cond_thumb),
+ INTERPRETER_TRANSLATE(bl_1_thumb),
+ INTERPRETER_TRANSLATE(bl_2_thumb),
+ INTERPRETER_TRANSLATE(blx_1_thumb)
+};
+
+typedef map<unsigned int, int> bb_map;
+bb_map CreamCache[65536];
+bb_map ProfileCache[65536];
+
+//#define USE_DUMMY_CACHE
+
+#ifdef USE_DUMMY_CACHE
+unsigned int DummyCache[0x100000];
+#endif
+
+#define HASH(x) ((x + (x << 3) + (x >> 6)) % 65536)
+void insert_bb(unsigned int addr, int start)
+{
+#ifdef USE_DUMMY_CACHE
+ DummyCache[addr] = start;
+#else
+// CreamCache[addr] = start;
+ CreamCache[HASH(addr)][addr] = start;
+#endif
+}
+
+#define TRANS_THRESHOLD 65000
+int find_bb(unsigned int addr, int &start)
+{
+ int ret = -1;
+#ifdef USE_DUMMY_CACHE
+ start = DummyCache[addr];
+ if (start) {
+ ret = 0;
+ } else
+ ret = -1;
+#else
+ bb_map::const_iterator it = CreamCache[HASH(addr)].find(addr);
+ if (it != CreamCache[HASH(addr)].end()) {
+ start = static_cast<int>(it->second);
+ ret = 0;
+#if HYBRID_MODE
+#if PROFILE
+#else
+ /* increase the bb counter */
+ if(get_bb_prof(cpu, addr, 1) == TRANS_THRESHOLD){
+ push_to_compiled(cpu, addr);
+ }
+#endif
+#endif
+ } else {
+ ret = -1;
+ }
+#endif
+ return ret;
+}
+
+
+enum {
+ FETCH_SUCCESS,
+ FETCH_FAILURE
+};
+static tdstate decode_thumb_instr(arm_processor *cpu, uint32_t inst, addr_t addr, uint32_t *arm_inst, uint32_t* inst_size, ARM_INST_PTR* ptr_inst_base){
+ /* Check if in Thumb mode. */
+ tdstate ret;
+ ret = thumb_translate (addr, inst, arm_inst, inst_size);
+ if(ret == t_branch){
+ /* FIXME, endian should be judged */
+ uint32 tinstr;
+ if((addr & 0x3) != 0)
+ tinstr = inst >> 16;
+ else
+ tinstr = inst & 0xFFFF;
+
+ //tinstr = inst & 0xFFFF;
+ int inst_index;
+ /* table_length */
+ int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t);
+
+ switch((tinstr & 0xF800) >> 11){
+ /* we will translate the thumb instruction directly here */
+ /* we will translate the thumb instruction directly here */
+ case 26:
+ case 27:
+ if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){
+ uint32 cond = (tinstr & 0x0F00) >> 8;
+ inst_index = table_length - 4;
+ //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index);
+ *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
+ }
+ else{
+ /* something wrong */
+ DEBUG_LOG(ARM11, "In %s, thumb decoder error\n", __FUNCTION__);
+ }
+ break;
+ case 28:
+ /* Branch 2, unconditional branch */
+ inst_index = table_length - 5;
+ //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index);
+ *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
+ break;
+
+ case 8:
+ case 29:
+ /* For BLX 1 thumb instruction*/
+ inst_index = table_length - 1;
+ //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc);
+ *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
+ break;
+ case 30:
+ /* For BL 1 thumb instruction*/
+ inst_index = table_length - 3;
+ //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc);
+ *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
+ break;
+ case 31:
+ /* For BL 2 thumb instruction*/
+ inst_index = table_length - 2;
+ //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 2 thumb index=%d, px=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc);
+ *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
+ break;
+ default:
+ ret = t_undefined;
+ break;
+ }
+ }
+ return ret;
+}
+
+#if 0
+int FetchInst(cpu_t *core, unsigned int &inst)
+{
+ //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
+ arm_processor *cpu = (arm_processor *)(core->cpu_data->obj);
+// fault_t fault = interpreter_read_memory(cpu->translate_pc, inst, 32);
+ fault_t fault = interpreter_fetch(core, cpu->translate_pc, inst, 32);
+ if (!core->is_user_mode) {
+ if (fault) {
+ cpu->abortSig = true;
+ cpu->Aborted = ARMul_PrefetchAbortV;
+ cpu->AbortAddr = cpu->translate_pc;
+ cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
+ cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->translate_pc;
+ return FETCH_FAILURE;
+ }
+ }
+ return FETCH_SUCCESS;
+}
+#endif
+
+unsigned int *InstLength;
+
+enum {
+ KEEP_GOING,
+ FETCH_EXCEPTION
+};
+
+typedef struct instruction_set_encoding_item ISEITEM;
+
+extern const ISEITEM arm_instruction[];
+
+vector<uint64_t> code_page_set;
+
+void flush_bb(uint32_t addr)
+{
+ bb_map::iterator it;
+ uint32_t start;
+
+ addr &= 0xfffff000;
+ for (int i = 0; i < 65536; i ++) {
+ for (it = CreamCache[i].begin(); it != CreamCache[i].end(); ) {
+ start = static_cast<uint32_t>(it->first);
+ //start = (start >> 12) << 12;
+ start &= 0xfffff000;
+ if (start == addr) {
+ //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
+ CreamCache[i].erase(it ++);
+ } else
+ ++it;
+ }
+ }
+
+ for (int i = 0; i < 65536; i ++) {
+ for (it = ProfileCache[i].begin(); it != ProfileCache[i].end(); ) {
+ start = static_cast<uint32_t>(it->first);
+ //start = (start >> 12) << 12;
+ start &= 0xfffff000;
+ if (start == addr) {
+ //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
+ ProfileCache[i].erase(it ++);
+ } else
+ ++it;
+ }
+ }
+
+ //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr);
+}
+
+//static uint32_t get_bank_addr(void *addr)
+//{
+// uint64_t address = (uint64_t)addr;
+// uint64_t bank0 = get_dma_addr(BANK0_START);
+// if ((address >= bank0) && (address < (bank0 + BANK0_SIZE))) {
+// //DEBUG_LOG(ARM11, "1.addr is %llx\n", addr);
+// return ((uint64_t)addr - bank0) + BANK0_START;
+// }
+// return 0;
+//}
+
+/* shenoubang add win32 2012-6-12 */
+//#ifndef __WIN32__
+//static void flush_code_cache(int signal_number, siginfo_t *si, void *unused)
+//{
+// DEBUG_LOG(ARM11, "in %s, addr=0x%llx\n", __FUNCTION__, si->si_addr);
+// uint64_t addr = (uint64_t)si->si_addr;
+// addr = (addr >> 12) << 12;
+// skyeye_backtrace();
+// #if 0
+// if (addr == 0) {
+// return;
+// }
+// const vector<uint64_t>::iterator it = find(code_page_set.begin(),
+// code_page_set.end(),
+// (uint64_t)addr);
+// if (it != code_page_set.end()) {
+// code_page_set.erase(it);
+// }
+// mprotect((void *)addr, 4096, PROT_READ | PROT_WRITE);
+// //DEBUG_LOG(ARM11, "[flush][ADDR:0x%08llx]\n", addr);
+// uint32_t phys_addr = get_bank_addr((void *)addr);
+//// DEBUG_LOG(ARM11, "[PHYSICAL][ADDR:0x%08llx]\n", phys_addr);
+// flush_bb(phys_addr);
+// flush_bb(phys_addr + 4096);
+//#if HYBRID_MODE
+// /* flush the translated BB of dyncom */
+// clear_translated_cache(phys_addr);
+//#endif
+// #endif
+//}
+//#endif /* shenoubang */
+
+//void protect_code_page(uint32_t addr)
+//{
+// void *mem_ptr = (void *)get_dma_addr(addr);
+// mem_ptr = (void *)((long long int)mem_ptr & 0xfffffffffffff000LL);
+//
+// const vector<uint64_t>::iterator it = find(code_page_set.begin(),
+// code_page_set.end(),
+// (uint64_t)mem_ptr);
+// if (it != code_page_set.end()) {
+// return;
+// }
+// //DEBUG_LOG(ARM11, "[mprotect][ADDR:0x%08llx]\n", mem_ptr);
+// /* shenoubang add win32 2012-6-12 */
+//#ifndef __WIN32__
+// struct sigaction sa;
+//
+// memset(&sa, 0, sizeof(sa));
+// sa.sa_flags = SA_RESTART | SA_SIGINFO;
+// sa.sa_sigaction = &flush_code_cache;
+// sigaction(SIGSEGV, &sa, NULL);
+//
+// //mprotect(mem_ptr, 4096, PROT_READ);
+//
+// code_page_set.push_back((uint64_t)mem_ptr);
+//#endif /* shenoubang */
+//}
+
+
+
+int InterpreterTranslate(arm_processor *cpu, int &bb_start, addr_t addr)
+{
+ /* Decode instruction, get index */
+ /* Allocate memory and init InsCream */
+ /* Go on next, until terminal instruction */
+ /* Save start addr of basicblock in CreamCache */
+ //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
+ //arm_processor *cpu = (arm_processor *)(core->cpu_data->obj);
+ ARM_INST_PTR inst_base = NULL;
+ unsigned int inst, inst_size = 4;
+ int idx;
+ int ret = NON_BRANCH;
+ int thumb = 0;
+ /* instruction size of basic block */
+ int size = 0;
+ /* (R15 - 8) ? */
+ //cpu->translate_pc = cpu->Reg[15];
+ bb_start = top;
+
+ if (cpu->TFlag)
+ thumb = THUMB;
+
+ addr_t phys_addr;
+ addr_t pc_start;
+ fault_t fault = NO_FAULT;
+ //fault = check_address_validity(cpu, addr, &phys_addr, 1, INSN_TLB);
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if(fault != NO_FAULT){
+ cpu->abortSig = true;
+ cpu->Aborted = ARMul_PrefetchAbortV;
+ cpu->AbortAddr = addr;
+ cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
+ cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
+ return FETCH_EXCEPTION;
+ }
+ pc_start = phys_addr;
+ //phys_addr = get_dma_addr(phys_addr);
+ while(ret == NON_BRANCH) {
+ /* shenoubang add win32 2012-6-14 */
+#ifdef __WIN32__
+ mem_bank_t* bank;
+ if (bank = bank_ptr(addr)) {
+ bank->bank_read(32, phys_addr, &inst);
+ }
+ else {
+ DEBUG_LOG(ARM11, "SKYEYE: Read physical addr 0x%x error!!\n", phys_addr);
+ return FETCH_FAILURE;
+ }
+#else
+ inst = Memory::Read32(phys_addr & 0xFFFFFFFC);//*(uint32_t *)(phys_addr & 0xFFFFFFFC);
+#endif
+ //or_tag(core, phys_addr, TAG_FAST_INTERP);
+
+ /*if (ret == FETCH_FAILURE) {
+ return FETCH_EXCEPTION;
+ }*/
+
+ size ++;
+ /* If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction */
+ if (cpu->TFlag){
+ //if(cpu->Cpsr & (1 << THUMB_BIT)){
+ uint32_t arm_inst;
+ tdstate state;
+ state = decode_thumb_instr(cpu, inst, phys_addr, &arm_inst, &inst_size, &inst_base);
+ //or_tag(core, phys_addr, TAG_THUMB);
+ //DEBUG_LOG(ARM11, "In thumb state, arm_inst=0x%x, inst_size=0x%x, pc=0x%x\n", arm_inst, inst_size, cpu->translate_pc);
+ /* we have translated the branch instruction of thumb in thumb decoder */
+ if(state == t_branch){
+ goto translated;
+ }
+ inst = arm_inst;
+ }
+
+ ret = decode_arm_instr(inst, &idx);
+ if (ret == DECODE_FAILURE) {
+ DEBUG_LOG(ARM11, "[info] : Decode failure.\tPC : [0x%x]\tInstruction : [%x]\n", phys_addr, inst);
+ DEBUG_LOG(ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x\n", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]);
+ CITRA_IGNORE_EXIT(-1);
+ }
+// DEBUG_LOG(ARM11, "PC : [0x%x] INST : %s\n", cpu->translate_pc, arm_instruction[idx].name);
+ inst_base = arm_instruction_trans[idx](inst, idx);
+// DEBUG_LOG(ARM11, "translated @ %x INST : %x\n", cpu->translate_pc, inst);
+// DEBUG_LOG(ARM11, "inst size is %d\n", InstLength[idx]);
+translated:
+ phys_addr += inst_size;
+
+ if ((phys_addr & 0xfff) == 0) {
+ inst_base->br = END_OF_PAGE;
+ }
+ ret = inst_base->br;
+ };
+
+ //DEBUG_LOG(ARM11, "In %s,insert_bb pc=0x%x, TFlag=0x%x\n", __FUNCTION__, pc_start, cpu->TFlag);
+ insert_bb(pc_start, bb_start);
+ return KEEP_GOING;
+}
+
+#define LOG_IN_CLR skyeye_printf_in_color
+
+int cmp(const void *x, const void *y)
+{
+ return *(unsigned long long int*)x - *(unsigned long long int *)y;
+}
+
+void InterpreterInitInstLength(unsigned long long int *ptr, size_t size)
+{
+ int array_size = size / sizeof(void *);
+ unsigned long long int *InstLabel = new unsigned long long int[array_size];
+ memcpy(InstLabel, ptr, size);
+ qsort(InstLabel, array_size, sizeof(void *), cmp);
+ InstLength = new unsigned int[array_size - 4];
+ for (int i = 0; i < array_size - 4; i ++) {
+ for (int j = 0; j < array_size; j ++) {
+ if (ptr[i] == InstLabel[j]) {
+ InstLength[i] = InstLabel[j + 1] - InstLabel[j];
+ break;
+ }
+ }
+ }
+ for (int i = 0; i < array_size - 4; i ++)
+ DEBUG_LOG(ARM11, "[%d]:%d\n", i, InstLength[i]);
+}
+
+int clz(unsigned int x)
+{
+ int n;
+ if (x == 0) return (32);
+ n = 1;
+ if ((x >> 16) == 0) { n = n + 16; x = x << 16;}
+ if ((x >> 24) == 0) { n = n + 8; x = x << 8;}
+ if ((x >> 28) == 0) { n = n + 4; x = x << 4;}
+ if ((x >> 30) == 0) { n = n + 2; x = x << 2;}
+ n = n - (x >> 31);
+ return n;
+}
+
+unsigned arm_dyncom_SWI (ARMul_State * state, ARMword number);
+
+static bool InAPrivilegedMode(arm_core_t *core)
+{
+ return (core->Mode != USER32MODE);
+}
+
+/* r15 = r15 + 8 */
+unsigned InterpreterMainLoop(ARMul_State* state)
+{
+ #define CRn inst_cream->crn
+ #define OPCODE_2 inst_cream->opcode_2
+ #define CRm inst_cream->crm
+ #define CP15_REG(n) cpu->CP15[CP15(n)]
+ #define RD cpu->Reg[inst_cream->Rd]
+ #define RN cpu->Reg[inst_cream->Rn]
+ #define RM cpu->Reg[inst_cream->Rm]
+ #define RS cpu->Reg[inst_cream->Rs]
+ #define RDHI cpu->Reg[inst_cream->RdHi]
+ #define RDLO cpu->Reg[inst_cream->RdLo]
+ #define LINK_RTN_ADDR (cpu->Reg[14] = cpu->Reg[15] + 4)
+ #define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24)
+ #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand)
+
+ #if ENABLE_ICOUNTER
+ #define INC_ICOUNTER cpu->icounter++; \
+ if(cpu->Reg[15] > 0xc0000000) \
+ cpu->kernel_icounter++;
+ //if (debug_function(core)) \
+ if (core->check_int_flag) \
+ goto END
+ //DEBUG_LOG(ARM11, "icounter is %llx line is %d pc is %x\n", cpu->icounter, __LINE__, cpu->Reg[15])
+ #else
+ #define INC_ICOUNTER ;
+ #endif
+
+ #define FETCH_INST if (inst_base->br != NON_BRANCH) \
+ goto DISPATCH; \
+ inst_base = (arm_inst *)&inst_buf[ptr]
+#define INC_PC(l) ptr += sizeof(arm_inst) + l
+
+// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
+// clunky switch statement.
+#if defined __GNUC__ || defined __clang__
+#define GOTO_NEXT_INST \
+ if (num_instrs >= cpu->NumInstrsToExecute) goto END; \
+ num_instrs++; \
+ goto *InstLabel[inst_base->idx]
+#else
+#define GOTO_NEXT_INST \
+ if (num_instrs >= cpu->NumInstrsToExecute) goto END; \
+ num_instrs++; \
+ switch(inst_base->idx) { \
+ case 0: goto VMLA_INST; \
+ case 1: goto VMLS_INST; \
+ case 2: goto VNMLA_INST; \
+ case 3: goto VNMLA_INST; \
+ case 4: goto VNMLS_INST; \
+ case 5: goto VNMUL_INST; \
+ case 6: goto VMUL_INST; \
+ case 7: goto VADD_INST; \
+ case 8: goto VSUB_INST; \
+ case 9: goto VDIV_INST; \
+ case 10: goto VMOVI_INST; \
+ case 11: goto VMOVR_INST; \
+ case 12: goto VABS_INST; \
+ case 13: goto VNEG_INST; \
+ case 14: goto VSQRT_INST; \
+ case 15: goto VCMP_INST; \
+ case 16: goto VCMP2_INST; \
+ case 17: goto VCVTBDS_INST; \
+ case 18: goto VCVTBFF_INST; \
+ case 19: goto VCVTBFI_INST; \
+ case 20: goto VMOVBRS_INST; \
+ case 21: goto VMSR_INST; \
+ case 22: goto VMOVBRC_INST; \
+ case 23: goto VMRS_INST; \
+ case 24: goto VMOVBCR_INST; \
+ case 25: goto VMOVBRRSS_INST; \
+ case 26: goto VMOVBRRD_INST; \
+ case 27: goto VSTR_INST; \
+ case 28: goto VPUSH_INST; \
+ case 29: goto VSTM_INST; \
+ case 30: goto VPOP_INST; \
+ case 31: goto VLDR_INST; \
+ case 32: goto VLDM_INST ; \
+ case 33: goto SRS_INST; \
+ case 34: goto RFE_INST; \
+ case 35: goto BKPT_INST; \
+ case 36: goto BLX_INST; \
+ case 37: goto CPS_INST; \
+ case 38: goto PLD_INST; \
+ case 39: goto SETEND_INST; \
+ case 40: goto CLREX_INST; \
+ case 41: goto REV16_INST; \
+ case 42: goto USAD8_INST; \
+ case 43: goto SXTB_INST; \
+ case 44: goto UXTB_INST; \
+ case 45: goto SXTH_INST; \
+ case 46: goto SXTB16_INST; \
+ case 47: goto UXTH_INST; \
+ case 48: goto UXTB16_INST; \
+ case 49: goto CPY_INST; \
+ case 50: goto UXTAB_INST; \
+ case 51: goto SSUB8_INST; \
+ case 52: goto SHSUB8_INST; \
+ case 53: goto SSUBADDX_INST; \
+ case 54: goto STREX_INST; \
+ case 55: goto STREXB_INST; \
+ case 56: goto SWP_INST; \
+ case 57: goto SWPB_INST; \
+ case 58: goto SSUB16_INST; \
+ case 59: goto SSAT16_INST; \
+ case 60: goto SHSUBADDX_INST; \
+ case 61: goto QSUBADDX_INST; \
+ case 62: goto SHADDSUBX_INST; \
+ case 63: goto SHADD8_INST; \
+ case 64: goto SHADD16_INST; \
+ case 65: goto SEL_INST; \
+ case 66: goto SADDSUBX_INST; \
+ case 67: goto SADD8_INST; \
+ case 68: goto SADD16_INST; \
+ case 69: goto SHSUB16_INST; \
+ case 70: goto UMAAL_INST; \
+ case 71: goto UXTAB16_INST; \
+ case 72: goto USUBADDX_INST; \
+ case 73: goto USUB8_INST; \
+ case 74: goto USUB16_INST; \
+ case 75: goto USAT16_INST; \
+ case 76: goto USADA8_INST; \
+ case 77: goto UQSUBADDX_INST; \
+ case 78: goto UQSUB8_INST; \
+ case 79: goto UQSUB16_INST; \
+ case 80: goto UQADDSUBX_INST; \
+ case 81: goto UQADD8_INST; \
+ case 82: goto UQADD16_INST; \
+ case 83: goto SXTAB_INST; \
+ case 84: goto UHSUBADDX_INST; \
+ case 85: goto UHSUB8_INST; \
+ case 86: goto UHSUB16_INST; \
+ case 87: goto UHADDSUBX_INST; \
+ case 88: goto UHADD8_INST; \
+ case 89: goto UHADD16_INST; \
+ case 90: goto UADDSUBX_INST; \
+ case 91: goto UADD8_INST; \
+ case 92: goto UADD16_INST; \
+ case 93: goto SXTAH_INST; \
+ case 94: goto SXTAB16_INST; \
+ case 95: goto QADD8_INST; \
+ case 96: goto BXJ_INST; \
+ case 97: goto CLZ_INST; \
+ case 98: goto UXTAH_INST; \
+ case 99: goto BX_INST; \
+ case 100: goto REV_INST; \
+ case 101: goto BLX_INST; \
+ case 102: goto REVSH_INST; \
+ case 103: goto QADD_INST; \
+ case 104: goto QADD16_INST; \
+ case 105: goto QADDSUBX_INST; \
+ case 106: goto LDREX_INST; \
+ case 107: goto QDADD_INST; \
+ case 108: goto QDSUB_INST; \
+ case 109: goto QSUB_INST; \
+ case 110: goto LDREXB_INST; \
+ case 111: goto QSUB8_INST; \
+ case 112: goto QSUB16_INST; \
+ case 113: goto SMUAD_INST; \
+ case 114: goto SMMUL_INST; \
+ case 115: goto SMUSD_INST; \
+ case 116: goto SMLSD_INST; \
+ case 117: goto SMLSLD_INST; \
+ case 118: goto SMMLA_INST; \
+ case 119: goto SMMLS_INST; \
+ case 120: goto SMLALD_INST; \
+ case 121: goto SMLAD_INST; \
+ case 122: goto SMLAW_INST; \
+ case 123: goto SMULW_INST; \
+ case 124: goto PKHTB_INST; \
+ case 125: goto PKHBT_INST; \
+ case 126: goto SMUL_INST; \
+ case 127: goto SMLAL_INST; \
+ case 128: goto SMLA_INST; \
+ case 129: goto MCRR_INST; \
+ case 130: goto MRRC_INST; \
+ case 131: goto CMP_INST; \
+ case 132: goto TST_INST; \
+ case 133: goto TEQ_INST; \
+ case 134: goto CMN_INST; \
+ case 135: goto SMULL_INST; \
+ case 136: goto UMULL_INST; \
+ case 137: goto UMLAL_INST; \
+ case 138: goto SMLAL_INST; \
+ case 139: goto MUL_INST; \
+ case 140: goto MLA_INST; \
+ case 141: goto SSAT_INST; \
+ case 142: goto USAT_INST; \
+ case 143: goto MRS_INST; \
+ case 144: goto MSR_INST; \
+ case 145: goto AND_INST; \
+ case 146: goto BIC_INST; \
+ case 147: goto LDM_INST; \
+ case 148: goto EOR_INST; \
+ case 149: goto ADD_INST; \
+ case 150: goto RSB_INST; \
+ case 151: goto RSC_INST; \
+ case 152: goto SBC_INST; \
+ case 153: goto ADC_INST; \
+ case 154: goto SUB_INST; \
+ case 155: goto ORR_INST; \
+ case 156: goto MVN_INST; \
+ case 157: goto MOV_INST; \
+ case 158: goto STM_INST; \
+ case 159: goto LDM_INST; \
+ case 160: goto LDRSH_INST; \
+ case 161: goto STM_INST; \
+ case 162: goto LDM_INST; \
+ case 163: goto LDRSB_INST; \
+ case 164: goto STRD_INST; \
+ case 165: goto LDRH_INST; \
+ case 166: goto STRH_INST; \
+ case 167: goto LDRD_INST; \
+ case 168: goto STRT_INST; \
+ case 169: goto STRBT_INST; \
+ case 170: goto LDRBT_INST; \
+ case 171: goto LDRT_INST; \
+ case 172: goto MRC_INST; \
+ case 173: goto MCR_INST; \
+ case 174: goto MSR_INST; \
+ case 175: goto LDRB_INST; \
+ case 176: goto STRB_INST; \
+ case 177: goto LDR_INST; \
+ case 178: goto LDRCOND_INST ; \
+ case 179: goto STR_INST; \
+ case 180: goto CDP_INST; \
+ case 181: goto STC_INST; \
+ case 182: goto LDC_INST; \
+ case 183: goto SWI_INST; \
+ case 184: goto BBL_INST; \
+ case 185: goto B_2_THUMB ; \
+ case 186: goto B_COND_THUMB ; \
+ case 187: goto BL_1_THUMB ; \
+ case 188: goto BL_2_THUMB ; \
+ case 189: goto BLX_1_THUMB ; \
+ case 190: goto DISPATCH; \
+ case 191: goto INIT_INST_LENGTH; \
+ case 192: goto END; \
+ }
+#endif
+
+ #define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0)
+ #define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1)
+// #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((ISNEG(lop) && ISPOS(rop)) || \
+ (ISNEG(lop) && ISPOS(dst)) || \
+ (ISPOS(rop) && ISPOS(dst))))
+ #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((dst < lop) || (dst < rop)))
+ #define UPDATE_CFLAG_CARRY_FROM_ADD(lop, rop, flag) (cpu->CFlag = (((uint64_t) lop + (uint64_t) rop + (uint64_t) flag) > 0xffffffff) )
+ #define UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(lop, rop, flag) (cpu->CFlag = ((uint64_t) lop >= ((uint64_t) rop + (uint64_t) flag)))
+ #define UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop) (cpu->CFlag = (lop >= rop))
+ #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) (cpu->CFlag = !(dst < lop))
+ #define UPDATE_CFLAG_WITH_SC cpu->CFlag = cpu->shifter_carry_out
+// #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || \
+ (ISNEG(lop) && ISPOS(dst)) || \
+ (ISPOS(rop) && ISPOS(dst)))
+ #define UPDATE_VFLAG(dst, lop, rop) (cpu->VFlag = (((lop < 0) && (rop < 0) && (dst >= 0)) || \
+ ((lop >= 0) && (rop) >= 0 && (dst < 0))))
+ #define UPDATE_VFLAG_WITH_NOT(dst, lop, rop) (cpu->VFlag = !(((lop < 0) && (rop < 0) && (dst >= 0)) || \
+ ((lop >= 0) && (rop) >= 0 && (dst < 0))))
+ #define UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop) (cpu->VFlag = (((lop ^ rop) & (lop ^ dst)) >> 31))
+
+ #define SAVE_NZCVT cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | \
+ (cpu->NFlag << 31) | \
+ (cpu->ZFlag << 30) | \
+ (cpu->CFlag << 29) | \
+ (cpu->VFlag << 28) | \
+ (cpu->TFlag << 5)
+ #define LOAD_NZCVT cpu->NFlag = (cpu->Cpsr >> 31); \
+ cpu->ZFlag = (cpu->Cpsr >> 30) & 1; \
+ cpu->CFlag = (cpu->Cpsr >> 29) & 1; \
+ cpu->VFlag = (cpu->Cpsr >> 28) & 1; \
+ cpu->TFlag = (cpu->Cpsr >> 5) & 1;
+
+ #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE)
+ #define PC (cpu->Reg[15])
+ #define CHECK_EXT_INT if (!cpu->NirqSig) { \
+ if (!(cpu->Cpsr & 0x80)) { \
+ goto END; \
+ } \
+ }
+
+
+
+ //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
+ arm_processor *cpu = state; //(arm_processor *)(core->cpu_data->obj);
+
+ // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback
+ // to a clunky switch statement.
+#if defined __GNUC__ || defined __clang__
+ void *InstLabel[] = {
+ #define VFP_INTERPRETER_LABEL
+ #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+ #undef VFP_INTERPRETER_LABEL
+ &&SRS_INST,&&RFE_INST,&&BKPT_INST,&&BLX_INST,&&CPS_INST,&&PLD_INST,&&SETEND_INST,&&CLREX_INST,&&REV16_INST,&&USAD8_INST,&&SXTB_INST,
+ &&UXTB_INST,&&SXTH_INST,&&SXTB16_INST,&&UXTH_INST,&&UXTB16_INST,&&CPY_INST,&&UXTAB_INST,&&SSUB8_INST,&&SHSUB8_INST,&&SSUBADDX_INST,
+ &&STREX_INST,&&STREXB_INST,&&SWP_INST,&&SWPB_INST,&&SSUB16_INST,&&SSAT16_INST,&&SHSUBADDX_INST,&&QSUBADDX_INST,&&SHADDSUBX_INST,
+ &&SHADD8_INST,&&SHADD16_INST,&&SEL_INST,&&SADDSUBX_INST,&&SADD8_INST,&&SADD16_INST,&&SHSUB16_INST,&&UMAAL_INST,&&UXTAB16_INST,
+ &&USUBADDX_INST,&&USUB8_INST,&&USUB16_INST,&&USAT16_INST,&&USADA8_INST,&&UQSUBADDX_INST,&&UQSUB8_INST,&&UQSUB16_INST,
+ &&UQADDSUBX_INST,&&UQADD8_INST,&&UQADD16_INST,&&SXTAB_INST,&&UHSUBADDX_INST,&&UHSUB8_INST,&&UHSUB16_INST,&&UHADDSUBX_INST,&&UHADD8_INST,
+ &&UHADD16_INST,&&UADDSUBX_INST,&&UADD8_INST,&&UADD16_INST,&&SXTAH_INST,&&SXTAB16_INST,&&QADD8_INST,&&BXJ_INST,&&CLZ_INST,&&UXTAH_INST,
+ &&BX_INST,&&REV_INST,&&BLX_INST,&&REVSH_INST,&&QADD_INST,&&QADD16_INST,&&QADDSUBX_INST,&&LDREX_INST,&&QDADD_INST,&&QDSUB_INST,
+ &&QSUB_INST,&&LDREXB_INST,&&QSUB8_INST,&&QSUB16_INST,&&SMUAD_INST,&&SMMUL_INST,&&SMUSD_INST,&&SMLSD_INST,&&SMLSLD_INST,&&SMMLA_INST,
+ &&SMMLS_INST,&&SMLALD_INST,&&SMLAD_INST,&&SMLAW_INST,&&SMULW_INST,&&PKHTB_INST,&&PKHBT_INST,&&SMUL_INST,&&SMLAL_INST,&&SMLA_INST,
+ &&MCRR_INST,&&MRRC_INST,&&CMP_INST,&&TST_INST,&&TEQ_INST,&&CMN_INST,&&SMULL_INST,&&UMULL_INST,&&UMLAL_INST,&&SMLAL_INST,&&MUL_INST,
+ &&MLA_INST,&&SSAT_INST,&&USAT_INST,&&MRS_INST,&&MSR_INST,&&AND_INST,&&BIC_INST,&&LDM_INST,&&EOR_INST,&&ADD_INST,&&RSB_INST,&&RSC_INST,
+ &&SBC_INST,&&ADC_INST,&&SUB_INST,&&ORR_INST,&&MVN_INST,&&MOV_INST,&&STM_INST,&&LDM_INST,&&LDRSH_INST,&&STM_INST,&&LDM_INST,&&LDRSB_INST,
+ &&STRD_INST,&&LDRH_INST,&&STRH_INST,&&LDRD_INST,&&STRT_INST,&&STRBT_INST,&&LDRBT_INST,&&LDRT_INST,&&MRC_INST,&&MCR_INST,&&MSR_INST,
+ &&LDRB_INST,&&STRB_INST,&&LDR_INST,&&LDRCOND_INST, &&STR_INST,&&CDP_INST,&&STC_INST,&&LDC_INST,&&SWI_INST,&&BBL_INST,&&B_2_THUMB, &&B_COND_THUMB,
+ &&BL_1_THUMB, &&BL_2_THUMB, &&BLX_1_THUMB, &&DISPATCH,&&INIT_INST_LENGTH,&&END
+ };
+#endif
+ arm_inst * inst_base;
+ unsigned int lop, rop, dst;
+ unsigned int addr;
+ unsigned int phys_addr;
+ unsigned int last_pc = 0;
+ unsigned int num_instrs = 0;
+ fault_t fault;
+ static unsigned int last_physical_base = 0, last_logical_base = 0;
+ int ptr;
+ bool single_step = (cpu->NumInstrsToExecute == 1);
+
+ LOAD_NZCVT;
+ DISPATCH:
+ {
+ if (!cpu->NirqSig) {
+ if (!(cpu->Cpsr & 0x80)) {
+ goto END;
+ }
+ }
+
+ if (cpu->TFlag) {
+ cpu->Reg[15] &= 0xfffffffe;
+ } else
+ cpu->Reg[15] &= 0xfffffffc;
+#if PROFILE
+ /* check next instruction address is valid. */
+ last_pc = cpu->Reg[15];
+#endif
+#if USER_MODE_OPT
+ phys_addr = cpu->Reg[15];
+#else
+ {
+ if (last_logical_base == (cpu->Reg[15] & 0xfffff000))
+ phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff);
+ else {
+ /* check next instruction address is valid. */
+ fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB);
+ if (fault) {
+ cpu->abortSig = true;
+ cpu->Aborted = ARMul_PrefetchAbortV;
+ cpu->AbortAddr = cpu->Reg[15];
+ cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
+ cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15];
+ goto END;
+ }
+ last_logical_base = cpu->Reg[15] & 0xfffff000;
+ last_physical_base = phys_addr & 0xfffff000;
+ }
+ }
+#if HYBRID_MODE
+ /* check if the native code of dyncom is available */
+ //fast_map hash_map = core->dyncom_engine->fmap;
+ //void * pfunc = NULL;
+ //PFUNC(phys_addr);
+ //if(pfunc){
+ if(is_translated_entry(core, phys_addr)){
+ int rc = JIT_RETURN_NOERR;
+ //DEBUG_LOG(ARM11, "enter jit icounter is %lld, pc=0x%x\n", core->icounter, cpu->Reg[15]);
+ SAVE_NZCVT;
+// resume_timing();
+ rc = cpu_run(core);
+ LOAD_NZCVT;
+ //DEBUG_LOG(ARM11, "out of jit ret is %d icounter is %lld, pc=0x%x\n", rc, core->icounter, cpu->Reg[15]);
+ if((rc == JIT_RETURN_FUNCNOTFOUND) || (rc == JIT_RETURN_FUNC_BLANK)){
+ /* keep the tflag same with the bit in CPSR */
+ //cpu->TFlag = cpu->Cpsr & (1 << THUMB_BIT);
+ //cpu->TFlag = cpu->Cpsr & (1 << 5);
+ //switch_mode(cpu, cpu->Cpsr & 0x1f);
+ //DEBUG_LOG(ARM11, "FUNCTION not found , pc=0x%x\n", cpu->Reg[15]);
+ fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB);
+ if (fault) {
+ cpu->abortSig = true;
+ cpu->Aborted = ARMul_PrefetchAbortV;
+ cpu->AbortAddr = cpu->Reg[15];
+ cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
+ cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15];
+ goto END;
+ }
+ last_logical_base = cpu->Reg[15] & 0xfffff000;
+ last_physical_base = phys_addr & 0xfffff000;
+ core->current_page_phys = last_physical_base;
+ core->current_page_effec = last_logical_base;
+ //push_to_compiled(core, phys_addr);
+ }
+ else{
+ if((cpu->CP15[CP15(CP15_TLB_FAULT_STATUS)] & 0xf0)){
+ //DEBUG_LOG(ARM11, "\n\n###############In %s, fsr=0x%x, fault_addr=0x%x, pc=0x%x\n\n", __FUNCTION__, cpu->CP15[CP15(CP15_FAULT_STATUS)], cpu->CP15[CP15(CP15_FAULT_ADDRESS)], cpu->Reg[15]);
+ //core->Reg[15] -= get_instr_size(cpu_dyncom);
+ fill_tlb(cpu);
+ goto END;
+ }
+ if (cpu->syscallSig) {
+ goto END;
+ }
+ if (cpu->abortSig) {
+ cpu->CP15[CP15_TLB_FAULT_STATUS - CP15_BASE] &= 0xFFFFFFF0;
+ goto END;
+ }
+ if (!cpu->NirqSig) {
+ if (!(cpu->Cpsr & 0x80)) {
+ goto END;
+ }
+ }
+
+ /* if regular trap */
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ /*uint32_t mode = cpu->Cpsr & 0x1f;
+ if ((mode != cpu->Mode) && (!is_user_mode(core))) {
+ switch_mode(cpu, mode);
+ return 1;
+ }*/
+
+ goto END;
+ }
+ //phys_addr = cpu->Reg[15];
+ }
+ else{
+ if (last_logical_base == (cpu->Reg[15] & 0xfffff000))
+ phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff);
+ else {
+ /* check next instruction address is valid. */
+ fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB);
+ if (fault) {
+ cpu->abortSig = true;
+ cpu->Aborted = ARMul_PrefetchAbortV;
+ cpu->AbortAddr = cpu->Reg[15];
+ cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
+ cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15];
+ goto END;
+ }
+ last_logical_base = cpu->Reg[15] & 0xfffff000;
+ last_physical_base = phys_addr & 0xfffff000;
+ }
+ }
+#endif /* #if HYBRID_MODE */
+#endif /* #if USER_MODE_OPT */
+ if (true){//if(is_fast_interp_code(core, phys_addr)){
+ if (find_bb(phys_addr, ptr) == -1)
+ if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
+ goto END;
+ }
+ else{
+ if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
+ goto END;
+ }
+#if PROFILE
+ resume_timing();
+#endif
+ inst_base = (arm_inst *)&inst_buf[ptr];
+ GOTO_NEXT_INST;
+ }
+ ADC_INST:
+ {
+ INC_ICOUNTER;
+ adc_inst *inst_cream = (adc_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ lop = RN;
+ unsigned int sht_op = SHIFTER_OPERAND;
+ rop = SHIFTER_OPERAND + cpu->CFlag;
+ RD = dst = lop + rop;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr */
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_CARRY_FROM_ADD(lop, sht_op, cpu->CFlag);
+ UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(adc_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(adc_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ ADD_INST:
+ {
+ INC_ICOUNTER;
+ add_inst *inst_cream = (add_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ lop = RN;
+ if (inst_cream->Rn == 15) {
+ lop += 2 * GET_INST_SIZE(cpu);
+ }
+ rop = SHIFTER_OPERAND;
+ RD = dst = lop + rop;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr*/
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Cpsr & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG(dst, lop, rop);
+ UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(add_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(add_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ AND_INST:
+ {
+ INC_ICOUNTER;
+ and_inst *inst_cream = (and_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ lop = RN;
+ rop = SHIFTER_OPERAND;
+ RD = dst = lop & rop;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr*/
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Cpsr & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_WITH_SC;
+ //UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(and_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(and_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ BBL_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ bbl_inst *inst_cream = (bbl_inst *)inst_base->component;
+ if (inst_cream->L) {
+ LINK_RTN_ADDR;
+ }
+ SET_PC;
+ INC_PC(sizeof(bbl_inst));
+ goto DISPATCH;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(bbl_inst));
+ goto DISPATCH;
+ }
+ BIC_INST:
+ {
+ INC_ICOUNTER;
+ bic_inst *inst_cream = (bic_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ lop = RN;
+ if (inst_cream->Rn == 15) {
+ lop += 2 * GET_INST_SIZE(cpu);
+ }
+ rop = SHIFTER_OPERAND;
+// RD = dst = lop & (rop ^ 0xffffffff);
+ RD = dst = lop & (~rop);
+ if ((inst_cream->S) && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr */
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_WITH_SC;
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(bic_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(bic_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ BKPT_INST:
+ BLX_INST:
+ {
+ INC_ICOUNTER;
+ blx_inst *inst_cream = (blx_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ unsigned int inst = inst_cream->inst;
+ if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
+ //LINK_RTN_ADDR;
+ cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu));
+ if(cpu->TFlag)
+ cpu->Reg[14] |= 0x1;
+ cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe;
+ cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1;
+ //cpu->Reg[15] = cpu->Reg[BITS(inst, 0, 3)] & 0xfffffffe;
+ //cpu->TFlag = cpu->Reg[BITS(inst, 0, 3)] & 0x1;
+ } else {
+ cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu));
+ cpu->TFlag = 0x1;
+ int signed_int = inst_cream->val.signed_immed_24;
+ signed_int = (signed_int) & 0x800000 ? (0x3F000000 | signed_int) : signed_int;
+ signed_int = signed_int << 2;
+ // cpu->Reg[15] = cpu->Reg[15] + 2 * GET_INST_SIZE(cpu)
+ cpu->Reg[15] = cpu->Reg[15] + 8
+ + signed_int + (BIT(inst, 24) << 1);
+ //DEBUG_MSG;
+ }
+ INC_PC(sizeof(blx_inst));
+ goto DISPATCH;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+// INC_PC(sizeof(bx_inst));
+ INC_PC(sizeof(blx_inst));
+ goto DISPATCH;
+ }
+ BX_INST:
+ {
+ INC_ICOUNTER;
+ bx_inst *inst_cream = (bx_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ if (inst_cream->Rm == 15)
+ DEBUG_LOG(ARM11, "In %s, BX at pc %x: use of Rm = R15 is discouraged\n", __FUNCTION__, cpu->Reg[15]);
+ cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1;
+ cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe;
+// cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1;
+ INC_PC(sizeof(bx_inst));
+ goto DISPATCH;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+// INC_PC(sizeof(bx_inst));
+ INC_PC(sizeof(bx_inst));
+ goto DISPATCH;
+ }
+ BXJ_INST:
+ CDP_INST:
+ {
+ INC_ICOUNTER;
+ cdp_inst *inst_cream = (cdp_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ /* FIXME, check if cp access allowed */
+ #define CP_ACCESS_ALLOW 0
+ if(CP_ACCESS_ALLOW){
+ /* undefined instruction here */
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
+ }
+ ERROR_LOG(ARM11, "CDP insn inst=0x%x, pc=0x%x\n", inst_cream->inst, cpu->Reg[15]);
+ unsigned cpab = (cpu->CDP[inst_cream->cp_num]) (cpu, ARMul_FIRST, inst_cream->inst);
+ if(cpab != ARMul_DONE){
+ ERROR_LOG(ARM11, "CDP insn wrong, inst=0x%x, cp_num=0x%x\n", inst_cream->inst, inst_cream->cp_num);
+ //CITRA_IGNORE_EXIT(-1);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(cdp_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+
+ CLREX_INST:
+ {
+ INC_ICOUNTER;
+ remove_exclusive(cpu, 0);
+ cpu->exclusive_state = 0;
+
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(clrex_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ CLZ_INST:
+ {
+ INC_ICOUNTER;
+ clz_inst *inst_cream = (clz_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ RD = clz(RM);
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(clz_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ CMN_INST:
+ {
+ INC_ICOUNTER;
+ cmn_inst *inst_cream = (cmn_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+// DEBUG_LOG(ARM11, "RN is %x\n", RN);
+ lop = RN;
+ rop = SHIFTER_OPERAND;
+ dst = lop + rop;
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG(dst, lop, rop);
+ UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(cmn_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ CMP_INST:
+ {
+// DEBUG_LOG(ARM11, "cmp inst\n");
+// DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]);
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+// DEBUG_LOG(ARM11, "r0 is %x\n", cpu->Reg[0]);
+ cmp_inst *inst_cream = (cmp_inst *)inst_base->component;
+ lop = RN;
+ if (inst_cream->Rn == 15) {
+ lop += 2 * GET_INST_SIZE(cpu);
+ }
+ rop = SHIFTER_OPERAND;
+ dst = lop - rop;
+
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+// UPDATE_CFLAG(dst, lop, rop);
+ UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
+// UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
+ UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
+// UPDATE_VFLAG_WITH_NOT(dst, lop, rop);
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(cmp_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ CPS_INST:
+ {
+ INC_ICOUNTER;
+ cps_inst *inst_cream = (cps_inst *)inst_base->component;
+ uint32_t aif_val = 0;
+ uint32_t aif_mask = 0;
+ if (InAPrivilegedMode(cpu)) {
+ /* isInAPrivilegedMode */
+ if (inst_cream->imod1) {
+ if (inst_cream->A) {
+ aif_val |= (inst_cream->imod0 << 8);
+ aif_mask |= 1 << 8;
+ }
+ if (inst_cream->I) {
+ aif_val |= (inst_cream->imod0 << 7);
+ aif_mask |= 1 << 7;
+ }
+ if (inst_cream->F) {
+ aif_val |= (inst_cream->imod0 << 6);
+ aif_mask |= 1 << 6;
+ }
+ aif_mask = ~aif_mask;
+ cpu->Cpsr = (cpu->Cpsr & aif_mask) | aif_val;
+ }
+ if (inst_cream->mmod) {
+ cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode;
+ switch_mode(cpu, inst_cream->mode);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(cps_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ CPY_INST:
+ {
+ INC_ICOUNTER;
+ mov_inst *inst_cream = (mov_inst *)inst_base->component;
+// cpy_inst *inst_cream = (cpy_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ RD = SHIFTER_OPERAND;
+// RD = RM;
+ if ((inst_cream->Rd == 15)) {
+ INC_PC(sizeof(mov_inst));
+ goto DISPATCH;
+ }
+ }
+// DEBUG_LOG(ARM11, "cpy inst %x\n", cpu->Reg[15]);
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mov_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ EOR_INST:
+ {
+ INC_ICOUNTER;
+ eor_inst *inst_cream = (eor_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ lop = RN;
+ if (inst_cream->Rn == 15) {
+ lop += 2 * GET_INST_SIZE(cpu);
+ }
+ rop = SHIFTER_OPERAND;
+ RD = dst = lop ^ rop;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr*/
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_WITH_SC;
+// UPDATE_CFLAG(dst, lop, rop);
+// UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(eor_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(eor_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDC_INST:
+ {
+ INC_ICOUNTER;
+ /* NOT IMPL */
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldc_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDM_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ int i;
+ unsigned int ret;
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ unsigned int inst = inst_cream->inst;
+ if (BIT(inst, 22) && !BIT(inst, 15)) {
+// DEBUG_MSG;
+ #if 1
+ /* LDM (2) user */
+ for (i = 0; i < 13; i++) {
+ if(BIT(inst, i)){
+ #if 0
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ #endif
+ fault = interpreter_read_memory(addr, phys_addr, ret, 32);
+ //if (fault) goto MMU_EXCEPTION;
+ cpu->Reg[i] = ret;
+ addr += 4;
+ if ((addr & 0xfff) == 0) {
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ } else {
+ phys_addr += 4;
+ }
+ }
+ }
+ if (BIT(inst, 13)) {
+ #if 0
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ #endif
+ fault = interpreter_read_memory(addr, phys_addr, ret, 32);
+ //if (fault) goto MMU_EXCEPTION;
+ if (cpu->Mode == USER32MODE)
+ cpu->Reg[13] = ret;
+ else
+ cpu->Reg_usr[0] = ret;
+ addr += 4;
+ if ((addr & 0xfff) == 0) {
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ } else {
+ phys_addr += 4;
+ }
+ }
+ if (BIT(inst, 14)) {
+ #if 0
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ #endif
+ fault = interpreter_read_memory(addr, phys_addr, ret, 32);
+ //if (fault) goto MMU_EXCEPTION;
+ if (cpu->Mode == USER32MODE)
+ cpu->Reg[14] = ret;
+ else
+ cpu->Reg_usr[1] = ret;
+ }
+ #endif
+ } else if (!BIT(inst, 22)) {
+ for( i = 0; i < 16; i ++ ){
+ if(BIT(inst, i)){
+ //bus_read(32, addr, &ret);
+ #if 0
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ #endif
+ fault = interpreter_read_memory(addr, phys_addr, ret, 32);
+ if (fault) goto MMU_EXCEPTION;
+ /* For armv5t, should enter thumb when bits[0] is non-zero. */
+ if(i == 15){
+ cpu->TFlag = ret & 0x1;
+ ret &= 0xFFFFFFFE;
+ //DEBUG_LOG(ARM11, "In %s, TFlag ret=0x%x\n", __FUNCTION__, ret);
+ }
+
+ cpu->Reg[i] = ret;
+ addr += 4;
+ if ((addr & 0xfff) == 0) {
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ } else {
+ phys_addr += 4;
+ }
+ }
+ }
+ } else if (BIT(inst, 22) && BIT(inst, 15)) {
+ for( i = 0; i < 15; i ++ ){
+ if(BIT(inst, i)){
+ #if 0
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ #endif
+ fault = interpreter_read_memory(addr, phys_addr, ret, 32);
+ //if (fault) goto MMU_EXCEPTION;
+ cpu->Reg[i] = ret;
+ addr += 4;
+ if ((addr & 0xfff) == 0) {
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ } else {
+ phys_addr += 4;
+ }
+ }
+ }
+
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Cpsr & 0x1f);
+ LOAD_NZCVT;
+ }
+ #if 0
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ #endif
+ fault = interpreter_read_memory(addr, phys_addr, ret, 32);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ cpu->Reg[15] = ret;
+ #if 0
+ addr += 4;
+ phys_addr += 4;
+ #endif
+ }
+ if (BIT(inst, 15)) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SXTH_INST:
+ {
+ INC_ICOUNTER;
+ sxth_inst *inst_cream = (sxth_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
+ if (BIT(operand2, 15)) {
+ operand2 |= 0xffff0000;
+ } else {
+ operand2 &= 0xffff;
+ }
+ RD = operand2;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(sxth_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDR_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ //if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ //bus_read(32, addr, &value);
+ fault = interpreter_read_memory(addr, phys_addr, value, 32);
+ if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ else {
+ value = ROTATE_RIGHT_32(value,(8*(addr&0x3)));
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ }
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ /* For armv5t, should enter thumb when bits[0] is non-zero. */
+ cpu->TFlag = value & 0x1;
+ cpu->Reg[15] &= 0xFFFFFFFE;
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ //}
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDRCOND_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if (CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ //bus_read(32, addr, &value);
+ fault = interpreter_read_memory(addr, phys_addr, value, 32);
+ if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ else {
+ value = ROTATE_RIGHT_32(value,(8*(addr&0x3)));
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ }
+
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ /* For armv5t, should enter thumb when bits[0] is non-zero. */
+ cpu->TFlag = value & 0x1;
+ cpu->Reg[15] &= 0xFFFFFFFE;
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ UXTH_INST:
+ {
+ INC_ICOUNTER;
+ uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
+ & 0xffff;
+ RD = operand2;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(uxth_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ UXTAH_INST:
+ {
+ INC_ICOUNTER;
+ uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
+ & 0xffff;
+ RD = RN + operand2;
+ if (inst_cream->Rn == 15 || inst_cream->Rm == 15) {
+ DEBUG_LOG(ARM11, "in line %d\n", __LINE__);
+ CITRA_IGNORE_EXIT(-1);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(uxtah_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDRB_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 8);
+ if (fault) goto MMU_EXCEPTION;
+ //bus_read(8, addr, &value);
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDRBT_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 8);
+ if (fault) goto MMU_EXCEPTION;
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDRD_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ /* Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 || addr[2] == 0) */
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ uint32_t rear_phys_addr;
+ fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 1);
+ if(fault){
+ ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n");
+ CITRA_IGNORE_EXIT(-1);
+ goto MMU_EXCEPTION;
+ }
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ fault = interpreter_read_memory(addr + 4, rear_phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = value;
+ /* No dispatch since this operation should not modify R15 */
+ }
+ cpu->Reg[15] += 4;
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+
+ LDREX_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+
+ add_exclusive_addr(cpu, phys_addr);
+ cpu->exclusive_state = 1;
+
+ //bus_read(32, addr, &value);
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDREXB_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 8);
+ if (fault) goto MMU_EXCEPTION;
+
+ add_exclusive_addr(cpu, phys_addr);
+ cpu->exclusive_state = 1;
+
+ //bus_read(8, addr, &value);
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDRH_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value = 0;
+ fault = interpreter_read_memory(addr, phys_addr, value, 16);
+// fault = interpreter_read_memory(addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ //if (value == 0xffff && cpu->icounter > 190000000 && cpu->icounter < 210000000) {
+ // value = 0xffffffff;
+ //}
+ //bus_read(16, addr, &value);
+// cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value & 0xffff;
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDRSB_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+// DEBUG_LOG(ARM11, "ldrsb addr is %x\n", addr);
+ fault = interpreter_read_memory(addr, phys_addr, value, 8);
+ if (fault) goto MMU_EXCEPTION;
+ //bus_read(8, addr, &value);
+ if (BIT(value, 7)) {
+ value |= 0xffffff00;
+ }
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDRSH_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 16);
+ if (fault) goto MMU_EXCEPTION;
+ //bus_read(16, addr, &value);
+ if (BIT(value, 15)) {
+ value |= 0xffff0000;
+ }
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ LDRT_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+
+ if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+ else
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ROTATE_RIGHT_32(value,(8*(addr&0x3))) ;
+
+ if (BITS(inst_cream->inst, 12, 15) == 15) {
+ INC_PC(sizeof(ldst_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ MCR_INST:
+ {
+ INC_ICOUNTER;
+ /* NOT IMPL */
+ mcr_inst *inst_cream = (mcr_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ unsigned int inst = inst_cream->inst;
+ if (inst_cream->Rd == 15) {
+ DEBUG_MSG;
+ } else {
+ if (inst_cream->cp_num == 15) {
+ if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) {
+ //LET(RD, CONST(0x0007b000));
+ //LET(RD, CONST(0x410FB760));
+ //LET(CP15_MAIN_ID, R(RD));
+ CP15_REG(CP15_MAIN_ID) = RD;
+ } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
+ //LET(RD, R(CP15_CONTROL));
+ CP15_REG(CP15_AUXILIARY_CONTROL) = RD;
+ } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
+ //LET(RD, R(CP15_CONTROL));
+ CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD;
+ } else if(CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
+ //LET(CP15_CONTROL, R(RD));
+ CP15_REG(CP15_CONTROL) = RD;
+ } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
+ //LET(CP15_DOMAIN_ACCESS_CONTROL, R(RD));
+ CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD;
+ } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
+ //LET(CP15_TRANSLATION_BASE_TABLE_0, R(RD));
+ CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD;
+ } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) {
+ //LET(CP15_TRANSLATION_BASE_TABLE_1, R(RD));
+ CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD;
+ } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) {
+ //LET(CP15_TRANSLATION_BASE_CONTROL, R(RD));
+ CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD;
+ } else if(CRn == MMU_CACHE_OPS){
+ //SKYEYE_WARNING("cache operation have not implemented.\n");
+ } else if(CRn == MMU_TLB_OPS){
+ switch (CRm) {
+ case 5: /* ITLB */
+ switch(OPCODE_2){
+ case 0: /* invalidate all */
+ //invalidate_all_tlb(state);
+ DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate all\n");
+ //remove_tlb(INSN_TLB);
+ //erase_all(core, INSN_TLB);
+ break;
+ case 1: /* invalidate by MVA */
+ //invalidate_by_mva(state, value);
+ //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by mva\n");
+ //remove_tlb_by_mva(RD, INSN_TLB);
+ //erase_by_mva(core, RD, INSN_TLB);
+ break;
+ case 2: /* invalidate by asid */
+ //invalidate_by_asid(state, value);
+ //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by asid\n");
+ //erase_by_asid(core, RD, INSN_TLB);
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case 6: /* DTLB */
+ switch(OPCODE_2){
+ case 0: /* invalidate all */
+ //invalidate_all_tlb(state);
+ //remove_tlb(DATA_TLB);
+ //erase_all(core, DATA_TLB);
+ DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate all\n");
+ break;
+ case 1: /* invalidate by MVA */
+ //invalidate_by_mva(state, value);
+ //remove_tlb_by_mva(RD, DATA_TLB);
+ //erase_by_mva(core, RD, DATA_TLB);
+ //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by mva\n");
+ break;
+ case 2: /* invalidate by asid */
+ //invalidate_by_asid(state, value);
+ //remove_tlb_by_asid(RD, DATA_TLB);
+ //erase_by_asid(core, RD, DATA_TLB);
+ //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by asid\n");
+ break;
+ default:
+ break;
+ }
+ break;
+ case 7: /* UNIFILED TLB */
+ switch(OPCODE_2){
+ case 0: /* invalidate all */
+ //invalidate_all_tlb(state);
+ //erase_all(core, INSN_TLB);
+ //erase_all(core, DATA_TLB);
+ //remove_tlb(DATA_TLB);
+ //remove_tlb(INSN_TLB);
+ //DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate all\n");
+ break;
+ case 1: /* invalidate by MVA */
+ //invalidate_by_mva(state, value);
+ //erase_by_mva(core, RD, DATA_TLB);
+ //erase_by_mva(core, RD, INSN_TLB);
+ DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by mva\n");
+ break;
+ case 2: /* invalidate by asid */
+ //invalidate_by_asid(state, value);
+ //erase_by_asid(core, RD, DATA_TLB);
+ //erase_by_asid(core, RD, INSN_TLB);
+ DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by asid\n");
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if(CRn == MMU_PID){
+ if(OPCODE_2 == 0)
+ CP15_REG(CP15_PID) = RD;
+ else if(OPCODE_2 == 1)
+ CP15_REG(CP15_CONTEXT_ID) = RD;
+ else if(OPCODE_2 == 3){
+ CP15_REG(CP15_THREAD_URO) = RD;
+ }
+ else{
+ printf ("mmu_mcr wrote UNKNOWN - reg %d\n", CRn);
+ }
+
+ } else {
+ DEBUG_LOG(ARM11, "mcr is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2);
+ }
+ }
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mcr_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ MCRR_INST:
+ MLA_INST:
+ {
+ INC_ICOUNTER;
+ mla_inst *inst_cream = (mla_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ uint64_t rm = RM;
+ uint64_t rs = RS;
+ uint64_t rn = RN;
+ if (inst_cream->Rm == 15 || inst_cream->Rs == 15 || inst_cream->Rn == 15) {
+ DEBUG_LOG(ARM11, "in __line__\n", __LINE__);
+ CITRA_IGNORE_EXIT(-1);
+ }
+// RD = dst = RM * RS + RN;
+ RD = dst = static_cast<uint32_t>((rm * rs + rn) & 0xffffffff);
+ if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(mla_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mla_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ MOV_INST:
+ {
+// DEBUG_LOG(ARM11, "mov inst\n");
+// DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]);
+// debug_function(cpu);
+// cpu->icount ++;
+ INC_ICOUNTER;
+ mov_inst *inst_cream = (mov_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ RD = dst = SHIFTER_OPERAND;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr */
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_WITH_SC;
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(mov_inst));
+ goto DISPATCH;
+ }
+// return;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mov_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ MRC_INST:
+ {
+ INC_ICOUNTER;
+ /* NOT IMPL */
+ mrc_inst *inst_cream = (mrc_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ unsigned int inst = inst_cream->inst;
+ if (inst_cream->Rd == 15) {
+ DEBUG_MSG;
+ }
+ if (inst_cream->inst == 0xeef04a10) {
+ /* undefined instruction fmrx */
+ RD = 0x20000000;
+ CITRA_IGNORE_EXIT(-1);
+ goto END;
+ } else {
+ if (inst_cream->cp_num == 15) {
+ if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) {
+ //LET(RD, CONST(0x0007b000));
+ //LET(RD, CONST(0x410FB760));
+ //LET(RD, R(CP15_MAIN_ID));
+ RD = cpu->CP15[CP15(CP15_MAIN_ID)];
+ } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
+ //LET(RD, R(CP15_CONTROL));
+ RD = cpu->CP15[CP15(CP15_CONTROL)];
+ } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
+ //LET(RD, R(CP15_CONTROL));
+ RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)];
+ } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
+ //LET(RD, R(CP15_CONTROL));
+ RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)];
+ } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
+ //LET(RD, R(CP15_DOMAIN_ACCESS_CONTROL));
+ RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)];
+ } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
+ //LET(RD, R(CP15_TRANSLATION_BASE_TABLE_0));
+ RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)];
+ } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) {
+ //LET(RD, R(CP15_FAULT_STATUS));
+ RD = cpu->CP15[CP15(CP15_FAULT_STATUS)];
+ } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) {
+ //LET(RD, R(CP15_FAULT_ADDRESS));
+ RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)];
+ } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) {
+ //LET(RD, R(CP15_CACHE_TYPE));
+ RD = cpu->CP15[CP15(CP15_CACHE_TYPE)];
+ } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) {
+ //LET(RD, R(CP15_INSTR_FAULT_STATUS));
+ RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)];
+ } else if (CRn == 13) {
+ if(OPCODE_2 == 0)
+ RD = CP15_REG(CP15_PID);
+ else if(OPCODE_2 == 1)
+ RD = CP15_REG(CP15_CONTEXT_ID);
+ else if(OPCODE_2 == 3){
+ RD = Memory::KERNEL_MEMORY_VADDR;
+ }
+ else{
+ printf ("mmu_mrr wrote UNKNOWN - reg %d\n", CRn);
+ }
+ }
+ else {
+ DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2);
+ }
+ }
+ //DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mrc_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ MRRC_INST:
+ MRS_INST:
+ {
+ INC_ICOUNTER;
+ mrs_inst *inst_cream = (mrs_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ if (inst_cream->R) {
+ RD = cpu->Spsr_copy;
+ } else {
+ SAVE_NZCVT;
+ RD = cpu->Cpsr;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mrs_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ MSR_INST:
+ {
+ INC_ICOUNTER;
+ msr_inst *inst_cream = (msr_inst *)inst_base->component;
+ const uint32_t UnallocMask = 0x06f0fc00, UserMask = 0xf80f0200, PrivMask = 0x000001df, StateMask = 0x01000020;
+ unsigned int inst = inst_cream->inst;
+ unsigned int operand;
+
+ if (BIT(inst, 25)) {
+ int rot_imm = BITS(inst, 8, 11) * 2;
+ //operand = ROTL(CONST(BITS(0, 7)), CONST(32 - rot_imm));
+ operand = ROTATE_RIGHT_32(BITS(inst, 0, 7), rot_imm);
+ } else {
+ //operand = R(RM);
+ operand = cpu->Reg[BITS(inst, 0, 3)];
+ }
+ uint32_t byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0)
+ | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0);
+ uint32_t mask;
+ if (!inst_cream->R) {
+ if (InAPrivilegedMode(cpu)) {
+ if ((operand & StateMask) != 0) {
+ /* UNPREDICTABLE */
+ DEBUG_MSG;
+ } else
+ mask = byte_mask & (UserMask | PrivMask);
+ } else {
+ mask = byte_mask & UserMask;
+ }
+ //LET(CPSR_REG, OR(AND(R(CPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask))));
+ SAVE_NZCVT;
+
+ cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask);
+ switch_mode(cpu, cpu->Cpsr & 0x1f);
+ LOAD_NZCVT;
+ } else {
+ if (CurrentModeHasSPSR) {
+ mask = byte_mask & (UserMask | PrivMask | StateMask);
+ //LET(SPSR_REG, OR(AND(R(SPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask))));
+ cpu->Spsr_copy = (cpu->Spsr_copy & ~mask) | (operand & mask);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(msr_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ MUL_INST:
+ {
+ INC_ICOUNTER;
+ mul_inst *inst_cream = (mul_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+// RD = dst = SHIFTER_OPERAND;
+ uint64_t rm = RM;
+ uint64_t rs = RS;
+ RD = dst = static_cast<uint32_t>((rm * rs) & 0xffffffff);
+ if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(mul_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mul_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ MVN_INST:
+ {
+ INC_ICOUNTER;
+ mvn_inst *inst_cream = (mvn_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+// RD = dst = (SHIFTER_OPERAND ^ 0xffffffff);
+ RD = dst = ~SHIFTER_OPERAND;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr */
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_WITH_SC;
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(mvn_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(mvn_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ ORR_INST:
+ {
+ INC_ICOUNTER;
+ orr_inst *inst_cream = (orr_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ lop = RN;
+ rop = SHIFTER_OPERAND;
+// DEBUG_LOG(ARM11, "lop is %x, rop is %x, r2 is %x, r3 is %x\n", lop, rop, cpu->Reg[2], cpu->Reg[3]);
+ RD = dst = lop | rop;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr*/
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_WITH_SC;
+// UPDATE_CFLAG(dst, lop, rop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(orr_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(orr_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ PKHBT_INST:
+ PKHTB_INST:
+ PLD_INST:
+ {
+ INC_ICOUNTER;
+ /* NOT IMPL */
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(stc_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ QADD_INST:
+ QADD16_INST:
+ QADD8_INST:
+ QADDSUBX_INST:
+ QDADD_INST:
+ QDSUB_INST:
+ QSUB_INST:
+ QSUB16_INST:
+ QSUB8_INST:
+ QSUBADDX_INST:
+ REV_INST:
+ {
+ INC_ICOUNTER;
+ rev_inst *inst_cream = (rev_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ RD = ((RM & 0xff) << 24) |
+ (((RM >> 8) & 0xff) << 16) |
+ (((RM >> 16) & 0xff) << 8) |
+ ((RM >> 24) & 0xff);
+ if (inst_cream->Rm == 15) {
+ DEBUG_LOG(ARM11, "in line %d\n", __LINE__);
+ CITRA_IGNORE_EXIT(-1);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(rev_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ REV16_INST:
+ {
+ INC_ICOUNTER;
+ rev_inst *inst_cream = (rev_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ RD = (BITS(RM, 0, 7) << 8) |
+ BITS(RM, 8, 15) |
+ (BITS(RM, 16, 23) << 24) |
+ (BITS(RM, 24, 31) << 16);
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(rev_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ REVSH_INST:
+ RFE_INST:
+ RSB_INST:
+ {
+ INC_ICOUNTER;
+ rsb_inst *inst_cream = (rsb_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ rop = RN;
+ lop = SHIFTER_OPERAND;
+ if (inst_cream->Rn == 15) {
+ rop += 2 * GET_INST_SIZE(cpu);;
+ }
+ RD = dst = lop - rop;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr */
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
+// UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
+ UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(rsb_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(rsb_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ RSC_INST:
+ {
+ INC_ICOUNTER;
+ rsc_inst *inst_cream = (rsc_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ //lop = RN + !cpu->CFlag;
+ //rop = SHIFTER_OPERAND;
+ //RD = dst = rop - lop;
+ lop = RN;
+ rop = SHIFTER_OPERAND;
+ RD = dst = rop - lop - !cpu->CFlag;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr */
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+// UPDATE_CFLAG(dst, lop, rop);
+// UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop);
+ UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(rop, lop, !cpu->CFlag);
+// cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst)));
+ UPDATE_VFLAG_OVERFLOW_FROM((int)dst, (int)rop, (int)lop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(rsc_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(rsc_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SADD16_INST:
+ SADD8_INST:
+ SADDSUBX_INST:
+ SBC_INST:
+ {
+ INC_ICOUNTER;
+ sbc_inst *inst_cream = (sbc_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ lop = SHIFTER_OPERAND + !cpu->CFlag;
+ rop = RN;
+ RD = dst = rop - lop;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr */
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+// UPDATE_CFLAG(dst, lop, rop);
+ //UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop);
+ //rop = rop - !cpu->CFlag;
+ if(rop >= !cpu->CFlag)
+ UPDATE_CFLAG_NOT_BORROW_FROM(rop - !cpu->CFlag, SHIFTER_OPERAND);
+ else
+ UPDATE_CFLAG_NOT_BORROW_FROM(rop, !cpu->CFlag);
+// cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst)));
+ UPDATE_VFLAG_OVERFLOW_FROM(dst, rop, lop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(sbc_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(sbc_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SEL_INST:
+ SETEND_INST:
+ SHADD16_INST:
+ SHADD8_INST:
+ SHADDSUBX_INST:
+ SHSUB16_INST:
+ SHSUB8_INST:
+ SHSUBADDX_INST:
+ SMLA_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ smla_inst *inst_cream = (smla_inst *)inst_base->component;
+ int32_t operand1, operand2;
+ if (inst_cream->x == 0)
+ operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15);
+ else
+ operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31);
+
+ if (inst_cream->y == 0)
+ operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15);
+ else
+ operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
+ RD = operand1 * operand2 + RN;
+ //FIXME: UPDATE Q FLAGS
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(smla_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SMLAD_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
+ long long int rm = cpu->Reg[inst_cream->Rm];
+ long long int rn = cpu->Reg[inst_cream->Rn];
+ long long int ra = cpu->Reg[inst_cream->Ra];
+ /* see SMUAD */
+ if(inst_cream->Ra == 15)
+ CITRA_IGNORE_EXIT(-1);
+ int operand2 = (inst_cream->m)? ROTATE_RIGHT_32(rm, 16):rm;
+
+ int half_rn, half_operand2;
+ half_rn = rn & 0xFFFF;
+ half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn;
+
+ half_operand2 = operand2 & 0xFFFF;
+ half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2;
+
+ long long int product1 = half_rn * half_operand2;
+
+ half_rn = (rn & 0xFFFF0000) >> 16;
+ half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn;
+
+ half_operand2 = (operand2 & 0xFFFF0000) >> 16;
+ half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2;
+
+ long long int product2 = half_rn * half_operand2;
+
+ long long int signed_ra = (ra & 0x80000000)? (0xFFFFFFFF00000000LL) | ra : ra;
+ long long int result = product1 + product2 + signed_ra;
+ cpu->Reg[inst_cream->Rd] = result & 0xFFFFFFFF;
+ /* FIXME , should check Signed overflow */
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(umlal_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+
+ SMLAL_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
+ long long int rm = RM;
+ long long int rs = RS;
+ if (BIT(rm, 31)) {
+ rm |= 0xffffffff00000000LL;
+ }
+ if (BIT(rs, 31)) {
+ rs |= 0xffffffff00000000LL;
+ }
+ long long int rst = rm * rs;
+ long long int rdhi32 = RDHI;
+ long long int hilo = (rdhi32 << 32) + RDLO;
+ rst += hilo;
+ RDLO = BITS(rst, 0, 31);
+ RDHI = BITS(rst, 32, 63);
+ if (inst_cream->S) {
+ cpu->NFlag = BIT(RDHI, 31);
+ cpu->ZFlag = (RDHI == 0 && RDLO == 0);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(umlal_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SMLALXY_INST:
+ SMLALD_INST:
+ SMLAW_INST:
+ SMLSD_INST:
+ SMLSLD_INST:
+ SMMLA_INST:
+ SMMLS_INST:
+ SMMUL_INST:
+ SMUAD_INST:
+ SMUL_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ smul_inst *inst_cream = (smul_inst *)inst_base->component;
+ uint32_t operand1, operand2;
+ if (inst_cream->x == 0)
+ operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15);
+ else
+ operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31);
+
+ if (inst_cream->y == 0)
+ operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15);
+ else
+ operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
+ RD = operand1 * operand2;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(smul_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SMULL_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ umull_inst *inst_cream = (umull_inst *)inst_base->component;
+// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst);
+ int64_t rm = RM;
+ int64_t rs = RS;
+ if (BIT(rm, 31)) {
+ rm |= 0xffffffff00000000LL;
+ }
+ if (BIT(rs, 31)) {
+ rs |= 0xffffffff00000000LL;
+ }
+ int64_t rst = rm * rs;
+ RDHI = BITS(rst, 32, 63);
+ RDLO = BITS(rst, 0, 31);
+
+
+ if (inst_cream->S) {
+ cpu->NFlag = BIT(RDHI, 31);
+ cpu->ZFlag = (RDHI == 0 && RDLO == 0);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(umull_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SMULW_INST:
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
+// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst);
+ int64_t rm = RM;
+ int64_t rn = RN;
+ if (inst_cream->m)
+ rm = BITS(rm,16 , 31);
+ else
+ rm = BITS(rm,0 , 15);
+ int64_t rst = rm * rn;
+ RD = BITS(rst, 16, 47);
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(smlad_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+
+ SMUSD_INST:
+ SRS_INST:
+ SSAT_INST:
+ SSAT16_INST:
+ SSUB16_INST:
+ SSUB8_INST:
+ SSUBADDX_INST:
+ STC_INST:
+ {
+ INC_ICOUNTER;
+ /* NOT IMPL */
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(stc_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STM_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ unsigned int inst = inst_cream->inst;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ int i;
+ unsigned int Rn = BITS(inst, 16, 19);
+ unsigned int old_RN = cpu->Reg[Rn];
+
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+ if (BIT(inst_cream->inst, 22) == 1) {
+// DEBUG_MSG;
+ #if 1
+ for (i = 0; i < 13; i++) {
+ if(BIT(inst_cream->inst, i)){
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
+ if (fault) goto MMU_EXCEPTION;
+ addr += 4;
+ phys_addr += 4;
+ }
+ }
+ if (BIT(inst_cream->inst, 13)) {
+ if (cpu->Mode == USER32MODE) {
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
+ if (fault) goto MMU_EXCEPTION;
+ addr += 4;
+ phys_addr += 4;
+ } else {
+ fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[0], 32);
+ if (fault) goto MMU_EXCEPTION;
+ addr += 4;
+ phys_addr += 4;
+ }
+ }
+ if (BIT(inst_cream->inst, 14)) {
+ if (cpu->Mode == USER32MODE) {
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
+ if (fault) goto MMU_EXCEPTION;
+ addr += 4;
+ phys_addr += 4;
+ } else {
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[1], 32);
+ if (fault) goto MMU_EXCEPTION;
+ addr += 4;
+ phys_addr += 4;
+ }
+ }
+ if (BIT(inst_cream->inst, 15)) {
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ #endif
+ } else {
+ for( i = 0; i < 15; i ++ ){
+ if(BIT(inst_cream->inst, i)){
+ //arch_write_memory(cpu, bb, Addr, R(i), 32);
+ //bus_write(32, addr, cpu->Reg[i]);
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ if(i == Rn)
+ fault = interpreter_write_memory(addr, phys_addr, old_RN, 32);
+ else
+ fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
+ if (fault) goto MMU_EXCEPTION;
+ addr += 4;
+ phys_addr += 4;
+ //Addr = ADD(Addr, CONST(4));
+ }
+ }
+
+ /* check pc reg*/
+ if(BIT(inst_cream->inst, i)){
+ //arch_write_memory(cpu, bb, Addr, STOREM_CHECK_PC, 32);
+ //bus_write(32, addr, cpu->Reg[i] + 8);
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) {
+ goto MMU_EXCEPTION;
+ }
+ fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SXTB_INST:
+ {
+ INC_ICOUNTER;
+ sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ if (inst_cream->Rm == 15) {
+ DEBUG_LOG(ARM11, "line is %d\n", __LINE__);
+ CITRA_IGNORE_EXIT(-1);
+ }
+ unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
+ if (BIT(operand2, 7)) {
+ operand2 |= 0xffffff00;
+ } else
+ operand2 &= 0xff;
+ RD = operand2;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(sxtb_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STR_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
+ //bus_write(32, addr, value);
+ fault = interpreter_write_memory(addr, phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ UXTB_INST:
+ {
+ INC_ICOUNTER;
+ uxtb_inst *inst_cream = (uxtb_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
+ & 0xff;
+ RD = operand2;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(uxtb_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ UXTAB_INST:
+ {
+ INC_ICOUNTER;
+ uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
+ & 0xff;
+ RD = RN + operand2;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(uxtab_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STRB_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
+ //bus_write(8, addr, value);
+ fault = interpreter_write_memory(addr, phys_addr, value, 8);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STRBT_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
+ //bus_write(8, addr, value);
+ fault = interpreter_write_memory(addr, phys_addr, value, 8);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ //if (BITS(inst_cream->inst, 12, 15) == 15)
+ // goto DISPATCH;
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STRD_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+ uint32_t rear_phys_addr;
+ fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 0);
+ if (fault){
+ ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n");
+ CITRA_IGNORE_EXIT(-1);
+ goto MMU_EXCEPTION;
+ }
+
+ //fault = inst_cream->get_addr(cpu, inst_cream->inst, addr + 4, phys_addr + 4, 0);
+ //if (fault) goto MMU_EXCEPTION;
+
+ unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
+ //bus_write(32, addr, value);
+ fault = interpreter_write_memory(addr, phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ value = cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1];
+ //bus_write(32, addr, value);
+ fault = interpreter_write_memory(addr + 4, rear_phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STREX_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
+ unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)];
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+
+ int dest_reg = BITS(inst_cream->inst, 12, 15);
+ if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){
+ remove_exclusive(cpu, phys_addr);
+ cpu->Reg[dest_reg] = 0;
+ cpu->exclusive_state = 0;
+
+ // bus_write(32, addr, value);
+ fault = interpreter_write_memory(addr, phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ else{
+ /* Failed to write due to mutex access */
+ cpu->Reg[dest_reg] = 1;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STREXB_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
+ unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)] & 0xff;
+ fault = check_address_validity(cpu, addr, &phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+ //bus_write(8, addr, value);
+ int dest_reg = BITS(inst_cream->inst, 12, 15);
+ if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){
+ remove_exclusive(cpu, phys_addr);
+ cpu->Reg[dest_reg] = 0;
+ cpu->exclusive_state = 0;
+ fault = interpreter_write_memory(addr, phys_addr, value, 8);
+ if (fault) goto MMU_EXCEPTION;
+
+ }
+ else{
+ cpu->Reg[dest_reg] = 1;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STRH_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff;
+ //bus_write(16, addr, value);
+ fault = interpreter_write_memory(addr, phys_addr, value, 16);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ //if (BITS(inst_cream->inst, 12, 15) == 15)
+ // goto DISPATCH;
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ STRT_INST:
+ {
+ INC_ICOUNTER;
+ ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
+ //bus_write(16, addr, value);
+ fault = interpreter_write_memory(addr, phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(ldst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SUB_INST:
+ {
+ INC_ICOUNTER;
+ sub_inst *inst_cream = (sub_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ lop = RN;
+ if (inst_cream->Rn == 15) {
+ lop += 8;
+ }
+ rop = SHIFTER_OPERAND;
+ RD = dst = lop - rop;
+ if (inst_cream->S && (inst_cream->Rd == 15)) {
+ /* cpsr = spsr */
+ if (CurrentModeHasSPSR) {
+ cpu->Cpsr = cpu->Spsr_copy;
+ switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ LOAD_NZCVT;
+ }
+ } else if (inst_cream->S) {
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+// UPDATE_CFLAG(dst, lop, rop);
+ UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
+ // UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
+ UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
+ }
+ if (inst_cream->Rd == 15) {
+ INC_PC(sizeof(sub_inst));
+ goto DISPATCH;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(sub_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SWI_INST:
+ {
+ INC_ICOUNTER;
+ swi_inst *inst_cream = (swi_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ if (true){ //if (core->is_user_mode) { --> Citra only emulates user mode
+ //arm_dyncom_SWI(cpu, inst_cream->num);
+ HLE::CallSVC(Memory::Read32(cpu->Reg[15]));
+ } else {
+ cpu->syscallSig = 1;
+ goto END;
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(swi_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SWP_INST:
+ {
+ INC_ICOUNTER;
+ swp_inst *inst_cream = (swp_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ addr = RN;
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 32);
+ if (fault) goto MMU_EXCEPTION;
+ fault = interpreter_write_memory(addr, phys_addr, RM, 32);
+ if (fault) goto MMU_EXCEPTION;
+
+ /* ROR(data, 8*UInt(address<1:0>)); */
+ assert((phys_addr & 0x3) == 0);
+ RD = value;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(swp_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SWPB_INST:
+ {
+ INC_ICOUNTER;
+ swp_inst *inst_cream = (swp_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ addr = RN;
+ fault = check_address_validity(cpu, addr, &phys_addr, 1);
+ if (fault) goto MMU_EXCEPTION;
+ unsigned int value;
+ fault = interpreter_read_memory(addr, phys_addr, value, 8);
+ if (fault) goto MMU_EXCEPTION;
+ fault = interpreter_write_memory(addr, phys_addr, (RM & 0xFF), 8);
+ if (fault) goto MMU_EXCEPTION;
+
+ /* FIXME */
+ #if 0
+ if Shared(address) then
+ /* ARMv6 */
+ physical_address = TLB(address)
+ ClearExclusiveByAddress(physical_address,processor_id,1)
+ /* See Summary of operation on page A2-49 */
+ #endif
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(swp_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SXTAB_INST:
+ {
+ INC_ICOUNTER;
+ sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ /* R15 should be check */
+ if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){
+ CITRA_IGNORE_EXIT(-1);
+ }
+ unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
+ & 0xff;
+ /* sign extend for byte */
+ operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2;
+ RD = RN + operand2;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(uxtab_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SXTAB16_INST:
+ SXTAH_INST:
+ {
+ INC_ICOUNTER;
+ sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ /* R15 should be check */
+ if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){
+ CITRA_IGNORE_EXIT(-1);
+ }
+ unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff;
+ /* sign extend for half */
+ operand2 = (0x8000 & operand2)? (0xFFFF0000 | operand2):operand2;
+ RD = RN + operand2;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(sxtah_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ SXTB16_INST:
+ TEQ_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ teq_inst *inst_cream = (teq_inst *)inst_base->component;
+ lop = RN;
+ if (inst_cream->Rn == 15)
+ lop += GET_INST_SIZE(cpu) * 2;
+
+ rop = SHIFTER_OPERAND;
+ dst = lop ^ rop;
+
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_WITH_SC;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(teq_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ TST_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ tst_inst *inst_cream = (tst_inst *)inst_base->component;
+ lop = RN;
+ if (inst_cream->Rn == 15)
+ lop += GET_INST_SIZE(cpu) * 2;
+ rop = SHIFTER_OPERAND;
+ dst = lop & rop;
+
+ UPDATE_NFLAG(dst);
+ UPDATE_ZFLAG(dst);
+ UPDATE_CFLAG_WITH_SC;
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(tst_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ UADD16_INST:
+ UADD8_INST:
+ UADDSUBX_INST:
+ UHADD16_INST:
+ UHADD8_INST:
+ UHADDSUBX_INST:
+ UHSUB16_INST:
+ UHSUB8_INST:
+ UHSUBADDX_INST:
+ UMAAL_INST:
+ UMLAL_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
+ unsigned long long int rm = RM;
+ unsigned long long int rs = RS;
+ unsigned long long int rst = rm * rs;
+ unsigned long long int add = ((unsigned long long) RDHI)<<32;
+ add += RDLO;
+ //DEBUG_LOG(ARM11, "rm[%llx] * rs[%llx] = rst[%llx] | add[%llx]\n", RM, RS, rst, add);
+ rst += add;
+ RDLO = BITS(rst, 0, 31);
+ RDHI = BITS(rst, 32, 63);
+
+ if (inst_cream->S)
+ {
+ cpu->NFlag = BIT(RDHI, 31);
+ cpu->ZFlag = (RDHI == 0 && RDLO == 0);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(umlal_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ UMULL_INST:
+ {
+ INC_ICOUNTER;
+ if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ umull_inst *inst_cream = (umull_inst *)inst_base->component;
+ unsigned long long int rm = RM;
+ unsigned long long int rs = RS;
+ unsigned long long int rst = rm * rs;
+// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst);
+ RDHI = BITS(rst, 32, 63);
+ RDLO = BITS(rst, 0, 31);
+
+ if (inst_cream->S) {
+ cpu->NFlag = BIT(RDHI, 31);
+ cpu->ZFlag = (RDHI == 0 && RDLO == 0);
+ }
+ }
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(umull_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
+ B_2_THUMB:
+ {
+ INC_ICOUNTER;
+ b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component;
+ cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
+ //DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
+ INC_PC(sizeof(b_2_thumb));
+ goto DISPATCH;
+ }
+ B_COND_THUMB:
+ {
+ INC_ICOUNTER;
+ b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component;
+ if(CondPassed(cpu, inst_cream->cond))
+ cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
+ else
+ cpu->Reg[15] += 2;
+ //DEBUG_LOG(ARM11, " B_COND_THUMB: imm=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[15]);
+ INC_PC(sizeof(b_cond_thumb));
+ goto DISPATCH;
+ }
+ BL_1_THUMB:
+ {
+ INC_ICOUNTER;
+ bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component;
+ cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm;
+ //cpu->Reg[15] += 2;
+ //DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
+
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(bl_1_thumb));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+
+ }
+ BL_2_THUMB:
+ {
+ INC_ICOUNTER;
+ bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component;
+ int tmp = ((cpu->Reg[15] + 2) | 1);
+ cpu->Reg[15] =
+ (cpu->Reg[14] + inst_cream->imm);
+ cpu->Reg[14] = tmp;
+ //DEBUG_LOG(ARM11, " BL_2_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
+ INC_PC(sizeof(bl_2_thumb));
+ goto DISPATCH;
+ }
+ BLX_1_THUMB:
+ {
+ /* BLX 1 for armv5t and above */
+ INC_ICOUNTER;
+ uint32 tmp = cpu->Reg[15];
+ blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component;
+ cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm) & 0xFFFFFFFC;
+ //DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, instr=0x%x\n", inst_cream->imm, cpu->Reg[14], inst_cream->instr);
+ cpu->Reg[14] = ((tmp + 2) | 1);
+ //(state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC;
+ /* switch to arm state from thumb state */
+ cpu->TFlag = 0;
+ //DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, r15=0x%x, \n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
+ INC_PC(sizeof(blx_1_thumb));
+ goto DISPATCH;
+ }
+
+ UQADD16_INST:
+ UQADD8_INST:
+ UQADDSUBX_INST:
+ UQSUB16_INST:
+ UQSUB8_INST:
+ UQSUBADDX_INST:
+ USAD8_INST:
+ USADA8_INST:
+ USAT_INST:
+ USAT16_INST:
+ USUB16_INST:
+ USUB8_INST:
+ USUBADDX_INST:
+ UXTAB16_INST:
+ UXTB16_INST:
+ #define VFP_INTERPRETER_IMPL
+ #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+ #undef VFP_INTERPRETER_IMPL
+ MMU_EXCEPTION:
+ {
+ SAVE_NZCVT;
+ cpu->abortSig = true;
+ cpu->Aborted = ARMul_DataAbortV;
+ cpu->AbortAddr = addr;
+ cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff;
+ cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
+ }
+ END:
+ {
+ SAVE_NZCVT;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
+ }
+ INIT_INST_LENGTH:
+ {
+#if 0
+ DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel));
+ for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++)
+ DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]);
+ DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel));
+#endif
+#if defined __GNUC__ || defined __clang__
+ InterpreterInitInstLength((unsigned long long int *)InstLabel, sizeof(InstLabel));
+#endif
+#if 0
+ for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++)
+ DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]);
+ DEBUG_LOG(ARM11, "%llx\n", InstEndLabel[1]);
+ DEBUG_LOG(ARM11, "%llx\n", InstLabel[1]);
+ DEBUG_LOG(ARM11, "%lld\n", (char *)InstEndLabel[1] - (char *)InstLabel[1]);
+#endif
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
+ }
+}
+
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h
new file mode 100644
index 000000000..c65eb23f7
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h
@@ -0,0 +1,7 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+unsigned InterpreterMainLoop(ARMul_State* state);
diff --git a/src/core/arm/dyncom/arm_dyncom_run.cpp b/src/core/arm/dyncom/arm_dyncom_run.cpp
new file mode 100644
index 000000000..a2026cbf3
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_run.cpp
@@ -0,0 +1,120 @@
+/* Copyright (C)
+* 2011 - Michael.Kang blackfin.kang@gmail.com
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+*/
+/**
+* @file arm_dyncom_run.cpp
+* @brief The dyncom run implementation for arm
+* @author Michael.Kang blackfin.kang@gmail.com
+* @version 78.77
+* @date 2011-11-20
+*/
+
+#include <assert.h>
+
+#include "core/arm/skyeye_common/armdefs.h"
+
+void switch_mode(arm_core_t *core, uint32_t mode)
+{
+ uint32_t tmp1, tmp2;
+ if (core->Mode == mode) {
+ //Mode not changed.
+ //printf("mode not changed\n");
+ return;
+ }
+ //printf("%d --->>> %d\n", core->Mode, mode);
+ //printf("In %s, Cpsr=0x%x, R15=0x%x, last_pc=0x%x, cpsr=0x%x, spsr_copy=0x%x, icounter=%lld\n", __FUNCTION__, core->Cpsr, core->Reg[15], core->last_pc, core->Cpsr, core->Spsr_copy, core->icounter);
+ if (mode != USERBANK) {
+ switch (core->Mode) {
+ case USER32MODE:
+ core->Reg_usr[0] = core->Reg[13];
+ core->Reg_usr[1] = core->Reg[14];
+ break;
+ case IRQ32MODE:
+ core->Reg_irq[0] = core->Reg[13];
+ core->Reg_irq[1] = core->Reg[14];
+ core->Spsr[IRQBANK] = core->Spsr_copy;
+ break;
+ case SVC32MODE:
+ core->Reg_svc[0] = core->Reg[13];
+ core->Reg_svc[1] = core->Reg[14];
+ core->Spsr[SVCBANK] = core->Spsr_copy;
+ break;
+ case ABORT32MODE:
+ core->Reg_abort[0] = core->Reg[13];
+ core->Reg_abort[1] = core->Reg[14];
+ core->Spsr[ABORTBANK] = core->Spsr_copy;
+ break;
+ case UNDEF32MODE:
+ core->Reg_undef[0] = core->Reg[13];
+ core->Reg_undef[1] = core->Reg[14];
+ core->Spsr[UNDEFBANK] = core->Spsr_copy;
+ break;
+ case FIQ32MODE:
+ core->Reg_firq[0] = core->Reg[13];
+ core->Reg_firq[1] = core->Reg[14];
+ core->Spsr[FIQBANK] = core->Spsr_copy;
+ break;
+
+ }
+
+ switch (mode) {
+ case USER32MODE:
+ core->Reg[13] = core->Reg_usr[0];
+ core->Reg[14] = core->Reg_usr[1];
+ core->Bank = USERBANK;
+ break;
+ case IRQ32MODE:
+ core->Reg[13] = core->Reg_irq[0];
+ core->Reg[14] = core->Reg_irq[1];
+ core->Spsr_copy = core->Spsr[IRQBANK];
+ core->Bank = IRQBANK;
+ break;
+ case SVC32MODE:
+ core->Reg[13] = core->Reg_svc[0];
+ core->Reg[14] = core->Reg_svc[1];
+ core->Spsr_copy = core->Spsr[SVCBANK];
+ core->Bank = SVCBANK;
+ break;
+ case ABORT32MODE:
+ core->Reg[13] = core->Reg_abort[0];
+ core->Reg[14] = core->Reg_abort[1];
+ core->Spsr_copy = core->Spsr[ABORTBANK];
+ core->Bank = ABORTBANK;
+ break;
+ case UNDEF32MODE:
+ core->Reg[13] = core->Reg_undef[0];
+ core->Reg[14] = core->Reg_undef[1];
+ core->Spsr_copy = core->Spsr[UNDEFBANK];
+ core->Bank = UNDEFBANK;
+ break;
+ case FIQ32MODE:
+ core->Reg[13] = core->Reg_firq[0];
+ core->Reg[14] = core->Reg_firq[1];
+ core->Spsr_copy = core->Spsr[FIQBANK];
+ core->Bank = FIQBANK;
+ break;
+
+ }
+ core->Mode = mode;
+ //printf("In %si end, Cpsr=0x%x, R15=0x%x, last_pc=0x%x, cpsr=0x%x, spsr_copy=0x%x, icounter=%lld\n", __FUNCTION__, core->Cpsr, core->Reg[15], core->last_pc, core->Cpsr, core->Spsr_copy, core->icounter);
+ //printf("\n--------------------------------------\n");
+ }
+ else {
+ printf("user mode\n");
+ exit(-2);
+ }
+}
diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h
new file mode 100644
index 000000000..aeabeac16
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_run.h
@@ -0,0 +1,55 @@
+/* Copyright (C)
+* 2011 - Michael.Kang blackfin.kang@gmail.com
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+*/
+
+#ifndef __ARM_DYNCOM_RUN__
+#define __ARM_DYNCOM_RUN__
+
+#include "core/arm/skyeye_common/skyeye_types.h"
+
+void switch_mode(arm_core_t *core, uint32_t mode);
+
+/* FIXME, we temporarily think thumb instruction is always 16 bit */
+static inline uint32 GET_INST_SIZE(arm_core_t* core){
+ return core->TFlag? 2 : 4;
+}
+
+/**
+* @brief Read R15 and forced R15 to wold align, used address calculation
+*
+* @param core
+* @param Rn
+*
+* @return
+*/
+static inline addr_t CHECK_READ_REG15_WA(arm_core_t* core, int Rn){
+ return (Rn == 15)? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
+}
+
+/**
+* @brief Read R15, used to data processing with pc
+*
+* @param core
+* @param Rn
+*
+* @return
+*/
+static inline uint32 CHECK_READ_REG15(arm_core_t* core, int Rn){
+ return (Rn == 15)? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
+}
+
+#endif
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
new file mode 100644
index 000000000..e10f2f9ee
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -0,0 +1,521 @@
+/* Copyright (C)
+* 2011 - Michael.Kang blackfin.kang@gmail.com
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+*/
+/**
+* @file arm_dyncom_thumb.c
+* @brief The thumb dynamic interpreter
+* @author Michael.Kang blackfin.kang@gmail.com
+* @version 78.77
+* @date 2011-11-07
+*/
+
+/* We can provide simple Thumb simulation by decoding the Thumb
+instruction into its corresponding ARM instruction, and using the
+existing ARM simulator. */
+
+#include "core/arm/skyeye_common/skyeye_defs.h"
+
+#ifndef MODET /* required for the Thumb instruction support */
+#if 1
+#error "MODET needs to be defined for the Thumb world to work"
+#else
+#define MODET (1)
+#endif
+#endif
+
+#include "core/arm/skyeye_common/armos.h"
+#include "core/arm/dyncom/arm_dyncom_thumb.h"
+
+/* Decode a 16bit Thumb instruction. The instruction is in the low
+ 16-bits of the tinstr field, with the following Thumb instruction
+ held in the high 16-bits. Passing in two Thumb instructions allows
+ easier simulation of the special dual BL instruction. */
+
+tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size)
+{
+ tdstate valid = t_uninitialized;
+ ARMword next_instr;
+ ARMword tinstr;
+ tinstr = instr;
+ /* The endian should be judge here */
+ #if 0
+ if (state->bigendSig) {
+ next_instr = tinstr & 0xFFFF;
+ tinstr >>= 16;
+ }
+ else {
+ next_instr = tinstr >> 16;
+ tinstr &= 0xFFFF;
+ }
+ #endif
+ if((addr & 0x3) != 0)
+ tinstr = instr >> 16;
+ else
+ tinstr &= 0xFFFF;
+
+ //printf("In %s, instr=0x%x, tinstr=0x%x, r15=0x%x\n", __FUNCTION__, instr, tinstr, cpu->translate_pc);
+#if 1 /* debugging to catch non updates */
+ *ainstr = 0xDEADC0DE;
+#endif
+
+ switch ((tinstr & 0xF800) >> 11) {
+ case 0: /* LSL */
+ case 1: /* LSR */
+ case 2: /* ASR */
+ /* Format 1 */
+ *ainstr = 0xE1B00000 /* base opcode */
+ | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */
+ |((tinstr & 0x07C0) << (7 - 6)) /* imm5 */
+ |((tinstr & 0x0038) >> 3) /* Rs */
+ |((tinstr & 0x0007) << 12); /* Rd */
+ break;
+ case 3: /* ADD/SUB */
+ /* Format 2 */
+ {
+ ARMword subset[4] = {
+ 0xE0900000, /* ADDS Rd,Rs,Rn */
+ 0xE0500000, /* SUBS Rd,Rs,Rn */
+ 0xE2900000, /* ADDS Rd,Rs,#imm3 */
+ 0xE2500000 /* SUBS Rd,Rs,#imm3 */
+ };
+ /* It is quicker indexing into a table, than performing switch
+ or conditionals: */
+ *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */
+ |((tinstr & 0x01C0) >> 6) /* Rn or imm3 */
+ |((tinstr & 0x0038) << (16 - 3)) /* Rs */
+ |((tinstr & 0x0007) << (12 - 0)); /* Rd */
+ }
+ break;
+ case 4: /* MOV */
+ case 5: /* CMP */
+ case 6: /* ADD */
+ case 7: /* SUB */
+ /* Format 3 */
+ {
+ ARMword subset[4] = {
+ 0xE3B00000, /* MOVS Rd,#imm8 */
+ 0xE3500000, /* CMP Rd,#imm8 */
+ 0xE2900000, /* ADDS Rd,Rd,#imm8 */
+ 0xE2500000, /* SUBS Rd,Rd,#imm8 */
+ };
+ *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */
+ |((tinstr & 0x00FF) >> 0) /* imm8 */
+ |((tinstr & 0x0700) << (16 - 8)) /* Rn */
+ |((tinstr & 0x0700) << (12 - 8)); /* Rd */
+ }
+ break;
+ case 8: /* Arithmetic and high register transfers */
+ /* TODO: Since the subsets for both Format 4 and Format 5
+ instructions are made up of different ARM encodings, we could
+ save the following conditional, and just have one large
+ subset. */
+ if ((tinstr & (1 << 10)) == 0) {
+ typedef enum
+ { t_norm, t_shift, t_neg, t_mul }otype_t;
+
+ /* Format 4 */
+ struct
+ {
+ ARMword opcode;
+ otype_t otype;
+ }
+ subset[16] = {
+ {
+ 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */
+ {
+ 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */
+ {
+ 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */
+ {
+ 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */
+ {
+ 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */
+ {
+ 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */
+ {
+ 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */
+ {
+ 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */
+ {
+ 0xE1100000, t_norm}, /* TST Rd,Rs */
+ {
+ 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */
+ {
+ 0xE1500000, t_norm}, /* CMP Rd,Rs */
+ {
+ 0xE1700000, t_norm}, /* CMN Rd,Rs */
+ {
+ 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */
+ {
+ 0xE0100090, t_mul}, /* MULS Rd,Rd,Rs */
+ {
+ 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */
+ {
+ 0xE1F00000, t_norm} /* MVNS Rd,Rs */
+ };
+ *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
+ switch (subset[(tinstr & 0x03C0) >> 6].otype) {
+ case t_norm:
+ *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */
+ |((tinstr & 0x0007) << 12) /* Rd */
+ |((tinstr & 0x0038) >> 3); /* Rs */
+ break;
+ case t_shift:
+ *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
+ |((tinstr & 0x0007) >> 0) /* Rm */
+ |((tinstr & 0x0038) << (8 - 3)); /* Rs */
+ break;
+ case t_neg:
+ *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
+ |((tinstr & 0x0038) << (16 - 3)); /* Rn */
+ break;
+ case t_mul:
+ *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */
+ |((tinstr & 0x0007) << 8) /* Rs */
+ |((tinstr & 0x0038) >> 3); /* Rm */
+ break;
+ }
+ }
+ else {
+ /* Format 5 */
+ ARMword Rd = ((tinstr & 0x0007) >> 0);
+ ARMword Rs = ((tinstr & 0x0038) >> 3);
+ if (tinstr & (1 << 7))
+ Rd += 8;
+ if (tinstr & (1 << 6))
+ Rs += 8;
+ switch ((tinstr & 0x03C0) >> 6) {
+ case 0x1: /* ADD Rd,Rd,Hs */
+ case 0x2: /* ADD Hd,Hd,Rs */
+ case 0x3: /* ADD Hd,Hd,Hs */
+ *ainstr = 0xE0800000 /* base */
+ | (Rd << 16) /* Rn */
+ |(Rd << 12) /* Rd */
+ |(Rs << 0); /* Rm */
+ break;
+ case 0x5: /* CMP Rd,Hs */
+ case 0x6: /* CMP Hd,Rs */
+ case 0x7: /* CMP Hd,Hs */
+ *ainstr = 0xE1500000 /* base */
+ | (Rd << 16) /* Rn */
+ |(Rd << 12) /* Rd */
+ |(Rs << 0); /* Rm */
+ break;
+ case 0x9: /* MOV Rd,Hs */
+ case 0xA: /* MOV Hd,Rs */
+ case 0xB: /* MOV Hd,Hs */
+ *ainstr = 0xE1A00000 /* base */
+ | (Rd << 16) /* Rn */
+ |(Rd << 12) /* Rd */
+ |(Rs << 0); /* Rm */
+ break;
+ case 0xC: /* BX Rs */
+ case 0xD: /* BX Hs */
+ *ainstr = 0xE12FFF10 /* base */
+ | ((tinstr & 0x0078) >> 3); /* Rd */
+ break;
+ case 0x0: /* UNDEFINED */
+ case 0x4: /* UNDEFINED */
+ case 0x8: /* UNDEFINED */
+ valid = t_undefined;
+ break;
+ case 0xE: /* BLX */
+ case 0xF: /* BLX */
+
+ //if (state->is_v5) {
+ if(1){
+ //valid = t_branch;
+ #if 1
+ *ainstr = 0xE1200030 /* base */
+ |(Rs << 0); /* Rm */
+ #endif
+ } else {
+ valid = t_undefined;
+ }
+ break;
+ }
+ }
+ break;
+ case 9: /* LDR Rd,[PC,#imm8] */
+ /* Format 6 */
+ *ainstr = 0xE59F0000 /* base */
+ | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
+ |((tinstr & 0x00FF) << (2 - 0)); /* off8 */
+ break;
+ case 10:
+ case 11:
+ /* TODO: Format 7 and Format 8 perform the same ARM encoding, so
+ the following could be merged into a single subset, saving on
+ the following boolean: */
+ if ((tinstr & (1 << 9)) == 0) {
+ /* Format 7 */
+ ARMword subset[4] = {
+ 0xE7800000, /* STR Rd,[Rb,Ro] */
+ 0xE7C00000, /* STRB Rd,[Rb,Ro] */
+ 0xE7900000, /* LDR Rd,[Rb,Ro] */
+ 0xE7D00000 /* LDRB Rd,[Rb,Ro] */
+ };
+ *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
+ |((tinstr & 0x0007) << (12 - 0)) /* Rd */
+ |((tinstr & 0x0038) << (16 - 3)) /* Rb */
+ |((tinstr & 0x01C0) >> 6); /* Ro */
+ }
+ else {
+ /* Format 8 */
+ ARMword subset[4] = {
+ 0xE18000B0, /* STRH Rd,[Rb,Ro] */
+ 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */
+ 0xE19000B0, /* LDRH Rd,[Rb,Ro] */
+ 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */
+ };
+ *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
+ |((tinstr & 0x0007) << (12 - 0)) /* Rd */
+ |((tinstr & 0x0038) << (16 - 3)) /* Rb */
+ |((tinstr & 0x01C0) >> 6); /* Ro */
+ }
+ break;
+ case 12: /* STR Rd,[Rb,#imm5] */
+ case 13: /* LDR Rd,[Rb,#imm5] */
+ case 14: /* STRB Rd,[Rb,#imm5] */
+ case 15: /* LDRB Rd,[Rb,#imm5] */
+ /* Format 9 */
+ {
+ ARMword subset[4] = {
+ 0xE5800000, /* STR Rd,[Rb,#imm5] */
+ 0xE5900000, /* LDR Rd,[Rb,#imm5] */
+ 0xE5C00000, /* STRB Rd,[Rb,#imm5] */
+ 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */
+ };
+ /* The offset range defends on whether we are transferring a
+ byte or word value: */
+ *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */
+ |((tinstr & 0x0007) << (12 - 0)) /* Rd */
+ |((tinstr & 0x0038) << (16 - 3)) /* Rb */
+ |((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */
+ }
+ break;
+ case 16: /* STRH Rd,[Rb,#imm5] */
+ case 17: /* LDRH Rd,[Rb,#imm5] */
+ /* Format 10 */
+ *ainstr = ((tinstr & (1 << 11)) /* base */
+ ? 0xE1D000B0 /* LDRH */
+ : 0xE1C000B0) /* STRH */
+ |((tinstr & 0x0007) << (12 - 0)) /* Rd */
+ |((tinstr & 0x0038) << (16 - 3)) /* Rb */
+ |((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */
+ |((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */
+ break;
+ case 18: /* STR Rd,[SP,#imm8] */
+ case 19: /* LDR Rd,[SP,#imm8] */
+ /* Format 11 */
+ *ainstr = ((tinstr & (1 << 11)) /* base */
+ ? 0xE59D0000 /* LDR */
+ : 0xE58D0000) /* STR */
+ |((tinstr & 0x0700) << (12 - 8)) /* Rd */
+ |((tinstr & 0x00FF) << 2); /* off8 */
+ break;
+ case 20: /* ADD Rd,PC,#imm8 */
+ case 21: /* ADD Rd,SP,#imm8 */
+ /* Format 12 */
+ if ((tinstr & (1 << 11)) == 0) {
+ /* NOTE: The PC value used here should by word aligned */
+ /* We encode shift-left-by-2 in the rotate immediate field,
+ so no shift of off8 is needed. */
+ *ainstr = 0xE28F0F00 /* base */
+ | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
+ |(tinstr & 0x00FF); /* off8 */
+ }
+ else {
+ /* We encode shift-left-by-2 in the rotate immediate field,
+ so no shift of off8 is needed. */
+ *ainstr = 0xE28D0F00 /* base */
+ | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
+ |(tinstr & 0x00FF); /* off8 */
+ }
+ break;
+ case 22:
+ case 23:
+ if ((tinstr & 0x0F00) == 0x0000) {
+ /* Format 13 */
+ /* NOTE: The instruction contains a shift left of 2
+ equivalent (implemented as ROR #30): */
+ *ainstr = ((tinstr & (1 << 7)) /* base */
+ ? 0xE24DDF00 /* SUB */
+ : 0xE28DDF00) /* ADD */
+ |(tinstr & 0x007F); /* off7 */
+ }
+ else if ((tinstr & 0x0F00) == 0x0e00)
+ *ainstr = 0xEF000000 | SWI_Breakpoint;
+ else {
+ /* Format 14 */
+ ARMword subset[4] = {
+ 0xE92D0000, /* STMDB sp!,{rlist} */
+ 0xE92D4000, /* STMDB sp!,{rlist,lr} */
+ 0xE8BD0000, /* LDMIA sp!,{rlist} */
+ 0xE8BD8000 /* LDMIA sp!,{rlist,pc} */
+ };
+ *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] /* base */
+ |(tinstr & 0x00FF); /* mask8 */
+ }
+ break;
+ case 24: /* STMIA */
+ case 25: /* LDMIA */
+ /* Format 15 */
+ *ainstr = ((tinstr & (1 << 11)) /* base */
+ ? 0xE8B00000 /* LDMIA */
+ : 0xE8A00000) /* STMIA */
+ |((tinstr & 0x0700) << (16 - 8)) /* Rb */
+ |(tinstr & 0x00FF); /* mask8 */
+ break;
+ case 26: /* Bcc */
+ case 27: /* Bcc/SWI */
+ if ((tinstr & 0x0F00) == 0x0F00) {
+ #if 0
+ if (tinstr == (ARMul_ABORTWORD & 0xffff) &&
+ state->AbortAddr == pc) {
+ *ainstr = ARMul_ABORTWORD;
+ break;
+ }
+ #endif
+ /* Format 17 : SWI */
+ *ainstr = 0xEF000000;
+ /* Breakpoint must be handled specially. */
+ if ((tinstr & 0x00FF) == 0x18)
+ *ainstr |= ((tinstr & 0x00FF) << 16);
+ /* New breakpoint value. See gdb/arm-tdep.c */
+ else if ((tinstr & 0x00FF) == 0xFE)
+ *ainstr |= SWI_Breakpoint;
+ else
+ *ainstr |= (tinstr & 0x00FF);
+ }
+ else if ((tinstr & 0x0F00) != 0x0E00) {
+ /* Format 16 */
+ #if 0
+ int doit = FALSE;
+ /* TODO: Since we are doing a switch here, we could just add
+ the SWI and undefined instruction checks into this
+ switch to same on a couple of conditionals: */
+ switch ((tinstr & 0x0F00) >> 8) {
+ case EQ:
+ doit = ZFLAG;
+ break;
+ case NE:
+ doit = !ZFLAG;
+ break;
+ case VS:
+ doit = VFLAG;
+ break;
+ case VC:
+ doit = !VFLAG;
+ break;
+ case MI:
+ doit = NFLAG;
+ break;
+ case PL:
+ doit = !NFLAG;
+ break;
+ case CS:
+ doit = CFLAG;
+ break;
+ case CC:
+ doit = !CFLAG;
+ break;
+ case HI:
+ doit = (CFLAG && !ZFLAG);
+ break;
+ case LS:
+ doit = (!CFLAG || ZFLAG);
+ break;
+ case GE:
+ doit = ((!NFLAG && !VFLAG)
+ || (NFLAG && VFLAG));
+ break;
+ case LT:
+ doit = ((NFLAG && !VFLAG)
+ || (!NFLAG && VFLAG));
+ break;
+ case GT:
+ doit = ((!NFLAG && !VFLAG && !ZFLAG)
+ || (NFLAG && VFLAG && !ZFLAG));
+ break;
+ case LE:
+ doit = ((NFLAG && !VFLAG)
+ || (!NFLAG && VFLAG)) || ZFLAG;
+ break;
+ }
+ if (doit) {
+ state->Reg[15] = (pc + 4
+ + (((tinstr & 0x7F) << 1)
+ | ((tinstr & (1 << 7)) ?
+ 0xFFFFFF00 : 0)));
+ FLUSHPIPE;
+ }
+ #endif
+ valid = t_branch;
+ }
+ else /* UNDEFINED : cc=1110(AL) uses different format */
+ valid = t_undefined;
+ break;
+ case 28: /* B */
+ /* Format 18 */
+ #if 0
+ state->Reg[15] = (pc + 4 + (((tinstr & 0x3FF) << 1)
+ | ((tinstr & (1 << 10)) ?
+ 0xFFFFF800 : 0)));
+ #endif
+ //FLUSHPIPE;
+ valid = t_branch;
+ break;
+ case 29:
+ if(tinstr & 0x1)
+ valid = t_undefined;
+ else{
+ /* BLX 1 for armv5t and above */
+ //printf("In %s, After BLX(1),LR=0x%x,PC=0x%x, offset=0x%x\n", __FUNCTION__, state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1);
+ valid = t_branch;
+ }
+ break;
+ case 30: /* BL instruction 1 */
+ /* Format 19 */
+ /* There is no single ARM instruction equivalent for this Thumb
+ instruction. To keep the simulation simple (from the user
+ perspective) we check if the following instruction is the
+ second half of this BL, and if it is we simulate it
+ immediately. */
+ valid = t_branch;
+ break;
+ case 31: /* BL instruction 2 */
+ /* Format 19 */
+ /* There is no single ARM instruction equivalent for this
+ instruction. Also, it should only ever be matched with the
+ fmt19 "BL instruction 1" instruction. However, we do allow
+ the simulation of it on its own, with undefined results if
+ r14 is not suitably initialised. */
+ {
+ #if 0
+ ARMword tmp = (pc + 2);
+ state->Reg[15] =
+ (state->Reg[14] + ((tinstr & 0x07FF) << 1));
+ state->Reg[14] = (tmp | 1);
+ #endif
+ valid = t_branch;
+ }
+ break;
+ }
+ *inst_size = 2;
+ return valid;
+}
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h
new file mode 100644
index 000000000..5541de9d1
--- /dev/null
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.h
@@ -0,0 +1,51 @@
+/* Copyright (C)
+* 2011 - Michael.Kang blackfin.kang@gmail.com
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program 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 General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+*/
+
+/**
+* @file arm_dyncom_thumb.h
+* @brief The thumb dyncom
+* @author Michael.Kang blackfin.kang@gmail.com
+* @version 78.77
+* @date 2011-11-07
+*/
+
+#ifndef __ARM_DYNCOM_THUMB_H__
+#define __ARM_DYNCOM_THUMB_H__
+
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/skyeye_types.h"
+
+enum tdstate {
+ t_undefined, // Undefined Thumb instruction
+ t_decoded, // Instruction decoded to ARM equivalent
+ t_branch, // Thumb branch (already processed)
+ t_uninitialized,
+};
+
+tdstate
+thumb_translate(addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size);
+static inline uint32 get_thumb_instr(uint32 instr, addr_t pc){
+ uint32 tinstr;
+ if ((pc & 0x3) != 0)
+ tinstr = instr >> 16;
+ else
+ tinstr = instr & 0xFFFF;
+ return tinstr;
+}
+
+#endif
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index 0842d2f8e..ed4415082 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -4,7 +4,7 @@
#include "core/arm/interpreter/arm_interpreter.h"
-const static cpu_config_t s_arm11_cpu_info = {
+const static cpu_config_t arm11_cpu_info = {
"armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE
};
@@ -17,12 +17,11 @@ ARM_Interpreter::ARM_Interpreter() {
ARMul_NewState(state);
state->abort_model = 0;
- state->cpu = (cpu_config_t*)&s_arm11_cpu_info;
+ state->cpu = (cpu_config_t*)&arm11_cpu_info;
state->bigendSig = LOW;
ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
state->lateabtSig = LOW;
- mmu_init(state);
// Reset the core to initial state
ARMul_CoProInit(state);
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index 1e82883a2..ceb1be438 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -7,10 +7,10 @@
#include "common/common.h"
#include "core/arm/arm_interface.h"
-#include "core/arm/interpreter/armdefs.h"
-#include "core/arm/interpreter/armemu.h"
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armemu.h"
-class ARM_Interpreter : virtual public ARM_Interface {
+class ARM_Interpreter final : virtual public ARM_Interface {
public:
ARM_Interpreter();
@@ -20,60 +20,60 @@ public:
* Set the Program Counter to an address
* @param addr Address to set PC to
*/
- void SetPC(u32 pc);
+ void SetPC(u32 pc) override;
/*
* Get the current Program Counter
* @return Returns current PC
*/
- u32 GetPC() const;
+ u32 GetPC() const override;
/**
* Get an ARM register
* @param index Register index (0-15)
* @return Returns the value in the register
*/
- u32 GetReg(int index) const;
+ u32 GetReg(int index) const override;
/**
* Set an ARM register
* @param index Register index (0-15)
* @param value Value to set register to
*/
- void SetReg(int index, u32 value);
+ void SetReg(int index, u32 value) override;
/**
* Get the current CPSR register
* @return Returns the value of the CPSR register
*/
- u32 GetCPSR() const;
+ u32 GetCPSR() const override;
/**
* Set the current CPSR register
* @param cpsr Value to set CPSR to
*/
- void SetCPSR(u32 cpsr);
+ void SetCPSR(u32 cpsr) override;
/**
* Returns the number of clock ticks since the last reset
* @return Returns number of clock ticks
*/
- u64 GetTicks() const;
+ u64 GetTicks() const override;
/**
* Saves the current CPU context
* @param ctx Thread context to save
*/
- void SaveContext(ThreadContext& ctx);
+ void SaveContext(ThreadContext& ctx) override;
/**
* Loads a CPU context
* @param ctx Thread context to load
*/
- void LoadContext(const ThreadContext& ctx);
+ void LoadContext(const ThreadContext& ctx) override;
/// Prepare core for thread reschedule (if needed to correctly handle state)
- void PrepareReschedule();
+ void PrepareReschedule() override;
protected:
@@ -81,7 +81,7 @@ protected:
* Executes the given number of instructions
* @param num_instructions Number of instructions to executes
*/
- void ExecuteInstructions(int num_instructions);
+ void ExecuteInstructions(int num_instructions) override;
private:
diff --git a/src/core/arm/interpreter/armcopro.cpp b/src/core/arm/interpreter/armcopro.cpp
index 6a75e6601..b4ddc3d96 100644
--- a/src/core/arm/interpreter/armcopro.cpp
+++ b/src/core/arm/interpreter/armcopro.cpp
@@ -15,828 +15,311 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "core/arm/interpreter/armdefs.h"
-#include "core/arm/interpreter/armos.h"
-#include "core/arm/interpreter/armemu.h"
-#include "core/arm/interpreter/vfp/vfp.h"
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armemu.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
//chy 2005-07-08
//#include "ansidecl.h"
//chy -------
//#include "iwmmxt.h"
-
-//chy 2005-09-19 add CP6 MRC support (for get irq number and base)
-extern unsigned xscale_cp6_mrc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword * data);
-//chy 2005-09-19---------------
-
-extern unsigned xscale_cp13_init (ARMul_State * state);
-extern unsigned xscale_cp13_exit (ARMul_State * state);
-extern unsigned xscale_cp13_ldc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword data);
-extern unsigned xscale_cp13_stc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword * data);
-extern unsigned xscale_cp13_mrc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword * data);
-extern unsigned xscale_cp13_mcr (ARMul_State * state, unsigned type,
- ARMword instr, ARMword data);
-extern unsigned xscale_cp13_cdp (ARMul_State * state, unsigned type,
- ARMword instr);
-extern unsigned xscale_cp13_read_reg (ARMul_State * state, unsigned reg,
- ARMword * data);
-extern unsigned xscale_cp13_write_reg (ARMul_State * state, unsigned reg,
- ARMword data);
-extern unsigned xscale_cp14_init (ARMul_State * state);
-extern unsigned xscale_cp14_exit (ARMul_State * state);
-extern unsigned xscale_cp14_ldc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword data);
-extern unsigned xscale_cp14_stc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword * data);
-extern unsigned xscale_cp14_mrc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword * data);
-extern unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type,
- ARMword instr, ARMword data);
-extern unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type,
- ARMword instr);
-extern unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg,
- ARMword * data);
-extern unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg,
- ARMword data);
-extern unsigned xscale_cp15_init (ARMul_State * state);
-extern unsigned xscale_cp15_exit (ARMul_State * state);
-extern unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword data);
-extern unsigned xscale_cp15_stc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword * data);
-extern unsigned xscale_cp15_mrc (ARMul_State * state, unsigned type,
- ARMword instr, ARMword * data);
-extern unsigned xscale_cp15_mcr (ARMul_State * state, unsigned type,
- ARMword instr, ARMword data);
-extern unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type,
- ARMword instr);
-extern unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg,
- ARMword * data);
-extern unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg,
- ARMword data);
-extern unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
- unsigned cpnum);
-
/* Dummy Co-processors. */
static unsigned
-NoCoPro3R (ARMul_State * state,
- unsigned a, ARMword b)
+NoCoPro3R(ARMul_State * state,
+unsigned a, ARMword b)
{
- return ARMul_CANT;
+ return ARMul_CANT;
}
static unsigned
-NoCoPro4R (ARMul_State * state,
- unsigned a,
- ARMword b, ARMword c)
+NoCoPro4R(ARMul_State * state,
+unsigned a,
+ARMword b, ARMword c)
{
- return ARMul_CANT;
+ return ARMul_CANT;
}
static unsigned
-NoCoPro4W (ARMul_State * state,
- unsigned a,
- ARMword b, ARMword * c)
+NoCoPro4W(ARMul_State * state,
+unsigned a,
+ARMword b, ARMword * c)
{
- return ARMul_CANT;
+ return ARMul_CANT;
}
static unsigned
-NoCoPro5R (ARMul_State * state,
- unsigned a,
- ARMword b,
- ARMword c, ARMword d)
+NoCoPro5R(ARMul_State * state,
+unsigned a,
+ARMword b,
+ARMword c, ARMword d)
{
- return ARMul_CANT;
+ return ARMul_CANT;
}
static unsigned
-NoCoPro5W (ARMul_State * state,
- unsigned a,
- ARMword b,
- ARMword * c, ARMword * d )
+NoCoPro5W(ARMul_State * state,
+unsigned a,
+ARMword b,
+ARMword * c, ARMword * d)
{
- return ARMul_CANT;
+ return ARMul_CANT;
}
/* The XScale Co-processors. */
/* Coprocessor 15: System Control. */
-static void write_cp14_reg (unsigned, ARMword);
-static ARMword read_cp14_reg (unsigned);
-
-/* There are two sets of registers for copro 15.
- One set is available when opcode_2 is 0 and
- the other set when opcode_2 >= 1. */
-static ARMword XScale_cp15_opcode_2_is_0_Regs[16];
-static ARMword XScale_cp15_opcode_2_is_not_0_Regs[16];
-/* There are also a set of breakpoint registers
- which are accessed via CRm instead of opcode_2. */
-static ARMword XScale_cp15_DBR1;
-static ARMword XScale_cp15_DBCON;
-static ARMword XScale_cp15_IBCR0;
-static ARMword XScale_cp15_IBCR1;
-
-static unsigned
-XScale_cp15_init (ARMul_State * state)
-{
- int i;
-
- for (i = 16; i--;) {
- XScale_cp15_opcode_2_is_0_Regs[i] = 0;
- XScale_cp15_opcode_2_is_not_0_Regs[i] = 0;
- }
-
- /* Initialise the processor ID. */
- //chy 2003-03-24, is same as cpu id in skyeye_options.c
- //XScale_cp15_opcode_2_is_0_Regs[0] = 0x69052000;
- XScale_cp15_opcode_2_is_0_Regs[0] = 0x69050000;
-
- /* Initialise the cache type. */
- XScale_cp15_opcode_2_is_not_0_Regs[0] = 0x0B1AA1AA;
-
- /* Initialise the ARM Control Register. */
- XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078;
-
- return No_exp;
-}
-
-/* Check an access to a register. */
-
-static unsigned
-check_cp15_access (ARMul_State * state,
- unsigned reg,
- unsigned CRm, unsigned opcode_1, unsigned opcode_2)
-{
- /* Do not allow access to these register in USER mode. */
- //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
- if (state->Mode == USER26MODE || state->Mode == USER32MODE )
- return ARMul_CANT;
-
- /* Opcode_1should be zero. */
- if (opcode_1 != 0)
- return ARMul_CANT;
-
- /* Different register have different access requirements. */
- switch (reg) {
- case 0:
- case 1:
- /* CRm must be 0. Opcode_2 can be anything. */
- if (CRm != 0)
- return ARMul_CANT;
- break;
- case 2:
- case 3:
- /* CRm must be 0. Opcode_2 must be zero. */
- if ((CRm != 0) || (opcode_2 != 0))
- return ARMul_CANT;
- break;
- case 4:
- /* Access not allowed. */
- return ARMul_CANT;
- case 5:
- case 6:
- /* Opcode_2 must be zero. CRm must be 0. */
- if ((CRm != 0) || (opcode_2 != 0))
- return ARMul_CANT;
- break;
- case 7:
- /* Permissable combinations:
- Opcode_2 CRm
- 0 5
- 0 6
- 0 7
- 1 5
- 1 6
- 1 10
- 4 10
- 5 2
- 6 5 */
- switch (opcode_2) {
- default:
- return ARMul_CANT;
- case 6:
- if (CRm != 5)
- return ARMul_CANT;
- break;
- case 5:
- if (CRm != 2)
- return ARMul_CANT;
- break;
- case 4:
- if (CRm != 10)
- return ARMul_CANT;
- break;
- case 1:
- if ((CRm != 5) && (CRm != 6) && (CRm != 10))
- return ARMul_CANT;
- break;
- case 0:
- if ((CRm < 5) || (CRm > 7))
- return ARMul_CANT;
- break;
- }
- break;
-
- case 8:
- /* Permissable combinations:
- Opcode_2 CRm
- 0 5
- 0 6
- 0 7
- 1 5
- 1 6 */
- if (opcode_2 > 1)
- return ARMul_CANT;
- if ((CRm < 5) || (CRm > 7))
- return ARMul_CANT;
- if (opcode_2 == 1 && CRm == 7)
- return ARMul_CANT;
- break;
- case 9:
- /* Opcode_2 must be zero or one. CRm must be 1 or 2. */
- if (((CRm != 0) && (CRm != 1))
- || ((opcode_2 != 1) && (opcode_2 != 2)))
- return ARMul_CANT;
- break;
- case 10:
- /* Opcode_2 must be zero or one. CRm must be 4 or 8. */
- if (((CRm != 0) && (CRm != 1))
- || ((opcode_2 != 4) && (opcode_2 != 8)))
- return ARMul_CANT;
- break;
- case 11:
- /* Access not allowed. */
- return ARMul_CANT;
- case 12:
- /* Access not allowed. */
- return ARMul_CANT;
- case 13:
- /* Opcode_2 must be zero. CRm must be 0. */
- if ((CRm != 0) || (opcode_2 != 0))
- return ARMul_CANT;
- break;
- case 14:
- /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */
- if (opcode_2 != 0)
- return ARMul_CANT;
-
- if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8)
- && (CRm != 9))
- return ARMul_CANT;
- break;
- case 15:
- /* Opcode_2 must be zero. CRm must be 1. */
- if ((CRm != 1) || (opcode_2 != 0))
- return ARMul_CANT;
- break;
- default:
- /* Should never happen. */
- return ARMul_CANT;
- }
-
- return ARMul_DONE;
-}
-
-/* Coprocessor 13: Interrupt Controller and Bus Controller. */
-
-/* There are two sets of registers for copro 13.
- One set (of three registers) is available when CRm is 0
- and the other set (of six registers) when CRm is 1. */
-
-static ARMword XScale_cp13_CR0_Regs[16];
-static ARMword XScale_cp13_CR1_Regs[16];
-
-static unsigned
-XScale_cp13_init (ARMul_State * state)
-{
- int i;
-
- for (i = 16; i--;) {
- XScale_cp13_CR0_Regs[i] = 0;
- XScale_cp13_CR1_Regs[i] = 0;
- }
-
- return No_exp;
-}
-
-/* Check an access to a register. */
-
-static unsigned
-check_cp13_access (ARMul_State * state,
- unsigned reg,
- unsigned CRm, unsigned opcode_1, unsigned opcode_2)
-{
- /* Do not allow access to these registers in USER mode. */
- //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
- if (state->Mode == USER26MODE || state->Mode == USER32MODE )
- return ARMul_CANT;
-
- /* The opcodes should be zero. */
- if ((opcode_1 != 0) || (opcode_2 != 0))
- return ARMul_CANT;
-
- /* Do not allow access to these register if bit
- 13 of coprocessor 15's register 15 is zero. */
- if (!CP_ACCESS_ALLOWED (state, 13))
- return ARMul_CANT;
-
- /* Registers 0, 4 and 8 are defined when CRm == 0.
- Registers 0, 1, 4, 5, 6, 7, 8 are defined when CRm == 1.
- For all other CRm values undefined behaviour results. */
- if (CRm == 0) {
- if (reg == 0 || reg == 4 || reg == 8)
- return ARMul_DONE;
- }
- else if (CRm == 1) {
- if (reg == 0 || reg == 1 || (reg >= 4 && reg <= 8))
- return ARMul_DONE;
- }
-
- return ARMul_CANT;
-}
-
-/* Coprocessor 14: Performance Monitoring, Clock and Power management,
- Software Debug. */
-
-static ARMword XScale_cp14_Regs[16];
-
-static unsigned
-XScale_cp14_init (ARMul_State * state)
-{
- int i;
-
- for (i = 16; i--;)
- XScale_cp14_Regs[i] = 0;
-
- return No_exp;
-}
+static void write_cp14_reg(unsigned, ARMword);
+static ARMword read_cp14_reg(unsigned);
/* Check an access to a register. */
static unsigned
-check_cp14_access (ARMul_State * state,
- unsigned reg,
- unsigned CRm, unsigned opcode1, unsigned opcode2)
-{
- /* Not allowed to access these register in USER mode. */
- //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
- if (state->Mode == USER26MODE || state->Mode == USER32MODE )
- return ARMul_CANT;
-
- /* CRm should be zero. */
- if (CRm != 0)
- return ARMul_CANT;
-
- /* OPcodes should be zero. */
- if (opcode1 != 0 || opcode2 != 0)
- return ARMul_CANT;
-
- /* Accessing registers 4 or 5 has unpredicatable results. */
- if (reg >= 4 && reg <= 5)
- return ARMul_CANT;
-
- return ARMul_DONE;
-}
-
-/* Here's ARMulator's MMU definition. A few things to note:
- 1) It has eight registers, but only two are defined.
- 2) You can only access its registers with MCR and MRC.
- 3) MMU Register 0 (ID) returns 0x41440110
- 4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4
- controls 32/26 bit program space, bit 5 controls 32/26 bit data space,
- bit 6 controls late abort timimg and bit 7 controls big/little endian. */
-
-static ARMword MMUReg[8];
-
-static unsigned
-MMUInit (ARMul_State * state)
-{
-/* 2004-05-09 chy
--------------------------------------------------------------
-read ARM Architecture Reference Manual
-2.6.5 Data Abort
-There are three Abort Model in ARM arch.
-
-Early Abort Model: used in some ARMv3 and earlier implementations. In this
-model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and
-the base register was unchanged for all other instructions. (oldest)
-
-Base Restored Abort Model: If a Data Abort occurs in an instruction which
-specifies base register writeback, the value in the base register is
-unchanged. (strongarm, xscale)
-
-Base Updated Abort Model: If a Data Abort occurs in an instruction which
-specifies base register writeback, the base register writeback still occurs.
-(arm720T)
-
-read PART B
-chap2 The System Control Coprocessor CP15
-2.4 Register1:control register
-L(bit 6): in some ARMv3 and earlier implementations, the abort model of the
-processor could be configured:
-0=early Abort Model Selected(now obsolete)
-1=Late Abort Model selceted(same as Base Updated Abort Model)
-
-on later processors, this bit reads as 1 and ignores writes.
--------------------------------------------------------------
-So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
- if lateabtSig=0, then it means Base Restored Abort Model
-because the ARMs which skyeye simulates are all belonged to ARMv4,
-so I think MMUReg[1]'s bit 6 should always be 1
-
-*/
-
- MMUReg[1] = state->prog32Sig << 4 |
- state->data32Sig << 5 | 1 << 6 | state->bigendSig << 7;
- //state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7;
-
-
- NOTICE_LOG(ARM11, "ARMul_ConsolePrint: MMU present");
-
- return TRUE;
-}
-
-static unsigned
-MMUMRC (ARMul_State * state, unsigned type,
- ARMword instr, ARMword * value)
-{
- mmu_mrc (state, instr, value);
- return (ARMul_DONE);
-}
-
-static unsigned
-MMUMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
-{
- mmu_mcr (state, instr, value);
- return (ARMul_DONE);
-}
-
-/* What follows is the Validation Suite Coprocessor. It uses two
- co-processor numbers (4 and 5) and has the follwing functionality.
- Sixteen registers. Both co-processor nuimbers can be used in an MCR
- and MRC to access these registers. CP 4 can LDC and STC to and from
- the registers. CP 4 and CP 5 CDP 0 will busy wait for the number of
- cycles specified by a CP register. CP 5 CDP 1 issues a FIQ after a
- number of cycles (specified in a CP register), CDP 2 issues an IRQW
- in the same way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5
- stores a 32 bit time value in a CP register (actually it's the total
- number of N, S, I, C and F cyles). */
-
-static ARMword ValReg[16];
-
-static unsigned
-ValLDC (ARMul_State * state,
- unsigned type, ARMword instr, ARMword data)
-{
- static unsigned words;
-
- if (type != ARMul_DATA)
- words = 0;
- else {
- ValReg[BITS (12, 15)] = data;
-
- if (BIT (22))
- /* It's a long access, get two words. */
- if (words++ != 4)
- return ARMul_INC;
- }
-
- return ARMul_DONE;
-}
-
-static unsigned
-ValSTC (ARMul_State * state,
- unsigned type, ARMword instr, ARMword * data)
-{
- static unsigned words;
-
- if (type != ARMul_DATA)
- words = 0;
- else {
- *data = ValReg[BITS (12, 15)];
-
- if (BIT (22))
- /* It's a long access, get two words. */
- if (words++ != 4)
- return ARMul_INC;
- }
-
- return ARMul_DONE;
-}
-
-static unsigned
-ValMRC (ARMul_State * state,
- unsigned type, ARMword instr, ARMword * value)
-{
- *value = ValReg[BITS (16, 19)];
-
- return ARMul_DONE;
-}
-
-static unsigned
-ValMCR (ARMul_State * state,
- unsigned type, ARMword instr, ARMword value)
-{
- ValReg[BITS (16, 19)] = value;
-
- return ARMul_DONE;
-}
-
-static unsigned
-ValCDP (ARMul_State * state, unsigned type, ARMword instr)
-{
- static unsigned int finish = 0;
-
- if (BITS (20, 23) != 0)
- return ARMul_CANT;
-
- if (type == ARMul_FIRST) {
- ARMword howlong;
-
- howlong = ValReg[BITS (0, 3)];
-
- /* First cycle of a busy wait. */
- finish = ARMul_Time (state) + howlong;
-
- return howlong == 0 ? ARMul_DONE : ARMul_BUSY;
- }
- else if (type == ARMul_BUSY) {
- if (ARMul_Time (state) >= finish)
- return ARMul_DONE;
- else
- return ARMul_BUSY;
- }
-
- return ARMul_CANT;
-}
-
-static unsigned
-DoAFIQ (ARMul_State * state)
-{
- state->NfiqSig = LOW;
- return 0;
-}
-
-static unsigned
-DoAIRQ (ARMul_State * state)
-{
- state->NirqSig = LOW;
- return 0;
-}
-
-static unsigned
-IntCDP (ARMul_State * state, unsigned type, ARMword instr)
+check_cp15_access(ARMul_State * state,
+unsigned reg,
+unsigned CRm, unsigned opcode_1, unsigned opcode_2)
{
- static unsigned int finish;
- ARMword howlong;
-
- howlong = ValReg[BITS (0, 3)];
-
- switch ((int) BITS (20, 23)) {
- case 0:
- if (type == ARMul_FIRST) {
- /* First cycle of a busy wait. */
- finish = ARMul_Time (state) + howlong;
-
- return howlong == 0 ? ARMul_DONE : ARMul_BUSY;
- }
- else if (type == ARMul_BUSY) {
- if (ARMul_Time (state) >= finish)
- return ARMul_DONE;
- else
- return ARMul_BUSY;
- }
- return ARMul_DONE;
-
- case 1:
- if (howlong == 0)
- ARMul_Abort (state, ARMul_FIQV);
- else
- ARMul_ScheduleEvent (state, howlong, DoAFIQ);
- return ARMul_DONE;
-
- case 2:
- if (howlong == 0)
- ARMul_Abort (state, ARMul_IRQV);
- else
- ARMul_ScheduleEvent (state, howlong, DoAIRQ);
- return ARMul_DONE;
-
- case 3:
- state->NfiqSig = HIGH;
- return ARMul_DONE;
-
- case 4:
- state->NirqSig = HIGH;
- return ARMul_DONE;
-
- case 5:
- ValReg[BITS (0, 3)] = ARMul_Time (state);
- return ARMul_DONE;
- }
-
- return ARMul_CANT;
+ /* Do not allow access to these register in USER mode. */
+ //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
+ if (state->Mode == USER26MODE || state->Mode == USER32MODE)
+ return ARMul_CANT;
+
+ /* Opcode_1should be zero. */
+ if (opcode_1 != 0)
+ return ARMul_CANT;
+
+ /* Different register have different access requirements. */
+ switch (reg) {
+ case 0:
+ case 1:
+ /* CRm must be 0. Opcode_2 can be anything. */
+ if (CRm != 0)
+ return ARMul_CANT;
+ break;
+ case 2:
+ case 3:
+ /* CRm must be 0. Opcode_2 must be zero. */
+ if ((CRm != 0) || (opcode_2 != 0))
+ return ARMul_CANT;
+ break;
+ case 4:
+ /* Access not allowed. */
+ return ARMul_CANT;
+ case 5:
+ case 6:
+ /* Opcode_2 must be zero. CRm must be 0. */
+ if ((CRm != 0) || (opcode_2 != 0))
+ return ARMul_CANT;
+ break;
+ case 7:
+ /* Permissable combinations:
+ Opcode_2 CRm
+ 0 5
+ 0 6
+ 0 7
+ 1 5
+ 1 6
+ 1 10
+ 4 10
+ 5 2
+ 6 5 */
+ switch (opcode_2) {
+ default:
+ return ARMul_CANT;
+ case 6:
+ if (CRm != 5)
+ return ARMul_CANT;
+ break;
+ case 5:
+ if (CRm != 2)
+ return ARMul_CANT;
+ break;
+ case 4:
+ if (CRm != 10)
+ return ARMul_CANT;
+ break;
+ case 1:
+ if ((CRm != 5) && (CRm != 6) && (CRm != 10))
+ return ARMul_CANT;
+ break;
+ case 0:
+ if ((CRm < 5) || (CRm > 7))
+ return ARMul_CANT;
+ break;
+ }
+ break;
+
+ case 8:
+ /* Permissable combinations:
+ Opcode_2 CRm
+ 0 5
+ 0 6
+ 0 7
+ 1 5
+ 1 6 */
+ if (opcode_2 > 1)
+ return ARMul_CANT;
+ if ((CRm < 5) || (CRm > 7))
+ return ARMul_CANT;
+ if (opcode_2 == 1 && CRm == 7)
+ return ARMul_CANT;
+ break;
+ case 9:
+ /* Opcode_2 must be zero or one. CRm must be 1 or 2. */
+ if (((CRm != 0) && (CRm != 1))
+ || ((opcode_2 != 1) && (opcode_2 != 2)))
+ return ARMul_CANT;
+ break;
+ case 10:
+ /* Opcode_2 must be zero or one. CRm must be 4 or 8. */
+ if (((CRm != 0) && (CRm != 1))
+ || ((opcode_2 != 4) && (opcode_2 != 8)))
+ return ARMul_CANT;
+ break;
+ case 11:
+ /* Access not allowed. */
+ return ARMul_CANT;
+ case 12:
+ /* Access not allowed. */
+ return ARMul_CANT;
+ case 13:
+ /* Opcode_2 must be zero. CRm must be 0. */
+ if ((CRm != 0) || (opcode_2 != 0))
+ return ARMul_CANT;
+ break;
+ case 14:
+ /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */
+ if (opcode_2 != 0)
+ return ARMul_CANT;
+
+ if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8)
+ && (CRm != 9))
+ return ARMul_CANT;
+ break;
+ case 15:
+ /* Opcode_2 must be zero. CRm must be 1. */
+ if ((CRm != 1) || (opcode_2 != 0))
+ return ARMul_CANT;
+ break;
+ default:
+ /* Should never happen. */
+ return ARMul_CANT;
+ }
+
+ return ARMul_DONE;
}
/* Install co-processor instruction handlers in this routine. */
unsigned
-ARMul_CoProInit (ARMul_State * state)
+ARMul_CoProInit(ARMul_State * state)
{
- unsigned int i;
-
- /* Initialise tham all first. */
- for (i = 0; i < 16; i++)
- ARMul_CoProDetach (state, i);
-
- /* Install CoPro Instruction handlers here.
- The format is:
- ARMul_CoProAttach (state, CP Number, Init routine, Exit routine
- LDC routine, STC routine, MRC routine, MCR routine,
- CDP routine, Read Reg routine, Write Reg routine). */
- if (state->is_ep9312) {
- ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4,
- DSPMRC4, DSPMCR4, NULL, NULL, DSPCDP4, NULL, NULL);
- ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5,
- DSPMRC5, DSPMCR5, NULL, NULL, DSPCDP5, NULL, NULL);
- ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL,
- DSPMRC6, DSPMCR6, NULL, NULL, DSPCDP6, NULL, NULL);
- }
- else {
- ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC,
- ValMRC, ValMCR, NULL, NULL, ValCDP, NULL, NULL);
-
- ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL,
- ValMRC, ValMCR, NULL, NULL, IntCDP, NULL, NULL);
- }
-
- if (state->is_XScale) {
- //chy 2005-09-19, for PXA27x's CP6
- if (state->is_pxa27x) {
- ARMul_CoProAttach (state, 6, NULL, NULL,
- NULL, NULL, xscale_cp6_mrc,
- NULL, NULL, NULL, NULL, NULL, NULL);
- }
- //chy 2005-09-19 end-------------
- ARMul_CoProAttach (state, 13, xscale_cp13_init,
- xscale_cp13_exit, xscale_cp13_ldc,
- xscale_cp13_stc, xscale_cp13_mrc,
- xscale_cp13_mcr, NULL, NULL, xscale_cp13_cdp,
- xscale_cp13_read_reg,
- xscale_cp13_write_reg);
-
- ARMul_CoProAttach (state, 14, xscale_cp14_init,
- xscale_cp14_exit, xscale_cp14_ldc,
- xscale_cp14_stc, xscale_cp14_mrc,
- xscale_cp14_mcr, NULL, NULL, xscale_cp14_cdp,
- xscale_cp14_read_reg,
- xscale_cp14_write_reg);
- //chy: 2003-08-24.
- ARMul_CoProAttach (state, 15, xscale_cp15_init,
- xscale_cp15_exit, xscale_cp15_ldc,
- xscale_cp15_stc, xscale_cp15_mrc,
- xscale_cp15_mcr, NULL, NULL, xscale_cp15_cdp,
- xscale_cp15_read_reg,
- xscale_cp15_write_reg);
- }
- else if (state->is_v6) {
- ARMul_CoProAttach (state, 10, VFPInit, NULL, VFPLDC, VFPSTC,
- VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
- ARMul_CoProAttach (state, 11, VFPInit, NULL, VFPLDC, VFPSTC,
- VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
-
- ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
- MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);
- }
- else { //all except xscale
- ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
- // MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
- MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);
- }
-//chy 2003-09-03 do it in future!!!!????
+ unsigned int i;
+
+ /* Initialise tham all first. */
+ for (i = 0; i < 16; i++)
+ ARMul_CoProDetach(state, i);
+
+ /* Install CoPro Instruction handlers here.
+ The format is:
+ ARMul_CoProAttach (state, CP Number, Init routine, Exit routine
+ LDC routine, STC routine, MRC routine, MCR routine,
+ CDP routine, Read Reg routine, Write Reg routine). */
+ if (state->is_v6) {
+ ARMul_CoProAttach(state, 10, VFPInit, NULL, VFPLDC, VFPSTC,
+ VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
+ ARMul_CoProAttach(state, 11, VFPInit, NULL, VFPLDC, VFPSTC,
+ VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
+
+ /*ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
+ MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);*/
+ }
+ //chy 2003-09-03 do it in future!!!!????
#if 0
- if (state->is_iWMMXt) {
- ARMul_CoProAttach (state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC,
- NULL, NULL, IwmmxtCDP, NULL, NULL);
-
- ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL,
- IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL,
- NULL);
- }
+ if (state->is_iWMMXt) {
+ ARMul_CoProAttach(state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC,
+ NULL, NULL, IwmmxtCDP, NULL, NULL);
+
+ ARMul_CoProAttach(state, 1, NULL, NULL, NULL, NULL,
+ IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL,
+ NULL);
+ }
#endif
- //-----------------------------------------------------------------------------
- //chy 2004-05-25, found the user/system code visit CP 1,2, so I add below code.
- ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL,
- ValMRC, ValMCR, NULL, NULL, NULL, NULL, NULL);
- ARMul_CoProAttach (state, 2, NULL, NULL, ValLDC, ValSTC,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL);
- //------------------------------------------------------------------------------
- /* No handlers below here. */
-
- /* Call all the initialisation routines. */
- for (i = 0; i < 16; i++)
- if (state->CPInit[i])
- (state->CPInit[i]) (state);
-
- return TRUE;
+ /* No handlers below here. */
+
+ /* Call all the initialisation routines. */
+ for (i = 0; i < 16; i++)
+ if (state->CPInit[i])
+ (state->CPInit[i]) (state);
+
+ return TRUE;
}
/* Install co-processor finalisation routines in this routine. */
void
-ARMul_CoProExit (ARMul_State * state)
+ARMul_CoProExit(ARMul_State * state)
{
- register unsigned i;
+ register unsigned i;
- for (i = 0; i < 16; i++)
- if (state->CPExit[i])
- (state->CPExit[i]) (state);
+ for (i = 0; i < 16; i++)
+ if (state->CPExit[i])
+ (state->CPExit[i]) (state);
- for (i = 0; i < 16; i++) /* Detach all handlers. */
- ARMul_CoProDetach (state, i);
+ for (i = 0; i < 16; i++) /* Detach all handlers. */
+ ARMul_CoProDetach(state, i);
}
/* Routines to hook Co-processors into ARMulator. */
void
-ARMul_CoProAttach (ARMul_State * state,
- unsigned number,
- ARMul_CPInits * init,
- ARMul_CPExits * exit,
- ARMul_LDCs * ldc,
- ARMul_STCs * stc,
- ARMul_MRCs * mrc,
- ARMul_MCRs * mcr,
- ARMul_MRRCs * mrrc,
- ARMul_MCRRs * mcrr,
- ARMul_CDPs * cdp,
- ARMul_CPReads * read, ARMul_CPWrites * write)
-{
- if (init != NULL)
- state->CPInit[number] = init;
- if (exit != NULL)
- state->CPExit[number] = exit;
- if (ldc != NULL)
- state->LDC[number] = ldc;
- if (stc != NULL)
- state->STC[number] = stc;
- if (mrc != NULL)
- state->MRC[number] = mrc;
- if (mcr != NULL)
- state->MCR[number] = mcr;
- if (mrrc != NULL)
- state->MRRC[number] = mrrc;
- if (mcrr != NULL)
- state->MCRR[number] = mcrr;
- if (cdp != NULL)
- state->CDP[number] = cdp;
- if (read != NULL)
- state->CPRead[number] = read;
- if (write != NULL)
- state->CPWrite[number] = write;
-}
-
-void
-ARMul_CoProDetach (ARMul_State * state, unsigned number)
+ARMul_CoProAttach(ARMul_State * state,
+unsigned number,
+ARMul_CPInits * init,
+ARMul_CPExits * exit,
+ARMul_LDCs * ldc,
+ARMul_STCs * stc,
+ARMul_MRCs * mrc,
+ARMul_MCRs * mcr,
+ARMul_MRRCs * mrrc,
+ARMul_MCRRs * mcrr,
+ARMul_CDPs * cdp,
+ARMul_CPReads * read, ARMul_CPWrites * write)
{
- ARMul_CoProAttach (state, number, NULL, NULL,
- NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R,
- NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL);
-
- state->CPInit[number] = NULL;
- state->CPExit[number] = NULL;
- state->CPRead[number] = NULL;
- state->CPWrite[number] = NULL;
+ if (init != NULL)
+ state->CPInit[number] = init;
+ if (exit != NULL)
+ state->CPExit[number] = exit;
+ if (ldc != NULL)
+ state->LDC[number] = ldc;
+ if (stc != NULL)
+ state->STC[number] = stc;
+ if (mrc != NULL)
+ state->MRC[number] = mrc;
+ if (mcr != NULL)
+ state->MCR[number] = mcr;
+ if (mrrc != NULL)
+ state->MRRC[number] = mrrc;
+ if (mcrr != NULL)
+ state->MCRR[number] = mcrr;
+ if (cdp != NULL)
+ state->CDP[number] = cdp;
+ if (read != NULL)
+ state->CPRead[number] = read;
+ if (write != NULL)
+ state->CPWrite[number] = write;
}
-//chy 2003-09-03:below funs just replace the old ones
-
-/* Set the XScale FSR and FAR registers. */
-
void
-XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far)
-{
- //if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0)
- if (!state->is_XScale)
- return;
- //assume opcode2=0 crm =0
- xscale_cp15_write_reg (state, 5, fsr);
- xscale_cp15_write_reg (state, 6, _far);
-}
-
-//chy 2003-09-03 seems 0 is CANT, 1 is DONE ????
-int
-XScale_debug_moe (ARMul_State * state, int moe)
+ARMul_CoProDetach(ARMul_State * state, unsigned number)
{
- //chy 2003-09-03 , W/R CP14 reg, now it's no use ????
- printf ("SKYEYE: XScale_debug_moe called !!!!\n");
- return 1;
+ ARMul_CoProAttach(state, number, NULL, NULL,
+ NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R,
+ NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL);
+
+ state->CPInit[number] = NULL;
+ state->CPExit[number] = NULL;
+ state->CPRead[number] = NULL;
+ state->CPWrite[number] = NULL;
}
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index f9130ef88..73223874e 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -18,9 +18,9 @@
//#include <util.h> // DEBUG()
-#include "arm_regformat.h"
-#include "armdefs.h"
-#include "armemu.h"
+#include "core/arm/skyeye_common/arm_regformat.h"
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armemu.h"
#include "core/hle/hle.h"
//#include "svc.h"
@@ -28,9 +28,6 @@
//ichfly
//#define callstacker 1
-
-//#include "armos.h"
-
//#include "skyeye_callback.h"
//#include "skyeye_bus.h"
//#include "sim_control.h"
@@ -66,13 +63,6 @@ static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int);
static void Handle_Load_Double (ARMul_State *, ARMword);
static void Handle_Store_Double (ARMul_State *, ARMword);
-void
-XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far);
-int
-XScale_debug_moe (ARMul_State * state, int moe);
-unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
- unsigned cpnum);
-
static int
handle_v6_insn (ARMul_State * state, ARMword instr);
@@ -379,7 +369,7 @@ ARMul_Emulate26 (ARMul_State * state)
#endif
{
/* The PC pipeline value depends on whether ARM
- or Thumb instructions are being
+ or Thumb instructions are being
d. */
ARMword isize;
ARMword instr; /* The current instruction. */
@@ -541,6 +531,7 @@ ARMul_Emulate26 (ARMul_State * state)
state->AbortAddr = 1;
instr = ARMul_LoadInstrN (state, pc, isize);
+
//chy 2006-04-12, for ICE debug
have_bp=ARMul_ICE_debug(state,instr,pc);
#if 0
@@ -565,6 +556,7 @@ ARMul_Emulate26 (ARMul_State * state)
}
printf("\n");
#endif
+
instr = ARMul_LoadInstrN (state, pc, isize);
state->last_instr = state->CurrInstr;
state->CurrInstr = instr;
@@ -955,9 +947,8 @@ ARMul_Emulate26 (ARMul_State * state)
case t_decoded:
/* ARM instruction available. */
//printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp);
-
- if (armOp == 0xDEADC0DE)
- {
+
+ if (armOp == 0xDEADC0DE) {
DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc);
}
@@ -970,7 +961,6 @@ ARMul_Emulate26 (ARMul_State * state)
}
}
#endif
-
/* Check the condition codes. */
if ((temp = TOPBITS (28)) == AL) {
/* Vile deed in the need for speed. */
@@ -1127,6 +1117,7 @@ ARMul_Emulate26 (ARMul_State * state)
//chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it...
+
/* Actual execution of instructions begins here. */
/* If the condition codes don't match, stop here. */
if (temp) {
@@ -2311,12 +2302,9 @@ mainswitch:
if (state->Aborted) {
TAKEABORT;
}
- if (enter)
- {
+ if (enter) {
state->Reg[DESTReg] = 0;
- }
- else
- {
+ } else {
state->Reg[DESTReg] = 1;
}
break;
@@ -3066,7 +3054,27 @@ mainswitch:
break;
case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */
- if (BIT (4)) {
+ //ichfly PKHBT PKHTB todo check this
+ if ((instr & 0x70) == 0x10) //pkhbt
+ {
+ u8 idest = BITS(12, 15);
+ u8 rfis = BITS(16, 19);
+ u8 rlast = BITS(0, 3);
+ u8 ishi = BITS(7,11);
+ state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000);
+ break;
+ }
+ else if ((instr & 0x70) == 0x50)//pkhtb
+ {
+ u8 idest = BITS(12, 15);
+ u8 rfis = BITS(16, 19);
+ u8 rlast = BITS(0, 3);
+ u8 ishi = BITS(7, 11);
+ if (ishi == 0)ishi = 0x20;
+ state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000);
+ break;
+ }
+ else if (BIT (4)) {
#ifdef MODE32
if (state->is_v6
&& handle_v6_insn (state, instr))
@@ -3678,7 +3686,13 @@ mainswitch:
/* Co-Processor Data Transfers. */
case 0xc4:
- if (state->is_v5) {
+ if ((instr & 0x0FF00FF0) == 0xC400B10) //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0
+ {
+ state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)];
+ state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)];
+ break;
+ }
+ else if (state->is_v5) {
/* Reading from R15 is UNPREDICTABLE. */
if (BITS (12, 15) == 15 || BITS (16, 19) == 15)
ARMul_UndefInstr (state, instr);
@@ -3698,13 +3712,21 @@ mainswitch:
break;
case 0xc5:
- if (state->is_v5) {
+ if ((instr & 0x00000FF0) == 0xB10) //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0
+ {
+ state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1];
+ state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1];
+ break;
+ }
+ else if (state->is_v5) {
/* Writes to R15 are UNPREDICATABLE. */
if (DESTReg == 15 || LHSReg == 15)
ARMul_UndefInstr (state, instr);
/* Is access to the coprocessor allowed ? */
else if (!CP_ACCESS_ALLOWED(state, CPNum))
- ARMul_UndefInstr (state, instr);
+ {
+ ARMul_UndefInstr(state, instr);
+ }
else {
/* MRRC, ARMv5TE and up */
ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg]));
@@ -4062,9 +4084,11 @@ TEST_EMULATE:
// continue;
else if (state->Emulate != RUN)
break;
- }
- while (state->NumInstrsToExecute--);
+
+ }
+ while (state->NumInstrsToExecute);
+exit:
state->decoded = decoded;
state->loaded = loaded;
state->pc = pc;
@@ -5689,12 +5713,98 @@ L_stm_s_takeabort:
case 0x3f:
printf ("Unhandled v6 insn: rbit\n");
break;
+#endif
case 0x61:
- printf ("Unhandled v6 insn: sadd/ssub\n");
+ if ((instr & 0xFF0) == 0xf70)//ssub16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = (a1 - a2)&0xFFFF | (((b1 - b2)&0xFFFF)<< 0x10);
+ return 1;
+ }
+ else if ((instr & 0xFF0) == 0xf10)//sadd16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10);
+ return 1;
+ }
+ else if ((instr & 0xFF0) == 0xf50)//ssax
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
+ return 1;
+ }
+ else if ((instr & 0xFF0) == 0xf30)//sasx
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
+ return 1;
+ }
+ else printf ("Unhandled v6 insn: sadd/ssub\n");
break;
case 0x62:
- printf ("Unhandled v6 insn: qadd/qsub\n");
+ if ((instr & 0xFF0) == 0xf70)//QSUB16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ s32 res1 = (a1 - b1);
+ s32 res2 = (a2 - b2);
+ if (res1 > 0x7FFF) res1 = 0x7FFF;
+ if (res2 > 0x7FFF) res2 = 0x7FFF;
+ if (res1 < 0x7FFF) res1 = -0x8000;
+ if (res2 < 0x7FFF) res2 = -0x8000;
+ state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10);
+ return 1;
+ }
+ else if ((instr & 0xFF0) == 0xf10)//QADD16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ s32 res1 = (a1 + b1);
+ s32 res2 = (a2 + b2);
+ if (res1 > 0x7FFF) res1 = 0x7FFF;
+ if (res2 > 0x7FFF) res2 = 0x7FFF;
+ if (res1 < 0x7FFF) res1 = -0x8000;
+ if (res2 < 0x7FFF) res2 = -0x8000;
+ state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10);
+ return 1;
+ }
+ else printf ("Unhandled v6 insn: qadd/qsub\n");
break;
+#if 0
case 0x63:
printf ("Unhandled v6 insn: shadd/shsub\n");
break;
@@ -5712,10 +5822,65 @@ L_stm_s_takeabort:
break;
#endif
case 0x6c:
- printf ("Unhandled v6 insn: uxtb16/uxtab16\n");
+ if ((instr & 0xf03f0) == 0xf0070) //uxtb16
+ {
+ u8 src1 = BITS(0, 3);
+ u8 tar = BITS(12, 15);
+ u32 base = state->Reg[src1];
+ u32 shamt = BITS(9,10)* 8;
+ u32 in = ((base << (32 - shamt)) | (base >> shamt));
+ state->Reg[tar] = in & 0x00FF00FF;
+ return 1;
+ }
+ else
+ printf ("Unhandled v6 insn: uxtb16/uxtab16\n");
break;
case 0x70:
- printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n");
+ if ((instr & 0xf0d0) == 0xf010)//smuad //ichfly
+ {
+ u8 tar = BITS(16, 19);
+ u8 src1 = BITS(0, 3);
+ u8 src2 = BITS(8, 11);
+ u8 swap = BIT(5);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
+ s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = a1*a2 + b1*b2;
+ return 1;
+
+ }
+ else if ((instr & 0xf0d0) == 0xf050)//smusd
+ {
+ u8 tar = BITS(16, 19);
+ u8 src1 = BITS(0, 3);
+ u8 src2 = BITS(8, 11);
+ u8 swap = BIT(5);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
+ s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = a1*a2 - b1*b2;
+ return 1;
+ }
+ else if ((instr & 0xd0) == 0x10)//smlad
+ {
+ u8 tar = BITS(16, 19);
+ u8 src1 = BITS(0, 3);
+ u8 src2 = BITS(8, 11);
+ u8 src3 = BITS(12, 15);
+ u8 swap = BIT(5);
+
+ u32 a3 = state->Reg[src3];
+
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
+ s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = a1*a2 + b1*b2 + a3;
+ return 1;
+ }
+ else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n");
break;
case 0x74:
printf ("Unhandled v6 insn: smlald/smlsld\n");
@@ -5753,13 +5918,10 @@ L_stm_s_takeabort:
if (state->Aborted) {
TAKEABORT;
}
-
- if (enter)
- {
+
+ if (enter) {
state->Reg[DESTReg] = 0;
- }
- else
- {
+ } else {
state->Reg[DESTReg] = 1;
}
@@ -5798,12 +5960,9 @@ L_stm_s_takeabort:
}
- if (enter)
- {
+ if (enter) {
state->Reg[DESTReg] = 0;
- }
- else
- {
+ } else {
state->Reg[DESTReg] = 1;
}
@@ -5856,8 +6015,25 @@ L_stm_s_takeabort:
case 0x01:
case 0xf3:
- printf ("Unhandled v6 insn: ssat\n");
- return 0;
+ //ichfly
+ //SSAT16
+ {
+ u8 tar = BITS(12,15);
+ u8 src = BITS(0, 3);
+ u8 val = BITS(16, 19) + 1;
+ s16 a1 = (state->Reg[src]);
+ s16 a2 = (state->Reg[src] >> 0x10);
+ s16 min = (s16)(0x8000) >> (16 - val);
+ s16 max = 0x7FFF >> (16 - val);
+ if (min > a1) a1 = min;
+ if (max < a1) a1 = max;
+ if (min > a2) a2 = min;
+ if (max < a2) a2 = max;
+ u32 temp2 = ((u32)(a2)) << 0x10;
+ state->Reg[tar] = (a1&0xFFFF) | (temp2);
+ }
+
+ return 1;
default:
break;
}
@@ -5947,8 +6123,21 @@ L_stm_s_takeabort:
case 0x01:
case 0xf3:
- printf ("Unhandled v6 insn: usat\n");
- return 0;
+ //ichfly
+ //USAT16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src = BITS(0, 3);
+ u8 val = BITS(16, 19);
+ s16 a1 = (state->Reg[src]);
+ s16 a2 = (state->Reg[src] >> 0x10);
+ s16 max = 0xFFFF >> (16 - val);
+ if (max < a1) a1 = max;
+ if (max < a2) a2 = max;
+ u32 temp2 = ((u32)(a2)) << 0x10;
+ state->Reg[tar] = (a1 & 0xFFFF) | (temp2);
+ }
+ return 1;
default:
break;
}
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp
index 6fbab3bfb..03bca2870 100644
--- a/src/core/arm/interpreter/arminit.cpp
+++ b/src/core/arm/interpreter/arminit.cpp
@@ -17,8 +17,8 @@
//#include <unistd.h>
-#include "core/arm/interpreter/armdefs.h"
-#include "core/arm/interpreter/armemu.h"
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armemu.h"
/***************************************************************************\
* Definitions for the emulator architecture *
diff --git a/src/core/arm/interpreter/armmmu.cpp b/src/core/arm/interpreter/armmmu.cpp
deleted file mode 100644
index 242e6a83c..000000000
--- a/src/core/arm/interpreter/armmmu.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- armmmu.c - Memory Management Unit emulation.
- ARMulator extensions for the ARM7100 family.
- Copyright (C) 1999 Ben Williamson
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <assert.h>
-#include <string.h>
-#include "armdefs.h"
-/* two header for arm disassemble */
-//#include "skyeye_arch.h"
-#include "armcpu.h"
-
-
-extern mmu_ops_t xscale_mmu_ops;
-exception_t arm_mmu_write(short size, u32 addr, uint32_t *value);
-exception_t arm_mmu_read(short size, u32 addr, uint32_t *value);
-#define MMU_OPS (state->mmu.ops)
-ARMword skyeye_cachetype = -1;
-
-int
-mmu_init (ARMul_State * state)
-{
- int ret;
-
- state->mmu.control = 0x70;
- state->mmu.translation_table_base = 0xDEADC0DE;
- state->mmu.domain_access_control = 0xDEADC0DE;
- state->mmu.fault_status = 0;
- state->mmu.fault_address = 0;
- state->mmu.process_id = 0;
-
- switch (state->cpu->cpu_val & state->cpu->cpu_mask) {
- //case SA1100:
- //case SA1110:
- // NOTICE_LOG(ARM11, "SKYEYE: use sa11xx mmu ops\n");
- // state->mmu.ops = sa_mmu_ops;
- // break;
- //case PXA250:
- //case PXA270: //xscale
- // NOTICE_LOG(ARM11, "SKYEYE: use xscale mmu ops\n");
- // state->mmu.ops = xscale_mmu_ops;
- // break;
- //case 0x41807200: //arm720t
- //case 0x41007700: //arm7tdmi
- //case 0x41007100: //arm7100
- // NOTICE_LOG(ARM11, "SKYEYE: use arm7100 mmu ops\n");
- // state->mmu.ops = arm7100_mmu_ops;
- // break;
- //case 0x41009200:
- // NOTICE_LOG(ARM11, "SKYEYE: use arm920t mmu ops\n");
- // state->mmu.ops = arm920t_mmu_ops;
- // break;
- //case 0x41069260:
- // NOTICE_LOG(ARM11, "SKYEYE: use arm926ejs mmu ops\n");
- // state->mmu.ops = arm926ejs_mmu_ops;
- // break;
- /* case 0x560f5810: */
- case 0x0007b000:
- NOTICE_LOG(ARM11, "SKYEYE: use arm11jzf-s mmu ops\n");
- state->mmu.ops = arm1176jzf_s_mmu_ops;
- break;
-
- default:
- ERROR_LOG (ARM11,
- "SKYEYE: armmmu.c : mmu_init: unknown cpu_val&cpu_mask 0x%x\n",
- state->cpu->cpu_val & state->cpu->cpu_mask);
- break;
-
- };
- ret = state->mmu.ops.init (state);
- state->mmu_inited = (ret == 0);
- /* initialize mmu_read and mmu_write for disassemble */
- //skyeye_config_t *config = get_current_config();
- //generic_arch_t *arch_instance = get_arch_instance(config->arch->arch_name);
- //arch_instance->mmu_read = arm_mmu_read;
- //arch_instance->mmu_write = arm_mmu_write;
-
- return ret;
-}
-
-int
-mmu_reset (ARMul_State * state)
-{
- if (state->mmu_inited)
- mmu_exit (state);
- return mmu_init (state);
-}
-
-void
-mmu_exit (ARMul_State * state)
-{
- MMU_OPS.exit (state);
- state->mmu_inited = 0;
-}
-
-fault_t
-mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data)
-{
- return MMU_OPS.read_byte (state, virt_addr, data);
-};
-
-fault_t
-mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data)
-{
- return MMU_OPS.read_halfword (state, virt_addr, data);
-};
-
-fault_t
-mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data)
-{
- return MMU_OPS.read_word (state, virt_addr, data);
-};
-
-fault_t
-mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data)
-{
- fault_t fault;
- //static int count = 0;
- //count ++;
- fault = MMU_OPS.write_byte (state, virt_addr, data);
- return fault;
-}
-
-fault_t
-mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data)
-{
- fault_t fault;
- //static int count = 0;
- //count ++;
- fault = MMU_OPS.write_halfword (state, virt_addr, data);
- return fault;
-}
-
-fault_t
-mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data)
-{
- fault_t fault;
- fault = MMU_OPS.write_word (state, virt_addr, data);
-
- /*used for debug for MMU*
-
- if (!fault){
- ARMword tmp;
-
- if (mmu_read_word(state, virt_addr, &tmp)){
- err_msg("load back\n");
- exit(-1);
- }else{
- if (tmp != data){
- err_msg("load back not equal %d %x\n", count, virt_addr);
- }
- }
- }
- */
-
- return fault;
-};
-
-fault_t
-mmu_load_instr (ARMul_State * state, ARMword virt_addr, ARMword * instr)
-{
- return MMU_OPS.load_instr (state, virt_addr, instr);
-}
-
-ARMword
-mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value)
-{
- return MMU_OPS.mrc (state, instr, value);
-}
-
-void
-mmu_mcr (ARMul_State * state, ARMword instr, ARMword value)
-{
- MMU_OPS.mcr (state, instr, value);
-}
-
-/*ywc 20050416*/
-int
-mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr)
-{
- return (MMU_OPS.v2p_dbct (state, virt_addr, phys_addr));
-}
-
-//
-//
-///* dis_mmu_read for disassemble */
-//exception_t arm_mmu_read(short size, uint32_t addr, uint32_t * value)
-//{
-// ARMul_State *state;
-// ARM_CPU_State *cpu = get_current_cpu();
-// state = &cpu->core[0];
-// switch(size){
-// case 8:
-// MMU_OPS.read_byte (state, addr, value);
-// break;
-// case 16:
-// case 32:
-// break;
-// default:
-// ERROR_LOG(ARM11, "Error size %d", size);
-// break;
-// }
-// return No_exp;
-//}
-///* dis_mmu_write for disassemble */
-//exception_t arm_mmu_write(short size, uint32_t addr, uint32_t *value)
-//{
-// ARMul_State *state;
-// ARM_CPU_State *cpu = get_current_cpu();
-// state = &cpu->core[0];
-// switch(size){
-// case 8:
-// MMU_OPS.write_byte (state, addr, value);
-// break;
-// case 16:
-// case 32:
-// break;
-// default:
-// printf("In %s error size %d Line %d\n", __func__, size, __LINE__);
-// break;
-// }
-// return No_exp;
-//}
diff --git a/src/core/arm/interpreter/armos.cpp b/src/core/arm/interpreter/armos.cpp
deleted file mode 100644
index 43484ee5f..000000000
--- a/src/core/arm/interpreter/armos.cpp
+++ /dev/null
@@ -1,742 +0,0 @@
-/* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator.
- Copyright (C) 1994 Advanced RISC Machines Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* This file contains a model of Demon, ARM Ltd's Debug Monitor,
-including all the SWI's required to support the C library. The code in
-it is not really for the faint-hearted (especially the abort handling
-code), but it is a complete example. Defining NOOS will disable all the
-fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI
-0x11 to halt the emulator. */
-
-//chy 2005-09-12 disable below line
-//#include "config.h"
-
-#include <time.h>
-#include <errno.h>
-#include <string.h>
-#include "skyeye_defs.h"
-#ifndef __USE_LARGEFILE64
-#define __USE_LARGEFILE64 /* When use 64 bit large file need define it! for stat64*/
-#endif
-#include <fcntl.h>
-#include <sys/stat.h>
-
-
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-#ifndef O_WRONLY
-#define O_WRONLY 1
-#endif
-#ifndef O_RDWR
-#define O_RDWR 2
-#endif
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-#ifdef __STDC__
-#define unlink(s) remove(s)
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* For SEEK_SET etc */
-#endif
-
-#ifdef __riscos
-extern int _fisatty (FILE *);
-#define isatty_(f) _fisatty(f)
-#else
-#ifdef __ZTC__
-#include <io.h>
-#define isatty_(f) isatty((f)->_file)
-#else
-#ifdef macintosh
-#include <ioctl.h>
-#define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL))
-#else
-#define isatty_(f) isatty (fileno (f))
-#endif
-#endif
-#endif
-
-#include "armdefs.h"
-#include "armos.h"
-#include "armemu.h"
-
-#ifndef NOOS
-#ifndef VALIDATE
-/* #ifndef ASIM */
-//chy 2005-09-12 disable below line
-//#include "armfpe.h"
-/* #endif */
-#endif
-#endif
-
-#define DUMP_SYSCALL 0
-#define dump(...) do { if (DUMP_SYSCALL) printf(__VA_ARGS__); } while(0)
-//#define debug(...) printf(__VA_ARGS__);
-#define debug(...) ;
-
-extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number);
-
-#ifndef FOPEN_MAX
-#define FOPEN_MAX 64
-#endif
-
-/***************************************************************************\
-* OS private Information *
-\***************************************************************************/
-
-unsigned arm_dyncom_SWI(ARMul_State * state, ARMword number)
-{
- return ARMul_OSHandleSWI(state, number);
-}
-
-//mmap_area_t *mmap_global = NULL;
-
-static int translate_open_mode[] = {
- O_RDONLY, /* "r" */
- O_RDONLY + O_BINARY, /* "rb" */
- O_RDWR, /* "r+" */
- O_RDWR + O_BINARY, /* "r+b" */
- O_WRONLY + O_CREAT + O_TRUNC, /* "w" */
- O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */
- O_RDWR + O_CREAT + O_TRUNC, /* "w+" */
- O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */
- O_WRONLY + O_APPEND + O_CREAT, /* "a" */
- O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */
- O_RDWR + O_APPEND + O_CREAT, /* "a+" */
- O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */
-};
-//
-//static void
-//SWIWrite0 (ARMul_State * state, ARMword addr)
-//{
-// ARMword temp;
-//
-// //while ((temp = ARMul_ReadByte (state, addr++)) != 0)
-// while(1){
-// mem_read(8, addr++, &temp);
-// if(temp != 0)
-// (void) fputc ((char) temp, stdout);
-// else
-// break;
-// }
-//}
-//
-//static void
-//WriteCommandLineTo (ARMul_State * state, ARMword addr)
-//{
-// ARMword temp;
-// char *cptr = state->CommandLine;
-// if (cptr == NULL)
-// cptr = "\0";
-// do {
-// temp = (ARMword) * cptr++;
-// //ARMul_WriteByte (state, addr++, temp);
-// mem_write(8, addr++, temp);
-// }
-// while (temp != 0);
-//}
-//
-//static void
-//SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags)
-//{
-// char dummy[2000];
-// int flags;
-// int i;
-//
-// for (i = 0; (dummy[i] = ARMul_ReadByte (state, name + i)); i++);
-// assert(SWIflags< (sizeof(translate_open_mode)/ sizeof(translate_open_mode[0])));
-// /* Now we need to decode the Demon open mode */
-// flags = translate_open_mode[SWIflags];
-// flags = SWIflags;
-//
-// /* Filename ":tt" is special: it denotes stdin/out */
-// if (strcmp (dummy, ":tt") == 0) {
-// if (flags == O_RDONLY) /* opening tty "r" */
-// state->Reg[0] = 0; /* stdin */
-// else
-// state->Reg[0] = 1; /* stdout */
-// }
-// else {
-// state->Reg[0] = (int) open (dummy, flags, 0666);
-// }
-//}
-//
-//static void
-//SWIread (ARMul_State * state, ARMword f, ARMword ptr, ARMword len)
-//{
-// int res;
-// int i;
-// char *local = (char*) malloc (len);
-//
-// if (local == NULL) {
-// fprintf (stderr,
-// "sim: Unable to read 0x%ulx bytes - out of memory\n",
-// len);
-// return;
-// }
-//
-// res = read (f, local, len);
-// if (res > 0)
-// for (i = 0; i < res; i++)
-// //ARMul_WriteByte (state, ptr + i, local[i]);
-// mem_write(8, ptr + i, local[i]);
-// free (local);
-// //state->Reg[0] = res == -1 ? -1 : len - res;
-// state->Reg[0] = res;
-//}
-//
-//static void
-//SWIwrite (ARMul_State * state, ARMword f, ARMword ptr, ARMword len)
-//{
-// int res;
-// ARMword i;
-// char *local = malloc (len);
-//
-// if (local == NULL) {
-// fprintf (stderr,
-// "sim: Unable to write 0x%lx bytes - out of memory\n",
-// (long unsigned int) len);
-// return;
-// }
-//
-// for (i = 0; i < len; i++){
-// //local[i] = ARMul_ReadByte (state, ptr + i);
-// ARMword data;
-// mem_read(8, ptr + i, &data);
-// local[i] = data & 0xFF;
-// }
-//
-// res = write (f, local, len);
-// //state->Reg[0] = res == -1 ? -1 : len - res;
-// state->Reg[0] = res;
-// free (local);
-//}
-
-//static void
-//SWIflen (ARMul_State * state, ARMword fh)
-//{
-// ARMword addr;
-//
-// if (fh == 0 || fh > FOPEN_MAX) {
-// state->Reg[0] = -1L;
-// return;
-// }
-//
-// addr = lseek (fh, 0, SEEK_CUR);
-//
-// state->Reg[0] = lseek (fh, 0L, SEEK_END);
-// (void) lseek (fh, addr, SEEK_SET);
-//
-//}
-
-/***************************************************************************\
-* The emulator calls this routine when a SWI instruction is encuntered. The *
-* parameter passed is the SWI number (lower 24 bits of the instruction). *
-\***************************************************************************/
-/* ahe-ykl information is retrieved from elf header and the starting value of
- brk_static is in sky_info_t */
-
-/* brk static hold the value of brk */
-static uint32_t brk_static = -1;
-
-unsigned
-ARMul_OSHandleSWI (ARMul_State * state, ARMword number)
-{
- number &= 0xfffff;
- ARMword addr, temp;
-
- switch (number) {
-// case SWI_Syscall:
-// if (state->Reg[7] != 0)
-// return ARMul_OSHandleSWI(state, state->Reg[7]);
-// else
-// return FALSE;
-// case SWI_Read:
-// SWIread (state, state->Reg[0], state->Reg[1], state->Reg[2]);
-// return TRUE;
-//
-// case SWI_GetUID32:
-// state->Reg[0] = getuid();
-// return TRUE;
-//
-// case SWI_GetGID32:
-// state->Reg[0] = getgid();
-// return TRUE;
-//
-// case SWI_GetEUID32:
-// state->Reg[0] = geteuid();
-// return TRUE;
-//
-// case SWI_GetEGID32:
-// state->Reg[0] = getegid();
-// return TRUE;
-//
-// case SWI_Write:
-// SWIwrite (state, state->Reg[0], state->Reg[1], state->Reg[2]);
-// return TRUE;
-//
-// case SWI_Open:
-// SWIopen (state, state->Reg[0], state->Reg[1]);
-// return TRUE;
-//
-// case SWI_Close:
-// state->Reg[0] = close (state->Reg[0]);
-// return TRUE;
-//
-// case SWI_Seek:{
-// /* We must return non-zero for failure */
-// state->Reg[0] =
-// lseek (state->Reg[0], state->Reg[1],
-// SEEK_SET);
-// return TRUE;
-// }
-//
-// case SWI_ExitGroup:
-// case SWI_Exit:
-// {
-// struct timeval tv;
-// //gettimeofday(&tv,NULL);
-// //printf("In %s, %d sec, %d usec\n", __FUNCTION__, tv.tv_sec, tv.tv_usec);
-// printf("passed %d sec, %lld usec\n", get_clock_sec(), get_clock_us());
-//
-// /* quit here */
-// run_command("quit");
-// return TRUE;
-// }
-// case SWI_Times:{
-// uint32_t dest = state->Reg[0];
-// struct tms now;
-// struct target_tms32 nowret;
-//
-// uint32_t ret = times(&now);
-//
-// if (ret == -1){
-// debug("syscall %s error %d\n", "SWI_Times", ret);
-// state->Reg[0] = ret;
-// return FALSE;
-// }
-//
-// nowret.tms_cstime = now.tms_cstime;
-// nowret.tms_cutime = now.tms_cutime;
-// nowret.tms_stime = now.tms_stime;
-// nowret.tms_utime = now.tms_utime;
-//
-// uint32_t offset;
-// for (offset = 0; offset < sizeof(nowret); offset++) {
-// bus_write(8, dest + offset, *((uint8_t *) &nowret + offset));
-// }
-//
-// state->Reg[0] = ret;
-// return TRUE;
-// }
-//
-// case SWI_Gettimeofday: {
-// uint32_t dest1 = state->Reg[0];
-// uint32_t dest2 = state->Reg[1]; // Unsure of this
-// struct timeval val;
-// struct timezone zone;
-// struct target_timeval32 valret;
-// struct target_timezone32 zoneret;
-//
-// uint32_t ret = gettimeofday(&val, &zone);
-// valret.tv_sec = val.tv_sec;
-// valret.tv_usec = val.tv_usec;
-// zoneret.tz_dsttime = zoneret.tz_dsttime;
-// zoneret.tz_minuteswest = zoneret.tz_minuteswest;
-//
-// if (ret == -1){
-// debug("syscall %s error %d\n", "SWI_Gettimeofday", ret);
-// state->Reg[0] = ret;
-// return FALSE;
-// }
-//
-// uint32_t offset;
-// if (dest1) {
-// for (offset = 0; offset < sizeof(valret); offset++) {
-// bus_write(8, dest1 + offset, *((uint8_t *) &valret + offset));
-// }
-// state->Reg[0] = ret;
-// }
-// if (dest2) {
-// for (offset = 0; offset < sizeof(zoneret); offset++) {
-// bus_write(8, dest2 + offset, *((uint8_t *) &zoneret + offset));
-// }
-// state->Reg[0] = ret;
-// }
-//
-// return TRUE;
-// }
-// case SWI_Brk:
-// /* initialize brk value */
-// /* suppose that brk_static doesn't reach 0xffffffff... */
-// if (brk_static == -1) {
-// brk_static = (get_skyeye_pref()->info).brk;
-// }
-//
-// /* FIXME there might be a need to do a mmap */
-//
-// if(state->Reg[0]){
-// if (get_skyeye_exec_info()->mmap_access) {
-// /* if new brk is greater than current brk, allocate memory */
-// if (state->Reg[0] > brk_static) {
-// uint32_t ret = mmap( (void *) brk_static, state->Reg[0] - brk_static,
-// PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0 );
-// if (ret != MAP_FAILED)
-// brk_static = ret;
-// }
-// }
-// brk_static = state->Reg[0];
-// //state->Reg[0] = 0; /* FIXME return value of brk set to be the address on success */
-// } else {
-// state->Reg[0] = brk_static;
-// }
-// return TRUE;
-//
-// case SWI_Break:
-// state->Emulate = FALSE;
-// return TRUE;
-//
-// case SWI_Mmap:{
-// int addr = state->Reg[0];
-// int len = state->Reg[1];
-// int prot = state->Reg[2];
-// int flag = state->Reg[3];
-// int fd = state->Reg[4];
-// int offset = state->Reg[5];
-// mmap_area_t *area = new_mmap_area(addr, len);
-// state->Reg[0] = area->bank.addr;
-// //printf("syscall %d mmap(0x%x,%x,0x%x,0x%x,%d,0x%x) = 0x%x\n",\
-// SWI_Mmap, addr, len, prot, flag, fd, offset, state->Reg[0]);
-// return TRUE;
-// }
-//
-// case SWI_Munmap:
-// state->Reg[0] = 0;
-// return TRUE;
-//
-// case SWI_Mmap2:{
-// int addr = state->Reg[0];
-// int len = state->Reg[1];
-// int prot = state->Reg[2];
-// int flag = state->Reg[3];
-// int fd = state->Reg[4];
-// int offset = state->Reg[5] * 4096; /* page offset */
-// mmap_area_t *area = new_mmap_area(addr, len);
-// state->Reg[0] = area->bank.addr;
-//
-// return TRUE;
-// }
-//
-// case SWI_Breakpoint:
-// //chy 2005-09-12 change below line
-// //state->EndCondition = RDIError_BreakpointReached;
-// //printf ("SKYEYE: in armos.c : should not come here!!!!\n");
-// state->EndCondition = 0;
-// /*modified by ksh to support breakpoiont*/
-// state->Emulate = STOP;
-// return (TRUE);
-// case SWI_Uname:
-// {
-// struct utsname *uts = (uintptr_t) state->Reg[0]; /* uname should write data in this address */
-// struct utsname utsbuf;
-// //printf("Uname size is %x\n", sizeof(utsbuf));
-// char *buf;
-// uintptr_t sp ; /* used as a temporary address */
-//
-//#define COPY_UTS_STRING(addr) \
-// buf = addr; \
-// while(*buf != NULL) { \
-// bus_write(8, sp, *buf); \
-// sp++; \
-// buf++; \
-// }
-//#define COPY_UTS(field) /*printf("%s: %s at %p\n", #field, utsbuf.field, uts->field);*/ \
-// sp = (uintptr_t) uts->field; \
-// COPY_UTS_STRING((&utsbuf)->field);
-//
-// if (uname(&utsbuf) < 0) {
-// printf("syscall uname: utsname error\n");
-// state->Reg[0] = -1;
-// return FALSE;
-// }
-//
-// /* FIXME for now, this is just the host system call
-// Some data should be missing, as it depends on
-// the version of utsname */
-// COPY_UTS(sysname);
-// COPY_UTS(nodename);
-// COPY_UTS(release);
-// COPY_UTS(version);
-// COPY_UTS(machine);
-//
-// state->Reg[0] = 0;
-// return TRUE;
-// }
-// case SWI_Fcntl:
-// {
-// uint32_t fd = state->Reg[0];
-// uint32_t cmd = state->Reg[1];
-// uint32_t arg = state->Reg[2];
-// uint32_t ret;
-//
-// switch(cmd){
-// case (F_GETFD):
-// {
-// ret = fcntl(fd, cmd, arg);
-// //printf("syscall fcntl for getfd not implemented, ret %d\n", ret);
-// state->Reg[0] = ret;
-// return FALSE;
-// }
-// default:
-// break;
-// }
-//
-// printf("syscall fcntl unimplemented fd %x cmd %x\n", fd, cmd);
-// state->Reg[0] = -1;
-// return FALSE;
-//
-// }
-// case SWI_Fstat64:
-// {
-// uint32_t dest = state->Reg[1];
-// uint32_t fd = state->Reg[0];
-// struct stat64 statbuf;
-// struct target_stat64 statret;
-// memset(&statret, 0, sizeof(struct target_stat64));
-// uint32_t ret = fstat64(fd, &statbuf);
-//
-// if (ret == -1){
-// printf("syscall %s returned error\n", "SWI_Fstat");
-// state->Reg[0] = ret;
-// return FALSE;
-// }
-//
-// /* copy statbuf to the process memory space
-// FIXME can't say if endian has an effect here */
-// uint32_t offset;
-// //printf("Fstat system is size %x\n", sizeof(statbuf));
-// //printf("Fstat target is size %x\n", sizeof(statret));
-//
-// /* we copy system structure data stat64 into arm fixed size structure target_stat64 */
-// statret.st_dev = statbuf.st_dev;
-// statret.st_ino = statbuf.st_ino;
-// statret.st_mode = statbuf.st_mode;
-// statret.st_nlink = statbuf.st_nlink;
-// statret.st_uid = statbuf.st_uid;
-// statret.st_gid = statbuf.st_gid;
-// statret.st_rdev = statbuf.st_rdev;
-// statret.st_size = statbuf.st_size;
-// statret.st_blksize = statbuf.st_blksize;
-// statret.st_blocks = statbuf.st_blocks;
-// statret.st32_atime = statbuf.st_atime;
-// statret.st32_mtime = statbuf.st_mtime;
-// statret.st32_ctime = statbuf.st_ctime;
-//
-// for (offset = 0; offset < sizeof(statret); offset++) {
-// bus_write(8, dest + offset, *((uint8_t *) &statret + offset));
-// }
-//
-// state->Reg[0] = ret;
-// return TRUE;
-// }
-// case SWI_Set_tls:
-// {
-// //printf("syscall set_tls unimplemented\n");
-// state->mmu.thread_uro_id = state->Reg[0];
-// state->CP15[CP15_THREAD_URO - CP15_BASE] = state->Reg[0];
-// state->Reg[0] = 0;
-// return FALSE;
-// }
-//#if 0
-// case SWI_Clock:
-// /* return number of centi-seconds... */
-// state->Reg[0] =
-//#ifdef CLOCKS_PER_SEC
-// (CLOCKS_PER_SEC >= 100)
-// ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100))
-// : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC);
-//#else
-// /* presume unix... clock() returns microseconds */
-// (ARMword) (clock () / 10000);
-//#endif
-// return (TRUE);
-//
-// case SWI_Time:
-// state->Reg[0] = (ARMword) time (NULL);
-// return (TRUE);
-// case SWI_Flen:
-// SWIflen (state, state->Reg[0]);
-// return (TRUE);
-//
-//#endif
- default:
-
- _dbg_assert_msg_(ARM11, false, "ImplementMe: ARMul_OSHandleSWI!");
-
- return (FALSE);
- }
-}
-//
-///**
-// * @brief For mmap syscall.A mmap_area is a memory bank. Get from ppc.
-// */
-//static mmap_area_t* new_mmap_area(int sim_addr, int len){
-// mmap_area_t *area = (mmap_area_t *)malloc(sizeof(mmap_area_t));
-// if(area == NULL){
-// printf("error, failed %s\n",__FUNCTION__);
-// exit(0);
-// }
-//#if FAST_MEMORY
-// if (mmap_next_base == -1)
-// {
-// mmap_next_base = get_skyeye_exec_info()->brk;
-// }
-//#endif
-//
-// memset(area, 0x0, sizeof(mmap_area_t));
-// area->bank.addr = mmap_next_base;
-// area->bank.len = len;
-// area->bank.bank_write = mmap_mem_write;
-// area->bank.bank_read = mmap_mem_read;
-// area->bank.type = MEMTYPE_RAM;
-// area->bank.objname = "mmap";
-// addr_mapping(&area->bank);
-//
-//#if FAST_MEMORY
-// if (get_skyeye_exec_info()->mmap_access)
-// {
-// /* FIXME check proper flags */
-// /* FIXME we may delete the need of banks up there */
-// uint32_t ret = mmap(mmap_next_base, len, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-// mmap_next_base = ret;
-// }
-// area->mmap_addr = (uint8_t*)get_dma_addr(mmap_next_base);
-//#else
-// area->mmap_addr = malloc(len);
-// if(area->mmap_addr == NULL){
-// printf("error mmap malloc\n");
-// exit(0);
-// }
-// memset(area->mmap_addr, 0x0, len);
-//#endif
-//
-// area->next = NULL;
-// if(mmap_global){
-// area->next = mmap_global->next;
-// mmap_global->next = area;
-// }else{
-// mmap_global = area;
-// }
-// mmap_next_base = mmap_next_base + len;
-// return area;
-//}
-//
-//static mmap_area_t *get_mmap_area(int addr){
-// mmap_area_t *tmp = mmap_global;
-// while(tmp){
-// if ((tmp->bank.addr <= addr) && (tmp->bank.addr + tmp->bank.len > addr)){
-// return tmp;
-// }
-// tmp = tmp->next;
-// }
-// printf("cannot get mmap area:addr=0x%x\n", addr);
-// return NULL;
-//}
-//
-///**
-// * @brief the mmap_area bank write function. Get from ppc.
-// *
-// * @param size size to write, 8/16/32
-// * @param addr address to write
-// * @param value value to write
-// *
-// * @return sucess return 1,otherwise 0.
-// */
-//static char mmap_mem_write(short size, int addr, uint32_t value){
-// mmap_area_t *area_tmp = get_mmap_area(addr);
-// mem_bank_t *bank_tmp = &area_tmp->bank;
-// int offset = addr - bank_tmp->addr;
-// switch(size){
-// case 8:{
-// //uint8_t value_endian = value;
-// uint8_t value_endian = (uint8_t)value;
-// *(uint8_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian;
-// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian);
-// break;
-// }
-// case 16:{
-// //uint16_t value_endian = half_to_BE((uint16_t)value);
-// uint16_t value_endian = ((uint16_t)value);
-// *(uint16_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian;
-// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian);
-// break;
-// }
-// case 32:{
-// //uint32_t value_endian = word_to_BE((uint32_t)value);
-// uint32_t value_endian = ((uint32_t)value);
-// *(uint32_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian;
-// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian);
-// break;
-// }
-// default:
-// printf("invalid size %d\n",size);
-// return 0;
-// }
-// return 1;
-//}
-//
-///**
-// * @brief the mmap_area bank read function. Get from ppc.
-// *
-// * @param size size to read, 8/16/32
-// * @param addr address to read
-// * @param value value to read
-// *
-// * @return sucess return 1,otherwise 0.
-// */
-//static char mmap_mem_read(short size, int addr, uint32_t * value){
-// mmap_area_t *area_tmp = get_mmap_area(addr);
-// mem_bank_t *bank_tmp = &area_tmp->bank;
-// int offset = addr - bank_tmp->addr;
-// switch(size){
-// case 8:{
-// //*(uint8_t *)value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]);
-// *value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]);
-// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value);
-// break;
-// }
-// case 16:{
-// //*(uint16_t *)value = half_from_BE(*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]));
-// *value = (*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]));
-// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint16_t*)value);
-// break;
-// }
-// case 32:
-// //*value = (uint32_t)word_from_BE(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]));
-// *value = (uint32_t)(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]));
-// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value);
-// break;
-// default:
-// printf("invalid size %d\n",size);
-// return 0;
-// }
-// return 1;
-//}
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index 3d3545c65..2568b93ef 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -15,18 +15,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-//#include <util.h>
-
-#include <string>
-#include "core/arm/interpreter/armdefs.h"
-#include "core/arm/interpreter/armemu.h"
-#include "core/hle/coprocessor.h"
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armemu.h"
#include "core/arm/disassembler/arm_disasm.h"
+#include "core/mem_map.h"
-//#include "ansidecl.h"
-//#include "skyeye.h"
-//extern int skyeye_instr_debug;
-/* Definitions for the support routines. */
static ARMword ModeToBank (ARMword);
static void EnvokeList (ARMul_State *, unsigned int, unsigned int);
@@ -751,7 +744,7 @@ ARMword ARMul_MRC (ARMul_State * state, ARMword instr)
int cpopc = BITS(21, 23) & 0x7;
if (cn == 13 && cm == 0 && cp == 3) { //c13,c0,3; returns CPU svc buffer
- ARMword result = HLE::CallMRC(instr);
+ ARMword result = Memory::KERNEL_MEMORY_VADDR;
if (result != -1) {
return result;
diff --git a/src/core/arm/interpreter/armvirt.cpp b/src/core/arm/interpreter/armvirt.cpp
index a072b73be..7845d1042 100644
--- a/src/core/arm/interpreter/armvirt.cpp
+++ b/src/core/arm/interpreter/armvirt.cpp
@@ -23,658 +23,143 @@ table. The routines PutWord and GetWord implement this. Pages are never
freed as they might be needed again. A single area of memory may be
defined to generate aborts. */
-#include "armdefs.h"
-#include "skyeye_defs.h"
-//#include "code_cov.h"
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armemu.h"
-#ifdef VALIDATE /* for running the validate suite */
-#define TUBE 48 * 1024 * 1024 /* write a char on the screen */
-#define ABORTS 1
-#endif
-
-/* #define ABORTS */
-
-#ifdef ABORTS /* the memory system will abort */
-/* For the old test suite Abort between 32 Kbytes and 32 Mbytes
- For the new test suite Abort between 8 Mbytes and 26 Mbytes */
-/* #define LOWABORT 32 * 1024
-#define HIGHABORT 32 * 1024 * 1024 */
-#define LOWABORT 8 * 1024 * 1024
-#define HIGHABORT 26 * 1024 * 1024
-
-#endif
-
-#define NUMPAGES 64 * 1024
-#define PAGESIZE 64 * 1024
-#define PAGEBITS 16
-#define OFFSETBITS 0xffff
-//chy 2003-08-19: seems no use ????
-int SWI_vector_installed = FALSE;
-extern ARMword skyeye_cachetype;
-
-/***************************************************************************\
-* Get a byte into Virtual Memory, maybe allocating the page *
-\***************************************************************************/
-static fault_t
-GetByte (ARMul_State * state, ARMword address, ARMword * data)
-{
- fault_t fault;
-
- fault = mmu_read_byte (state, address, data);
- if (fault) {
-//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
-// printf("SKYEYE: GetByte fault %d \n", fault);
- }
- return fault;
-}
-
-/***************************************************************************\
-* Get a halfword into Virtual Memory, maybe allocating the page *
-\***************************************************************************/
-static fault_t
-GetHalfWord (ARMul_State * state, ARMword address, ARMword * data)
-{
- fault_t fault;
-
- fault = mmu_read_halfword (state, address, data);
- if (fault) {
-//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
-// printf("SKYEYE: GetHalfWord fault %d \n", fault);
- }
- return fault;
-}
-
-/***************************************************************************\
-* Get a Word from Virtual Memory, maybe allocating the page *
-\***************************************************************************/
+#include "core/mem_map.h"
-static fault_t
-GetWord (ARMul_State * state, ARMword address, ARMword * data)
-{
- fault_t fault;
+#define dumpstack 1
+#define dumpstacksize 0x10
+#define maxdmupaddr 0x0033a850
- fault = mmu_read_word (state, address, data);
- if (fault) {
-//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
-#if 0
-/* XXX */ extern int hack;
- hack = 1;
-#endif
-#if 0
- printf ("mmu_read_word at 0x%08x: ", address);
- switch (fault) {
- case ALIGNMENT_FAULT:
- printf ("ALIGNMENT_FAULT");
- break;
- case SECTION_TRANSLATION_FAULT:
- printf ("SECTION_TRANSLATION_FAULT");
- break;
- case PAGE_TRANSLATION_FAULT:
- printf ("PAGE_TRANSLATION_FAULT");
- break;
- case SECTION_DOMAIN_FAULT:
- printf ("SECTION_DOMAIN_FAULT");
- break;
- case SECTION_PERMISSION_FAULT:
- printf ("SECTION_PERMISSION_FAULT");
- break;
- case SUBPAGE_PERMISSION_FAULT:
- printf ("SUBPAGE_PERMISSION_FAULT");
- break;
- default:
- printf ("Unrecognized fault number!");
- }
- printf ("\tpc = 0x%08x\n", state->Reg[15]);
-#endif
- }
- return fault;
+/*ARMword ARMul_GetCPSR (ARMul_State * state) {
+return 0;
}
-
-//2003-07-10 chy: lyh change
-/****************************************************************************\
- * Load a Instrion Word into Virtual Memory *
-\****************************************************************************/
-static fault_t
-LoadInstr (ARMul_State * state, ARMword address, ARMword * instr)
-{
- fault_t fault;
- fault = mmu_load_instr (state, address, instr);
- return fault;
- //if (fault)
- // log_msg("load_instr fault = %d, address = %x\n", fault, address);
+ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode) {
+return 0;
}
+void ARMul_SetCPSR (ARMul_State * state, ARMword value) {
-/***************************************************************************\
-* Put a byte into Virtual Memory, maybe allocating the page *
-\***************************************************************************/
-static fault_t
-PutByte (ARMul_State * state, ARMword address, ARMword data)
-{
- fault_t fault;
-
- fault = mmu_write_byte (state, address, data);
- if (fault) {
-//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
-// printf("SKYEYE: PutByte fault %d \n", fault);
- }
- return fault;
}
+void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) {
-/***************************************************************************\
-* Put a halfword into Virtual Memory, maybe allocating the page *
-\***************************************************************************/
-static fault_t
-PutHalfWord (ARMul_State * state, ARMword address, ARMword data)
-{
- fault_t fault;
+}*/
- fault = mmu_write_halfword (state, address, data);
- if (fault) {
-//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
-// printf("SKYEYE: PutHalfWord fault %d \n", fault);
- }
- return fault;
+void ARMul_Icycles(ARMul_State * state, unsigned number, ARMword address) {
}
-/***************************************************************************\
-* Put a Word into Virtual Memory, maybe allocating the page *
-\***************************************************************************/
-
-static fault_t
-PutWord (ARMul_State * state, ARMword address, ARMword data)
-{
- fault_t fault;
-
- fault = mmu_write_word (state, address, data);
- if (fault) {
-//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
-#if 0
-/* XXX */ extern int hack;
- hack = 1;
-#endif
-#if 0
- printf ("mmu_write_word at 0x%08x: ", address);
- switch (fault) {
- case ALIGNMENT_FAULT:
- printf ("ALIGNMENT_FAULT");
- break;
- case SECTION_TRANSLATION_FAULT:
- printf ("SECTION_TRANSLATION_FAULT");
- break;
- case PAGE_TRANSLATION_FAULT:
- printf ("PAGE_TRANSLATION_FAULT");
- break;
- case SECTION_DOMAIN_FAULT:
- printf ("SECTION_DOMAIN_FAULT");
- break;
- case SECTION_PERMISSION_FAULT:
- printf ("SECTION_PERMISSION_FAULT");
- break;
- case SUBPAGE_PERMISSION_FAULT:
- printf ("SUBPAGE_PERMISSION_FAULT");
- break;
- default:
- printf ("Unrecognized fault number!");
- }
- printf ("\tpc = 0x%08x\n", state->Reg[15]);
-#endif
- }
- return fault;
+void ARMul_Ccycles(ARMul_State * state, unsigned number, ARMword address) {
}
-/***************************************************************************\
-* Initialise the memory interface *
-\***************************************************************************/
-
-unsigned
-ARMul_MemoryInit (ARMul_State * state, unsigned int initmemsize)
-{
- return TRUE;
-}
-
-/***************************************************************************\
-* Remove the memory interface *
-\***************************************************************************/
-
-void
-ARMul_MemoryExit (ARMul_State * state)
-{
-}
-
-/***************************************************************************\
-* ReLoad Instruction *
-\***************************************************************************/
-
-ARMword
-ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize)
-{
- ARMword data;
- fault_t fault;
-
-#ifdef ABORTS
- if (address >= LOWABORT && address < HIGHABORT) {
- ARMul_PREFETCHABORT (address);
- return ARMul_ABORTWORD;
- }
- else {
- ARMul_CLEARABORT;
- }
-#endif
-#if 0
- /* do profiling for code coverage */
- if (skyeye_config.code_cov.prof_on)
- cov_prof(EXEC_FLAG, address);
-#endif
-#if 1
- if ((isize == 2) && (address & 0x2)) {
- ARMword lo, hi;
- if (!(skyeye_cachetype == INSTCACHE))
- fault = GetHalfWord (state, address, &lo);
- else
- fault = LoadInstr (state, address, &lo);
-#if 0
- if (!fault) {
- if (!(skyeye_cachetype == INSTCACHE))
- fault = GetHalfWord (state, address + isize, &hi);
- else
- fault = LoadInstr (state, address + isize, &hi);
-
- }
-#endif
- if (fault) {
- ARMul_PREFETCHABORT (address);
- return ARMul_ABORTWORD;
- }
- else {
- ARMul_CLEARABORT;
- }
- return lo;
-#if 0
- if (state->bigendSig == HIGH)
- return (lo << 16) | (hi >> 16);
- else
- return ((hi & 0xFFFF) << 16) | (lo >> 16);
-#endif
- }
-#endif
- if (!(skyeye_cachetype == INSTCACHE))
- fault = GetWord (state, address, &data);
- else
- fault = LoadInstr (state, address, &data);
-
- if (fault) {
-
- /* dyf add for s3c6410 no instcache temporary 2010.9.17 */
- if (!(skyeye_cachetype == INSTCACHE)) {
- /* set translation fault on prefetch abort */
- state->mmu.fault_statusi = fault & 0xFF;
- state->mmu.fault_address = address;
- }
- /* add end */
-
- ARMul_PREFETCHABORT (address);
- return ARMul_ABORTWORD;
- }
- else {
- ARMul_CLEARABORT;
- }
-
- return data;
-}
-
-/***************************************************************************\
-* Load Instruction, Sequential Cycle *
-\***************************************************************************/
-
-ARMword
-ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize)
-{
- state->NumScycles++;
+ARMword ARMul_LoadInstrS(ARMul_State * state, ARMword address, ARMword isize) {
+ state->NumScycles++;
#ifdef HOURGLASS
- if ((state->NumScycles & HOURGLASS_RATE) == 0) {
- HOURGLASS;
- }
+ if ((state->NumScycles & HOURGLASS_RATE) == 0) {
+ HOURGLASS;
+ }
#endif
-
- return ARMul_ReLoadInstr (state, address, isize);
+ if (isize == 2)
+ return (u16)Memory::Read16(address);
+ else
+ return (u32)Memory::Read32(address);
}
-/***************************************************************************\
-* Load Instruction, Non Sequential Cycle *
-\***************************************************************************/
-
-ARMword
-ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize)
-{
- state->NumNcycles++;
+ARMword ARMul_LoadInstrN(ARMul_State * state, ARMword address, ARMword isize) {
+ state->NumNcycles++;
- return ARMul_ReLoadInstr (state, address, isize);
+ if (isize == 2)
+ return (u16)Memory::Read16(address);
+ else
+ return (u32)Memory::Read32(address);
}
-/***************************************************************************\
-* Read Word (but don't tell anyone!) *
-\***************************************************************************/
+ARMword ARMul_ReLoadInstr(ARMul_State * state, ARMword address, ARMword isize) {
+ ARMword data;
-ARMword
-ARMul_ReadWord (ARMul_State * state, ARMword address)
-{
- ARMword data;
- fault_t fault;
-
-#ifdef ABORTS
- if (address >= LOWABORT && address < HIGHABORT) {
- ARMul_DATAABORT (address);
- return ARMul_ABORTWORD;
- }
- else {
- ARMul_CLEARABORT;
- }
-#endif
+ if ((isize == 2) && (address & 0x2)) {
+ ARMword lo;
+ lo = (u16)Memory::Read16(address);
+ return lo;
+ }
- fault = GetWord (state, address, &data);
- if (fault) {
- state->mmu.fault_status =
- (fault | (state->mmu.last_domain << 4)) & 0xFF;
- state->mmu.fault_address = address;
- ARMul_DATAABORT (address);
- return ARMul_ABORTWORD;
- }
- else {
- ARMul_CLEARABORT;
- }
- return data;
+ data = (u32)Memory::Read32(address);
+ return data;
}
-/***************************************************************************\
-* Load Word, Sequential Cycle *
-\***************************************************************************/
-
-ARMword
-ARMul_LoadWordS (ARMul_State * state, ARMword address)
-{
- state->NumScycles++;
-
- return ARMul_ReadWord (state, address);
+ARMword ARMul_ReadWord(ARMul_State * state, ARMword address) {
+ ARMword data;
+ data = Memory::Read32(address);
+ return data;
}
-/***************************************************************************\
-* Load Word, Non Sequential Cycle *
-\***************************************************************************/
-
-ARMword
-ARMul_LoadWordN (ARMul_State * state, ARMword address)
-{
- state->NumNcycles++;
-
- return ARMul_ReadWord (state, address);
+ARMword ARMul_LoadWordS(ARMul_State * state, ARMword address) {
+ state->NumScycles++;
+ return ARMul_ReadWord(state, address);
}
-/***************************************************************************\
-* Load Halfword, (Non Sequential Cycle) *
-\***************************************************************************/
-
-ARMword
-ARMul_LoadHalfWord (ARMul_State * state, ARMword address)
-{
- ARMword data;
- fault_t fault;
-
- state->NumNcycles++;
- fault = GetHalfWord (state, address, &data);
-
- if (fault) {
- state->mmu.fault_status =
- (fault | (state->mmu.last_domain << 4)) & 0xFF;
- state->mmu.fault_address = address;
- ARMul_DATAABORT (address);
- return ARMul_ABORTWORD;
- }
- else {
- ARMul_CLEARABORT;
- }
-
- return data;
-
+ARMword ARMul_LoadWordN(ARMul_State * state, ARMword address) {
+ state->NumNcycles++;
+ return ARMul_ReadWord(state, address);
}
-/***************************************************************************\
-* Read Byte (but don't tell anyone!) *
-\***************************************************************************/
-int ARMul_ICE_ReadByte(ARMul_State * state, ARMword address, ARMword *presult)
-{
- ARMword data;
- fault_t fault;
- fault = GetByte (state, address, &data);
- if (fault) {
- *presult=-1; fault=ALIGNMENT_FAULT; return fault;
- }else{
- *(char *)presult=(unsigned char)(data & 0xff); fault=NO_FAULT; return fault;
- }
+ARMword ARMul_LoadHalfWord(ARMul_State * state, ARMword address) {
+ state->NumNcycles++;
+ return (u16)Memory::Read16(address);;
}
-
-
-ARMword
-ARMul_ReadByte (ARMul_State * state, ARMword address)
-{
- ARMword data;
- fault_t fault;
-
- fault = GetByte (state, address, &data);
-
- if (fault) {
- state->mmu.fault_status =
- (fault | (state->mmu.last_domain << 4)) & 0xFF;
- state->mmu.fault_address = address;
- ARMul_DATAABORT (address);
- return ARMul_ABORTWORD;
- }
- else {
- ARMul_CLEARABORT;
- }
-
- return data;
-
-}
-
-/***************************************************************************\
-* Load Byte, (Non Sequential Cycle) *
-\***************************************************************************/
-
-ARMword
-ARMul_LoadByte (ARMul_State * state, ARMword address)
-{
- state->NumNcycles++;
-
- return ARMul_ReadByte (state, address);
-}
-
-/***************************************************************************\
-* Write Word (but don't tell anyone!) *
-\***************************************************************************/
-
-void
-ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data)
-{
- fault_t fault;
-
-#ifdef ABORTS
- if (address >= LOWABORT && address < HIGHABORT) {
- ARMul_DATAABORT (address);
- return;
- }
- else {
- ARMul_CLEARABORT;
- }
-#endif
- fault = PutWord (state, address, data);
- if (fault) {
- state->mmu.fault_status =
- (fault | (state->mmu.last_domain << 4)) & 0xFF;
- state->mmu.fault_address = address;
- ARMul_DATAABORT (address);
- return;
- }
- else {
- ARMul_CLEARABORT;
- }
+ARMword ARMul_ReadByte(ARMul_State * state, ARMword address) {
+ return (u8)Memory::Read8(address);
}
-/***************************************************************************\
-* Store Word, Sequential Cycle *
-\***************************************************************************/
-
-void
-ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data)
-{
- state->NumScycles++;
-
- ARMul_WriteWord (state, address, data);
+ARMword ARMul_LoadByte(ARMul_State * state, ARMword address) {
+ state->NumNcycles++;
+ return ARMul_ReadByte(state, address);
}
-/***************************************************************************\
-* Store Word, Non Sequential Cycle *
-\***************************************************************************/
-
-void
-ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data)
-{
- state->NumNcycles++;
-
- ARMul_WriteWord (state, address, data);
+void ARMul_StoreHalfWord(ARMul_State * state, ARMword address, ARMword data) {
+ state->NumNcycles++;
+ Memory::Write16(address, data);
}
-/***************************************************************************\
-* Store HalfWord, (Non Sequential Cycle) *
-\***************************************************************************/
-
-void
-ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data)
-{
- fault_t fault;
- state->NumNcycles++;
- fault = PutHalfWord (state, address, data);
- if (fault) {
- state->mmu.fault_status =
- (fault | (state->mmu.last_domain << 4)) & 0xFF;
- state->mmu.fault_address = address;
- ARMul_DATAABORT (address);
- return;
- }
- else {
- ARMul_CLEARABORT;
- }
+void ARMul_StoreByte(ARMul_State * state, ARMword address, ARMword data) {
+ state->NumNcycles++;
+ ARMul_WriteByte(state, address, data);
}
-//chy 2006-04-15
-int ARMul_ICE_WriteByte (ARMul_State * state, ARMword address, ARMword data)
-{
- fault_t fault;
- fault = PutByte (state, address, data);
- if (fault)
- return 1;
- else
- return 0;
-}
-/***************************************************************************\
-* Write Byte (but don't tell anyone!) *
-\***************************************************************************/
-//chy 2003-07-10, add real write byte fun
-void
-ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data)
-{
- fault_t fault;
- fault = PutByte (state, address, data);
- if (fault) {
- state->mmu.fault_status =
- (fault | (state->mmu.last_domain << 4)) & 0xFF;
- state->mmu.fault_address = address;
- ARMul_DATAABORT (address);
- return;
- }
- else {
- ARMul_CLEARABORT;
- }
+ARMword ARMul_SwapWord(ARMul_State * state, ARMword address, ARMword data) {
+ ARMword temp;
+ state->NumNcycles++;
+ temp = ARMul_ReadWord(state, address);
+ state->NumNcycles++;
+ Memory::Write32(address, data);
+ return temp;
}
-/***************************************************************************\
-* Store Byte, (Non Sequential Cycle) *
-\***************************************************************************/
-
-void
-ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data)
-{
- state->NumNcycles++;
-
-#ifdef VALIDATE
- if (address == TUBE) {
- if (data == 4)
- state->Emulate = FALSE;
- else
- (void) putc ((char) data, stderr); /* Write Char */
- return;
- }
-#endif
-
- ARMul_WriteByte (state, address, data);
+ARMword ARMul_SwapByte(ARMul_State * state, ARMword address, ARMword data) {
+ ARMword temp;
+ temp = ARMul_LoadByte(state, address);
+ Memory::Write8(address, data);
+ return temp;
}
-/***************************************************************************\
-* Swap Word, (Two Non Sequential Cycles) *
-\***************************************************************************/
-
-ARMword
-ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data)
-{
- ARMword temp;
-
- state->NumNcycles++;
-
- temp = ARMul_ReadWord (state, address);
-
- state->NumNcycles++;
-
- PutWord (state, address, data);
-
- return temp;
+void ARMul_WriteWord(ARMul_State * state, ARMword address, ARMword data) {
+ Memory::Write32(address, data);
}
-/***************************************************************************\
-* Swap Byte, (Two Non Sequential Cycles) *
-\***************************************************************************/
-
-ARMword
-ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data)
+void ARMul_WriteByte(ARMul_State * state, ARMword address, ARMword data)
{
- ARMword temp;
-
- temp = ARMul_LoadByte (state, address);
- ARMul_StoreByte (state, address, data);
-
- return temp;
+ Memory::Write8(address, data);
}
-/***************************************************************************\
-* Count I Cycles *
-\***************************************************************************/
-
-void
-ARMul_Icycles (ARMul_State * state, unsigned number,
- ARMword address)
+void ARMul_StoreWordS(ARMul_State * state, ARMword address, ARMword data)
{
- state->NumIcycles += number;
- ARMul_CLEARABORT;
+ state->NumScycles++;
+ ARMul_WriteWord(state, address, data);
}
-/***************************************************************************\
-* Count C Cycles *
-\***************************************************************************/
-
-void
-ARMul_Ccycles (ARMul_State * state, unsigned number,
- ARMword address)
+void ARMul_StoreWordN(ARMul_State * state, ARMword address, ARMword data)
{
- state->NumCcycles += number;
- ARMul_CLEARABORT;
+ state->NumNcycles++;
+ ARMul_WriteWord(state, address, data);
}
diff --git a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp
deleted file mode 100644
index a32f076b9..000000000
--- a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp
+++ /dev/null
@@ -1,1132 +0,0 @@
-/*
- arm1176jzf_s_mmu.c - ARM920T Memory Management Unit emulation.
- Copyright (C) 2003 Skyeye Develop Group
- for help please send mail to <skyeye-developer@lists.gro.clinux.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <assert.h>
-#include <string.h>
-#include <stdint.h>
-
-#include "core/mem_map.h"
-
-#include "core/arm/interpreter/skyeye_defs.h"
-
-#include "core/arm/interpreter/armdefs.h"
-//#include "bank_defs.h"
-#if 0
-#define TLB_SIZE 1024 * 1024
-#define ASID 255
-static uint32_t tlb_entry_array[TLB_SIZE][ASID];
-static inline void invalidate_all_tlb(ARMul_State *state){
- memset(&tlb_entry_array[0], 0xFF, sizeof(uint32_t) * TLB_SIZE * ASID);
-}
-static inline void invalidate_by_mva(ARMul_State *state, ARMword va){
- memset(&tlb_entry_array[va >> 12][va & 0xFF], 0xFF, sizeof(uint32_t));
- return;
-}
-static inline void invalidate_by_asid(ARMul_State *state, ARMword asid){
- int i;
- for(i = 0; i < TLB_SIZE; i++)
- memset(&tlb_entry_array[i][asid & 0xFF], 0xFF, sizeof(uint32_t));
- return;
-}
-
-static uint32_t get_phys_page(ARMul_State* state, ARMword va){
- uint32_t phys_page = tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF];
- //printf("In %s, for va=0x%x, page=0x%x\n", __func__, va, phys_page);
- return phys_page;
-}
-
-static inline void insert_tlb(ARMul_State* state, ARMword va, ARMword pa){
- //printf("In %s, insert va=0x%x, pa=0x%x\n", __FUNCTION__, va, pa);
- //printf("In %s, insert va=0x%x, va>>12=0x%x, pa=0x%x, pa>>12=0x%x\n", __FUNCTION__, va, va >> 12, pa, pa >> 12);
- tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF] = pa >> 12;
-
- return;
-}
-#endif
-#define BANK0_START 0x50000000
-static void* mem_ptr = NULL;
-
-static int exclusive_detect(ARMul_State* state, ARMword addr){
- #if 0
- for(int i = 0; i < 128; i++){
- if(state->exclusive_tag_array[i] == addr)
- return 0;
- }
- #endif
- if(state->exclusive_tag_array[0] == addr)
- return 0;
- else
- return -1;
-}
-
-static void add_exclusive_addr(ARMul_State* state, ARMword addr){
- #if 0
- for(int i = 0; i < 128; i++){
- if(state->exclusive_tag_array[i] == 0xffffffff){
- state->exclusive_tag_array[i] = addr;
- //printf("In %s, add addr 0x%x\n", __func__, addr);
- return;
- }
- }
- printf("In %s ,can not monitor the addr, out of array\n", __FUNCTION__);
- #endif
- state->exclusive_tag_array[0] = addr;
- return;
-}
-
-static void remove_exclusive(ARMul_State* state, ARMword addr){
- #if 0
- int i;
- for(i = 0; i < 128; i++){
- if(state->exclusive_tag_array[i] == addr){
- state->exclusive_tag_array[i] = 0xffffffff;
- //printf("In %s, remove addr 0x%x\n", __func__, addr);
- return;
- }
- }
- #endif
- state->exclusive_tag_array[0] = 0xFFFFFFFF;
-}
-
-/* This function encodes table 8-2 Interpreting AP bits,
- returning non-zero if access is allowed. */
-static int
-check_perms (ARMul_State *state, int ap, int read)
-{
- int s, r, user;
-
- s = state->mmu.control & CONTROL_SYSTEM;
- r = state->mmu.control & CONTROL_ROM;
- /* chy 2006-02-15 , should consider system mode, don't conside 26bit mode */
-// printf("ap is %x, user is %x, s is %x, read is %x\n", ap, user, s, read);
-// printf("mode is %x\n", state->Mode);
- user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE);
-
- switch (ap) {
- case 0:
- return read && ((s && !user) || r);
- case 1:
- return !user;
- case 2:
- return read || !user;
- case 3:
- return 1;
- }
- return 0;
-}
-
-#if 0
-fault_t
-check_access (ARMul_State *state, ARMword virt_addr, tlb_entry_t *tlb,
- int read)
-{
- int access;
-
- state->mmu.last_domain = tlb->domain;
- access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3;
- if ((access == 0) || (access == 2)) {
- /* It's unclear from the documentation whether this
- should always raise a section domain fault, or if
- it should be a page domain fault in the case of an
- L1 that describes a page table. In the ARM710T
- datasheets, "Figure 8-9: Sequence for checking faults"
- seems to indicate the former, while "Table 8-4: Priority
- encoding of fault status" gives a value for FS[3210] in
- the event of a domain fault for a page. Hmm. */
- return SECTION_DOMAIN_FAULT;
- }
- if (access == 1) {
- /* client access - check perms */
- int subpage, ap;
-#if 0
- switch (tlb->mapping) {
- /*ks 2004-05-09
- * only for XScale
- * Extend Small Page(ESP) Format
- * 31-12 bits the base addr of ESP
- * 11-10 bits SBZ
- * 9-6 bits TEX
- * 5-4 bits AP
- * 3 bit C
- * 2 bit B
- * 1-0 bits 11
- * */
- case TLB_ESMALLPAGE: /* xj */
- subpage = 0;
- /* printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); */
- break;
-
- case TLB_TINYPAGE:
- subpage = 0;
- /* printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); */
- break;
-
- case TLB_SMALLPAGE:
- subpage = (virt_addr >> 10) & 3;
- break;
- case TLB_LARGEPAGE:
- subpage = (virt_addr >> 14) & 3;
- break;
- case TLB_SECTION:
- subpage = 3;
- break;
- default:
- assert (0);
- subpage = 0; /* cleans a warning */
- }
- ap = (tlb->perms >> (subpage * 2 + 4)) & 3;
- if (!check_perms (state, ap, read)) {
- if (tlb->mapping == TLB_SECTION) {
- return SECTION_PERMISSION_FAULT;
- } else {
- return SUBPAGE_PERMISSION_FAULT;
- }
- }
-#endif
- } else { /* access == 3 */
- /* manager access - don't check perms */
- }
- return NO_FAULT;
-}
-#endif
-
-#if 0
-fault_t
-mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr)
-#endif
-
-/* ap: AP bits value.
- * sop: section or page description 0:section 1:page
- */
-fault_t
-mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr, int *ap, int *sop)
-{
- {
- /* walk the translation tables */
- ARMword l1addr, l1desc;
- if (state->mmu.translation_table_ctrl && virt_addr << state->mmu.translation_table_ctrl >> (32 - state->mmu.translation_table_ctrl - 1)) {
- l1addr = state->mmu.translation_table_base1;
- l1addr = (((l1addr >> 14) << 14) | (virt_addr >> 18)) & ~3;
- } else {
- l1addr = state->mmu.translation_table_base0;
- l1addr = (((l1addr >> (14 - state->mmu.translation_table_ctrl)) << (14 - state->mmu.translation_table_ctrl)) | (virt_addr << state->mmu.translation_table_ctrl) >> (18 + state->mmu.translation_table_ctrl)) & ~3;
- }
-
- /* l1desc = mem_read_word (state, l1addr); */
- if (state->space.conf_obj != NULL)
- state->space.read(state->space.conf_obj, l1addr, &l1desc, 4);
- else
- l1desc = Memory::Read32(l1addr); //mem_read_raw(32, l1addr, &l1desc);
-
- #if 0
- if (virt_addr == 0xc000d2bc) {
- printf("mmu_control is %x\n", state->mmu.translation_table_ctrl);
- printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0);
- printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1);
- printf("l1addr is %x l1desc is %x\n", l1addr, l1desc);
- // exit(-1);
- }
- #endif
- switch (l1desc & 3) {
- case 0:
- case 3:
- /*
- * according to Figure 3-9 Sequence for checking faults in arm manual,
- * section translation fault should be returned here.
- */
- {
- return SECTION_TRANSLATION_FAULT;
- }
- case 1:
- /* coarse page table */
- {
- ARMword l2addr, l2desc;
-
-
- l2addr = l1desc & 0xFFFFFC00;
- l2addr = (l2addr |
- ((virt_addr & 0x000FF000) >> 10)) &
- ~3;
- if(state->space.conf_obj != NULL)
- state->space.read(state->space.conf_obj, l2addr, &l2desc, 4);
- else
- l2desc = Memory::Read32(l2addr); //mem_read_raw(32, l2addr, &l2desc);
-
- /* chy 2003-09-02 for xscale */
- *ap = (l2desc >> 4) & 0x3;
- *sop = 1; /* page */
-
- switch (l2desc & 3) {
- case 0:
- return PAGE_TRANSLATION_FAULT;
- break;
- case 1:
- *phys_addr = (l2desc & 0xFFFF0000) | (virt_addr & 0x0000FFFF);
- break;
- case 2:
- case 3:
- *phys_addr = (l2desc & 0xFFFFF000) | (virt_addr & 0x00000FFF);
- break;
-
- }
- }
- break;
- case 2:
- /* section */
-
- *ap = (l1desc >> 10) & 3;
- *sop = 0; /* section */
- #if 0
- if (virt_addr == 0xc000d2bc) {
- printf("mmu_control is %x\n", state->mmu.translation_table_ctrl);
- printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0);
- printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1);
- printf("l1addr is %x l1desc is %x\n", l1addr, l1desc);
-// printf("l2addr is %x l2desc is %x\n", l2addr, l2desc);
- printf("ap is %x, sop is %x\n", *ap, *sop);
- printf("mode is %d\n", state->Mode);
-// exit(-1);
- }
- #endif
-
- if (l1desc & 0x30000)
- *phys_addr = (l1desc & 0xFF000000) | (virt_addr & 0x00FFFFFF);
- else
- *phys_addr = (l1desc & 0xFFF00000) | (virt_addr & 0x000FFFFF);
- break;
- }
- }
- return NO_FAULT;
-}
-
-
-static fault_t arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va,
- ARMword data, ARMword datatype);
-static fault_t arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va,
- ARMword *data, ARMword datatype);
-
-int
-arm1176jzf_s_mmu_init (ARMul_State *state)
-{
- state->mmu.control = 0x50078;
- state->mmu.translation_table_base = 0xDEADC0DE;
- state->mmu.domain_access_control = 0xDEADC0DE;
- state->mmu.fault_status = 0;
- state->mmu.fault_address = 0;
- state->mmu.process_id = 0;
- state->mmu.context_id = 0;
- state->mmu.thread_uro_id = 0;
- //invalidate_all_tlb(state);
-
- return No_exp;
-}
-
-void
-arm1176jzf_s_mmu_exit (ARMul_State *state)
-{
-}
-
-
-static fault_t
-arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr)
-{
- fault_t fault;
- int c; /* cache bit */
- ARMword pa; /* physical addr */
- ARMword perm; /* physical addr access permissions */
- int ap, sop;
-
- static int debug_count = 0; /* used for debug */
-
- //DEBUG_LOG(ARM11, "va = %x\n", va);
-
- va = mmu_pid_va_map (va);
- if (MMU_Enabled) {
-// printf("MMU enabled.\n");
-// sleep(1);
- /* align check */
- if ((va & (WORD_SIZE - 1)) && MMU_Aligned) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- } else
- va &= ~(WORD_SIZE - 1);
-
- /* translate tlb */
- fault = mmu_translate (state, va, &pa, &ap, &sop);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- printf("va=0x%x, icounter=%lld, fault=%d\n", va, state->NumInstrs, fault);
- return fault;
- }
-
-
- /* no tlb, only check permission */
- if (!check_perms(state, ap, 1)) {
- if (sop == 0) {
- return SECTION_PERMISSION_FAULT;
- } else {
- return SUBPAGE_PERMISSION_FAULT;
- }
- }
-
-#if 0
- /*check access */
- fault = check_access (state, va, tlb, 1);
- if (fault) {
- DEBUG_LOG(ARM11, "check_fault\n");
- return fault;
- }
-#endif
- }
-
- /*if MMU disabled or C flag is set alloc cache */
- if (MMU_Disabled) {
-// printf("MMU disabled.\n");
-// sleep(1);
- pa = va;
- }
- if(state->space.conf_obj == NULL)
- state->space.read(state->space.conf_obj, pa, instr, 4);
- else
- *instr = Memory::Read32(pa); //mem_read_raw(32, pa, instr);
-
- return NO_FAULT;
-}
-
-static fault_t
-arm1176jzf_s_mmu_read_byte (ARMul_State *state, ARMword virt_addr, ARMword *data)
-{
- /* ARMword temp,offset; */
- fault_t fault;
- fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE);
- return fault;
-}
-
-static fault_t
-arm1176jzf_s_mmu_read_halfword (ARMul_State *state, ARMword virt_addr,
- ARMword *data)
-{
- /* ARMword temp,offset; */
- fault_t fault;
- fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE);
- return fault;
-}
-
-static fault_t
-arm1176jzf_s_mmu_read_word (ARMul_State *state, ARMword virt_addr, ARMword *data)
-{
- return arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);
-}
-
-static fault_t
-arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data,
- ARMword datatype)
-{
- fault_t fault;
- ARMword pa, real_va, temp, offset;
- ARMword perm; /* physical addr access permissions */
- int ap, sop;
-
- //DEBUG_LOG(ARM11, "va = %x\n", va);
-
- va = mmu_pid_va_map (va);
- real_va = va;
- /* if MMU disabled, memory_read */
- if (MMU_Disabled) {
-// printf("MMU disabled cpu_id:%x addr:%x.\n", state->mmu.process_id, va);
-// sleep(1);
-
- /* *data = mem_read_word(state, va); */
- if (datatype == ARM_BYTE_TYPE)
- /* *data = mem_read_byte (state, va); */
- if(state->space.conf_obj != NULL)
- state->space.read(state->space.conf_obj, va, data, 1);
- else
- *data = Memory::Read8(va); //mem_read_raw(8, va, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- /* *data = mem_read_halfword (state, va); */
- if(state->space.conf_obj != NULL)
- state->space.read(state->space.conf_obj, va, data, 2);
- else
- *data = Memory::Read16(va); //mem_read_raw(16, va, data);
- else if (datatype == ARM_WORD_TYPE)
- /* *data = mem_read_word (state, va); */
- if(state->space.conf_obj != NULL)
- state->space.read(state->space.conf_obj, va, data, 4);
- else
- *data = Memory::Read32(va); //mem_read_raw(32, va, data);
- else {
- ERROR_LOG(ARM11, "SKYEYE:1 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype);
- }
-
- return NO_FAULT;
- }
-// printf("MMU enabled.\n");
-// sleep(1);
-
- /* align check */
- if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
- ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- }
-
- /* va &= ~(WORD_SIZE - 1); */
- #if 0
- uint32_t page_base;
- page_base = get_phys_page(state, va);
- if((page_base & 0xFFF) == 0){
- pa = (page_base << 12) | (va & 0xFFF);
- goto skip_translation;
- }
- #endif
- /*translate va to tlb */
-#if 0
- fault = mmu_translate (state, va, ARM920T_D_TLB (), &tlb);
-#endif
- fault = mmu_translate (state, va, &pa, &ap, &sop);
-#if 0
- if(va ==0xbebb1774 || state->Reg[15] == 0x400ff594){
- //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]);
- printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data);
- int i;
- for(i = 0; i < 16; i++)
- printf("Reg[%d]=0x%x\t", i, state->Reg[i]);
- printf("\n");
- }
-#endif
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- //printf("mmu read fault at %x\n", va);
- //printf("fault is %d\n", fault);
- return fault;
- }
-// printf("va is %x pa is %x\n", va, pa);
-
- /* no tlb, only check permission */
- if (!check_perms(state, ap, 1)) {
- if (sop == 0) {
- return SECTION_PERMISSION_FAULT;
- } else {
- return SUBPAGE_PERMISSION_FAULT;
- }
- }
-#if 0
- /*check access permission */
- fault = check_access (state, va, tlb, 1);
- if (fault)
- return fault;
-#endif
-
- //insert_tlb(state, va, pa);
-skip_translation:
- /* *data = mem_read_word(state, pa); */
- if (datatype == ARM_BYTE_TYPE) {
- /* *data = mem_read_byte (state, pa | (real_va & 3)); */
- if(state->space.conf_obj != NULL)
- state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 1);
- else
- *data = Memory::Read8(pa | (real_va & 3)); //mem_read_raw(8, pa | (real_va & 3), data);
- /* mem_read_raw(32, pa | (real_va & 3), data); */
- } else if (datatype == ARM_HALFWORD_TYPE) {
- /* *data = mem_read_halfword (state, pa | (real_va & 2)); */
- if(state->space.conf_obj != NULL)
- state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 2);
- else
- *data = Memory::Read16(pa | (real_va & 3)); //mem_read_raw(16, pa | (real_va & 3), data);
- /* mem_read_raw(32, pa | (real_va & 2), data); */
- } else if (datatype == ARM_WORD_TYPE)
- /* *data = mem_read_word (state, pa); */
- if(state->space.conf_obj != NULL)
- state->space.read(state->space.conf_obj, pa , data, 4);
- else
- *data = Memory::Read32(pa); //mem_read_raw(32, pa, data);
- else {
- ERROR_LOG(ARM11, "SKYEYE:2 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype);
- }
- if(0 && (va == 0x2869c)){
- printf("In %s, pa is %x va=0x%x, value is %x pc %x, instr=0x%x\n", __FUNCTION__, pa, va, *data, state->Reg[15], state->CurrInstr);
- }
-
- /* ldrex or ldrexb */
- if(((state->CurrInstr & 0x0FF000F0) == 0x01900090) ||
- ((state->CurrInstr & 0x0FF000F0) == 0x01d00090)){
- int rn = (state->CurrInstr & 0xF0000) >> 16;
- if(state->Reg[rn] == va){
- add_exclusive_addr(state, pa | (real_va & 3));
- state->exclusive_access_state = 1;
- }
- }
-#if 0
- if (state->pc == 0xc011a868) {
- printf("pa is %x value is %x size is %x\n", pa, data, datatype);
- printf("icounter is %lld\n", state->NumInstrs);
-// exit(-1);
- }
-#endif
-
- return NO_FAULT;
-}
-
-
-static fault_t
-arm1176jzf_s_mmu_write_byte (ARMul_State *state, ARMword virt_addr, ARMword data)
-{
- return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);
-}
-
-static fault_t
-arm1176jzf_s_mmu_write_halfword (ARMul_State *state, ARMword virt_addr,
- ARMword data)
-{
- return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);
-}
-
-static fault_t
-arm1176jzf_s_mmu_write_word (ARMul_State *state, ARMword virt_addr, ARMword data)
-{
- return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);
-}
-
-
-
-static fault_t
-arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data,
- ARMword datatype)
-{
- int b;
- ARMword pa, real_va;
- ARMword perm; /* physical addr access permissions */
- fault_t fault;
- int ap, sop;
-
-#if 0
- /8 for sky_printk debugger.*/
- if (va == 0xffffffff) {
- putchar((char)data);
- return 0;
- }
- if (va == 0xBfffffff) {
- putchar((char)data);
- return 0;
- }
-#endif
-
- //DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data);
- va = mmu_pid_va_map (va);
- real_va = va;
-
- if (MMU_Disabled) {
- /* mem_write_word(state, va, data); */
- if (datatype == ARM_BYTE_TYPE)
- /* mem_write_byte (state, va, data); */
- if(state->space.conf_obj != NULL)
- state->space.write(state->space.conf_obj, va, &data, 1);
- else
- Memory::Write8(va, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- /* mem_write_halfword (state, va, data); */
- if(state->space.conf_obj != NULL)
- state->space.write(state->space.conf_obj, va, &data, 2);
- else
- Memory::Write16(va, data);
- else if (datatype == ARM_WORD_TYPE)
- /* mem_write_word (state, va, data); */
- if(state->space.conf_obj != NULL)
- state->space.write(state->space.conf_obj, va, &data, 4);
- else
- Memory::Write32(va, data);
- else {
- ERROR_LOG (ARM11, "SKYEYE:1 arm1176jzf_s_mmu_write error: unknown data type %d\n", datatype);
- }
- goto finished_write;
- //return 0;
- }
- /*align check */
- /* if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ */
- if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
- ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- }
- va &= ~(WORD_SIZE - 1);
- #if 0
- uint32_t page_base;
- page_base = get_phys_page(state, va);
- if((page_base & 0xFFF) == 0){
- pa = (page_base << 12) | (va & 0xFFF);
- goto skip_translation;
- }
- #endif
- /*tlb translate */
- fault = mmu_translate (state, va, &pa, &ap, &sop);
-#if 0
- if(va ==0xbebb1774 || state->Reg[15] == 0x40102334){
- //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]);
- printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data);
- int i;
- for(i = 0; i < 16; i++)
- printf("Reg[%d]=0x%x\t", i, state->Reg[i]);
- printf("\n");
- }
-#endif
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- //printf("mmu write fault at %x\n", va);
- return fault;
- }
-// printf("va is %x pa is %x\n", va, pa);
-
- /* no tlb, only check permission */
- if (!check_perms(state, ap, 0)) {
- if (sop == 0) {
- return SECTION_PERMISSION_FAULT;
- } else {
- return SUBPAGE_PERMISSION_FAULT;
- }
- }
-
-#if 0
- /* tlb check access */
- fault = check_access (state, va, tlb, 0);
- if (fault) {
- DEBUG_LOG(ARM11, "check_access\n");
- return fault;
- }
-#endif
-#if 0
- if (pa <= 0x502860ff && (pa + 1 << datatype) > 0x502860ff) {
- printf("pa is %x value is %x size is %x\n", pa, data, datatype);
- }
-#endif
-#if 0
- if (state->pc == 0xc011a878) {
- printf("write pa is %x value is %x size is %x\n", pa, data, datatype);
- printf("icounter is %lld\n", state->NumInstrs);
- exit(-1);
- }
-#endif
- //insert_tlb(state, va, pa);
-skip_translation:
- /* strex */
- if(((state->CurrInstr & 0x0FF000F0) == 0x01800090) ||
- ((state->CurrInstr & 0x0FF000F0) == 0x01c00090)){
- /* failed , the address is monitord now. */
- int dest_reg = (state->CurrInstr & 0xF000) >> 12;
- if((exclusive_detect(state, pa | (real_va & 3)) == 0) && (state->exclusive_access_state == 1)){
- remove_exclusive(state, pa | (real_va & 3));
- state->Reg[dest_reg] = 0;
- state->exclusive_access_state = 0;
- }
- else{
- state->Reg[dest_reg] = 1;
- //printf("In %s, try to strex a monitored address 0x%x\n", __FUNCTION__, pa);
- return NO_FAULT;
- }
- }
-
- if (datatype == ARM_BYTE_TYPE) {
- /* mem_write_byte (state,
- (pa | (real_va & 3)),
- data);
- */
- if(state->space.conf_obj != NULL)
- state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 1);
- else
- Memory::Write8((pa | (real_va & 3)), data);
-
- } else if (datatype == ARM_HALFWORD_TYPE)
- /* mem_write_halfword (state,
- (pa |
- (real_va & 2)),
- data);
- */
- if(state->space.conf_obj != NULL)
- state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 2);
- else
- Memory::Write16((pa | (real_va & 3)), data);
- else if (datatype == ARM_WORD_TYPE)
- /* mem_write_word (state, pa, data); */
- if(state->space.conf_obj != NULL)
- state->space.write(state->space.conf_obj, pa, &data, 4);
- else
- Memory::Write32(pa, data);
-#if 0
- if (state->NumInstrs > 236403) {
- printf("write memory\n");
- printf("pa is %x value is %x size is %x\n", pa, data, datatype);
- printf("icounter is %lld\n", state->NumInstrs);
- }
-#endif
-finished_write:
-#if DIFF_WRITE
- if(state->icounter > state->debug_icounter){
- if(state->CurrWrite >= 17 ){
- printf("Wrong write array, 0x%x", state->CurrWrite);
- exit(-1);
- }
- uint32 record_data = data;
- if(datatype == ARM_BYTE_TYPE)
- record_data &= 0xFF;
- if(datatype == ARM_HALFWORD_TYPE)
- record_data &= 0xFFFF;
-
- state->WriteAddr[state->CurrWrite] = pa | (real_va & 3);
- state->WriteData[state->CurrWrite] = record_data;
- state->WritePc[state->CurrWrite] = state->Reg[15];
- state->CurrWrite++;
- //printf("In %s, pc=0x%x, addr=0x%x, data=0x%x, CFlag=%d\n", __FUNCTION__, state->Reg[15], pa | (real_va & 3), record_data, state->CFlag);
- }
-#endif
-
- return NO_FAULT;
-}
-
-ARMword
-arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value)
-{
- int creg = BITS (16, 19) & 0xf;
- int OPC_1 = BITS (21, 23) & 0x7;
- int OPC_2 = BITS (5, 7) & 0x7;
- ARMword data;
-
- switch (creg) {
- case MMU_ID:
- if (OPC_2 == 0) {
- data = state->cpu->cpu_val;
- } else if (OPC_2 == 1) {
- /* Cache type:
- * 000 0110 1 000 101 110 0 10 000 101 110 0 10
- * */
- data = 0x0D172172;
- }
- break;
- case MMU_CONTROL:
- /*
- * 6:3 read as 1
- * 10 read as 0
- * 18,16 read as 1
- * */
- data = (state->mmu.control | 0x50078) & 0xFFFFFBFF;
- break;
- case MMU_TRANSLATION_TABLE_BASE:
-#if 0
- data = state->mmu.translation_table_base;
-#endif
- switch (OPC_2) {
- case 0:
- data = state->mmu.translation_table_base0;
- break;
- case 1:
- data = state->mmu.translation_table_base1;
- break;
- case 2:
- data = state->mmu.translation_table_ctrl;
- break;
- default:
- printf ("mmu_mrc read UNKNOWN - p15 c2 opcode2 %d\n", OPC_2);
- break;
- }
- break;
- case MMU_DOMAIN_ACCESS_CONTROL:
- data = state->mmu.domain_access_control;
- break;
- case MMU_FAULT_STATUS:
- /* OPC_2 = 0: data FSR value
- * */
- if (OPC_2 == 0)
- data = state->mmu.fault_status;
- if (OPC_2 == 1)
- data = state->mmu.fault_statusi;
- break;
- case MMU_FAULT_ADDRESS:
- data = state->mmu.fault_address;
- break;
- case MMU_PID:
- //data = state->mmu.process_id;
- if(OPC_2 == 0)
- data = state->mmu.process_id;
- else if(OPC_2 == 1)
- data = state->mmu.context_id;
- else if(OPC_2 == 3){
- data = state->mmu.thread_uro_id;
- }
- else{
- printf ("mmu_mcr read UNKNOWN - reg %d\n", creg);
- }
- //printf("SKYEYE In %s, read pid 0x%x, OPC_2 %d, instr=0x%x\n", __FUNCTION__, data, OPC_2, instr);
- //exit(-1);
- break;
- default:
- printf ("mmu_mrc read UNKNOWN - reg %d\n", creg);
- data = 0;
- break;
- }
-/* printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); */
- *value = data;
- return data;
-}
-
-
-static ARMword
-arm1176jzf_s_mmu_mcr (ARMul_State *state, ARMword instr, ARMword value)
-{
- int creg = BITS (16, 19) & 0xf;
- int CRm = BITS (0, 3) & 0xf;
- int OPC_1 = BITS (21, 23) & 0x7;
- int OPC_2 = BITS (5, 7) & 0x7;
- if (!strncmp (state->cpu->cpu_arch_name, "armv6", 5)) {
- switch (creg) {
- case MMU_CONTROL:
- /*
- * 6:3 read as 1
- * 10 read as 0
- * 18,16 read as 1
- * */
- if(OPC_2 == 0)
- state->mmu.control = (value | 0x50078) & 0xFFFFFBFF;
- else if(OPC_2 == 1)
- state->mmu.auxiliary_control = value;
- else if(OPC_2 == 2)
- state->mmu.coprocessor_access_control = value;
- else
- fprintf(stderr, "In %s, wrong OPC_2 %d\n", __FUNCTION__, OPC_2);
- break;
- case MMU_TRANSLATION_TABLE_BASE:
- switch (OPC_2) {
- /* int i; */
- case 0:
-#if 0
- /* TTBR0 */
- if (state->mmu.translation_table_ctrl & 0x7) {
- for (i = 0; i <= state->mmu.translation_table_ctrl; i++)
- state->mmu.translation_table_base0 &= ~(1 << (5 + i));
- }
-#endif
- state->mmu.translation_table_base0 = (value);
- break;
- case 1:
-#if 0
- /* TTBR1 */
- if (state->mmu.translation_table_ctrl & 0x7) {
- for (i = 0; i <= state->mmu.translation_table_ctrl; i++)
- state->mmu.translation_table_base1 &= 1 << (5 + i);
- }
-#endif
- state->mmu.translation_table_base1 = (value);
- break;
- case 2:
- /* TTBC */
- state->mmu.translation_table_ctrl = value & 0x7;
- break;
- default:
- printf ("mmu_mcr wrote UNKNOWN - cp15 c2 opcode2 %d\n", OPC_2);
- break;
- }
- //printf("SKYEYE In %s, write TLB_BASE 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr);
- //invalidate_all_tlb(state);
- break;
- case MMU_DOMAIN_ACCESS_CONTROL:
- /* printf("mmu_mcr wrote DACR "); */
- state->mmu.domain_access_control = value;
- break;
-
- case MMU_FAULT_STATUS:
- if (OPC_2 == 0)
- state->mmu.fault_status = value & 0xFF;
- if (OPC_2 == 1) {
- printf("set fault status instr\n");
- }
- break;
- case MMU_FAULT_ADDRESS:
- state->mmu.fault_address = value;
- break;
-
- case MMU_CACHE_OPS:
- break;
- case MMU_TLB_OPS:
- {
- switch(CRm){
- case 5: /* ITLB */
- {
- switch(OPC_2){
- case 0: /* invalidate all */
- //invalidate_all_tlb(state);
- break;
- case 1: /* invalidate by MVA */
- //invalidate_by_mva(state, value);
- break;
- case 2: /* invalidate by asid */
- //invalidate_by_asid(state, value);
- break;
- default:
- printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
- break;
- }
- break;
- }
- case 6: /* DTLB */
- {
- switch(OPC_2){
- case 0: /* invalidate all */
- //invalidate_all_tlb(state);
- break;
- case 1: /* invalidate by MVA */
- //invalidate_by_mva(state, value);
- break;
- case 2: /* invalidate by asid */
- //invalidate_by_asid(state, value);
- break;
- default:
- printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
- break;
- }
- break;
- }
- case 7: /* Unified TLB */
- {
- switch(OPC_2){
- case 0: /* invalidate all */
- //invalidate_all_tlb(state);
- break;
- case 1: /* invalidate by MVA */
- //invalidate_by_mva(state, value);
- break;
- case 2: /* invalidate by asid */
- //invalidate_by_asid(state, value);
- break;
- default:
- printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
- break;
- }
- break;
- }
-
- default:
- printf ("mmu_mcr wrote UNKNOWN - reg %d, CRm=%d\n", creg, CRm);
- break;
- }
- //printf("SKYEYE In %s, write TLB 0x%x OPC_1=%d, OPC_2=%d , CRm=%d instr=0x%x\n", __FUNCTION__, value, OPC_1, OPC_2, CRm, instr);
- }
- break;
- case MMU_CACHE_LOCKDOWN:
- /*
- * FIXME: cache lock down*/
- break;
- case MMU_TLB_LOCKDOWN:
- printf("SKYEYE In %s, write TLB_LOCKDOWN 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr);
- /* FIXME:tlb lock down */
- break;
- case MMU_PID:
- //printf("SKYEYE In %s, write pid 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr);
- //state->mmu.process_id = value;
- /*0:24 should be zero. */
- //state->mmu.process_id = value & 0xfe000000;
- if(OPC_2 == 0)
- state->mmu.process_id = value;
- else if(OPC_2 == 1)
- state->mmu.context_id = value;
- else if(OPC_2 == 3){
- state->mmu.thread_uro_id = value;
- }
- else{
- printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
- }
- break;
-
- default:
- printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
- break;
- }
- }
-
- return No_exp;
-}
-
-///* teawater add for arm2x86 2005.06.19------------------------------------------- */
-//static int
-//arm1176jzf_s_mmu_v2p_dbct (ARMul_State *state, ARMword virt_addr,
-// ARMword *phys_addr)
-//{
-// fault_t fault;
-// int ap, sop;
-//
-// ARMword perm; /* physical addr access permissions */
-// virt_addr = mmu_pid_va_map (virt_addr);
-// if (MMU_Enabled) {
-//
-// /*align check */
-// if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) {
-// DEBUG_LOG(ARM11, "align\n");
-// return ALIGNMENT_FAULT;
-// } else
-// virt_addr &= ~(WORD_SIZE - 1);
-//
-// /*translate tlb */
-// fault = mmu_translate (state, virt_addr, phys_addr, &ap, &sop);
-// if (fault) {
-// DEBUG_LOG(ARM11, "translate\n");
-// return fault;
-// }
-//
-// /* permission check */
-// if (!check_perms(state, ap, 1)) {
-// if (sop == 0) {
-// return SECTION_PERMISSION_FAULT;
-// } else {
-// return SUBPAGE_PERMISSION_FAULT;
-// }
-// }
-//#if 0
-// /*check access */
-// fault = check_access (state, virt_addr, tlb, 1);
-// if (fault) {
-// DEBUG_LOG(ARM11, "check_fault\n");
-// return fault;
-// }
-//#endif
-// }
-//
-// if (MMU_Disabled) {
-// *phys_addr = virt_addr;
-// }
-//
-// return 0;
-//}
-
-/* AJ2D-------------------------------------------------------------------------- */
-
-/*arm1176jzf-s mmu_ops_t*/
-mmu_ops_t arm1176jzf_s_mmu_ops = {
- arm1176jzf_s_mmu_init,
- arm1176jzf_s_mmu_exit,
- arm1176jzf_s_mmu_read_byte,
- arm1176jzf_s_mmu_write_byte,
- arm1176jzf_s_mmu_read_halfword,
- arm1176jzf_s_mmu_write_halfword,
- arm1176jzf_s_mmu_read_word,
- arm1176jzf_s_mmu_write_word,
- arm1176jzf_s_mmu_load_instr,
- arm1176jzf_s_mmu_mcr,
- arm1176jzf_s_mmu_mrc
-/* teawater add for arm2x86 2005.06.19------------------------------------------- */
-/* arm1176jzf_s_mmu_v2p_dbct, */
-/* AJ2D-------------------------------------------------------------------------- */
-};
diff --git a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h
deleted file mode 100644
index 299c6b46b..000000000
--- a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- arm1176JZF-S_mmu.h - ARM1176JZF-S Memory Management Unit emulation.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _ARM1176JZF_S_MMU_H_
-#define _ARM1176JZF_S_MMU_H_
-
-#if 0
-typedef struct arm1176jzf-s_mmu_s
-{
- tlb_t i_tlb;
- cache_t i_cache;
-
- tlb_t d_tlb;
- cache_t d_cache;
- wb_t wb_t;
-} arm1176jzf-s_mmu_t;
-#endif
-extern mmu_ops_t arm1176jzf_s_mmu_ops;
-
-ARMword
-arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value);
-#endif /*_ARM1176JZF_S_MMU_H_*/
diff --git a/src/core/arm/interpreter/mmu/cache.cpp b/src/core/arm/interpreter/mmu/cache.cpp
deleted file mode 100644
index f3c4e0531..000000000
--- a/src/core/arm/interpreter/mmu/cache.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-#include "core/arm/interpreter/armdefs.h"
-
-/* mmu cache init
- *
- * @cache_t :cache_t to init
- * @width :cache line width in byte
- * @way :way of each cache set
- * @set :cache set num
- *
- * $ -1: error
- * 0: sucess
- */
-int
-mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode)
-{
- int i, j;
- cache_set_t *sets;
- cache_line_t *lines;
-
- /*alloc cache set */
- sets = NULL;
- lines = NULL;
- //fprintf(stderr, "mmu_cache_init: mallloc beg size %d,sets 0x%x\n", sizeof(cache_set_t) * set,sets);
- //exit(-1);
- sets = (cache_set_t *) malloc (sizeof (cache_set_t) * set);
- if (sets == NULL) {
- ERROR_LOG(ARM11, "set malloc size %d\n", sizeof (cache_set_t) * set);
- goto sets_error;
- }
- //fprintf(stderr, "mmu_cache_init: mallloc end sets 0x%x\n", sets);
- cache_t->sets = sets;
-
- /*init cache set */
- for (i = 0; i < set; i++) {
- /*alloc cache line */
- lines = (cache_line_t *) malloc (sizeof (cache_line_t) * way);
- if (lines == NULL) {
- ERROR_LOG(ARM11, "line malloc size %d\n",
- sizeof (cache_line_t) * way);
- goto lines_error;
- }
- /*init cache line */
- for (j = 0; j < way; j++) {
- lines[j].tag = 0; //invalid
- lines[j].data = (ARMword *) malloc (width);
- if (lines[j].data == NULL) {
- ERROR_LOG(ARM11, "data alloc size %d\n", width);
- goto data_error;
- }
- }
-
- sets[i].lines = lines;
- sets[i].cycle = 0;
-
- }
- cache_t->width = width;
- cache_t->set = set;
- cache_t->way = way;
- cache_t->w_mode = w_mode;
- return 0;
-
- data_error:
- /*free data */
- while (j-- > 0)
- free (lines[j].data);
- /*free data error line */
- free (lines);
- lines_error:
- /*free lines already alloced */
- while (i-- > 0) {
- for (j = 0; j < way; j++)
- free (sets[i].lines[j].data);
- free (sets[i].lines);
- }
- /*free sets */
- free (sets);
- sets_error:
- return -1;
-};
-
-/* free a cache_t's inner data, the ptr self is not freed,
- * when needed do like below:
- * mmu_cache_exit(cache);
- * free(cache_t);
- *
- * @cache_t : the cache_t to free
- */
-
-void
-mmu_cache_exit (cache_s * cache_t)
-{
- int i, j;
- cache_set_t *sets, *set;
- cache_line_t *lines, *line;
-
- /*free all set */
- sets = cache_t->sets;
- for (set = sets, i = 0; i < cache_t->set; i++, set++) {
- /*free all line */
- lines = set->lines;
- for (line = lines, j = 0; j < cache_t->way; j++, line++)
- free (line->data);
- free (lines);
- }
- free (sets);
-}
-
-/* mmu cache search
- *
- * @state :ARMul_State
- * @cache_t :cache_t to search
- * @va :virtual address
- *
- * $ NULL: no cache match
- * cache :cache matched
- */
-cache_line_t *
-mmu_cache_search (ARMul_State * state, cache_s * cache_t, ARMword va)
-{
- int i;
- int set = va_cache_set (va, cache_t);
- ARMword tag = va_cache_align (va, cache_t);
- cache_line_t *cache;
-
- cache_set_t *cache_set = cache_t->sets + set;
- for (i = 0, cache = cache_set->lines; i < cache_t->way; i++, cache++) {
- if ((cache->tag & TAG_VALID_FLAG)
- && (tag == va_cache_align (cache->tag, cache_t)))
- return cache;
- }
- return NULL;
-}
-
-/* mmu cache search by set/index
- *
- * @state :ARMul_State
- * @cache_t :cache_t to search
- * @index :set/index value.
- *
- * $ NULL: no cache match
- * cache :cache matched
- */
-cache_line_t *
-mmu_cache_search_by_index (ARMul_State * state, cache_s * cache_t,
- ARMword index)
-{
- int way = cache_t->way;
- int set_v = index_cache_set (index, cache_t);
- int i = 0, index_v = 0;
- cache_set_t *set;
-
- while ((way >>= 1) >= 1)
- i++;
- index_v = index >> (32 - i);
- set = cache_t->sets + set_v;
-
- return set->lines + index_v;
-}
-
-
-/* mmu cache alloc
- *
- * @state :ARMul_State
- * @cache_t :cache_t to alloc from
- * @va :virtual address that require cache alloc, need not cache aligned
- * @pa :physical address of va
- *
- * $ cache_alloced, always alloc OK
- */
-cache_line_t *
-mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, ARMword va,
- ARMword pa)
-{
- cache_line_t *cache;
- cache_set_t *set;
- int i;
-
- va = va_cache_align (va, cache_t);
- pa = va_cache_align (pa, cache_t);
-
- set = &cache_t->sets[va_cache_set (va, cache_t)];
-
- /*robin-round */
- cache = &set->lines[set->cycle++];
- if (set->cycle == cache_t->way)
- set->cycle = 0;
-
- if (cache_t->w_mode == CACHE_WRITE_BACK) {
- ARMword t;
-
- /*if cache valid, try to write back */
- if (cache->tag & TAG_VALID_FLAG) {
- mmu_cache_write_back (state, cache_t, cache);
- }
- /*read in cache_line */
- t = pa;
- for (i = 0; i < (cache_t->width >> WORD_SHT);
- i++, t += WORD_SIZE) {
- //cache->data[i] = mem_read_word (state, t);
- bus_read(32, t, &cache->data[i]);
- }
- }
- /*store tag and pa */
- cache->tag = va | TAG_VALID_FLAG;
- cache->pa = pa;
-
- return cache;
-};
-
-/* mmu_cache_write_back write cache data to memory
- * @state
- * @cache_t :cache_t of the cache line
- * @cache : cache line
- */
-void
-mmu_cache_write_back (ARMul_State * state, cache_s * cache_t,
- cache_line_t * cache)
-{
- ARMword pa = cache->pa;
- int nw = cache_t->width >> WORD_SHT;
- ARMword *data = cache->data;
- int i;
- int t0, t1, t2;
-
- if ((cache->tag & 1) == 0)
- return;
-
- switch (cache->
- tag & ~1 & (TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY)) {
- case 0:
- return;
- case TAG_FIRST_HALF_DIRTY:
- nw /= 2;
- break;
- case TAG_LAST_HALF_DIRTY:
- nw /= 2;
- pa += nw << WORD_SHT;
- data += nw;
- break;
- case TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY:
- break;
- }
- for (i = 0; i < nw; i++, data++, pa += WORD_SIZE)
- //mem_write_word (state, pa, *data);
- bus_write(32, pa, *data);
-
- cache->tag &= ~(TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY);
-};
-
-
-/* mmu_cache_clean: clean a cache of va in cache_t
- *
- * @state :ARMul_State
- * @cache_t :cache_t to clean
- * @va :virtaul address
- */
-void
-mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va)
-{
- cache_line_t *cache;
-
- cache = mmu_cache_search (state, cache_t, va);
- if (cache)
- mmu_cache_write_back (state, cache_t, cache);
-}
-
-/* mmu_cache_clean_by_index: clean a cache by set/index format value
- *
- * @state :ARMul_State
- * @cache_t :cache_t to clean
- * @va :set/index format value
- */
-void
-mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t,
- ARMword index)
-{
- cache_line_t *cache;
-
- cache = mmu_cache_search_by_index (state, cache_t, index);
- if (cache)
- mmu_cache_write_back (state, cache_t, cache);
-}
-
-/* mmu_cache_invalidate : invalidate a cache of va
- *
- * @state :ARMul_State
- * @cache_t :cache_t to invalid
- * @va :virt_addr to invalid
- */
-void
-mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va)
-{
- cache_line_t *cache;
-
- cache = mmu_cache_search (state, cache_t, va);
- if (cache) {
- mmu_cache_write_back (state, cache_t, cache);
- cache->tag = 0;
- }
-}
-
-/* mmu_cache_invalidate_by_index : invalidate a cache by index format
- *
- * @state :ARMul_State
- * @cache_t :cache_t to invalid
- * @index :set/index data
- */
-void
-mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t,
- ARMword index)
-{
- cache_line_t *cache;
-
- cache = mmu_cache_search_by_index (state, cache_t, index);
- if (cache) {
- mmu_cache_write_back (state, cache_t, cache);
- cache->tag = 0;
- }
-}
-
-/* mmu_cache_invalidate_all
- *
- * @state:
- * @cache_t
- * */
-void
-mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t)
-{
- int i, j;
- cache_set_t *set;
- cache_line_t *cache;
-
- set = cache_t->sets;
- for (i = 0; i < cache_t->set; i++, set++) {
- cache = set->lines;
- for (j = 0; j < cache_t->way; j++, cache++) {
- mmu_cache_write_back (state, cache_t, cache);
- cache->tag = 0;
- }
- }
-};
-
-void
-mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa)
-{
- ARMword set, way;
- cache_line_t *cache;
- pa = (pa / cache_t->width);
- way = pa & (cache_t->way - 1);
- set = (pa / cache_t->way) & (cache_t->set - 1);
- cache = &cache_t->sets[set].lines[way];
-
- mmu_cache_write_back (state, cache_t, cache);
- cache->tag = 0;
-}
-
-cache_line_t* mmu_cache_dirty_cache(ARMul_State *state,cache_s *cache){
- int i;
- int j;
- cache_line_t *cache_line = NULL;
- cache_set_t *cache_set = cache->sets;
- int sets = cache->set;
- for (i = 0; i < sets; i++){
- for(j = 0,cache_line = &cache_set[i].lines[0]; j < cache->way; j++,cache_line++){
- if((cache_line->tag & TAG_FIRST_HALF_DIRTY) || (cache_line->tag & TAG_LAST_HALF_DIRTY))
- return cache_line;
- }
- }
- return NULL;
-}
diff --git a/src/core/arm/interpreter/mmu/cache.h b/src/core/arm/interpreter/mmu/cache.h
deleted file mode 100644
index d308d9b87..000000000
--- a/src/core/arm/interpreter/mmu/cache.h
+++ /dev/null
@@ -1,168 +0,0 @@
-#ifndef _MMU_CACHE_H_
-#define _MMU_CACHE_H_
-
-typedef struct cache_line_t
-{
- ARMword tag; /* cache line align address |
- bit2: last half dirty
- bit1: first half dirty
- bit0: cache valid flag
- */
- ARMword pa; /*physical address */
- ARMword *data; /*array of cached data */
-} cache_line_t;
-#define TAG_VALID_FLAG 0x00000001
-#define TAG_FIRST_HALF_DIRTY 0x00000002
-#define TAG_LAST_HALF_DIRTY 0x00000004
-
-/*cache set association*/
-typedef struct cache_set_s
-{
- cache_line_t *lines;
- int cycle;
-} cache_set_t;
-
-enum
-{
- CACHE_WRITE_BACK,
- CACHE_WRITE_THROUGH,
-};
-
-typedef struct cache_s
-{
- int width; /*bytes in a line */
- int way; /*way of set asscociate */
- int set; /*num of set */
- int w_mode; /*write back or write through */
- //int a_mode; /*alloc mode: random or round-bin*/
- cache_set_t *sets;
- /**/} cache_s;
-
-typedef struct cache_desc_s
-{
- int width;
- int way;
- int set;
- int w_mode;
-// int a_mode;
-} cache_desc_t;
-
-
-/*virtual address to cache set index*/
-#define va_cache_set(va, cache_t) \
- (((va) / (cache_t)->width) & ((cache_t)->set - 1))
-/*virtual address to cahce line aligned*/
-#define va_cache_align(va, cache_t) \
- ((va) & ~((cache_t)->width - 1))
-/*virtaul address to cache line word index*/
-#define va_cache_index(va, cache_t) \
- (((va) & ((cache_t)->width - 1)) >> WORD_SHT)
-
-/*see Page 558 in arm manual*/
-/*set/index format value to cache set value*/
-#define index_cache_set(index, cache_t) \
- (((index) / (cache_t)->width) & ((cache_t)->set - 1))
-
-/*************************cache********************/
-/* mmu cache init
- *
- * @cache_t :cache_t to init
- * @width :cache line width in byte
- * @way :way of each cache set
- * @set :cache set num
- * @w_mode :cache w_mode
- *
- * $ -1: error
- * 0: sucess
- */
-int
-mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode);
-
-/* free a cache_t's inner data, the ptr self is not freed,
- * when needed do like below:
- * mmu_cache_exit(cache);
- * free(cache_t);
- *
- * @cache_t : the cache_t to free
- */
-void mmu_cache_exit (cache_s * cache_t);
-
-/* mmu cache search
- *
- * @state :ARMul_State
- * @cache_t :cache_t to search
- * @va :virtual address
- *
- * $ NULL: no cache match
- * cache :cache matched
- * */
-cache_line_t *mmu_cache_search (ARMul_State * state, cache_s * cache_t,
- ARMword va);
-
-/* mmu cache search by set/index
- *
- * @state :ARMul_State
- * @cache_t :cache_t to search
- * @index :set/index value.
- *
- * $ NULL: no cache match
- * cache :cache matched
- * */
-
-cache_line_t *mmu_cache_search_by_index (ARMul_State * state,
- cache_s * cache_t, ARMword index);
-
-/* mmu cache alloc
- *
- * @state :ARMul_State
- * @cache_t :cache_t to alloc from
- * @va :virtual address that require cache alloc, need not cache aligned
- * @pa :physical address of va
- *
- * $ cache_alloced, always alloc OK
- */
-cache_line_t *mmu_cache_alloc (ARMul_State * state, cache_s * cache_t,
- ARMword va, ARMword pa);
-
-/* mmu_cache_write_back write cache data to memory
- *
- * @state:
- * @cache_t :cache_t of the cache line
- * @cache : cache line
- */
-void
-mmu_cache_write_back (ARMul_State * state, cache_s * cache_t,
- cache_line_t * cache);
-
-/* mmu_cache_clean: clean a cache of va in cache_t
- *
- * @state :ARMul_State
- * @cache_t :cache_t to clean
- * @va :virtaul address
- */
-void mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va);
-void
-mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t,
- ARMword index);
-
-/* mmu_cache_invalidate : invalidate a cache of va
- *
- * @state :ARMul_State
- * @cache_t :cache_t to invalid
- * @va :virt_addr to invalid
- */
-void
-mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va);
-
-void
-mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t,
- ARMword index);
-
-void mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t);
-
-void
-mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa);
-
-cache_line_t* mmu_cache_dirty_cache(ARMul_State * state, cache_s * cache_t);
-
-#endif /*_MMU_CACHE_H_*/
diff --git a/src/core/arm/interpreter/mmu/maverick.cpp b/src/core/arm/interpreter/mmu/maverick.cpp
deleted file mode 100644
index adcc2efb5..000000000
--- a/src/core/arm/interpreter/mmu/maverick.cpp
+++ /dev/null
@@ -1,1206 +0,0 @@
-/* maverick.c -- Cirrus/DSP co-processor interface.
- Copyright (C) 2003 Free Software Foundation, Inc.
- Contributed by Aldy Hernandez (aldyh@redhat.com).
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include <assert.h>
-
-#include "core/arm/interpreter/armdefs.h"
-#include "core/arm/interpreter/armemu.h"
-
-
-/*#define CIRRUS_DEBUG 1 */
-#if CIRRUS_DEBUG
-# define printfdbg printf
-#else
-# define printfdbg printf_nothing
-#endif
-
-#define POS64(i) ( (~(i)) >> 63 )
-#define NEG64(i) ( (i) >> 63 )
-
-/* Define Co-Processor instruction handlers here. */
-
-/* Here's ARMulator's DSP definition. A few things to note:
- 1) it has 16 64-bit registers and 4 72-bit accumulators
- 2) you can only access its registers with MCR and MRC. */
-
-/* We can't define these in here because this file might not be linked
- unless the target is arm9e-*. They are defined in wrapper.c.
- Eventually the simulator should be made to handle any coprocessor
- at run time. */
-struct maverick_regs
-{
- union
- {
- int i;
- float f;
- } upper;
-
- union
- {
- int i;
- float f;
- } lower;
-};
-
-union maverick_acc_regs
-{
- long double ld; /* Acc registers are 72-bits. */
-};
-
-struct maverick_regs DSPregs[16];
-union maverick_acc_regs DSPacc[4];
-ARMword DSPsc;
-
-#define DEST_REG (BITS (12, 15))
-#define SRC1_REG (BITS (16, 19))
-#define SRC2_REG (BITS (0, 3))
-
-static int lsw_int_index, msw_int_index;
-static int lsw_float_index, msw_float_index;
-
-static double mv_getRegDouble (int);
-static long long mv_getReg64int (int);
-static void mv_setRegDouble (int, double val);
-static void mv_setReg64int (int, long long val);
-
-static union
-{
- double d;
- long long ll;
- int ints[2];
-} reg_conv;
-
-static void
-printf_nothing (const char *foo, ...)
-{
-}
-
-static void
-cirrus_not_implemented (const char *insn)
-{
- fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn);
- fprintf (stderr, "aborting!\n");
-
- // skyeye_exit (1);
-}
-
-static unsigned
-DSPInit (ARMul_State * state)
-{
- NOTICE_LOG(ARM11, "ARMul_ConsolePrint: DSP present");
- return TRUE;
-}
-
-unsigned
-DSPMRC4 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword * value)
-{
- switch (BITS (5, 7)) {
- case 0: /* cfmvrdl */
- /* Move lower half of a DF stored in a DSP reg into an Arm reg. */
- printfdbg ("cfmvrdl\n");
- printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i);
- printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
-
- *value = (ARMword) DSPregs[SRC1_REG].lower.i;
- break;
-
- case 1: /* cfmvrdh */
- /* Move upper half of a DF stored in a DSP reg into an Arm reg. */
- printfdbg ("cfmvrdh\n");
- printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i);
- printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
-
- *value = (ARMword) DSPregs[SRC1_REG].upper.i;
- break;
-
- case 2: /* cfmvrs */
- /* Move SF from upper half of a DSP register to an Arm register. */
- *value = (ARMword) DSPregs[SRC1_REG].upper.i;
- printfdbg ("cfmvrs = mvf%d <-- %f\n",
- SRC1_REG, DSPregs[SRC1_REG].upper.f);
- break;
-
-#ifdef doesnt_work
- case 4: /* cfcmps */
- {
- float a, b;
- int n, z, c, v;
-
- a = DSPregs[SRC1_REG].upper.f;
- b = DSPregs[SRC2_REG].upper.f;
-
- printfdbg ("cfcmps\n");
- printfdbg ("\tcomparing %f and %f\n", a, b);
-
- z = a == b; /* zero */
- n = a != b; /* negative */
- v = a > b; /* overflow */
- c = 0; /* carry */
- *value = (n << 31) | (z << 30) | (c << 29) | (v <<
- 28);
- break;
- }
-
- case 5: /* cfcmpd */
- {
- double a, b;
- int n, z, c, v;
-
- a = mv_getRegDouble (SRC1_REG);
- b = mv_getRegDouble (SRC2_REG);
-
- printfdbg ("cfcmpd\n");
- printfdbg ("\tcomparing %g and %g\n", a, b);
-
- z = a == b; /* zero */
- n = a != b; /* negative */
- v = a > b; /* overflow */
- c = 0; /* carry */
- *value = (n << 31) | (z << 30) | (c << 29) | (v <<
- 28);
- break;
- }
-#else
- case 4: /* cfcmps */
- {
- float a, b;
- int n, z, c, v;
-
- a = DSPregs[SRC1_REG].upper.f;
- b = DSPregs[SRC2_REG].upper.f;
-
- printfdbg ("cfcmps\n");
- printfdbg ("\tcomparing %f and %f\n", a, b);
-
- z = a == b; /* zero */
- n = a < b; /* negative */
- c = a > b; /* carry */
- v = 0; /* fixme */
- printfdbg ("\tz = %d, n = %d\n", z, n);
- *value = (n << 31) | (z << 30) | (c << 29) | (v <<
- 28);
- break;
- }
-
- case 5: /* cfcmpd */
- {
- double a, b;
- int n, z, c, v;
-
- a = mv_getRegDouble (SRC1_REG);
- b = mv_getRegDouble (SRC2_REG);
-
- printfdbg ("cfcmpd\n");
- printfdbg ("\tcomparing %g and %g\n", a, b);
-
- z = a == b; /* zero */
- n = a < b; /* negative */
- c = a > b; /* carry */
- v = 0; /* fixme */
- *value = (n << 31) | (z << 30) | (c << 29) | (v <<
- 28);
- break;
- }
-#endif
- default:
- fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr);
- cirrus_not_implemented ("unknown");
- break;
- }
-
- return ARMul_DONE;
-}
-
-unsigned
-DSPMRC5 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword * value)
-{
- switch (BITS (5, 7)) {
- case 0: /* cfmvr64l */
- /* Move lower half of 64bit int from Cirrus to Arm. */
- *value = (ARMword) DSPregs[SRC1_REG].lower.i;
- printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n",
- DEST_REG, (int) *value);
- break;
-
- case 1: /* cfmvr64h */
- /* Move upper half of 64bit int from Cirrus to Arm. */
- *value = (ARMword) DSPregs[SRC1_REG].upper.i;
- printfdbg ("cfmvr64h <-- %d\n", (int) *value);
- break;
-
- case 4: /* cfcmp32 */
- {
- int res;
- int n, z, c, v;
- unsigned int a, b;
-
- printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", SRC1_REG,
- SRC2_REG);
-
- /* FIXME: see comment for cfcmps. */
- a = DSPregs[SRC1_REG].lower.i;
- b = DSPregs[SRC2_REG].lower.i;
-
- res = DSPregs[SRC1_REG].lower.i -
- DSPregs[SRC2_REG].lower.i;
- /* zero */
- z = res == 0;
- /* negative */
- n = res < 0;
- /* overflow */
- v = SubOverflow (DSPregs[SRC1_REG].lower.i,
- DSPregs[SRC2_REG].lower.i, res);
- /* carry */
- c = (NEG (a) && POS (b) ||
- (NEG (a) && POS (res)) || (POS (b)
- && POS (res)));
-
- *value = (n << 31) | (z << 30) | (c << 29) | (v <<
- 28);
- break;
- }
-
- case 5: /* cfcmp64 */
- {
- long long res;
- int n, z, c, v;
- unsigned long long a, b;
-
- printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", SRC1_REG,
- SRC2_REG);
-
- /* fixme: see comment for cfcmps. */
-
- a = mv_getReg64int (SRC1_REG);
- b = mv_getReg64int (SRC2_REG);
-
- res = mv_getReg64int (SRC1_REG) -
- mv_getReg64int (SRC2_REG);
- /* zero */
- z = res == 0;
- /* negative */
- n = res < 0;
- /* overflow */
- v = ((NEG64 (a) && POS64 (b) && POS64 (res))
- || (POS64 (a) && NEG64 (b) && NEG64 (res)));
- /* carry */
- c = (NEG64 (a) && POS64 (b) ||
- (NEG64 (a) && POS64 (res)) || (POS64 (b)
- && POS64 (res)));
-
- *value = (n << 31) | (z << 30) | (c << 29) | (v <<
- 28);
- break;
- }
-
- default:
- fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr);
- cirrus_not_implemented ("unknown");
- break;
- }
-
- return ARMul_DONE;
-}
-
-unsigned
-DSPMRC6 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword * value)
-{
- switch (BITS (5, 7)) {
- case 0: /* cfmval32 */
- cirrus_not_implemented ("cfmval32");
- break;
-
- case 1: /* cfmvam32 */
- cirrus_not_implemented ("cfmvam32");
- break;
-
- case 2: /* cfmvah32 */
- cirrus_not_implemented ("cfmvah32");
- break;
-
- case 3: /* cfmva32 */
- cirrus_not_implemented ("cfmva32");
- break;
-
- case 4: /* cfmva64 */
- cirrus_not_implemented ("cfmva64");
- break;
-
- case 5: /* cfmvsc32 */
- cirrus_not_implemented ("cfmvsc32");
- break;
-
- default:
- fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr);
- cirrus_not_implemented ("unknown");
- break;
- }
-
- return ARMul_DONE;
-}
-
-unsigned
-DSPMCR4 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword value)
-{
- switch (BITS (5, 7)) {
- case 0: /* cfmvdlr */
- /* Move the lower half of a DF value from an Arm register into
- the lower half of a Cirrus register. */
- printfdbg ("cfmvdlr <-- 0x%x\n", (int) value);
- DSPregs[SRC1_REG].lower.i = (int) value;
- break;
-
- case 1: /* cfmvdhr */
- /* Move the upper half of a DF value from an Arm register into
- the upper half of a Cirrus register. */
- printfdbg ("cfmvdhr <-- 0x%x\n", (int) value);
- DSPregs[SRC1_REG].upper.i = (int) value;
- break;
-
- case 2: /* cfmvsr */
- /* Move SF from Arm register into upper half of Cirrus register. */
- printfdbg ("cfmvsr <-- 0x%x\n", (int) value);
- DSPregs[SRC1_REG].upper.i = (int) value;
- break;
-
- default:
- fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr);
- cirrus_not_implemented ("unknown");
- break;
- }
-
- return ARMul_DONE;
-}
-
-unsigned
-DSPMCR5 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword value)
-{
- union
- {
- int s;
- unsigned int us;
- } val;
-
- switch (BITS (5, 7)) {
- case 0: /* cfmv64lr */
- /* Move lower half of a 64bit int from an ARM register into the
- lower half of a DSP register and sign extend it. */
- printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG,
- (int) value);
- DSPregs[SRC1_REG].lower.i = (int) value;
- break;
-
- case 1: /* cfmv64hr */
- /* Move upper half of a 64bit int from an ARM register into the
- upper half of a DSP register. */
- printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n",
- SRC1_REG, (int) value);
- DSPregs[SRC1_REG].upper.i = (int) value;
- break;
-
- case 2: /* cfrshl32 */
- printfdbg ("cfrshl32\n");
- val.us = value;
- if (val.s > 0)
- DSPregs[SRC2_REG].lower.i =
- DSPregs[SRC1_REG].lower.i << value;
- else
- DSPregs[SRC2_REG].lower.i =
- DSPregs[SRC1_REG].lower.i >> -value;
- break;
-
- case 3: /* cfrshl64 */
- printfdbg ("cfrshl64\n");
- val.us = value;
- if (val.s > 0)
- mv_setReg64int (SRC2_REG,
- mv_getReg64int (SRC1_REG) << value);
- else
- mv_setReg64int (SRC2_REG,
- mv_getReg64int (SRC1_REG) >> -value);
- break;
-
- default:
- fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr);
- cirrus_not_implemented ("unknown");
- break;
- }
-
- return ARMul_DONE;
-}
-
-unsigned
-DSPMCR6 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword value)
-{
- switch (BITS (5, 7)) {
- case 0: /* cfmv32al */
- cirrus_not_implemented ("cfmv32al");
- break;
-
- case 1: /* cfmv32am */
- cirrus_not_implemented ("cfmv32am");
- break;
-
- case 2: /* cfmv32ah */
- cirrus_not_implemented ("cfmv32ah");
- break;
-
- case 3: /* cfmv32a */
- cirrus_not_implemented ("cfmv32a");
- break;
-
- case 4: /* cfmv64a */
- cirrus_not_implemented ("cfmv64a");
- break;
-
- case 5: /* cfmv32sc */
- cirrus_not_implemented ("cfmv32sc");
- break;
-
- default:
- fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr);
- cirrus_not_implemented ("unknown");
- break;
- }
-
- return ARMul_DONE;
-}
-
-unsigned
-DSPLDC4 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword data)
-{
- static unsigned words;
-
- if (type != ARMul_DATA) {
- words = 0;
- return ARMul_DONE;
- }
-
- if (BIT (22)) { /* it's a long access, get two words */
- /* cfldrd */
-
- printfdbg
- ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n",
- data, words, state->bigendSig, DEST_REG);
-
- if (words == 0) {
- if (state->bigendSig)
- DSPregs[DEST_REG].upper.i = (int) data;
- else
- DSPregs[DEST_REG].lower.i = (int) data;
- }
- else {
- if (state->bigendSig)
- DSPregs[DEST_REG].lower.i = (int) data;
- else
- DSPregs[DEST_REG].upper.i = (int) data;
- }
-
- ++words;
-
- if (words == 2) {
- printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG,
- mv_getRegDouble (DEST_REG));
-
- return ARMul_DONE;
- }
- else
- return ARMul_INC;
- }
- else {
- /* Get just one word. */
-
- /* cfldrs */
- printfdbg ("cfldrs\n");
-
- DSPregs[DEST_REG].upper.i = (int) data;
-
- printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG,
- DSPregs[DEST_REG].upper.f);
-
- return ARMul_DONE;
- }
-}
-
-unsigned
-DSPLDC5 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword data)
-{
- static unsigned words;
-
- if (type != ARMul_DATA) {
- words = 0;
- return ARMul_DONE;
- }
-
- if (BIT (22)) {
- /* It's a long access, get two words. */
-
- /* cfldr64 */
- printfdbg ("cfldr64: %d\n", data);
-
- if (words == 0) {
- if (state->bigendSig)
- DSPregs[DEST_REG].upper.i = (int) data;
- else
- DSPregs[DEST_REG].lower.i = (int) data;
- }
- else {
- if (state->bigendSig)
- DSPregs[DEST_REG].lower.i = (int) data;
- else
- DSPregs[DEST_REG].upper.i = (int) data;
- }
-
- ++words;
-
- if (words == 2) {
- printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG,
- mv_getReg64int (DEST_REG));
-
- return ARMul_DONE;
- }
- else
- return ARMul_INC;
- }
- else {
- /* Get just one word. */
-
- /* cfldr32 */
- printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data);
-
- /* 32bit ints should be sign extended to 64bits when loaded. */
- mv_setReg64int (DEST_REG, (long long) data);
-
- return ARMul_DONE;
- }
-}
-
-unsigned
-DSPSTC4 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword * data)
-{
- static unsigned words;
-
- if (type != ARMul_DATA) {
- words = 0;
- return ARMul_DONE;
- }
-
- if (BIT (22)) {
- /* It's a long access, get two words. */
- /* cfstrd */
- printfdbg ("cfstrd\n");
-
- if (words == 0) {
- if (state->bigendSig)
- *data = (ARMword) DSPregs[DEST_REG].upper.i;
- else
- *data = (ARMword) DSPregs[DEST_REG].lower.i;
- }
- else {
- if (state->bigendSig)
- *data = (ARMword) DSPregs[DEST_REG].lower.i;
- else
- *data = (ARMword) DSPregs[DEST_REG].upper.i;
- }
-
- ++words;
-
- if (words == 2) {
- printfdbg ("\tmem = mvd%d = %g\n", DEST_REG,
- mv_getRegDouble (DEST_REG));
-
- return ARMul_DONE;
- }
- else
- return ARMul_INC;
- }
- else {
- /* Get just one word. */
- /* cfstrs */
- printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG,
- DSPregs[DEST_REG].upper.f);
-
- *data = (ARMword) DSPregs[DEST_REG].upper.i;
-
- return ARMul_DONE;
- }
-}
-
-unsigned
-DSPSTC5 (ARMul_State * state,
- unsigned type, ARMword instr, ARMword * data)
-{
- static unsigned words;
-
- if (type != ARMul_DATA) {
- words = 0;
- return ARMul_DONE;
- }
-
- if (BIT (22)) {
- /* It's a long access, store two words. */
- /* cfstr64 */
- printfdbg ("cfstr64\n");
-
- if (words == 0) {
- if (state->bigendSig)
- *data = (ARMword) DSPregs[DEST_REG].upper.i;
- else
- *data = (ARMword) DSPregs[DEST_REG].lower.i;
- }
- else {
- if (state->bigendSig)
- *data = (ARMword) DSPregs[DEST_REG].lower.i;
- else
- *data = (ARMword) DSPregs[DEST_REG].upper.i;
- }
-
- ++words;
-
- if (words == 2) {
- printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG,
- mv_getReg64int (DEST_REG));
-
- return ARMul_DONE;
- }
- else
- return ARMul_INC;
- }
- else {
- /* Store just one word. */
- /* cfstr32 */
- *data = (ARMword) DSPregs[DEST_REG].lower.i;
-
- printfdbg ("cfstr32 MEM = %d\n", (int) *data);
-
- return ARMul_DONE;
- }
-}
-
-unsigned
-DSPCDP4 (ARMul_State * state, unsigned type, ARMword instr)
-{
- int opcode2;
-
- opcode2 = BITS (5, 7);
-
- switch (BITS (20, 21)) {
- case 0:
- switch (opcode2) {
- case 0: /* cfcpys */
- printfdbg ("cfcpys mvf%d = mvf%d = %f\n",
- DEST_REG, SRC1_REG,
- DSPregs[SRC1_REG].upper.f);
- DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f;
- break;
-
- case 1: /* cfcpyd */
- printfdbg ("cfcpyd mvd%d = mvd%d = %g\n",
- DEST_REG, SRC1_REG,
- mv_getRegDouble (SRC1_REG));
- mv_setRegDouble (DEST_REG,
- mv_getRegDouble (SRC1_REG));
- break;
-
- case 2: /* cfcvtds */
- printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n",
- DEST_REG, SRC1_REG,
- (float) mv_getRegDouble (SRC1_REG));
- DSPregs[DEST_REG].upper.f =
- (float) mv_getRegDouble (SRC1_REG);
- break;
-
- case 3: /* cfcvtsd */
- printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n",
- DEST_REG, SRC1_REG,
- (double) DSPregs[SRC1_REG].upper.f);
- mv_setRegDouble (DEST_REG,
- (double) DSPregs[SRC1_REG].upper.f);
- break;
-
- case 4: /* cfcvt32s */
- printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n",
- DEST_REG, SRC1_REG,
- (float) DSPregs[SRC1_REG].lower.i);
- DSPregs[DEST_REG].upper.f =
- (float) DSPregs[SRC1_REG].lower.i;
- break;
-
- case 5: /* cfcvt32d */
- printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n",
- DEST_REG, SRC1_REG,
- (double) DSPregs[SRC1_REG].lower.i);
- mv_setRegDouble (DEST_REG,
- (double) DSPregs[SRC1_REG].lower.i);
- break;
-
- case 6: /* cfcvt64s */
- printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n",
- DEST_REG, SRC1_REG,
- (float) mv_getReg64int (SRC1_REG));
- DSPregs[DEST_REG].upper.f =
- (float) mv_getReg64int (SRC1_REG);
- break;
-
- case 7: /* cfcvt64d */
- printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n",
- DEST_REG, SRC1_REG,
- (double) mv_getReg64int (SRC1_REG));
- mv_setRegDouble (DEST_REG,
- (double) mv_getReg64int (SRC1_REG));
- break;
- }
- break;
-
- case 1:
- switch (opcode2) {
- case 0: /* cfmuls */
- printfdbg ("cfmuls mvf%d = mvf%d = %f\n",
- DEST_REG,
- SRC1_REG,
- DSPregs[SRC1_REG].upper.f *
- DSPregs[SRC2_REG].upper.f);
-
- DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
- * DSPregs[SRC2_REG].upper.f;
- break;
-
- case 1: /* cfmuld */
- printfdbg ("cfmuld mvd%d = mvd%d = %g\n",
- DEST_REG,
- SRC1_REG,
- mv_getRegDouble (SRC1_REG) *
- mv_getRegDouble (SRC2_REG));
-
- mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
- * mv_getRegDouble (SRC2_REG));
- break;
-
- default:
- fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n",
- instr);
- cirrus_not_implemented ("unknown");
- break;
- }
- break;
-
- case 3:
- switch (opcode2) {
- case 0: /* cfabss */
- DSPregs[DEST_REG].upper.f =
- (DSPregs[SRC1_REG].upper.f <
- 0.0F ? -DSPregs[SRC1_REG].upper.
- f : DSPregs[SRC1_REG].upper.f);
- printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", DEST_REG,
- SRC1_REG, DSPregs[DEST_REG].upper.f);
- break;
-
- case 1: /* cfabsd */
- mv_setRegDouble (DEST_REG,
- (mv_getRegDouble (SRC1_REG) < 0.0 ?
- -mv_getRegDouble (SRC1_REG)
- : mv_getRegDouble (SRC1_REG)));
- printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n",
- DEST_REG, SRC1_REG,
- mv_getRegDouble (DEST_REG));
- break;
-
- case 2: /* cfnegs */
- DSPregs[DEST_REG].upper.f =
- -DSPregs[SRC1_REG].upper.f;
- printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", DEST_REG,
- SRC1_REG, DSPregs[DEST_REG].upper.f);
- break;
-
- case 3: /* cfnegd */
- mv_setRegDouble (DEST_REG,
- -mv_getRegDouble (SRC1_REG));
- printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", DEST_REG,
- mv_getRegDouble (DEST_REG));
- break;
-
- case 4: /* cfadds */
- DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
- + DSPregs[SRC2_REG].upper.f;
- printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].upper.f);
- break;
-
- case 5: /* cfaddd */
- mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
- + mv_getRegDouble (SRC2_REG));
- printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n",
- DEST_REG,
- SRC1_REG, SRC2_REG,
- mv_getRegDouble (DEST_REG));
- break;
-
- case 6: /* cfsubs */
- DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
- - DSPregs[SRC2_REG].upper.f;
- printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].upper.f);
- break;
-
- case 7: /* cfsubd */
- mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
- - mv_getRegDouble (SRC2_REG));
- printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n",
- DEST_REG,
- SRC1_REG, SRC2_REG,
- mv_getRegDouble (DEST_REG));
- break;
- }
- break;
-
- default:
- fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr);
- cirrus_not_implemented ("unknown");
- break;
- }
-
- return ARMul_DONE;
-}
-
-unsigned
-DSPCDP5 (ARMul_State * state, unsigned type, ARMword instr)
-{
- int opcode2;
- char shift;
-
- opcode2 = BITS (5, 7);
-
- /* Shift constants are 7bit signed numbers in bits 0..3|5..7. */
- shift = BITS (0, 3) | (BITS (5, 7)) << 4;
- if (shift & 0x40)
- shift |= 0xc0;
-
- switch (BITS (20, 21)) {
- case 0:
- /* cfsh32 */
- printfdbg ("cfsh32 %s amount=%d\n",
- shift < 0 ? "right" : "left", shift);
- if (shift < 0)
- /* Negative shift is a right shift. */
- DSPregs[DEST_REG].lower.i =
- DSPregs[SRC1_REG].lower.i >> -shift;
- else
- /* Positive shift is a left shift. */
- DSPregs[DEST_REG].lower.i =
- DSPregs[SRC1_REG].lower.i << shift;
- break;
-
- case 1:
- switch (opcode2) {
- case 0: /* cfmul32 */
- DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
- * DSPregs[SRC2_REG].lower.i;
- printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].lower.i);
- break;
-
- case 1: /* cfmul64 */
- mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
- * mv_getReg64int (SRC2_REG));
- printfdbg
- ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- mv_getReg64int (DEST_REG));
- break;
-
- case 2: /* cfmac32 */
- DSPregs[DEST_REG].lower.i
- +=
- DSPregs[SRC1_REG].lower.i *
- DSPregs[SRC2_REG].lower.i;
- printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].lower.i);
- break;
-
- case 3: /* cfmsc32 */
- DSPregs[DEST_REG].lower.i
- -=
- DSPregs[SRC1_REG].lower.i *
- DSPregs[SRC2_REG].lower.i;
- printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].lower.i);
- break;
-
- case 4: /* cfcvts32 */
- /* fixme: this should round */
- DSPregs[DEST_REG].lower.i =
- (int) DSPregs[SRC1_REG].upper.f;
- printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", DEST_REG,
- SRC1_REG, DSPregs[DEST_REG].lower.i);
- break;
-
- case 5: /* cfcvtd32 */
- /* fixme: this should round */
- DSPregs[DEST_REG].lower.i =
- (int) mv_getRegDouble (SRC1_REG);
- printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", DEST_REG,
- SRC1_REG, DSPregs[DEST_REG].lower.i);
- break;
-
- case 6: /* cftruncs32 */
- DSPregs[DEST_REG].lower.i =
- (int) DSPregs[SRC1_REG].upper.f;
- printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n",
- DEST_REG, SRC1_REG,
- DSPregs[DEST_REG].lower.i);
- break;
-
- case 7: /* cftruncd32 */
- DSPregs[DEST_REG].lower.i =
- (int) mv_getRegDouble (SRC1_REG);
- printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n",
- DEST_REG, SRC1_REG,
- DSPregs[DEST_REG].lower.i);
- break;
- }
- break;
-
- case 2:
- /* cfsh64 */
- printfdbg ("cfsh64\n");
-
- if (shift < 0)
- /* Negative shift is a right shift. */
- mv_setReg64int (DEST_REG,
- mv_getReg64int (SRC1_REG) >> -shift);
- else
- /* Positive shift is a left shift. */
- mv_setReg64int (DEST_REG,
- mv_getReg64int (SRC1_REG) << shift);
- printfdbg ("\t%llx\n", mv_getReg64int (DEST_REG));
- break;
-
- case 3:
- switch (opcode2) {
- case 0: /* cfabs32 */
- DSPregs[DEST_REG].lower.i =
- (DSPregs[SRC1_REG].lower.i <
- 0 ? -DSPregs[SRC1_REG].lower.
- i : DSPregs[SRC1_REG].lower.i);
- printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].lower.i);
- break;
-
- case 1: /* cfabs64 */
- mv_setReg64int (DEST_REG,
- (mv_getReg64int (SRC1_REG) < 0
- ? -mv_getReg64int (SRC1_REG)
- : mv_getReg64int (SRC1_REG)));
- printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- mv_getReg64int (DEST_REG));
- break;
-
- case 2: /* cfneg32 */
- DSPregs[DEST_REG].lower.i =
- -DSPregs[SRC1_REG].lower.i;
- printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].lower.i);
- break;
-
- case 3: /* cfneg64 */
- mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG));
- printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- mv_getReg64int (DEST_REG));
- break;
-
- case 4: /* cfadd32 */
- DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
- + DSPregs[SRC2_REG].lower.i;
- printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].lower.i);
- break;
-
- case 5: /* cfadd64 */
- mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
- + mv_getReg64int (SRC2_REG));
- printfdbg
- ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- mv_getReg64int (DEST_REG));
- break;
-
- case 6: /* cfsub32 */
- DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
- - DSPregs[SRC2_REG].lower.i;
- printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- DSPregs[DEST_REG].lower.i);
- break;
-
- case 7: /* cfsub64 */
- mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
- - mv_getReg64int (SRC2_REG));
- printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n",
- DEST_REG, SRC1_REG, SRC2_REG,
- mv_getReg64int (DEST_REG));
- break;
- }
- break;
-
- default:
- fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr);
- cirrus_not_implemented ("unknown");
- break;
- }
-
- return ARMul_DONE;
-}
-
-unsigned
-DSPCDP6 (ARMul_State * state, unsigned type, ARMword instr)
-{
- int opcode2;
-
- opcode2 = BITS (5, 7);
-
- switch (BITS (20, 21)) {
- case 0:
- /* cfmadd32 */
- cirrus_not_implemented ("cfmadd32");
- break;
-
- case 1:
- /* cfmsub32 */
- cirrus_not_implemented ("cfmsub32");
- break;
-
- case 2:
- /* cfmadda32 */
- cirrus_not_implemented ("cfmadda32");
- break;
-
- case 3:
- /* cfmsuba32 */
- cirrus_not_implemented ("cfmsuba32");
- break;
-
- default:
- fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr);
- }
-
- return ARMul_DONE;
-}
-
-/* Conversion functions.
-
- 32-bit integers are stored in the LOWER half of a 64-bit physical
- register.
-
- Single precision floats are stored in the UPPER half of a 64-bit
- physical register. */
-
-static double
-mv_getRegDouble (int regnum)
-{
- reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i;
- reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i;
- return reg_conv.d;
-}
-
-static void
-mv_setRegDouble (int regnum, double val)
-{
- reg_conv.d = val;
- DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index];
- DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index];
-}
-
-static long long
-mv_getReg64int (int regnum)
-{
- reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i;
- reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i;
- return reg_conv.ll;
-}
-
-static void
-mv_setReg64int (int regnum, long long val)
-{
- reg_conv.ll = val;
- DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index];
- DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index];
-}
-
-/* Compute LSW in a double and a long long. */
-
-void
-mv_compute_host_endianness (ARMul_State * state)
-{
- static union
- {
- long long ll;
- int ints[2];
- int i;
- double d;
- float floats[2];
- float f;
- } conv;
-
- /* Calculate where's the LSW in a 64bit int. */
- conv.ll = 45;
-
- if (conv.ints[0] == 0) {
- msw_int_index = 0;
- lsw_int_index = 1;
- }
- else {
- assert (conv.ints[1] == 0);
- msw_int_index = 1;
- lsw_int_index = 0;
- }
-
- /* Calculate where's the LSW in a double. */
- conv.d = 3.0;
-
- if (conv.ints[0] == 0) {
- msw_float_index = 0;
- lsw_float_index = 1;
- }
- else {
- assert (conv.ints[1] == 0);
- msw_float_index = 1;
- lsw_float_index = 0;
- }
-
- printfdbg ("lsw_int_index %d\n", lsw_int_index);
- printfdbg ("lsw_float_index %d\n", lsw_float_index);
-}
diff --git a/src/core/arm/interpreter/mmu/rb.cpp b/src/core/arm/interpreter/mmu/rb.cpp
deleted file mode 100644
index 07b11e311..000000000
--- a/src/core/arm/interpreter/mmu/rb.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-#include "core/arm/interpreter/armdefs.h"
-
-/*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu*/
-ARMword rb_masks[] = {
- 0x0, //RB_INVALID
- 4, //RB_1
- 16, //RB_4
- 32, //RB_8
-};
-
-/*mmu_rb_init
- * @rb_t :rb_t to init
- * @num :number of entry
- * */
-int
-mmu_rb_init (rb_s * rb_t, int num)
-{
- int i;
- rb_entry_t *entrys;
-
- entrys = (rb_entry_t *) malloc (sizeof (*entrys) * num);
- if (entrys == NULL) {
- printf ("SKYEYE:mmu_rb_init malloc error\n");
- return -1;
- }
- for (i = 0; i < num; i++) {
- entrys[i].type = RB_INVALID;
- entrys[i].fault = NO_FAULT;
- }
-
- rb_t->entrys = entrys;
- rb_t->num = num;
- return 0;
-}
-
-/*mmu_rb_exit*/
-void
-mmu_rb_exit (rb_s * rb_t)
-{
- free (rb_t->entrys);
-};
-
-/*mmu_rb_search
- * @rb_t :rb_t to serach
- * @va :va address to math
- *
- * $ NULL :not match
- * NO-NULL:
- * */
-rb_entry_t *
-mmu_rb_search (rb_s * rb_t, ARMword va)
-{
- int i;
- rb_entry_t *rb = rb_t->entrys;
-
- DEBUG_LOG(ARM11, "va = %x\n", va);
- for (i = 0; i < rb_t->num; i++, rb++) {
- //2004-06-06 lyh bug from wenye@cs.ucsb.edu
- if (rb->type) {
- if ((va >= rb->va)
- && (va < (rb->va + rb_masks[rb->type])))
- return rb;
- }
- }
- return NULL;
-};
-
-void
-mmu_rb_invalidate_entry (rb_s * rb_t, int i)
-{
- rb_t->entrys[i].type = RB_INVALID;
-}
-
-void
-mmu_rb_invalidate_all (rb_s * rb_t)
-{
- int i;
-
- for (i = 0; i < rb_t->num; i++)
- mmu_rb_invalidate_entry (rb_t, i);
-};
-
-void
-mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, int type, ARMword va)
-{
- rb_entry_t *rb;
- int i;
- ARMword max_start, min_end;
- fault_t fault;
- tlb_entry_t *tlb;
-
- /*align va according to type */
- va &= ~(rb_masks[type] - 1);
- /*invalidate all RB match [va, va + rb_masks[type]] */
- for (rb = rb_t->entrys, i = 0; i < rb_t->num; i++, rb++) {
- if (rb->type) {
- max_start = max (va, rb->va);
- min_end =
- min (va + rb_masks[type],
- rb->va + rb_masks[rb->type]);
- if (max_start < min_end)
- rb->type = RB_INVALID;
- }
- }
- /*load word */
- rb = &rb_t->entrys[i_rb];
- rb->type = type;
- fault = translate (state, va, D_TLB (), &tlb);
- if (fault) {
- rb->fault = fault;
- return;
- }
- fault = check_access (state, va, tlb, 1);
- if (fault) {
- rb->fault = fault;
- return;
- }
-
- rb->fault = NO_FAULT;
- va = tlb_va_to_pa (tlb, va);
- //2004-06-06 lyh bug from wenye@cs.ucsb.edu
- for (i = 0; i < (rb_masks[type] / 4); i++, va += WORD_SIZE) {
- //rb->data[i] = mem_read_word (state, va);
- bus_read(32, va, &rb->data[i]);
- };
-}
diff --git a/src/core/arm/interpreter/mmu/rb.h b/src/core/arm/interpreter/mmu/rb.h
deleted file mode 100644
index 7bf0ebb26..000000000
--- a/src/core/arm/interpreter/mmu/rb.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _MMU_RB_H
-#define _MMU_RB_H
-
-enum rb_type_t
-{
- RB_INVALID = 0, //invalid
- RB_1, //1 word
- RB_4, //4 word
- RB_8, //8 word
-};
-
-/*bytes of each rb_type*/
-extern ARMword rb_masks[];
-
-#define RB_WORD_NUM 8
-typedef struct rb_entry_s
-{
- ARMword data[RB_WORD_NUM]; //array to store data
- ARMword va; //first word va
- int type; //rb type
- fault_t fault; //fault set by rb alloc
-} rb_entry_t;
-
-typedef struct rb_s
-{
- int num;
- rb_entry_t *entrys;
-} rb_s;
-
-/*mmu_rb_init
- * @rb_t :rb_t to init
- * @num :number of entry
- * */
-int mmu_rb_init (rb_s * rb_t, int num);
-
-/*mmu_rb_exit*/
-void mmu_rb_exit (rb_s * rb_t);
-
-
-/*mmu_rb_search
- * @rb_t :rb_t to serach
- * @va :va address to math
- *
- * $ NULL :not match
- * NO-NULL:
- * */
-rb_entry_t *mmu_rb_search (rb_s * rb_t, ARMword va);
-
-
-void mmu_rb_invalidate_entry (rb_s * rb_t, int i);
-void mmu_rb_invalidate_all (rb_s * rb_t);
-void mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb,
- int type, ARMword va);
-
-#endif /*_MMU_RB_H_*/
diff --git a/src/core/arm/interpreter/mmu/sa_mmu.cpp b/src/core/arm/interpreter/mmu/sa_mmu.cpp
deleted file mode 100644
index eff5002de..000000000
--- a/src/core/arm/interpreter/mmu/sa_mmu.cpp
+++ /dev/null
@@ -1,864 +0,0 @@
-/*
- armmmu.c - Memory Management Unit emulation.
- ARMulator extensions for the ARM7100 family.
- Copyright (C) 1999 Ben Williamson
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <assert.h>
-#include <string.h>
-
-#include "core/arm/interpreter/armdefs.h"
-
-/**
- * The interface of read data from bus
- */
-int bus_read(short size, int addr, uint32_t * value) {
- ERROR_LOG(ARM11, "unimplemented bus_read");
- return 0;
-}
-
-/**
- * The interface of write data from bus
- */
-int bus_write(short size, int addr, uint32_t value) {
- ERROR_LOG(ARM11, "unimplemented bus_write");
- return 0;
-}
-
-
-typedef struct sa_mmu_desc_s
-{
- int i_tlb;
- cache_desc_t i_cache;
-
- int d_tlb;
- cache_desc_t main_d_cache;
- cache_desc_t mini_d_cache;
- int rb;
- wb_desc_t wb;
-} sa_mmu_desc_t;
-
-static sa_mmu_desc_t sa11xx_mmu_desc = {
- 32,
- {32, 32, 16, CACHE_WRITE_BACK},
-
- 32,
- {32, 32, 8, CACHE_WRITE_BACK},
- {32, 2, 8, CACHE_WRITE_BACK},
- 4,
- //{8, 4}, for word size
- {8, 16}, //for byte size, chy 2003-07-11
-};
-
-static fault_t sa_mmu_write (ARMul_State * state, ARMword va, ARMword data,
- ARMword datatype);
-static fault_t sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
- ARMword datatype);
-static fault_t update_cache (ARMul_State * state, ARMword va, ARMword data,
- ARMword datatype, cache_line_t * cache,
- cache_s * cache_t, ARMword real_va);
-
-void
-mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa,
- ARMbyte * data, int n);
-int
-sa_mmu_init (ARMul_State * state)
-{
- sa_mmu_desc_t *desc;
- cache_desc_t *c_desc;
-
- state->mmu.control = 0x70;
- state->mmu.translation_table_base = 0xDEADC0DE;
- state->mmu.domain_access_control = 0xDEADC0DE;
- state->mmu.fault_status = 0;
- state->mmu.fault_address = 0;
- state->mmu.process_id = 0;
-
- desc = &sa11xx_mmu_desc;
- if (mmu_tlb_init (I_TLB (), desc->i_tlb)) {
- ERROR_LOG(ARM11, "i_tlb init %d\n", -1);
- goto i_tlb_init_error;
- }
-
- c_desc = &desc->i_cache;
- if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way,
- c_desc->set, c_desc->w_mode)) {
- ERROR_LOG(ARM11, "i_cache init %d\n", -1);
- goto i_cache_init_error;
- }
-
- if (mmu_tlb_init (D_TLB (), desc->d_tlb)) {
- ERROR_LOG(ARM11, "d_tlb init %d\n", -1);
- goto d_tlb_init_error;
- }
-
- c_desc = &desc->main_d_cache;
- if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way,
- c_desc->set, c_desc->w_mode)) {
- ERROR_LOG(ARM11, "main_d_cache init %d\n", -1);
- goto main_d_cache_init_error;
- }
-
- c_desc = &desc->mini_d_cache;
- if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way,
- c_desc->set, c_desc->w_mode)) {
- ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1);
- goto mini_d_cache_init_error;
- }
-
- if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) {
- ERROR_LOG(ARM11, "wb init %d\n", -1);
- goto wb_init_error;
- }
-
- if (mmu_rb_init (RB (), desc->rb)) {
- ERROR_LOG(ARM11, "rb init %d\n", -1);
- goto rb_init_error;
- }
- return 0;
-
- rb_init_error:
- mmu_wb_exit (WB ());
- wb_init_error:
- mmu_cache_exit (MINI_D_CACHE ());
- mini_d_cache_init_error:
- mmu_cache_exit (MAIN_D_CACHE ());
- main_d_cache_init_error:
- mmu_tlb_exit (D_TLB ());
- d_tlb_init_error:
- mmu_cache_exit (I_CACHE ());
- i_cache_init_error:
- mmu_tlb_exit (I_TLB ());
- i_tlb_init_error:
- return -1;
-}
-
-void
-sa_mmu_exit (ARMul_State * state)
-{
- mmu_rb_exit (RB ());
- mmu_wb_exit (WB ());
- mmu_cache_exit (MINI_D_CACHE ());
- mmu_cache_exit (MAIN_D_CACHE ());
- mmu_tlb_exit (D_TLB ());
- mmu_cache_exit (I_CACHE ());
- mmu_tlb_exit (I_TLB ());
-};
-
-
-static fault_t
-sa_mmu_load_instr (ARMul_State * state, ARMword va, ARMword * instr)
-{
- fault_t fault;
- tlb_entry_t *tlb;
- cache_line_t *cache;
- int c; //cache bit
- ARMword pa; //physical addr
-
- static int debug_count = 0; //used for debug
-
- DEBUG_LOG(ARM11, "va = %x\n", va);
-
- va = mmu_pid_va_map (va);
- if (MMU_Enabled) {
- /*align check */
- if ((va & (WORD_SIZE - 1)) && MMU_Aligned) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- }
- else
- va &= ~(WORD_SIZE - 1);
-
- /*translate tlb */
- fault = translate (state, va, I_TLB (), &tlb);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- return fault;
- }
-
- /*check access */
- fault = check_access (state, va, tlb, 1);
- if (fault) {
- DEBUG_LOG(ARM11, "check_fault\n");
- return fault;
- }
- }
-
- /*search cache no matter MMU enabled/disabled */
- cache = mmu_cache_search (state, I_CACHE (), va);
- if (cache) {
- *instr = cache->data[va_cache_index (va, I_CACHE ())];
- return NO_FAULT;
- }
-
- /*if MMU disabled or C flag is set alloc cache */
- if (MMU_Disabled) {
- c = 1;
- pa = va;
- }
- else {
- c = tlb_c_flag (tlb);
- pa = tlb_va_to_pa (tlb, va);
- }
-
- if (c) {
- int index;
-
- debug_count++;
- cache = mmu_cache_alloc (state, I_CACHE (), va, pa);
- index = va_cache_index (va, I_CACHE ());
- *instr = cache->data[va_cache_index (va, I_CACHE ())];
- }
- else
- //*instr = mem_read_word (state, pa);
- bus_read(32, pa, instr);
-
- return NO_FAULT;
-};
-
-
-
-static fault_t
-sa_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data)
-{
- //ARMword temp,offset;
- fault_t fault;
- fault = sa_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE);
- return fault;
-}
-
-static fault_t
-sa_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data)
-{
- //ARMword temp,offset;
- fault_t fault;
- fault = sa_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE);
- return fault;
-}
-
-static fault_t
-sa_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data)
-{
- return sa_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);
-}
-
-
-
-
-static fault_t
-sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
- ARMword datatype)
-{
- fault_t fault;
- rb_entry_t *rb;
- tlb_entry_t *tlb;
- cache_line_t *cache;
- ARMword pa, real_va, temp, offset;
-
- DEBUG_LOG(ARM11, "va = %x\n", va);
-
- va = mmu_pid_va_map (va);
- real_va = va;
- /*if MMU disabled, memory_read */
- if (MMU_Disabled) {
- //*data = mem_read_word(state, va);
- if (datatype == ARM_BYTE_TYPE)
- //*data = mem_read_byte (state, va);
- bus_read(8, va, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //*data = mem_read_halfword (state, va);
- bus_read(16, va, data);
- else if (datatype == ARM_WORD_TYPE)
- //*data = mem_read_word (state, va);
- bus_read(32, va, data);
- else {
- printf ("SKYEYE:1 sa_mmu_read error: unknown data type %d\n", datatype);
- // skyeye_exit (-1);
- }
-
- return NO_FAULT;
- }
-
- /*align check */
- if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
- ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- } // else
-
- va &= ~(WORD_SIZE - 1);
-
- /*translate va to tlb */
- fault = translate (state, va, D_TLB (), &tlb);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- return fault;
- }
- /*check access permission */
- fault = check_access (state, va, tlb, 1);
- if (fault)
- return fault;
- /*search in read buffer */
- rb = mmu_rb_search (RB (), va);
- if (rb) {
- if (rb->fault)
- return rb->fault;
- *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT];
- goto datatrans;
- //return 0;
- };
- /*search main cache */
- cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
- if (cache) {
- *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())];
- goto datatrans;
- //return 0;
- }
- /*search mini cache */
- cache = mmu_cache_search (state, MINI_D_CACHE (), va);
- if (cache) {
- *data = cache->data[va_cache_index (va, MINI_D_CACHE ())];
- goto datatrans;
- //return 0;
- }
-
- /*get phy_addr */
- pa = tlb_va_to_pa (tlb, va);
- if ((pa >= 0xe0000000) && (pa < 0xe8000000)) {
- if (tlb_c_flag (tlb)) {
- if (tlb_b_flag (tlb)) {
- mmu_cache_soft_flush (state, MAIN_D_CACHE (),
- pa);
- }
- else {
- mmu_cache_soft_flush (state, MINI_D_CACHE (),
- pa);
- }
- }
- return NO_FAULT;
- }
-
- /*if Buffer, drain Write Buffer first */
- if (tlb_b_flag (tlb))
- mmu_wb_drain_all (state, WB ());
-
- /*alloc cache or mem_read */
- if (tlb_c_flag (tlb) && MMU_DCacheEnabled) {
- cache_s *cache_t;
-
- if (tlb_b_flag (tlb))
- cache_t = MAIN_D_CACHE ();
- else
- cache_t = MINI_D_CACHE ();
- cache = mmu_cache_alloc (state, cache_t, va, pa);
- *data = cache->data[va_cache_index (va, cache_t)];
- }
- else {
- //*data = mem_read_word(state, pa);
- if (datatype == ARM_BYTE_TYPE)
- //*data = mem_read_byte (state, pa | (real_va & 3));
- bus_read(8, pa | (real_va & 3), data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //*data = mem_read_halfword (state, pa | (real_va & 2));
- bus_read(16, pa | (real_va & 2), data);
- else if (datatype == ARM_WORD_TYPE)
- //*data = mem_read_word (state, pa);
- bus_read(32, pa, data);
- else {
- printf ("SKYEYE:2 sa_mmu_read error: unknown data type %d\n", datatype);
- // skyeye_exit (-1);
- }
- return NO_FAULT;
- }
-
-
- datatrans:
- if (datatype == ARM_HALFWORD_TYPE) {
- temp = *data;
- offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
- *data = (temp >> offset) & 0xffff;
- }
- else if (datatype == ARM_BYTE_TYPE) {
- temp = *data;
- offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
- *data = (temp >> offset & 0xffL);
- }
- end:
- return NO_FAULT;
-}
-
-
-static fault_t
-sa_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data)
-{
- return sa_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);
-}
-
-static fault_t
-sa_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data)
-{
- return sa_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);
-}
-
-static fault_t
-sa_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data)
-{
- return sa_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);
-}
-
-
-
-static fault_t
-sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, ARMword datatype)
-{
- tlb_entry_t *tlb;
- cache_line_t *cache;
- int b;
- ARMword pa, real_va;
- fault_t fault;
-
- DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data);
- va = mmu_pid_va_map (va);
- real_va = va;
-
- /*search instruction cache */
- cache = mmu_cache_search (state, I_CACHE (), va);
- if (cache) {
- update_cache (state, va, data, datatype, cache, I_CACHE (),
- real_va);
- }
-
- if (MMU_Disabled) {
- //mem_write_word(state, va, data);
- if (datatype == ARM_BYTE_TYPE)
- //mem_write_byte (state, va, data);
- bus_write(8, va, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //mem_write_halfword (state, va, data);
- bus_write(16, va, data);
- else if (datatype == ARM_WORD_TYPE)
- //mem_write_word (state, va, data);
- bus_write(32, va, data);
- else {
- printf ("SKYEYE:1 sa_mmu_write error: unknown data type %d\n", datatype);
- // skyeye_exit (-1);
- }
-
- return NO_FAULT;
- }
- /*align check */
- //if ((va & (WORD_SIZE - 1)) && MMU_Aligned){
- if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
- ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- } //else
- va &= ~(WORD_SIZE - 1);
- /*tlb translate */
- fault = translate (state, va, D_TLB (), &tlb);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- return fault;
- }
- /*tlb check access */
- fault = check_access (state, va, tlb, 0);
- if (fault) {
- DEBUG_LOG(ARM11, "check_access\n");
- return fault;
- }
- /*search main cache */
- cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
- if (cache) {
- update_cache (state, va, data, datatype, cache,
- MAIN_D_CACHE (), real_va);
- }
- else {
- /*search mini cache */
- cache = mmu_cache_search (state, MINI_D_CACHE (), va);
- if (cache) {
- update_cache (state, va, data, datatype, cache,
- MINI_D_CACHE (), real_va);
- }
- }
-
- if (!cache) {
- b = tlb_b_flag (tlb);
- pa = tlb_va_to_pa (tlb, va);
- if (b) {
- if (MMU_WBEnabled) {
- if (datatype == ARM_WORD_TYPE)
- mmu_wb_write_bytes (state, WB (), pa,
- (ARMbyte*)&data, 4);
- else if (datatype == ARM_HALFWORD_TYPE)
- mmu_wb_write_bytes (state, WB (),
- (pa |
- (real_va & 2)),
- (ARMbyte*)&data, 2);
- else if (datatype == ARM_BYTE_TYPE)
- mmu_wb_write_bytes (state, WB (),
- (pa |
- (real_va & 3)),
- (ARMbyte*)&data, 1);
-
- }
- else {
- if (datatype == ARM_WORD_TYPE)
- //mem_write_word (state, pa, data);
- bus_write(32, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- /*
- mem_write_halfword (state,
- (pa |
- (real_va & 2)),
- data);
- */
- bus_write(16, pa | (real_va & 2), data);
- else if (datatype == ARM_BYTE_TYPE)
- /*
- mem_write_byte (state,
- (pa | (real_va & 3)),
- data);
- */
- bus_write(8, pa | (real_va & 3), data);
- }
- }
- else {
- mmu_wb_drain_all (state, WB ());
-
- if (datatype == ARM_WORD_TYPE)
- //mem_write_word (state, pa, data);
- bus_write(32, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- /*
- mem_write_halfword (state,
- (pa | (real_va & 2)),
- data);
- */
- bus_write(16, pa | (real_va & 2), data);
- else if (datatype == ARM_BYTE_TYPE)
- /*
- mem_write_byte (state, (pa | (real_va & 3)),
- data);
- */
- bus_write(8, pa | (real_va & 3), data);
- }
- }
- return NO_FAULT;
-}
-
-static fault_t
-update_cache (ARMul_State * state, ARMword va, ARMword data, ARMword datatype,
- cache_line_t * cache, cache_s * cache_t, ARMword real_va)
-{
- ARMword temp, offset;
-
- ARMword index = va_cache_index (va, cache_t);
-
- //cache->data[index] = data;
-
- if (datatype == ARM_WORD_TYPE)
- cache->data[index] = data;
- else if (datatype == ARM_HALFWORD_TYPE) {
- temp = cache->data[index];
- offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
- cache->data[index] =
- (temp & ~(0xffffL << offset)) | ((data & 0xffffL) <<
- offset);
- }
- else if (datatype == ARM_BYTE_TYPE) {
- temp = cache->data[index];
- offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
- cache->data[index] =
- (temp & ~(0xffL << offset)) | ((data & 0xffL) <<
- offset);
- }
-
- if (index < (cache_t->width >> (WORD_SHT + 1)))
- cache->tag |= TAG_FIRST_HALF_DIRTY;
- else
- cache->tag |= TAG_LAST_HALF_DIRTY;
-
- return NO_FAULT;
-}
-
-ARMword
-sa_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value)
-{
- mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15);
- ARMword data;
-
- switch (creg) {
- case MMU_ID:
-// printf("mmu_mrc read ID ");
- data = 0x41007100; /* v3 */
- data = state->cpu->cpu_val;
- break;
- case MMU_CONTROL:
-// printf("mmu_mrc read CONTROL");
- data = state->mmu.control;
- break;
- case MMU_TRANSLATION_TABLE_BASE:
-// printf("mmu_mrc read TTB ");
- data = state->mmu.translation_table_base;
- break;
- case MMU_DOMAIN_ACCESS_CONTROL:
-// printf("mmu_mrc read DACR ");
- data = state->mmu.domain_access_control;
- break;
- case MMU_FAULT_STATUS:
-// printf("mmu_mrc read FSR ");
- data = state->mmu.fault_status;
- break;
- case MMU_FAULT_ADDRESS:
-// printf("mmu_mrc read FAR ");
- data = state->mmu.fault_address;
- break;
- case MMU_PID:
- data = state->mmu.process_id;
- default:
- printf ("mmu_mrc read UNKNOWN - reg %d\n", creg);
- data = 0;
- break;
- }
-// printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]);
- *value = data;
- return data;
-}
-
-void
-sa_mmu_cache_ops (ARMul_State * state, ARMword instr, ARMword value)
-{
- int CRm, OPC_2;
-
- CRm = BITS (0, 3);
- OPC_2 = BITS (5, 7);
-
- if (OPC_2 == 0 && CRm == 7) {
- mmu_cache_invalidate_all (state, I_CACHE ());
- mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
- mmu_cache_invalidate_all (state, MINI_D_CACHE ());
- return;
- }
-
- if (OPC_2 == 0 && CRm == 5) {
- mmu_cache_invalidate_all (state, I_CACHE ());
- return;
- }
-
- if (OPC_2 == 0 && CRm == 6) {
- mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
- mmu_cache_invalidate_all (state, MINI_D_CACHE ());
- return;
- }
-
- if (OPC_2 == 1 && CRm == 6) {
- mmu_cache_invalidate (state, MAIN_D_CACHE (), value);
- mmu_cache_invalidate (state, MINI_D_CACHE (), value);
- return;
- }
-
- if (OPC_2 == 1 && CRm == 0xa) {
- mmu_cache_clean (state, MAIN_D_CACHE (), value);
- mmu_cache_clean (state, MINI_D_CACHE (), value);
- return;
- }
-
- if (OPC_2 == 4 && CRm == 0xa) {
- mmu_wb_drain_all (state, WB ());
- return;
- }
- ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
-}
-
-static void
-sa_mmu_tlb_ops (ARMul_State * state, ARMword instr, ARMword value)
-{
- int CRm, OPC_2;
-
- CRm = BITS (0, 3);
- OPC_2 = BITS (5, 7);
-
-
- if (OPC_2 == 0 && CRm == 0x7) {
- mmu_tlb_invalidate_all (state, I_TLB ());
- mmu_tlb_invalidate_all (state, D_TLB ());
- return;
- }
-
- if (OPC_2 == 0 && CRm == 0x5) {
- mmu_tlb_invalidate_all (state, I_TLB ());
- return;
- }
-
- if (OPC_2 == 0 && CRm == 0x6) {
- mmu_tlb_invalidate_all (state, D_TLB ());
- return;
- }
-
- if (OPC_2 == 1 && CRm == 0x6) {
- mmu_tlb_invalidate_entry (state, D_TLB (), value);
- return;
- }
-
- ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
-}
-
-static void
-sa_mmu_rb_ops (ARMul_State * state, ARMword instr, ARMword value)
-{
- int CRm, OPC_2;
-
- CRm = BITS (0, 3);
- OPC_2 = BITS (5, 7);
-
- if (OPC_2 == 0x0 && CRm == 0x0) {
- mmu_rb_invalidate_all (RB ());
- return;
- }
-
- if (OPC_2 == 0x2) {
- int idx = CRm & 0x3;
- int type = ((CRm >> 2) & 0x3) + 1;
-
- if ((idx < 4) && (type < 4))
- mmu_rb_load (state, RB (), idx, type, value);
- return;
- }
-
- if ((OPC_2 == 1) && (CRm < 4)) {
- mmu_rb_invalidate_entry (RB (), CRm);
- return;
- }
-
- ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
-}
-
-static ARMword
-sa_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value)
-{
- mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15);
- if (!strncmp (state->cpu->cpu_arch_name, "armv4", 5)) {
- switch (creg) {
- case MMU_CONTROL:
-// printf("mmu_mcr wrote CONTROL ");
- state->mmu.control = (value | 0x70) & 0xFFFD;
- break;
- case MMU_TRANSLATION_TABLE_BASE:
-// printf("mmu_mcr wrote TTB ");
- state->mmu.translation_table_base =
- value & 0xFFFFC000;
- break;
- case MMU_DOMAIN_ACCESS_CONTROL:
-// printf("mmu_mcr wrote DACR ");
- state->mmu.domain_access_control = value;
- break;
-
- case MMU_FAULT_STATUS:
- state->mmu.fault_status = value & 0xFF;
- break;
- case MMU_FAULT_ADDRESS:
- state->mmu.fault_address = value;
- break;
-
- case MMU_CACHE_OPS:
- sa_mmu_cache_ops (state, instr, value);
- break;
- case MMU_TLB_OPS:
- sa_mmu_tlb_ops (state, instr, value);
- break;
- case MMU_SA_RB_OPS:
- sa_mmu_rb_ops (state, instr, value);
- break;
- case MMU_SA_DEBUG:
- break;
- case MMU_SA_CP15_R15:
- break;
- case MMU_PID:
- //2004-06-06 lyh, bug provided by wen ye wenye@cs.ucsb.edu
- state->mmu.process_id = value & 0x7e000000;
- break;
-
- default:
- printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
- break;
- }
- }
- return 0;
-}
-
-//teawater add for arm2x86 2005.06.24-------------------------------------------
-static int
-sa_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr)
-{
- fault_t fault;
- tlb_entry_t *tlb;
-
- virt_addr = mmu_pid_va_map (virt_addr);
- if (MMU_Enabled) {
-
- /*align check */
- if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- }
- else
- virt_addr &= ~(WORD_SIZE - 1);
-
- /*translate tlb */
- fault = translate (state, virt_addr, I_TLB (), &tlb);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- return fault;
- }
-
- /*check access */
- fault = check_access (state, virt_addr, tlb, 1);
- if (fault) {
- DEBUG_LOG(ARM11, "check_fault\n");
- return fault;
- }
- }
-
- if (MMU_Disabled) {
- *phys_addr = virt_addr;
- }
- else {
- *phys_addr = tlb_va_to_pa (tlb, virt_addr);
- }
-
- return (0);
-}
-
-//AJ2D--------------------------------------------------------------------------
-
-/*sa mmu_ops_t*/
-mmu_ops_t sa_mmu_ops = {
- sa_mmu_init,
- sa_mmu_exit,
- sa_mmu_read_byte,
- sa_mmu_write_byte,
- sa_mmu_read_halfword,
- sa_mmu_write_halfword,
- sa_mmu_read_word,
- sa_mmu_write_word,
- sa_mmu_load_instr,
- sa_mmu_mcr,
- sa_mmu_mrc,
-//teawater add for arm2x86 2005.06.24-------------------------------------------
- sa_mmu_v2p_dbct,
-//AJ2D--------------------------------------------------------------------------
-};
diff --git a/src/core/arm/interpreter/mmu/sa_mmu.h b/src/core/arm/interpreter/mmu/sa_mmu.h
deleted file mode 100644
index 64b1c5470..000000000
--- a/src/core/arm/interpreter/mmu/sa_mmu.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- sa_mmu.h - StrongARM Memory Management Unit emulation.
- ARMulator extensions for SkyEye.
- <lyhost@263.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _SA_MMU_H_
-#define _SA_MMU_H_
-
-
-/**
- * The interface of read data from bus
- */
-int bus_read(short size, int addr, uint32_t * value);
-
-/**
- * The interface of write data from bus
- */
-int bus_write(short size, int addr, uint32_t value);
-
-
-typedef struct sa_mmu_s
-{
- tlb_s i_tlb;
- cache_s i_cache;
-
- tlb_s d_tlb;
- cache_s main_d_cache;
- cache_s mini_d_cache;
- rb_s rb_t;
- wb_s wb_t;
-} sa_mmu_t;
-
-#define I_TLB() (&state->mmu.u.sa_mmu.i_tlb)
-#define I_CACHE() (&state->mmu.u.sa_mmu.i_cache)
-
-#define D_TLB() (&state->mmu.u.sa_mmu.d_tlb)
-#define MAIN_D_CACHE() (&state->mmu.u.sa_mmu.main_d_cache)
-#define MINI_D_CACHE() (&state->mmu.u.sa_mmu.mini_d_cache)
-#define WB() (&state->mmu.u.sa_mmu.wb_t)
-#define RB() (&state->mmu.u.sa_mmu.rb_t)
-
-extern mmu_ops_t sa_mmu_ops;
-#endif /*_SA_MMU_H_*/
diff --git a/src/core/arm/interpreter/mmu/tlb.cpp b/src/core/arm/interpreter/mmu/tlb.cpp
deleted file mode 100644
index ca60ac1a1..000000000
--- a/src/core/arm/interpreter/mmu/tlb.cpp
+++ /dev/null
@@ -1,307 +0,0 @@
-#include <assert.h>
-
-#include "core/arm/interpreter/armdefs.h"
-
-ARMword tlb_masks[] = {
- 0x00000000, /* TLB_INVALID */
- 0xFFFFF000, /* TLB_SMALLPAGE */
- 0xFFFF0000, /* TLB_LARGEPAGE */
- 0xFFF00000, /* TLB_SECTION */
- 0xFFFFF000, /*TLB_ESMALLPAGE, have TEX attirbute, only for XScale */
- 0xFFFFFC00 /* TLB_TINYPAGE */
-};
-
-/* This function encodes table 8-2 Interpreting AP bits,
- returning non-zero if access is allowed. */
-static int
-check_perms (ARMul_State * state, int ap, int read)
-{
- int s, r, user;
-
- s = state->mmu.control & CONTROL_SYSTEM;
- r = state->mmu.control & CONTROL_ROM;
- //chy 2006-02-15 , should consider system mode, don't conside 26bit mode
- user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE);
-
- switch (ap) {
- case 0:
- return read && ((s && !user) || r);
- case 1:
- return !user;
- case 2:
- return read || !user;
- case 3:
- return 1;
- }
- return 0;
-}
-
-fault_t
-check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb,
- int read)
-{
- int access;
-
- state->mmu.last_domain = tlb->domain;
- access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3;
- if ((access == 0) || (access == 2)) {
- /* It's unclear from the documentation whether this
- should always raise a section domain fault, or if
- it should be a page domain fault in the case of an
- L1 that describes a page table. In the ARM710T
- datasheets, "Figure 8-9: Sequence for checking faults"
- seems to indicate the former, while "Table 8-4: Priority
- encoding of fault status" gives a value for FS[3210] in
- the event of a domain fault for a page. Hmm. */
- return SECTION_DOMAIN_FAULT;
- }
- if (access == 1) {
- /* client access - check perms */
- int subpage, ap;
-
- switch (tlb->mapping) {
- /*ks 2004-05-09
- * only for XScale
- * Extend Small Page(ESP) Format
- * 31-12 bits the base addr of ESP
- * 11-10 bits SBZ
- * 9-6 bits TEX
- * 5-4 bits AP
- * 3 bit C
- * 2 bit B
- * 1-0 bits 11
- * */
- case TLB_ESMALLPAGE: //xj
- subpage = 0;
- //printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr );
- break;
-
- case TLB_TINYPAGE:
- subpage = 0;
- //printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr );
- break;
-
- case TLB_SMALLPAGE:
- subpage = (virt_addr >> 10) & 3;
- break;
- case TLB_LARGEPAGE:
- subpage = (virt_addr >> 14) & 3;
- break;
- case TLB_SECTION:
- subpage = 3;
- break;
- default:
- assert (0);
- subpage = 0; /* cleans a warning */
- }
- ap = (tlb->perms >> (subpage * 2 + 4)) & 3;
- if (!check_perms (state, ap, read)) {
- if (tlb->mapping == TLB_SECTION) {
- return SECTION_PERMISSION_FAULT;
- }
- else {
- return SUBPAGE_PERMISSION_FAULT;
- }
- }
- }
- else { /* access == 3 */
- /* manager access - don't check perms */
- }
- return NO_FAULT;
-}
-
-fault_t
-translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t,
- tlb_entry_t ** tlb)
-{
- *tlb = mmu_tlb_search (state, tlb_t, virt_addr);
- if (!*tlb) {
- /* walk the translation tables */
- ARMword l1addr, l1desc;
- tlb_entry_t entry;
-
- l1addr = state->mmu.translation_table_base & 0xFFFFC000;
- l1addr = (l1addr | (virt_addr >> 18)) & ~3;
- //l1desc = mem_read_word (state, l1addr);
- bus_read(32, l1addr, &l1desc);
- switch (l1desc & 3) {
- case 0:
- /*
- * according to Figure 3-9 Sequence for checking faults in arm manual,
- * section translation fault should be returned here.
- */
- {
- return SECTION_TRANSLATION_FAULT;
- }
- case 3:
- /* fine page table */
- // dcl 2006-01-08
- {
- ARMword l2addr, l2desc;
-
- l2addr = l1desc & 0xFFFFF000;
- l2addr = (l2addr |
- ((virt_addr & 0x000FFC00) >> 8)) &
- ~3;
- //l2desc = mem_read_word (state, l2addr);
- bus_read(32, l2addr, &l2desc);
-
- entry.virt_addr = virt_addr;
- entry.phys_addr = l2desc;
- entry.perms = l2desc & 0x00000FFC;
- entry.domain = (l1desc >> 5) & 0x0000000F;
- switch (l2desc & 3) {
- case 0:
- state->mmu.last_domain = entry.domain;
- return PAGE_TRANSLATION_FAULT;
- case 3:
- entry.mapping = TLB_TINYPAGE;
- break;
- case 1:
- // this is untested
- entry.mapping = TLB_LARGEPAGE;
- break;
- case 2:
- // this is untested
- entry.mapping = TLB_SMALLPAGE;
- break;
- }
- }
- break;
- case 1:
- /* coarse page table */
- {
- ARMword l2addr, l2desc;
-
- l2addr = l1desc & 0xFFFFFC00;
- l2addr = (l2addr |
- ((virt_addr & 0x000FF000) >> 10)) &
- ~3;
- //l2desc = mem_read_word (state, l2addr);
- bus_read(32, l2addr, &l2desc);
-
- entry.virt_addr = virt_addr;
- entry.phys_addr = l2desc;
- entry.perms = l2desc & 0x00000FFC;
- entry.domain = (l1desc >> 5) & 0x0000000F;
- //printf("SKYEYE:PAGE virt_addr = %x,l1desc=%x,phys_addr=%x\n",virt_addr,l1desc,entry.phys_addr);
- //chy 2003-09-02 for xscale
- switch (l2desc & 3) {
- case 0:
- state->mmu.last_domain = entry.domain;
- return PAGE_TRANSLATION_FAULT;
- case 3:
- if (!state->is_XScale) {
- state->mmu.last_domain =
- entry.domain;
- return PAGE_TRANSLATION_FAULT;
- };
- //ks 2004-05-09 xscale shold use Extend Small Page
- //entry.mapping = TLB_SMALLPAGE;
- entry.mapping = TLB_ESMALLPAGE; //xj
- break;
- case 1:
- entry.mapping = TLB_LARGEPAGE;
- break;
- case 2:
- entry.mapping = TLB_SMALLPAGE;
- break;
- }
- }
- break;
- case 2:
- /* section */
- //printf("SKYEYE:WARNING: not implement section mapping incompletely\n");
- //printf("SKYEYE:SECTION virt_addr = %x,l1desc=%x\n",virt_addr,l1desc);
- //return SECTION_DOMAIN_FAULT;
- //#if 0
- entry.virt_addr = virt_addr;
- entry.phys_addr = l1desc;
- entry.perms = l1desc & 0x00000C0C;
- entry.domain = (l1desc >> 5) & 0x0000000F;
- entry.mapping = TLB_SECTION;
- break;
- //#endif
- }
- entry.virt_addr &= tlb_masks[entry.mapping];
- entry.phys_addr &= tlb_masks[entry.mapping];
-
- /* place entry in the tlb */
- *tlb = &tlb_t->entrys[tlb_t->cycle];
- tlb_t->cycle = (tlb_t->cycle + 1) % tlb_t->num;
- **tlb = entry;
- }
- state->mmu.last_domain = (*tlb)->domain;
- return NO_FAULT;
-}
-
-int
-mmu_tlb_init (tlb_s * tlb_t, int num)
-{
- tlb_entry_t *e;
- int i;
-
- e = (tlb_entry_t *) malloc (sizeof (*e) * num);
- if (e == NULL) {
- ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*e) * num);
- goto tlb_malloc_error;
- }
- tlb_t->entrys = e;
- for (i = 0; i < num; i++, e++)
- e->mapping = TLB_INVALID;
- tlb_t->cycle = 0;
- tlb_t->num = num;
- return 0;
-
- tlb_malloc_error:
- return -1;
-}
-
-void
-mmu_tlb_exit (tlb_s * tlb_t)
-{
- free (tlb_t->entrys);
-};
-
-void
-mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t)
-{
- int entry;
-
- for (entry = 0; entry < tlb_t->num; entry++) {
- tlb_t->entrys[entry].mapping = TLB_INVALID;
- }
- tlb_t->cycle = 0;
-}
-
-void
-mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr)
-{
- tlb_entry_t *tlb;
-
- tlb = mmu_tlb_search (state, tlb_t, addr);
- if (tlb) {
- tlb->mapping = TLB_INVALID;
- }
-}
-
-tlb_entry_t *
-mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, ARMword virt_addr)
-{
- int entry;
-
- for (entry = 0; entry < tlb_t->num; entry++) {
- tlb_entry_t *tlb;
- ARMword mask;
-
- tlb = &(tlb_t->entrys[entry]);
- if (tlb->mapping == TLB_INVALID) {
- continue;
- }
- mask = tlb_masks[tlb->mapping];
- if ((virt_addr & mask) == (tlb->virt_addr & mask)) {
- return tlb;
- }
- }
- return NULL;
-}
diff --git a/src/core/arm/interpreter/mmu/tlb.h b/src/core/arm/interpreter/mmu/tlb.h
deleted file mode 100644
index 40856567b..000000000
--- a/src/core/arm/interpreter/mmu/tlb.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef _MMU_TLB_H_
-#define _MMU_TLB_H_
-
-typedef enum tlb_mapping_t
-{
- TLB_INVALID = 0,
- TLB_SMALLPAGE = 1,
- TLB_LARGEPAGE = 2,
- TLB_SECTION = 3,
- TLB_ESMALLPAGE = 4,
- TLB_TINYPAGE = 5
-} tlb_mapping_t;
-
-extern ARMword tlb_masks[];
-
-/* Permissions bits in a TLB entry:
- *
- * 31 12 11 10 9 8 7 6 5 4 3 2 1 0
- * +-------------+-----+-----+-----+-----+---+---+-------+
- * Page:| | ap3 | ap2 | ap1 | ap0 | C | B | |
- * +-------------+-----+-----+-----+-----+---+---+-------+
- *
- * 31 12 11 10 9 4 3 2 1 0
- * +-------------+-----+-----------------+---+---+-------+
- * Section: | | AP | | C | B | |
- * +-------------+-----+-----------------+---+---+-------+
- */
-
-/*
-section:
- section base address [31:20]
- AP - table 8-2, page 8-8
- domain
- C,B
-
-page:
- page base address [31:16] or [31:12]
- ap[3:0]
- domain (from L1)
- C,B
-*/
-
-
-typedef struct tlb_entry_t
-{
- ARMword virt_addr;
- ARMword phys_addr;
- ARMword perms;
- ARMword domain;
- tlb_mapping_t mapping;
-} tlb_entry_t;
-
-typedef struct tlb_s
-{
- int num; /*num of tlb entry */
- int cycle; /*current tlb cycle */
- tlb_entry_t *entrys;
-} tlb_s;
-
-
-#define tlb_c_flag(tlb) \
- ((tlb)->perms & 0x8)
-#define tlb_b_flag(tlb) \
- ((tlb)->perms & 0x4)
-
-#define tlb_va_to_pa(tlb, va) ((tlb->phys_addr & tlb_masks[tlb->mapping]) | (va & ~tlb_masks[tlb->mapping]))
-fault_t
-check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb,
- int read);
-
-fault_t
-translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t,
- tlb_entry_t ** tlb);
-
-int mmu_tlb_init (tlb_s * tlb_t, int num);
-
-void mmu_tlb_exit (tlb_s * tlb_t);
-
-void mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t);
-
-void
-mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr);
-
-tlb_entry_t *mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t,
- ARMword virt_addr);
-
-#endif /*_MMU_TLB_H_*/
diff --git a/src/core/arm/interpreter/mmu/wb.cpp b/src/core/arm/interpreter/mmu/wb.cpp
deleted file mode 100644
index 82c0cec02..000000000
--- a/src/core/arm/interpreter/mmu/wb.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "core/arm/interpreter/armdefs.h"
-
-/* wb_init
- * @wb_t :wb_t to init
- * @num :num of entrys
- * @nb :num of byte of each entry
- *
- * $ -1:error
- * 0:ok
- * */
-int
-mmu_wb_init (wb_s * wb_t, int num, int nb)
-{
- int i;
- wb_entry_t *entrys, *wb;
-
- entrys = (wb_entry_t *) malloc (sizeof (*entrys) * num);
- if (entrys == NULL) {
- ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*entrys) * num);
- goto entrys_malloc_error;
- }
-
- for (wb = entrys, i = 0; i < num; i++, wb++) {
- /*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu */
- //wb->data = (ARMword *)malloc(sizeof(ARMword) * nb);
- wb->data = (ARMbyte *) malloc (nb);
- if (wb->data == NULL) {
- ERROR_LOG(ARM11, "malloc size of %d\n", nb);
- goto data_malloc_error;
- }
-
- };
-
- wb_t->first = wb_t->last = wb_t->used = 0;
- wb_t->num = num;
- wb_t->nb = nb;
- wb_t->entrys = entrys;
- return 0;
-
- data_malloc_error:
- while (--i >= 0)
- free (entrys[i].data);
- free (entrys);
- entrys_malloc_error:
- return -1;
-};
-
-/* wb_exit
- * @wb_t :wb_t to exit
- * */
-void
-mmu_wb_exit (wb_s * wb_t)
-{
- int i;
- wb_entry_t *wb;
-
- wb = wb_t->entrys;
- for (i = 0; i < wb_t->num; i++, wb++) {
- free (wb->data);
- }
- free (wb_t->entrys);
-};
-
-/* wb_write_words :put words in Write Buffer
- * @state: ARMul_State
- * @wb_t: write buffer
- * @pa: physical address
- * @data: data ptr
- * @n number of word to write
- *
- * Note: write buffer merge is not implemented, can be done late
- * */
-void
-mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa,
- ARMbyte * data, int n)
-{
- int i;
- wb_entry_t *wb;
-
- while (n) {
- if (wb_t->num == wb_t->used) {
- /*clean the last wb entry */
- ARMword t;
-
- wb = &wb_t->entrys[wb_t->last];
- t = wb->pa;
- for (i = 0; i < wb->nb; i++) {
- //mem_write_byte (state, t, wb->data[i]);
- bus_write(8, t, wb->data[i]);
- //t += WORD_SIZE;
- t++;
- }
- wb_t->last++;
- if (wb_t->last == wb_t->num)
- wb_t->last = 0;
- wb_t->used--;
- }
-
- wb = &wb_t->entrys[wb_t->first];
- i = (n < wb_t->nb) ? n : wb_t->nb;
-
- wb->pa = pa;
- //pa += i << WORD_SHT;
- pa += i;
-
- wb->nb = i;
- //memcpy(wb->data, data, i << WORD_SHT);
- memcpy (wb->data, data, i);
- data += i;
- n -= i;
- wb_t->first++;
- if (wb_t->first == wb_t->num)
- wb_t->first = 0;
- wb_t->used++;
- };
-//teawater add for set_dirty fflash cache function 2005.07.18-------------------
-#ifdef DBCT
- if (!skyeye_config.no_dbct) {
- tb_setdirty (state, pa, NULL);
- }
-#endif
-//AJ2D--------------------------------------------------------------------------
-}
-
-/* wb_drain_all
- * @wb_t wb_t to drain
- * */
-void
-mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t)
-{
- ARMword pa;
- wb_entry_t *wb;
- int i;
-
- while (wb_t->used) {
- wb = &wb_t->entrys[wb_t->last];
- pa = wb->pa;
- for (i = 0; i < wb->nb; i++) {
- //mem_write_byte (state, pa, wb->data[i]);
- bus_write(8, pa, wb->data[i]);
- //pa += WORD_SIZE;
- pa++;
- }
- wb_t->last++;
- if (wb_t->last == wb_t->num)
- wb_t->last = 0;
- wb_t->used--;
- };
-}
diff --git a/src/core/arm/interpreter/mmu/wb.h b/src/core/arm/interpreter/mmu/wb.h
deleted file mode 100644
index 8fb7de946..000000000
--- a/src/core/arm/interpreter/mmu/wb.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef _MMU_WB_H_
-#define _MMU_WB_H_
-
-typedef struct wb_entry_s
-{
- ARMword pa; //phy_addr
- ARMbyte *data; //data
- int nb; //number byte to write
-} wb_entry_t;
-
-typedef struct wb_s
-{
- int num; //number of wb_entry
- int nb; //number of byte of each entry
- int first; //
- int last; //
- int used; //
- wb_entry_t *entrys;
-} wb_s;
-
-typedef struct wb_desc_s
-{
- int num;
- int nb;
-} wb_desc_t;
-
-/* wb_init
- * @wb_t :wb_t to init
- * @num :num of entrys
- * @nw :num of word of each entry
- *
- * $ -1:error
- * 0:ok
- * */
-int mmu_wb_init (wb_s * wb_t, int num, int nb);
-
-
-/* wb_exit
- * @wb_t :wb_t to exit
- * */
-void mmu_wb_exit (wb_s * wb);
-
-
-/* wb_write_bytes :put bytess in Write Buffer
- * @state: ARMul_State
- * @wb_t: write buffer
- * @pa: physical address
- * @data: data ptr
- * @n number of byte to write
- *
- * Note: write buffer merge is not implemented, can be done late
- * */
-void
-mmu_wb_write_bytess (ARMul_State * state, wb_s * wb_t, ARMword pa,
- ARMbyte * data, int n);
-
-
-/* wb_drain_all
- * @wb_t wb_t to drain
- * */
-void mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t);
-
-#endif /*_MMU_WB_H_*/
diff --git a/src/core/arm/interpreter/mmu/xscale_copro.cpp b/src/core/arm/interpreter/mmu/xscale_copro.cpp
deleted file mode 100644
index 433ce8e02..000000000
--- a/src/core/arm/interpreter/mmu/xscale_copro.cpp
+++ /dev/null
@@ -1,1391 +0,0 @@
-/*
- armmmu.c - Memory Management Unit emulation.
- ARMulator extensions for the ARM7100 family.
- Copyright (C) 1999 Ben Williamson
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <assert.h>
-#include <string.h>
-
-#include "core/arm/interpreter/armdefs.h"
-#include "core/arm/interpreter/armemu.h"
-
-/*#include "pxa.h" */
-
-/* chy 2005-09-19 */
-
-/* extern pxa270_io_t pxa270_io; */
-/* chy 2005-09-19 -----end */
-
-typedef struct xscale_mmu_desc_s
-{
- int i_tlb;
- cache_desc_t i_cache;
-
- int d_tlb;
- cache_desc_t main_d_cache;
- cache_desc_t mini_d_cache;
- //int rb; xscale has no read buffer
- wb_desc_t wb;
-} xscale_mmu_desc_t;
-
-static xscale_mmu_desc_t pxa_mmu_desc = {
- 32,
- {32, 32, 32, CACHE_WRITE_BACK},
-
- 32,
- {32, 32, 32, CACHE_WRITE_BACK},
- {32, 2, 8, CACHE_WRITE_BACK},
- {8, 16}, //for byte size,
-};
-
-//chy 2005-09-19 for cp6
-#define CR0_ICIP 0
-#define CR1_ICMR 1
-//chy 2005-09-19 ---end
-//----------- for cp14-----------------
-#define CCLKCFG 6
-#define PWRMODE 7
-typedef struct xscale_cp14_reg_s
-{
- unsigned cclkcfg; //reg6
- unsigned pwrmode; //reg7
-} xscale_cp14_reg_s;
-
-xscale_cp14_reg_s pxa_cp14_regs;
-
-//--------------------------------------
-
-static fault_t xscale_mmu_write (ARMul_State * state, ARMword va,
- ARMword data, ARMword datatype);
-static fault_t xscale_mmu_read (ARMul_State * state, ARMword va,
- ARMword * data, ARMword datatype);
-
-ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value);
-ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value);
-
-
-/* jeff add 2010.9.26 for pxa270 cp6*/
-#define PXA270_ICMR 0x40D00004
-#define PXA270_ICPR 0x40D00010
-#define PXA270_ICLR 0x40D00008
-//chy 2005-09-19 for xscale pxa27x cp6
-unsigned
-xscale_cp6_mrc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword * data)
-{
- unsigned opcode_2 = BITS (5, 7);
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
-
- //printf("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,state->Reg[15], instr);
-
- switch (reg) {
- case CR0_ICIP: { // cp 6 reg 0
- //printf("cp6_mrc cr0 ICIP \n");
- /* *data = (pxa270_io.icmr & pxa270_io.icpr) & ~pxa270_io.iclr; */
- /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/
- int icmr, icpr, iclr;
- bus_read(32, PXA270_ICMR, (uint32_t*)&icmr);
- bus_read(32, PXA270_ICPR, (uint32_t*)&icpr);
- bus_read(32, PXA270_ICLR, (uint32_t*)&iclr);
- *data = (icmr & icpr) & ~iclr;
- }
- break;
- case CR1_ICMR: { // cp 6 reg 1
- //printf("cp6_mrc cr1 ICMR\n");
- /* *data = pxa270_io.icmr; */
- int icmr;
- /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/
- bus_read(32, PXA270_ICMR, (uint32_t*)&icmr);
- *data = icmr;
- }
- break;
- default:
- *data = 0;
- printf ("SKYEYE:cp6_mrc unknown cp6 regs!!!!!!\n");
- printf ("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n", opcode_2, CRm, reg, state->Reg[15], instr);
- break;
- }
- return 0;
-}
-
-//chy 2005-09-19 end
-//xscale cp13 ----------------------------------------------------
-unsigned
-xscale_cp13_init (ARMul_State * state)
-{
- //printf("SKYEYE: xscale_cp13_init: begin\n");
- return 0;
-}
-
-unsigned
-xscale_cp13_exit (ARMul_State * state)
-{
- //printf("SKYEYE: xscale_cp13_exit: begin\n");
- return 0;
-}
-
-unsigned
-xscale_cp13_ldc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword data)
-{
- printf ("SKYEYE: xscale_cp13_ldc: ERROR isn't existed,");
- SKYEYE_OUTREGS (stderr);
- fprintf (stderr, "\n");
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-
-unsigned
-xscale_cp13_stc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword * data)
-{
- printf ("SKYEYE: xscale_cp13_stc: ERROR isn't existed,");
- SKYEYE_OUTREGS (stderr);
- fprintf (stderr, "\n");
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-
-unsigned
-xscale_cp13_mrc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword * data)
-{
- printf ("SKYEYE: xscale_cp13_mrc: ERROR isn't existed,");
- SKYEYE_OUTREGS (stderr);
- fprintf (stderr, "\n");
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-
-unsigned
-xscale_cp13_mcr (ARMul_State * state, unsigned type, ARMword instr,
- ARMword data)
-{
- printf ("SKYEYE: xscale_cp13_mcr: ERROR isn't existed,");
- SKYEYE_OUTREGS (stderr);
- fprintf (stderr, "\n");
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-
-unsigned
-xscale_cp13_cdp (ARMul_State * state, unsigned type, ARMword instr)
-{
- printf ("SKYEYE: xscale_cp13_cdp: ERROR isn't existed,");
- SKYEYE_OUTREGS (stderr);
- fprintf (stderr, "\n");
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-
-unsigned
-xscale_cp13_read_reg (ARMul_State * state, unsigned reg, ARMword * data)
-{
- printf ("SKYEYE: xscale_cp13_read_reg: ERROR isn't existed,");
- SKYEYE_OUTREGS (stderr);
- fprintf (stderr, "\n");
- return 0;
- //exit(-1);
-}
-
-unsigned
-xscale_cp13_write_reg (ARMul_State * state, unsigned reg, ARMword data)
-{
- printf ("SKYEYE: xscale_cp13_write_reg: ERROR isn't existed,");
- SKYEYE_OUTREGS (stderr);
- fprintf (stderr, "\n");
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-
-//------------------------------------------------------------------
-//xscale cp14 ----------------------------------------------------
-unsigned
-xscale_cp14_init (ARMul_State * state)
-{
- //printf("SKYEYE: xscale_cp14_init: begin\n");
- pxa_cp14_regs.cclkcfg = 0;
- pxa_cp14_regs.pwrmode = 0;
- return 0;
-}
-
-unsigned
-xscale_cp14_exit (ARMul_State * state)
-{
- //printf("SKYEYE: xscale_cp14_exit: begin\n");
- return 0;
-}
-
-unsigned
-xscale_cp14_ldc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword data)
-{
- printf ("SKYEYE: xscale_cp14_ldc: ERROR isn't existed, reg15 0x%x\n",
- state->Reg[15]);
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-
-unsigned
-xscale_cp14_stc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword * data)
-{
- printf ("SKYEYE: xscale_cp14_stc: ERROR isn't existed, reg15 0x%x\n",
- state->Reg[15]);
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-
-unsigned
-xscale_cp14_mrc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword * data)
-{
- unsigned opcode_2 = BITS (5, 7);
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
-
- //printf("SKYEYE: xscale_cp14_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\
- state->Reg[15], instr);
-
- switch (reg) {
- case CCLKCFG: // cp 14 reg 6
- //printf("cp14_mrc cclkcfg \n");
- *data = pxa_cp14_regs.cclkcfg;
- break;
- case PWRMODE: // cp 14 reg 7
- //printf("cp14_mrc pwrmode \n");
- *data = pxa_cp14_regs.pwrmode;
- break;
- default:
- *data = 0;
- printf ("SKYEYE:cp14_mrc unknown cp14 regs!!!!!!\n");
- break;
- }
- return 0;
-}
-unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, ARMword instr,
- ARMword data)
-{
- unsigned opcode_2 = BITS (5, 7);
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
-
- //printf("SKYEYE: xscale_cp14_mcr:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\
- state->Reg[15], instr);
-
- switch (reg) {
- case CCLKCFG: // cp 14 reg 6
- //printf("cp14_mcr cclkcfg \n");
- pxa_cp14_regs.cclkcfg = data & 0xf;
- break;
- case PWRMODE: // cp 14 reg 7
- //printf("cp14_mcr pwrmode \n");
- pxa_cp14_regs.pwrmode = data & 0x3;
- break;
- default:printf ("SKYEYE: cp14_mcr unknown cp14 regs!!!!!!\n");
- break;
- }
- return 0;
-}
-unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, ARMword instr)
-{
- printf ("SKYEYE: xscale_cp14_cdp: ERROR isn't existed, reg15 0x%x\n",
- state->Reg[15]);
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg,
- ARMword * data)
-{
- printf ("SKYEYE: xscale_cp14_read_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]);
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
- return 0; //No matter return value, only for compiler.
-}
-unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg,
- ARMword data)
-{
- printf ("SKYEYE: xscale_cp14_write_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]);
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
-
- return 0; //No matter return value, only for compiler.
-}
-
-//------------------------------------------------------------------
-//cp15 -------------------------------------
-unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword data)
-{
- printf ("SKYEYE: xscale_cp15_ldc: ERROR isn't existed\n");
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
-
- return 0; //No matter return value, only for compiler.
-}
-unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, ARMword instr,
- ARMword * data)
-{
- printf ("SKYEYE: xscale_cp15_stc: ERROR isn't existed\n");
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
-
- return 0; //No matter return value, only for compiler.
-}
-unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, ARMword instr)
-{
- printf ("SKYEYE: xscale_cp15_cdp: ERROR isn't existed\n");
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
-
- return 0; //No matter return value, only for compiler.
-}
-unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg,
- ARMword * data)
-{
-//chy 2003-09-03: for xsacle_cp15_cp_access_allowed
- if (reg == 15) {
- *data = state->mmu.copro_access;
- //printf("SKYEYE: xscale_cp15_read_reg: reg 0x%x,data %x\n",reg,*data);
- return 0;
- }
- printf ("SKYEYE: xscale_cp15_read_reg: reg 0x%x, ERROR isn't existed\n", reg);
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
-
- return 0; //No matter return value, only for compiler.
-}
-
-//chy 2003-09-03 used by macro CP_ACCESS_ALLOWED in armemu.h
-unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
- unsigned cpnum)
-{
- unsigned data;
-
- xscale_cp15_read_reg (state, reg, &data);
- //printf("SKYEYE: cp15_cp_access_allowed data %x, cpnum %x, result %x\n", data, cpnum, (data & 1<<cpnum));
- if (data & 1 << cpnum)
- return 1;
- else
- return 0;
-}
-
-unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg,
- ARMword value)
-{
- switch (reg) {
- case MMU_FAULT_STATUS:
- //printf("SKYEYE:cp15_write_reg wrote FS val 0x%x \n",value);
- state->mmu.fault_status = value & 0x6FF;
- break;
- case MMU_FAULT_ADDRESS:
- //printf("SKYEYE:cp15_write_reg wrote FA val 0x%x \n",value);
- state->mmu.fault_address = value;
- break;
- default:
- printf ("SKYEYE: xscale_cp15_write_reg: reg 0x%x R15 %x ERROR isn't existed\n", reg, state->Reg[15]);
- SKYEYE_OUTREGS (stderr);
- // skyeye_exit (-1);
- }
- return 0;
-}
-
-unsigned
-xscale_cp15_init (ARMul_State * state)
-{
- xscale_mmu_desc_t *desc;
- cache_desc_t *c_desc;
-
- state->mmu.control = 0;
- state->mmu.translation_table_base = 0xDEADC0DE;
- state->mmu.domain_access_control = 0xDEADC0DE;
- state->mmu.fault_status = 0;
- state->mmu.fault_address = 0;
- state->mmu.process_id = 0;
- state->mmu.cache_type = 0xB1AA1AA; //0000 1011 0001 1010 1010 0001 1010 1010
- state->mmu.aux_control = 0;
-
- desc = &pxa_mmu_desc;
-
- if (mmu_tlb_init (I_TLB (), desc->i_tlb)) {
- ERROR_LOG(ARM11, "i_tlb init %d\n", -1);
- goto i_tlb_init_error;
- }
-
- c_desc = &desc->i_cache;
- if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way,
- c_desc->set, c_desc->w_mode)) {
- ERROR_LOG(ARM11, "i_cache init %d\n", -1);
- goto i_cache_init_error;
- }
-
- if (mmu_tlb_init (D_TLB (), desc->d_tlb)) {
- ERROR_LOG(ARM11, "d_tlb init %d\n", -1);
- goto d_tlb_init_error;
- }
-
- c_desc = &desc->main_d_cache;
- if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way,
- c_desc->set, c_desc->w_mode)) {
- ERROR_LOG(ARM11, "main_d_cache init %d\n", -1);
- goto main_d_cache_init_error;
- }
-
- c_desc = &desc->mini_d_cache;
- if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way,
- c_desc->set, c_desc->w_mode)) {
- ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1);
- goto mini_d_cache_init_error;
- }
-
- if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) {
- ERROR_LOG(ARM11, "wb init %d\n", -1);
- goto wb_init_error;
- }
-#if 0
- if (mmu_rb_init (RB (), desc->rb)) {
- ERROR_LOG(ARM11, "rb init %d\n", -1);
- goto rb_init_error;
- }
-#endif
-
- return 0;
-#if 0
- rb_init_error:
- mmu_wb_exit (WB ());
-#endif
- wb_init_error:
- mmu_cache_exit (MINI_D_CACHE ());
- mini_d_cache_init_error:
- mmu_cache_exit (MAIN_D_CACHE ());
- main_d_cache_init_error:
- mmu_tlb_exit (D_TLB ());
- d_tlb_init_error:
- mmu_cache_exit (I_CACHE ());
- i_cache_init_error:
- mmu_tlb_exit (I_TLB ());
- i_tlb_init_error:
- return -1;
-}
-
-unsigned
-xscale_cp15_exit (ARMul_State * state)
-{
- //mmu_rb_exit(RB());
- mmu_wb_exit (WB ());
- mmu_cache_exit (MINI_D_CACHE ());
- mmu_cache_exit (MAIN_D_CACHE ());
- mmu_tlb_exit (D_TLB ());
- mmu_cache_exit (I_CACHE ());
- mmu_tlb_exit (I_TLB ());
- return 0;
-};
-
-
-static fault_t
- xscale_mmu_load_instr (ARMul_State * state, ARMword va,
- ARMword * instr)
-{
- fault_t fault;
- tlb_entry_t *tlb;
- cache_line_t *cache;
- int c; //cache bit
- ARMword pa; //physical addr
-
- static int debug_count = 0; //used for debug
-
- DEBUG_LOG(ARM11, "va = %x\n", va);
-
- va = mmu_pid_va_map (va);
- if (MMU_Enabled) {
- /*align check */
- if ((va & (INSN_SIZE - 1)) && MMU_Aligned) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- }
- else
- va &= ~(INSN_SIZE - 1);
-
- /*translate tlb */
- fault = translate (state, va, I_TLB (), &tlb);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- return fault;
- }
-
- /*check access */
- fault = check_access (state, va, tlb, 1);
- if (fault) {
- DEBUG_LOG(ARM11, "check_fault\n");
- return fault;
- }
- }
- //chy 2003-09-02 for test, don't use cache ?????
-#if 0
- /*search cache no matter MMU enabled/disabled */
- cache = mmu_cache_search (state, I_CACHE (), va);
- if (cache) {
- *instr = cache->data[va_cache_index (va, I_CACHE ())];
- return 0;
- }
-#endif
- /*if MMU disabled or C flag is set alloc cache */
- if (MMU_Disabled) {
- c = 1;
- pa = va;
- }
- else {
- c = tlb_c_flag (tlb);
- pa = tlb_va_to_pa (tlb, va);
- }
-
- //chy 2003-09-03 only read mem, don't use cache now,will change later ????
- //*instr = mem_read_word (state, pa);
- bus_read(32, pa, instr);
-#if 0
-//-----------------------------------------------------------
- //chy 2003-09-02 for test????
- if (pa >= 0xa01c8000 && pa <= 0xa01c8020) {
- printf ("SKYEYE:load_instr: pa %x, va %x,instr %x, R15 %x\n",
- pa, va, *instr, state->Reg[15]);
- }
-
-//----------------------------------------------------------------------
-#endif
- return NO_FAULT;
-
- if (c) {
- int index;
-
- debug_count++;
- cache = mmu_cache_alloc (state, I_CACHE (), va, pa);
- index = va_cache_index (va, I_CACHE ());
- *instr = cache->data[va_cache_index (va, I_CACHE ())];
- }
- else
- //*instr = mem_read_word (state, pa);
- bus_read(32, pa, instr);
-
- return NO_FAULT;
-};
-
-
-
-static fault_t
- xscale_mmu_read_byte (ARMul_State * state, ARMword virt_addr,
- ARMword * data)
-{
- //ARMword temp,offset;
- fault_t fault;
- fault = xscale_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE);
- return fault;
-}
-
-static fault_t
- xscale_mmu_read_halfword (ARMul_State * state, ARMword virt_addr,
- ARMword * data)
-{
- //ARMword temp,offset;
- fault_t fault;
- fault = xscale_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE);
- return fault;
-}
-
-static fault_t
- xscale_mmu_read_word (ARMul_State * state, ARMword virt_addr,
- ARMword * data)
-{
- return xscale_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);
-}
-
-
-
-
-static fault_t
- xscale_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
- ARMword datatype)
-{
- fault_t fault;
-// rb_entry_t *rb;
- tlb_entry_t *tlb;
- cache_line_t *cache;
- ARMword pa, real_va, temp, offset;
- //chy 2003-09-02 for test ????
- static unsigned chyst1 = 0, chyst2 = 0;
-
- DEBUG_LOG(ARM11, "va = %x\n", va);
-
- va = mmu_pid_va_map (va);
- real_va = va;
- /*if MMU disabled, memory_read */
- if (MMU_Disabled) {
- //*data = mem_read_word(state, va);
- if (datatype == ARM_BYTE_TYPE)
- //*data = mem_read_byte (state, va);
- bus_read(8, va, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //*data = mem_read_halfword (state, va);
- bus_read(16, va, data);
- else if (datatype == ARM_WORD_TYPE)
- //*data = mem_read_word (state, va);
- bus_read(32, va, data);
- else {
- printf ("SKYEYE:1 xscale_mmu_read error: unknown data type %d\n", datatype);
- // skyeye_exit (-1);
- }
-
- return NO_FAULT;
- }
-
- /*align check */
- if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
- ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- } // else
-
- va &= ~(WORD_SIZE - 1);
-
- /*translate va to tlb */
- fault = translate (state, va, D_TLB (), &tlb);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- return fault;
- }
- /*check access permission */
- fault = check_access (state, va, tlb, 1);
- if (fault)
- return fault;
-
-#if 0
-//------------------------------------------------
-//chy 2003-09-02 for test only ,should commit ????
- if (datatype == ARM_WORD_TYPE) {
- if (real_va >= 0xffff0000 && real_va <= 0xffff0020) {
- pa = tlb_va_to_pa (tlb, va);
- *data = mem_read_word (state, pa);
- chyst1++;
- printf ("**SKYEYE:mmu_read word %d: pa %x, va %x, data %x, R15 %x\n", chyst1, pa, real_va, *data, state->Reg[15]);
- /*
- cache==mmu_cache_search(state,MAIN_D_CACHE(),va);
- if(cache){
- *data = cache->data[va_cache_index(va, MAIN_D_CACHE())];
- printf("cached data %x\n",*data);
- }else printf("no cached data\n");
- */
- }
- }
-//-------------------------------------------------
-#endif
-#if 0
- /*search in read buffer */
- rb = mmu_rb_search (RB (), va);
- if (rb) {
- if (rb->fault)
- return rb->fault;
- *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT];
- goto datatrans;
- //return 0;
- };
-#endif
-
- /*2004-07-19 chy: add support of xscale MMU CacheDisabled option */
- if (MMU_CacheDisabled) {
- //if(1){ can be used to test cache error
- /*get phy_addr */
- pa = tlb_va_to_pa (tlb, real_va);
- if (datatype == ARM_BYTE_TYPE)
- //*data = mem_read_byte (state, pa);
- bus_read(8, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //*data = mem_read_halfword (state, pa);
- bus_read(16, pa, data);
- else if (datatype == ARM_WORD_TYPE)
- //*data = mem_read_word (state, pa);
- bus_read(32, pa, data);
- else {
- printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_read error: unknown data type %d\n", datatype);
- // skyeye_exit (-1);
- }
- return NO_FAULT;
- }
-
-
- /*search main cache */
- cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
- if (cache) {
- *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())];
-#if 0
-//------------------------------------------------------------------------
-//chy 2003-09-02 for test only ,should commit ????
- if (real_va >= 0xffff0000 && real_va <= 0xffff0020) {
- pa = tlb_va_to_pa (tlb, va);
- chyst2++;
- printf ("**SKYEYE:mmu_read wordk:cache %d: pa %x, va %x, data %x, R15 %x\n", chyst2, pa, real_va, *data, state->Reg[15]);
- }
-//-------------------------------------------------------------------
-#endif
- goto datatrans;
- //return 0;
- }
- //chy 2003-08-24, now maybe we don't need minidcache ????
-#if 0
- /*search mini cache */
- cache = mmu_cache_search (state, MINI_D_CACHE (), va);
- if (cache) {
- *data = cache->data[va_cache_index (va, MINI_D_CACHE ())];
- goto datatrans;
- //return 0;
- }
-#endif
- /*get phy_addr */
- pa = tlb_va_to_pa (tlb, va);
- //chy 2003-08-24 , in xscale it means what ?????
-#if 0
- if ((pa >= 0xe0000000) && (pa < 0xe8000000)) {
-
- if (tlb_c_flag (tlb)) {
- if (tlb_b_flag (tlb)) {
- mmu_cache_soft_flush (state, MAIN_D_CACHE (),
- pa);
- }
- else {
- mmu_cache_soft_flush (state, MINI_D_CACHE (),
- pa);
- }
- }
- return 0;
- }
-#endif
- //chy 2003-08-24, check phy addr
- //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address
- /*
- if(pa >= 0xb0000000){
- printf("SKYEYE:xscale_mmu_read: phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]);
- return 0;
- }
- */
-
- //chy 2003-08-24, now maybe we don't need wb ????
-#if 0
- /*if Buffer, drain Write Buffer first */
- if (tlb_b_flag (tlb))
- mmu_wb_drain_all (state, WB ());
-#endif
- /*alloc cache or mem_read */
- if (tlb_c_flag (tlb) && MMU_DCacheEnabled) {
- cache_s *cache_t;
-
- if (tlb_b_flag (tlb))
- cache_t = MAIN_D_CACHE ();
- else
- cache_t = MINI_D_CACHE ();
- cache = mmu_cache_alloc (state, cache_t, va, pa);
- *data = cache->data[va_cache_index (va, cache_t)];
- }
- else {
- //*data = mem_read_word(state, pa);
- if (datatype == ARM_BYTE_TYPE)
- //*data = mem_read_byte (state, pa | (real_va & 3));
- bus_read(8, pa | (real_va & 3), data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //*data = mem_read_halfword (state, pa | (real_va & 2));
- bus_read(16, pa | (real_va & 2), data);
- else if (datatype == ARM_WORD_TYPE)
- //*data = mem_read_word (state, pa);
- bus_read(32, pa, data);
- else {
- printf ("SKYEYE:2 xscale_mmu_read error: unknown data type %d\n", datatype);
- // skyeye_exit (-1);
- }
- return NO_FAULT;
- }
-
-
- datatrans:
- if (datatype == ARM_HALFWORD_TYPE) {
- temp = *data;
- offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
- *data = (temp >> offset) & 0xffff;
- }
- else if (datatype == ARM_BYTE_TYPE) {
- temp = *data;
- offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
- *data = (temp >> offset & 0xffL);
- }
- end:
- return NO_FAULT;
-}
-
-
-static fault_t
- xscale_mmu_write_byte (ARMul_State * state, ARMword virt_addr,
- ARMword data)
-{
- return xscale_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);
-}
-
-static fault_t
- xscale_mmu_write_halfword (ARMul_State * state, ARMword virt_addr,
- ARMword data)
-{
- return xscale_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);
-}
-
-static fault_t
- xscale_mmu_write_word (ARMul_State * state, ARMword virt_addr,
- ARMword data)
-{
- return xscale_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);
-}
-
-
-
-static fault_t
- xscale_mmu_write (ARMul_State * state, ARMword va, ARMword data,
- ARMword datatype)
-{
- tlb_entry_t *tlb;
- cache_line_t *cache;
- cache_s *cache_t;
- int b;
- ARMword pa, real_va, temp, offset;
- fault_t fault;
-
- ARMword index;
-//chy 2003-09-02 for test ????
-// static unsigned chyst1=0,chyst2=0;
-
- DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data);
- va = mmu_pid_va_map (va);
- real_va = va;
-
- if (MMU_Disabled) {
- //mem_write_word(state, va, data);
- if (datatype == ARM_BYTE_TYPE)
- //mem_write_byte (state, va, data);
- bus_write(8, va, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //mem_write_halfword (state, va, data);
- bus_write(16, va, data);
- else if (datatype == ARM_WORD_TYPE)
- //mem_write_word (state, va, data);
- bus_write(32, va, data);
- else {
- printf ("SKYEYE:1 xscale_mmu_write error: unknown data type %d\n", datatype);
- // skyeye_exit (-1);
- }
-
- return NO_FAULT;
- }
- /*align check */
- if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
- ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- } //else
- va &= ~(WORD_SIZE - 1);
- /*tlb translate */
- fault = translate (state, va, D_TLB (), &tlb);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- return fault;
- }
- /*tlb check access */
- fault = check_access (state, va, tlb, 0);
- if (fault) {
- DEBUG_LOG(ARM11, "check_access\n");
- return fault;
- }
-
- /*2004-07-19 chy: add support for xscale MMU_CacheDisabled */
- if (MMU_CacheDisabled) {
- //if(1){ can be used to test the cache error
- /*get phy_addr */
- pa = tlb_va_to_pa (tlb, real_va);
- if (datatype == ARM_BYTE_TYPE)
- //mem_write_byte (state, pa, data);
- bus_write(8, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //mem_write_halfword (state, pa, data);
- bus_write(16, pa, data);
- else if (datatype == ARM_WORD_TYPE)
- //mem_write_word (state, pa, data);
- bus_write(32, pa , data);
- else {
- printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_write error: unknown data type %d\n", datatype);
- // skyeye_exit (-1);
- }
-
- return NO_FAULT;
- }
-
- /*search main cache */
- b = tlb_b_flag (tlb);
- pa = tlb_va_to_pa (tlb, va);
- cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
- if (cache) {
- cache_t = MAIN_D_CACHE ();
- goto has_cache;
- }
- //chy 2003-08-24, now maybe we don't need minidcache ????
-#if 0
- /*search mini cache */
- cache = mmu_cache_search (state, MINI_D_CACHE (), va);
- if (cache) {
- cache_t = MINI_D_CACHE ();
- goto has_cache;
- }
-#endif
- b = tlb_b_flag (tlb);
- pa = tlb_va_to_pa (tlb, va);
- //chy 2003-08-24, check phy addr 0xa0000000, size 0x04000000
- //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address
- /*
- if(pa >= 0xb0000000){
- printf("SKYEYE:xscale_mmu_write phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]);
- return 0;
- }
- */
-
- //chy 2003-08-24, now maybe we don't need WB ????
-#if 0
- if (b) {
- if (MMU_WBEnabled) {
- if (datatype == ARM_WORD_TYPE)
- mmu_wb_write_bytes (state, WB (), pa, &data,
- 4);
- else if (datatype == ARM_HALFWORD_TYPE)
- mmu_wb_write_bytes (state, WB (),
- (pa | (real_va & 2)),
- &data, 2);
- else if (datatype == ARM_BYTE_TYPE)
- mmu_wb_write_bytes (state, WB (),
- (pa | (real_va & 3)),
- &data, 1);
-
- }
- else {
- if (datatype == ARM_WORD_TYPE)
- mem_write_word (state, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- mem_write_halfword (state,
- (pa | (real_va & 2)),
- data);
- else if (datatype == ARM_BYTE_TYPE)
- mem_write_byte (state, (pa | (real_va & 3)),
- data);
- }
- }
- else {
-
- mmu_wb_drain_all (state, WB ());
-
- if (datatype == ARM_WORD_TYPE)
- mem_write_word (state, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- mem_write_halfword (state, (pa | (real_va & 2)),
- data);
- else if (datatype == ARM_BYTE_TYPE)
- mem_write_byte (state, (pa | (real_va & 3)), data);
- }
-#endif
- //chy 2003-08-24, just write phy addr
- if (datatype == ARM_WORD_TYPE)
- //mem_write_word (state, pa, data);
- bus_write(32, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //mem_write_halfword (state, (pa | (real_va & 2)), data);
- bus_write(16, pa | (real_va & 2), data);
- else if (datatype == ARM_BYTE_TYPE)
- //mem_write_byte (state, (pa | (real_va & 3)), data);
- bus_write(8, (pa | (real_va & 3)), data);
-#if 0
-//-------------------------------------------------------------
-//chy 2003-09-02 for test ????
- if (datatype == ARM_WORD_TYPE) {
- if (real_va >= 0xffff0000 && real_va <= 0xffff0020) {
- printf ("**SKYEYE:mmu_write word: pa %x, va %x, data %x, R15 %x \n", pa, real_va, data, state->Reg[15]);
- }
- }
-//--------------------------------------------------------------
-#endif
- return NO_FAULT;
-
- has_cache:
- index = va_cache_index (va, cache_t);
- //cache->data[index] = data;
-
- if (datatype == ARM_WORD_TYPE)
- cache->data[index] = data;
- else if (datatype == ARM_HALFWORD_TYPE) {
- temp = cache->data[index];
- offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
- cache->data[index] =
- (temp & ~(0xffffL << offset)) | ((data & 0xffffL) <<
- offset);
- }
- else if (datatype == ARM_BYTE_TYPE) {
- temp = cache->data[index];
- offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
- cache->data[index] =
- (temp & ~(0xffL << offset)) | ((data & 0xffL) <<
- offset);
- }
-
- if (index < (cache_t->width >> (WORD_SHT + 1)))
- cache->tag |= TAG_FIRST_HALF_DIRTY;
- else
- cache->tag |= TAG_LAST_HALF_DIRTY;
-//-------------------------------------------------------------
-//chy 2003-09-03 be sure the changed value will be in memory as soon as possible, so I cache can get the newest value
-#if 0
- {
- if (datatype == ARM_WORD_TYPE)
- mem_write_word (state, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- mem_write_halfword (state, (pa | (real_va & 2)),
- data);
- else if (datatype == ARM_BYTE_TYPE)
- mem_write_byte (state, (pa | (real_va & 3)), data);
- }
-#endif
-#if 0
-//chy 2003-09-02 for test ????
- if (datatype == ARM_WORD_TYPE) {
- if (real_va >= 0xffff0000 && real_va <= 0xffff0020) {
- printf ("**SKYEYE:mmu_write word:cache: pa %x, va %x, data %x, R15 %x\n", pa, real_va, data, state->Reg[15]);
- }
- }
-//-------------------------------------------------------------
-#endif
- if (datatype == ARM_WORD_TYPE)
- //mem_write_word (state, pa, data);
- bus_write(32, pa, data);
- else if (datatype == ARM_HALFWORD_TYPE)
- //mem_write_halfword (state, (pa | (real_va & 2)), data);
- bus_write(16, pa | (real_va & 2), data);
- else if (datatype == ARM_BYTE_TYPE)
- //mem_write_byte (state, (pa | (real_va & 3)), data);
- bus_write(8, (pa | (real_va & 3)), data);
- return NO_FAULT;
-}
-
-ARMword xscale_cp15_mrc (ARMul_State * state,
- unsigned type, ARMword instr, ARMword * value)
-{
- return xscale_mmu_mrc (state, instr, value);
-}
-
-ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value)
-{
- ARMword data;
- unsigned opcode_2 = BITS (5, 7);
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
- mmu_regnum_t creg = (mmu_regnum_t)reg;
-
-/*
- printf("SKYEYE: xscale_cp15_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\
- state->Reg[15], instr);
-*/
- switch (creg) {
- case MMU_ID: //XSCALE_CP15
- //printf("mmu_mrc read ID \n");
- data = (opcode_2 ? state->mmu.cache_type : state->cpu->
- cpu_val);
- break;
- case MMU_CONTROL: //XSCALE_CP15_AUX_CONTROL
- //printf("mmu_mrc read CONTROL \n");
- data = (opcode_2 ? state->mmu.aux_control : state->mmu.
- control);
- break;
- case MMU_TRANSLATION_TABLE_BASE:
- //printf("mmu_mrc read TTB \n");
- data = state->mmu.translation_table_base;
- break;
- case MMU_DOMAIN_ACCESS_CONTROL:
- //printf("mmu_mrc read DACR \n");
- data = state->mmu.domain_access_control;
- break;
- case MMU_FAULT_STATUS:
- //printf("mmu_mrc read FSR \n");
- data = state->mmu.fault_status;
- break;
- case MMU_FAULT_ADDRESS:
- //printf("mmu_mrc read FAR \n");
- data = state->mmu.fault_address;
- break;
- case MMU_PID:
- //printf("mmu_mrc read PID \n");
- data = state->mmu.process_id;
- case XSCALE_CP15_COPRO_ACCESS:
- //printf("xscale cp15 read coprocessor access\n");
- data = state->mmu.copro_access;
- break;
- default:
- data = 0;
- printf ("SKYEYE: xscale_cp15_mrc read UNKNOWN - reg %d, pc 0x%x\n", creg, state->Reg[15]);
- // skyeye_exit (-1);
- break;
- }
- *value = data;
- //printf("SKYEYE: xscale_cp15_mrc:end value 0x%x\n",data);
- return ARMul_DONE;
-}
-
-void xscale_cp15_cache_ops (ARMul_State * state, ARMword instr, ARMword value)
-{
-//chy: 2003-08-24 now, the BTB isn't simualted ....????
-
- unsigned CRm, OPC_2;
-
- CRm = BITS (0, 3);
- OPC_2 = BITS (5, 7);
- //err_msg("SKYEYE: xscale cp15_cache_ops:OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm,state->Reg[15]);
-
- if (OPC_2 == 0 && CRm == 7) {
- mmu_cache_invalidate_all (state, I_CACHE ());
- mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
- return;
- }
-
- if (OPC_2 == 0 && CRm == 5) {
- mmu_cache_invalidate_all (state, I_CACHE ());
- return;
- }
- if (OPC_2 == 1 && CRm == 5) {
- mmu_cache_invalidate (state, I_CACHE (), value);
- return;
- }
-
- if (OPC_2 == 0 && CRm == 6) {
- mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
- return;
- }
-
- if (OPC_2 == 1 && CRm == 6) {
- mmu_cache_invalidate (state, MAIN_D_CACHE (), value);
- return;
- }
-
- if (OPC_2 == 1 && CRm == 0xa) {
- mmu_cache_clean (state, MAIN_D_CACHE (), value);
- return;
- }
-
- if (OPC_2 == 4 && CRm == 0xa) {
- mmu_wb_drain_all (state, WB ());
- return;
- }
-
- if (OPC_2 == 6 && CRm == 5) {
- //chy 2004-07-19 shoud fix in the future????!!!!
- //printf("SKYEYE: xscale_cp15_cache_ops:invalidate BTB CANT!!!!!!!!!!\n");
- //exit(-1);
- return;
- }
-
- if (OPC_2 == 5 && CRm == 2) {
- //printf("SKYEYE: cp15_c_o: A L in D C, value %x, reg15 %x\n",value, state->Reg[15]);
- //exit(-1);
- //chy 2003-09-01 for test
- mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
- return;
- }
-
- ERROR_LOG(ARM11, "SKYEYE: xscale cp15_cache_ops:Unknown OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm, state->Reg[15]);
- // skyeye_exit (-1);
-}
-
-static void
- xscale_cp15_tlb_ops (ARMul_State * state, ARMword instr,
- ARMword value)
-{
- int CRm, OPC_2;
-
- CRm = BITS (0, 3);
- OPC_2 = BITS (5, 7);
-
-
- //err_msg("SKYEYE:xscale_cp15_tlb_ops:OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm,state->Reg[15]);
- if (OPC_2 == 0 && CRm == 0x7) {
- mmu_tlb_invalidate_all (state, I_TLB ());
- mmu_tlb_invalidate_all (state, D_TLB ());
- return;
- }
-
- if (OPC_2 == 0 && CRm == 0x5) {
- mmu_tlb_invalidate_all (state, I_TLB ());
- return;
- }
-
- if (OPC_2 == 1 && CRm == 0x5) {
- mmu_tlb_invalidate_entry (state, I_TLB (), value);
- return;
- }
-
- if (OPC_2 == 0 && CRm == 0x6) {
- mmu_tlb_invalidate_all (state, D_TLB ());
- return;
- }
-
- if (OPC_2 == 1 && CRm == 0x6) {
- mmu_tlb_invalidate_entry (state, D_TLB (), value);
- return;
- }
-
- ERROR_LOG(ARM11, "SKYEYE:xscale_cp15_tlb_ops:Unknow OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm, state->Reg[15]);
- // skyeye_exit (-1);
-}
-
-
-ARMword xscale_cp15_mcr (ARMul_State * state,
- unsigned type, ARMword instr, ARMword value)
-{
- return xscale_mmu_mcr (state, instr, value);
-}
-
-ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value)
-{
- ARMword data;
- unsigned opcode_2 = BITS (5, 7);
- unsigned CRm = BITS (0, 3);
- unsigned reg = BITS (16, 19);
- unsigned result;
- mmu_regnum_t creg = (mmu_regnum_t)reg;
-
- //printf("SKYEYE: xscale_cp15_mcr: opcode_2 0x%x, CRm 0x%x, reg ox%x, value 0x%x, reg[15] 0x%x, instr 0x%x\n",opcode_2,CRm,reg, value, state->Reg[15], instr);
-
- switch (creg) {
- case MMU_CONTROL:
- //printf("mmu_mcr wrote CONTROL val 0x%x \n",value);
- state->mmu.control =
- (opcode_2 ? (value & 0x33) : (value & 0x3FFF));
- break;
- case MMU_TRANSLATION_TABLE_BASE:
- //printf("mmu_mcr wrote TTB val 0x%x \n",value);
- state->mmu.translation_table_base = value & 0xFFFFC000;
- break;
- case MMU_DOMAIN_ACCESS_CONTROL:
- //printf("mmu_mcr wrote DACR val 0x%x \n",value);
- state->mmu.domain_access_control = value;
- break;
-
- case MMU_FAULT_STATUS:
- //printf("mmu_mcr wrote FS val 0x%x \n",value);
- state->mmu.fault_status = value & 0x6FF;
- break;
- case MMU_FAULT_ADDRESS:
- //printf("mmu_mcr wrote FA val 0x%x \n",value);
- state->mmu.fault_address = value;
- break;
-
- case MMU_CACHE_OPS:
-// printf("mmu_mcr wrote CO val 0x%x \n",value);
- xscale_cp15_cache_ops (state, instr, value);
- break;
- case MMU_TLB_OPS:
- //printf("mmu_mcr wrote TO val 0x%x \n",value);
- xscale_cp15_tlb_ops (state, instr, value);
- break;
- case MMU_PID:
- //printf("mmu_mcr wrote PID val 0x%x \n",value);
- state->mmu.process_id = value & 0xfe000000;
- break;
- case XSCALE_CP15_COPRO_ACCESS:
- //printf("xscale cp15 write coprocessor access val 0x %x\n",value);
- state->mmu.copro_access = value & 0x3ff;
- break;
-
- default:
- printf ("SKYEYE: xscale_cp15_mcr wrote UNKNOWN - reg %d, reg15 0x%x\n", creg, state->Reg[15]);
- break;
- }
- //printf("SKYEYE: xscale_cp15_mcr wrote val 0x%x\n", value);
- return 0;
-}
-
-//teawater add for arm2x86 2005.06.24-------------------------------------------
-static int xscale_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr,
- ARMword * phys_addr)
-{
- fault_t fault;
- tlb_entry_t *tlb;
-
- virt_addr = mmu_pid_va_map (virt_addr);
- if (MMU_Enabled) {
-
- /*align check */
- if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) {
- DEBUG_LOG(ARM11, "align\n");
- return ALIGNMENT_FAULT;
- }
- else
- virt_addr &= ~(WORD_SIZE - 1);
-
- /*translate tlb */
- fault = translate (state, virt_addr, I_TLB (), &tlb);
- if (fault) {
- DEBUG_LOG(ARM11, "translate\n");
- return fault;
- }
-
- /*check access */
- fault = check_access (state, virt_addr, tlb, 1);
- if (fault) {
- DEBUG_LOG(ARM11, "check_fault\n");
- return fault;
- }
- }
-
- if (MMU_Disabled) {
- *phys_addr = virt_addr;
- }
- else {
- *phys_addr = tlb_va_to_pa (tlb, virt_addr);
- }
-
- return (0);
-}
-
-//AJ2D--------------------------------------------------------------------------
-
-/*xscale mmu_ops_t*/
-//mmu_ops_t xscale_mmu_ops = {
-// xscale_cp15_init,
-// xscale_cp15_exit,
-// xscale_mmu_read_byte,
-// xscale_mmu_write_byte,
-// xscale_mmu_read_halfword,
-// xscale_mmu_write_halfword,
-// xscale_mmu_read_word,
-// xscale_mmu_write_word,
-// xscale_mmu_load_instr, xscale_mmu_mcr, xscale_mmu_mrc,
-////teawater add for arm2x86 2005.06.24-------------------------------------------
-// xscale_mmu_v2p_dbct,
-////AJ2D--------------------------------------------------------------------------
-//};
diff --git a/src/core/arm/interpreter/thumbemu.cpp b/src/core/arm/interpreter/thumbemu.cpp
index 032d84b65..f7f11f714 100644
--- a/src/core/arm/interpreter/thumbemu.cpp
+++ b/src/core/arm/interpreter/thumbemu.cpp
@@ -19,7 +19,7 @@
instruction into its corresponding ARM instruction, and using the
existing ARM simulator. */
-#include "skyeye_defs.h"
+#include "core/arm/skyeye_common/skyeye_defs.h"
#ifndef MODET /* required for the Thumb instruction support */
#if 1
@@ -29,9 +29,9 @@ existing ARM simulator. */
#endif
#endif
-#include "armdefs.h"
-#include "armemu.h"
-#include "armos.h"
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armemu.h"
+#include "core/arm/skyeye_common/armos.h"
/* Decode a 16bit Thumb instruction. The instruction is in the low
diff --git a/src/core/arm/interpreter/vfp/vfp.cpp b/src/core/arm/interpreter/vfp/vfp.cpp
deleted file mode 100644
index eea5e24a9..000000000
--- a/src/core/arm/interpreter/vfp/vfp.cpp
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- armvfp.c - ARM VFPv3 emulation unit
- Copyright (C) 2003 Skyeye Develop Group
- for help please send mail to <skyeye-developer@lists.gro.clinux.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-/* Note: this file handles interface with arm core and vfp registers */
-
-/* Opens debug for classic interpreter only */
-//#define DEBUG
-
-#include "common/common.h"
-
-#include "core/arm/interpreter/armdefs.h"
-#include "core/arm/interpreter/vfp/vfp.h"
-
-//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
-
-unsigned
-VFPInit (ARMul_State *state)
-{
- state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
- VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
- state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
-
- //persistent_state = state;
- /* Reset only specify VFP_FPEXC_EN = '0' */
-
- return No_exp;
-}
-
-unsigned
-VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
-{
- /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (21, 23);
- int Rt = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MRC_TRANS
- #include "core/arm/interpreter/vfp/vfpinstr.cpp"
- #undef VFP_MRC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
-}
-
-unsigned
-VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
-{
- /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (21, 23);
- int Rt = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MCR_TRANS
- #include "core/arm/interpreter/vfp/vfpinstr.cpp"
- #undef VFP_MCR_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
-}
-
-unsigned
-VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2)
-{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (4, 7);
- int Rt = BITS (12, 15);
- int Rt2 = BITS (16, 19);
- int CRm = BITS (0, 3);
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MRRC_TRANS
- #include "core/arm/interpreter/vfp/vfpinstr.cpp"
- #undef VFP_MRRC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
-}
-
-unsigned
-VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2)
-{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (4, 7);
- int Rt = BITS (12, 15);
- int Rt2 = BITS (16, 19);
- int CRm = BITS (0, 3);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 11 || CoProc == 10)
- {
- #define VFP_MCRR_TRANS
- #include "core/arm/interpreter/vfp/vfpinstr.cpp"
- #undef VFP_MCRR_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
-}
-
-unsigned
-VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
-{
- /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int CRd = BITS (12, 15);
- int Rn = BITS (16, 19);
- int imm8 = BITS (0, 7);
- int P = BIT(24);
- int U = BIT(23);
- int D = BIT(22);
- int W = BIT(21);
-
- /* TODO check access permission */
-
- /* VSTM */
- if ( (P|U|D|W) == 0 )
- {
- DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
- }
- if (CoProc == 10 || CoProc == 11)
- {
- #if 1
- if (P == 0 && U == 0 && W == 0)
- {
- DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1);
- }
- if (P == U && W == 1)
- {
- DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1);
- }
- #endif
-
- #define VFP_STC_TRANS
- #include "core/arm/interpreter/vfp/vfpinstr.cpp"
- #undef VFP_STC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
-}
-
-unsigned
-VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
-{
- /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int CRd = BITS (12, 15);
- int Rn = BITS (16, 19);
- int imm8 = BITS (0, 7);
- int P = BIT(24);
- int U = BIT(23);
- int D = BIT(22);
- int W = BIT(21);
-
- /* TODO check access permission */
-
- if ( (P|U|D|W) == 0 )
- {
- DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
- }
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_LDC_TRANS
- #include "core/arm/interpreter/vfp/vfpinstr.cpp"
- #undef VFP_LDC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
-}
-
-unsigned
-VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
-{
- /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (20, 23);
- int CRd = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_CDP_TRANS
- #include "core/arm/interpreter/vfp/vfpinstr.cpp"
- #undef VFP_CDP_TRANS
-
- int exceptions = 0;
- if (CoProc == 10)
- exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
- else
- exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
-
- vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
-
- return ARMul_DONE;
- }
- DEBUG_LOG(ARM11, "Can't identify %x\n", instr);
- return ARMul_CANT;
-}
-
-
-/* ----------- MRC ------------ */
-#define VFP_MRC_IMPL
-#include "core/arm/interpreter/vfp/vfpinstr.cpp"
-#undef VFP_MRC_IMPL
-
-#define VFP_MRRC_IMPL
-#include "core/arm/interpreter/vfp/vfpinstr.cpp"
-#undef VFP_MRRC_IMPL
-
-
-/* ----------- MCR ------------ */
-#define VFP_MCR_IMPL
-#include "core/arm/interpreter/vfp/vfpinstr.cpp"
-#undef VFP_MCR_IMPL
-
-#define VFP_MCRR_IMPL
-#include "core/arm/interpreter/vfp/vfpinstr.cpp"
-#undef VFP_MCRR_IMPL
-
-/* Memory operation are not inlined, as old Interpreter and Fast interpreter
- don't have the same memory operation interface.
- Old interpreter framework does one access to coprocessor per data, and
- handles already data write, as well as address computation,
- which is not the case for Fast interpreter. Therefore, implementation
- of vfp instructions in old interpreter and fast interpreter are separate. */
-
-/* ----------- STC ------------ */
-#define VFP_STC_IMPL
-#include "core/arm/interpreter/vfp/vfpinstr.cpp"
-#undef VFP_STC_IMPL
-
-
-/* ----------- LDC ------------ */
-#define VFP_LDC_IMPL
-#include "core/arm/interpreter/vfp/vfpinstr.cpp"
-#undef VFP_LDC_IMPL
-
-
-/* ----------- CDP ------------ */
-#define VFP_CDP_IMPL
-#include "core/arm/interpreter/vfp/vfpinstr.cpp"
-#undef VFP_CDP_IMPL
-
-/* Miscellaneous functions */
-int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
-{
- DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
- return state->ExtReg[reg];
-}
-
-void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg)
-{
- DBG("VFP put float: s%d <= [%08x]\n", reg, val);
- state->ExtReg[reg] = val;
-}
-
-uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
-{
- uint64_t result;
- result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
- DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
- return result;
-}
-
-void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
-{
- DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
- state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
- state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
-}
-
-
-
-/*
- * Process bitmask of exception conditions. (from vfpmodule.c)
- */
-void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
-{
- int si_code = 0;
-
- vfpdebug("VFP: raising exceptions %08x\n", exceptions);
-
- if (exceptions == VFP_EXCEPTION_ERROR) {
- DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst);
- exit(-1);
- return;
- }
-
- /*
- * If any of the status flags are set, update the FPSCR.
- * Comparison instructions always return at least one of
- * these flags set.
- */
- if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
- fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
-
- fpscr |= exceptions;
-
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
-}
diff --git a/src/core/arm/interpreter/vfp/vfpdouble.cpp b/src/core/arm/interpreter/vfp/vfpdouble.cpp
deleted file mode 100644
index 5ae99b88a..000000000
--- a/src/core/arm/interpreter/vfp/vfpdouble.cpp
+++ /dev/null
@@ -1,1263 +0,0 @@
-/*
- vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction
- Copyright (C) 2003 Skyeye Develop Group
- for help please send mail to <skyeye-developer@lists.gro.clinux.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-/*
- * This code is derived in part from :
- * - Android kernel
- * - John R. Housers softfloat library, which
- * carries the following notice:
- *
- * ===========================================================================
- * This C source file is part of the SoftFloat IEC/IEEE Floating-point
- * Arithmetic Package, Release 2.
- *
- * Written by John R. Hauser. This work was made possible in part by the
- * International Computer Science Institute, located at Suite 600, 1947 Center
- * Street, Berkeley, California 94704. Funding was partially provided by the
- * National Science Foundation under grant MIP-9311980. The original version
- * of this code was written as part of a project to build a fixed-point vector
- * processor in collaboration with the University of California at Berkeley,
- * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
- * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
- * arithmetic/softfloat.html'.
- *
- * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
- * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
- * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
- * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
- * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
- *
- * Derivative works are acceptable, even for commercial purposes, so long as
- * (1) they include prominent notice that the work is derivative, and (2) they
- * include prominent notice akin to these three paragraphs for those parts of
- * this code that are retained.
- * ===========================================================================
- */
-
-#include "core/arm/interpreter/vfp/vfp.h"
-#include "core/arm/interpreter/vfp/vfp_helper.h"
-#include "core/arm/interpreter/vfp/asm_vfp.h"
-
-static struct vfp_double vfp_double_default_qnan = {
- //.exponent = 2047,
- //.sign = 0,
- //.significand = VFP_DOUBLE_SIGNIFICAND_QNAN,
-};
-
-static void vfp_double_dump(const char *str, struct vfp_double *d)
-{
- pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
- str, d->sign != 0, d->exponent, d->significand);
-}
-
-static void vfp_double_normalise_denormal(struct vfp_double *vd)
-{
- int bits = 31 - vfp_fls(vd->significand >> 32);
- if (bits == 31)
- bits = 63 - vfp_fls(vd->significand);
-
- vfp_double_dump("normalise_denormal: in", vd);
-
- if (bits) {
- vd->exponent -= bits - 1;
- vd->significand <<= bits;
- }
-
- vfp_double_dump("normalise_denormal: out", vd);
-}
-
-u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
-{
- u64 significand, incr;
- int exponent, shift, underflow;
- u32 rmode;
-
- vfp_double_dump("pack: in", vd);
-
- /*
- * Infinities and NaNs are a special case.
- */
- if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
- goto pack;
-
- /*
- * Special-case zero.
- */
- if (vd->significand == 0) {
- vd->exponent = 0;
- goto pack;
- }
-
- exponent = vd->exponent;
- significand = vd->significand;
-
- shift = 32 - vfp_fls(significand >> 32);
- if (shift == 32)
- shift = 64 - vfp_fls(significand);
- if (shift) {
- exponent -= shift;
- significand <<= shift;
- }
-
-#if 1
- vd->exponent = exponent;
- vd->significand = significand;
- vfp_double_dump("pack: normalised", vd);
-#endif
-
- /*
- * Tiny number?
- */
- underflow = exponent < 0;
- if (underflow) {
- significand = vfp_shiftright64jamming(significand, -exponent);
- exponent = 0;
-#if 1
- vd->exponent = exponent;
- vd->significand = significand;
- vfp_double_dump("pack: tiny number", vd);
-#endif
- if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
- underflow = 0;
- }
-
- /*
- * Select rounding increment.
- */
- incr = 0;
- rmode = fpscr & FPSCR_RMODE_MASK;
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 1ULL << VFP_DOUBLE_LOW_BITS;
- if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
- incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
-
- pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
-
- /*
- * Is our rounding going to overflow?
- */
- if ((significand + incr) < significand) {
- exponent += 1;
- significand = (significand >> 1) | (significand & 1);
- incr >>= 1;
-#if 1
- vd->exponent = exponent;
- vd->significand = significand;
- vfp_double_dump("pack: overflow", vd);
-#endif
- }
-
- /*
- * If any of the low bits (which will be shifted out of the
- * number) are non-zero, the result is inexact.
- */
- if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
- exceptions |= FPSCR_IXC;
-
- /*
- * Do our rounding.
- */
- significand += incr;
-
- /*
- * Infinity?
- */
- if (exponent >= 2046) {
- exceptions |= FPSCR_OFC | FPSCR_IXC;
- if (incr == 0) {
- vd->exponent = 2045;
- vd->significand = 0x7fffffffffffffffULL;
- } else {
- vd->exponent = 2047; /* infinity */
- vd->significand = 0;
- }
- } else {
- if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
- exponent = 0;
- if (exponent || significand > 0x8000000000000000ULL)
- underflow = 0;
- if (underflow)
- exceptions |= FPSCR_UFC;
- vd->exponent = exponent;
- vd->significand = significand >> 1;
- }
-
- pack:
- vfp_double_dump("pack: final", vd);
- {
- s64 d = vfp_double_pack(vd);
- pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func,
- dd, d, exceptions);
- vfp_put_double(state, d, dd);
- }
- return exceptions;
-}
-
-/*
- * Propagate the NaN, setting exceptions if it is signalling.
- * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
- */
-static u32
-vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
- struct vfp_double *vdm, u32 fpscr)
-{
- struct vfp_double *nan;
- int tn, tm = 0;
-
- tn = vfp_double_type(vdn);
-
- if (vdm)
- tm = vfp_double_type(vdm);
-
- if (fpscr & FPSCR_DEFAULT_NAN)
- /*
- * Default NaN mode - always returns a quiet NaN
- */
- nan = &vfp_double_default_qnan;
- else {
- /*
- * Contemporary mode - select the first signalling
- * NAN, or if neither are signalling, the first
- * quiet NAN.
- */
- if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
- nan = vdn;
- else
- nan = vdm;
- /*
- * Make the NaN quiet.
- */
- nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
- }
-
- *vdd = *nan;
-
- /*
- * If one was a signalling NAN, raise invalid operation.
- */
- return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
-}
-
-/*
- * Extended operations
- */
-static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd);
- return 0;
-}
-
-static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- vfp_put_double(state, vfp_get_double(state, dm), dd);
- return 0;
-}
-
-static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd);
- return 0;
-}
-
-static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- struct vfp_double vdm, vdd, *vdp;
- int ret, tm;
-
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- tm = vfp_double_type(&vdm);
- if (tm & (VFP_NAN|VFP_INFINITY)) {
- vdp = &vdd;
-
- if (tm & VFP_NAN)
- ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
- else if (vdm.sign == 0) {
- sqrt_copy:
- vdp = &vdm;
- ret = 0;
- } else {
- sqrt_invalid:
- vdp = &vfp_double_default_qnan;
- ret = FPSCR_IOC;
- }
- vfp_put_double(state, vfp_double_pack(vdp), dd);
- return ret;
- }
-
- /*
- * sqrt(+/- 0) == +/- 0
- */
- if (tm & VFP_ZERO)
- goto sqrt_copy;
-
- /*
- * Normalise a denormalised number
- */
- if (tm & VFP_DENORMAL)
- vfp_double_normalise_denormal(&vdm);
-
- /*
- * sqrt(<0) = invalid
- */
- if (vdm.sign)
- goto sqrt_invalid;
-
- vfp_double_dump("sqrt", &vdm);
-
- /*
- * Estimate the square root.
- */
- vdd.sign = 0;
- vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
- vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
-
- vfp_double_dump("sqrt estimate1", &vdd);
-
- vdm.significand >>= 1 + (vdm.exponent & 1);
- vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
-
- vfp_double_dump("sqrt estimate2", &vdd);
-
- /*
- * And now adjust.
- */
- if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
- if (vdd.significand < 2) {
- vdd.significand = ~0ULL;
- } else {
- u64 termh, terml, remh, reml;
- vdm.significand <<= 2;
- mul64to128(&termh, &terml, vdd.significand, vdd.significand);
- sub128(&remh, &reml, vdm.significand, 0, termh, terml);
- while ((s64)remh < 0) {
- vdd.significand -= 1;
- shift64left(&termh, &terml, vdd.significand);
- terml |= 1;
- add128(&remh, &reml, remh, reml, termh, terml);
- }
- vdd.significand |= (remh | reml) != 0;
- }
- }
- vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
-
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt");
-}
-
-/*
- * Equal := ZC
- * Less than := N
- * Greater than := C
- * Unordered := CV
- */
-static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr)
-{
- s64 d, m;
- u32 ret = 0;
-
- pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr);
- m = vfp_get_double(state, dm);
- if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
- ret |= FPSCR_C | FPSCR_V;
- if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
- /*
- * Signalling NaN, or signalling on quiet NaN
- */
- ret |= FPSCR_IOC;
- }
-
- d = vfp_get_double(state, dd);
- if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
- ret |= FPSCR_C | FPSCR_V;
- if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
- /*
- * Signalling NaN, or signalling on quiet NaN
- */
- ret |= FPSCR_IOC;
- }
-
- if (ret == 0) {
- //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
- if (d == m || vfp_double_packed_abs(d | m) == 0) {
- /*
- * equal
- */
- ret |= FPSCR_Z | FPSCR_C;
- //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
- } else if (vfp_double_packed_sign(d ^ m)) {
- /*
- * different signs
- */
- if (vfp_double_packed_sign(d))
- /*
- * d is negative, so d < m
- */
- ret |= FPSCR_N;
- else
- /*
- * d is positive, so d > m
- */
- ret |= FPSCR_C;
- } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
- /*
- * d < m
- */
- ret |= FPSCR_N;
- } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
- /*
- * d > m
- */
- ret |= FPSCR_C;
- }
- }
- pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret);
-
- return ret;
-}
-
-static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_compare(state, dd, 0, dm, fpscr);
-}
-
-static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_compare(state, dd, 1, dm, fpscr);
-}
-
-static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr);
-}
-
-static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
-}
-
-static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
-{
- struct vfp_double vdm;
- struct vfp_single vsd;
- int tm;
- u32 exceptions = 0;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
-
- tm = vfp_double_type(&vdm);
-
- /*
- * If we have a signalling NaN, signal invalid operation.
- */
- if (tm == VFP_SNAN)
- exceptions = FPSCR_IOC;
-
- if (tm & VFP_DENORMAL)
- vfp_double_normalise_denormal(&vdm);
-
- vsd.sign = vdm.sign;
- vsd.significand = vfp_hi64to32jamming(vdm.significand);
-
- /*
- * If we have an infinity or a NaN, the exponent must be 255
- */
- if (tm & (VFP_INFINITY|VFP_NAN)) {
- vsd.exponent = 255;
- if (tm == VFP_QNAN)
- vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
- goto pack_nan;
- } else if (tm & VFP_ZERO)
- vsd.exponent = 0;
- else
- vsd.exponent = vdm.exponent - (1023 - 127);
-
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
-
- pack_nan:
- vfp_put_float(state, vfp_single_pack(&vsd), sd);
- return exceptions;
-}
-
-static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- struct vfp_double vdm;
- u32 m = vfp_get_float(state, dm);
-
- pr_debug("In %s\n", __FUNCTION__);
- vdm.sign = 0;
- vdm.exponent = 1023 + 63 - 1;
- vdm.significand = (u64)m;
-
- return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito");
-}
-
-static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- struct vfp_double vdm;
- u32 m = vfp_get_float(state, dm);
-
- pr_debug("In %s\n", __FUNCTION__);
- vdm.sign = (m & 0x80000000) >> 16;
- vdm.exponent = 1023 + 63 - 1;
- vdm.significand = vdm.sign ? -m : m;
-
- return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito");
-}
-
-static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
-{
- struct vfp_double vdm;
- u32 d, exceptions = 0;
- int rmode = fpscr & FPSCR_RMODE_MASK;
- int tm;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
-
- /*
- * Do we have a denormalised number?
- */
- tm = vfp_double_type(&vdm);
- if (tm & VFP_DENORMAL)
- exceptions |= FPSCR_IDC;
-
- if (tm & VFP_NAN)
- vdm.sign = 0;
-
- if (vdm.exponent >= 1023 + 32) {
- d = vdm.sign ? 0 : 0xffffffff;
- exceptions = FPSCR_IOC;
- } else if (vdm.exponent >= 1023 - 1) {
- int shift = 1023 + 63 - vdm.exponent;
- u64 rem, incr = 0;
-
- /*
- * 2^0 <= m < 2^32-2^8
- */
- d = (vdm.significand << 1) >> shift;
- rem = vdm.significand << (65 - shift);
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 0x8000000000000000ULL;
- if ((d & 1) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
- incr = ~0ULL;
- }
-
- if ((rem + incr) < rem) {
- if (d < 0xffffffff)
- d += 1;
- else
- exceptions |= FPSCR_IOC;
- }
-
- if (d && vdm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
- } else if (rem)
- exceptions |= FPSCR_IXC;
- } else {
- d = 0;
- if (vdm.exponent | vdm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
- d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
- }
- }
- }
-
- pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
-
- vfp_put_float(state, d, sd);
-
- return exceptions;
-}
-
-static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO);
-}
-
-static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
-{
- struct vfp_double vdm;
- u32 d, exceptions = 0;
- int rmode = fpscr & FPSCR_RMODE_MASK;
- int tm;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- vfp_double_dump("VDM", &vdm);
-
- /*
- * Do we have denormalised number?
- */
- tm = vfp_double_type(&vdm);
- if (tm & VFP_DENORMAL)
- exceptions |= FPSCR_IDC;
-
- if (tm & VFP_NAN) {
- d = 0;
- exceptions |= FPSCR_IOC;
- } else if (vdm.exponent >= 1023 + 32) {
- d = 0x7fffffff;
- if (vdm.sign)
- d = ~d;
- exceptions |= FPSCR_IOC;
- } else if (vdm.exponent >= 1023 - 1) {
- int shift = 1023 + 63 - vdm.exponent; /* 58 */
- u64 rem, incr = 0;
-
- d = (vdm.significand << 1) >> shift;
- rem = vdm.significand << (65 - shift);
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 0x8000000000000000ULL;
- if ((d & 1) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
- incr = ~0ULL;
- }
-
- if ((rem + incr) < rem && d < 0xffffffff)
- d += 1;
- if (d > 0x7fffffff + (vdm.sign != 0)) {
- d = 0x7fffffff + (vdm.sign != 0);
- exceptions |= FPSCR_IOC;
- } else if (rem)
- exceptions |= FPSCR_IXC;
-
- if (vdm.sign)
- d = -d;
- } else {
- d = 0;
- if (vdm.exponent | vdm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
- d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
- d = -1;
- }
- }
-
- pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
-
- vfp_put_float(state, (s32)d, sd);
-
- return exceptions;
-}
-
-static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO);
-}
-
-static struct op fops_ext[] = {
- { vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY
- { vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS
- { vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG
- { vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
- { vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
- { vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
- { vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
- { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
- { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
- { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
- { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
- { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
-};
-
-
-
-
-static u32
-vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
- struct vfp_double *vdm, u32 fpscr)
-{
- struct vfp_double *vdp;
- u32 exceptions = 0;
- int tn, tm;
-
- tn = vfp_double_type(vdn);
- tm = vfp_double_type(vdm);
-
- if (tn & tm & VFP_INFINITY) {
- /*
- * Two infinities. Are they different signs?
- */
- if (vdn->sign ^ vdm->sign) {
- /*
- * different signs -> invalid
- */
- exceptions = FPSCR_IOC;
- vdp = &vfp_double_default_qnan;
- } else {
- /*
- * same signs -> valid
- */
- vdp = vdn;
- }
- } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
- /*
- * One infinity and one number -> infinity
- */
- vdp = vdn;
- } else {
- /*
- * 'n' is a NaN of some type
- */
- return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
- }
- *vdd = *vdp;
- return exceptions;
-}
-
-static u32
-vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,
- struct vfp_double *vdm, u32 fpscr)
-{
- u32 exp_diff;
- u64 m_sig;
-
- if (vdn->significand & (1ULL << 63) ||
- vdm->significand & (1ULL << 63)) {
- pr_info("VFP: bad FP values\n");
- vfp_double_dump("VDN", vdn);
- vfp_double_dump("VDM", vdm);
- }
-
- /*
- * Ensure that 'n' is the largest magnitude number. Note that
- * if 'n' and 'm' have equal exponents, we do not swap them.
- * This ensures that NaN propagation works correctly.
- */
- if (vdn->exponent < vdm->exponent) {
- struct vfp_double *t = vdn;
- vdn = vdm;
- vdm = t;
- }
-
- /*
- * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
- * infinity or a NaN here.
- */
- if (vdn->exponent == 2047)
- return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
-
- /*
- * We have two proper numbers, where 'vdn' is the larger magnitude.
- *
- * Copy 'n' to 'd' before doing the arithmetic.
- */
- *vdd = *vdn;
-
- /*
- * Align 'm' with the result.
- */
- exp_diff = vdn->exponent - vdm->exponent;
- m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
-
- /*
- * If the signs are different, we are really subtracting.
- */
- if (vdn->sign ^ vdm->sign) {
- m_sig = vdn->significand - m_sig;
- if ((s64)m_sig < 0) {
- vdd->sign = vfp_sign_negate(vdd->sign);
- m_sig = -m_sig;
- } else if (m_sig == 0) {
- vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
- FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
- }
- } else {
- m_sig += vdn->significand;
- }
- vdd->significand = m_sig;
-
- return 0;
-}
-
-static u32
-vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
- struct vfp_double *vdm, u32 fpscr)
-{
- vfp_double_dump("VDN", vdn);
- vfp_double_dump("VDM", vdm);
-
- /*
- * Ensure that 'n' is the largest magnitude number. Note that
- * if 'n' and 'm' have equal exponents, we do not swap them.
- * This ensures that NaN propagation works correctly.
- */
- if (vdn->exponent < vdm->exponent) {
- struct vfp_double *t = vdn;
- vdn = vdm;
- vdm = t;
- pr_debug("VFP: swapping M <-> N\n");
- }
-
- vdd->sign = vdn->sign ^ vdm->sign;
-
- /*
- * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
- */
- if (vdn->exponent == 2047) {
- if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
- return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
- if ((vdm->exponent | vdm->significand) == 0) {
- *vdd = vfp_double_default_qnan;
- return FPSCR_IOC;
- }
- vdd->exponent = vdn->exponent;
- vdd->significand = 0;
- return 0;
- }
-
- /*
- * If 'm' is zero, the result is always zero. In this case,
- * 'n' may be zero or a number, but it doesn't matter which.
- */
- if ((vdm->exponent | vdm->significand) == 0) {
- vdd->exponent = 0;
- vdd->significand = 0;
- return 0;
- }
-
- /*
- * We add 2 to the destination exponent for the same reason
- * as the addition case - though this time we have +1 from
- * each input operand.
- */
- vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
- vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
-
- vfp_double_dump("VDD", vdd);
- return 0;
-}
-
-#define NEG_MULTIPLY (1 << 0)
-#define NEG_SUBTRACT (1 << 1)
-
-static u32
-vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func)
-{
- struct vfp_double vdd, vdp, vdn, vdm;
- u32 exceptions;
-
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
-
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
-
- exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
- if (negate & NEG_MULTIPLY)
- vdp.sign = vfp_sign_negate(vdp.sign);
-
- vfp_double_unpack(&vdn, vfp_get_double(state, dd));
- if (negate & NEG_SUBTRACT)
- vdn.sign = vfp_sign_negate(vdn.sign);
-
- exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
-
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func);
-}
-
-/*
- * Standard operations
- */
-
-/*
- * sd = sd + (sn * sm)
- */
-static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac");
-}
-
-/*
- * sd = sd - (sn * sm)
- */
-static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
-}
-
-/*
- * sd = -sd + (sn * sm)
- */
-static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
-}
-
-/*
- * sd = -sd - (sn * sm)
- */
-static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
-}
-
-/*
- * sd = sn * sm
- */
-static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
-
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
-
- exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul");
-}
-
-/*
- * sd = -(sn * sm)
- */
-static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
-
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
-
- exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
- vdd.sign = vfp_sign_negate(vdd.sign);
-
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul");
-}
-
-/*
- * sd = sn + sm
- */
-static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
-
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
-
- exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
-
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd");
-}
-
-/*
- * sd = sn - sm
- */
-static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
-
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
-
- /*
- * Subtraction is like addition, but with a negated operand.
- */
- vdm.sign = vfp_sign_negate(vdm.sign);
-
- exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
-
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub");
-}
-
-/*
- * sd = sn / sm
- */
-static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
-{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions = 0;
- int tm, tn;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
-
- vdd.sign = vdn.sign ^ vdm.sign;
-
- tn = vfp_double_type(&vdn);
- tm = vfp_double_type(&vdm);
-
- /*
- * Is n a NAN?
- */
- if (tn & VFP_NAN)
- goto vdn_nan;
-
- /*
- * Is m a NAN?
- */
- if (tm & VFP_NAN)
- goto vdm_nan;
-
- /*
- * If n and m are infinity, the result is invalid
- * If n and m are zero, the result is invalid
- */
- if (tm & tn & (VFP_INFINITY|VFP_ZERO))
- goto invalid;
-
- /*
- * If n is infinity, the result is infinity
- */
- if (tn & VFP_INFINITY)
- goto infinity;
-
- /*
- * If m is zero, raise div0 exceptions
- */
- if (tm & VFP_ZERO)
- goto divzero;
-
- /*
- * If m is infinity, or n is zero, the result is zero
- */
- if (tm & VFP_INFINITY || tn & VFP_ZERO)
- goto zero;
-
- if (tn & VFP_DENORMAL)
- vfp_double_normalise_denormal(&vdn);
- if (tm & VFP_DENORMAL)
- vfp_double_normalise_denormal(&vdm);
-
- /*
- * Ok, we have two numbers, we can perform division.
- */
- vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
- vdm.significand <<= 1;
- if (vdm.significand <= (2 * vdn.significand)) {
- vdn.significand >>= 1;
- vdd.exponent++;
- }
- vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
- if ((vdd.significand & 0x1ff) <= 2) {
- u64 termh, terml, remh, reml;
- mul64to128(&termh, &terml, vdm.significand, vdd.significand);
- sub128(&remh, &reml, vdn.significand, 0, termh, terml);
- while ((s64)remh < 0) {
- vdd.significand -= 1;
- add128(&remh, &reml, remh, reml, 0, vdm.significand);
- }
- vdd.significand |= (reml != 0);
- }
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
-
- vdn_nan:
- exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
- pack:
- vfp_put_double(state, vfp_double_pack(&vdd), dd);
- return exceptions;
-
- vdm_nan:
- exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
- goto pack;
-
- zero:
- vdd.exponent = 0;
- vdd.significand = 0;
- goto pack;
-
- divzero:
- exceptions = FPSCR_DZC;
- infinity:
- vdd.exponent = 2047;
- vdd.significand = 0;
- goto pack;
-
- invalid:
- vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
- return FPSCR_IOC;
-}
-
-static struct op fops[] = {
- { vfp_double_fmac, 0 },
- { vfp_double_fmsc, 0 },
- { vfp_double_fmul, 0 },
- { vfp_double_fadd, 0 },
- { vfp_double_fnmac, 0 },
- { vfp_double_fnmsc, 0 },
- { vfp_double_fnmul, 0 },
- { vfp_double_fsub, 0 },
- { vfp_double_fdiv, 0 },
-};
-
-#define FREG_BANK(x) ((x) & 0x0c)
-#define FREG_IDX(x) ((x) & 3)
-
-u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
-{
- u32 op = inst & FOP_MASK;
- u32 exceptions = 0;
- unsigned int dest;
- unsigned int dn = vfp_get_dn(inst);
- unsigned int dm;
- unsigned int vecitr, veclen, vecstride;
- struct op *fop;
-
- pr_debug("In %s\n", __FUNCTION__);
- vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
-
- fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
-
- /*
- * fcvtds takes an sN register number as destination, not dN.
- * It also always operates on scalars.
- */
- if (fop->flags & OP_SD)
- dest = vfp_get_sd(inst);
- else
- dest = vfp_get_dd(inst);
-
- /*
- * f[us]ito takes a sN operand, not a dN operand.
- */
- if (fop->flags & OP_SM)
- dm = vfp_get_sm(inst);
- else
- dm = vfp_get_dm(inst);
-
- /*
- * If destination bank is zero, vector length is always '1'.
- * ARM DDI0100F C5.1.3, C5.3.2.
- */
- if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
- veclen = 0;
- else
- veclen = fpscr & FPSCR_LENGTH_MASK;
-
- pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
- (veclen >> FPSCR_LENGTH_BIT) + 1);
-
- if (!fop->fn) {
- printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst));
- goto invalid;
- }
-
- for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
- u32 except;
- char type;
-
- type = fop->flags & OP_SD ? 's' : 'd';
- if (op == FOP_EXT)
- pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
- vecitr >> FPSCR_LENGTH_BIT,
- type, dest, dn, dm);
- else
- pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
- vecitr >> FPSCR_LENGTH_BIT,
- type, dest, dn, FOP_TO_IDX(op), dm);
-
- except = fop->fn(state, dest, dn, dm, fpscr);
- pr_debug("VFP: itr%d: exceptions=%08x\n",
- vecitr >> FPSCR_LENGTH_BIT, except);
-
- exceptions |= except;
-
- /*
- * CHECK: It appears to be undefined whether we stop when
- * we encounter an exception. We continue.
- */
- dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
- dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
- if (FREG_BANK(dm) != 0)
- dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
- }
- return exceptions;
-
- invalid:
- return ~0;
-}
diff --git a/src/core/arm/interpreter/vfp/vfpsingle.cpp b/src/core/arm/interpreter/vfp/vfpsingle.cpp
deleted file mode 100644
index 0fcc85266..000000000
--- a/src/core/arm/interpreter/vfp/vfpsingle.cpp
+++ /dev/null
@@ -1,1278 +0,0 @@
-/*
- vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction
- Copyright (C) 2003 Skyeye Develop Group
- for help please send mail to <skyeye-developer@lists.gro.clinux.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-/*
- * This code is derived in part from :
- * - Android kernel
- * - John R. Housers softfloat library, which
- * carries the following notice:
- *
- * ===========================================================================
- * This C source file is part of the SoftFloat IEC/IEEE Floating-point
- * Arithmetic Package, Release 2.
- *
- * Written by John R. Hauser. This work was made possible in part by the
- * International Computer Science Institute, located at Suite 600, 1947 Center
- * Street, Berkeley, California 94704. Funding was partially provided by the
- * National Science Foundation under grant MIP-9311980. The original version
- * of this code was written as part of a project to build a fixed-point vector
- * processor in collaboration with the University of California at Berkeley,
- * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
- * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
- * arithmetic/softfloat.html'.
- *
- * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
- * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
- * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
- * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
- * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
- *
- * Derivative works are acceptable, even for commercial purposes, so long as
- * (1) they include prominent notice that the work is derivative, and (2) they
- * include prominent notice akin to these three paragraphs for those parts of
- * this code that are retained.
- * ===========================================================================
- */
-
-#include "core/arm/interpreter/vfp/vfp_helper.h"
-#include "core/arm/interpreter/vfp/asm_vfp.h"
-#include "core/arm/interpreter/vfp/vfp.h"
-
-static struct vfp_single vfp_single_default_qnan = {
- //.exponent = 255,
- //.sign = 0,
- //.significand = VFP_SINGLE_SIGNIFICAND_QNAN,
-};
-
-static void vfp_single_dump(const char *str, struct vfp_single *s)
-{
- pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
- str, s->sign != 0, s->exponent, s->significand);
-}
-
-static void vfp_single_normalise_denormal(struct vfp_single *vs)
-{
- int bits = 31 - vfp_fls(vs->significand);
-
- vfp_single_dump("normalise_denormal: in", vs);
-
- if (bits) {
- vs->exponent -= bits - 1;
- vs->significand <<= bits;
- }
-
- vfp_single_dump("normalise_denormal: out", vs);
-}
-
-
-u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func)
-{
- u32 significand, incr, rmode;
- int exponent, shift, underflow;
-
- vfp_single_dump("pack: in", vs);
-
- /*
- * Infinities and NaNs are a special case.
- */
- if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
- goto pack;
-
- /*
- * Special-case zero.
- */
- if (vs->significand == 0) {
- vs->exponent = 0;
- goto pack;
- }
-
- exponent = vs->exponent;
- significand = vs->significand;
-
- /*
- * Normalise first. Note that we shift the significand up to
- * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
- * significant bit.
- */
- shift = 32 - vfp_fls(significand);
- if (shift < 32 && shift) {
- exponent -= shift;
- significand <<= shift;
- }
-
-#if 1
- vs->exponent = exponent;
- vs->significand = significand;
- vfp_single_dump("pack: normalised", vs);
-#endif
-
- /*
- * Tiny number?
- */
- underflow = exponent < 0;
- if (underflow) {
- significand = vfp_shiftright32jamming(significand, -exponent);
- exponent = 0;
-#if 1
- vs->exponent = exponent;
- vs->significand = significand;
- vfp_single_dump("pack: tiny number", vs);
-#endif
- if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
- underflow = 0;
- }
-
- /*
- * Select rounding increment.
- */
- incr = 0;
- rmode = fpscr & FPSCR_RMODE_MASK;
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 1 << VFP_SINGLE_LOW_BITS;
- if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
- incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
-
- pr_debug("VFP: rounding increment = 0x%08x\n", incr);
-
- /*
- * Is our rounding going to overflow?
- */
- if ((significand + incr) < significand) {
- exponent += 1;
- significand = (significand >> 1) | (significand & 1);
- incr >>= 1;
-#if 1
- vs->exponent = exponent;
- vs->significand = significand;
- vfp_single_dump("pack: overflow", vs);
-#endif
- }
-
- /*
- * If any of the low bits (which will be shifted out of the
- * number) are non-zero, the result is inexact.
- */
- if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
- exceptions |= FPSCR_IXC;
-
- /*
- * Do our rounding.
- */
- significand += incr;
-
- /*
- * Infinity?
- */
- if (exponent >= 254) {
- exceptions |= FPSCR_OFC | FPSCR_IXC;
- if (incr == 0) {
- vs->exponent = 253;
- vs->significand = 0x7fffffff;
- } else {
- vs->exponent = 255; /* infinity */
- vs->significand = 0;
- }
- } else {
- if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
- exponent = 0;
- if (exponent || significand > 0x80000000)
- underflow = 0;
- if (underflow)
- exceptions |= FPSCR_UFC;
- vs->exponent = exponent;
- vs->significand = significand >> 1;
- }
-
- pack:
- vfp_single_dump("pack: final", vs);
- {
- s32 d = vfp_single_pack(vs);
-#if 1
- pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
- sd, d, exceptions);
-#endif
- vfp_put_float(state, d, sd);
- }
-
- return exceptions;
-}
-
-/*
- * Propagate the NaN, setting exceptions if it is signalling.
- * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
- */
-static u32
-vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
- struct vfp_single *vsm, u32 fpscr)
-{
- struct vfp_single *nan;
- int tn, tm = 0;
-
- tn = vfp_single_type(vsn);
-
- if (vsm)
- tm = vfp_single_type(vsm);
-
- if (fpscr & FPSCR_DEFAULT_NAN)
- /*
- * Default NaN mode - always returns a quiet NaN
- */
- nan = &vfp_single_default_qnan;
- else {
- /*
- * Contemporary mode - select the first signalling
- * NAN, or if neither are signalling, the first
- * quiet NAN.
- */
- if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
- nan = vsn;
- else
- nan = vsm;
- /*
- * Make the NaN quiet.
- */
- nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
- }
-
- *vsd = *nan;
-
- /*
- * If one was a signalling NAN, raise invalid operation.
- */
- return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
-}
-
-
-/*
- * Extended operations
- */
-static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- vfp_put_float(state, vfp_single_packed_abs(m), sd);
- return 0;
-}
-
-static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- vfp_put_float(state, m, sd);
- return 0;
-}
-
-static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- vfp_put_float(state, vfp_single_packed_negate(m), sd);
- return 0;
-}
-
-static const u16 sqrt_oddadjust[] = {
- 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
- 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
-};
-
-static const u16 sqrt_evenadjust[] = {
- 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
- 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
-};
-
-u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
-{
- int index;
- u32 z, a;
-
- if ((significand & 0xc0000000) != 0x40000000) {
- pr_debug("VFP: estimate_sqrt: invalid significand\n");
- }
-
- a = significand << 1;
- index = (a >> 27) & 15;
- if (exponent & 1) {
- z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
- z = ((a / z) << 14) + (z << 15);
- a >>= 1;
- } else {
- z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
- z = a / z + z;
- z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
- if (z <= a)
- return (s32)a >> 1;
- }
- {
- u64 v = (u64)a << 31;
- do_div(v, z);
- return v + (z >> 1);
- }
-}
-
-static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- struct vfp_single vsm, vsd, *vsp;
- int ret, tm;
-
- vfp_single_unpack(&vsm, m);
- tm = vfp_single_type(&vsm);
- if (tm & (VFP_NAN|VFP_INFINITY)) {
- vsp = &vsd;
-
- if (tm & VFP_NAN)
- ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
- else if (vsm.sign == 0) {
- sqrt_copy:
- vsp = &vsm;
- ret = 0;
- } else {
- sqrt_invalid:
- vsp = &vfp_single_default_qnan;
- ret = FPSCR_IOC;
- }
- vfp_put_float(state, vfp_single_pack(vsp), sd);
- return ret;
- }
-
- /*
- * sqrt(+/- 0) == +/- 0
- */
- if (tm & VFP_ZERO)
- goto sqrt_copy;
-
- /*
- * Normalise a denormalised number
- */
- if (tm & VFP_DENORMAL)
- vfp_single_normalise_denormal(&vsm);
-
- /*
- * sqrt(<0) = invalid
- */
- if (vsm.sign)
- goto sqrt_invalid;
-
- vfp_single_dump("sqrt", &vsm);
-
- /*
- * Estimate the square root.
- */
- vsd.sign = 0;
- vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
- vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
-
- vfp_single_dump("sqrt estimate", &vsd);
-
- /*
- * And now adjust.
- */
- if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
- if (vsd.significand < 2) {
- vsd.significand = 0xffffffff;
- } else {
- u64 term;
- s64 rem;
- vsm.significand <<= !(vsm.exponent & 1);
- term = (u64)vsd.significand * vsd.significand;
- rem = ((u64)vsm.significand << 32) - term;
-
- pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
-
- while (rem < 0) {
- vsd.significand -= 1;
- rem += ((u64)vsd.significand << 1) | 1;
- }
- vsd.significand |= rem != 0;
- }
- }
- vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
-
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt");
-}
-
-/*
- * Equal := ZC
- * Less than := N
- * Greater than := C
- * Unordered := CV
- */
-static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr)
-{
- s32 d;
- u32 ret = 0;
-
- d = vfp_get_float(state, sd);
- if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
- ret |= FPSCR_C | FPSCR_V;
- if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
- /*
- * Signalling NaN, or signalling on quiet NaN
- */
- ret |= FPSCR_IOC;
- }
-
- if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
- ret |= FPSCR_C | FPSCR_V;
- if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
- /*
- * Signalling NaN, or signalling on quiet NaN
- */
- ret |= FPSCR_IOC;
- }
-
- if (ret == 0) {
- if (d == m || vfp_single_packed_abs(d | m) == 0) {
- /*
- * equal
- */
- ret |= FPSCR_Z | FPSCR_C;
- } else if (vfp_single_packed_sign(d ^ m)) {
- /*
- * different signs
- */
- if (vfp_single_packed_sign(d))
- /*
- * d is negative, so d < m
- */
- ret |= FPSCR_N;
- else
- /*
- * d is positive, so d > m
- */
- ret |= FPSCR_C;
- } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
- /*
- * d < m
- */
- ret |= FPSCR_N;
- } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
- /*
- * d > m
- */
- ret |= FPSCR_C;
- }
- }
- return ret;
-}
-
-static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- return vfp_compare(state, sd, 0, m, fpscr);
-}
-
-static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- return vfp_compare(state, sd, 1, m, fpscr);
-}
-
-static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- return vfp_compare(state, sd, 0, 0, fpscr);
-}
-
-static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- return vfp_compare(state, sd, 1, 0, fpscr);
-}
-
-static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr)
-{
- struct vfp_single vsm;
- struct vfp_double vdd;
- int tm;
- u32 exceptions = 0;
-
- vfp_single_unpack(&vsm, m);
-
- tm = vfp_single_type(&vsm);
-
- /*
- * If we have a signalling NaN, signal invalid operation.
- */
- if (tm == VFP_SNAN)
- exceptions = FPSCR_IOC;
-
- if (tm & VFP_DENORMAL)
- vfp_single_normalise_denormal(&vsm);
-
- vdd.sign = vsm.sign;
- vdd.significand = (u64)vsm.significand << 32;
-
- /*
- * If we have an infinity or NaN, the exponent must be 2047.
- */
- if (tm & (VFP_INFINITY|VFP_NAN)) {
- vdd.exponent = 2047;
- if (tm == VFP_QNAN)
- vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
- goto pack_nan;
- } else if (tm & VFP_ZERO)
- vdd.exponent = 0;
- else
- vdd.exponent = vsm.exponent + (1023 - 127);
-
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
-
- pack_nan:
- vfp_put_double(state, vfp_double_pack(&vdd), dd);
- return exceptions;
-}
-
-static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- struct vfp_single vs;
-
- vs.sign = 0;
- vs.exponent = 127 + 31 - 1;
- vs.significand = (u32)m;
-
- return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito");
-}
-
-static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- struct vfp_single vs;
-
- vs.sign = (m & 0x80000000) >> 16;
- vs.exponent = 127 + 31 - 1;
- vs.significand = vs.sign ? -m : m;
-
- return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito");
-}
-
-static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- struct vfp_single vsm;
- u32 d, exceptions = 0;
- int rmode = fpscr & FPSCR_RMODE_MASK;
- int tm;
-
- vfp_single_unpack(&vsm, m);
- vfp_single_dump("VSM", &vsm);
-
- /*
- * Do we have a denormalised number?
- */
- tm = vfp_single_type(&vsm);
- if (tm & VFP_DENORMAL)
- exceptions |= FPSCR_IDC;
-
- if (tm & VFP_NAN)
- vsm.sign = 0;
-
- if (vsm.exponent >= 127 + 32) {
- d = vsm.sign ? 0 : 0xffffffff;
- exceptions = FPSCR_IOC;
- } else if (vsm.exponent >= 127 - 1) {
- int shift = 127 + 31 - vsm.exponent;
- u32 rem, incr = 0;
-
- /*
- * 2^0 <= m < 2^32-2^8
- */
- d = (vsm.significand << 1) >> shift;
- rem = vsm.significand << (33 - shift);
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 0x80000000;
- if ((d & 1) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
- incr = ~0;
- }
-
- if ((rem + incr) < rem) {
- if (d < 0xffffffff)
- d += 1;
- else
- exceptions |= FPSCR_IOC;
- }
-
- if (d && vsm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
- } else if (rem)
- exceptions |= FPSCR_IXC;
- } else {
- d = 0;
- if (vsm.exponent | vsm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
- d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
- }
- }
- }
-
- pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
-
- vfp_put_float(state, d, sd);
-
- return exceptions;
-}
-
-static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO);
-}
-
-static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- struct vfp_single vsm;
- u32 d, exceptions = 0;
- int rmode = fpscr & FPSCR_RMODE_MASK;
- int tm;
-
- vfp_single_unpack(&vsm, m);
- vfp_single_dump("VSM", &vsm);
-
- /*
- * Do we have a denormalised number?
- */
- tm = vfp_single_type(&vsm);
- if (vfp_single_type(&vsm) & VFP_DENORMAL)
- exceptions |= FPSCR_IDC;
-
- if (tm & VFP_NAN) {
- d = 0;
- exceptions |= FPSCR_IOC;
- } else if (vsm.exponent >= 127 + 32) {
- /*
- * m >= 2^31-2^7: invalid
- */
- d = 0x7fffffff;
- if (vsm.sign)
- d = ~d;
- exceptions |= FPSCR_IOC;
- } else if (vsm.exponent >= 127 - 1) {
- int shift = 127 + 31 - vsm.exponent;
- u32 rem, incr = 0;
-
- /* 2^0 <= m <= 2^31-2^7 */
- d = (vsm.significand << 1) >> shift;
- rem = vsm.significand << (33 - shift);
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 0x80000000;
- if ((d & 1) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
- incr = ~0;
- }
-
- if ((rem + incr) < rem && d < 0xffffffff)
- d += 1;
- if (d > 0x7fffffff + (vsm.sign != 0)) {
- d = 0x7fffffff + (vsm.sign != 0);
- exceptions |= FPSCR_IOC;
- } else if (rem)
- exceptions |= FPSCR_IXC;
-
- if (vsm.sign)
- d = -d;
- } else {
- d = 0;
- if (vsm.exponent | vsm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
- d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign)
- d = -1;
- }
- }
-
- pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
-
- vfp_put_float(state, (s32)d, sd);
-
- return exceptions;
-}
-
-static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
-{
- return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO);
-}
-
-static struct op fops_ext[] = {
- { vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY
- { vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS
- { vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG
- { vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
- { vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
- { vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
- { vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
- { vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
- { vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
- { vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
- { vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
- { vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
-};
-
-
-
-
-
-static u32
-vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
- struct vfp_single *vsm, u32 fpscr)
-{
- struct vfp_single *vsp;
- u32 exceptions = 0;
- int tn, tm;
-
- tn = vfp_single_type(vsn);
- tm = vfp_single_type(vsm);
-
- if (tn & tm & VFP_INFINITY) {
- /*
- * Two infinities. Are they different signs?
- */
- if (vsn->sign ^ vsm->sign) {
- /*
- * different signs -> invalid
- */
- exceptions = FPSCR_IOC;
- vsp = &vfp_single_default_qnan;
- } else {
- /*
- * same signs -> valid
- */
- vsp = vsn;
- }
- } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
- /*
- * One infinity and one number -> infinity
- */
- vsp = vsn;
- } else {
- /*
- * 'n' is a NaN of some type
- */
- return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
- }
- *vsd = *vsp;
- return exceptions;
-}
-
-static u32
-vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
- struct vfp_single *vsm, u32 fpscr)
-{
- u32 exp_diff, m_sig;
-
- if (vsn->significand & 0x80000000 ||
- vsm->significand & 0x80000000) {
- pr_info("VFP: bad FP values\n");
- vfp_single_dump("VSN", vsn);
- vfp_single_dump("VSM", vsm);
- }
-
- /*
- * Ensure that 'n' is the largest magnitude number. Note that
- * if 'n' and 'm' have equal exponents, we do not swap them.
- * This ensures that NaN propagation works correctly.
- */
- if (vsn->exponent < vsm->exponent) {
- struct vfp_single *t = vsn;
- vsn = vsm;
- vsm = t;
- }
-
- /*
- * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
- * infinity or a NaN here.
- */
- if (vsn->exponent == 255)
- return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
-
- /*
- * We have two proper numbers, where 'vsn' is the larger magnitude.
- *
- * Copy 'n' to 'd' before doing the arithmetic.
- */
- *vsd = *vsn;
-
- /*
- * Align both numbers.
- */
- exp_diff = vsn->exponent - vsm->exponent;
- m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
-
- /*
- * If the signs are different, we are really subtracting.
- */
- if (vsn->sign ^ vsm->sign) {
- m_sig = vsn->significand - m_sig;
- if ((s32)m_sig < 0) {
- vsd->sign = vfp_sign_negate(vsd->sign);
- m_sig = -m_sig;
- } else if (m_sig == 0) {
- vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
- FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
- }
- } else {
- m_sig = vsn->significand + m_sig;
- }
- vsd->significand = m_sig;
-
- return 0;
-}
-
-static u32
-vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
-{
- vfp_single_dump("VSN", vsn);
- vfp_single_dump("VSM", vsm);
-
- /*
- * Ensure that 'n' is the largest magnitude number. Note that
- * if 'n' and 'm' have equal exponents, we do not swap them.
- * This ensures that NaN propagation works correctly.
- */
- if (vsn->exponent < vsm->exponent) {
- struct vfp_single *t = vsn;
- vsn = vsm;
- vsm = t;
- pr_debug("VFP: swapping M <-> N\n");
- }
-
- vsd->sign = vsn->sign ^ vsm->sign;
-
- /*
- * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
- */
- if (vsn->exponent == 255) {
- if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
- return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
- if ((vsm->exponent | vsm->significand) == 0) {
- *vsd = vfp_single_default_qnan;
- return FPSCR_IOC;
- }
- vsd->exponent = vsn->exponent;
- vsd->significand = 0;
- return 0;
- }
-
- /*
- * If 'm' is zero, the result is always zero. In this case,
- * 'n' may be zero or a number, but it doesn't matter which.
- */
- if ((vsm->exponent | vsm->significand) == 0) {
- vsd->exponent = 0;
- vsd->significand = 0;
- return 0;
- }
-
- /*
- * We add 2 to the destination exponent for the same reason as
- * the addition case - though this time we have +1 from each
- * input operand.
- */
- vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
- vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
-
- vfp_single_dump("VSD", vsd);
- return 0;
-}
-
-#define NEG_MULTIPLY (1 << 0)
-#define NEG_SUBTRACT (1 << 1)
-
-static u32
-vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func)
-{
- struct vfp_single vsd, vsp, vsn, vsm;
- u32 exceptions;
- s32 v;
-
- v = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, v);
- vfp_single_unpack(&vsn, v);
- if (vsn.exponent == 0 && vsn.significand)
- vfp_single_normalise_denormal(&vsn);
-
- vfp_single_unpack(&vsm, m);
- if (vsm.exponent == 0 && vsm.significand)
- vfp_single_normalise_denormal(&vsm);
-
- exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
- if (negate & NEG_MULTIPLY)
- vsp.sign = vfp_sign_negate(vsp.sign);
-
- v = vfp_get_float(state, sd);
- pr_debug("VFP: s%u = %08x\n", sd, v);
- vfp_single_unpack(&vsn, v);
- if (negate & NEG_SUBTRACT)
- vsn.sign = vfp_sign_negate(vsn.sign);
-
- exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
-
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
-}
-
-/*
- * Standard operations
- */
-
-/*
- * sd = sd + (sn * sm)
- */
-static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
- return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
-}
-
-/*
- * sd = sd - (sn * sm)
- */
-static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn);
- return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
-}
-
-/*
- * sd = -sd + (sn * sm)
- */
-static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
- return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
-}
-
-/*
- * sd = -sd - (sn * sm)
- */
-static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
- return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
-}
-
-/*
- * sd = sn * sm
- */
-static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- struct vfp_single vsd, vsn, vsm;
- u32 exceptions;
- s32 n = vfp_get_float(state, sn);
-
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n);
-
- vfp_single_unpack(&vsn, n);
- if (vsn.exponent == 0 && vsn.significand)
- vfp_single_normalise_denormal(&vsn);
-
- vfp_single_unpack(&vsm, m);
- if (vsm.exponent == 0 && vsm.significand)
- vfp_single_normalise_denormal(&vsm);
-
- exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul");
-}
-
-/*
- * sd = -(sn * sm)
- */
-static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- struct vfp_single vsd, vsn, vsm;
- u32 exceptions;
- s32 n = vfp_get_float(state, sn);
-
- pr_debug("VFP: s%u = %08x\n", sn, n);
-
- vfp_single_unpack(&vsn, n);
- if (vsn.exponent == 0 && vsn.significand)
- vfp_single_normalise_denormal(&vsn);
-
- vfp_single_unpack(&vsm, m);
- if (vsm.exponent == 0 && vsm.significand)
- vfp_single_normalise_denormal(&vsm);
-
- exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
- vsd.sign = vfp_sign_negate(vsd.sign);
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul");
-}
-
-/*
- * sd = sn + sm
- */
-static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- struct vfp_single vsd, vsn, vsm;
- u32 exceptions;
- s32 n = vfp_get_float(state, sn);
-
- pr_debug("VFP: s%u = %08x\n", sn, n);
-
- /*
- * Unpack and normalise denormals.
- */
- vfp_single_unpack(&vsn, n);
- if (vsn.exponent == 0 && vsn.significand)
- vfp_single_normalise_denormal(&vsn);
-
- vfp_single_unpack(&vsm, m);
- if (vsm.exponent == 0 && vsm.significand)
- vfp_single_normalise_denormal(&vsm);
-
- exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr);
-
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd");
-}
-
-/*
- * sd = sn - sm
- */
-static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
- /*
- * Subtraction is addition with one sign inverted.
- */
- return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr);
-}
-
-/*
- * sd = sn / sm
- */
-static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
-{
- struct vfp_single vsd, vsn, vsm;
- u32 exceptions = 0;
- s32 n = vfp_get_float(state, sn);
- int tm, tn;
-
- pr_debug("VFP: s%u = %08x\n", sn, n);
-
- vfp_single_unpack(&vsn, n);
- vfp_single_unpack(&vsm, m);
-
- vsd.sign = vsn.sign ^ vsm.sign;
-
- tn = vfp_single_type(&vsn);
- tm = vfp_single_type(&vsm);
-
- /*
- * Is n a NAN?
- */
- if (tn & VFP_NAN)
- goto vsn_nan;
-
- /*
- * Is m a NAN?
- */
- if (tm & VFP_NAN)
- goto vsm_nan;
-
- /*
- * If n and m are infinity, the result is invalid
- * If n and m are zero, the result is invalid
- */
- if (tm & tn & (VFP_INFINITY|VFP_ZERO))
- goto invalid;
-
- /*
- * If n is infinity, the result is infinity
- */
- if (tn & VFP_INFINITY)
- goto infinity;
-
- /*
- * If m is zero, raise div0 exception
- */
- if (tm & VFP_ZERO)
- goto divzero;
-
- /*
- * If m is infinity, or n is zero, the result is zero
- */
- if (tm & VFP_INFINITY || tn & VFP_ZERO)
- goto zero;
-
- if (tn & VFP_DENORMAL)
- vfp_single_normalise_denormal(&vsn);
- if (tm & VFP_DENORMAL)
- vfp_single_normalise_denormal(&vsm);
-
- /*
- * Ok, we have two numbers, we can perform division.
- */
- vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
- vsm.significand <<= 1;
- if (vsm.significand <= (2 * vsn.significand)) {
- vsn.significand >>= 1;
- vsd.exponent++;
- }
- {
- u64 significand = (u64)vsn.significand << 32;
- do_div(significand, vsm.significand);
- vsd.significand = significand;
- }
- if ((vsd.significand & 0x3f) == 0)
- vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
-
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
-
- vsn_nan:
- exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
- pack:
- vfp_put_float(state, vfp_single_pack(&vsd), sd);
- return exceptions;
-
- vsm_nan:
- exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
- goto pack;
-
- zero:
- vsd.exponent = 0;
- vsd.significand = 0;
- goto pack;
-
- divzero:
- exceptions = FPSCR_DZC;
- infinity:
- vsd.exponent = 255;
- vsd.significand = 0;
- goto pack;
-
- invalid:
- vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
- return FPSCR_IOC;
-}
-
-static struct op fops[] = {
- { vfp_single_fmac, 0 },
- { vfp_single_fmsc, 0 },
- { vfp_single_fmul, 0 },
- { vfp_single_fadd, 0 },
- { vfp_single_fnmac, 0 },
- { vfp_single_fnmsc, 0 },
- { vfp_single_fnmul, 0 },
- { vfp_single_fsub, 0 },
- { vfp_single_fdiv, 0 },
-};
-
-#define FREG_BANK(x) ((x) & 0x18)
-#define FREG_IDX(x) ((x) & 7)
-
-u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
-{
- u32 op = inst & FOP_MASK;
- u32 exceptions = 0;
- unsigned int dest;
- unsigned int sn = vfp_get_sn(inst);
- unsigned int sm = vfp_get_sm(inst);
- unsigned int vecitr, veclen, vecstride;
- struct op *fop;
- pr_debug("In %s\n", __FUNCTION__);
-
- vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
-
- fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
-
- /*
- * fcvtsd takes a dN register number as destination, not sN.
- * Technically, if bit 0 of dd is set, this is an invalid
- * instruction. However, we ignore this for efficiency.
- * It also only operates on scalars.
- */
- if (fop->flags & OP_DD)
- dest = vfp_get_dd(inst);
- else
- dest = vfp_get_sd(inst);
-
- /*
- * If destination bank is zero, vector length is always '1'.
- * ARM DDI0100F C5.1.3, C5.3.2.
- */
- if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
- veclen = 0;
- else
- veclen = fpscr & FPSCR_LENGTH_MASK;
-
- pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
- (veclen >> FPSCR_LENGTH_BIT) + 1);
-
- if (!fop->fn) {
- printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]);
- exit(-1);
- goto invalid;
- }
-
- for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
- s32 m = vfp_get_float(state, sm);
- u32 except;
- char type;
-
- type = fop->flags & OP_DD ? 'd' : 's';
- if (op == FOP_EXT)
- pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
- sm, m);
- else
- pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
- FOP_TO_IDX(op), sm, m);
-
- except = fop->fn(state, dest, sn, m, fpscr);
- pr_debug("VFP: itr%d: exceptions=%08x\n",
- vecitr >> FPSCR_LENGTH_BIT, except);
-
- exceptions |= except;
-
- /*
- * CHECK: It appears to be undefined whether we stop when
- * we encounter an exception. We continue.
- */
- dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
- sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
- if (FREG_BANK(sm) != 0)
- sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
- }
- return exceptions;
-
- invalid:
- return (u32)-1;
-}
diff --git a/src/core/arm/interpreter/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index 0ca62780b..4dac1a8bf 100644
--- a/src/core/arm/interpreter/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -99,5 +99,7 @@ enum arm_regno{
MAX_REG_NUM,
};
-#define VFP_OFFSET(x) (x - VFP_BASE)
+#define CP15(idx) (idx - CP15_BASE)
+#define VFP_OFFSET(x) (x - VFP_BASE)
+
#endif
diff --git a/src/core/arm/interpreter/armcpu.h b/src/core/arm/skyeye_common/armcpu.h
index 6b5ea8566..3a029f0e7 100644
--- a/src/core/arm/interpreter/armcpu.h
+++ b/src/core/arm/skyeye_common/armcpu.h
@@ -20,16 +20,13 @@
#ifndef __ARM_CPU_H__
#define __ARM_CPU_H__
-//#include <skyeye_thread.h>
-//#include <skyeye_obj.h>
-//#include <skyeye_mach.h>
-//#include <skyeye_exec.h>
#include <stddef.h>
#include <stdio.h>
#include "common/thread.h"
+#include "core/arm/skyeye_common/armdefs.h"
typedef struct ARM_CPU_State_s {
ARMul_State * core;
diff --git a/src/core/arm/interpreter/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index dd5983be3..8e71948c6 100644
--- a/src/core/arm/interpreter/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -31,7 +31,7 @@
#include "arm_regformat.h"
#include "common/platform.h"
-#include "skyeye_defs.h"
+#include "core/arm/skyeye_common/skyeye_defs.h"
//AJ2D--------------------------------------------------------------------------
@@ -130,7 +130,7 @@ typedef unsigned long long uint64_t;
#endif
*/
-#include "armmmu.h"
+#include "core/arm/skyeye_common/armmmu.h"
//#include "lcd/skyeye_lcd.h"
@@ -367,7 +367,6 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
int verbose; /* non-zero means print various messages like the banner */
- mmu_state_t mmu;
int mmu_inited;
//mem_state_t mem;
/*remove io_state to skyeye_mach_*.c files */
diff --git a/src/core/arm/interpreter/armemu.h b/src/core/arm/skyeye_common/armemu.h
index 36fb2d09b..c0f0270fe 100644
--- a/src/core/arm/interpreter/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -18,7 +18,7 @@
#define __ARMEMU_H__
-#include "armdefs.h"
+#include "core/arm/skyeye_common/armdefs.h"
//#include "skyeye.h"
//extern ARMword isize;
diff --git a/src/core/arm/interpreter/armmmu.h b/src/core/arm/skyeye_common/armmmu.h
index 818108c9c..30858f9ba 100644
--- a/src/core/arm/interpreter/armmmu.h
+++ b/src/core/arm/skyeye_common/armmmu.h
@@ -134,121 +134,4 @@ typedef enum fault_t
} fault_t;
-typedef struct mmu_ops_s
-{
- /*initilization */
- int (*init) (ARMul_State * state);
- /*free on exit */
- void (*exit) (ARMul_State * state);
- /*read byte data */
- fault_t (*read_byte) (ARMul_State * state, ARMword va,
- ARMword * data);
- /*write byte data */
- fault_t (*write_byte) (ARMul_State * state, ARMword va,
- ARMword data);
- /*read halfword data */
- fault_t (*read_halfword) (ARMul_State * state, ARMword va,
- ARMword * data);
- /*write halfword data */
- fault_t (*write_halfword) (ARMul_State * state, ARMword va,
- ARMword data);
- /*read word data */
- fault_t (*read_word) (ARMul_State * state, ARMword va,
- ARMword * data);
- /*write word data */
- fault_t (*write_word) (ARMul_State * state, ARMword va,
- ARMword data);
- /*load instr */
- fault_t (*load_instr) (ARMul_State * state, ARMword va,
- ARMword * instr);
- /*mcr */
- ARMword (*mcr) (ARMul_State * state, ARMword instr, ARMword val);
- /*mrc */
- ARMword (*mrc) (ARMul_State * state, ARMword instr, ARMword * val);
-
- /*ywc 2005-04-16 convert virtual address to physics address */
- int (*v2p_dbct) (ARMul_State * state, ARMword virt_addr,
- ARMword * phys_addr);
-} mmu_ops_t;
-
-
-#include "core/arm/interpreter/mmu/tlb.h"
-#include "core/arm/interpreter/mmu/rb.h"
-#include "core/arm/interpreter/mmu/wb.h"
-#include "core/arm/interpreter/mmu/cache.h"
-
-/*special process mmu.h*/
-#include "core/arm/interpreter/mmu/sa_mmu.h"
-//#include "core/arm/interpreter/mmu/arm7100_mmu.h"
-//#include "core/arm/interpreter/mmu/arm920t_mmu.h"
-//#include "core/arm/interpreter/mmu/arm926ejs_mmu.h"
-#include "core/arm/interpreter/mmu/arm1176jzf_s_mmu.h"
-//#include "core/arm/interpreter/mmu/cortex_a9_mmu.h"
-
-typedef struct mmu_state_t
-{
- ARMword control;
- ARMword translation_table_base;
-/* dyf 201-08-11 for arm1176 */
- ARMword auxiliary_control;
- ARMword coprocessor_access_control;
- ARMword translation_table_base0;
- ARMword translation_table_base1;
- ARMword translation_table_ctrl;
-/* arm1176 end */
-
- ARMword domain_access_control;
- ARMword fault_status;
- ARMword fault_statusi; /* prefetch fault status */
- ARMword fault_address;
- ARMword last_domain;
- ARMword process_id;
- ARMword context_id;
- ARMword thread_uro_id;
- ARMword cache_locked_down;
- ARMword tlb_locked_down;
-//chy 2003-08-24 for xscale
- ARMword cache_type; // 0
- ARMword aux_control; // 1
- ARMword copro_access; // 15
-
- mmu_ops_t ops;
- union
- {
- sa_mmu_t sa_mmu;
- //arm7100_mmu_t arm7100_mmu;
- //arm920t_mmu_t arm920t_mmu;
- //arm926ejs_mmu_t arm926ejs_mmu;
- } u;
-} mmu_state_t;
-
-int mmu_init (ARMul_State * state);
-int mmu_reset (ARMul_State * state);
-void mmu_exit (ARMul_State * state);
-
-fault_t mmu_read_word (ARMul_State * state, ARMword virt_addr,
- ARMword * data);
-fault_t mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data);
-fault_t mmu_load_instr (ARMul_State * state, ARMword virt_addr,
- ARMword * instr);
-
-ARMword mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value);
-void mmu_mcr (ARMul_State * state, ARMword instr, ARMword value);
-
-/*ywc 20050416*/
-int mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr,
- ARMword * phys_addr);
-
-fault_t
-mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data);
-fault_t
-mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data);
-fault_t
-mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data);
-fault_t
-mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data);
-fault_t
-mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data);
-fault_t
-mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data);
#endif /* _ARMMMU_H_ */
diff --git a/src/core/arm/interpreter/armos.h b/src/core/arm/skyeye_common/armos.h
index 4b58801ad..ffdadcd1c 100644
--- a/src/core/arm/interpreter/armos.h
+++ b/src/core/arm/skyeye_common/armos.h
@@ -15,14 +15,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-//#include "bank_defs.h"
-//#include "dyncom/defines.h"
-
-//typedef struct mmap_area{
-// mem_bank_t bank;
-// void *mmap_addr;
-// struct mmap_area *next;
-//}mmap_area_t;
+#include <stdint.h>
#if FAST_MEMORY
/* in user mode, mmap_base will be on initial brk,
diff --git a/src/core/arm/interpreter/skyeye_defs.h b/src/core/arm/skyeye_common/skyeye_defs.h
index b6713ebad..d4088383f 100644
--- a/src/core/arm/interpreter/skyeye_defs.h
+++ b/src/core/arm/skyeye_common/skyeye_defs.h
@@ -108,4 +108,6 @@ typedef struct generic_arch_s
align_t alignment;
} generic_arch_t;
-#endif \ No newline at end of file
+typedef u32 addr_t;
+
+#endif
diff --git a/src/core/arm/skyeye_common/skyeye_types.h b/src/core/arm/skyeye_common/skyeye_types.h
new file mode 100644
index 000000000..e7f022f19
--- /dev/null
+++ b/src/core/arm/skyeye_common/skyeye_types.h
@@ -0,0 +1,55 @@
+/*
+ skyeye_types.h - some data types definition for skyeye debugger
+ Copyright (C) 2003 Skyeye Develop Group
+ for help please send mail to <skyeye-developer@lists.sf.linuxforum.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+/*
+ * 12/16/2006 Michael.Kang <blackfin.kang@gmail.com>
+ */
+
+#ifndef __SKYEYE_TYPES_H
+#define __SKYEYE_TYPES_H
+
+#include <stdint.h>
+
+/*default machine word length */
+
+#ifndef __BEOS__
+/* To avoid the type conflict with the qemu */
+#ifndef QEMU
+typedef uint8_t uint8;
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+
+typedef int8_t sint8;
+typedef int16_t sint16;
+typedef int32_t sint32;
+typedef int64_t sint64;
+#endif
+
+typedef uint32_t address_t;
+typedef uint32_t uinteger_t;
+typedef int32_t integer_t;
+
+typedef uint32_t physical_address_t;
+typedef uint32_t generic_address_t;
+
+#endif
+
+#endif
diff --git a/src/core/arm/interpreter/vfp/asm_vfp.h b/src/core/arm/skyeye_common/vfp/asm_vfp.h
index f4ab34fd4..f4ab34fd4 100644
--- a/src/core/arm/interpreter/vfp/asm_vfp.h
+++ b/src/core/arm/skyeye_common/vfp/asm_vfp.h
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
new file mode 100644
index 000000000..454f60099
--- /dev/null
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -0,0 +1,397 @@
+/*
+ armvfp.c - ARM VFPv3 emulation unit
+ Copyright (C) 2003 Skyeye Develop Group
+ for help please send mail to <skyeye-developer@lists.gro.clinux.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* Note: this file handles interface with arm core and vfp registers */
+
+/* Opens debug for classic interpreter only */
+//#define DEBUG
+
+#include "common/common.h"
+
+#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
+
+#define DEBUG DBG
+
+//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
+
+unsigned
+VFPInit (ARMul_State *state)
+{
+ state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
+ VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
+ state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
+ state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
+
+ //persistent_state = state;
+ /* Reset only specify VFP_FPEXC_EN = '0' */
+
+ return 0;
+}
+
+unsigned
+VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
+{
+ /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (21, 23);
+ int Rt = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MRC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MRC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
+ instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
+
+ return ARMul_CANT;
+}
+
+unsigned
+VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value)
+{
+ /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (21, 23);
+ int Rt = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MCR_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MCR_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
+ instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
+
+ return ARMul_CANT;
+}
+
+unsigned
+VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2)
+{
+ /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (4, 7);
+ int Rt = BITS (12, 15);
+ int Rt2 = BITS (16, 19);
+ int CRm = BITS (0, 3);
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MRRC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MRRC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
+ instr, CoProc, OPC_1, Rt, Rt2, CRm);
+
+ return ARMul_CANT;
+}
+
+unsigned
+VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2)
+{
+ /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (4, 7);
+ int Rt = BITS (12, 15);
+ int Rt2 = BITS (16, 19);
+ int CRm = BITS (0, 3);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 11 || CoProc == 10) {
+#define VFP_MCRR_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MCRR_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
+ instr, CoProc, OPC_1, Rt, Rt2, CRm);
+
+ return ARMul_CANT;
+}
+
+unsigned
+VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
+{
+ /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int CRd = BITS (12, 15);
+ int Rn = BITS (16, 19);
+ int imm8 = BITS (0, 7);
+ int P = BIT(24);
+ int U = BIT(23);
+ int D = BIT(22);
+ int W = BIT(21);
+
+ /* TODO check access permission */
+
+ /* VSTM */
+ if ( (P|U|D|W) == 0 ) {
+ DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
+ exit(-1);
+ }
+ if (CoProc == 10 || CoProc == 11) {
+#if 1
+ if (P == 0 && U == 0 && W == 0) {
+ DEBUG("VSTM Related encodings\n");
+ exit(-1);
+ }
+ if (P == U && W == 1) {
+ DEBUG("UNDEFINED\n");
+ exit(-1);
+ }
+#endif
+
+#define VFP_STC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_STC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
+ instr, CoProc, CRd, Rn, imm8, P, U, D, W);
+
+ return ARMul_CANT;
+}
+
+unsigned
+VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value)
+{
+ /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int CRd = BITS (12, 15);
+ int Rn = BITS (16, 19);
+ int imm8 = BITS (0, 7);
+ int P = BIT(24);
+ int U = BIT(23);
+ int D = BIT(22);
+ int W = BIT(21);
+
+ /* TODO check access permission */
+
+ if ( (P|U|D|W) == 0 ) {
+ DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
+ exit(-1);
+ }
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_LDC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_LDC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
+ instr, CoProc, CRd, Rn, imm8, P, U, D, W);
+
+ return ARMul_CANT;
+}
+
+unsigned
+VFPCDP (ARMul_State * state, unsigned type, u32 instr)
+{
+ /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (20, 23);
+ int CRd = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ //ichfly
+ /*if ((instr & 0x0FBF0FD0) == 0x0EB70AC0) //vcvt.f64.f32 d8, s16 (s is bit 0-3 and LSB bit 22) (d is bit 12 - 15 MSB is Bit 6)
+ {
+ struct vfp_double vdd;
+ struct vfp_single vsd;
+ int dn = BITS(12, 15) + (BIT(22) << 4);
+ int sd = (BITS(0, 3) << 1) + BIT(5);
+ s32 n = vfp_get_float(state, sd);
+ vfp_single_unpack(&vsd, n);
+ if (vsd.exponent & 0x80)
+ {
+ vdd.exponent = (vsd.exponent&~0x80) | 0x400;
+ }
+ else
+ {
+ vdd.exponent = vsd.exponent | 0x380;
+ }
+ vdd.sign = vsd.sign;
+ vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand
+ vfp_put_double(state, vfp_double_pack(&vdd), dn);
+ return ARMul_DONE;
+ }
+ if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6
+ {
+ struct vfp_double vdd;
+ struct vfp_single vsd;
+ int sd = BITS(0, 3) + (BIT(5) << 4);
+ int dn = (BITS(12, 15) << 1) + BIT(22);
+ vfp_double_unpack(&vdd, vfp_get_double(state, sd));
+ if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert
+ {
+ vsd.exponent = (vdd.exponent) | 0x80;
+ }
+ else
+ {
+ vsd.exponent = vdd.exponent & ~0x80;
+ }
+ vsd.exponent &= 0xFF;
+ // vsd.exponent = vdd.exponent >> 3;
+ vsd.sign = vdd.sign;
+ vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000;
+ vfp_put_float(state, vfp_single_pack(&vsd), dn);
+ return ARMul_DONE;
+ }*/
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_CDP_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_CDP_TRANS
+
+ int exceptions = 0;
+ if (CoProc == 10)
+ exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ else
+ exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+
+ vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+
+ return ARMul_DONE;
+ }
+ DEBUG("Can't identify %x\n", instr);
+ return ARMul_CANT;
+}
+
+
+/* ----------- MRC ------------ */
+#define VFP_MRC_IMPL
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MRC_IMPL
+
+#define VFP_MRRC_IMPL
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MRRC_IMPL
+
+
+/* ----------- MCR ------------ */
+#define VFP_MCR_IMPL
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MCR_IMPL
+
+#define VFP_MCRR_IMPL
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MCRR_IMPL
+
+/* Memory operation are not inlined, as old Interpreter and Fast interpreter
+ don't have the same memory operation interface.
+ Old interpreter framework does one access to coprocessor per data, and
+ handles already data write, as well as address computation,
+ which is not the case for Fast interpreter. Therefore, implementation
+ of vfp instructions in old interpreter and fast interpreter are separate. */
+
+/* ----------- STC ------------ */
+#define VFP_STC_IMPL
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_STC_IMPL
+
+
+/* ----------- LDC ------------ */
+#define VFP_LDC_IMPL
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_LDC_IMPL
+
+
+/* ----------- CDP ------------ */
+#define VFP_CDP_IMPL
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_CDP_IMPL
+
+/* Miscellaneous functions */
+int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
+{
+ DEBUG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
+ return state->ExtReg[reg];
+}
+
+void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg)
+{
+ DEBUG("VFP put float: s%d <= [%08x]\n", reg, val);
+ state->ExtReg[reg] = val;
+}
+
+uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
+{
+ uint64_t result;
+ result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
+ DEBUG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
+ return result;
+}
+
+void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
+{
+ DEBUG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
+ state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
+ state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
+}
+
+
+
+/*
+ * Process bitmask of exception conditions. (from vfpmodule.c)
+ */
+void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
+{
+ int si_code = 0;
+
+ vfpdebug("VFP: raising exceptions %08x\n", exceptions);
+
+ if (exceptions == VFP_EXCEPTION_ERROR) {
+ DEBUG("unhandled bounce %x\n", inst);
+ exit(-1);
+ return;
+ }
+
+ /*
+ * If any of the status flags are set, update the FPSCR.
+ * Comparison instructions always return at least one of
+ * these flags set.
+ */
+ if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
+ fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
+
+ fpscr |= exceptions;
+
+ state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
+}
diff --git a/src/core/arm/interpreter/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index bbf4caeb0..7256701f3 100644
--- a/src/core/arm/interpreter/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -25,7 +25,7 @@
#define vfpdebug //printf
-#include "core/arm/interpreter/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
+#include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
unsigned VFPInit (ARMul_State *state);
unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value);
@@ -88,21 +88,21 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
/* MRC */
-inline void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value);
-inline void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value);
-inline void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2);
-inline void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
-inline void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
+void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value);
+void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value);
+void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2);
+void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
+void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
/* MCR */
-inline void VMSR(ARMul_State * state, ARMword reg, ARMword Rt);
+void VMSR(ARMul_State * state, ARMword reg, ARMword Rt);
/* STC */
-inline int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value);
-inline int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value);
-inline int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value);
+int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value);
+int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value);
+int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value);
/* LDC */
-inline int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value);
-inline int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value);
-inline int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value);
+int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value);
+int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value);
+int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value);
#ifdef __cplusplus
}
diff --git a/src/core/arm/interpreter/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index b222e79f1..b1949603a 100644
--- a/src/core/arm/interpreter/vfp/vfp_helper.h
+++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h
@@ -38,19 +38,13 @@
#include <stdint.h>
#include <stdio.h>
-#include "core/arm/interpreter/armdefs.h"
-
-#define u16 uint16_t
-#define u32 uint32_t
-#define u64 uint64_t
-#define s16 int16_t
-#define s32 int32_t
-#define s64 int64_t
+#include "common/common_types.h"
+#include "core/arm/skyeye_common/armdefs.h"
#define pr_info //printf
#define pr_debug //printf
-static u32 vfp_fls(int x);
+static u32 fls(ARMword x);
#define do_div(n, base) {n/=base;}
/* From vfpinstr.h */
@@ -508,7 +502,7 @@ struct op {
u32 flags;
};
-static u32 vfp_fls(int x)
+static u32 fls(ARMword x)
{
int r = 32;
@@ -538,4 +532,9 @@ static u32 vfp_fls(int x)
}
+u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func);
+u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr);
+u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr);
+u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr);
+
#endif
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
new file mode 100644
index 000000000..765c1f6bc
--- /dev/null
+++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
@@ -0,0 +1,1432 @@
+/*
+ vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction
+ Copyright (C) 2003 Skyeye Develop Group
+ for help please send mail to <skyeye-developer@lists.gro.clinux.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * This code is derived in part from :
+ * - Android kernel
+ * - John R. Housers softfloat library, which
+ * carries the following notice:
+ *
+ * ===========================================================================
+ * This C source file is part of the SoftFloat IEC/IEEE Floating-point
+ * Arithmetic Package, Release 2.
+ *
+ * Written by John R. Hauser. This work was made possible in part by the
+ * International Computer Science Institute, located at Suite 600, 1947 Center
+ * Street, Berkeley, California 94704. Funding was partially provided by the
+ * National Science Foundation under grant MIP-9311980. The original version
+ * of this code was written as part of a project to build a fixed-point vector
+ * processor in collaboration with the University of California at Berkeley,
+ * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+ * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+ * arithmetic/softfloat.html'.
+ *
+ * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+ * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+ * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+ * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+ * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+ *
+ * Derivative works are acceptable, even for commercial purposes, so long as
+ * (1) they include prominent notice that the work is derivative, and (2) they
+ * include prominent notice akin to these three paragraphs for those parts of
+ * this code that are retained.
+ * ===========================================================================
+ */
+
+#include "core/arm/skyeye_common/vfp/vfp.h"
+#include "core/arm/skyeye_common/vfp/vfp_helper.h"
+#include "core/arm/skyeye_common/vfp/asm_vfp.h"
+
+static struct vfp_double vfp_double_default_qnan = {
+ 2047,
+ 0,
+ VFP_DOUBLE_SIGNIFICAND_QNAN,
+};
+
+static void vfp_double_dump(const char *str, struct vfp_double *d)
+{
+ pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
+ str, d->sign != 0, d->exponent, d->significand);
+}
+
+static void vfp_double_normalise_denormal(struct vfp_double *vd)
+{
+ int bits = 31 - fls((ARMword)(vd->significand >> 32));
+ if (bits == 31)
+ bits = 63 - fls((ARMword)vd->significand);
+
+ vfp_double_dump("normalise_denormal: in", vd);
+
+ if (bits) {
+ vd->exponent -= bits - 1;
+ vd->significand <<= bits;
+ }
+
+ vfp_double_dump("normalise_denormal: out", vd);
+}
+
+u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
+{
+ u64 significand, incr;
+ int exponent, shift, underflow;
+ u32 rmode;
+
+ vfp_double_dump("pack: in", vd);
+
+ /*
+ * Infinities and NaNs are a special case.
+ */
+ if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
+ goto pack;
+
+ /*
+ * Special-case zero.
+ */
+ if (vd->significand == 0) {
+ vd->exponent = 0;
+ goto pack;
+ }
+
+ exponent = vd->exponent;
+ significand = vd->significand;
+
+ shift = 32 - fls((ARMword)(significand >> 32));
+ if (shift == 32)
+ shift = 64 - fls((ARMword)significand);
+ if (shift) {
+ exponent -= shift;
+ significand <<= shift;
+ }
+
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: normalised", vd);
+#endif
+
+ /*
+ * Tiny number?
+ */
+ underflow = exponent < 0;
+ if (underflow) {
+ significand = vfp_shiftright64jamming(significand, -exponent);
+ exponent = 0;
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: tiny number", vd);
+#endif
+ if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
+ underflow = 0;
+ }
+
+ /*
+ * Select rounding increment.
+ */
+ incr = 0;
+ rmode = fpscr & FPSCR_RMODE_MASK;
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 1ULL << VFP_DOUBLE_LOW_BITS;
+ if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
+ incr -= 1;
+ }
+ else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ }
+ else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
+ incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
+
+ pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
+
+ /*
+ * Is our rounding going to overflow?
+ */
+ if ((significand + incr) < significand) {
+ exponent += 1;
+ significand = (significand >> 1) | (significand & 1);
+ incr >>= 1;
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: overflow", vd);
+#endif
+ }
+
+ /*
+ * If any of the low bits (which will be shifted out of the
+ * number) are non-zero, the result is inexact.
+ */
+ if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
+ exceptions |= FPSCR_IXC;
+
+ /*
+ * Do our rounding.
+ */
+ significand += incr;
+
+ /*
+ * Infinity?
+ */
+ if (exponent >= 2046) {
+ exceptions |= FPSCR_OFC | FPSCR_IXC;
+ if (incr == 0) {
+ vd->exponent = 2045;
+ vd->significand = 0x7fffffffffffffffULL;
+ }
+ else {
+ vd->exponent = 2047; /* infinity */
+ vd->significand = 0;
+ }
+ }
+ else {
+ if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
+ exponent = 0;
+ if (exponent || significand > 0x8000000000000000ULL)
+ underflow = 0;
+ if (underflow)
+ exceptions |= FPSCR_UFC;
+ vd->exponent = exponent;
+ vd->significand = significand >> 1;
+ }
+ pack:
+ return 0;
+}
+
+u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
+{
+ u64 significand, incr;
+ int exponent, shift, underflow;
+ u32 rmode;
+
+ vfp_double_dump("pack: in", vd);
+
+ /*
+ * Infinities and NaNs are a special case.
+ */
+ if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
+ goto pack;
+
+ /*
+ * Special-case zero.
+ */
+ if (vd->significand == 0) {
+ vd->exponent = 0;
+ goto pack;
+ }
+
+ exponent = vd->exponent;
+ significand = vd->significand;
+
+ shift = 32 - fls((ARMword)(significand >> 32));
+ if (shift == 32)
+ shift = 64 - fls((ARMword)significand);
+ if (shift) {
+ exponent -= shift;
+ significand <<= shift;
+ }
+
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: normalised", vd);
+#endif
+
+ /*
+ * Tiny number?
+ */
+ underflow = exponent < 0;
+ if (underflow) {
+ significand = vfp_shiftright64jamming(significand, -exponent);
+ exponent = 0;
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: tiny number", vd);
+#endif
+ if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
+ underflow = 0;
+ }
+
+ /*
+ * Select rounding increment.
+ */
+ incr = 0;
+ rmode = fpscr & FPSCR_RMODE_MASK;
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 1ULL << VFP_DOUBLE_LOW_BITS;
+ if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
+ incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
+
+ pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
+
+ /*
+ * Is our rounding going to overflow?
+ */
+ if ((significand + incr) < significand) {
+ exponent += 1;
+ significand = (significand >> 1) | (significand & 1);
+ incr >>= 1;
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: overflow", vd);
+#endif
+ }
+
+ /*
+ * If any of the low bits (which will be shifted out of the
+ * number) are non-zero, the result is inexact.
+ */
+ if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
+ exceptions |= FPSCR_IXC;
+
+ /*
+ * Do our rounding.
+ */
+ significand += incr;
+
+ /*
+ * Infinity?
+ */
+ if (exponent >= 2046) {
+ exceptions |= FPSCR_OFC | FPSCR_IXC;
+ if (incr == 0) {
+ vd->exponent = 2045;
+ vd->significand = 0x7fffffffffffffffULL;
+ } else {
+ vd->exponent = 2047; /* infinity */
+ vd->significand = 0;
+ }
+ } else {
+ if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
+ exponent = 0;
+ if (exponent || significand > 0x8000000000000000ULL)
+ underflow = 0;
+ if (underflow)
+ exceptions |= FPSCR_UFC;
+ vd->exponent = exponent;
+ vd->significand = significand >> 1;
+ }
+
+pack:
+ vfp_double_dump("pack: final", vd);
+ {
+ s64 d = vfp_double_pack(vd);
+ pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func,
+ dd, d, exceptions);
+ vfp_put_double(state, d, dd);
+ }
+ return exceptions;
+}
+
+/*
+ * Propagate the NaN, setting exceptions if it is signalling.
+ * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
+ */
+static u32
+vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
+ struct vfp_double *vdm, u32 fpscr)
+{
+ struct vfp_double *nan;
+ int tn, tm = 0;
+
+ tn = vfp_double_type(vdn);
+
+ if (vdm)
+ tm = vfp_double_type(vdm);
+
+ if (fpscr & FPSCR_DEFAULT_NAN)
+ /*
+ * Default NaN mode - always returns a quiet NaN
+ */
+ nan = &vfp_double_default_qnan;
+ else {
+ /*
+ * Contemporary mode - select the first signalling
+ * NAN, or if neither are signalling, the first
+ * quiet NAN.
+ */
+ if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
+ nan = vdn;
+ else
+ nan = vdm;
+ /*
+ * Make the NaN quiet.
+ */
+ nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
+ }
+
+ *vdd = *nan;
+
+ /*
+ * If one was a signalling NAN, raise invalid operation.
+ */
+ return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
+}
+
+/*
+ * Extended operations
+ */
+static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd);
+ return 0;
+}
+
+static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_put_double(state, vfp_get_double(state, dm), dd);
+ return 0;
+}
+
+static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd);
+ return 0;
+}
+
+static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double vdm, vdd, *vdp;
+ int ret, tm;
+
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ tm = vfp_double_type(&vdm);
+ if (tm & (VFP_NAN|VFP_INFINITY)) {
+ vdp = &vdd;
+
+ if (tm & VFP_NAN)
+ ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
+ else if (vdm.sign == 0) {
+sqrt_copy:
+ vdp = &vdm;
+ ret = 0;
+ } else {
+sqrt_invalid:
+ vdp = &vfp_double_default_qnan;
+ ret = FPSCR_IOC;
+ }
+ vfp_put_double(state, vfp_double_pack(vdp), dd);
+ return ret;
+ }
+
+ /*
+ * sqrt(+/- 0) == +/- 0
+ */
+ if (tm & VFP_ZERO)
+ goto sqrt_copy;
+
+ /*
+ * Normalise a denormalised number
+ */
+ if (tm & VFP_DENORMAL)
+ vfp_double_normalise_denormal(&vdm);
+
+ /*
+ * sqrt(<0) = invalid
+ */
+ if (vdm.sign)
+ goto sqrt_invalid;
+
+ vfp_double_dump("sqrt", &vdm);
+
+ /*
+ * Estimate the square root.
+ */
+ vdd.sign = 0;
+ vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
+ vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
+
+ vfp_double_dump("sqrt estimate1", &vdd);
+
+ vdm.significand >>= 1 + (vdm.exponent & 1);
+ vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
+
+ vfp_double_dump("sqrt estimate2", &vdd);
+
+ /*
+ * And now adjust.
+ */
+ if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
+ if (vdd.significand < 2) {
+ vdd.significand = ~0ULL;
+ } else {
+ u64 termh, terml, remh, reml;
+ vdm.significand <<= 2;
+ mul64to128(&termh, &terml, vdd.significand, vdd.significand);
+ sub128(&remh, &reml, vdm.significand, 0, termh, terml);
+ while ((s64)remh < 0) {
+ vdd.significand -= 1;
+ shift64left(&termh, &terml, vdd.significand);
+ terml |= 1;
+ add128(&remh, &reml, remh, reml, termh, terml);
+ }
+ vdd.significand |= (remh | reml) != 0;
+ }
+ }
+ vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
+
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt");
+}
+
+/*
+ * Equal := ZC
+ * Less than := N
+ * Greater than := C
+ * Unordered := CV
+ */
+static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr)
+{
+ s64 d, m;
+ u32 ret = 0;
+
+ pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr);
+ m = vfp_get_double(state, dm);
+ if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
+ ret |= FPSCR_C | FPSCR_V;
+ if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
+ /*
+ * Signalling NaN, or signalling on quiet NaN
+ */
+ ret |= FPSCR_IOC;
+ }
+
+ d = vfp_get_double(state, dd);
+ if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
+ ret |= FPSCR_C | FPSCR_V;
+ if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
+ /*
+ * Signalling NaN, or signalling on quiet NaN
+ */
+ ret |= FPSCR_IOC;
+ }
+
+ if (ret == 0) {
+ //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
+ if (d == m || vfp_double_packed_abs(d | m) == 0) {
+ /*
+ * equal
+ */
+ ret |= FPSCR_Z | FPSCR_C;
+ //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
+ } else if (vfp_double_packed_sign(d ^ m)) {
+ /*
+ * different signs
+ */
+ if (vfp_double_packed_sign(d))
+ /*
+ * d is negative, so d < m
+ */
+ ret |= FPSCR_N;
+ else
+ /*
+ * d is positive, so d > m
+ */
+ ret |= FPSCR_C;
+ } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
+ /*
+ * d < m
+ */
+ ret |= FPSCR_N;
+ } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
+ /*
+ * d > m
+ */
+ ret |= FPSCR_C;
+ }
+ }
+ pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret);
+
+ return ret;
+}
+
+static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_compare(state, dd, 0, dm, fpscr);
+}
+
+static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_compare(state, dd, 1, dm, fpscr);
+}
+
+static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr);
+}
+
+static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
+}
+
+u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr) //ichfly for internal use only
+{
+ struct vfp_single vsd;
+ int tm;
+ u32 exceptions = 0;
+
+ pr_debug("In %s\n", __FUNCTION__);
+
+ tm = vfp_double_type(dm);
+
+ /*
+ * If we have a signalling NaN, signal invalid operation.
+ */
+ if (tm == VFP_SNAN)
+ exceptions = FPSCR_IOC;
+
+ if (tm & VFP_DENORMAL)
+ vfp_double_normalise_denormal(dm);
+
+ vsd.sign = dm->sign;
+ vsd.significand = vfp_hi64to32jamming(dm->significand);
+
+ /*
+ * If we have an infinity or a NaN, the exponent must be 255
+ */
+ if (tm & (VFP_INFINITY | VFP_NAN)) {
+ vsd.exponent = 255;
+ if (tm == VFP_QNAN)
+ vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
+ goto pack_nan;
+ }
+ else if (tm & VFP_ZERO)
+ vsd.exponent = 0;
+ else
+ vsd.exponent = dm->exponent - (1023 - 127);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
+
+pack_nan:
+ vfp_put_float(state, vfp_single_pack(&vsd), sd);
+ return exceptions;
+}
+
+static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
+{
+ struct vfp_double vdm;
+ struct vfp_single vsd;
+ int tm;
+ u32 exceptions = 0;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+
+ tm = vfp_double_type(&vdm);
+
+ /*
+ * If we have a signalling NaN, signal invalid operation.
+ */
+ if (tm == VFP_SNAN)
+ exceptions = FPSCR_IOC;
+
+ if (tm & VFP_DENORMAL)
+ vfp_double_normalise_denormal(&vdm);
+
+ vsd.sign = vdm.sign;
+ vsd.significand = vfp_hi64to32jamming(vdm.significand);
+
+ /*
+ * If we have an infinity or a NaN, the exponent must be 255
+ */
+ if (tm & (VFP_INFINITY|VFP_NAN)) {
+ vsd.exponent = 255;
+ if (tm == VFP_QNAN)
+ vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
+ goto pack_nan;
+ } else if (tm & VFP_ZERO)
+ vsd.exponent = 0;
+ else
+ vsd.exponent = vdm.exponent - (1023 - 127);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
+
+pack_nan:
+ vfp_put_float(state, vfp_single_pack(&vsd), sd);
+ return exceptions;
+}
+
+static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ struct vfp_double vdm;
+ u32 m = vfp_get_float(state, dm);
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vdm.sign = 0;
+ vdm.exponent = 1023 + 63 - 1;
+ vdm.significand = (u64)m;
+
+ return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito");
+}
+
+static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ struct vfp_double vdm;
+ u32 m = vfp_get_float(state, dm);
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vdm.sign = (m & 0x80000000) >> 16;
+ vdm.exponent = 1023 + 63 - 1;
+ vdm.significand = vdm.sign ? -m : m;
+
+ return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito");
+}
+
+static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
+{
+ struct vfp_double vdm;
+ u32 d, exceptions = 0;
+ int rmode = fpscr & FPSCR_RMODE_MASK;
+ int tm;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+
+ /*
+ * Do we have a denormalised number?
+ */
+ tm = vfp_double_type(&vdm);
+ if (tm & VFP_DENORMAL)
+ exceptions |= FPSCR_IDC;
+
+ if (tm & VFP_NAN)
+ vdm.sign = 0;
+
+ if (vdm.exponent >= 1023 + 32) {
+ d = vdm.sign ? 0 : 0xffffffff;
+ exceptions = FPSCR_IOC;
+ } else if (vdm.exponent >= 1023 - 1) {
+ int shift = 1023 + 63 - vdm.exponent;
+ u64 rem, incr = 0;
+
+ /*
+ * 2^0 <= m < 2^32-2^8
+ */
+ d = (ARMword)((vdm.significand << 1) >> shift);
+ rem = vdm.significand << (65 - shift);
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 0x8000000000000000ULL;
+ if ((d & 1) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
+ incr = ~0ULL;
+ }
+
+ if ((rem + incr) < rem) {
+ if (d < 0xffffffff)
+ d += 1;
+ else
+ exceptions |= FPSCR_IOC;
+ }
+
+ if (d && vdm.sign) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ } else if (rem)
+ exceptions |= FPSCR_IXC;
+ } else {
+ d = 0;
+ if (vdm.exponent | vdm.significand) {
+ exceptions |= FPSCR_IXC;
+ if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
+ d = 1;
+ else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ }
+ }
+ }
+
+ pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+
+ vfp_put_float(state, d, sd);
+
+ return exceptions;
+}
+
+static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO);
+}
+
+static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
+{
+ struct vfp_double vdm;
+ u32 d, exceptions = 0;
+ int rmode = fpscr & FPSCR_RMODE_MASK;
+ int tm;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_dump("VDM", &vdm);
+
+ /*
+ * Do we have denormalised number?
+ */
+ tm = vfp_double_type(&vdm);
+ if (tm & VFP_DENORMAL)
+ exceptions |= FPSCR_IDC;
+
+ if (tm & VFP_NAN) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ } else if (vdm.exponent >= 1023 + 32) {
+ d = 0x7fffffff;
+ if (vdm.sign)
+ d = ~d;
+ exceptions |= FPSCR_IOC;
+ } else if (vdm.exponent >= 1023 - 1) {
+ int shift = 1023 + 63 - vdm.exponent; /* 58 */
+ u64 rem, incr = 0;
+
+ d = (ARMword)((vdm.significand << 1) >> shift);
+ rem = vdm.significand << (65 - shift);
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 0x8000000000000000ULL;
+ if ((d & 1) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
+ incr = ~0ULL;
+ }
+
+ if ((rem + incr) < rem && d < 0xffffffff)
+ d += 1;
+ if (d > (0x7fffffff + (vdm.sign != 0))) {
+ d = (0x7fffffff + (vdm.sign != 0));
+ exceptions |= FPSCR_IOC;
+ } else if (rem)
+ exceptions |= FPSCR_IXC;
+
+ if (vdm.sign)
+ d = -d;
+ } else {
+ d = 0;
+ if (vdm.exponent | vdm.significand) {
+ exceptions |= FPSCR_IXC;
+ if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
+ d = 1;
+ else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
+ d = -1;
+ }
+ }
+
+ pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+
+ vfp_put_float(state, (s32)d, sd);
+
+ return exceptions;
+}
+
+static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO);
+}
+
+static struct op fops_ext[] = {
+ { vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY
+ { vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS
+ { vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG
+ { vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
+ { vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
+ { vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
+ { vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
+ { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
+ { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
+ { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
+ { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
+ { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
+};
+
+
+
+
+static u32
+vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
+ struct vfp_double *vdm, u32 fpscr)
+{
+ struct vfp_double *vdp;
+ u32 exceptions = 0;
+ int tn, tm;
+
+ tn = vfp_double_type(vdn);
+ tm = vfp_double_type(vdm);
+
+ if (tn & tm & VFP_INFINITY) {
+ /*
+ * Two infinities. Are they different signs?
+ */
+ if (vdn->sign ^ vdm->sign) {
+ /*
+ * different signs -> invalid
+ */
+ exceptions = FPSCR_IOC;
+ vdp = &vfp_double_default_qnan;
+ } else {
+ /*
+ * same signs -> valid
+ */
+ vdp = vdn;
+ }
+ } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
+ /*
+ * One infinity and one number -> infinity
+ */
+ vdp = vdn;
+ } else {
+ /*
+ * 'n' is a NaN of some type
+ */
+ return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
+ }
+ *vdd = *vdp;
+ return exceptions;
+}
+
+u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_double *vdm, u32 fpscr)
+{
+ u32 exp_diff;
+ u64 m_sig;
+
+ if (vdn->significand & (1ULL << 63) ||
+ vdm->significand & (1ULL << 63)) {
+ pr_info("VFP: bad FP values in %s\n", __func__);
+ vfp_double_dump("VDN", vdn);
+ vfp_double_dump("VDM", vdm);
+ }
+
+ /*
+ * Ensure that 'n' is the largest magnitude number. Note that
+ * if 'n' and 'm' have equal exponents, we do not swap them.
+ * This ensures that NaN propagation works correctly.
+ */
+ if (vdn->exponent < vdm->exponent) {
+ struct vfp_double *t = vdn;
+ vdn = vdm;
+ vdm = t;
+ }
+
+ /*
+ * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
+ * infinity or a NaN here.
+ */
+ if (vdn->exponent == 2047)
+ return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
+
+ /*
+ * We have two proper numbers, where 'vdn' is the larger magnitude.
+ *
+ * Copy 'n' to 'd' before doing the arithmetic.
+ */
+ *vdd = *vdn;
+
+ /*
+ * Align 'm' with the result.
+ */
+ exp_diff = vdn->exponent - vdm->exponent;
+ m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
+
+ /*
+ * If the signs are different, we are really subtracting.
+ */
+ if (vdn->sign ^ vdm->sign) {
+ m_sig = vdn->significand - m_sig;
+ if ((s64)m_sig < 0) {
+ vdd->sign = vfp_sign_negate(vdd->sign);
+ m_sig = -m_sig;
+ } else if (m_sig == 0) {
+ vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
+ FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
+ }
+ } else {
+ m_sig += vdn->significand;
+ }
+ vdd->significand = m_sig;
+
+ return 0;
+}
+
+u32
+vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
+ struct vfp_double *vdm, u32 fpscr)
+{
+ vfp_double_dump("VDN", vdn);
+ vfp_double_dump("VDM", vdm);
+
+ /*
+ * Ensure that 'n' is the largest magnitude number. Note that
+ * if 'n' and 'm' have equal exponents, we do not swap them.
+ * This ensures that NaN propagation works correctly.
+ */
+ if (vdn->exponent < vdm->exponent) {
+ struct vfp_double *t = vdn;
+ vdn = vdm;
+ vdm = t;
+ pr_debug("VFP: swapping M <-> N\n");
+ }
+
+ vdd->sign = vdn->sign ^ vdm->sign;
+
+ /*
+ * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
+ */
+ if (vdn->exponent == 2047) {
+ if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
+ return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
+ if ((vdm->exponent | vdm->significand) == 0) {
+ *vdd = vfp_double_default_qnan;
+ return FPSCR_IOC;
+ }
+ vdd->exponent = vdn->exponent;
+ vdd->significand = 0;
+ return 0;
+ }
+
+ /*
+ * If 'm' is zero, the result is always zero. In this case,
+ * 'n' may be zero or a number, but it doesn't matter which.
+ */
+ if ((vdm->exponent | vdm->significand) == 0) {
+ vdd->exponent = 0;
+ vdd->significand = 0;
+ return 0;
+ }
+
+ /*
+ * We add 2 to the destination exponent for the same reason
+ * as the addition case - though this time we have +1 from
+ * each input operand.
+ */
+ vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
+ vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
+
+ vfp_double_dump("VDD", vdd);
+ return 0;
+}
+
+#define NEG_MULTIPLY (1 << 0)
+#define NEG_SUBTRACT (1 << 1)
+
+static u32
+vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, char *func)
+{
+ struct vfp_double vdd, vdp, vdn, vdm;
+ u32 exceptions;
+
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
+
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
+
+ exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
+ if (negate & NEG_MULTIPLY)
+ vdp.sign = vfp_sign_negate(vdp.sign);
+
+ vfp_double_unpack(&vdn, vfp_get_double(state, dd));
+ if (negate & NEG_SUBTRACT)
+ vdn.sign = vfp_sign_negate(vdn.sign);
+
+ exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
+
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func);
+}
+
+/*
+ * Standard operations
+ */
+
+/*
+ * sd = sd + (sn * sm)
+ */
+static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac");
+}
+
+/*
+ * sd = sd - (sn * sm)
+ */
+static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
+}
+
+/*
+ * sd = -sd + (sn * sm)
+ */
+static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
+}
+
+/*
+ * sd = -sd - (sn * sm)
+ */
+static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
+}
+
+/*
+ * sd = sn * sm
+ */
+static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
+
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
+
+ exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul");
+}
+
+/*
+ * sd = -(sn * sm)
+ */
+static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
+
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
+
+ exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
+ vdd.sign = vfp_sign_negate(vdd.sign);
+
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul");
+}
+
+/*
+ * sd = sn + sm
+ */
+static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
+
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
+
+ exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
+
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd");
+}
+
+/*
+ * sd = sn - sm
+ */
+static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
+
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
+
+ /*
+ * Subtraction is like addition, but with a negated operand.
+ */
+ vdm.sign = vfp_sign_negate(vdm.sign);
+
+ exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
+
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub");
+}
+
+/*
+ * sd = sn / sm
+ */
+static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
+{
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions = 0;
+ int tm, tn;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+
+ vdd.sign = vdn.sign ^ vdm.sign;
+
+ tn = vfp_double_type(&vdn);
+ tm = vfp_double_type(&vdm);
+
+ /*
+ * Is n a NAN?
+ */
+ if (tn & VFP_NAN)
+ goto vdn_nan;
+
+ /*
+ * Is m a NAN?
+ */
+ if (tm & VFP_NAN)
+ goto vdm_nan;
+
+ /*
+ * If n and m are infinity, the result is invalid
+ * If n and m are zero, the result is invalid
+ */
+ if (tm & tn & (VFP_INFINITY|VFP_ZERO))
+ goto invalid;
+
+ /*
+ * If n is infinity, the result is infinity
+ */
+ if (tn & VFP_INFINITY)
+ goto infinity;
+
+ /*
+ * If m is zero, raise div0 exceptions
+ */
+ if (tm & VFP_ZERO)
+ goto divzero;
+
+ /*
+ * If m is infinity, or n is zero, the result is zero
+ */
+ if (tm & VFP_INFINITY || tn & VFP_ZERO)
+ goto zero;
+
+ if (tn & VFP_DENORMAL)
+ vfp_double_normalise_denormal(&vdn);
+ if (tm & VFP_DENORMAL)
+ vfp_double_normalise_denormal(&vdm);
+
+ /*
+ * Ok, we have two numbers, we can perform division.
+ */
+ vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
+ vdm.significand <<= 1;
+ if (vdm.significand <= (2 * vdn.significand)) {
+ vdn.significand >>= 1;
+ vdd.exponent++;
+ }
+ vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
+ if ((vdd.significand & 0x1ff) <= 2) {
+ u64 termh, terml, remh, reml;
+ mul64to128(&termh, &terml, vdm.significand, vdd.significand);
+ sub128(&remh, &reml, vdn.significand, 0, termh, terml);
+ while ((s64)remh < 0) {
+ vdd.significand -= 1;
+ add128(&remh, &reml, remh, reml, 0, vdm.significand);
+ }
+ vdd.significand |= (reml != 0);
+ }
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
+
+vdn_nan:
+ exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
+pack:
+ vfp_put_double(state, vfp_double_pack(&vdd), dd);
+ return exceptions;
+
+vdm_nan:
+ exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
+ goto pack;
+
+zero:
+ vdd.exponent = 0;
+ vdd.significand = 0;
+ goto pack;
+
+divzero:
+ exceptions = FPSCR_DZC;
+infinity:
+ vdd.exponent = 2047;
+ vdd.significand = 0;
+ goto pack;
+
+invalid:
+ vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
+ return FPSCR_IOC;
+}
+
+static struct op fops[] = {
+ { vfp_double_fmac, 0 },
+ { vfp_double_fmsc, 0 },
+ { vfp_double_fmul, 0 },
+ { vfp_double_fadd, 0 },
+ { vfp_double_fnmac, 0 },
+ { vfp_double_fnmsc, 0 },
+ { vfp_double_fnmul, 0 },
+ { vfp_double_fsub, 0 },
+ { vfp_double_fdiv, 0 },
+};
+
+#define FREG_BANK(x) ((x) & 0x0c)
+#define FREG_IDX(x) ((x) & 3)
+
+u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
+{
+ u32 op = inst & FOP_MASK;
+ u32 exceptions = 0;
+ unsigned int dest;
+ unsigned int dn = vfp_get_dn(inst);
+ unsigned int dm;
+ unsigned int vecitr, veclen, vecstride;
+ struct op *fop;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
+
+ fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
+
+ /*
+ * fcvtds takes an sN register number as destination, not dN.
+ * It also always operates on scalars.
+ */
+ if (fop->flags & OP_SD)
+ dest = vfp_get_sd(inst);
+ else
+ dest = vfp_get_dd(inst);
+
+ /*
+ * f[us]ito takes a sN operand, not a dN operand.
+ */
+ if (fop->flags & OP_SM)
+ dm = vfp_get_sm(inst);
+ else
+ dm = vfp_get_dm(inst);
+
+ /*
+ * If destination bank is zero, vector length is always '1'.
+ * ARM DDI0100F C5.1.3, C5.3.2.
+ */
+ if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
+ veclen = 0;
+ else
+ veclen = fpscr & FPSCR_LENGTH_MASK;
+
+ pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
+ (veclen >> FPSCR_LENGTH_BIT) + 1);
+
+ if (!fop->fn) {
+ printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst));
+ goto invalid;
+ }
+
+ for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
+ u32 except;
+ char type;
+
+ type = fop->flags & OP_SD ? 's' : 'd';
+ if (op == FOP_EXT)
+ pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
+ vecitr >> FPSCR_LENGTH_BIT,
+ type, dest, dn, dm);
+ else
+ pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
+ vecitr >> FPSCR_LENGTH_BIT,
+ type, dest, dn, FOP_TO_IDX(op), dm);
+
+ except = fop->fn(state, dest, dn, dm, fpscr);
+ pr_debug("VFP: itr%d: exceptions=%08x\n",
+ vecitr >> FPSCR_LENGTH_BIT, except);
+
+ exceptions |= except;
+
+ /*
+ * CHECK: It appears to be undefined whether we stop when
+ * we encounter an exception. We continue.
+ */
+ dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
+ dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
+ if (FREG_BANK(dm) != 0)
+ dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
+ }
+ return exceptions;
+
+invalid:
+ return ~0;
+}
diff --git a/src/core/arm/interpreter/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index a57047911..45208fb13 100644
--- a/src/core/arm/interpreter/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -3709,7 +3709,7 @@ VFPLABEL_INST:
{
fault = check_address_validity(cpu, addr, &phys_addr, 0);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d], 32);
+ fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d, cpu->ExtReg[inst_cream->d]);
}
@@ -3719,13 +3719,13 @@ VFPLABEL_INST:
if (fault) goto MMU_EXCEPTION;
/* Check endianness */
- fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d*2], 32);
+ fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d*2], 32);
if (fault) goto MMU_EXCEPTION;
fault = check_address_validity(cpu, addr + 4, &phys_addr, 0);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[inst_cream->d*2+1], 32);
+ fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[inst_cream->d*2+1], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, inst_cream->d*2+1, inst_cream->d*2, cpu->ExtReg[inst_cream->d*2+1], cpu->ExtReg[inst_cream->d*2]);
}
@@ -3926,7 +3926,7 @@ VFPLABEL_INST:
{
fault = check_address_validity(cpu, addr, &phys_addr, 0);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
+ fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]);
addr += 4;
@@ -3936,12 +3936,12 @@ VFPLABEL_INST:
/* Careful of endianness, little by default */
fault = check_address_validity(cpu, addr, &phys_addr, 0);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
+ fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
if (fault) goto MMU_EXCEPTION;
fault = check_address_validity(cpu, addr + 4, &phys_addr, 0);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
+ fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]);
addr += 8;
@@ -4048,7 +4048,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
{
if (single)
{
- //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
+ //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
#if 0
phys_addr = get_phys_addr(cpu, bb, Addr, 0);
bb = cpu->dyncom_engine->bb;
@@ -4166,7 +4166,7 @@ VFPLABEL_INST: /* encoding 1 */
fault = check_address_validity(cpu, addr, &phys_addr, 0);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
+ fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]);
addr += 4;
@@ -4177,13 +4177,13 @@ VFPLABEL_INST: /* encoding 1 */
fault = check_address_validity(cpu, addr, &phys_addr, 0);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
+ fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
if (fault) goto MMU_EXCEPTION;
fault = check_address_validity(cpu, addr + 4, &phys_addr, 0);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
+ fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]);
addr += 8;
@@ -4304,7 +4304,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
if (single)
{
- //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
+ //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
/* if R(i) is R15? */
#if 0
phys_addr = get_phys_addr(cpu, bb, Addr, 0);
@@ -4321,7 +4321,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
else
{
- //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
+ //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
#if 0
phys_addr = get_phys_addr(cpu, bb, Addr, 0);
bb = cpu->dyncom_engine->bb;
@@ -4332,7 +4332,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
bb = cpu->dyncom_engine->bb;
//if (fault) goto MMU_EXCEPTION;
- //fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
+ //fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
#if 0
phys_addr = get_phys_addr(cpu, bb, ADD(Addr, CONST(4)), 0);
bb = cpu->dyncom_engine->bb;
@@ -4431,7 +4431,7 @@ VFPLABEL_INST:
fault = check_address_validity(cpu, addr, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr, phys_addr, value1, 32);
+ fault = interpreter_read_memory(addr, phys_addr, value1, 32);
if (fault) goto MMU_EXCEPTION;
DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, value1, addr);
cpu->ExtReg[inst_cream->d+i] = value1;
@@ -4443,13 +4443,13 @@ VFPLABEL_INST:
fault = check_address_validity(cpu, addr, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr, phys_addr, value1, 32);
+ fault = interpreter_read_memory(addr, phys_addr, value1, 32);
if (fault) goto MMU_EXCEPTION;
fault = check_address_validity(cpu, addr + 4, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr + 4, phys_addr, value2, 32);
+ fault = interpreter_read_memory(addr + 4, phys_addr, value2, 32);
if (fault) goto MMU_EXCEPTION;
DBG("\ts[%d-%d] <= [%x-%x] addr[%x-%x]\n", (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, value2, value1, addr+4, addr);
cpu->ExtReg[(inst_cream->d+i)*2] = value1;
@@ -4682,7 +4682,7 @@ VFPLABEL_INST:
{
fault = check_address_validity(cpu, addr, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d], 32);
+ fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d, cpu->ExtReg[inst_cream->d], addr);
}
@@ -4691,12 +4691,12 @@ VFPLABEL_INST:
unsigned int word1, word2;
fault = check_address_validity(cpu, addr, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr, phys_addr, word1, 32);
+ fault = interpreter_read_memory(addr, phys_addr, word1, 32);
if (fault) goto MMU_EXCEPTION;
fault = check_address_validity(cpu, addr + 4, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr + 4, phys_addr, word2, 32);
+ fault = interpreter_read_memory(addr + 4, phys_addr, word2, 32);
if (fault) goto MMU_EXCEPTION;
/* Check endianness */
cpu->ExtReg[inst_cream->d*2] = word1;
@@ -4923,7 +4923,7 @@ VFPLABEL_INST:
{
fault = check_address_validity(cpu, addr, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
+ fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, cpu->ExtReg[inst_cream->d+i], addr);
addr += 4;
@@ -4933,12 +4933,12 @@ VFPLABEL_INST:
/* Careful of endianness, little by default */
fault = check_address_validity(cpu, addr, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
+ fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
if (fault) goto MMU_EXCEPTION;
fault = check_address_validity(cpu, addr + 4, &phys_addr, 1);
if (fault) goto MMU_EXCEPTION;
- fault = interpreter_read_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
+ fault = interpreter_read_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
if (fault) goto MMU_EXCEPTION;
DBG("\ts[%d-%d] <= [%x-%x] addr[%x-%x]\n", (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2], addr+4, addr);
addr += 8;
@@ -5058,7 +5058,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
if (single)
{
- //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
+ //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
/* if R(i) is R15? */
#if 0
phys_addr = get_phys_addr(cpu, bb, Addr, 1);
@@ -5095,7 +5095,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb);
LETFPS((d + i) * 2 + 1, FPBITCAST32(val));
- //fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
+ //fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
//DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]);
//addr += 8;
Addr = ADD(Addr, CONST(8));
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
new file mode 100644
index 000000000..07d0c1f44
--- /dev/null
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -0,0 +1,1356 @@
+/*
+ vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction
+ Copyright (C) 2003 Skyeye Develop Group
+ for help please send mail to <skyeye-developer@lists.gro.clinux.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ * This code is derived in part from :
+ * - Android kernel
+ * - John R. Housers softfloat library, which
+ * carries the following notice:
+ *
+ * ===========================================================================
+ * This C source file is part of the SoftFloat IEC/IEEE Floating-point
+ * Arithmetic Package, Release 2.
+ *
+ * Written by John R. Hauser. This work was made possible in part by the
+ * International Computer Science Institute, located at Suite 600, 1947 Center
+ * Street, Berkeley, California 94704. Funding was partially provided by the
+ * National Science Foundation under grant MIP-9311980. The original version
+ * of this code was written as part of a project to build a fixed-point vector
+ * processor in collaboration with the University of California at Berkeley,
+ * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+ * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+ * arithmetic/softfloat.html'.
+ *
+ * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+ * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+ * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+ * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+ * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+ *
+ * Derivative works are acceptable, even for commercial purposes, so long as
+ * (1) they include prominent notice that the work is derivative, and (2) they
+ * include prominent notice akin to these three paragraphs for those parts of
+ * this code that are retained.
+ * ===========================================================================
+ */
+
+#include "core/arm/skyeye_common/vfp/vfp_helper.h"
+#include "core/arm/skyeye_common/vfp/asm_vfp.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
+
+static struct vfp_single vfp_single_default_qnan = {
+ 255,
+ 0,
+ VFP_SINGLE_SIGNIFICAND_QNAN,
+};
+
+static void vfp_single_dump(const char *str, struct vfp_single *s)
+{
+ pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
+ str, s->sign != 0, s->exponent, s->significand);
+}
+
+static void vfp_single_normalise_denormal(struct vfp_single *vs)
+{
+ int bits = 31 - fls(vs->significand);
+
+ vfp_single_dump("normalise_denormal: in", vs);
+
+ if (bits) {
+ vs->exponent -= bits - 1;
+ vs->significand <<= bits;
+ }
+
+ vfp_single_dump("normalise_denormal: out", vs);
+}
+
+
+u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func)
+{
+ u32 significand, incr, rmode;
+ int exponent, shift, underflow;
+
+ vfp_single_dump("pack: in", vs);
+
+ /*
+ * Infinities and NaNs are a special case.
+ */
+ if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
+ goto pack;
+
+ /*
+ * Special-case zero.
+ */
+ if (vs->significand == 0) {
+ vs->exponent = 0;
+ goto pack;
+ }
+
+ exponent = vs->exponent;
+ significand = vs->significand;
+
+ /*
+ * Normalise first. Note that we shift the significand up to
+ * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
+ * significant bit.
+ */
+ shift = 32 - fls(significand);
+ if (shift < 32 && shift) {
+ exponent -= shift;
+ significand <<= shift;
+ }
+
+#if 1
+ vs->exponent = exponent;
+ vs->significand = significand;
+ vfp_single_dump("pack: normalised", vs);
+#endif
+
+ /*
+ * Tiny number?
+ */
+ underflow = exponent < 0;
+ if (underflow) {
+ significand = vfp_shiftright32jamming(significand, -exponent);
+ exponent = 0;
+#if 1
+ vs->exponent = exponent;
+ vs->significand = significand;
+ vfp_single_dump("pack: tiny number", vs);
+#endif
+ if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
+ underflow = 0;
+ }
+
+ /*
+ * Select rounding increment.
+ */
+ incr = 0;
+ rmode = fpscr & FPSCR_RMODE_MASK;
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 1 << VFP_SINGLE_LOW_BITS;
+ if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
+ incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
+
+ pr_debug("VFP: rounding increment = 0x%08x\n", incr);
+
+ /*
+ * Is our rounding going to overflow?
+ */
+ if ((significand + incr) < significand) {
+ exponent += 1;
+ significand = (significand >> 1) | (significand & 1);
+ incr >>= 1;
+#if 1
+ vs->exponent = exponent;
+ vs->significand = significand;
+ vfp_single_dump("pack: overflow", vs);
+#endif
+ }
+
+ /*
+ * If any of the low bits (which will be shifted out of the
+ * number) are non-zero, the result is inexact.
+ */
+ if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
+ exceptions |= FPSCR_IXC;
+
+ /*
+ * Do our rounding.
+ */
+ significand += incr;
+
+ /*
+ * Infinity?
+ */
+ if (exponent >= 254) {
+ exceptions |= FPSCR_OFC | FPSCR_IXC;
+ if (incr == 0) {
+ vs->exponent = 253;
+ vs->significand = 0x7fffffff;
+ } else {
+ vs->exponent = 255; /* infinity */
+ vs->significand = 0;
+ }
+ } else {
+ if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
+ exponent = 0;
+ if (exponent || significand > 0x80000000)
+ underflow = 0;
+ if (underflow)
+ exceptions |= FPSCR_UFC;
+ vs->exponent = exponent;
+ vs->significand = significand >> 1;
+ }
+
+pack:
+ vfp_single_dump("pack: final", vs);
+ {
+ s32 d = vfp_single_pack(vs);
+#if 1
+ pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
+ sd, d, exceptions);
+#endif
+ vfp_put_float(state, d, sd);
+ }
+
+ return exceptions;
+}
+
+/*
+ * Propagate the NaN, setting exceptions if it is signalling.
+ * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
+ */
+static u32
+vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
+ struct vfp_single *vsm, u32 fpscr)
+{
+ struct vfp_single *nan;
+ int tn, tm = 0;
+
+ tn = vfp_single_type(vsn);
+
+ if (vsm)
+ tm = vfp_single_type(vsm);
+
+ if (fpscr & FPSCR_DEFAULT_NAN)
+ /*
+ * Default NaN mode - always returns a quiet NaN
+ */
+ nan = &vfp_single_default_qnan;
+ else {
+ /*
+ * Contemporary mode - select the first signalling
+ * NAN, or if neither are signalling, the first
+ * quiet NAN.
+ */
+ if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
+ nan = vsn;
+ else
+ nan = vsm;
+ /*
+ * Make the NaN quiet.
+ */
+ nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
+ }
+
+ *vsd = *nan;
+
+ /*
+ * If one was a signalling NAN, raise invalid operation.
+ */
+ return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
+}
+
+
+/*
+ * Extended operations
+ */
+static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ vfp_put_float(state, vfp_single_packed_abs(m), sd);
+ return 0;
+}
+
+static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ vfp_put_float(state, m, sd);
+ return 0;
+}
+
+static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ vfp_put_float(state, vfp_single_packed_negate(m), sd);
+ return 0;
+}
+
+static const u16 sqrt_oddadjust[] = {
+ 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
+ 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
+};
+
+static const u16 sqrt_evenadjust[] = {
+ 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
+ 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
+};
+
+u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
+{
+ int index;
+ u32 z, a;
+
+ if ((significand & 0xc0000000) != 0x40000000) {
+ pr_debug("VFP: estimate_sqrt: invalid significand\n");
+ }
+
+ a = significand << 1;
+ index = (a >> 27) & 15;
+ if (exponent & 1) {
+ z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
+ z = ((a / z) << 14) + (z << 15);
+ a >>= 1;
+ } else {
+ z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
+ z = a / z + z;
+ z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
+ if (z <= a)
+ return (s32)a >> 1;
+ }
+ {
+ u64 v = (u64)a << 31;
+ do_div(v, z);
+ return (u32)(v + (z >> 1));
+ }
+}
+
+static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ struct vfp_single vsm, vsd, *vsp;
+ int ret, tm;
+
+ vfp_single_unpack(&vsm, m);
+ tm = vfp_single_type(&vsm);
+ if (tm & (VFP_NAN|VFP_INFINITY)) {
+ vsp = &vsd;
+
+ if (tm & VFP_NAN)
+ ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
+ else if (vsm.sign == 0) {
+sqrt_copy:
+ vsp = &vsm;
+ ret = 0;
+ } else {
+sqrt_invalid:
+ vsp = &vfp_single_default_qnan;
+ ret = FPSCR_IOC;
+ }
+ vfp_put_float(state, vfp_single_pack(vsp), sd);
+ return ret;
+ }
+
+ /*
+ * sqrt(+/- 0) == +/- 0
+ */
+ if (tm & VFP_ZERO)
+ goto sqrt_copy;
+
+ /*
+ * Normalise a denormalised number
+ */
+ if (tm & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsm);
+
+ /*
+ * sqrt(<0) = invalid
+ */
+ if (vsm.sign)
+ goto sqrt_invalid;
+
+ vfp_single_dump("sqrt", &vsm);
+
+ /*
+ * Estimate the square root.
+ */
+ vsd.sign = 0;
+ vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
+ vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
+
+ vfp_single_dump("sqrt estimate", &vsd);
+
+ /*
+ * And now adjust.
+ */
+ if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
+ if (vsd.significand < 2) {
+ vsd.significand = 0xffffffff;
+ } else {
+ u64 term;
+ s64 rem;
+ vsm.significand <<= !(vsm.exponent & 1);
+ term = (u64)vsd.significand * vsd.significand;
+ rem = ((u64)vsm.significand << 32) - term;
+
+ pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
+
+ while (rem < 0) {
+ vsd.significand -= 1;
+ rem += ((u64)vsd.significand << 1) | 1;
+ }
+ vsd.significand |= rem != 0;
+ }
+ }
+ vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt");
+}
+
+/*
+ * Equal := ZC
+ * Less than := N
+ * Greater than := C
+ * Unordered := CV
+ */
+static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr)
+{
+ s32 d;
+ u32 ret = 0;
+
+ d = vfp_get_float(state, sd);
+ if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
+ ret |= FPSCR_C | FPSCR_V;
+ if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
+ /*
+ * Signalling NaN, or signalling on quiet NaN
+ */
+ ret |= FPSCR_IOC;
+ }
+
+ if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
+ ret |= FPSCR_C | FPSCR_V;
+ if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
+ /*
+ * Signalling NaN, or signalling on quiet NaN
+ */
+ ret |= FPSCR_IOC;
+ }
+
+ if (ret == 0) {
+ if (d == m || vfp_single_packed_abs(d | m) == 0) {
+ /*
+ * equal
+ */
+ ret |= FPSCR_Z | FPSCR_C;
+ } else if (vfp_single_packed_sign(d ^ m)) {
+ /*
+ * different signs
+ */
+ if (vfp_single_packed_sign(d))
+ /*
+ * d is negative, so d < m
+ */
+ ret |= FPSCR_N;
+ else
+ /*
+ * d is positive, so d > m
+ */
+ ret |= FPSCR_C;
+ } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
+ /*
+ * d < m
+ */
+ ret |= FPSCR_N;
+ } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
+ /*
+ * d > m
+ */
+ ret |= FPSCR_C;
+ }
+ }
+ return ret;
+}
+
+static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ return vfp_compare(state, sd, 0, m, fpscr);
+}
+
+static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ return vfp_compare(state, sd, 1, m, fpscr);
+}
+
+static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ return vfp_compare(state, sd, 0, 0, fpscr);
+}
+
+static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ return vfp_compare(state, sd, 1, 0, fpscr);
+}
+
+static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ichfly for internal use only
+{
+ struct vfp_single vsm;
+ struct vfp_double vdd;
+ int tm;
+ u32 exceptions = 0;
+
+ vfp_single_unpack(&vsm, m);
+
+ tm = vfp_single_type(&vsm);
+
+ /*
+ * If we have a signalling NaN, signal invalid operation.
+ */
+ if (tm == VFP_SNAN)
+ exceptions = FPSCR_IOC;
+
+ if (tm & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsm);
+
+ vdd.sign = vsm.sign;
+ vdd.significand = (u64)vsm.significand << 32;
+
+ /*
+ * If we have an infinity or NaN, the exponent must be 2047.
+ */
+ if (tm & (VFP_INFINITY | VFP_NAN)) {
+ vdd.exponent = 2047;
+ if (tm == VFP_QNAN)
+ vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
+ goto pack_nan;
+ }
+ else if (tm & VFP_ZERO)
+ vdd.exponent = 0;
+ else
+ vdd.exponent = vsm.exponent + (1023 - 127);
+pack_nan:
+ vfp_double_normaliseroundintern(state, &vdd, fpscr, exceptions, "fcvtd");
+ return vfp_double_pack(&vdd);
+}
+
+static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr)
+{
+ struct vfp_single vsm;
+ struct vfp_double vdd;
+ int tm;
+ u32 exceptions = 0;
+
+ vfp_single_unpack(&vsm, m);
+
+ tm = vfp_single_type(&vsm);
+
+ /*
+ * If we have a signalling NaN, signal invalid operation.
+ */
+ if (tm == VFP_SNAN)
+ exceptions = FPSCR_IOC;
+
+ if (tm & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsm);
+
+ vdd.sign = vsm.sign;
+ vdd.significand = (u64)vsm.significand << 32;
+
+ /*
+ * If we have an infinity or NaN, the exponent must be 2047.
+ */
+ if (tm & (VFP_INFINITY|VFP_NAN)) {
+ vdd.exponent = 2047;
+ if (tm == VFP_QNAN)
+ vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
+ goto pack_nan;
+ } else if (tm & VFP_ZERO)
+ vdd.exponent = 0;
+ else
+ vdd.exponent = vsm.exponent + (1023 - 127);
+
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
+
+pack_nan:
+ vfp_put_double(state, vfp_double_pack(&vdd), dd);
+ return exceptions;
+}
+
+static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ struct vfp_single vs;
+
+ vs.sign = 0;
+ vs.exponent = 127 + 31 - 1;
+ vs.significand = (u32)m;
+
+ return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito");
+}
+
+static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ struct vfp_single vs;
+
+ vs.sign = (m & 0x80000000) >> 16;
+ vs.exponent = 127 + 31 - 1;
+ vs.significand = vs.sign ? -m : m;
+
+ return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito");
+}
+
+static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ struct vfp_single vsm;
+ u32 d, exceptions = 0;
+ int rmode = fpscr & FPSCR_RMODE_MASK;
+ int tm;
+
+ vfp_single_unpack(&vsm, m);
+ vfp_single_dump("VSM", &vsm);
+
+ /*
+ * Do we have a denormalised number?
+ */
+ tm = vfp_single_type(&vsm);
+ if (tm & VFP_DENORMAL)
+ exceptions |= FPSCR_IDC;
+
+ if (tm & VFP_NAN)
+ vsm.sign = 0;
+
+ if (vsm.exponent >= 127 + 32) {
+ d = vsm.sign ? 0 : 0xffffffff;
+ exceptions = FPSCR_IOC;
+ } else if (vsm.exponent >= 127 - 1) {
+ int shift = 127 + 31 - vsm.exponent;
+ u32 rem, incr = 0;
+
+ /*
+ * 2^0 <= m < 2^32-2^8
+ */
+ d = (vsm.significand << 1) >> shift;
+ rem = vsm.significand << (33 - shift);
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 0x80000000;
+ if ((d & 1) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
+ incr = ~0;
+ }
+
+ if ((rem + incr) < rem) {
+ if (d < 0xffffffff)
+ d += 1;
+ else
+ exceptions |= FPSCR_IOC;
+ }
+
+ if (d && vsm.sign) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ } else if (rem)
+ exceptions |= FPSCR_IXC;
+ } else {
+ d = 0;
+ if (vsm.exponent | vsm.significand) {
+ exceptions |= FPSCR_IXC;
+ if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
+ d = 1;
+ else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ }
+ }
+ }
+
+ pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+
+ vfp_put_float(state, d, sd);
+
+ return exceptions;
+}
+
+static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO);
+}
+
+static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ struct vfp_single vsm;
+ u32 d, exceptions = 0;
+ int rmode = fpscr & FPSCR_RMODE_MASK;
+ int tm;
+
+ vfp_single_unpack(&vsm, m);
+ vfp_single_dump("VSM", &vsm);
+
+ /*
+ * Do we have a denormalised number?
+ */
+ tm = vfp_single_type(&vsm);
+ if (vfp_single_type(&vsm) & VFP_DENORMAL)
+ exceptions |= FPSCR_IDC;
+
+ if (tm & VFP_NAN) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ } else if (vsm.exponent >= 127 + 32) {
+ /*
+ * m >= 2^31-2^7: invalid
+ */
+ d = 0x7fffffff;
+ if (vsm.sign)
+ d = ~d;
+ exceptions |= FPSCR_IOC;
+ } else if (vsm.exponent >= 127 - 1) {
+ int shift = 127 + 31 - vsm.exponent;
+ u32 rem, incr = 0;
+
+ /* 2^0 <= m <= 2^31-2^7 */
+ d = (vsm.significand << 1) >> shift;
+ rem = vsm.significand << (33 - shift);
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 0x80000000;
+ if ((d & 1) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
+ incr = ~0;
+ }
+
+ if ((rem + incr) < rem && d < 0xffffffff)
+ d += 1;
+ if (d > (0x7fffffffu + (vsm.sign != 0))) {
+ d = (0x7fffffffu + (vsm.sign != 0));
+ exceptions |= FPSCR_IOC;
+ } else if (rem)
+ exceptions |= FPSCR_IXC;
+
+ if (vsm.sign)
+ d = 0-d;
+ } else {
+ d = 0;
+ if (vsm.exponent | vsm.significand) {
+ exceptions |= FPSCR_IXC;
+ if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
+ d = 1;
+ else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign)
+ d = -1;
+ }
+ }
+
+ pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+
+ vfp_put_float(state, (s32)d, sd);
+
+ return exceptions;
+}
+
+static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
+{
+ return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO);
+}
+
+static struct op fops_ext[] = {
+ { vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY
+ { vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS
+ { vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG
+ { vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
+ { vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
+ { vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
+ { vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
+ { vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
+ { vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { NULL, 0 },
+ { vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
+ { vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
+ { vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
+ { vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
+};
+
+
+
+
+
+static u32
+vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
+ struct vfp_single *vsm, u32 fpscr)
+{
+ struct vfp_single *vsp;
+ u32 exceptions = 0;
+ int tn, tm;
+
+ tn = vfp_single_type(vsn);
+ tm = vfp_single_type(vsm);
+
+ if (tn & tm & VFP_INFINITY) {
+ /*
+ * Two infinities. Are they different signs?
+ */
+ if (vsn->sign ^ vsm->sign) {
+ /*
+ * different signs -> invalid
+ */
+ exceptions = FPSCR_IOC;
+ vsp = &vfp_single_default_qnan;
+ } else {
+ /*
+ * same signs -> valid
+ */
+ vsp = vsn;
+ }
+ } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
+ /*
+ * One infinity and one number -> infinity
+ */
+ vsp = vsn;
+ } else {
+ /*
+ * 'n' is a NaN of some type
+ */
+ return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
+ }
+ *vsd = *vsp;
+ return exceptions;
+}
+
+static u32
+vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
+ struct vfp_single *vsm, u32 fpscr)
+{
+ u32 exp_diff, m_sig;
+
+ if (vsn->significand & 0x80000000 ||
+ vsm->significand & 0x80000000) {
+ pr_info("VFP: bad FP values in %s\n", __func__);
+ vfp_single_dump("VSN", vsn);
+ vfp_single_dump("VSM", vsm);
+ }
+
+ /*
+ * Ensure that 'n' is the largest magnitude number. Note that
+ * if 'n' and 'm' have equal exponents, we do not swap them.
+ * This ensures that NaN propagation works correctly.
+ */
+ if (vsn->exponent < vsm->exponent) {
+ struct vfp_single *t = vsn;
+ vsn = vsm;
+ vsm = t;
+ }
+
+ /*
+ * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
+ * infinity or a NaN here.
+ */
+ if (vsn->exponent == 255)
+ return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
+
+ /*
+ * We have two proper numbers, where 'vsn' is the larger magnitude.
+ *
+ * Copy 'n' to 'd' before doing the arithmetic.
+ */
+ *vsd = *vsn;
+
+ /*
+ * Align both numbers.
+ */
+ exp_diff = vsn->exponent - vsm->exponent;
+ m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
+
+ /*
+ * If the signs are different, we are really subtracting.
+ */
+ if (vsn->sign ^ vsm->sign) {
+ m_sig = vsn->significand - m_sig;
+ if ((s32)m_sig < 0) {
+ vsd->sign = vfp_sign_negate(vsd->sign);
+ m_sig = 0-m_sig;
+ } else if (m_sig == 0) {
+ vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
+ FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
+ }
+ } else {
+ m_sig = vsn->significand + m_sig;
+ }
+ vsd->significand = m_sig;
+
+ return 0;
+}
+
+static u32
+vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
+{
+ vfp_single_dump("VSN", vsn);
+ vfp_single_dump("VSM", vsm);
+
+ /*
+ * Ensure that 'n' is the largest magnitude number. Note that
+ * if 'n' and 'm' have equal exponents, we do not swap them.
+ * This ensures that NaN propagation works correctly.
+ */
+ if (vsn->exponent < vsm->exponent) {
+ struct vfp_single *t = vsn;
+ vsn = vsm;
+ vsm = t;
+ pr_debug("VFP: swapping M <-> N\n");
+ }
+
+ vsd->sign = vsn->sign ^ vsm->sign;
+
+ /*
+ * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
+ */
+ if (vsn->exponent == 255) {
+ if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
+ return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
+ if ((vsm->exponent | vsm->significand) == 0) {
+ *vsd = vfp_single_default_qnan;
+ return FPSCR_IOC;
+ }
+ vsd->exponent = vsn->exponent;
+ vsd->significand = 0;
+ return 0;
+ }
+
+ /*
+ * If 'm' is zero, the result is always zero. In this case,
+ * 'n' may be zero or a number, but it doesn't matter which.
+ */
+ if ((vsm->exponent | vsm->significand) == 0) {
+ vsd->exponent = 0;
+ vsd->significand = 0;
+ return 0;
+ }
+
+ /*
+ * We add 2 to the destination exponent for the same reason as
+ * the addition case - though this time we have +1 from each
+ * input operand.
+ */
+ vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
+ vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
+
+ vfp_single_dump("VSD", vsd);
+ return 0;
+}
+
+#define NEG_MULTIPLY (1 << 0)
+#define NEG_SUBTRACT (1 << 1)
+
+static u32
+vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func)
+{
+
+ {
+ struct vfp_single vsd, vsp, vsn, vsm;
+ u32 exceptions;
+ s32 v;
+
+
+
+ v = vfp_get_float(state, sn);
+ pr_debug("VFP: s%u = %08x\n", sn, v);
+ vfp_single_unpack(&vsn, v);
+ if (vsn.exponent == 0 && vsn.significand)
+ vfp_single_normalise_denormal(&vsn);
+
+ vfp_single_unpack(&vsm, m);
+ if (vsm.exponent == 0 && vsm.significand)
+ vfp_single_normalise_denormal(&vsm);
+
+ exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
+
+ if (negate & NEG_MULTIPLY)
+ vsp.sign = vfp_sign_negate(vsp.sign);
+
+ v = vfp_get_float(state, sd);
+ pr_debug("VFP: s%u = %08x\n", sd, v);
+ vfp_single_unpack(&vsn, v);
+ if (negate & NEG_SUBTRACT)
+ vsn.sign = vfp_sign_negate(vsn.sign);
+
+ exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
+ }
+
+ struct vfp_double vsd, vsp, vsn, vsm;
+ u32 exceptions;
+ s32 v;
+ s64 vd;
+ s64 md;
+
+ v = vfp_get_float(state, sn);
+ vd = vfp_single_to_doubleintern(state, v, fpscr);
+ vfp_double_unpack(&vsn, vd);
+
+ md = vfp_single_to_doubleintern(state, m, fpscr);
+ vfp_double_unpack(&vsm, md);
+
+ exceptions = vfp_double_multiply(&vsp, &vsn, &vsm, fpscr);
+ if (negate & NEG_MULTIPLY)
+ vsp.sign = vfp_sign_negate(vsp.sign);
+
+ v = vfp_get_float(state, sd);
+ vd = vfp_single_to_doubleintern(state, v, fpscr);
+ vfp_double_unpack(&vsn, vd);
+
+ if (negate & NEG_SUBTRACT)
+ vsn.sign = vfp_sign_negate(vsn.sign);
+
+ exceptions |= vfp_double_add(&vsd, &vsn, &vsp, fpscr);
+
+ s64 debug = vfp_double_pack(&vsd);
+
+ return vfp_double_fcvtsinterncutting(state, sd, &vsd, fpscr);
+
+}
+
+/*
+ * Standard operations
+ */
+
+/*
+ * sd = sd + (sn * sm)
+ */
+static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
+}
+
+/*
+ * sd = sd - (sn * sm)
+ */
+static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn);
+ return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
+}
+
+/*
+ * sd = -sd + (sn * sm)
+ */
+static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
+}
+
+/*
+ * sd = -sd - (sn * sm)
+ */
+static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
+}
+
+/*
+ * sd = sn * sm
+ */
+static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ struct vfp_single vsd, vsn, vsm;
+ u32 exceptions;
+ s32 n = vfp_get_float(state, sn);
+
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n);
+
+ vfp_single_unpack(&vsn, n);
+ if (vsn.exponent == 0 && vsn.significand)
+ vfp_single_normalise_denormal(&vsn);
+
+ vfp_single_unpack(&vsm, m);
+ if (vsm.exponent == 0 && vsm.significand)
+ vfp_single_normalise_denormal(&vsm);
+
+ exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul");
+}
+
+/*
+ * sd = -(sn * sm)
+ */
+static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ struct vfp_single vsd, vsn, vsm;
+ u32 exceptions;
+ s32 n = vfp_get_float(state, sn);
+
+ pr_debug("VFP: s%u = %08x\n", sn, n);
+
+ vfp_single_unpack(&vsn, n);
+ if (vsn.exponent == 0 && vsn.significand)
+ vfp_single_normalise_denormal(&vsn);
+
+ vfp_single_unpack(&vsm, m);
+ if (vsm.exponent == 0 && vsm.significand)
+ vfp_single_normalise_denormal(&vsm);
+
+ exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
+ vsd.sign = vfp_sign_negate(vsd.sign);
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul");
+}
+
+/*
+ * sd = sn + sm
+ */
+static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ struct vfp_single vsd, vsn, vsm;
+ u32 exceptions;
+ s32 n = vfp_get_float(state, sn);
+
+ pr_debug("VFP: s%u = %08x\n", sn, n);
+
+ /*
+ * Unpack and normalise denormals.
+ */
+ vfp_single_unpack(&vsn, n);
+ if (vsn.exponent == 0 && vsn.significand)
+ vfp_single_normalise_denormal(&vsn);
+
+ vfp_single_unpack(&vsm, m);
+ if (vsm.exponent == 0 && vsm.significand)
+ vfp_single_normalise_denormal(&vsm);
+
+ exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd");
+}
+
+/*
+ * sd = sn - sm
+ */
+static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ /*
+ * Subtraction is addition with one sign inverted.
+ */
+ return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr);
+}
+
+/*
+ * sd = sn / sm
+ */
+static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
+{
+ struct vfp_single vsd, vsn, vsm;
+ u32 exceptions = 0;
+ s32 n = vfp_get_float(state, sn);
+ int tm, tn;
+
+ pr_debug("VFP: s%u = %08x\n", sn, n);
+
+ vfp_single_unpack(&vsn, n);
+ vfp_single_unpack(&vsm, m);
+
+ vsd.sign = vsn.sign ^ vsm.sign;
+
+ tn = vfp_single_type(&vsn);
+ tm = vfp_single_type(&vsm);
+
+ /*
+ * Is n a NAN?
+ */
+ if (tn & VFP_NAN)
+ goto vsn_nan;
+
+ /*
+ * Is m a NAN?
+ */
+ if (tm & VFP_NAN)
+ goto vsm_nan;
+
+ /*
+ * If n and m are infinity, the result is invalid
+ * If n and m are zero, the result is invalid
+ */
+ if (tm & tn & (VFP_INFINITY|VFP_ZERO))
+ goto invalid;
+
+ /*
+ * If n is infinity, the result is infinity
+ */
+ if (tn & VFP_INFINITY)
+ goto infinity;
+
+ /*
+ * If m is zero, raise div0 exception
+ */
+ if (tm & VFP_ZERO)
+ goto divzero;
+
+ /*
+ * If m is infinity, or n is zero, the result is zero
+ */
+ if (tm & VFP_INFINITY || tn & VFP_ZERO)
+ goto zero;
+
+ if (tn & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsn);
+ if (tm & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsm);
+
+ /*
+ * Ok, we have two numbers, we can perform division.
+ */
+ vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
+ vsm.significand <<= 1;
+ if (vsm.significand <= (2 * vsn.significand)) {
+ vsn.significand >>= 1;
+ vsd.exponent++;
+ }
+ {
+ u64 significand = (u64)vsn.significand << 32;
+ do_div(significand, vsm.significand);
+ vsd.significand = (u32)significand;
+ }
+ if ((vsd.significand & 0x3f) == 0)
+ vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
+
+vsn_nan:
+ exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
+pack:
+ vfp_put_float(state, vfp_single_pack(&vsd), sd);
+ return exceptions;
+
+vsm_nan:
+ exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
+ goto pack;
+
+zero:
+ vsd.exponent = 0;
+ vsd.significand = 0;
+ goto pack;
+
+divzero:
+ exceptions = FPSCR_DZC;
+infinity:
+ vsd.exponent = 255;
+ vsd.significand = 0;
+ goto pack;
+
+invalid:
+ vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
+ return FPSCR_IOC;
+}
+
+static struct op fops[] = {
+ { vfp_single_fmac, 0 },
+ { vfp_single_fmsc, 0 },
+ { vfp_single_fmul, 0 },
+ { vfp_single_fadd, 0 },
+ { vfp_single_fnmac, 0 },
+ { vfp_single_fnmsc, 0 },
+ { vfp_single_fnmul, 0 },
+ { vfp_single_fsub, 0 },
+ { vfp_single_fdiv, 0 },
+};
+
+#define FREG_BANK(x) ((x) & 0x18)
+#define FREG_IDX(x) ((x) & 7)
+
+u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
+{
+ u32 op = inst & FOP_MASK;
+ u32 exceptions = 0;
+ unsigned int dest;
+ unsigned int sn = vfp_get_sn(inst);
+ unsigned int sm = vfp_get_sm(inst);
+ unsigned int vecitr, veclen, vecstride;
+ struct op *fop;
+ pr_debug("In %s\n", __FUNCTION__);
+
+ vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
+
+ fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
+
+ /*
+ * fcvtsd takes a dN register number as destination, not sN.
+ * Technically, if bit 0 of dd is set, this is an invalid
+ * instruction. However, we ignore this for efficiency.
+ * It also only operates on scalars.
+ */
+ if (fop->flags & OP_DD)
+ dest = vfp_get_dd(inst);
+ else
+ dest = vfp_get_sd(inst);
+
+ /*
+ * If destination bank is zero, vector length is always '1'.
+ * ARM DDI0100F C5.1.3, C5.3.2.
+ */
+ if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
+ veclen = 0;
+ else
+ veclen = fpscr & FPSCR_LENGTH_MASK;
+
+ pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
+ (veclen >> FPSCR_LENGTH_BIT) + 1);
+
+ if (!fop->fn) {
+ printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]);
+ exit(-1);
+ goto invalid;
+ }
+
+ for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
+ s32 m = vfp_get_float(state, sm);
+ u32 except;
+ char type;
+
+ type = fop->flags & OP_DD ? 'd' : 's';
+ if (op == FOP_EXT)
+ pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ sm, m);
+ else
+ pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ FOP_TO_IDX(op), sm, m);
+
+ except = fop->fn(state, dest, sn, m, fpscr);
+ pr_debug("VFP: itr%d: exceptions=%08x\n",
+ vecitr >> FPSCR_LENGTH_BIT, except);
+
+ exceptions |= except;
+
+ /*
+ * CHECK: It appears to be undefined whether we stop when
+ * we encounter an exception. We continue.
+ */
+ dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
+ sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
+ if (FREG_BANK(sm) != 0)
+ sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
+ }
+ return exceptions;
+
+invalid:
+ return (u32)-1;
+}
diff --git a/src/core/core.cpp b/src/core/core.cpp
index f21801e52..25c78d33c 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -3,20 +3,16 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
-#include "common/log.h"
-#include "common/symbols.h"
-
-#include "video_core/video_core.h"
#include "core/core.h"
-#include "core/mem_map.h"
-#include "core/hw/hw.h"
-#include "core/hw/gpu.h"
+
+#include "core/settings.h"
#include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/interpreter/arm_interpreter.h"
-
+#include "core/arm/dyncom/arm_dyncom.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/thread.h"
+#include "core/hw/hw.h"
namespace Core {
@@ -54,9 +50,18 @@ int Init() {
NOTICE_LOG(MASTER_LOG, "initialized OK");
g_disasm = new ARM_Disasm();
- g_app_core = new ARM_Interpreter();
g_sys_core = new ARM_Interpreter();
+ switch (Settings::values.cpu_core) {
+ case CPU_FastInterpreter:
+ g_app_core = new ARM_DynCom();
+ break;
+ case CPU_Interpreter:
+ default:
+ g_app_core = new ARM_Interpreter();
+ break;
+ }
+
g_last_ticks = Core::g_app_core->GetTicks();
return 0;
diff --git a/src/core/core.h b/src/core/core.h
index 9c72c8b3f..850bb0ab4 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -5,12 +5,17 @@
#pragma once
#include "core/arm/arm_interface.h"
-#include "core/arm/interpreter/armdefs.h"
+#include "core/arm/skyeye_common/armdefs.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Core {
+enum CPUCore {
+ CPU_Interpreter,
+ CPU_FastInterpreter
+};
+
extern ARM_Interface* g_app_core; ///< ARM11 application core
extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core
@@ -21,13 +26,13 @@ void Start();
/**
* Run the core CPU loop
- * This function loops for 100 instructions in the CPU before trying to update hardware. This is a
- * little bit faster than SingleStep, and should be pretty much equivalent. The number of
- * instructions chosen is fairly arbitrary, however a large number will more drastically affect the
- * frequency of GSP interrupts and likely break things. The point of this is to just loop in the CPU
- * for more than 1 instruction to reduce overhead and make it a little bit faster...
+ * This function runs the core for the specified number of CPU instructions before trying to update
+ * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not
+ * required to do a full dispatch with each instruction. NOTE: the number of instructions requested
+ * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is
+ * requested (e.g. on a thread switch).
*/
-void RunLoop(int tight_loop=100);
+void RunLoop(int tight_loop=1000);
/// Step the CPU one instruction
void SingleStep();
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 25fccce76..0116cb376 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -7,11 +7,12 @@
#include <atomic>
#include <mutex>
-#include "common/msg_handler.h"
#include "common/chunk_file.h"
+#include "common/msg_handler.h"
+#include "common/string_util.h"
-#include "core/core_timing.h"
#include "core/core.h"
+#include "core/core_timing.h"
int g_clock_rate_arm11 = 268123480;
@@ -586,9 +587,10 @@ std::string GetScheduledEventsSummary()
const char *name = event_types[ptr->type].name;
if (!name)
name = "[unknown]";
- char temp[512];
- sprintf(temp, "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata));
- text += temp;
+
+ text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)ptr->time,
+ (u32)(ptr->userdata >> 32), (u32)(ptr->userdata));
+
ptr = ptr->next;
}
return text;
diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h
index ac5630bea..38145eed8 100644
--- a/src/core/file_sys/archive.h
+++ b/src/core/file_sys/archive.h
@@ -4,8 +4,16 @@
#pragma once
+#include <memory>
+
#include "common/common_types.h"
+#include "common/string_util.h"
+#include "common/bit_field.h"
+
+#include "core/file_sys/file.h"
+#include "core/file_sys/directory.h"
+#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -13,6 +21,110 @@
namespace FileSys {
+// Path string type
+enum LowPathType : u32 {
+ Invalid = 0,
+ Empty = 1,
+ Binary = 2,
+ Char = 3,
+ Wchar = 4
+};
+
+union Mode {
+ u32 hex;
+ BitField<0, 1, u32> read_flag;
+ BitField<1, 1, u32> write_flag;
+ BitField<2, 1, u32> create_flag;
+};
+
+class Path {
+public:
+
+ Path():
+ type(Invalid)
+ {
+ }
+
+ Path(LowPathType type, u32 size, u32 pointer):
+ type(type)
+ {
+ switch (type) {
+ case Binary:
+ {
+ u8* data = Memory::GetPointer(pointer);
+ binary = std::vector<u8>(data, data + size);
+ break;
+ }
+ case Char:
+ {
+ const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
+ string = std::string(data, size - 1); // Data is always null-terminated.
+ break;
+ }
+ case Wchar:
+ {
+ const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer));
+ u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
+ break;
+ }
+ }
+ }
+
+ LowPathType GetType() const {
+ return type;
+ }
+
+ const std::string AsString() const {
+ switch (GetType()) {
+ case Char:
+ return string;
+ case Wchar:
+ return Common::UTF16ToUTF8(u16str);
+ case Empty:
+ return {};
+ default:
+ ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!");
+ return {};
+ }
+ }
+
+ const std::u16string AsU16Str() const {
+ switch (GetType()) {
+ case Char:
+ return Common::UTF8ToUTF16(string);
+ case Wchar:
+ return u16str;
+ case Empty:
+ return {};
+ default:
+ ERROR_LOG(KERNEL, "LowPathType cannot be converted to u16string!");
+ return {};
+ }
+ }
+
+ const std::vector<u8> AsBinary() const {
+ switch (GetType()) {
+ case Binary:
+ return binary;
+ case Char:
+ return std::vector<u8>(string.begin(), string.end());
+ case Wchar:
+ return std::vector<u8>(u16str.begin(), u16str.end());
+ case Empty:
+ return {};
+ default:
+ ERROR_LOG(KERNEL, "LowPathType cannot be converted to binary!");
+ return {};
+ }
+ }
+
+private:
+ LowPathType type;
+ std::vector<u8> binary;
+ std::string string;
+ std::u16string u16str;
+};
+
class Archive : NonCopyable {
public:
/// Supported archive types
@@ -36,6 +148,28 @@ public:
virtual IdCode GetIdCode() const = 0;
/**
+ * Open a file specified by its path, using the specified mode
+ * @param path Path relative to the archive
+ * @param mode Mode to open the file with
+ * @return Opened file, or nullptr
+ */
+ virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0;
+
+ /**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+ virtual bool CreateDirectory(const std::string& path) const = 0;
+
+ /**
+ * Open a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Opened directory, or nullptr
+ */
+ virtual std::unique_ptr<Directory> OpenDirectory(const std::string& path) const = 0;
+
+ /**
* Read data from the archive
* @param offset Offset in bytes to start reading data from
* @param length Length in bytes of data to read from archive
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index dc3fb1807..cc759faa8 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -5,6 +5,8 @@
#include "common/common_types.h"
#include "core/file_sys/archive_romfs.h"
+#include "core/file_sys/directory_romfs.h"
+#include "core/file_sys/file_romfs.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
@@ -22,6 +24,35 @@ Archive_RomFS::~Archive_RomFS() {
}
/**
+ * Open a file specified by its path, using the specified mode
+ * @param path Path relative to the archive
+ * @param mode Mode to open the file with
+ * @return Opened file, or nullptr
+ */
+std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mode mode) const {
+ return std::unique_ptr<File>(new File_RomFS);
+}
+
+/**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+bool Archive_RomFS::CreateDirectory(const std::string& path) const {
+ ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS.");
+ return false;
+};
+
+/**
+ * Open a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Opened directory, or nullptr
+ */
+std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path) const {
+ return std::unique_ptr<Directory>(new Directory_RomFS);
+}
+
+/**
* Read data from the archive
* @param offset Offset in bytes to start reading data from
* @param length Length in bytes of data to read from archive
@@ -29,7 +60,7 @@ Archive_RomFS::~Archive_RomFS() {
* @return Number of bytes read
*/
size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {
- DEBUG_LOG(FILESYS, "called offset=%d, length=%d", offset, length);
+ DEBUG_LOG(FILESYS, "called offset=%llu, length=%d", offset, length);
memcpy(buffer, &raw_data[(u32)offset], length);
return length;
}
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index e9ed6f77a..ae2344e82 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -29,6 +29,28 @@ public:
IdCode GetIdCode() const override { return IdCode::RomFS; };
/**
+ * Open a file specified by its path, using the specified mode
+ * @param path Path relative to the archive
+ * @param mode Mode to open the file with
+ * @return Opened file, or nullptr
+ */
+ std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override;
+
+ /**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+ bool CreateDirectory(const std::string& path) const override;
+
+ /**
+ * Open a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Opened directory, or nullptr
+ */
+ std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override;
+
+ /**
* Read data from the archive
* @param offset Offset in bytes to start reading data from
* @param length Length in bytes of data to read from archive
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
new file mode 100644
index 000000000..66931e93e
--- /dev/null
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -0,0 +1,129 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/archive_sdmc.h"
+#include "core/file_sys/directory_sdmc.h"
+#include "core/file_sys/file_sdmc.h"
+#include "core/settings.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+Archive_SDMC::Archive_SDMC(const std::string& mount_point) {
+ this->mount_point = mount_point;
+ DEBUG_LOG(FILESYS, "Directory %s set as SDMC.", mount_point.c_str());
+}
+
+Archive_SDMC::~Archive_SDMC() {
+}
+
+/**
+ * Initialize the archive.
+ * @return true if it initialized successfully
+ */
+bool Archive_SDMC::Initialize() {
+ if (!Settings::values.use_virtual_sd) {
+ WARN_LOG(FILESYS, "SDMC disabled by config.");
+ return false;
+ }
+
+ if (!FileUtil::CreateFullPath(mount_point)) {
+ WARN_LOG(FILESYS, "Unable to create SDMC path.");
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Open a file specified by its path, using the specified mode
+ * @param path Path relative to the archive
+ * @param mode Mode to open the file with
+ * @return Opened file, or nullptr
+ */
+std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const {
+ DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.c_str(), mode);
+ File_SDMC* file = new File_SDMC(this, path, mode);
+ if (!file->Open())
+ return nullptr;
+ return std::unique_ptr<File>(file);
+}
+
+/**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+bool Archive_SDMC::CreateDirectory(const std::string& path) const {
+ return FileUtil::CreateDir(GetMountPoint() + path);
+}
+
+/**
+ * Open a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Opened directory, or nullptr
+ */
+std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const std::string& path) const {
+ DEBUG_LOG(FILESYS, "called path=%s", path.c_str());
+ Directory_SDMC* directory = new Directory_SDMC(this, path);
+ return std::unique_ptr<Directory>(directory);
+}
+
+/**
+ * Read data from the archive
+ * @param offset Offset in bytes to start reading archive from
+ * @param length Length in bytes to read data from archive
+ * @param buffer Buffer to read data into
+ * @return Number of bytes read
+ */
+size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
+ ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
+ return -1;
+}
+
+/**
+ * Write data to the archive
+ * @param offset Offset in bytes to start writing data to
+ * @param length Length in bytes of data to write to archive
+ * @param buffer Buffer to write data from
+ * @param flush The flush parameters (0 == do not flush)
+ * @return Number of bytes written
+ */
+size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) {
+ ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
+ return -1;
+}
+
+/**
+ * Get the size of the archive in bytes
+ * @return Size of the archive in bytes
+ */
+size_t Archive_SDMC::GetSize() const {
+ ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
+ return 0;
+}
+
+/**
+ * Set the size of the archive in bytes
+ */
+void Archive_SDMC::SetSize(const u64 size) {
+ ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
+}
+
+/**
+ * Getter for the path used for this Archive
+ * @return Mount point of that passthrough archive
+ */
+std::string Archive_SDMC::GetMountPoint() const {
+ return mount_point;
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
new file mode 100644
index 000000000..0e059b635
--- /dev/null
+++ b/src/core/file_sys/archive_sdmc.h
@@ -0,0 +1,97 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/file_sys/archive.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+/// File system interface to the SDMC archive
+class Archive_SDMC final : public Archive {
+public:
+ Archive_SDMC(const std::string& mount_point);
+ ~Archive_SDMC() override;
+
+ /**
+ * Initialize the archive.
+ * @return true if it initialized successfully
+ */
+ bool Initialize();
+
+ /**
+ * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
+ * @return IdCode of the archive
+ */
+ IdCode GetIdCode() const override { return IdCode::SDMC; };
+
+ /**
+ * Open a file specified by its path, using the specified mode
+ * @param path Path relative to the archive
+ * @param mode Mode to open the file with
+ * @return Opened file, or nullptr
+ */
+ std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override;
+
+ /**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+ bool CreateDirectory(const std::string& path) const override;
+
+ /**
+ * Open a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Opened directory, or nullptr
+ */
+ std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override;
+
+ /**
+ * Read data from the archive
+ * @param offset Offset in bytes to start reading archive from
+ * @param length Length in bytes to read data from archive
+ * @param buffer Buffer to read data into
+ * @return Number of bytes read
+ */
+ size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
+
+ /**
+ * Write data to the archive
+ * @param offset Offset in bytes to start writing data to
+ * @param length Length in bytes of data to write to archive
+ * @param buffer Buffer to write data from
+ * @param flush The flush parameters (0 == do not flush)
+ * @return Number of bytes written
+ */
+ size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override;
+
+ /**
+ * Get the size of the archive in bytes
+ * @return Size of the archive in bytes
+ */
+ size_t GetSize() const override;
+
+ /**
+ * Set the size of the archive in bytes
+ */
+ void SetSize(const u64 size) override;
+
+ /**
+ * Getter for the path used for this Archive
+ * @return Mount point of that passthrough archive
+ */
+ std::string GetMountPoint() const;
+
+private:
+ std::string mount_point;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
new file mode 100644
index 000000000..e10431337
--- /dev/null
+++ b/src/core/file_sys/directory.h
@@ -0,0 +1,59 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstddef>
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+// Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format
+const size_t FILENAME_LENGTH = 0x20C / 2;
+struct Entry {
+ char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated)
+ std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated)
+ char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD)
+ std::array<char, 4> extension; // 8.3 file extension (set to spaces for directories, null-terminated)
+ char unknown2; // unknown (always 0x01)
+ char unknown3; // unknown (0x00 or 0x08)
+ char is_directory; // directory flag
+ char is_hidden; // hidden flag
+ char is_archive; // archive flag
+ char is_read_only; // read-only flag
+ u64 file_size; // file size (for files only)
+};
+static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!");
+static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry.");
+static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry.");
+static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry.");
+static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry.");
+
+class Directory : NonCopyable {
+public:
+ Directory() { }
+ virtual ~Directory() { }
+
+ /**
+ * List files contained in the directory
+ * @param count Number of entries to return at once in entries
+ * @param entries Buffer to read data into
+ * @return Number of entries listed
+ */
+ virtual u32 Read(const u32 count, Entry* entries) = 0;
+
+ /**
+ * Close the directory
+ * @return true if the directory closed correctly
+ */
+ virtual bool Close() const = 0;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/directory_romfs.cpp b/src/core/file_sys/directory_romfs.cpp
new file mode 100644
index 000000000..4e8f4c04d
--- /dev/null
+++ b/src/core/file_sys/directory_romfs.cpp
@@ -0,0 +1,38 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/common_types.h"
+
+#include "core/file_sys/directory_romfs.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+Directory_RomFS::Directory_RomFS() {
+}
+
+Directory_RomFS::~Directory_RomFS() {
+}
+
+/**
+ * List files contained in the directory
+ * @param count Number of entries to return at once in entries
+ * @param entries Buffer to read data into
+ * @return Number of entries listed
+ */
+u32 Directory_RomFS::Read(const u32 count, Entry* entries) {
+ return 0;
+}
+
+/**
+ * Close the directory
+ * @return true if the directory closed correctly
+ */
+bool Directory_RomFS::Close() const {
+ return false;
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/directory_romfs.h b/src/core/file_sys/directory_romfs.h
new file mode 100644
index 000000000..4b71c4b13
--- /dev/null
+++ b/src/core/file_sys/directory_romfs.h
@@ -0,0 +1,37 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/file_sys/directory.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+class Directory_RomFS final : public Directory {
+public:
+ Directory_RomFS();
+ ~Directory_RomFS() override;
+
+ /**
+ * List files contained in the directory
+ * @param count Number of entries to return at once in entries
+ * @param entries Buffer to read data into
+ * @return Number of entries listed
+ */
+ u32 Read(const u32 count, Entry* entries) override;
+
+ /**
+ * Close the directory
+ * @return true if the directory closed correctly
+ */
+ bool Close() const override;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp
new file mode 100644
index 000000000..fd558def9
--- /dev/null
+++ b/src/core/file_sys/directory_sdmc.cpp
@@ -0,0 +1,81 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/directory_sdmc.h"
+#include "core/file_sys/archive_sdmc.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const std::string& path) {
+ // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
+ // the root directory we set while opening the archive.
+ // For example, opening /../../usr/bin can give the emulated program your installed programs.
+ std::string absolute_path = archive->GetMountPoint() + path;
+ FileUtil::ScanDirectoryTree(absolute_path, directory);
+ children_iterator = directory.children.begin();
+}
+
+Directory_SDMC::~Directory_SDMC() {
+ Close();
+}
+
+/**
+ * List files contained in the directory
+ * @param count Number of entries to return at once in entries
+ * @param entries Buffer to read data into
+ * @return Number of entries listed
+ */
+u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
+ u32 entries_read = 0;
+
+ while (entries_read < count && children_iterator != directory.children.cend()) {
+ const FileUtil::FSTEntry& file = *children_iterator;
+ const std::string& filename = file.virtualName;
+ Entry& entry = entries[entries_read];
+
+ WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
+
+ // TODO(Link Mauve): use a proper conversion to UTF-16.
+ for (int j = 0; j < FILENAME_LENGTH; ++j) {
+ entry.filename[j] = filename[j];
+ if (!filename[j])
+ break;
+ }
+
+ FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
+
+ entry.is_directory = file.isDirectory;
+ entry.is_hidden = (filename[0] == '.');
+ entry.is_read_only = 0;
+ entry.file_size = file.size;
+
+ // We emulate a SD card where the archive bit has never been cleared, as it would be on
+ // most user SD cards.
+ // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
+ // file bit.
+ entry.is_archive = !file.isDirectory;
+
+ ++entries_read;
+ ++children_iterator;
+ }
+ return entries_read;
+}
+
+/**
+ * Close the directory
+ * @return true if the directory closed correctly
+ */
+bool Directory_SDMC::Close() const {
+ return true;
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h
new file mode 100644
index 000000000..cb8d32fda
--- /dev/null
+++ b/src/core/file_sys/directory_sdmc.h
@@ -0,0 +1,48 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/directory.h"
+#include "core/file_sys/archive_sdmc.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+class Directory_SDMC final : public Directory {
+public:
+ Directory_SDMC();
+ Directory_SDMC(const Archive_SDMC* archive, const std::string& path);
+ ~Directory_SDMC() override;
+
+ /**
+ * List files contained in the directory
+ * @param count Number of entries to return at once in entries
+ * @param entries Buffer to read data into
+ * @return Number of entries listed
+ */
+ u32 Read(const u32 count, Entry* entries) override;
+
+ /**
+ * Close the directory
+ * @return true if the directory closed correctly
+ */
+ bool Close() const override;
+
+private:
+ u32 total_entries_in_directory;
+ FileUtil::FSTEntry directory;
+
+ // We need to remember the last entry we returned, so a subsequent call to Read will continue
+ // from the next one. This iterator will always point to the next unread entry.
+ std::vector<FileUtil::FSTEntry>::iterator children_iterator;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/file.h b/src/core/file_sys/file.h
new file mode 100644
index 000000000..4013b6c3e
--- /dev/null
+++ b/src/core/file_sys/file.h
@@ -0,0 +1,66 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+class File : NonCopyable {
+public:
+ File() { }
+ virtual ~File() { }
+
+ /**
+ * Open the file
+ * @return true if the file opened correctly
+ */
+ virtual bool Open() = 0;
+
+ /**
+ * Read data from the file
+ * @param offset Offset in bytes to start reading data from
+ * @param length Length in bytes of data to read from file
+ * @param buffer Buffer to read data into
+ * @return Number of bytes read
+ */
+ virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0;
+
+ /**
+ * Write data to the file
+ * @param offset Offset in bytes to start writing data to
+ * @param length Length in bytes of data to write to file
+ * @param flush The flush parameters (0 == do not flush)
+ * @param buffer Buffer to read data from
+ * @return Number of bytes written
+ */
+ virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0;
+
+ /**
+ * Get the size of the file in bytes
+ * @return Size of the file in bytes
+ */
+ virtual size_t GetSize() const = 0;
+
+ /**
+ * Set the size of the file in bytes
+ * @param size New size of the file
+ * @return true if successful
+ */
+ virtual bool SetSize(const u64 size) const = 0;
+
+ /**
+ * Close the file
+ * @return true if the file closed correctly
+ */
+ virtual bool Close() const = 0;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp
new file mode 100644
index 000000000..b55708df4
--- /dev/null
+++ b/src/core/file_sys/file_romfs.cpp
@@ -0,0 +1,76 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/common_types.h"
+
+#include "core/file_sys/file_romfs.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+File_RomFS::File_RomFS() {
+}
+
+File_RomFS::~File_RomFS() {
+}
+
+/**
+ * Open the file
+ * @return true if the file opened correctly
+ */
+bool File_RomFS::Open() {
+ return false;
+}
+
+/**
+ * Read data from the file
+ * @param offset Offset in bytes to start reading data from
+ * @param length Length in bytes of data to read from file
+ * @param buffer Buffer to read data into
+ * @return Number of bytes read
+ */
+size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {
+ return -1;
+}
+
+/**
+ * Write data to the file
+ * @param offset Offset in bytes to start writing data to
+ * @param length Length in bytes of data to write to file
+ * @param flush The flush parameters (0 == do not flush)
+ * @param buffer Buffer to read data from
+ * @return Number of bytes written
+ */
+size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
+ return -1;
+}
+
+/**
+ * Get the size of the file in bytes
+ * @return Size of the file in bytes
+ */
+size_t File_RomFS::GetSize() const {
+ return -1;
+}
+
+/**
+ * Set the size of the file in bytes
+ * @param size New size of the file
+ * @return true if successful
+ */
+bool File_RomFS::SetSize(const u64 size) const {
+ return false;
+}
+
+/**
+ * Close the file
+ * @return true if the file closed correctly
+ */
+bool File_RomFS::Close() const {
+ return false;
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h
new file mode 100644
index 000000000..5196701d3
--- /dev/null
+++ b/src/core/file_sys/file_romfs.h
@@ -0,0 +1,67 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/file_sys/file.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+class File_RomFS final : public File {
+public:
+ File_RomFS();
+ ~File_RomFS() override;
+
+ /**
+ * Open the file
+ * @return true if the file opened correctly
+ */
+ bool Open() override;
+
+ /**
+ * Read data from the file
+ * @param offset Offset in bytes to start reading data from
+ * @param length Length in bytes of data to read from file
+ * @param buffer Buffer to read data into
+ * @return Number of bytes read
+ */
+ size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
+
+ /**
+ * Write data to the file
+ * @param offset Offset in bytes to start writing data to
+ * @param length Length in bytes of data to write to file
+ * @param flush The flush parameters (0 == do not flush)
+ * @param buffer Buffer to read data from
+ * @return Number of bytes written
+ */
+ size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
+
+ /**
+ * Get the size of the file in bytes
+ * @return Size of the file in bytes
+ */
+ size_t GetSize() const override;
+
+ /**
+ * Set the size of the file in bytes
+ * @param size New size of the file
+ * @return true if successful
+ */
+ bool SetSize(const u64 size) const override;
+
+ /**
+ * Close the file
+ * @return true if the file closed correctly
+ */
+ bool Close() const override;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp
new file mode 100644
index 000000000..26204392c
--- /dev/null
+++ b/src/core/file_sys/file_sdmc.cpp
@@ -0,0 +1,107 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/file_sdmc.h"
+#include "core/file_sys/archive_sdmc.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+File_SDMC::File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode) {
+ // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
+ // the root directory we set while opening the archive.
+ // For example, opening /../../etc/passwd can give the emulated program your users list.
+ this->path = archive->GetMountPoint() + path;
+ this->mode.hex = mode.hex;
+}
+
+File_SDMC::~File_SDMC() {
+ Close();
+}
+
+/**
+ * Open the file
+ * @return true if the file opened correctly
+ */
+bool File_SDMC::Open() {
+ if (!mode.create_flag && !FileUtil::Exists(path)) {
+ ERROR_LOG(FILESYS, "Non-existing file %s can’t be open without mode create.", path.c_str());
+ return false;
+ }
+
+ std::string mode_string;
+ if (mode.read_flag && mode.write_flag)
+ mode_string = "w+";
+ else if (mode.read_flag)
+ mode_string = "r";
+ else if (mode.write_flag)
+ mode_string = "w";
+
+ file = new FileUtil::IOFile(path, mode_string.c_str());
+ return true;
+}
+
+/**
+ * Read data from the file
+ * @param offset Offset in bytes to start reading data from
+ * @param length Length in bytes of data to read from file
+ * @param buffer Buffer to read data into
+ * @return Number of bytes read
+ */
+size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
+ file->Seek(offset, SEEK_SET);
+ return file->ReadBytes(buffer, length);
+}
+
+/**
+ * Write data to the file
+ * @param offset Offset in bytes to start writing data to
+ * @param length Length in bytes of data to write to file
+ * @param flush The flush parameters (0 == do not flush)
+ * @param buffer Buffer to read data from
+ * @return Number of bytes written
+ */
+size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
+ file->Seek(offset, SEEK_SET);
+ size_t written = file->WriteBytes(buffer, length);
+ if (flush)
+ file->Flush();
+ return written;
+}
+
+/**
+ * Get the size of the file in bytes
+ * @return Size of the file in bytes
+ */
+size_t File_SDMC::GetSize() const {
+ return static_cast<size_t>(file->GetSize());
+}
+
+/**
+ * Set the size of the file in bytes
+ * @param size New size of the file
+ * @return true if successful
+ */
+bool File_SDMC::SetSize(const u64 size) const {
+ file->Resize(size);
+ file->Flush();
+ return true;
+}
+
+/**
+ * Close the file
+ * @return true if the file closed correctly
+ */
+bool File_SDMC::Close() const {
+ return file->Close();
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h
new file mode 100644
index 000000000..df032f7c0
--- /dev/null
+++ b/src/core/file_sys/file_sdmc.h
@@ -0,0 +1,75 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/file.h"
+#include "core/file_sys/archive_sdmc.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+class File_SDMC final : public File {
+public:
+ File_SDMC();
+ File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode);
+ ~File_SDMC() override;
+
+ /**
+ * Open the file
+ * @return true if the file opened correctly
+ */
+ bool Open() override;
+
+ /**
+ * Read data from the file
+ * @param offset Offset in bytes to start reading data from
+ * @param length Length in bytes of data to read from file
+ * @param buffer Buffer to read data into
+ * @return Number of bytes read
+ */
+ size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
+
+ /**
+ * Write data to the file
+ * @param offset Offset in bytes to start writing data to
+ * @param length Length in bytes of data to write to file
+ * @param flush The flush parameters (0 == do not flush)
+ * @param buffer Buffer to read data from
+ * @return Number of bytes written
+ */
+ size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
+
+ /**
+ * Get the size of the file in bytes
+ * @return Size of the file in bytes
+ */
+ size_t GetSize() const override;
+
+ /**
+ * Set the size of the file in bytes
+ * @param size New size of the file
+ * @return true if successful
+ */
+ bool SetSize(const u64 size) const override;
+
+ /**
+ * Close the file
+ * @return true if the file closed correctly
+ */
+ bool Close() const override;
+
+private:
+ std::string path;
+ Mode mode;
+ FileUtil::IOFile* file;
+};
+
+} // namespace FileSys
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index 8c898b265..a45e61427 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
-#include "common/log.h"
#include "core/hle/config_mem.h"
diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp
index 9a5b0deda..1eb33eb86 100644
--- a/src/core/hle/coprocessor.cpp
+++ b/src/core/hle/coprocessor.cpp
@@ -5,7 +5,6 @@
#include "core/hle/coprocessor.h"
#include "core/hle/hle.h"
#include "core/mem_map.h"
-#include "core/core.h"
namespace HLE {
diff --git a/src/core/hle/coprocessor.h b/src/core/hle/coprocessor.h
deleted file mode 100644
index b08d6f3ee..000000000
--- a/src/core/hle/coprocessor.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-
-namespace HLE {
-
-/// Coprocessor operations
-enum CoprocessorOperation {
- DATA_SYNCHRONIZATION_BARRIER = 0xE0,
- CALL_GET_THREAD_COMMAND_BUFFER = 0xE1,
-};
-
-/// Call an MRC (move to ARM register from coprocessor) instruction in HLE
-s32 CallMRC(u32 instruction);
-
-} // namespace
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 53cda4a61..b03894ad7 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -6,7 +6,6 @@
#include "core/mem_map.h"
#include "core/hle/hle.h"
-#include "core/hle/svc.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h"
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 174d4cd6e..2b21657da 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -17,11 +17,11 @@ namespace Kernel {
class AddressArbiter : public Object {
public:
- std::string GetTypeName() const { return "Arbiter"; }
- std::string GetName() const { return name; }
+ std::string GetTypeName() const override { return "Arbiter"; }
+ std::string GetName() const override { return name; }
static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; }
- Kernel::HandleType GetHandleType() const { return HandleType::AddressArbiter; }
+ Kernel::HandleType GetHandleType() const override { return HandleType::AddressArbiter; }
std::string name; ///< Name of address arbiter object (optional)
@@ -30,7 +30,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
index 1596367c3..764082d71 100644
--- a/src/core/hle/kernel/archive.cpp
+++ b/src/core/hle/kernel/archive.cpp
@@ -3,11 +3,13 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
+#include "common/file_util.h"
#include "common/math_util.h"
#include "core/file_sys/archive.h"
+#include "core/file_sys/archive_sdmc.h"
+#include "core/file_sys/directory.h"
#include "core/hle/service/service.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -30,13 +32,21 @@ enum class FileCommand : u32 {
Flush = 0x08090000,
};
+// Command to access directory
+enum class DirectoryCommand : u32 {
+ Dummy1 = 0x000100C6,
+ Control = 0x040100C4,
+ Read = 0x08010042,
+ Close = 0x08020000,
+};
+
class Archive : public Object {
public:
- std::string GetTypeName() const { return "Archive"; }
- std::string GetName() const { return name; }
+ std::string GetTypeName() const override { return "Archive"; }
+ std::string GetName() const override { return name; }
static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; }
- Kernel::HandleType GetHandleType() const { return HandleType::Archive; }
+ Kernel::HandleType GetHandleType() const override { return HandleType::Archive; }
std::string name; ///< Name of archive (optional)
FileSys::Archive* backend; ///< Archive backend interface
@@ -46,7 +56,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result SyncRequest(bool* wait) {
+ Result SyncRequest(bool* wait) override {
u32* cmd_buff = Service::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
@@ -86,6 +96,13 @@ public:
backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32));
break;
}
+ case FileCommand::Close:
+ {
+ DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
+ Kernel::g_object_pool.Destroy<Archive>(GetHandle());
+ CloseArchive(backend->GetIdCode());
+ break;
+ }
// Unknown command...
default:
{
@@ -102,7 +119,162 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
+ // TODO(bunnei): ImplementMe
+ ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
+ return 0;
+ }
+};
+
+class File : public Object {
+public:
+ std::string GetTypeName() const override { return "File"; }
+ std::string GetName() const override { return path; }
+
+ static Kernel::HandleType GetStaticHandleType() { return HandleType::File; }
+ Kernel::HandleType GetHandleType() const override { return HandleType::File; }
+
+ std::string path; ///< Path of the file
+ std::unique_ptr<FileSys::File> backend; ///< File backend interface
+
+ /**
+ * Synchronize kernel object
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result SyncRequest(bool* wait) override {
+ u32* cmd_buff = Service::GetCommandBuffer();
+ FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
+ switch (cmd) {
+
+ // Read from file...
+ case FileCommand::Read:
+ {
+ u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
+ u32 length = cmd_buff[3];
+ u32 address = cmd_buff[5];
+ DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%llx length=%d address=0x%x",
+ GetTypeName().c_str(), GetName().c_str(), offset, length, address);
+ cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
+ break;
+ }
+
+ // Write to file...
+ case FileCommand::Write:
+ {
+ u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
+ u32 length = cmd_buff[3];
+ u32 flush = cmd_buff[4];
+ u32 address = cmd_buff[6];
+ DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
+ GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
+ cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
+ break;
+ }
+
+ case FileCommand::GetSize:
+ {
+ DEBUG_LOG(KERNEL, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
+ u64 size = backend->GetSize();
+ cmd_buff[2] = (u32)size;
+ cmd_buff[3] = size >> 32;
+ break;
+ }
+
+ case FileCommand::SetSize:
+ {
+ u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
+ DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size);
+ backend->SetSize(size);
+ break;
+ }
+
+ case FileCommand::Close:
+ {
+ DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
+ Kernel::g_object_pool.Destroy<File>(GetHandle());
+ break;
+ }
+
+ // Unknown command...
+ default:
+ ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
+ cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that.
+ return -1;
+ }
+ cmd_buff[1] = 0; // No error
+ return 0;
+ }
+
+ /**
+ * Wait for kernel object to synchronize
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result WaitSynchronization(bool* wait) override {
+ // TODO(bunnei): ImplementMe
+ ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
+ return 0;
+ }
+};
+
+class Directory : public Object {
+public:
+ std::string GetTypeName() const override { return "Directory"; }
+ std::string GetName() const override { return path; }
+
+ static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; }
+ Kernel::HandleType GetHandleType() const override { return HandleType::Directory; }
+
+ std::string path; ///< Path of the directory
+ std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
+
+ /**
+ * Synchronize kernel object
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result SyncRequest(bool* wait) override {
+ u32* cmd_buff = Service::GetCommandBuffer();
+ DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
+ switch (cmd) {
+
+ // Read from directory...
+ case DirectoryCommand::Read:
+ {
+ u32 count = cmd_buff[1];
+ u32 address = cmd_buff[3];
+ FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
+ DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count);
+
+ // Number of entries actually read
+ cmd_buff[2] = backend->Read(count, entries);
+ break;
+ }
+
+ case DirectoryCommand::Close:
+ {
+ DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
+ Kernel::g_object_pool.Destroy<Directory>(GetHandle());
+ break;
+ }
+
+ // Unknown command...
+ default:
+ ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
+ cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that.
+ return -1;
+ }
+ cmd_buff[1] = 0; // No error
+ return 0;
+ }
+
+ /**
+ * Wait for kernel object to synchronize
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
@@ -127,6 +299,21 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code) {
}
/**
+ * Closes an archive
+ * @param id_code IdCode of the archive to open
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result CloseArchive(FileSys::Archive::IdCode id_code) {
+ if (1 != g_archive_map.erase(id_code)) {
+ ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code);
+ return -1;
+ }
+
+ INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
+ return 0;
+}
+
+/**
* Mounts an archive
* @param archive Pointer to the archive to mount
* @return Result of operation, 0 on success, otherwise error code
@@ -172,9 +359,73 @@ Handle CreateArchive(FileSys::Archive* backend, const std::string& name) {
return handle;
}
+/**
+ * Open a File from an Archive
+ * @param archive_handle Handle to an open Archive object
+ * @param path Path to the File inside of the Archive
+ * @param mode Mode under which to open the File
+ * @return Opened File object
+ */
+Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) {
+ File* file = new File;
+ Handle handle = Kernel::g_object_pool.Create(file);
+
+ Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
+ file->path = path;
+ file->backend = archive->backend->OpenFile(path, mode);
+
+ if (!file->backend)
+ return 0;
+
+ return handle;
+}
+
+/**
+ * Create a Directory from an Archive
+ * @param archive_handle Handle to an open Archive object
+ * @param path Path to the Directory inside of the Archive
+ * @return Opened Directory object
+ */
+Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) {
+ Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
+ if (archive == nullptr)
+ return -1;
+ if (archive->backend->CreateDirectory(path))
+ return 0;
+ return -1;
+}
+
+/**
+ * Open a Directory from an Archive
+ * @param archive_handle Handle to an open Archive object
+ * @param path Path to the Directory inside of the Archive
+ * @return Opened Directory object
+ */
+Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) {
+ Directory* directory = new Directory;
+ Handle handle = Kernel::g_object_pool.Create(directory);
+
+ Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
+ directory->path = path;
+ directory->backend = archive->backend->OpenDirectory(path);
+
+ return handle;
+}
+
/// Initialize archives
void ArchiveInit() {
g_archive_map.clear();
+
+ // TODO(Link Mauve): Add the other archive types (see here for the known types:
+ // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished
+ // archive type is SDMC, so it is the only one getting exposed.
+
+ std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
+ auto archive = new FileSys::Archive_SDMC(sdmc_directory);
+ if (archive->Initialize())
+ CreateArchive(archive, "SDMC");
+ else
+ ERROR_LOG(KERNEL, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
}
/// Shutdown archives
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h
index 3758e7061..0230996b6 100644
--- a/src/core/hle/kernel/archive.h
+++ b/src/core/hle/kernel/archive.h
@@ -22,6 +22,13 @@ namespace Kernel {
Handle OpenArchive(FileSys::Archive::IdCode id_code);
/**
+ * Closes an archive
+ * @param id_code IdCode of the archive to open
+ * @return true if it worked fine
+ */
+Result CloseArchive(FileSys::Archive::IdCode id_code);
+
+/**
* Creates an Archive
* @param backend File system backend interface to the archive
* @param name Optional name of Archive
@@ -29,6 +36,31 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code);
*/
Handle CreateArchive(FileSys::Archive* backend, const std::string& name);
+/**
+ * Open a File from an Archive
+ * @param archive_handle Handle to an open Archive object
+ * @param path Path to the File inside of the Archive
+ * @param mode Mode under which to open the File
+ * @return Opened File object
+ */
+Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode);
+
+/**
+ * Create a Directory from an Archive
+ * @param archive_handle Handle to an open Archive object
+ * @param path Path to the Directory inside of the Archive
+ * @return Whether creation of directory succeeded
+ */
+Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name);
+
+/**
+ * Open a Directory from an Archive
+ * @param archive_handle Handle to an open Archive object
+ * @param path Path to the Directory inside of the Archive
+ * @return Opened Directory object
+ */
+Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name);
+
/// Initialize archives
void ArchiveInit();
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 64f6a9649..45ed79be8 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -16,11 +16,11 @@ namespace Kernel {
class Event : public Object {
public:
- std::string GetTypeName() const { return "Event"; }
- std::string GetName() const { return name; }
+ std::string GetTypeName() const override { return "Event"; }
+ std::string GetName() const override { return name; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Event; }
ResetType intitial_reset_type; ///< ResetType specified at Event initialization
ResetType reset_type; ///< Current ResetType
@@ -35,7 +35,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
*wait = locked;
if (locked) {
Handle thread = GetCurrentThreadHandle();
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index a4a258875..88cbc1af5 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -2,8 +2,6 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
-#include <string.h>
-
#include "common/common.h"
#include "core/core.h"
@@ -87,47 +85,8 @@ int ObjectPool::GetCount() {
}
Object* ObjectPool::CreateByIDType(int type) {
- // Used for save states. This is ugly, but what other way is there?
- switch (type) {
- //case SCE_KERNEL_TMID_Alarm:
- // return __KernelAlarmObject();
- //case SCE_KERNEL_TMID_EventFlag:
- // return __KernelEventFlagObject();
- //case SCE_KERNEL_TMID_Mbox:
- // return __KernelMbxObject();
- //case SCE_KERNEL_TMID_Fpl:
- // return __KernelMemoryFPLObject();
- //case SCE_KERNEL_TMID_Vpl:
- // return __KernelMemoryVPLObject();
- //case PPSSPP_KERNEL_TMID_PMB:
- // return __KernelMemoryPMBObject();
- //case PPSSPP_KERNEL_TMID_Module:
- // return __KernelModuleObject();
- //case SCE_KERNEL_TMID_Mpipe:
- // return __KernelMsgPipeObject();
- //case SCE_KERNEL_TMID_Mutex:
- // return __KernelMutexObject();
- //case SCE_KERNEL_TMID_LwMutex:
- // return __KernelLwMutexObject();
- //case SCE_KERNEL_TMID_Semaphore:
- // return __KernelSemaphoreObject();
- //case SCE_KERNEL_TMID_Callback:
- // return __KernelCallbackObject();
- //case SCE_KERNEL_TMID_Thread:
- // return __KernelThreadObject();
- //case SCE_KERNEL_TMID_VTimer:
- // return __KernelVTimerObject();
- //case SCE_KERNEL_TMID_Tlspl:
- // return __KernelTlsplObject();
- //case PPSSPP_KERNEL_TMID_File:
- // return __KernelFileNodeObject();
- //case PPSSPP_KERNEL_TMID_DirList:
- // return __KernelDirListingObject();
-
- default:
- ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
- return nullptr;
- }
+ ERROR_LOG(COMMON, "Unimplemented: %d.", type);
+ return nullptr;
}
/// Initialize the kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 0e7e5ff68..867d1b89c 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -32,6 +32,7 @@ enum class HandleType : u32 {
File = 10,
Semaphore = 11,
Archive = 12,
+ Directory = 13,
};
enum {
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 5d7d65dd9..fcfd061ac 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -15,11 +15,11 @@ namespace Kernel {
class Mutex : public Object {
public:
- std::string GetTypeName() const { return "Mutex"; }
- std::string GetName() const { return name; }
+ std::string GetTypeName() const override { return "Mutex"; }
+ std::string GetName() const override { return name; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; }
bool initial_locked; ///< Initial lock state when mutex was created
bool locked; ///< Current locked state
@@ -32,7 +32,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result SyncRequest(bool* wait) {
+ Result SyncRequest(bool* wait) override {
// TODO(bunnei): ImplementMe
locked = true;
return 0;
@@ -43,7 +43,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
*wait = locked;
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 2a6a483a1..6bd5e2728 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -11,17 +11,17 @@ namespace Kernel {
class SharedMemory : public Object {
public:
- std::string GetTypeName() const { return "SharedMemory"; }
+ std::string GetTypeName() const override { return "SharedMemory"; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; }
/**
* Wait for kernel object to synchronize
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 8bd9ca1a1..e15590c49 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -3,10 +3,8 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <cstdio>
#include <list>
#include <map>
-#include <string>
#include <vector>
#include "common/common.h"
@@ -15,7 +13,6 @@
#include "core/core.h"
#include "core/mem_map.h"
#include "core/hle/hle.h"
-#include "core/hle/svc.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
@@ -24,11 +21,11 @@ namespace Kernel {
class Thread : public Kernel::Object {
public:
- std::string GetName() const { return name; }
- std::string GetTypeName() const { return "Thread"; }
+ std::string GetName() const override { return name; }
+ std::string GetTypeName() const override { return "Thread"; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; }
inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
@@ -41,7 +38,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
if (status != THREADSTATUS_DORMANT) {
Handle thread = GetCurrentThreadHandle();
if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
new file mode 100644
index 000000000..b39603bdf
--- /dev/null
+++ b/src/core/hle/service/ac_u.cpp
@@ -0,0 +1,44 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/ac_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace AC_U
+
+namespace AC_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, nullptr, "CreateDefaultConfig"},
+ {0x00040006, nullptr, "ConnectAsync"},
+ {0x00050002, nullptr, "GetConnectResult"},
+ {0x00080004, nullptr, "CloseAsync"},
+ {0x00090002, nullptr, "GetCloseResult"},
+ {0x000A0000, nullptr, "GetLastErrorCode"},
+ {0x000D0000, nullptr, "GetWifiStatus"},
+ {0x000E0042, nullptr, "GetCurrentAPInfo"},
+ {0x00100042, nullptr, "GetCurrentNZoneInfo"},
+ {0x00110042, nullptr, "GetNZoneApNumService"},
+ {0x00240042, nullptr, "AddDenyApType "},
+ {0x00270002, nullptr, "GetInfraPriority "},
+ {0x002D0082, nullptr, "SetRequestEulaVersion"},
+ {0x00300004, nullptr, "RegisterDisconnectEvent"},
+ {0x003C0042, nullptr, "GetAPSSIDList"},
+ {0x003E0042, nullptr, "IsConnected "},
+ {0x00400042, nullptr, "SetClientVersion"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/hid.h b/src/core/hle/service/ac_u.h
index b17fcfa86..3c5958d27 100644
--- a/src/core/hle/service/hid.h
+++ b/src/core/hle/service/ac_u.h
@@ -7,28 +7,23 @@
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace HID_User
+// Namespace AC_U
-// This service is used for interfacing to physical user controls... perhaps "Human Interface
-// Devices"? Uses include game pad controls, accelerometers, gyroscopes, etc.
+// socket service "ac:u"
-namespace HID_User {
+namespace AC_U {
class Interface : public Service::Interface {
public:
-
Interface();
-
~Interface();
-
/**
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
std::string GetPortName() const {
- return "hid:USER";
+ return "ac:u";
}
-
};
} // namespace
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt_u.cpp
index e97e7dbf7..4f41ec5f4 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt_u.cpp
@@ -8,13 +8,15 @@
#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
-#include "core/hle/service/apt.h"
+#include "apt_u.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace APT_U
namespace APT_U {
+static Handle lock_handle = 0;
+
/// Signals used by APT functions
enum class SignalType : u32 {
None = 0x0,
@@ -32,15 +34,32 @@ void Initialize(Service::Interface* self) {
Kernel::SetEventLocked(cmd_buff[3], true);
Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
+ _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock");
+ Kernel::ReleaseMutex(lock_handle);
+
cmd_buff[1] = 0; // No error
+
DEBUG_LOG(KERNEL, "called");
}
void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
+
+ if (0 == lock_handle) {
+ // TODO(bunnei): Verify if this is created here or at application boot?
+ lock_handle = Kernel::CreateMutex(false, "APT_U:Lock");
+ Kernel::ReleaseMutex(lock_handle);
+ }
cmd_buff[1] = 0; // No error
- cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock");
+
+ // Not sure what these parameters are used for, but retail apps check that they are 0 after
+ // GetLockHandle has been called.
+ cmd_buff[2] = 0;
+ cmd_buff[3] = 0;
+ cmd_buff[4] = 0;
+
+ cmd_buff[5] = lock_handle;
DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
}
@@ -59,6 +78,25 @@ void InquireNotification(Service::Interface* self) {
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id);
}
+/**
+ * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state,
+ * from the source process which set the parameters. Once finished, NS will clear a flag in the NS
+ * state so that this command will return an error if this command is used again if parameters were
+ * not set again. This is called when the second Initialize event is triggered. It returns a signal
+ * type indicating why it was triggered.
+ * Inputs:
+ * 1 : AppID
+ * 2 : Parameter buffer size, max size is 0x1000
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Unknown, for now assume AppID of the process which sent these parameters
+ * 3 : Unknown, for now assume Signal type
+ * 4 : Actual parameter buffer size, this is <= to the the input size
+ * 5 : Value
+ * 6 : Handle from the source process which set the parameters, likely used for shared memory
+ * 7 : Size
+ * 8 : Output parameter buffer ptr
+ */
void ReceiveParameter(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 app_id = cmd_buff[1];
@@ -66,13 +104,74 @@ void ReceiveParameter(Service::Interface* self) {
cmd_buff[1] = 0; // No error
cmd_buff[2] = 0;
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
- cmd_buff[4] = 0x10;
+ cmd_buff[4] = 0x10; // Parameter buffer size (16)
cmd_buff[5] = 0;
cmd_buff[6] = 0;
cmd_buff[7] = 0;
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
}
+/**
+ * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter
+ * (except for the word value prior to the output handle), except this will not clear the flag
+ * (except when responseword[3]==8 || responseword[3]==9) in NS state.
+ * Inputs:
+ * 1 : AppID
+ * 2 : Parameter buffer size, max size is 0x1000
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Unknown, for now assume AppID of the process which sent these parameters
+ * 3 : Unknown, for now assume Signal type
+ * 4 : Actual parameter buffer size, this is <= to the the input size
+ * 5 : Value
+ * 6 : Handle from the source process which set the parameters, likely used for shared memory
+ * 7 : Size
+ * 8 : Output parameter buffer ptr
+ */
+void GlanceParameter(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+ u32 app_id = cmd_buff[1];
+ u32 buffer_size = cmd_buff[2];
+
+ cmd_buff[1] = 0; // No error
+ cmd_buff[2] = 0;
+ cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
+ cmd_buff[4] = 0x10; // Parameter buffer size (16)
+ cmd_buff[5] = 0;
+ cmd_buff[6] = 0;
+ cmd_buff[7] = 0;
+
+ WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
+}
+
+/**
+ * APT_U::AppletUtility service function
+ * Inputs:
+ * 1 : Unknown, but clearly used for something
+ * 2 : Buffer 1 size (purpose is unknown)
+ * 3 : Buffer 2 size (purpose is unknown)
+ * 5 : Buffer 1 address (purpose is unknown)
+ * 65 : Buffer 2 address (purpose is unknown)
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void AppletUtility(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ // These are from 3dbrew - I'm not really sure what they're used for.
+ u32 unk = cmd_buff[1];
+ u32 buffer1_size = cmd_buff[2];
+ u32 buffer2_size = cmd_buff[3];
+ u32 buffer1_addr = cmd_buff[5];
+ u32 buffer2_addr = cmd_buff[65];
+
+ cmd_buff[1] = 0; // No error
+
+ WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, "
+ "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size,
+ buffer1_addr, buffer2_addr);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, GetLockHandle, "GetLockHandle"},
{0x00020080, Initialize, "Initialize"},
@@ -87,7 +186,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000B0040, InquireNotification, "InquireNotification"},
{0x000C0104, nullptr, "SendParameter"},
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
- {0x000E0080, nullptr, "GlanceParameter"},
+ {0x000E0080, GlanceParameter, "GlanceParameter"},
{0x000F0100, nullptr, "CancelParameter"},
{0x001000C2, nullptr, "DebugFunc"},
{0x001100C0, nullptr, "MapProgramIdForDebug"},
@@ -148,10 +247,12 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00480100, nullptr, "GetProgramInfo"},
{0x00490180, nullptr, "Reboot"},
{0x004A0040, nullptr, "GetCaptureInfo"},
- {0x004B00C2, nullptr, "AppletUtility"},
+ {0x004B00C2, AppletUtility, "AppletUtility"},
{0x004C0000, nullptr, "SetFatalErrDispMode"},
{0x004D0080, nullptr, "GetAppletProgramInfo"},
{0x004E0000, nullptr, "HardwareResetAsync"},
+ {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"},
+ {0x00500040, nullptr, "GetApplicationCpuTimeLimit"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -159,6 +260,8 @@ const Interface::FunctionInfo FunctionTable[] = {
Interface::Interface() {
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+
+ lock_handle = 0;
}
Interface::~Interface() {
diff --git a/src/core/hle/service/apt.h b/src/core/hle/service/apt_u.h
index 4c7dd07e7..5af39e085 100644
--- a/src/core/hle/service/apt.h
+++ b/src/core/hle/service/apt_u.h
@@ -29,7 +29,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "APT:U";
}
};
diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp
new file mode 100644
index 000000000..822b0e2b8
--- /dev/null
+++ b/src/core/hle/service/cfg_u.cpp
@@ -0,0 +1,36 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/cfg_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace CFG_U
+
+namespace CFG_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010082, nullptr, "GetConfigInfoBlk2"},
+ {0x00020000, nullptr, "SecureInfoGetRegion"},
+ {0x00030000, nullptr, "GenHashConsoleUnique"},
+ {0x00040000, nullptr, "GetRegionCanadaUSA"},
+ {0x00050000, nullptr, "GetSystemModel"},
+ {0x00060000, nullptr, "GetModelNintendo2DS"},
+ {0x00070040, nullptr, "unknown"},
+ {0x00080080, nullptr, "unknown"},
+ {0x00090080, nullptr, "GetCountryCodeString"},
+ {0x000A0040, nullptr, "GetCountryCodeID"},
+};
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/cfg_u.h b/src/core/hle/service/cfg_u.h
new file mode 100644
index 000000000..7525bd7c6
--- /dev/null
+++ b/src/core/hle/service/cfg_u.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace CFG_U
+
+namespace CFG_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "cfg:u";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
new file mode 100644
index 000000000..9e84ac938
--- /dev/null
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -0,0 +1,52 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/dsp_dsp.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace DSP_DSP
+
+namespace DSP_DSP {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010040, nullptr, "RecvData"},
+ {0x00020040, nullptr, "RecvDataIsReady"},
+ {0x00030080, nullptr, "SendData"},
+ {0x00040040, nullptr, "SendDataIsEmpty"},
+ {0x00070040, nullptr, "WriteReg0x10"},
+ {0x00080000, nullptr, "GetSemaphore"},
+ {0x00090040, nullptr, "ClearSemaphore"},
+ {0x000B0000, nullptr, "CheckSemaphoreRequest"},
+ {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"},
+ {0x000D0082, nullptr, "WriteProcessPipe"},
+ {0x001000C0, nullptr, "ReadPipeIfPossible"},
+ {0x001100C2, nullptr, "LoadComponent"},
+ {0x00120000, nullptr, "UnloadComponent"},
+ {0x00130082, nullptr, "FlushDataCache"},
+ {0x00140082, nullptr, "InvalidateDCache "},
+ {0x00150082, nullptr, "RegisterInterruptEvents"},
+ {0x00160000, nullptr, "GetSemaphoreEventHandle"},
+ {0x00170040, nullptr, "SetSemaphoreMask"},
+ {0x00180040, nullptr, "GetPhysicalAddress"},
+ {0x00190040, nullptr, "GetVirtualAddress" },
+ {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
+ {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
+ {0x001C0082, nullptr, "SetIirFilterEQ"},
+ {0x001F0000, nullptr, "GetHeadphoneStatus"},
+ {0x00210000, nullptr, "GetIsDspOccupied"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
new file mode 100644
index 000000000..c439ed266
--- /dev/null
+++ b/src/core/hle/service/dsp_dsp.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace DSP_DSP
+
+namespace DSP_DSP {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "dsp:DSP";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
new file mode 100644
index 000000000..917b2f8ca
--- /dev/null
+++ b/src/core/hle/service/err_f.cpp
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/err_f.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace ERR_F
+
+namespace ERR_F {
+
+ const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010800, nullptr, "ThrowFatalError"}
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Interface class
+
+ Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+ }
+
+ Interface::~Interface() {
+ }
+
+} // namespace
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
new file mode 100644
index 000000000..5da663267
--- /dev/null
+++ b/src/core/hle/service/err_f.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace ERR_F
+
+namespace ERR_F {
+
+ class Interface : public Service::Interface {
+ public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "err:f";
+ }
+ };
+
+} // namespace
diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd_u.cpp
new file mode 100644
index 000000000..58023e536
--- /dev/null
+++ b/src/core/hle/service/frd_u.cpp
@@ -0,0 +1,35 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/frd_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace FRD_U
+
+namespace FRD_U {
+
+ const Interface::FunctionInfo FunctionTable[] = {
+ {0x00050000, nullptr, "GetFriendKey"},
+ {0x00080000, nullptr, "GetMyPresence"},
+ {0x00100040, nullptr, "GetPassword"},
+ {0x00190042, nullptr, "GetFriendFavoriteGame"},
+ {0x001A00C4, nullptr, "GetFriendInfo"},
+ {0x001B0080, nullptr, "IsOnFriendList"},
+ {0x001C0042, nullptr, "DecodeLocalFriendCode"},
+ {0x001D0002, nullptr, "SetCurrentlyPlayingText"},
+ {0x00320042, nullptr, "SetClientSdkVersion"}
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Interface class
+
+ Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+ }
+
+ Interface::~Interface() {
+ }
+
+} // namespace
diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h
new file mode 100644
index 000000000..9df8a815a
--- /dev/null
+++ b/src/core/hle/service/frd_u.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace FRD_U
+
+namespace FRD_U {
+
+ class Interface : public Service::Interface {
+ public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "frd:u";
+ }
+ };
+
+} // namespace
diff --git a/src/core/hle/service/fs.cpp b/src/core/hle/service/fs.cpp
deleted file mode 100644
index 5eabf36ad..000000000
--- a/src/core/hle/service/fs.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include "common/common.h"
-
-#include "core/loader/loader.h"
-#include "core/hle/hle.h"
-#include "core/hle/service/fs.h"
-#include "core/hle/kernel/archive.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace FS_User
-
-namespace FS_User {
-
-void Initialize(Service::Interface* self) {
- u32* cmd_buff = Service::GetCommandBuffer();
- cmd_buff[1] = 0; // No error
- DEBUG_LOG(KERNEL, "called");
-}
-
-void OpenFileDirectly(Service::Interface* self) {
- u32* cmd_buff = Service::GetCommandBuffer();
-
- FileSys::Archive::IdCode arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
-
- // TODO(bunnei): Properly implement use of these...
- //u32 transaction = cmd_buff[1];
- //u32 arch_lowpath_type = cmd_buff[3];
- //u32 arch_lowpath_sz = cmd_buff[4];
- //u32 file_lowpath_type = cmd_buff[5];
- //u32 file_lowpath_sz = cmd_buff[6];
- //u32 flags = cmd_buff[7];
- //u32 attr = cmd_buff[8];
- //u32 arch_lowpath_desc = cmd_buff[9];
- //u32 arch_lowpath_ptr = cmd_buff[10];
- //u32 file_lowpath_desc = cmd_buff[11];
- //u32 file_lowpath_ptr = cmd_buff[12];
-
- Handle handle = Kernel::OpenArchive(arch_id);
- if (0 != handle) {
- cmd_buff[1] = 0; // No error
- cmd_buff[3] = handle;
- }
- DEBUG_LOG(KERNEL, "called");
-}
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x000100C6, nullptr, "Dummy1"},
- {0x040100C4, nullptr, "Control"},
- {0x08010002, Initialize, "Initialize"},
- {0x080201C2, nullptr, "OpenFile"},
- {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
- {0x08040142, nullptr, "DeleteFile"},
- {0x08050244, nullptr, "RenameFile"},
- {0x08060142, nullptr, "DeleteDirectory"},
- {0x08070142, nullptr, "DeleteDirectoryRecursively"},
- {0x08080202, nullptr, "CreateFile"},
- {0x08090182, nullptr, "CreateDirectory"},
- {0x080A0244, nullptr, "RenameDirectory"},
- {0x080B0102, nullptr, "OpenDirectory"},
- {0x080C00C2, nullptr, "OpenArchive"},
- {0x080D0144, nullptr, "ControlArchive"},
- {0x080E0080, nullptr, "CloseArchive"},
- {0x080F0180, nullptr, "FormatThisUserSaveData"},
- {0x08100200, nullptr, "CreateSystemSaveData"},
- {0x08110040, nullptr, "DeleteSystemSaveData"},
- {0x08120080, nullptr, "GetFreeBytes"},
- {0x08130000, nullptr, "GetCardType"},
- {0x08140000, nullptr, "GetSdmcArchiveResource"},
- {0x08150000, nullptr, "GetNandArchiveResource"},
- {0x08160000, nullptr, "GetSdmcFatfsErro"},
- {0x08170000, nullptr, "IsSdmcDetected"},
- {0x08180000, nullptr, "IsSdmcWritable"},
- {0x08190042, nullptr, "GetSdmcCid"},
- {0x081A0042, nullptr, "GetNandCid"},
- {0x081B0000, nullptr, "GetSdmcSpeedInfo"},
- {0x081C0000, nullptr, "GetNandSpeedInfo"},
- {0x081D0042, nullptr, "GetSdmcLog"},
- {0x081E0042, nullptr, "GetNandLog"},
- {0x081F0000, nullptr, "ClearSdmcLog"},
- {0x08200000, nullptr, "ClearNandLog"},
- {0x08210000, nullptr, "CardSlotIsInserted"},
- {0x08220000, nullptr, "CardSlotPowerOn"},
- {0x08230000, nullptr, "CardSlotPowerOff"},
- {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
- {0x08250040, nullptr, "CardNorDirectCommand"},
- {0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
- {0x08270082, nullptr, "CardNorDirectRead"},
- {0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
- {0x08290082, nullptr, "CardNorDirectWrite"},
- {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
- {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
- {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
- {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
- {0x082E0040, nullptr, "GetProductInfo"},
- {0x082F0040, nullptr, "GetProgramLaunchInfo"},
- {0x08300182, nullptr, "CreateExtSaveData"},
- {0x08310180, nullptr, "CreateSharedExtSaveData"},
- {0x08320102, nullptr, "ReadExtSaveDataIcon"},
- {0x08330082, nullptr, "EnumerateExtSaveData"},
- {0x08340082, nullptr, "EnumerateSharedExtSaveData"},
- {0x08350080, nullptr, "DeleteExtSaveData"},
- {0x08360080, nullptr, "DeleteSharedExtSaveData"},
- {0x08370040, nullptr, "SetCardSpiBaudRate"},
- {0x08380040, nullptr, "SetCardSpiBusMode"},
- {0x08390000, nullptr, "SendInitializeInfoTo9"},
- {0x083A0100, nullptr, "GetSpecialContentIndex"},
- {0x083B00C2, nullptr, "GetLegacyRomHeader"},
- {0x083C00C2, nullptr, "GetLegacyBannerData"},
- {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
- {0x083E00C2, nullptr, "QueryTotalQuotaSize"},
- {0x083F00C0, nullptr, "GetExtDataBlockSize"},
- {0x08400040, nullptr, "AbnegateAccessRight"},
- {0x08410000, nullptr, "DeleteSdmcRoot"},
- {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
- {0x08430000, nullptr, "InitializeCtrFileSystem"},
- {0x08440000, nullptr, "CreateSeed"},
- {0x084500C2, nullptr, "GetFormatInfo"},
- {0x08460102, nullptr, "GetLegacyRomHeader2"},
- {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
- {0x08480042, nullptr, "GetSdmcCtrRootPath"},
- {0x08490040, nullptr, "GetArchiveResource"},
- {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
- {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
- {0x084C0242, nullptr, "FormatSaveData"},
- {0x084D0102, nullptr, "GetLegacySubBannerData"},
- {0x084E0342, nullptr, "UpdateSha256Context"},
- {0x084F0102, nullptr, "ReadSpecialFile"},
- {0x08500040, nullptr, "GetSpecialFileSize"},
- {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
- {0x08610042, nullptr, "InitializeWithSdkVersion"},
- {0x08620040, nullptr, "SetPriority"},
- {0x08630000, nullptr, "GetPriority"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable, ARRAY_SIZE(FunctionTable));
-}
-
-Interface::~Interface() {
-}
-
-} // namespace
diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp
new file mode 100644
index 000000000..9dc83291d
--- /dev/null
+++ b/src/core/hle/service/fs_user.cpp
@@ -0,0 +1,352 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/common.h"
+
+#include "fs_user.h"
+#include "common/string_util.h"
+#include "core/settings.h"
+#include "core/hle/kernel/archive.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace FS_User
+
+namespace FS_User {
+
+// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it
+// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make
+// sure we don't mislead the application into thinking something worked.
+
+void Initialize(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
+ // http://3dbrew.org/wiki/FS:Initialize#Request
+ cmd_buff[1] = 0;
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
+void OpenFile(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
+ // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
+ Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
+ auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
+ u32 filename_size = cmd_buff[5];
+ FileSys::Mode mode; mode.hex = cmd_buff[6];
+ u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
+ u32 filename_ptr = cmd_buff[9];
+
+ FileSys::Path file_path(filename_type, filename_size, filename_ptr);
+ std::string file_string;
+ switch (file_path.GetType()) {
+ case FileSys::Char:
+ case FileSys::Wchar:
+ file_string = file_path.AsString();
+ break;
+ default:
+ WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead");
+ return;
+ }
+
+ DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s",
+ filename_type, filename_size, mode, attributes, file_string.c_str());
+
+ Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode);
+ if (handle) {
+ cmd_buff[1] = 0;
+ cmd_buff[3] = handle;
+ } else {
+ ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str());
+ // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
+ cmd_buff[1] = -1;
+ }
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
+void OpenFileDirectly(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
+ auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
+ u32 archivename_size = cmd_buff[4];
+ auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]);
+ u32 filename_size = cmd_buff[6];
+ FileSys::Mode mode; mode.hex = cmd_buff[7];
+ u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
+ u32 archivename_ptr = cmd_buff[10];
+ u32 filename_ptr = cmd_buff[12];
+
+ DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d file_type=%d file_size=%d file_mode=%d file_attrs=%d",
+ archivename_type, archivename_size, filename_type, filename_size, mode, attributes);
+
+ if (archivename_type != FileSys::Empty) {
+ ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
+ cmd_buff[1] = -1;
+ return;
+ }
+
+ // TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it.
+ Handle archive_handle = Kernel::OpenArchive(archive_id);
+ if (archive_handle) {
+ cmd_buff[1] = 0;
+ // cmd_buff[2] isn't used according to 3dmoo's implementation.
+ cmd_buff[3] = archive_handle;
+ } else {
+ ERROR_LOG(KERNEL, "failed to get a handle for archive");
+ // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
+ cmd_buff[1] = -1;
+ return;
+ }
+
+ FileSys::Path file_path(filename_type, filename_size, filename_ptr);
+ std::string file_string;
+ switch (file_path.GetType()) {
+ case FileSys::Char:
+ case FileSys::Wchar:
+ file_string = file_path.AsString();
+ break;
+ default:
+ WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead");
+ return;
+ }
+
+ Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode);
+ if (handle) {
+ cmd_buff[1] = 0;
+ cmd_buff[3] = handle;
+ } else {
+ ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str());
+ // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
+ cmd_buff[1] = -1;
+ }
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
+/*
+ * FS_User::CreateDirectory service function
+ * Inputs:
+ * 2 : Archive handle lower word
+ * 3 : Archive handle upper word
+ * 4 : Directory path string type
+ * 5 : Directory path string size
+ * 8 : Directory path string data
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void CreateDirectory(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to
+ // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
+ Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
+ auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
+ u32 dirname_size = cmd_buff[5];
+ u32 dirname_ptr = cmd_buff[8];
+
+ FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
+ std::string dir_string;
+ switch (dir_path.GetType()) {
+ case FileSys::Char:
+ case FileSys::Wchar:
+ dir_string = dir_path.AsString();
+ break;
+ default:
+ cmd_buff[1] = -1;
+ return;
+ }
+
+ DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str());
+
+ cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_string);
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
+void OpenDirectory(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
+ // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
+ Handle archive_handle = static_cast<Handle>(cmd_buff[2]);
+ auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
+ u32 dirname_size = cmd_buff[4];
+ u32 dirname_ptr = cmd_buff[6];
+
+ FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
+ std::string dir_string;
+ switch (dir_path.GetType()) {
+ case FileSys::Char:
+ case FileSys::Wchar:
+ dir_string = dir_path.AsString();
+ break;
+ default:
+ cmd_buff[1] = -1;
+ return;
+ }
+
+ DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str());
+
+ Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_string);
+ if (handle) {
+ cmd_buff[1] = 0;
+ cmd_buff[3] = handle;
+ } else {
+ ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str());
+ // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
+ cmd_buff[1] = -1;
+ }
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
+void OpenArchive(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]);
+ auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
+ u32 archivename_size = cmd_buff[3];
+ u32 archivename_ptr = cmd_buff[5];
+
+ DEBUG_LOG(KERNEL, "type=%d size=%d", archivename_type, archivename_size);
+
+ if (archivename_type != FileSys::Empty) {
+ ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
+ cmd_buff[1] = -1;
+ return;
+ }
+
+ Handle handle = Kernel::OpenArchive(archive_id);
+ if (handle) {
+ cmd_buff[1] = 0;
+ // cmd_buff[2] isn't used according to 3dmoo's implementation.
+ cmd_buff[3] = handle;
+ } else {
+ ERROR_LOG(KERNEL, "failed to get a handle for archive");
+ // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
+ cmd_buff[1] = -1;
+ }
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
+/*
+* FS_User::IsSdmcDetected service function
+* Outputs:
+* 1 : Result of function, 0 on success, otherwise error code
+* 2 : Whether the Sdmc could be detected
+*/
+void IsSdmcDetected(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ cmd_buff[1] = 0;
+ cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000100C6, nullptr, "Dummy1"},
+ {0x040100C4, nullptr, "Control"},
+ {0x08010002, Initialize, "Initialize"},
+ {0x080201C2, OpenFile, "OpenFile"},
+ {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
+ {0x08040142, nullptr, "DeleteFile"},
+ {0x08050244, nullptr, "RenameFile"},
+ {0x08060142, nullptr, "DeleteDirectory"},
+ {0x08070142, nullptr, "DeleteDirectoryRecursively"},
+ {0x08080202, nullptr, "CreateFile"},
+ {0x08090182, CreateDirectory, "CreateDirectory"},
+ {0x080A0244, nullptr, "RenameDirectory"},
+ {0x080B0102, OpenDirectory, "OpenDirectory"},
+ {0x080C00C2, OpenArchive, "OpenArchive"},
+ {0x080D0144, nullptr, "ControlArchive"},
+ {0x080E0080, nullptr, "CloseArchive"},
+ {0x080F0180, nullptr, "FormatThisUserSaveData"},
+ {0x08100200, nullptr, "CreateSystemSaveData"},
+ {0x08110040, nullptr, "DeleteSystemSaveData"},
+ {0x08120080, nullptr, "GetFreeBytes"},
+ {0x08130000, nullptr, "GetCardType"},
+ {0x08140000, nullptr, "GetSdmcArchiveResource"},
+ {0x08150000, nullptr, "GetNandArchiveResource"},
+ {0x08160000, nullptr, "GetSdmcFatfsErro"},
+ {0x08170000, IsSdmcDetected, "IsSdmcDetected"},
+ {0x08180000, nullptr, "IsSdmcWritable"},
+ {0x08190042, nullptr, "GetSdmcCid"},
+ {0x081A0042, nullptr, "GetNandCid"},
+ {0x081B0000, nullptr, "GetSdmcSpeedInfo"},
+ {0x081C0000, nullptr, "GetNandSpeedInfo"},
+ {0x081D0042, nullptr, "GetSdmcLog"},
+ {0x081E0042, nullptr, "GetNandLog"},
+ {0x081F0000, nullptr, "ClearSdmcLog"},
+ {0x08200000, nullptr, "ClearNandLog"},
+ {0x08210000, nullptr, "CardSlotIsInserted"},
+ {0x08220000, nullptr, "CardSlotPowerOn"},
+ {0x08230000, nullptr, "CardSlotPowerOff"},
+ {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
+ {0x08250040, nullptr, "CardNorDirectCommand"},
+ {0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
+ {0x08270082, nullptr, "CardNorDirectRead"},
+ {0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
+ {0x08290082, nullptr, "CardNorDirectWrite"},
+ {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
+ {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
+ {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
+ {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
+ {0x082E0040, nullptr, "GetProductInfo"},
+ {0x082F0040, nullptr, "GetProgramLaunchInfo"},
+ {0x08300182, nullptr, "CreateExtSaveData"},
+ {0x08310180, nullptr, "CreateSharedExtSaveData"},
+ {0x08320102, nullptr, "ReadExtSaveDataIcon"},
+ {0x08330082, nullptr, "EnumerateExtSaveData"},
+ {0x08340082, nullptr, "EnumerateSharedExtSaveData"},
+ {0x08350080, nullptr, "DeleteExtSaveData"},
+ {0x08360080, nullptr, "DeleteSharedExtSaveData"},
+ {0x08370040, nullptr, "SetCardSpiBaudRate"},
+ {0x08380040, nullptr, "SetCardSpiBusMode"},
+ {0x08390000, nullptr, "SendInitializeInfoTo9"},
+ {0x083A0100, nullptr, "GetSpecialContentIndex"},
+ {0x083B00C2, nullptr, "GetLegacyRomHeader"},
+ {0x083C00C2, nullptr, "GetLegacyBannerData"},
+ {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
+ {0x083E00C2, nullptr, "QueryTotalQuotaSize"},
+ {0x083F00C0, nullptr, "GetExtDataBlockSize"},
+ {0x08400040, nullptr, "AbnegateAccessRight"},
+ {0x08410000, nullptr, "DeleteSdmcRoot"},
+ {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
+ {0x08430000, nullptr, "InitializeCtrFileSystem"},
+ {0x08440000, nullptr, "CreateSeed"},
+ {0x084500C2, nullptr, "GetFormatInfo"},
+ {0x08460102, nullptr, "GetLegacyRomHeader2"},
+ {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
+ {0x08480042, nullptr, "GetSdmcCtrRootPath"},
+ {0x08490040, nullptr, "GetArchiveResource"},
+ {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
+ {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
+ {0x084C0242, nullptr, "FormatSaveData"},
+ {0x084D0102, nullptr, "GetLegacySubBannerData"},
+ {0x084E0342, nullptr, "UpdateSha256Context"},
+ {0x084F0102, nullptr, "ReadSpecialFile"},
+ {0x08500040, nullptr, "GetSpecialFileSize"},
+ {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
+ {0x08610042, nullptr, "InitializeWithSdkVersion"},
+ {0x08620040, nullptr, "SetPriority"},
+ {0x08630000, nullptr, "GetPriority"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/fs.h b/src/core/hle/service/fs_user.h
index 36f3697d3..005382540 100644
--- a/src/core/hle/service/fs.h
+++ b/src/core/hle/service/fs_user.h
@@ -23,7 +23,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "fs:USER";
}
};
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp_gpu.cpp
index 46c5a8ddd..6119e6300 100644
--- a/src/core/hle/service/gsp.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -7,10 +7,9 @@
#include "common/bit_field.h"
#include "core/mem_map.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
-#include "core/hle/service/gsp.h"
+#include "gsp_gpu.h"
#include "core/hw/gpu.h"
#include "video_core/gpu_debugger.h"
@@ -359,6 +358,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x001C0040, nullptr, "SetLedForceOff"},
{0x001D0040, nullptr, "SetTestCommand"},
{0x001E0080, nullptr, "SetInternalPriorities"},
+ {0x001F0082, nullptr, "StoreDataCache"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/gsp.h b/src/core/hle/service/gsp_gpu.h
index a09d59dbb..177ce8da6 100644
--- a/src/core/hle/service/gsp.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -167,7 +167,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "gsp::Gpu";
}
diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid.cpp
deleted file mode 100644
index 4e470795f..000000000
--- a/src/core/hle/service/hid.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include "common/log.h"
-
-#include "core/hle/hle.h"
-#include "core/hle/kernel/event.h"
-#include "core/hle/kernel/shared_memory.h"
-#include "core/hle/service/hid.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace HID_User
-
-namespace HID_User {
-
-Handle g_shared_mem = 0; ///< Handle to shared memory region designated to HID_User service
-
-/**
- * HID_User::GetIPCHandles service function
- * Inputs:
- * None
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Unused
- * 3 : Handle to HID_User shared memory
- * 4 : Event signaled by HID_User
- * 5 : Event signaled by HID_User
- * 6 : Event signaled by HID_User
- * 7 : Gyroscope event
- * 8 : Event signaled by HID_User
- */
-void GetIPCHandles(Service::Interface* self) {
- u32* cmd_buff = Service::GetCommandBuffer();
-
- cmd_buff[1] = 0; // No error
- cmd_buff[3] = g_shared_mem;
- cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventA");
- cmd_buff[5] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventB");
- cmd_buff[6] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventC");
- cmd_buff[7] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope");
- cmd_buff[8] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventD");
-
- DEBUG_LOG(KERNEL, "called");
-}
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x000A0000, GetIPCHandles, "GetIPCHandles"},
- {0x000B0000, nullptr, "StartAnalogStickCalibration"},
- {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
- {0x00110000, nullptr, "EnableAccelerometer"},
- {0x00120000, nullptr, "DisableAccelerometer"},
- {0x00130000, nullptr, "EnableGyroscopeLow"},
- {0x00140000, nullptr, "DisableGyroscopeLow"},
- {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
- {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"},
- {0x00170000, nullptr, "GetSoundVolume"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- g_shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object
-
- Register(FunctionTable, ARRAY_SIZE(FunctionTable));
-}
-
-Interface::~Interface() {
-}
-
-} // namespace
diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp
new file mode 100644
index 000000000..0eb32ba4a
--- /dev/null
+++ b/src/core/hle/service/hid_user.cpp
@@ -0,0 +1,205 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+
+#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "hid_user.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace HID_User
+
+namespace HID_User {
+
+// Handle to shared memory region designated to HID_User service
+static Handle shared_mem = 0;
+
+// Event handles
+static Handle event_pad_or_touch_1 = 0;
+static Handle event_pad_or_touch_2 = 0;
+static Handle event_accelerometer = 0;
+static Handle event_gyroscope = 0;
+static Handle event_debug_pad = 0;
+
+// Next Pad state update information
+static PadState next_state = {{0}};
+static u32 next_index = 0;
+static s16 next_circle_x = 0;
+static s16 next_circle_y = 0;
+
+/**
+ * Gets a pointer to the PadData structure inside HID shared memory
+ */
+static inline PadData* GetPadData() {
+ if (0 == shared_mem)
+ return nullptr;
+
+ return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0));
+}
+
+/**
+ * Circle Pad from keys.
+ *
+ * This is implemented as "pushed all the way to an edge (max) or centered (0)".
+ *
+ * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions.
+ */
+void UpdateNextCirclePadState() {
+ static const s16 max_value = 0x9C;
+ next_circle_x = next_state.circle_left ? -max_value : 0x0;
+ next_circle_x += next_state.circle_right ? max_value : 0x0;
+ next_circle_y = next_state.circle_down ? -max_value : 0x0;
+ next_circle_y += next_state.circle_up ? max_value : 0x0;
+}
+
+/**
+ * Sets a Pad state (button or button combo) as pressed
+ */
+void PadButtonPress(PadState pad_state) {
+ next_state.hex |= pad_state.hex;
+ UpdateNextCirclePadState();
+}
+
+/**
+ * Sets a Pad state (button or button combo) as released
+ */
+void PadButtonRelease(PadState pad_state) {
+ next_state.hex &= ~pad_state.hex;
+ UpdateNextCirclePadState();
+}
+
+/**
+ * Called after all Pad changes to be included in this update have been made,
+ * including both Pad key changes and analog circle Pad changes.
+ */
+void PadUpdateComplete() {
+ PadData* pad_data = GetPadData();
+
+ if (pad_data == nullptr) {
+ return;
+ }
+
+ // Update PadData struct
+ pad_data->current_state.hex = next_state.hex;
+ pad_data->index = next_index;
+ next_index = (next_index + 1) % pad_data->entries.size();
+
+ // Get the previous Pad state
+ u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size();
+ PadState old_state = pad_data->entries[last_entry_index].current_state;
+
+ // Compute bitmask with 1s for bits different from the old state
+ PadState changed;
+ changed.hex = (next_state.hex ^ old_state.hex);
+
+ // Compute what was added
+ PadState additions;
+ additions.hex = changed.hex & next_state.hex;
+
+ // Compute what was removed
+ PadState removals;
+ removals.hex = changed.hex & old_state.hex;
+
+ // Get the current Pad entry
+ PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index];
+
+ // Update entry properties
+ current_pad_entry->current_state.hex = next_state.hex;
+ current_pad_entry->delta_additions.hex = additions.hex;
+ current_pad_entry->delta_removals.hex = removals.hex;
+
+ // Set circle Pad
+ current_pad_entry->circle_pad_x = next_circle_x;
+ current_pad_entry->circle_pad_y = next_circle_y;
+
+ // If we just updated index 0, provide a new timestamp
+ if (pad_data->index == 0) {
+ pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks;
+ pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks();
+ }
+
+ // Signal both handles when there's an update to Pad or touch
+ Kernel::SignalEvent(event_pad_or_touch_1);
+ Kernel::SignalEvent(event_pad_or_touch_2);
+}
+
+
+// TODO(peachum):
+// Add a method for setting analog input from joystick device for the circle Pad.
+//
+// This method should:
+// * Be called after both PadButton<Press, Release>().
+// * Be called before PadUpdateComplete()
+// * Set current PadEntry.circle_pad_<axis> using analog data
+// * Set PadData.raw_circle_pad_data
+// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41
+// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41
+// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41
+// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
+
+
+/**
+ * HID_User::GetIPCHandles service function
+ * Inputs:
+ * None
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Unused
+ * 3 : Handle to HID_User shared memory
+ * 4 : Event signaled by HID_User
+ * 5 : Event signaled by HID_User
+ * 6 : Event signaled by HID_User
+ * 7 : Gyroscope event
+ * 8 : Event signaled by HID_User
+ */
+void GetIPCHandles(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ cmd_buff[1] = 0; // No error
+ cmd_buff[3] = shared_mem;
+ cmd_buff[4] = event_pad_or_touch_1;
+ cmd_buff[5] = event_pad_or_touch_2;
+ cmd_buff[6] = event_accelerometer;
+ cmd_buff[7] = event_gyroscope;
+ cmd_buff[8] = event_debug_pad;
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000A0000, GetIPCHandles, "GetIPCHandles"},
+ {0x000B0000, nullptr, "StartAnalogStickCalibration"},
+ {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
+ {0x00110000, nullptr, "EnableAccelerometer"},
+ {0x00120000, nullptr, "DisableAccelerometer"},
+ {0x00130000, nullptr, "EnableGyroscopeLow"},
+ {0x00140000, nullptr, "DisableGyroscopeLow"},
+ {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
+ {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"},
+ {0x00170000, nullptr, "GetSoundVolume"},
+};
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object
+
+ // Create event handles
+ event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch1");
+ event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch2");
+ event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventAccelerometer");
+ event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope");
+ event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventDebugPad");
+
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/hid_user.h b/src/core/hle/service/hid_user.h
new file mode 100644
index 000000000..9f6c4d5ed
--- /dev/null
+++ b/src/core/hle/service/hid_user.h
@@ -0,0 +1,120 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+#include "common/bit_field.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace HID_User
+
+// This service is used for interfacing to physical user controls.
+// Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad.
+
+namespace HID_User {
+
+/**
+ * Structure of a Pad controller state.
+ */
+struct PadState {
+ union {
+ u32 hex;
+
+ BitField<0, 1, u32> a;
+ BitField<1, 1, u32> b;
+ BitField<2, 1, u32> select;
+ BitField<3, 1, u32> start;
+ BitField<4, 1, u32> right;
+ BitField<5, 1, u32> left;
+ BitField<6, 1, u32> up;
+ BitField<7, 1, u32> down;
+ BitField<8, 1, u32> r;
+ BitField<9, 1, u32> l;
+ BitField<10, 1, u32> x;
+ BitField<11, 1, u32> y;
+
+ BitField<28, 1, u32> circle_right;
+ BitField<29, 1, u32> circle_left;
+ BitField<30, 1, u32> circle_up;
+ BitField<31, 1, u32> circle_down;
+ };
+};
+
+/**
+ * Structure of a single entry in the PadData's Pad state history array.
+ */
+struct PadDataEntry {
+ PadState current_state;
+ PadState delta_additions;
+ PadState delta_removals;
+
+ s16 circle_pad_x;
+ s16 circle_pad_y;
+};
+
+/**
+ * Structure of all data related to the 3DS Pad.
+ */
+struct PadData {
+ s64 index_reset_ticks;
+ s64 index_reset_ticks_previous;
+ u32 index; // the index of the last updated Pad state history element
+
+ u32 pad1;
+ u32 pad2;
+
+ PadState current_state; // same as entries[index].current_state
+ u32 raw_circle_pad_data;
+
+ u32 pad3;
+
+ std::array<PadDataEntry, 8> entries; // Pad state history
+};
+
+// Pre-defined PadStates for single button presses
+const PadState PAD_NONE = {{0}};
+const PadState PAD_A = {{1u << 0}};
+const PadState PAD_B = {{1u << 1}};
+const PadState PAD_SELECT = {{1u << 2}};
+const PadState PAD_START = {{1u << 3}};
+const PadState PAD_RIGHT = {{1u << 4}};
+const PadState PAD_LEFT = {{1u << 5}};
+const PadState PAD_UP = {{1u << 6}};
+const PadState PAD_DOWN = {{1u << 7}};
+const PadState PAD_R = {{1u << 8}};
+const PadState PAD_L = {{1u << 9}};
+const PadState PAD_X = {{1u << 10}};
+const PadState PAD_Y = {{1u << 11}};
+const PadState PAD_CIRCLE_RIGHT = {{1u << 28}};
+const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
+const PadState PAD_CIRCLE_UP = {{1u << 30}};
+const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
+
+// Methods for updating the HID module's state
+void PadButtonPress(PadState pad_state);
+void PadButtonRelease(PadState pad_state);
+void PadUpdateComplete();
+
+/**
+ * HID service interface.
+ */
+class Interface : public Service::Interface {
+public:
+
+ Interface();
+
+ ~Interface();
+
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const override {
+ return "hid:USER";
+ }
+
+};
+
+} // namespace
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
new file mode 100644
index 000000000..58051f133
--- /dev/null
+++ b/src/core/hle/service/mic_u.cpp
@@ -0,0 +1,43 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/mic_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace MIC_U
+
+namespace MIC_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010042, nullptr, "MapSharedMem"},
+ {0x00020000, nullptr, "UnmapSharedMem"},
+ {0x00030140, nullptr, "Initialize"},
+ {0x00040040, nullptr, "AdjustSampling"},
+ {0x00050000, nullptr, "StopSampling"},
+ {0x00060000, nullptr, "IsSampling"},
+ {0x00070000, nullptr, "GetEventHandle"},
+ {0x00080040, nullptr, "SetControl"},
+ {0x00090000, nullptr, "GetControl"},
+ {0x000A0040, nullptr, "SetBias"},
+ {0x000B0000, nullptr, "GetBias"},
+ {0x000C0042, nullptr, "size"},
+ {0x000D0040, nullptr, "SetClamp"},
+ {0x000E0000, nullptr, "GetClamp"},
+ {0x000F0040, nullptr, "unknown_input1"},
+ {0x00100040, nullptr, "unknown_input2"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h
new file mode 100644
index 000000000..72ba048ef
--- /dev/null
+++ b/src/core/hle/service/mic_u.h
@@ -0,0 +1,29 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace MIC_U
+
+// mic service
+
+namespace MIC_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "mic:u";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/ndm.cpp b/src/core/hle/service/ndm_u.cpp
index 48755b6a7..37c0661bf 100644
--- a/src/core/hle/service/ndm.cpp
+++ b/src/core/hle/service/ndm_u.cpp
@@ -2,10 +2,8 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
-#include "common/log.h"
-
#include "core/hle/hle.h"
-#include "core/hle/service/ndm.h"
+#include "ndm_u.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace NDM_U
diff --git a/src/core/hle/service/ndm.h b/src/core/hle/service/ndm_u.h
index d5ec28f5b..2ca9fcf22 100644
--- a/src/core/hle/service/ndm.h
+++ b/src/core/hle/service/ndm_u.h
@@ -24,7 +24,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "ndm:u";
}
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
new file mode 100644
index 000000000..14df86d85
--- /dev/null
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -0,0 +1,35 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/nwm_uds.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace NWM_UDS
+
+namespace NWM_UDS {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00030000, nullptr, "Shutdown"},
+ {0x000F0404, nullptr, "RecvBeaconBroadcastData"},
+ {0x00100042, nullptr, "SetBeaconAdditionalData"},
+ {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
+ {0x001B0302, nullptr, "Initialize"},
+ {0x001D0044, nullptr, "BeginHostingNetwork"},
+ {0x001E0084, nullptr, "ConnectToNetwork"},
+ {0x001F0006, nullptr, "DecryptBeaconData"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
new file mode 100644
index 000000000..a956ca812
--- /dev/null
+++ b/src/core/hle/service/nwm_uds.h
@@ -0,0 +1,29 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace NWM_UDS
+
+// local-WLAN service
+
+namespace NWM_UDS {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "nwm:UDS";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp
new file mode 100644
index 000000000..f6a14d509
--- /dev/null
+++ b/src/core/hle/service/ptm_u.cpp
@@ -0,0 +1,42 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/ptm_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace PTM_U
+
+namespace PTM_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010002, nullptr, "RegisterAlarmClient"},
+ {0x00020080, nullptr, "SetRtcAlarm"},
+ {0x00030000, nullptr, "GetRtcAlarm"},
+ {0x00040000, nullptr, "CancelRtcAlarm"},
+ {0x00050000, nullptr, "GetAdapterState"},
+ {0x00060000, nullptr, "GetShellState "},
+ {0x00070000, nullptr, "GetBatteryLevel"},
+ {0x00080000, nullptr, "GetBatteryChargeState"},
+ {0x00090000, nullptr, "GetPedometerState"},
+ {0x000A0042, nullptr, "GetStepHistoryEntry"},
+ {0x000B00C2, nullptr, "GetStepHistory "},
+ {0x000C0000, nullptr, "GetTotalStepCount "},
+ {0x000D0040, nullptr, "SetPedometerRecordingMode"},
+ {0x000E0000, nullptr, "GetPedometerRecordingMode"},
+ {0x000F0084, nullptr, "GetStepHistoryAll"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm_u.h
new file mode 100644
index 000000000..82749fa39
--- /dev/null
+++ b/src/core/hle/service/ptm_u.h
@@ -0,0 +1,29 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace PTM_U
+
+// ptm service
+
+namespace PTM_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "ptm:u";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 00ac1c9c6..bb0f80e98 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -3,20 +3,25 @@
// Refer to the license.txt file included.
#include "common/common.h"
-#include "common/log.h"
#include "common/string_util.h"
-#include "core/hle/hle.h"
-
#include "core/hle/service/service.h"
-#include "core/hle/service/apt.h"
-#include "core/hle/service/fs.h"
-#include "core/hle/service/gsp.h"
-#include "core/hle/service/hid.h"
-#include "core/hle/service/ndm.h"
+#include "core/hle/service/ac_u.h"
+#include "core/hle/service/apt_u.h"
+#include "core/hle/service/cfg_u.h"
+#include "core/hle/service/dsp_dsp.h"
+#include "core/hle/service/err_f.h"
+#include "core/hle/service/fs_user.h"
+#include "core/hle/service/frd_u.h"
+#include "core/hle/service/gsp_gpu.h"
+#include "core/hle/service/hid_user.h"
+#include "core/hle/service/mic_u.h"
+#include "core/hle/service/ndm_u.h"
+#include "core/hle/service/nwm_uds.h"
+#include "core/hle/service/ptm_u.h"
+#include "core/hle/service/soc_u.h"
#include "core/hle/service/srv.h"
-
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/ssl_c.h"
namespace Service {
@@ -71,11 +76,21 @@ void Init() {
g_manager = new Manager;
g_manager->AddService(new SRV::Interface);
+ g_manager->AddService(new AC_U::Interface);
g_manager->AddService(new APT_U::Interface);
+ g_manager->AddService(new CFG_U::Interface);
+ g_manager->AddService(new DSP_DSP::Interface);
+ g_manager->AddService(new ERR_F::Interface);
+ g_manager->AddService(new FRD_U::Interface);
g_manager->AddService(new FS_User::Interface);
g_manager->AddService(new GSP_GPU::Interface);
g_manager->AddService(new HID_User::Interface);
+ g_manager->AddService(new MIC_U::Interface);
g_manager->AddService(new NDM_U::Interface);
+ g_manager->AddService(new NWM_UDS::Interface);
+ g_manager->AddService(new PTM_U::Interface);
+ g_manager->AddService(new SOC_U::Interface);
+ g_manager->AddService(new SSL_C::Interface);
NOTICE_LOG(HLE, "initialized OK");
}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index c0e803bda..2f5a866c9 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -39,11 +39,11 @@ class Interface : public Kernel::Object {
friend class Manager;
public:
- std::string GetName() const { return GetPortName(); }
- std::string GetTypeName() const { return GetPortName(); }
+ std::string GetName() const override { return GetPortName(); }
+ std::string GetTypeName() const override { return GetPortName(); }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Service; }
typedef void (*Function)(Interface*);
@@ -80,7 +80,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result SyncRequest(bool* wait) {
+ Result SyncRequest(bool* wait) override {
u32* cmd_buff = GetCommandBuffer();
auto itr = m_functions.find(cmd_buff[0]);
@@ -113,7 +113,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "unimplemented function");
return 0;
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
new file mode 100644
index 000000000..2f8910468
--- /dev/null
+++ b/src/core/hle/service/soc_u.cpp
@@ -0,0 +1,58 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/soc_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SOC_U
+
+namespace SOC_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010044, nullptr, "InitializeSockets"},
+ {0x000200C2, nullptr, "socket"},
+ {0x00030082, nullptr, "listen"},
+ {0x00040082, nullptr, "accept"},
+ {0x00050084, nullptr, "bind"},
+ {0x00060084, nullptr, "connect"},
+ {0x00070104, nullptr, "recvfrom_other"},
+ {0x00080102, nullptr, "recvfrom"},
+ {0x00090106, nullptr, "sendto_other"},
+ {0x000A0106, nullptr, "sendto"},
+ {0x000B0042, nullptr, "close"},
+ {0x000C0082, nullptr, "shutdown"},
+ {0x000D0082, nullptr, "gethostbyname"},
+ {0x000E00C2, nullptr, "gethostbyaddr"},
+ {0x000F0106, nullptr, "unknown_resolve_ip"},
+ {0x00110102, nullptr, "getsockopt"},
+ {0x00120104, nullptr, "setsockopt"},
+ {0x001300C2, nullptr, "fcntl"},
+ {0x00140084, nullptr, "poll"},
+ {0x00150042, nullptr, "sockatmark"},
+ {0x00160000, nullptr, "gethostid"},
+ {0x00170082, nullptr, "getsockname"},
+ {0x00180082, nullptr, "getpeername"},
+ {0x00190000, nullptr, "ShutdownSockets"},
+ {0x001A00C0, nullptr, "GetNetworkOpt"},
+ {0x001B0040, nullptr, "ICMPSocket"},
+ {0x001C0104, nullptr, "ICMPPing"},
+ {0x001D0040, nullptr, "ICMPCancel"},
+ {0x001E0040, nullptr, "ICMPClose"},
+ {0x001F0040, nullptr, "GetResolverInfo"},
+ {0x00210002, nullptr, "CloseSockets"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
new file mode 100644
index 000000000..e27a2b1fe
--- /dev/null
+++ b/src/core/hle/service/soc_u.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SOC_U
+
+namespace SOC_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "soc:U";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 23be3cf2c..6c02a43d9 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -4,7 +4,6 @@
#include "core/hle/hle.h"
#include "core/hle/service/srv.h"
-#include "core/hle/service/service.h"
#include "core/hle/kernel/event.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -58,6 +57,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00030100, nullptr, "RegisterService"},
{0x000400C0, nullptr, "UnregisterService"},
{0x00050100, GetServiceHandle, "GetServiceHandle"},
+ {0x000B0000, nullptr, "ReceiveNotification"},
+ {0x000C0080, nullptr, "PublishToSubscriber"}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 9451472de..6d5fe5048 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -22,7 +22,7 @@ public:
* Gets the string name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "srv:";
}
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
new file mode 100644
index 000000000..4aa660ecc
--- /dev/null
+++ b/src/core/hle/service/ssl_c.cpp
@@ -0,0 +1,31 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/ssl_c.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SSL_C
+
+namespace SSL_C {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000200C2, nullptr, "CreateContext"},
+ {0x00050082, nullptr, "AddTrustedRootCA"},
+ {0x00150082, nullptr, "Read"},
+ {0x00170082, nullptr, "Write"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h
new file mode 100644
index 000000000..7b4e7fd8a
--- /dev/null
+++ b/src/core/hle/service/ssl_c.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SSL_C
+
+namespace SSL_C {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "ssl:C";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index bdcfae6f5..1eda36c53 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <map>
-#include <string>
#include "common/string_util.h"
#include "common/symbols.h"
@@ -12,13 +11,11 @@
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/event.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/function_wrappers.h"
-#include "core/hle/svc.h"
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -118,7 +115,7 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
- DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName().c_str(),
+ DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(),
object->GetName().c_str(), nano_seconds);
_assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
@@ -141,7 +138,7 @@ Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wa
bool unlock_all = true;
bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
- DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d",
+ DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld",
handle_count, (wait_all ? "true" : "false"), nano_seconds);
// Iterate through each handle, synchronize kernel object
@@ -221,7 +218,7 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
TSymbol symbol = Symbols::GetSymbol(entry_point);
name = symbol.name;
} else {
- name = StringFromFormat("unknown-%08x", entry_point);
+ name = Common::StringFromFormat("unknown-%08x", entry_point);
}
Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id,
@@ -327,7 +324,7 @@ Result ClearEvent(Handle evt) {
/// Sleep the current thread
void SleepThread(s64 nanoseconds) {
- DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds);
+ DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds);
}
/// This returns the total CPU ticks elapsed since the CPU was powered-on
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 8709b8eb7..3ad801c63 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -3,14 +3,13 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
-#include "common/log.h"
+#include "core/settings.h"
#include "core/core.h"
#include "core/mem_map.h"
#include "core/hle/hle.h"
-#include "core/hle/kernel/thread.h"
-#include "core/hle/service/gsp.h"
+#include "core/hle/service/gsp_gpu.h"
#include "core/hw/gpu.h"
@@ -26,14 +25,17 @@ u32 g_cur_line = 0; ///< Current vertical screen line
u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame
+static u32 kFrameCycles = 0; ///< 268MHz / 60 frames per second
+static u32 kFrameTicks = 0; ///< Approximate number of instructions/frame
+
template <typename T>
inline void Read(T &var, const u32 raw_addr) {
u32 addr = raw_addr - 0x1EF00000;
- int index = addr / 4;
+ u32 index = addr / 4;
// Reads other than u32 are untested, so I'd rather have them abort than silently fail
if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) {
- ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
+ ERROR_LOG(GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
return;
}
@@ -43,15 +45,15 @@ inline void Read(T &var, const u32 raw_addr) {
template <typename T>
inline void Write(u32 addr, const T data) {
addr -= 0x1EF00000;
- int index = addr / 4;
+ u32 index = addr / 4;
// Writes other than u32 are untested, so I'd rather have them abort than silently fail
if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) {
- ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
+ ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
return;
}
- g_regs[index] = data;
+ g_regs[index] = static_cast<u32>(data);
switch (index) {
@@ -83,15 +85,15 @@ inline void Write(u32 addr, const T data) {
u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress()));
u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress()));
- for (int y = 0; y < config.output_height; ++y) {
+ for (u32 y = 0; y < config.output_height; ++y) {
// TODO: Why does the register seem to hold twice the framebuffer width?
- for (int x = 0; x < config.output_width; ++x) {
+ for (u32 x = 0; x < config.output_width; ++x) {
struct {
int r, g, b, a;
} source_color = { 0, 0, 0, 0 };
switch (config.input_format) {
- case Regs::FramebufferFormat::RGBA8:
+ case Regs::PixelFormat::RGBA8:
{
// TODO: Most likely got the component order messed up.
u8* srcptr = source_pointer + x * 4 + y * config.input_width * 4;
@@ -108,7 +110,7 @@ inline void Write(u32 addr, const T data) {
}
switch (config.output_format) {
- /*case Regs::FramebufferFormat::RGBA8:
+ /*case Regs::PixelFormat::RGBA8:
{
// TODO: Untested
u8* dstptr = (u32*)(dest_pointer + x * 4 + y * config.output_width * 4);
@@ -119,7 +121,7 @@ inline void Write(u32 addr, const T data) {
break;
}*/
- case Regs::FramebufferFormat::RGB8:
+ case Regs::PixelFormat::RGB8:
{
// TODO: Most likely got the component order messed up.
u8* dstptr = dest_pointer + x * 3 + y * config.output_width * 3;
@@ -136,10 +138,10 @@ inline void Write(u32 addr, const T data) {
}
}
- DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%dx%d)-> 0x%08x(%dx%d), dst format %x",
+ DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x",
config.output_height * config.output_width * 4,
- config.GetPhysicalInputAddress(), (int)config.input_width, (int)config.input_height,
- config.GetPhysicalOutputAddress(), (int)config.output_width, (int)config.output_height,
+ config.GetPhysicalInputAddress(), config.input_width, config.input_height,
+ config.GetPhysicalOutputAddress(), config.output_width, config.output_height,
config.output_format.Value());
}
break;
@@ -216,6 +218,9 @@ void Update() {
/// Initialize hardware
void Init() {
+ kFrameCycles = 268123480 / Settings::values.gpu_refresh_rate;
+ kFrameTicks = kFrameCycles / 3;
+
g_cur_line = 0;
g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks();
@@ -238,13 +243,13 @@ void Init() {
framebuffer_top.width = 240;
framebuffer_top.height = 400;
framebuffer_top.stride = 3 * 240;
- framebuffer_top.color_format = Regs::FramebufferFormat::RGB8;
+ framebuffer_top.color_format = Regs::PixelFormat::RGB8;
framebuffer_top.active_fb = 0;
framebuffer_sub.width = 240;
framebuffer_sub.height = 320;
framebuffer_sub.stride = 3 * 240;
- framebuffer_sub.color_format = Regs::FramebufferFormat::RGB8;
+ framebuffer_sub.color_format = Regs::PixelFormat::RGB8;
framebuffer_sub.active_fb = 0;
NOTICE_LOG(GPU, "initialized OK");
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 7186bfa84..3fa7b9ccf 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -11,9 +11,6 @@
namespace GPU {
-static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
-static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
-
// Returns index corresponding to the Regs member labeled by field_name
// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
// when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])).
@@ -56,7 +53,7 @@ struct Regs {
"Structure size and register block length don't match")
#endif
- enum class FramebufferFormat : u32 {
+ enum class PixelFormat : u32 {
RGBA8 = 0,
RGB8 = 1,
RGB565 = 2,
@@ -84,9 +81,7 @@ struct Regs {
INSERT_PADDING_WORDS(0x10b);
- struct {
- using Format = Regs::FramebufferFormat;
-
+ struct FramebufferConfig {
union {
u32 size;
@@ -102,7 +97,7 @@ struct Regs {
union {
u32 format;
- BitField< 0, 3, Format> color_format;
+ BitField< 0, 3, PixelFormat> color_format;
};
INSERT_PADDING_WORDS(0x1);
@@ -130,8 +125,6 @@ struct Regs {
INSERT_PADDING_WORDS(0x169);
struct {
- using Format = Regs::FramebufferFormat;
-
u32 input_address;
u32 output_address;
@@ -161,8 +154,8 @@ struct Regs {
u32 flags;
BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true
- BitField< 8, 3, Format> input_format;
- BitField<12, 3, Format> output_format;
+ BitField< 8, 3, PixelFormat> input_format;
+ BitField<12, 3, PixelFormat> output_format;
BitField<16, 1, u32> output_tiled; // stores output in a tiled format
};
@@ -201,7 +194,7 @@ struct Regs {
#undef INSERT_PADDING_WORDS_HELPER2
#undef INSERT_PADDING_WORDS
- static inline int NumIds() {
+ static inline size_t NumIds() {
return sizeof(Regs) / sizeof(u32);
}
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index ed70486e6..33f75c50a 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
-#include "common/log.h"
#include "core/hw/hw.h"
#include "core/hw/gpu.h"
@@ -51,7 +50,7 @@ inline void Read(T &var, const u32 addr) {
break;
default:
- ERROR_LOG(HW, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
+ ERROR_LOG(HW, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
}
}
@@ -69,7 +68,7 @@ inline void Write(u32 addr, const T data) {
break;
default:
- ERROR_LOG(HW, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
+ ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
}
}
diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp
index f6aa72d16..e29a773f1 100644
--- a/src/core/hw/ndma.cpp
+++ b/src/core/hw/ndma.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
-#include "common/log.h"
#include "core/hw/ndma.h"
@@ -11,12 +10,12 @@ namespace NDMA {
template <typename T>
inline void Read(T &var, const u32 addr) {
- ERROR_LOG(NDMA, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
+ ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
}
template <typename T>
inline void Write(u32 addr, const T data) {
- ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
+ ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
}
// Explicitly instantiate template functions because we aren't defining this in the header:
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 76c9d6d54..389d5a8c9 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -351,7 +351,7 @@ ResultStatus AppLoader_ELF::Load() {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
- File::IOFile file(filename, "rb");
+ FileUtil::IOFile file(filename, "rb");
if (file.IsOpen()) {
u32 size = (u32)file.GetSize();
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 365f5a277..a268e021a 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -5,7 +5,6 @@
#include <memory>
#include "core/file_sys/archive_romfs.h"
-#include "core/loader/loader.h"
#include "core/loader/elf.h"
#include "core/loader/ncch.h"
#include "core/hle/kernel/archive.h"
@@ -26,22 +25,23 @@ FileType IdentifyFile(const std::string &filename) {
ERROR_LOG(LOADER, "invalid filename %s", filename.c_str());
return FileType::Error;
}
- std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : "";
- if (!strcasecmp(extension.c_str(), ".elf")) {
- return FileType::ELF; // TODO(bunnei): Do some filetype checking :p
- }
- else if (!strcasecmp(extension.c_str(), ".axf")) {
- return FileType::ELF; // TODO(bunnei): Do some filetype checking :p
- }
- else if (!strcasecmp(extension.c_str(), ".cxi")) {
- return FileType::CXI; // TODO(bunnei): Do some filetype checking :p
- }
- else if (!strcasecmp(extension.c_str(), ".cci")) {
- return FileType::CCI; // TODO(bunnei): Do some filetype checking :p
- }
- else if (!strcasecmp(extension.c_str(), ".bin")) {
- return FileType::BIN; // TODO(bunnei): Do some filetype checking :p
+ size_t extension_loc = filename.find_last_of('.');
+ if (extension_loc == std::string::npos)
+ return FileType::Unknown;
+ std::string extension = Common::ToLower(filename.substr(extension_loc));
+
+ // TODO(bunnei): Do actual filetype checking instead of naively checking the extension
+ if (extension == ".elf") {
+ return FileType::ELF;
+ } else if (extension == ".axf") {
+ return FileType::ELF;
+ } else if (extension == ".cxi") {
+ return FileType::CXI;
+ } else if (extension == ".cci") {
+ return FileType::CCI;
+ } else if (extension == ".bin") {
+ return FileType::BIN;
}
return FileType::Unknown;
}
@@ -78,7 +78,7 @@ ResultStatus LoadFile(const std::string& filename) {
{
INFO_LOG(LOADER, "Loading BIN file %s...", filename.c_str());
- File::IOFile file(filename, "rb");
+ FileUtil::IOFile file(filename, "rb");
if (file.IsOpen()) {
file.ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), (size_t)file.GetSize());
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 9af59e419..1e5501e6d 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -138,7 +138,7 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
*/
ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const {
// Iterate through the ExeFs archive until we find the .code file...
- File::IOFile file(filename, "rb");
+ FileUtil::IOFile file(filename, "rb");
if (file.IsOpen()) {
for (int i = 0; i < kMaxSections; i++) {
// Load the specified section...
@@ -199,7 +199,7 @@ ResultStatus AppLoader_NCCH::Load() {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
- File::IOFile file(filename, "rb");
+ FileUtil::IOFile file(filename, "rb");
if (file.IsOpen()) {
file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
@@ -290,7 +290,7 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const {
* @return ResultStatus result of function
*/
ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
- File::IOFile file(filename, "rb");
+ FileUtil::IOFile file(filename, "rb");
if (file.IsOpen()) {
// Check if the NCCH has a RomFS...
if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index 14fc01471..cf12f24d9 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -6,7 +6,6 @@
#include "common/mem_arena.h"
#include "core/mem_map.h"
-#include "core/core.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index 391b75fc2..90951812b 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -8,7 +8,6 @@
#include "core/mem_map.h"
#include "core/hw/hw.h"
-#include "hle/hle.h"
#include "hle/config_mem.h"
namespace Memory {
@@ -288,7 +287,7 @@ void Write64(const VAddr addr, const u64 data) {
}
void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
- int offset = 0;
+ u32 offset = 0;
while (offset < (size & ~3)) {
Write32(addr + offset, *(u32*)&data[offset]);
offset += 4;
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
new file mode 100644
index 000000000..c486f6274
--- /dev/null
+++ b/src/core/settings.cpp
@@ -0,0 +1,11 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "settings.h"
+
+namespace Settings {
+
+Values values = {};
+
+}
diff --git a/src/core/settings.h b/src/core/settings.h
new file mode 100644
index 000000000..6a6265e18
--- /dev/null
+++ b/src/core/settings.h
@@ -0,0 +1,37 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Settings {
+
+struct Values {
+ // Controls
+ int pad_a_key;
+ int pad_b_key;
+ int pad_x_key;
+ int pad_y_key;
+ int pad_l_key;
+ int pad_r_key;
+ int pad_start_key;
+ int pad_select_key;
+ int pad_home_key;
+ int pad_dup_key;
+ int pad_ddown_key;
+ int pad_dleft_key;
+ int pad_dright_key;
+ int pad_sup_key;
+ int pad_sdown_key;
+ int pad_sleft_key;
+ int pad_sright_key;
+
+ // Core
+ int cpu_core;
+ int gpu_refresh_rate;
+
+ // Data Storage
+ bool use_virtual_sd;
+} extern values;
+
+}
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index 592f2f476..96d3dabe2 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -86,8 +86,8 @@ static void InitScreenCoordinates(OutputVertex& vtx)
viewport.halfsize_x = float24::FromRawFloat24(registers.viewport_size_x);
viewport.halfsize_y = float24::FromRawFloat24(registers.viewport_size_y);
- viewport.offset_x = float24::FromFloat32(registers.viewport_corner.x);
- viewport.offset_y = float24::FromFloat32(registers.viewport_corner.y);
+ viewport.offset_x = float24::FromFloat32(static_cast<float>(registers.viewport_corner.x));
+ viewport.offset_y = float24::FromFloat32(static_cast<float>(registers.viewport_corner.y));
viewport.zscale = float24::FromRawFloat24(registers.viewport_depth_range);
viewport.offset_z = float24::FromRawFloat24(registers.viewport_depth_far_plane);
@@ -150,7 +150,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
InitScreenCoordinates(*(output_list[0]));
InitScreenCoordinates(*(output_list[1]));
- for (int i = 0; i < output_list.size() - 2; i ++) {
+ for (size_t i = 0; i < output_list.size() - 2; i ++) {
OutputVertex& vtx0 = *(output_list[0]);
OutputVertex& vtx1 = *(output_list[i+1]);
OutputVertex& vtx2 = *(output_list[i+2]);
@@ -158,8 +158,8 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
InitScreenCoordinates(vtx2);
DEBUG_LOG(GPU,
- "Triangle %d/%d (%d buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), "
- "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
+ "Triangle %lu/%lu (%lu buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), "
+ "(%.3lu, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
"screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)",
i,output_list.size(), buffer_vertices.size(),
vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),output_list.size(),
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 9567a9849..1ec727698 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -63,8 +63,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
for (int component = 0; component < loader_config.component_count; ++component) {
u32 attribute_index = loader_config.GetComponent(component);
vertex_attribute_sources[attribute_index] = load_address;
- vertex_attribute_strides[attribute_index] = loader_config.byte_count;
- vertex_attribute_formats[attribute_index] = (u32)attribute_config.GetFormat(attribute_index);
+ vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
+ vertex_attribute_formats[attribute_index] = static_cast<u32>(attribute_config.GetFormat(attribute_index));
vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index);
vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index);
load_address += attribute_config.GetStride(attribute_index);
@@ -83,9 +83,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
PrimitiveAssembler<VertexShader::OutputVertex> clipper_primitive_assembler(registers.triangle_topology.Value());
PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(registers.triangle_topology.Value());
- for (int index = 0; index < registers.num_vertices; ++index)
+ for (unsigned int index = 0; index < registers.num_vertices; ++index)
{
- int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index;
+ unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index;
if (is_indexed) {
// TODO: Implement some sort of vertex cache!
@@ -95,14 +95,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
VertexShader::InputVertex input;
for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) {
- for (int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
+ for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
const u8* srcdata = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata :
(vertex_attribute_formats[i] == 1) ? *(u8*)srcdata :
(vertex_attribute_formats[i] == 2) ? *(s16*)srcdata :
*(float*)srcdata;
input.attr[i][comp] = float24::FromFloat32(srcval);
- DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08x + 0x%04x: %f",
+ DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
comp, i, vertex, index,
attribute_config.GetBaseAddress(),
vertex_attribute_sources[i] - base_address,
@@ -244,7 +244,7 @@ static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) {
WritePicaReg(header.cmd_id, *read_pointer, write_mask);
read_pointer += 2;
- for (int i = 1; i < 1+header.extra_data_length; ++i) {
+ for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) {
u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0);
WritePicaReg(cmd, *read_pointer, write_mask);
++read_pointer;
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 48e6dd182..22b8e9950 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -203,7 +203,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
} else {
it->component_mask = it->component_mask | component_mask;
}
- } catch (const std::out_of_range& oor) {
+ } catch (const std::out_of_range& ) {
_dbg_assert_msg_(GPU, 0, "Unknown output attribute mapping");
ERROR_LOG(GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x",
(int)output_attributes[i].map_x.Value(),
@@ -235,7 +235,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
dvlp.swizzle_patterns_offset = write_offset - dvlp_offset;
dvlp.swizzle_patterns_num_entries = swizzle_size;
u32 dummy = 0;
- for (int i = 0; i < swizzle_size; ++i) {
+ for (unsigned int i = 0; i < swizzle_size; ++i) {
QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i]));
QueueForWriting((u8*)&dummy, sizeof(dummy));
}
@@ -278,7 +278,7 @@ void StartPicaTracing()
bool IsPicaTracing()
{
- return is_pica_tracing;
+ return is_pica_tracing != 0;
}
void OnPicaRegWrite(u32 id, u32 value)
@@ -336,7 +336,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
png_infop info_ptr = nullptr;
// Open file for writing (binary mode)
- File::IOFile fp(filename, "wb");
+ FileUtil::IOFile fp(filename, "wb");
// Initialize write structure
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
@@ -428,7 +428,7 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages)
using Operation = Pica::Regs::TevStageConfig::Operation;
std::string stage_info = "Tev setup:\n";
- for (int index = 0; index < stages.size(); ++index) {
+ for (size_t index = 0; index < stages.size(); ++index) {
const auto& tev_stage = stages[index];
const std::map<Source, std::string> source_map = {
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h
index 5a81fcfcb..1242eb58f 100644
--- a/src/video_core/gpu_debugger.h
+++ b/src/video_core/gpu_debugger.h
@@ -10,7 +10,7 @@
#include "common/log.h"
-#include "core/hle/service/gsp.h"
+#include "core/hle/service/gsp_gpu.h"
#include "command_processor.h"
#include "pica.h"
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index cfdc9b934..5fe15a218 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -516,12 +516,12 @@ struct Regs {
// Used for debugging purposes, so performance is not an issue here
static std::string GetCommandName(int index) {
std::map<u32, std::string> map;
- Regs regs;
// TODO: MSVC does not support using offsetof() on non-static data members even though this
// is technically allowed since C++11. Hence, this functionality is disabled until
// MSVC properly supports it.
#ifndef _MSC_VER
+ Regs regs;
#define ADD_FIELD(name) \
do { \
map.insert({PICA_REG_INDEX(name), #name}); \
@@ -563,7 +563,7 @@ struct Regs {
return map[index];
}
- static inline int NumIds() {
+ static inline size_t NumIds() {
return sizeof(Regs) / sizeof(u32);
}
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index b55391e5e..a35f0c0d8 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -65,7 +65,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
// vertex positions in rasterizer coordinates
auto FloatToFix = [](float24 flt) {
- return Fix12P4(flt.ToFloat32() * 16.0f);
+ return Fix12P4(static_cast<unsigned short>(flt.ToFloat32() * 16.0f));
};
auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) {
return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)};
@@ -151,9 +151,9 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
auto w_inverse = Math::MakeVec(float24::FromFloat32(1.f) / v0.pos.w,
float24::FromFloat32(1.f) / v1.pos.w,
float24::FromFloat32(1.f) / v2.pos.w);
- auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(w0),
- float24::FromFloat32(w1),
- float24::FromFloat32(w2));
+ auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)),
+ float24::FromFloat32(static_cast<float>(w1)),
+ float24::FromFloat32(static_cast<float>(w2)));
float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates);
float24 interpolated_w_inverse = Math::Dot(w_inverse, baricentric_coordinates);
@@ -195,8 +195,8 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
// TODO(neobrain): Not sure if this swizzling pattern is used for all textures.
// To be flexible in case different but similar patterns are used, we keep this
// somewhat inefficient code around for now.
- int s = (int)(u * float24::FromFloat32(registers.texture0.width)).ToFloat32();
- int t = (int)(v * float24::FromFloat32(registers.texture0.height)).ToFloat32();
+ int s = (int)(u * float24::FromFloat32(static_cast<float>(registers.texture0.width))).ToFloat32();
+ int t = (int)(v * float24::FromFloat32(static_cast<float>(registers.texture0.height))).ToFloat32();
int texel_index_within_tile = 0;
for (int block_size_index = 0; block_size_index < 3; ++block_size_index) {
int sub_tile_width = 1 << block_size_index;
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 2650620b4..f1dbc9d17 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -19,7 +19,7 @@ public:
RendererBase() : m_current_fps(0), m_current_frame(0) {
}
- ~RendererBase() {
+ virtual ~RendererBase() {
}
/// Swap buffers (render frame)
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index 10239c8a7..a0eb0418c 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -29,10 +29,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result);
glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
- std::vector<char> vertex_shader_error(info_log_length);
- glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]);
-
if (info_log_length > 1) {
+ std::vector<char> vertex_shader_error(info_log_length);
+ glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]);
DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]);
}
@@ -46,10 +45,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result);
glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
- std::vector<char> fragment_shader_error(info_log_length);
- glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]);
-
if (info_log_length > 1) {
+ std::vector<char> fragment_shader_error(info_log_length);
+ glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]);
DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]);
}
@@ -65,10 +63,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
glGetProgramiv(program_id, GL_LINK_STATUS, &result);
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
- std::vector<char> program_error(std::max(info_log_length, int(1)));
- glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]);
-
if (info_log_length > 1) {
+ std::vector<char> program_error(info_log_length);
+ glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]);
DEBUG_LOG(GPU, "%s", &program_error[0]);
}
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h
index 380648f45..0f88ab802 100644
--- a/src/video_core/renderer_opengl/gl_shaders.h
+++ b/src/video_core/renderer_opengl/gl_shaders.h
@@ -6,34 +6,40 @@
namespace GLShaders {
-static const char g_vertex_shader[] = R"(
+const char g_vertex_shader[] = R"(
#version 150 core
-in vec3 position;
-in vec2 texCoord;
-out vec2 UV;
+in vec2 vert_position;
+in vec2 vert_tex_coord;
+out vec2 frag_tex_coord;
-mat3 window_scale = mat3(
- vec3(1.0, 0.0, 0.0),
- vec3(0.0, 5.0/6.0, 0.0), // TODO(princesspeachum): replace hard-coded aspect with uniform
- vec3(0.0, 0.0, 1.0)
- );
+// This is a truncated 3x3 matrix for 2D transformations:
+// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
+// The third column performs translation.
+// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
+// implicitly be [0, 0, 1]
+uniform mat3x2 modelview_matrix;
void main() {
- gl_Position.xyz = window_scale * position;
- gl_Position.w = 1.0;
-
- UV = texCoord;
-})";
+ // Multiply input position by the rotscale part of the matrix and then manually translate by
+ // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
+ // to `vec3(vert_position.xy, 1.0)`
+ gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
+ frag_tex_coord = vert_tex_coord;
+}
+)";
-static const char g_fragment_shader[] = R"(
+const char g_fragment_shader[] = R"(
#version 150 core
-in vec2 UV;
-out vec3 color;
-uniform sampler2D sampler;
+
+in vec2 frag_tex_coord;
+out vec4 color;
+
+uniform sampler2D color_texture;
void main() {
- color = texture(sampler, UV).rgb;
-})";
+ color = texture(color_texture, frag_tex_coord);
+}
+)";
}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 0e4e06517..8483f79be 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -3,64 +3,51 @@
// Refer to the license.txt file included.
#include "core/hw/gpu.h"
-
+#include "core/mem_map.h"
+#include "common/emu_window.h"
#include "video_core/video_core.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/gl_shaders.h"
-#include "core/mem_map.h"
-
#include <algorithm>
-static const GLfloat kViewportAspectRatio =
- (static_cast<float>(VideoCore::kScreenTopHeight) + VideoCore::kScreenBottomHeight) / VideoCore::kScreenTopWidth;
-
-// Fullscreen quad dimensions
-static const GLfloat kTopScreenWidthNormalized = 2;
-static const GLfloat kTopScreenHeightNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenTopHeight) / VideoCore::kScreenTopWidth);
-static const GLfloat kBottomScreenWidthNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth);
-static const GLfloat kBottomScreenHeightNormalized = kBottomScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomHeight) / VideoCore::kScreenBottomWidth);
-
-static const GLfloat g_vbuffer_top[] = {
- // x, y, z u, v
- -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
- 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f,
- 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f,
- -1.0f, kTopScreenHeightNormalized, 0.0f, 0.0f, 0.0f,
- -1.0f, 0.0f, 0.0f, 0.0f, 1.0f
-};
+/**
+ * Vertex structure that the drawn screen rectangles are composed of.
+ */
+struct ScreenRectVertex {
+ ScreenRectVertex(GLfloat x, GLfloat y, GLfloat u, GLfloat v) {
+ position[0] = x;
+ position[1] = y;
+ tex_coord[0] = u;
+ tex_coord[1] = v;
+ }
-static const GLfloat g_vbuffer_bottom[] = {
- // x, y, z u, v
- -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f,
- (kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 1.0f, 1.0f,
- (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f,
- (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f,
- -(kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 0.0f, 0.0f,
- -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f
+ GLfloat position[2];
+ GLfloat tex_coord[2];
};
+/**
+ * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left
+ * corner and (width, height) on the lower-bottom.
+ *
+ * The projection part of the matrix is trivial, hence these operations are represented
+ * by a 3x2 matrix.
+ */
+static std::array<GLfloat, 3*2> MakeOrthographicMatrix(const float width, const float height) {
+ std::array<GLfloat, 3*2> matrix;
+
+ matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f;
+ matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f;
+ // Last matrix row is implicitly assumed to be [0, 0, 1].
+
+ return matrix;
+}
+
/// RendererOpenGL constructor
RendererOpenGL::RendererOpenGL() {
-
resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight;
-
- // Initialize screen info
- const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0];
- const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1];
-
- screen_info.Top().width = VideoCore::kScreenTopWidth;
- screen_info.Top().height = VideoCore::kScreenTopHeight;
- screen_info.Top().stride = framebuffer_top.stride;
- screen_info.Top().flipped_xfb_data = xfb_top_flipped;
-
- screen_info.Bottom().width = VideoCore::kScreenBottomWidth;
- screen_info.Bottom().height = VideoCore::kScreenBottomHeight;
- screen_info.Bottom().stride = framebuffer_sub.stride;
- screen_info.Bottom().flipped_xfb_data = xfb_bottom_flipped;
}
/// RendererOpenGL destructor
@@ -71,17 +58,24 @@ RendererOpenGL::~RendererOpenGL() {
void RendererOpenGL::SwapBuffers() {
render_window->MakeCurrent();
- // EFB->XFB copy
- // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some
- // register write.
- //
- // TODO(princesspeachum): (related to above^) this should only be called when there's new data, not every frame.
- // Currently this uploads data that shouldn't have changed.
- common::Rect framebuffer_size(0, 0, resolution_width, resolution_height);
- RenderXFB(framebuffer_size, framebuffer_size);
+ for(int i : {0, 1}) {
+ const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
+
+ if (textures[i].width != framebuffer.width || textures[i].height != framebuffer.height) {
+ // Reallocate texture if the framebuffer size has changed.
+ // This is expected to not happen very often and hence should not be a
+ // performance problem.
+ glBindTexture(GL_TEXTURE_2D, textures[i].handle);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, framebuffer.width, framebuffer.height, 0,
+ GL_BGR, GL_UNSIGNED_BYTE, nullptr);
+ textures[i].width = framebuffer.width;
+ textures[i].height = framebuffer.height;
+ }
+
+ LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]);
+ }
- // XFB->Window copy
- RenderFramebuffer();
+ DrawScreens();
// Swap buffers
render_window->PollEvents();
@@ -89,144 +83,135 @@ void RendererOpenGL::SwapBuffers() {
}
/**
- * Helper function to flip framebuffer from left-to-right to top-to-bottom
- * @param raw_data Pointer to input raw framebuffer in V/RAM
- * @param screen_info ScreenInfo structure with screen size and output buffer pointer
- * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei
+ * Loads framebuffer from emulated memory into the active OpenGL texture.
*/
-void RendererOpenGL::FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info) {
- for (int x = 0; x < screen_info.width; x++) {
- int in_coord = x * screen_info.stride;
- for (int y = screen_info.height-1; y >= 0; y--) {
- // TODO: Properly support other framebuffer formats
- int out_coord = (x + y * screen_info.width) * 3;
- screen_info.flipped_xfb_data[out_coord] = raw_data[in_coord + 2]; // Red
- screen_info.flipped_xfb_data[out_coord + 1] = raw_data[in_coord + 1]; // Green
- screen_info.flipped_xfb_data[out_coord + 2] = raw_data[in_coord]; // Blue
- in_coord += 3;
- }
- }
+void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer,
+ const TextureInfo& texture) {
+ const VAddr framebuffer_vaddr = Memory::PhysicalToVirtualAddress(
+ framebuffer.active_fb == 1 ? framebuffer.address_left2 : framebuffer.address_left1);
+
+ DEBUG_LOG(GPU, "0x%08x bytes from 0x%08x(%dx%d), fmt %x",
+ framebuffer.stride * framebuffer.height,
+ framebuffer_vaddr, (int)framebuffer.width,
+ (int)framebuffer.height, (int)framebuffer.format);
+
+ const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr);
+
+ // TODO: Handle other pixel formats
+ _dbg_assert_msg_(RENDER, framebuffer.color_format == GPU::Regs::PixelFormat::RGB8,
+ "Unsupported 3DS pixel format.");
+
+ size_t pixel_stride = framebuffer.stride / 3;
+ // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately
+ _dbg_assert_(RENDER, pixel_stride * 3 == framebuffer.stride);
+ // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
+ // only allows rows to have a memory alignement of 4.
+ _dbg_assert_(RENDER, pixel_stride % 4 == 0);
+
+ glBindTexture(GL_TEXTURE_2D, texture.handle);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
+
+ // Update existing texture
+ // TODO: Test what happens on hardware when you change the framebuffer dimensions so that they
+ // differ from the LCD resolution.
+ // TODO: Applications could theoretically crash Citra here by specifying too large
+ // framebuffer sizes. We should make sure that this cannot happen.
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
+ GL_BGR, GL_UNSIGNED_BYTE, framebuffer_data);
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
}
/**
- * Renders external framebuffer (XFB)
- * @param src_rect Source rectangle in XFB to copy
- * @param dst_rect Destination rectangle in output framebuffer to copy to
+ * Initializes the OpenGL state and creates persistent objects.
*/
-void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) {
- const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0];
- const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1];
- const u32 active_fb_top = (framebuffer_top.active_fb == 1)
- ? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2)
- : Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1);
- const u32 active_fb_sub = (framebuffer_sub.active_fb == 1)
- ? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2)
- : Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1);
-
- DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x",
- framebuffer_top.stride * framebuffer_top.height,
- active_fb_top, (int)framebuffer_top.width,
- (int)framebuffer_top.height, (int)framebuffer_top.format);
-
- FlipFramebuffer(Memory::GetPointer(active_fb_top), screen_info.Top());
- FlipFramebuffer(Memory::GetPointer(active_fb_sub), screen_info.Bottom());
-
- for (int i = 0; i < 2; i++) {
- ScreenInfo* current_screen = &screen_info[i];
-
- glBindTexture(GL_TEXTURE_2D, current_screen->texture_id);
-
- // TODO: This should consider the GPU registers for framebuffer width, height and stride.
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, current_screen->width, current_screen->height,
- GL_RGB, GL_UNSIGNED_BYTE, current_screen->flipped_xfb_data);
- }
-
- glBindTexture(GL_TEXTURE_2D, 0);
-
- // TODO(princesspeachum):
- // Only the subset src_rect of the GPU buffer
- // should be copied into the texture of the relevant screen.
- //
- // The method's parameters also only include src_rect and dest_rec for one screen,
- // so this may need to be changed (pair for each screen).
-}
+void RendererOpenGL::InitOpenGLObjects() {
+ glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
+ glDisable(GL_DEPTH_TEST);
-/// Initialize the FBO
-void RendererOpenGL::InitFramebuffer() {
+ // Link shaders and get variable locations
program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader);
- sampler_id = glGetUniformLocation(program_id, "sampler");
- attrib_position = glGetAttribLocation(program_id, "position");
- attrib_texcoord = glGetAttribLocation(program_id, "texCoord");
-
- // Generate vertex buffers for both screens
- glGenBuffers(1, &screen_info.Top().vertex_buffer_id);
- glGenBuffers(1, &screen_info.Bottom().vertex_buffer_id);
-
- // Attach vertex data for top screen
- glBindBuffer(GL_ARRAY_BUFFER, screen_info.Top().vertex_buffer_id);
- glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_top), g_vbuffer_top, GL_STATIC_DRAW);
-
- // Attach vertex data for bottom screen
- glBindBuffer(GL_ARRAY_BUFFER, screen_info.Bottom().vertex_buffer_id);
- glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_bottom), g_vbuffer_bottom, GL_STATIC_DRAW);
+ uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix");
+ uniform_color_texture = glGetUniformLocation(program_id, "color_texture");
+ attrib_position = glGetAttribLocation(program_id, "vert_position");
+ attrib_tex_coord = glGetAttribLocation(program_id, "vert_tex_coord");
- // Create color buffers for both screens
- glGenTextures(1, &screen_info.Top().texture_id);
- glGenTextures(1, &screen_info.Bottom().texture_id);
+ // Generate VBO handle for drawing
+ glGenBuffers(1, &vertex_buffer_handle);
- for (int i = 0; i < 2; i++) {
+ // Generate VAO
+ glGenVertexArrays(1, &vertex_array_handle);
+ glBindVertexArray(vertex_array_handle);
+
+ // Attach vertex data to VAO
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
+ glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, position));
+ glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, tex_coord));
+ glEnableVertexAttribArray(attrib_position);
+ glEnableVertexAttribArray(attrib_tex_coord);
- ScreenInfo* current_screen = &screen_info[i];
+ // Allocate textures for each screen
+ for (auto& texture : textures) {
+ glGenTextures(1, &texture.handle);
- // Allocate texture
- glBindTexture(GL_TEXTURE_2D, current_screen->vertex_buffer_id);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, current_screen->width, current_screen->height,
- 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ // Allocation of storage is deferred until the first frame, when we
+ // know the framebuffer size.
+ glBindTexture(GL_TEXTURE_2D, texture.handle);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
-
glBindTexture(GL_TEXTURE_2D, 0);
}
-void RendererOpenGL::RenderFramebuffer() {
+/**
+ * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation.
+ */
+void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h) {
+ std::array<ScreenRectVertex, 4> vertices = {
+ ScreenRectVertex(x, y, 1.f, 0.f),
+ ScreenRectVertex(x+w, y, 1.f, 1.f),
+ ScreenRectVertex(x, y+h, 0.f, 0.f),
+ ScreenRectVertex(x+w, y+h, 0.f, 1.f),
+ };
+
+ glBindTexture(GL_TEXTURE_2D, texture.handle);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+/**
+ * Draws the emulated screens to the emulator window.
+ */
+void RendererOpenGL::DrawScreens() {
glViewport(0, 0, resolution_width, resolution_height);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program_id);
+ // Set projection matrix
+ std::array<GLfloat, 3*2> ortho_matrix = MakeOrthographicMatrix((float)resolution_width, (float)resolution_height);
+ glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
+
// Bind texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
+ glUniform1i(uniform_color_texture, 0);
- glEnableVertexAttribArray(attrib_position);
- glEnableVertexAttribArray(attrib_texcoord);
-
- for (int i = 0; i < 2; i++) {
+ const float max_width = std::max((float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenBottomWidth);
+ const float top_x = 0.5f * (max_width - VideoCore::kScreenTopWidth);
+ const float bottom_x = 0.5f * (max_width - VideoCore::kScreenBottomWidth);
- ScreenInfo* current_screen = &screen_info[i];
-
- glBindTexture(GL_TEXTURE_2D, current_screen->texture_id);
-
- // Set sampler on Texture Unit 0
- glUniform1i(sampler_id, 0);
-
- glBindBuffer(GL_ARRAY_BUFFER, current_screen->vertex_buffer_id);
-
- // Vertex buffer layout
- const GLsizei stride = 5 * sizeof(GLfloat);
- const GLvoid* uv_offset = (const GLvoid*)(3 * sizeof(GLfloat));
-
- // Configure vertex buffer
- glVertexAttribPointer(attrib_position, 3, GL_FLOAT, GL_FALSE, stride, NULL);
- glVertexAttribPointer(attrib_texcoord, 2, GL_FLOAT, GL_FALSE, stride, uv_offset);
-
- // Draw screen
- glDrawArrays(GL_TRIANGLES, 0, 6);
- }
-
- glDisableVertexAttribArray(attrib_position);
- glDisableVertexAttribArray(attrib_texcoord);
+ DrawSingleScreenRotated(textures[0], top_x, 0,
+ (float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenTopHeight);
+ DrawSingleScreenRotated(textures[1], bottom_x, (float)VideoCore::kScreenTopHeight,
+ (float)VideoCore::kScreenBottomWidth, (float)VideoCore::kScreenBottomHeight);
m_current_frame++;
}
@@ -253,20 +238,8 @@ void RendererOpenGL::Init() {
exit(-1);
}
- // Generate VAO
- glGenVertexArrays(1, &vertex_array_id);
- glBindVertexArray(vertex_array_id);
-
- glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
- glDisable(GL_DEPTH_TEST);
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-
- // Initialize everything else
- // --------------------------
- InitFramebuffer();
-
NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION));
+ InitOpenGLObjects();
}
/// Shutdown the renderer
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index eac91df51..eed201a95 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -7,73 +7,50 @@
#include "generated/gl_3_2_core.h"
#include "common/common.h"
-#include "common/emu_window.h"
-
+#include "core/hw/gpu.h"
#include "video_core/renderer_base.h"
#include <array>
-class RendererOpenGL : virtual public RendererBase {
+class EmuWindow;
+
+class RendererOpenGL : public RendererBase {
public:
RendererOpenGL();
- ~RendererOpenGL();
+ ~RendererOpenGL() override;
/// Swap buffers (render frame)
- void SwapBuffers();
-
- /**
- * Renders external framebuffer (XFB)
- * @param src_rect Source rectangle in XFB to copy
- * @param dst_rect Destination rectangle in output framebuffer to copy to
- */
- void RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect);
+ void SwapBuffers() override;
/**
* Set the emulator window to use for renderer
* @param window EmuWindow handle to emulator window to use for rendering
*/
- void SetWindow(EmuWindow* window);
+ void SetWindow(EmuWindow* window) override;
/// Initialize the renderer
- void Init();
+ void Init() override;
/// Shutdown the renderer
- void ShutDown();
+ void ShutDown() override;
private:
+ /// Structure used for storing information about the textures for each 3DS screen
+ struct TextureInfo {
+ GLuint handle;
+ GLsizei width;
+ GLsizei height;
+ };
- /// Initialize the FBO
- void InitFramebuffer();
-
- // Blit the FBO to the OpenGL default framebuffer
- void RenderFramebuffer();
-
- /// Updates the framerate
+ void InitOpenGLObjects();
+ void DrawScreens();
+ void DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h);
void UpdateFramerate();
- /// Structure used for storing information for rendering each 3DS screen
- struct ScreenInfo {
- // Properties
- int width;
- int height;
- int stride; ///< Number of bytes between the coordinates (0,0) and (1,0)
-
- // OpenGL object IDs
- GLuint texture_id;
- GLuint vertex_buffer_id;
-
- // Temporary
- u8* flipped_xfb_data;
- };
-
- /**
- * Helper function to flip framebuffer from left-to-right to top-to-bottom
- * @param raw_data Pointer to input raw framebuffer in V/RAM
- * @param screen_info ScreenInfo structure with screen size and output buffer pointer
- * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei
- */
- void FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info);
+ // Loads framebuffer from emulated memory into the active OpenGL texture.
+ static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer,
+ const TextureInfo& texture);
EmuWindow* render_window; ///< Handle to render window
u32 last_mode; ///< Last render mode
@@ -81,22 +58,15 @@ private:
int resolution_width; ///< Current resolution width
int resolution_height; ///< Current resolution height
- // OpenGL global object IDs
- GLuint vertex_array_id;
+ // OpenGL object IDs
+ GLuint vertex_array_handle;
+ GLuint vertex_buffer_handle;
GLuint program_id;
- GLuint sampler_id;
+ std::array<TextureInfo, 2> textures;
+ // Shader uniform location indices
+ GLuint uniform_modelview_matrix;
+ GLuint uniform_color_texture;
// Shader attribute input indices
GLuint attrib_position;
- GLuint attrib_texcoord;
-
- struct : std::array<ScreenInfo, 2> {
- ScreenInfo& Top() { return (*this)[0]; }
- ScreenInfo& Bottom() { return (*this)[1]; }
- } screen_info;
-
- // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom
- // as OpenGL expects them in a texture. There probably is a more efficient way of doing this:
- u8 xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4];
- u8 xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4];
-
+ GLuint attrib_tex_coord;
};
diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp
index b94376ac1..c1848f923 100644
--- a/src/video_core/utils.cpp
+++ b/src/video_core/utils.cpp
@@ -8,6 +8,7 @@
#include "video_core/utils.h"
namespace VideoCore {
+
/**
* Dumps a texture to TGA
* @param filename String filename to dump texture to
@@ -16,29 +17,20 @@ namespace VideoCore {
* @param raw_data Raw RGBA8 texture data to dump
* @todo This should be moved to some general purpose/common code
*/
-void DumpTGA(std::string filename, int width, int height, u8* raw_data) {
- TGAHeader hdr;
- FILE* fout;
- u8 r, g, b;
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.datatypecode = 2; // uncompressed RGB
- hdr.bitsperpixel = 24; // 24 bpp
- hdr.width = width;
- hdr.height = height;
-
- fout = fopen(filename.c_str(), "wb");
+void DumpTGA(std::string filename, short width, short height, u8* raw_data) {
+ TGAHeader hdr = {0, 0, 2, 0, 0, 0, 0, width, height, 24, 0};
+ FILE* fout = fopen(filename.c_str(), "wb");
+
fwrite(&hdr, sizeof(TGAHeader), 1, fout);
- for (int i = 0; i < height; i++) {
- for (int j = 0; j < width; j++) {
- b = raw_data[(3 * (i * width)) + (3 * j) + 0];
- g = raw_data[(3 * (i * width)) + (3 * j) + 1];
- r = raw_data[(3 * (i * width)) + (3 * j) + 2];
- putc(b, fout);
- putc(g, fout);
- putc(r, fout);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ putc(raw_data[(3 * (y * width)) + (3 * x) + 0], fout); // b
+ putc(raw_data[(3 * (y * width)) + (3 * x) + 1], fout); // g
+ putc(raw_data[(3 * (y * width)) + (3 * x) + 2], fout); // r
}
}
+
fclose(fout);
}
} // namespace
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index 20d4ec9e0..9cb3d4d43 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -59,6 +59,6 @@ struct TGAHeader {
* @param raw_data Raw RGBA8 texture data to dump
* @todo This should be moved to some general purpose/common code
*/
-void DumpTGA(std::string filename, int width, int height, u8* raw_data);
+void DumpTGA(std::string filename, short width, short height, u8* raw_data);
} // namespace
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index db8244317..96625791c 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -77,7 +77,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
: nullptr;
const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id];
- const bool negate_src1 = swizzle.negate;
+ const bool negate_src1 = (swizzle.negate != 0);
float24 src1[4] = {
src1_[(int)swizzle.GetSelectorSrc1(0)],
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index 847fdc450..607a8e803 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -225,7 +225,7 @@ union SwizzlePattern {
}
bool DestComponentEnabled(int i) const {
- return (dest_mask & (0x8 >> i));
+ return (dest_mask & (0x8 >> i)) != 0;
}
std::string SelectorToString(bool src2) const {
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 9aaff4917..c779771c5 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -21,13 +21,6 @@ EmuWindow* g_emu_window = NULL; ///< Frontend emulator window
RendererBase* g_renderer = NULL; ///< Renderer plugin
int g_current_frame = 0;
-/// Start the video core
-void Start() {
- if (g_emu_window == NULL) {
- ERROR_LOG(VIDEO, "VideoCore::Start called without calling Init()!");
- }
-}
-
/// Initialize the video core
void Init(EmuWindow* emu_window) {
g_emu_window = emu_window;
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index d227b6aa4..609aac513 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -17,6 +17,10 @@ namespace VideoCore {
// 3DS Video Constants
// -------------------
+// NOTE: The LCDs actually rotate the image 90 degrees when displaying. Because of that the
+// framebuffers in video memory are stored in column-major order and rendered sideways, causing
+// the widths and heights of the framebuffers read by the LCD to be switched compared to the
+// heights and widths of the screens listed here.
static const int kScreenTopWidth = 400; ///< 3DS top screen width
static const int kScreenTopHeight = 240; ///< 3DS top screen height
static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width
@@ -27,6 +31,7 @@ static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height
extern RendererBase* g_renderer; ///< Renderer plugin
extern int g_current_frame; ///< Current frame
+extern EmuWindow* g_emu_window; ///< Emu window
/// Start the video core
void Start();